From d1cee082558c585c79b4cca042d476b27fa347d0 Mon Sep 17 00:00:00 2001 From: Roopesh Gottipati Date: Mon, 13 Mar 2023 13:52:08 +0530 Subject: [PATCH 001/283] Correct spec for project services --- docs/health-api-specs/contracts/project.yml | 118 ++++++++++++++------ 1 file changed, 83 insertions(+), 35 deletions(-) diff --git a/docs/health-api-specs/contracts/project.yml b/docs/health-api-specs/contracts/project.yml index 2eb4df15a7d..f13529c2046 100644 --- a/docs/health-api-specs/contracts/project.yml +++ b/docs/health-api-specs/contracts/project.yml @@ -73,15 +73,16 @@ paths: description: Details for the project. required: true schema: - $ref: '#/definitions/ProjectSearchRequest' + $ref: '#/definitions/ProjectRequest' - $ref: '#/parameters/limit' - $ref: '#/parameters/offset' - $ref: '#/parameters/tenantId' - $ref: '#/parameters/lastChangedSince' - $ref: '#/parameters/includeDeleted' - - $ref: '#/parameters/includeEnded' - $ref: '#/parameters/includeAncestors' - $ref: '#/parameters/includeDescendants' + - $ref: '#/parameters/createdFrom' + - $ref: '#/parameters/createdTo' tags: - Project responses: @@ -1113,6 +1114,24 @@ parameters: default: false required: false + createdFrom: + name: createdFrom + description: | + Used in project search API to limit the search results to only those projects whose creation date is after the specified 'createdFrom' date. + in: query + required: false + type: integer + format: int64 + + createdTo: + name: createdTo + description: | + Used in project search API to limit the search results to only those projects whose creation date is before the specified 'createdTo' date. + in: query + required: false + type: integer + format: int64 + definitions: boundaryCode: $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/boundaryCode' @@ -1229,41 +1248,38 @@ definitions: Project: description: The purpose of this object to define the Project for a geography and period type: object - required: - - tenantId - - projectTypeId properties: id: - $ref: '#/definitions/id' + type: string + minLength: 2 + maxLength: 64 + description: Unique system generated GUID + readOnly: True tenantId: - $ref: '#/definitions/tenantId' - projectTypeId: - $ref: '#/definitions/projectTypeId' - subProjectTypeId: - $ref: '#/definitions/subProjectTypeId' - address: - $ref: '#/definitions/Address' - startDate: - type: integer - format: int64 - description: Project start date - endDate: - type: integer - format: int64 - description: Project end date - isTaskEnabled: - type: boolean - default: false - description: Task can be created if this is 'True' - parent: type: string minLength: 2 maxLength: 64 - description: Parent Project id - targets: - type: array - items: - $ref: '#/definitions/Target' + description: Unique tenant of the system + example: 'tenantA' + name: + type: string + description: Name of project + minLength: 2 + projectNumber: + type: string + description: 'The unique identifier of the project number the custom formatting.' + example: 'PR/2022-23/010' + readOnly: true + projectType: + type: string + description: Unique ID of project type from master data + minLength: 2 + maxLength: 64 + projectSubType: + type: string + description: Unique ID of subproject type from master data + minLength: 2 + maxLength: 64 department: type: string description: Unique department ID as defined in master data @@ -1273,7 +1289,7 @@ definitions: type: string description: Description of project minLength: 2 - referenceId: + referenceID: type: string description: Reference number to a physical file or docket or some other artifact of which this project is representative of. minLength: 2 @@ -1282,13 +1298,45 @@ definitions: type: array description: Reference to physical documents that have been attached via file upload items: - $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/master/core-services/docs/worfklow-2.0.yml#/definitions/Document' + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/master/core-services/docs/common-contract.yml#/components/schemas/Document' + natureOfWork: + type: string + description: Specifies nature of work for Project + minLength: 2 + maxLength: 64 projectHierarchy: type: "string" description: "Materialized Path of the hierarchy that this project element belongs to" readOnly: true - additionalFields: - $ref: '#/definitions/additionalFields' + ancestors: + $ref: '#/definitions/Project' + description: "Materialized Path of the hierarchy that this project element belongs to" + address: + $ref: '#/definitions/Address' + startDate: + type: integer + format: int64 + description: Project start date + endDate: + type: integer + format: int64 + description: Project end date + isTaskEnabled: + type: boolean + default: false + description: Task can be created if this is 'True' + parent: + type: string + minLength: 2 + maxLength: 64 + description: Parent Project id + targets: + type: array + items: + $ref: '#/definitions/Target' + additionalDetails: + type: object + description: Any additional details of the register isDeleted: $ref: '#/definitions/isDeleted' rowVersion: From 832d4564d2b07362078b277abe19e2d318f7ee31 Mon Sep 17 00:00:00 2001 From: Roopesh Gottipati Date: Mon, 13 Mar 2023 15:30:14 +0530 Subject: [PATCH 002/283] Correct spec for project services --- docs/health-api-specs/contracts/project.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/health-api-specs/contracts/project.yml b/docs/health-api-specs/contracts/project.yml index f13529c2046..0cfb314b670 100644 --- a/docs/health-api-specs/contracts/project.yml +++ b/docs/health-api-specs/contracts/project.yml @@ -1298,7 +1298,7 @@ definitions: type: array description: Reference to physical documents that have been attached via file upload items: - $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/master/core-services/docs/common-contract.yml#/components/schemas/Document' + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/master/core-services/docs/common-contract.yml#/definitions/Document' natureOfWork: type: string description: Specifies nature of work for Project From de0a109d4f060d26e219bf673660ec36360a26fa Mon Sep 17 00:00:00 2001 From: Roopesh Gottipati Date: Tue, 14 Mar 2023 09:26:43 +0530 Subject: [PATCH 003/283] Correct spec for project services --- docs/health-api-specs/contracts/project.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/health-api-specs/contracts/project.yml b/docs/health-api-specs/contracts/project.yml index 0cfb314b670..08f9427db15 100644 --- a/docs/health-api-specs/contracts/project.yml +++ b/docs/health-api-specs/contracts/project.yml @@ -1294,11 +1294,11 @@ definitions: description: Reference number to a physical file or docket or some other artifact of which this project is representative of. minLength: 2 maxLength: 100 - documents: - type: array - description: Reference to physical documents that have been attached via file upload - items: - $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/master/core-services/docs/common-contract.yml#/definitions/Document' + #documents: + # type: array + # description: Reference to physical documents that have been attached via file upload + # items: + # $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/master/core-services/docs/common-contract.yml#/definitions/Document' natureOfWork: type: string description: Specifies nature of work for Project From a5d583b403030c0f81326cdd6f657ef8f61a6f1d Mon Sep 17 00:00:00 2001 From: Shiva Burade Date: Tue, 4 Apr 2023 12:38:16 +0530 Subject: [PATCH 004/283] [hlm-2301]: Added pgr services to build config yml. --- build/build-config.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/build/build-config.yml b/build/build-config.yml index 6cf847c4235..c4ab6738c5f 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -99,4 +99,10 @@ config: build: - work-dir: "health-services/libraries/health-services-models" image-name: "health-services-models" - image-name: "health-services-models" + - name: "builds/health-campaign-services/core-services/pgr-services" + build: + - work-dir: "core-services/pgr-services" + image-name: "pgr-services" + dockerfile: "build/maven/Dockerfile" + - work-dir: "core-services/pgr-services/src/main/resources/db" + image-name: "pgr-services-db" From 66b7285a0bc18836965ca2f91f02ffa681c94c36 Mon Sep 17 00:00:00 2001 From: "anu.jaiswal" Date: Fri, 28 Apr 2023 11:49:33 +0530 Subject: [PATCH 005/283] [hlm-2706]: Added transformation for service-request --- .../ServiceDefinitionRequestRepository.java | 2 +- .../validators/ServiceRequestValidator.java | 6 +- .../servicerequest/web/models/Service.java | 12 +++ .../web/models/ServiceDefinitionCriteria.java | 5 ++ ...20230427045500__service_add_column_ddl.sql | 5 ++ .../helper/ServiceTestBuilder.java | 3 + health-services/transformer/pom.xml | 5 ++ .../transformer/config/MainConfiguration.java | 12 +++ .../config/TransformerProperties.java | 3 + .../consumer/ServiceTaskConsumer.java | 46 ++++++++++ .../org/egov/transformer/enums/Operation.java | 3 +- .../ServiceTaskTransformationHandler.java | 31 +++++++ .../models/downstream/ServiceTaskIndexV1.java | 39 +++++++++ ...rviceTaskIndexV1TransformationService.java | 31 +++++++ .../ServiceTaskTransformationService.java | 86 +++++++++++++++++++ .../src/main/resources/application.properties | 3 + 16 files changed, 287 insertions(+), 5 deletions(-) create mode 100644 core-services/service-request/src/main/resources/db/migration/main/V20230427045500__service_add_column_ddl.sql create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/consumer/ServiceTaskConsumer.java create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/handler/ServiceTaskTransformationHandler.java create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ServiceTaskIndexV1.java create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskIndexV1TransformationService.java create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/repository/ServiceDefinitionRequestRepository.java b/core-services/service-request/src/main/java/org/egov/servicerequest/repository/ServiceDefinitionRequestRepository.java index e805336b81a..73771504ace 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/repository/ServiceDefinitionRequestRepository.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/repository/ServiceDefinitionRequestRepository.java @@ -37,7 +37,7 @@ public List getServiceDefinitions(ServiceDefinitionSearchRequ List preparedStmtList = new ArrayList<>(); - if(CollectionUtils.isEmpty(criteria.getIds()) && ObjectUtils.isEmpty(criteria.getTenantId()) && CollectionUtils.isEmpty(criteria.getCode())) + if(CollectionUtils.isEmpty(criteria.getIds()) && ObjectUtils.isEmpty(criteria.getTenantId()) && ObjectUtils.isEmpty(criteria.getProjectId()) && CollectionUtils.isEmpty(criteria.getCode())) return new ArrayList<>(); // Fetch ids based on criteria if ids are not present 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 fc692f42310..cf804b992b2 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 @@ -55,7 +55,7 @@ public class ServiceRequestValidator { private Configuration config; public void validateServiceRequest(ServiceRequest serviceRequest){ - List serviceDefinitions = validateServiceDefID(serviceRequest.getService().getTenantId(), serviceRequest.getService().getServiceDefId()); + List serviceDefinitions = validateServiceDefID(serviceRequest.getService().getTenantId(), serviceRequest.getService().getServiceDefId(), serviceRequest.getService().getProjectId()); validateAttributeValuesAgainstServiceDefinition(serviceDefinitions.get(0), serviceRequest.getService()); validateAccountId(serviceRequest.getService()); } @@ -161,8 +161,8 @@ private void validateSize(Object value) { } } - private List validateServiceDefID(String tenantId, String serviceDefId) { - List serviceDefinitions = serviceDefinitionRequestRepository.getServiceDefinitions(ServiceDefinitionSearchRequest.builder().serviceDefinitionCriteria(ServiceDefinitionCriteria.builder().tenantId(tenantId).ids(Arrays.asList(serviceDefId)).build()).build()); + private List validateServiceDefID(String tenantId, String serviceDefId, String projectId) { + List serviceDefinitions = serviceDefinitionRequestRepository.getServiceDefinitions(ServiceDefinitionSearchRequest.builder().serviceDefinitionCriteria(ServiceDefinitionCriteria.builder().tenantId(tenantId).projectId(projectId).ids(Arrays.asList(serviceDefId)).build()).build()); if(serviceDefinitions.isEmpty()) throw new CustomException(SERVICE_REQUEST_INVALID_SERVICE_DEF_ID_CODE, SERVICE_REQUEST_INVALID_SERVICE_DEF_ID_MSG); 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..bf3f8d8840d 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 @@ -32,6 +32,18 @@ public class Service { @NotNull @Size(min = 2, max = 64) private String tenantId = null; + @JsonProperty("projectId") + @NotNull + @Size(min = 2, max = 64) + private String projectId = null; + @JsonProperty("checkListName") + @NotNull + @Size(min = 2, max = 64) + private String checkListName = null; + @JsonProperty("supervisorLevel") + @NotNull + @Size(min = 2, max = 64) + private String supervisorLevel = null; @JsonProperty("serviceDefId") @NotNull diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinitionCriteria.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinitionCriteria.java index 4649d339bb1..7a9ba9b0bd8 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinitionCriteria.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinitionCriteria.java @@ -28,6 +28,11 @@ public class ServiceDefinitionCriteria { @Size(min = 2, max = 64) private String tenantId = null; + @JsonProperty("projectId") + @NotNull + @Size(min = 2, max = 64) + private String projectId = null; + @JsonProperty("ids") private List ids = null; diff --git a/core-services/service-request/src/main/resources/db/migration/main/V20230427045500__service_add_column_ddl.sql b/core-services/service-request/src/main/resources/db/migration/main/V20230427045500__service_add_column_ddl.sql new file mode 100644 index 00000000000..6d0d04a8a91 --- /dev/null +++ b/core-services/service-request/src/main/resources/db/migration/main/V20230427045500__service_add_column_ddl.sql @@ -0,0 +1,5 @@ +ALTER TABLE eg_service ADD COLUMN projectId character varying(64); +ALTER TABLE eg_service ADD COLUMN checkListName character varying(64); +ALTER TABLE eg_service ADD COLUMN supervisorLevel character varying(64); + + diff --git a/core-services/service-request/src/test/java/org/egov/servicerequest/helper/ServiceTestBuilder.java b/core-services/service-request/src/test/java/org/egov/servicerequest/helper/ServiceTestBuilder.java index 763ededa33d..a8b818effe8 100644 --- a/core-services/service-request/src/test/java/org/egov/servicerequest/helper/ServiceTestBuilder.java +++ b/core-services/service-request/src/test/java/org/egov/servicerequest/helper/ServiceTestBuilder.java @@ -24,6 +24,9 @@ public Service build() { public ServiceTestBuilder withService() { this.builder.id("some-id") .tenantId("default") + .projectId("project-id") + .supervisorLevel("supervisor") + .checkListName("checkListName") .serviceDefId("service-def-id") .referenceId("reference-id") .attributes(Arrays.asList(AttributeValue.builder() diff --git a/health-services/transformer/pom.xml b/health-services/transformer/pom.xml index ba2b21ef154..e1ea8e6a417 100644 --- a/health-services/transformer/pom.xml +++ b/health-services/transformer/pom.xml @@ -74,6 +74,11 @@ javax.validation validation-api + + org.egov + service-request + 1.0.0 + diff --git a/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java b/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java index b699d3f942c..83c3fee5d39 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java @@ -12,6 +12,7 @@ import org.egov.common.models.project.ProjectStaff; import org.egov.common.models.project.Task; import org.egov.common.models.stock.Stock; +import org.egov.servicerequest.web.models.Service; import org.egov.tracer.config.TracerConfiguration; import org.egov.transformer.enums.Operation; import org.egov.transformer.service.TransformationService; @@ -118,4 +119,15 @@ public Map>> getOperationTransforma log.info(map.toString()); return map; } + @Bean + @Autowired + @Qualifier("serviceTaskTransformationServiceMap") + public Map>> getOperationTransformationServiceMapForServiceTask( + List> transformationServices) { + Map>> map = transformationServices + .stream() + .collect(Collectors.groupingBy(TransformationService::getOperation)); + log.info(map.toString()); + return map; + } } \ No newline at end of file diff --git a/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java b/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java index 3698ab4f6b5..6ba02445332 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java @@ -20,6 +20,9 @@ public class TransformerProperties { @Value("${transformer.producer.bulk.project.staff.index.v1.topic}") private String transformerProducerBulkProjectStaffIndexV1Topic; + @Value("${transformer.producer.service.task.index.v1.topic}") + private String transformerProducerServiceTaskIndexV1Topic; + @Value("${transformer.producer.bulk.project.index.v1.topic}") private String transformerProducerBulkProjectIndexV1Topic; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/consumer/ServiceTaskConsumer.java b/health-services/transformer/src/main/java/org/egov/transformer/consumer/ServiceTaskConsumer.java new file mode 100644 index 00000000000..2987bad952e --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/consumer/ServiceTaskConsumer.java @@ -0,0 +1,46 @@ +package org.egov.transformer.consumer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.egov.servicerequest.web.models.Service; +import org.egov.transformer.enums.Operation; +import org.egov.transformer.handler.TransformationHandler; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +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.Arrays; +import java.util.List; + +@Component +@Slf4j +public class ServiceTaskConsumer { + private final TransformationHandler transformationHandler; + + private final ObjectMapper objectMapper; + + @Autowired + public ServiceTaskConsumer(TransformationHandler transformationHandler, + @Qualifier("objectMapper") ObjectMapper objectMapper) { + this.transformationHandler = transformationHandler; + this.objectMapper = objectMapper; + } + + @KafkaListener(topics = {"${transformer.consumer.create.service.topic}"}) + public void consumeStaff(ConsumerRecord payload, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + List payloadList = Arrays.asList(objectMapper + .readValue((String) payload.value(), + Service[].class)); + transformationHandler.handle(payloadList, Operation.SERVICE); + } catch (Exception exception) { + log.error("error in service task consumer", exception); + } + } + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/enums/Operation.java b/health-services/transformer/src/main/java/org/egov/transformer/enums/Operation.java index 86a517f17f3..32b8b7d878e 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/enums/Operation.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/enums/Operation.java @@ -7,7 +7,8 @@ public enum Operation { TASK("TASK"), PROJECT_STAFF("PROJECT_STAFF"), PROJECT("PROJECT"), - STOCK("STOCK"); + STOCK("STOCK"), + SERVICE("SERVICE"); private String value; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/handler/ServiceTaskTransformationHandler.java b/health-services/transformer/src/main/java/org/egov/transformer/handler/ServiceTaskTransformationHandler.java new file mode 100644 index 00000000000..142313ff82b --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/handler/ServiceTaskTransformationHandler.java @@ -0,0 +1,31 @@ +package org.egov.transformer.handler; + +import org.egov.servicerequest.web.models.Service; +import org.egov.transformer.enums.Operation; +import org.egov.transformer.service.TransformationService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +@Component +public class ServiceTaskTransformationHandler implements TransformationHandler{ + private final Map>> operationTransformationServiceMap; + + @Autowired + public ServiceTaskTransformationHandler(@Qualifier("serviceTaskTransformationServiceMap") + Map>> operationTransformationServiceMap) { + this.operationTransformationServiceMap = operationTransformationServiceMap; + } + + @Override + public void handle(List payloadList, Operation operation) { + operationTransformationServiceMap.entrySet().stream() + .filter(e -> e.getKey().equals(operation)) + .map(Map.Entry::getValue) + .flatMap(Collection::stream).forEach(es -> es.transform(payloadList)); + } +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ServiceTaskIndexV1.java b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ServiceTaskIndexV1.java new file mode 100644 index 00000000000..da9db21ff21 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ServiceTaskIndexV1.java @@ -0,0 +1,39 @@ +package org.egov.transformer.models.downstream; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ServiceTaskIndexV1 { + @JsonProperty("id") + private String id; + @JsonProperty("createdTime") + private Long createdTime; + @JsonProperty("createdBy") + private String createdBy; + @JsonProperty("supervisorLevel") + private String supervisorLevel; + @JsonProperty("checklistName") + private String checklistName; + @JsonProperty("projectId") + private String projectId; + @JsonProperty("serviceDefinitionId") + private String serviceDefinitionId; + @JsonProperty("province") + private String province; + @JsonProperty("district") + private String district; + @JsonProperty("tenantId") + private String tenantId; + + + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskIndexV1TransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskIndexV1TransformationService.java new file mode 100644 index 00000000000..ef40feb704f --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskIndexV1TransformationService.java @@ -0,0 +1,31 @@ +package org.egov.transformer.service; + +import lombok.extern.slf4j.Slf4j; +import org.egov.servicerequest.web.models.Service; +import org.egov.transformer.config.TransformerProperties; +import org.egov.transformer.producer.Producer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +@Slf4j +public class ServiceTaskIndexV1TransformationService extends ServiceTaskTransformationService { + @Autowired + public ServiceTaskIndexV1TransformationService(ServiceTaskIndexV1Transformer transformer, + Producer producer, TransformerProperties properties) { + super(transformer, producer, properties); + } + @Override + public void transform(List payloadList) { + super.transform(payloadList); + } + + @Override + public String getTopic() { + return properties.getTransformerProducerServiceTaskIndexV1Topic(); + } + + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java new file mode 100644 index 00000000000..7362a4946bc --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java @@ -0,0 +1,86 @@ +package org.egov.transformer.service; + + +import lombok.extern.slf4j.Slf4j; +import org.egov.servicerequest.web.models.Service; +import org.egov.transformer.config.TransformerProperties; +import org.egov.transformer.enums.Operation; +import org.egov.transformer.models.downstream.ServiceTaskIndexV1; +import org.egov.transformer.producer.Producer; +import org.egov.transformer.service.transformer.Transformer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +@Slf4j +public abstract class ServiceTaskTransformationService implements TransformationService { + + protected final ServiceTaskIndexV1Transformer transformer; + + protected final Producer producer; + + protected final TransformerProperties properties; + + @Autowired + protected ServiceTaskTransformationService(ServiceTaskTransformationService.ServiceTaskIndexV1Transformer transformer, + Producer producer, TransformerProperties properties) { + this.transformer = transformer; + this.producer = producer; + this.properties = properties; + } + + @Override + public void transform(List payloadList) { + log.info("transforming for ids {}", payloadList.stream() + .map(Service::getId).collect(Collectors.toList())); + List transformedPayloadList = payloadList.stream() + .map(transformer::transform) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + log.info("transformation successful"); + producer.push(getTopic(), + transformedPayloadList); + } + + public abstract String getTopic(); + + @Override + public Operation getOperation() { + return Operation.SERVICE; + } + + @Component + static class ServiceTaskIndexV1Transformer implements + Transformer { + private final ProjectService projectService; + private final TransformerProperties properties; + + @Autowired + ServiceTaskIndexV1Transformer(ProjectService projectService, TransformerProperties properties) { + this.projectService = projectService; + this.properties = properties; + } + + @Override + public List transform(Service service) { + Map boundaryLabelToNameMap = projectService + .getBoundaryLabelToNameMap(service.getProjectId(), service.getTenantId()); + log.info("boundary labels {}", boundaryLabelToNameMap.toString()); + return Collections.singletonList(ServiceTaskIndexV1.builder() + .id(service.getId()) + .projectId(service.getProjectId()) + .serviceDefinitionId(service.getServiceDefId()) + .supervisorLevel(service.getSupervisorLevel()) + .checklistName(service.getCheckListName()) + .province(boundaryLabelToNameMap.get(properties.getProvince())) + .district(boundaryLabelToNameMap.get(properties.getDistrict())) + .createdTime(service.getAuditDetails().getCreatedTime()) + .createdBy(service.getAuditDetails().getCreatedBy()) + .build()); + } + } +} diff --git a/health-services/transformer/src/main/resources/application.properties b/health-services/transformer/src/main/resources/application.properties index bbb0b11d689..1b23bbd7841 100644 --- a/health-services/transformer/src/main/resources/application.properties +++ b/health-services/transformer/src/main/resources/application.properties @@ -73,6 +73,9 @@ transformer.consumer.bulk.create.stock.topic=save-stock-topic transformer.consumer.bulk.update.stock.topic=update-stock-topic transformer.producer.bulk.stock.index.v1.topic=transformer-producer-bulk-stock-index-v1-topic +transformer.consumer.create.service.topic=save-service +transformer.producer.service.task.index.v1.topic=transformer-producer-service-task-index-v1-topic + egov.project.host=http://localhost:8083 egov.search.project.url=/project/v1/_search From 8d350429f42365405d725f4e9f40e605aec9caae Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Fri, 28 Apr 2023 12:39:18 +0530 Subject: [PATCH 006/283] [hlm-1725]: Fixed address related issues --- .../facility/repository/rowmapper/FacilityRowMapper.java | 8 ++++++-- .../repository/rowmapper/HouseholdRowMapper.java | 9 +++++++-- .../repository/rowmapper/ProjectAddressRowMapper.java | 4 ++++ .../repository/rowmapper/ProjectTaskRowMapper.java | 9 +++++++-- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java index 8258ab1476f..eb6c2440792 100644 --- a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java +++ b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java @@ -22,7 +22,7 @@ public class FacilityRowMapper implements RowMapper { @Override public Facility mapRow(ResultSet resultSet, int i) throws SQLException { try { - return Facility.builder() + Facility facility = Facility.builder() .id(resultSet.getString("id")) .clientReferenceId(resultSet.getString("clientReferenceId")) .tenantId(resultSet.getString("tenantId")) @@ -45,7 +45,7 @@ public Facility mapRow(ResultSet resultSet, int i) throws SQLException { .pincode(resultSet.getString("pinCode")) .buildingName(resultSet.getString("buildingName")) .street(resultSet.getString("street")) - .locality(Boundary.builder().code(resultSet.getString("localityCode")).build()) + .locality(resultSet.getString("localityCode") != null ? Boundary.builder().code(resultSet.getString("localityCode")).build() : null) .build()) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) @@ -58,6 +58,10 @@ public Facility mapRow(ResultSet resultSet, int i) throws SQLException { .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) .build(); + if (facility.getAddress().getId() == null) { + facility.setAddress(null); + } + return facility; } catch (JsonProcessingException e) { throw new SQLException(e); } diff --git a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java index 6d79b983220..6846f9bb3bd 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java +++ b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java @@ -21,7 +21,7 @@ public class HouseholdRowMapper implements RowMapper { @Override public Household mapRow(ResultSet resultSet, int i) throws SQLException { try { - return Household.builder() + Household household = Household.builder() .id(resultSet.getString("id")) .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) @@ -52,9 +52,14 @@ public Household mapRow(ResultSet resultSet, int i) throws SQLException { .pincode(resultSet.getString("pinCode")) .buildingName(resultSet.getString("buildingName")) .street(resultSet.getString("street")) - .locality(Boundary.builder().code(resultSet.getString("localityCode")).build()) + .locality(resultSet.getString("localityCode") != null ? + Boundary.builder().code(resultSet.getString("localityCode")).build() : null) .build()) .build(); + if (household.getAddress().getId() == null) { + household.setAddress(null); + } + return household; } catch (JsonProcessingException e) { throw new SQLException(e); } diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectAddressRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectAddressRowMapper.java index 2e8d69f961f..fa5d72c5dc7 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectAddressRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectAddressRowMapper.java @@ -87,6 +87,10 @@ private Address getAddressObjFromResultSet(ResultSet rs) throws SQLException { .boundary(address_boundary) .build(); + if (address_id == null) { + return null; + } + return address; } diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java index af4c05002d4..f797ac57e70 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java @@ -22,7 +22,7 @@ public class ProjectTaskRowMapper implements RowMapper { @Override public Task mapRow(ResultSet resultSet, int i) throws SQLException { try { - return Task.builder() + Task task = Task.builder() .id(resultSet.getString("id")) .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) @@ -60,9 +60,14 @@ public Task mapRow(ResultSet resultSet, int i) throws SQLException { .pincode(resultSet.getString("pinCode")) .buildingName(resultSet.getString("buildingName")) .street(resultSet.getString("street")) - .locality(Boundary.builder().code(resultSet.getString("localityCode")).build()) + .locality(resultSet.getString("localityCode") != null ? + Boundary.builder().code(resultSet.getString("localityCode")).build() : null) .build()) .build(); + if (task.getAddress().getId() == null) { + task.setAddress(null); + } + return task; } catch (JsonProcessingException e) { throw new SQLException(e); } From 7f87986e6bcba08bdf7a0d62dffe4a3a395b5f8d Mon Sep 17 00:00:00 2001 From: Roopesh Gottipati Date: Mon, 1 May 2023 22:01:39 +0530 Subject: [PATCH 007/283] Add PGR specs --- .../contracts/complaints-v2.yaml | 570 ++++++++++++++++++ .../contracts/registries/individual.yml | 4 + 2 files changed, 574 insertions(+) create mode 100644 docs/health-api-specs/contracts/complaints-v2.yaml diff --git a/docs/health-api-specs/contracts/complaints-v2.yaml b/docs/health-api-specs/contracts/complaints-v2.yaml new file mode 100644 index 00000000000..0329de1a1d3 --- /dev/null +++ b/docs/health-api-specs/contracts/complaints-v2.yaml @@ -0,0 +1,570 @@ +openapi: 3.0.1 +info: + version: v2 + title: DIGIT Public Grievance Redressal(PGR) V2 + description: | + ### API specs for PGR ### + Application to Raise Grivances and track the progress. + . It allows any user registered in the system to raise a complaint (based on the Service definition provided in the master data, Please Refer MDMS service to Service Definition master) for any ulb belonging to the state. + . Notifications will be provided on progress of the complaint in evevry step. + . Feedback can be provided by the user once the compliant is resolved. + . If not satisfied the user can reopen the complaint. +paths: + + /v2/request/_search: + post: + tags: + - requests-api-controller + operationId: requestsSearchPost + requestBody: + content: + application/json: + schema: + type: object + properties: + requestInfoWrapper: + $ref: '#/components/schemas/RequestInfoWrapper' + criteria: + $ref: '#/components/schemas/RequestSearchCriteria' + required: true + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ServiceResponse' + /v2/request/_plainsearch: + post: + tags: + - requests-api-controller + operationId: requestsPlainSearchPost + requestBody: + content: + application/json: + schema: + type: object + properties: + requestInfoWrapper: + $ref: '#/components/schemas/RequestInfoWrapper' + requestSearchCriteria: + $ref: '#/components/schemas/RequestSearchCriteria' + required: true + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ServiceResponse' + /v2/request/_create: + post: + tags: + - requests-api-controller + operationId: requestsCreatePost + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ServiceRequest' + required: true + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ServiceResponse' + /v2/request/_update: + post: + tags: + - requests-api-controller + operationId: requestsUpdatePost + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ServiceRequest' + required: true + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/ServiceResponse' + /v2/request/_count: + post: + tags: + - requests-api-controller + operationId: requestsCountPost + requestBody: + content: + application/json: + schema: + type: object + properties: + requestInfoWrapper: + $ref: '#/components/schemas/RequestInfoWrapper' + criteria: + $ref: '#/components/schemas/RequestSearchCriteria' + required: true + responses: + '200': + description: OK + content: + '*/*': + schema: + $ref: '#/components/schemas/CountResponse' + /migration/_transform: + post: + tags: + - migration-controller + operationId: requestsCreatePost_1 + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/ServiceResponse' + required: true + responses: + '200': + description: OK + content: + '*/*': + schema: + type: object + additionalProperties: + type: object +components: + schemas: + Address: + type: object + properties: + tenantId: + type: string + description: Unique Identifier of the tenant to which user primarily belongs + doorNo: + type: string + description: House number or door number. + plotNo: + type: string + description: Plot number of the house. + id: + type: string + description: System generated id for the address + readOnly: true + landmark: + type: string + description: additional landmark to help locate the address + city: + type: string + description: City of the address. Can be represented by the tenantid itself + district: + type: string + description: The district in which the property is located + region: + type: string + description: The Region in which the property is located + state: + type: string + description: The State in which the property is located + country: + type: string + description: The Country in which the property is located + pincode: + type: string + description: PIN code of the address. Indian pincodes will usually be all numbers. + additionDetails: + type: object + description: more address detail as may be needed + buildingName: + type: string + description: Name of the building + maxLength: 64 + minLength: 2 + street: + type: string + description: Street Name + maxLength: 64 + minLength: 2 + locality: + $ref: '#/components/schemas/Boundary' + geoLocation: + $ref: '#/components/schemas/GeoLocation' + AuditDetails: + type: object + properties: + createdBy: + type: string + description: username (preferred) or userid of the user that created the object + lastModifiedBy: + type: string + description: username (preferred) or userid of the user that last modified the object + createdTime: + type: integer + format: int64 + description: epoch of the time object is created + lastModifiedTime: + type: integer + format: int64 + description: epoch of the time object is last modified + Boundary: + required: + - code + type: object + properties: + code: + type: string + description: code of the boundary. + name: + type: string + description: name of the boundary. + label: + type: string + description: localized label for the boundry. + latitude: + type: string + description: latitude of the boundary. + longitude: + type: string + description: longitude of the boundary. + children: + type: array + items: + $ref: '#/components/schemas/Boundary' + materializedPath: + type: string + description: materialized path of the boundary - this would be of the format tenantid.[code] from parentt till teh current boundary + Document: + type: object + description: This object holds list of documents attached during the transaciton for a property + properties: + id: + type: string + description: system id of the Document. + maximum: 64 + documentType: + type: string + description: unique document type code, should be validated with document type master + fileStoreId: + type: string + description: File store reference key. + documentUid: + type: string + description: The unique id(Pancard Number,Adhar etc.) of the given Document. + maxLength: 64 + additionalDetails: + type: object + description: The unique id(Pancard Number,Adhar etc.) of the given Document. + GeoLocation: + type: object + properties: + latitude: + type: number + format: double + description: latitude of the address + longitude: + type: number + format: double + description: longitude of the address + additionalDetails: + type: object + RequestInfo: + type: object + properties: + apiId: + type: string + ver: + type: string + ts: + type: integer + format: int64 + description: time in epoch + action: + type: string + description: API action to be performed like _create, _update, _search (denoting POST, PUT, GET) or _oauth etc + maxLength: 32 + did: + type: string + key: + type: string + description: API key (API key provided to the caller in case of server to server communication) + maxLength: 256 + msgId: + type: string + description: Unique request message id from the caller + maxLength: 256 + authToken: + type: string + description: token - the usual value that would go into HTTP bearer token + correlationId: + type: string + readOnly: true + userInfo: + $ref: '#/components/schemas/User' + Role: + type: object + properties: + id: + type: integer + format: int64 + name: + type: string + code: + type: string + tenantId: + type: string + Service: + required: + - address + - serviceCode + - source + - tenantId + type: object + properties: + active: + type: boolean + user: + $ref: '#/components/schemas/User' + id: + type: string + tenantId: + type: string + description: Unique identifier of the tenant. + minLength: 2 + maxLength: 64 + serviceCode: + type: string + description: Unique Code of the service defination (from service defination master) + minLength: 2 + maxLength: 64 + serviceRequestId: + type: string + readOnly: true + description: The unique formatted id for service request. + minLength: 2 + maxLength: 128 + description: + type: string + description: Additional information or description of the service request + minLength: 2 + maxLength: 256 + accountId: + type: string + description: userid of the user requesting the srervice - in our case it may be same as phone as we are using mobile number as the userid + minLength: 2 + maxLength: 64 + rating: + maximum: 5 + minimum: 1 + type: integer + format: int32 + additionalDetail: + type: object + description: This is the json object that will carry the actual input (whereever the metadata requries input). Structure should be same as the schema definition provided in the metadata of the service (schema compliance check to be performed at client/server) + applicationStatus: + type: string + description: The current status of the service request. + readOnly: true + source: + type: string + description: 'Source mdms master data. Which captures the source of the service request(ex:- whatsapp, ivr, Swachhata etc)' + minLength: 2 + maxLength: 64 + example: whatsapp, ivr etc + address: + $ref: '#/components/schemas/Address' + auditDetails: + $ref: '#/components/schemas/AuditDetails' + selfComplaint: + type: boolean + ServiceRequest: + required: + - RequestInfo + type: object + properties: + RequestInfo: + $ref: '#/components/schemas/RequestInfo' + service: + $ref: '#/components/schemas/Service' + workflow: + $ref: '#/components/schemas/Workflow' + User: + type: object + description: This is acting ID token of the authenticated user on the server. Any value provided by the clients will be ignored and actual user based on authtoken will be used on the server. + properties: + id: + type: integer + format: int64 + userName: + type: string + description: Unique user name of the authenticated user + name: + type: string + type: + type: string + mobileNumber: + type: string + emailId: + type: string + roles: + type: array + items: + $ref: '#/components/schemas/Role' + tenantId: + type: string + description: Unique Identifier of the tenant to which user primarily belongs + uuid: + type: string + description: System Generated User id of the authenticated user. + active: + type: boolean + Workflow: + type: object + description: BPA application object to capture the details of land, land owners, and address of the land. + properties: + action: + type: string + description: Action on the application in certain + minLength: 1 + maxLength: 64 + assignes: + type: array + + items: + type: string + comments: + type: string + description: Unique Identifier scrutinized number + minLength: 1 + maxLength: 64 + verificationDocuments: + type: array + description: Attach the workflow varification documents. + items: + $ref: '#/components/schemas/Document' + ResponseInfo: + type: object + properties: + apiId: + type: string + ver: + type: string + ts: + type: integer + format: int64 + resMsgId: + type: string + msgId: + type: string + status: + type: string + ServiceResponse: + type: object + properties: + responseInfo: + $ref: '#/components/schemas/ResponseInfo' + ServiceWrappers: + type: array + items: + $ref: '#/components/schemas/ServiceWrapper' + complaintsResolved: + type: integer + format: int32 + averageResolutionTime: + type: integer + format: int32 + complaintTypes: + type: integer + format: int32 + ServiceWrapper: + type: object + properties: + service: + $ref: '#/components/schemas/Service' + workflow: + $ref: '#/components/schemas/Workflow' + RequestInfoWrapper: + type: object + properties: + RequestInfo: + $ref: '#/components/schemas/RequestInfo' + RequestSearchCriteria: + type: object + properties: + empty: + type: boolean + tenantId: + type: string + tenantIds: + uniqueItems: true + type: array + items: + type: string + serviceCode: + uniqueItems: true + type: array + items: + type: string + applicationStatus: + uniqueItems: true + type: array + items: + type: string + mobileNumber: + type: string + serviceRequestId: + readOnly: true + description: The unique formatted id for service request. + minLength: 2 + maxLength: 128 + sortBy: + type: string + enum: + - locality + - applicationStatus + - serviceRequestId + sortOrder: + type: string + enum: + - ASC + - DESC + locality: + uniqueItems: true + type: array + items: + type: string + ids: + uniqueItems: true + type: array + items: + type: string + fromDate: + type: integer + format: int64 + toDate: + type: integer + format: int64 + slaDeltaMaxLimit: + type: integer + format: int64 + slaDeltaMinLimit: + type: integer + format: int64 + limit: + type: integer + format: int32 + offset: + type: integer + format: int32 + accountId: + type: string + CountResponse: + type: object + properties: + ResponseInfo: + $ref: '#/components/schemas/ResponseInfo' + count: + type: integer + format: int32 \ No newline at end of file diff --git a/docs/health-api-specs/contracts/registries/individual.yml b/docs/health-api-specs/contracts/registries/individual.yml index 50a2f79d37c..dac0f81f2a2 100644 --- a/docs/health-api-specs/contracts/registries/individual.yml +++ b/docs/health-api-specs/contracts/registries/individual.yml @@ -423,6 +423,10 @@ definitions: $ref: '#/definitions/additionalFields' isDeleted: $ref: '#/definitions/isDeleted' + isSystemUser: + type: boolean + description: Flag to indicate if the individual should be registered with Egov-user service + readOnly: true rowVersion: $ref: '#/definitions/rowVersion' auditDetails: From 82316c16191dd09085d26bac5c334a0b51440abe Mon Sep 17 00:00:00 2001 From: Roopesh Gottipati Date: Mon, 1 May 2023 22:04:07 +0530 Subject: [PATCH 008/283] Add PGR specs --- docs/health-api-specs/contracts/project.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/health-api-specs/contracts/project.yml b/docs/health-api-specs/contracts/project.yml index 08f9427db15..69c19b24a0a 100644 --- a/docs/health-api-specs/contracts/project.yml +++ b/docs/health-api-specs/contracts/project.yml @@ -1821,7 +1821,7 @@ definitions: RequestInfo: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo - Project: + Projects: type: array minItems: 1 items: @@ -1848,7 +1848,7 @@ definitions: ResponseInfo: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo - Project: + Projects: type: array items: $ref: '#/definitions/Project' From 653cadef1a837338e9478f0d3430e4346e6a69ba Mon Sep 17 00:00:00 2001 From: "anu.jaiswal" Date: Tue, 2 May 2023 16:25:46 +0530 Subject: [PATCH 009/283] [hlm-2706]: Revert service-request changes --- .../ServiceDefinitionRequestRepository.java | 2 +- .../validators/ServiceRequestValidator.java | 6 +++--- .../org/egov/servicerequest/web/models/Service.java | 12 ------------ .../web/models/ServiceDefinitionCriteria.java | 5 ----- .../main/V20230427045500__service_add_column_ddl.sql | 5 ----- .../servicerequest/helper/ServiceTestBuilder.java | 3 --- 6 files changed, 4 insertions(+), 29 deletions(-) delete mode 100644 core-services/service-request/src/main/resources/db/migration/main/V20230427045500__service_add_column_ddl.sql diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/repository/ServiceDefinitionRequestRepository.java b/core-services/service-request/src/main/java/org/egov/servicerequest/repository/ServiceDefinitionRequestRepository.java index 73771504ace..e805336b81a 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/repository/ServiceDefinitionRequestRepository.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/repository/ServiceDefinitionRequestRepository.java @@ -37,7 +37,7 @@ public List getServiceDefinitions(ServiceDefinitionSearchRequ List preparedStmtList = new ArrayList<>(); - if(CollectionUtils.isEmpty(criteria.getIds()) && ObjectUtils.isEmpty(criteria.getTenantId()) && ObjectUtils.isEmpty(criteria.getProjectId()) && CollectionUtils.isEmpty(criteria.getCode())) + if(CollectionUtils.isEmpty(criteria.getIds()) && ObjectUtils.isEmpty(criteria.getTenantId()) && CollectionUtils.isEmpty(criteria.getCode())) return new ArrayList<>(); // Fetch ids based on criteria if ids are not present 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 cf804b992b2..fc692f42310 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 @@ -55,7 +55,7 @@ public class ServiceRequestValidator { private Configuration config; public void validateServiceRequest(ServiceRequest serviceRequest){ - List serviceDefinitions = validateServiceDefID(serviceRequest.getService().getTenantId(), serviceRequest.getService().getServiceDefId(), serviceRequest.getService().getProjectId()); + List serviceDefinitions = validateServiceDefID(serviceRequest.getService().getTenantId(), serviceRequest.getService().getServiceDefId()); validateAttributeValuesAgainstServiceDefinition(serviceDefinitions.get(0), serviceRequest.getService()); validateAccountId(serviceRequest.getService()); } @@ -161,8 +161,8 @@ private void validateSize(Object value) { } } - private List validateServiceDefID(String tenantId, String serviceDefId, String projectId) { - List serviceDefinitions = serviceDefinitionRequestRepository.getServiceDefinitions(ServiceDefinitionSearchRequest.builder().serviceDefinitionCriteria(ServiceDefinitionCriteria.builder().tenantId(tenantId).projectId(projectId).ids(Arrays.asList(serviceDefId)).build()).build()); + private List validateServiceDefID(String tenantId, String serviceDefId) { + List serviceDefinitions = serviceDefinitionRequestRepository.getServiceDefinitions(ServiceDefinitionSearchRequest.builder().serviceDefinitionCriteria(ServiceDefinitionCriteria.builder().tenantId(tenantId).ids(Arrays.asList(serviceDefId)).build()).build()); if(serviceDefinitions.isEmpty()) throw new CustomException(SERVICE_REQUEST_INVALID_SERVICE_DEF_ID_CODE, SERVICE_REQUEST_INVALID_SERVICE_DEF_ID_MSG); 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 bf3f8d8840d..b0348458c15 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 @@ -32,18 +32,6 @@ public class Service { @NotNull @Size(min = 2, max = 64) private String tenantId = null; - @JsonProperty("projectId") - @NotNull - @Size(min = 2, max = 64) - private String projectId = null; - @JsonProperty("checkListName") - @NotNull - @Size(min = 2, max = 64) - private String checkListName = null; - @JsonProperty("supervisorLevel") - @NotNull - @Size(min = 2, max = 64) - private String supervisorLevel = null; @JsonProperty("serviceDefId") @NotNull diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinitionCriteria.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinitionCriteria.java index 7a9ba9b0bd8..4649d339bb1 100644 --- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinitionCriteria.java +++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinitionCriteria.java @@ -28,11 +28,6 @@ public class ServiceDefinitionCriteria { @Size(min = 2, max = 64) private String tenantId = null; - @JsonProperty("projectId") - @NotNull - @Size(min = 2, max = 64) - private String projectId = null; - @JsonProperty("ids") private List ids = null; diff --git a/core-services/service-request/src/main/resources/db/migration/main/V20230427045500__service_add_column_ddl.sql b/core-services/service-request/src/main/resources/db/migration/main/V20230427045500__service_add_column_ddl.sql deleted file mode 100644 index 6d0d04a8a91..00000000000 --- a/core-services/service-request/src/main/resources/db/migration/main/V20230427045500__service_add_column_ddl.sql +++ /dev/null @@ -1,5 +0,0 @@ -ALTER TABLE eg_service ADD COLUMN projectId character varying(64); -ALTER TABLE eg_service ADD COLUMN checkListName character varying(64); -ALTER TABLE eg_service ADD COLUMN supervisorLevel character varying(64); - - diff --git a/core-services/service-request/src/test/java/org/egov/servicerequest/helper/ServiceTestBuilder.java b/core-services/service-request/src/test/java/org/egov/servicerequest/helper/ServiceTestBuilder.java index a8b818effe8..763ededa33d 100644 --- a/core-services/service-request/src/test/java/org/egov/servicerequest/helper/ServiceTestBuilder.java +++ b/core-services/service-request/src/test/java/org/egov/servicerequest/helper/ServiceTestBuilder.java @@ -24,9 +24,6 @@ public Service build() { public ServiceTestBuilder withService() { this.builder.id("some-id") .tenantId("default") - .projectId("project-id") - .supervisorLevel("supervisor") - .checkListName("checkListName") .serviceDefId("service-def-id") .referenceId("reference-id") .attributes(Arrays.asList(AttributeValue.builder() From 0fc18ecb1865a1cf3ab88ac306de684c4c17d613 Mon Sep 17 00:00:00 2001 From: Roopesh Gottipati Date: Wed, 3 May 2023 14:19:03 +0530 Subject: [PATCH 010/283] Add PGR postman collection --- .../test/pgr-services.postman_collection.json | 309 ++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100644 core-services/pgr-services/src/test/pgr-services.postman_collection.json diff --git a/core-services/pgr-services/src/test/pgr-services.postman_collection.json b/core-services/pgr-services/src/test/pgr-services.postman_collection.json new file mode 100644 index 00000000000..7b0756b9d94 --- /dev/null +++ b/core-services/pgr-services/src/test/pgr-services.postman_collection.json @@ -0,0 +1,309 @@ +{ + "info": { + "_postman_id": "bbf398e2-eeac-407e-891a-cf4f89c22ad9", + "name": "pgr-services", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "24751924" + }, + "item": [ + { + "name": "pgr search", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{devAuth}}\",\n \"userInfo\": {\n \"id\": 93,\n \"uuid\": \"56b5c31b-b843-426c-b8d5-64a4c80286aa\",\n \"userName\": \"sysadmin\",\n \"name\": null,\n \"mobileNumber\": \"3989999999\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"CSR\",\n \"code\": \"CSR\",\n \"tenantId\": \"default\"\n },\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"default\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"default\",\n \"permanentCity\": null\n },\n \"msgId\": \"1683099938019|en_MZ\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{dev}}/pgr-services/v2/request/_search?serviceRequestId=PGR-2023-05-03-000193&tenantId=default", + "host": [ + "{{dev}}" + ], + "path": [ + "pgr-services", + "v2", + "request", + "_search" + ], + "query": [ + { + "key": "ids", + "value": "39a07047-9759-4503-91ad-14cbeaa8df20", + "disabled": true + }, + { + "key": "mobileNumber", + "value": "8004376134", + "disabled": true + }, + { + "key": "serviceCode", + "value": "StreetLightNotWorking", + "disabled": true + }, + { + "key": "limit", + "value": "10", + "disabled": true + }, + { + "key": "applicationStatus", + "value": "RESOLVED", + "disabled": true + }, + { + "key": "serviceRequestId", + "value": "PGR-2023-05-03-000193" + }, + { + "key": "sortBy", + "value": "serviceRequestId", + "disabled": true + }, + { + "key": "sortOrder", + "value": "ASC", + "disabled": true + }, + { + "key": "locality", + "value": "SUN04", + "disabled": true + }, + { + "key": "tenantId", + "value": "default" + } + ] + } + }, + "response": [] + }, + { + "name": "pgr create", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"service\": {\n \"active\": true,\n \"tenantId\": \"default\",\n \"serviceCode\": \"SyncNotWorking\",\n \"description\": \"sync issue\",\n \"applicationStatus\": \"CREATED\",\n \"source\": \"web\",\n \"user\": {\n \"userName\": \"3989999999\",\n \"name\": \"Syadmin\",\n \"type\": \"EMPLOYEE\",\n \"mobileNumber\": \"3989999999\",\n \"roles\": [],\n \"tenantId\": \"default\",\n \"uuid\": \"56b5c31b-b843-426c-b8d5-64a4c80286aa\",\n \"active\": true,\n \"isDeleted\": false,\n \"rowVersion\": 1,\n \"auditDetails\": {\n \"createdBy\": \"56b5c31b-b843-426c-b8d5-64a4c80286aa\",\n \"createdTime\": 1683072000,\n \"lastModifiedBy\": \"56b5c31b-b843-426c-b8d5-64a4c80286aa\",\n \"lastModifiedTime\": 1683072000\n }\n },\n \"isDeleted\": false,\n \"rowVersion\": 1,\n \"address\": {\n \"landmark\": \"\",\n \"buildingName\": \"\",\n \"street\": \"\",\n \"pincode\": \"\",\n \"locality\": {\n \"code\": \"VFTw0jbRf1y\",\n \"name\": \"CAVINA1\"\n },\n \"geoLocation\": {}\n },\n \"additionalDetail\": \"{\\\"supervisorName\\\":\\\"ad\\\",\\\"supervisorMobileNumber\\\":\\\"3333333333\\\"}\",\n \"auditDetails\": {\n \"createdBy\": \"56b5c31b-b843-426c-b8d5-64a4c80286aa\",\n \"createdTime\": 1683072000,\n \"lastModifiedBy\": \"56b5c31b-b843-426c-b8d5-64a4c80286aa\",\n \"lastModifiedTime\": 1683072000\n }\n },\n \"workflow\": {\n \"action\": \"CREATE\",\n \"assignes\": [],\n \"comments\": \"\"\n },\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{devAuth}}\",\n \"userInfo\": {\n \"id\": 93,\n \"uuid\": \"56b5c31b-b843-426c-b8d5-64a4c80286aa\",\n \"userName\": \"sysadmin\",\n \"name\": null,\n \"mobileNumber\": \"3989999999\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"CSR\",\n \"code\": \"CSR\",\n \"tenantId\": \"default\"\n },\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"default\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"default\",\n \"permanentCity\": null\n },\n \"msgId\": \"1683093762211|en_MZ\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{dev}}/pgr-services/v2/request/_create", + "host": [ + "{{dev}}" + ], + "path": [ + "pgr-services", + "v2", + "request", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "pgr update", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"{{devAuth}}\",\n \"userInfo\": {\n \"id\": 23287,\n \"uuid\": \"4632c941-cb1e-4b83-b2d4-200022c1a137\",\n \"userName\": \"PalashS\",\n \"name\": \"Palash S\",\n \"mobileNumber\": \"9949032246\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"PGR Last Mile Employee\",\n \"code\": \"PGR_LME\",\n \"tenantId\": \"pb.amritsar\"\n },\n {\n \"name\": \"Employee\",\n \"code\": \"EMPLOYEE\",\n \"tenantId\": \"pb\"\n },\n {\n \"name\": \"Employee\",\n \"code\": \"EMPLOYEE\",\n \"tenantId\": \"pb.amritsar\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"pb.amritsar\"\n }\n },\n \"service\": {\n \"active\": true,\n \"user\": {\n \"id\": 29678,\n \"userName\": \"9916210028\",\n \"name\": \"Vinoth Rallapalli\",\n \"type\": \"CITIZEN\",\n \"mobileNumber\": \"9916210028\",\n \"emailId\": \"ddd@fff.com\",\n \"roles\": [\n {\n \"id\": null,\n \"name\": \"Citizen\",\n \"code\": \"CITIZEN\",\n \"tenantId\": \"pb\"\n },\n {\n \"id\": null,\n \"name\": \"BPA Town Planner\",\n \"code\": \"BPA_TOWNPLANNER\",\n \"tenantId\": \"pb\"\n }\n ],\n \"tenantId\": \"pb\",\n \"uuid\": \"47babcd6-2823-43c2-a64f-bf146b6c408d\",\n \"active\": true\n },\n \"id\": \"a8143375-bd9b-4eea-bf45-68996f676fc9\",\n \"tenantId\": \"pb.amritsar\",\n \"serviceCode\": \"OverflowingOrBlockedDrain\",\n \"serviceRequestId\": \"PB-PGR-2021-09-14-001175\",\n \"description\": \"overflowing drain\",\n \"accountId\": \"47babcd6-2823-43c2-a64f-bf146b6c408d\",\n \"rating\": null,\n \"additionalDetail\": {\n \"sdsadsadsad\": \"asdsadsadsadsa\"\n },\n \"applicationStatus\": \"PENDINGFORASSIGNMENT\",\n \"source\": \"whatsapp\",\n \"address\": {\n \"tenantId\": \"pb.amritsar\",\n \"doorNo\": \"2\",\n \"plotNo\": \"10\",\n \"id\": \"c073f0eb-c8bd-484b-ae20-d7c87321bec0\",\n \"landmark\": \"Near City Hall\",\n \"city\": \"Amritsar\",\n \"district\": \"Amritsar\",\n \"region\": \"Amritsar\",\n \"state\": \"Punjab\",\n \"country\": \"India\",\n \"pincode\": \"111111\",\n \"additionDetails\": null,\n \"buildingName\": \"Safalya\",\n \"street\": \"10th main\",\n \"locality\": {\n \"code\": \"SUN01\",\n \"name\": null,\n \"label\": null,\n \"latitude\": null,\n \"longitude\": null,\n \"children\": null,\n \"materializedPath\": null\n },\n \"geoLocation\": {\n \"latitude\": 21.0,\n \"longitude\": 56.0,\n \"additionalDetails\": null\n }\n },\n \"auditDetails\": {\n \"createdBy\": \"47babcd6-2823-43c2-a64f-bf146b6c408d\",\n \"lastModifiedBy\": \"47babcd6-2823-43c2-a64f-bf146b6c408d\",\n \"createdTime\": 1631603018031,\n \"lastModifiedTime\": 1631603018031\n }\n },\n \"workflow\": {\n \"action\": \"ASSIGN\",\n \"assignes\": [\"4632c941-cb1e-4b83-b2d4-200022c1a137\"],\n \"comments\": \"Drain Overflowing. Please check\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{dev}}/pgr-services/v2/request/_update", + "host": [ + "{{dev}}" + ], + "path": [ + "pgr-services", + "v2", + "request", + "_update" + ], + "query": [ + { + "key": null, + "value": "", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "count API", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"ver\": \".01\",\n \"action\": \"\",\n \"did\": \"1\",\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"authToken\": \"{{devAuth}}\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{dev}}/pgr-services/v2/request/_count?tenantId=pb.amritsar&applicationStatus=REJECTED", + "host": [ + "{{dev}}" + ], + "path": [ + "pgr-services", + "v2", + "request", + "_count" + ], + "query": [ + { + "key": "tenantId", + "value": "pb.amritsar" + }, + { + "key": "serviceCode", + "value": "StreetLightNotWorking", + "disabled": true + }, + { + "key": "applicationStatus", + "value": "REJECTED" + } + ] + } + }, + "response": [] + }, + { + "name": "pgr old plain search", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"ver\": \".01\",\n \"action\": \"\",\n \"did\": \"1\",\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"authToken\": \"{{devAuth}}\",\n \"userInfo\": {\n \"id\": 23349,\n \"userName\": \"9404052047\",\n \"salutation\": null,\n \"name\": \"at\",\n \"gender\": \"MALE\",\n \"mobileNumber\": \"9404052047\",\n \"emailId\": \"xc@gmail.com\",\n \"altContactNumber\": null,\n \"pan\": null,\n \"aadhaarNumber\": null,\n \"permanentAddress\": \",,,lucknow,lucknow\",\n \"permanentCity\": \"jalandhar\",\n \"permanentPinCode\": \"343434\",\n \"correspondenceAddress\": \"address \",\n \"correspondenceCity\": null,\n \"correspondencePinCode\": null,\n \"active\": true,\n \"locale\": null,\n \"type\": \"CITIZEN\",\n \"accountLocked\": false,\n \"accountLockedDate\": 0,\n \"fatherOrHusbandName\": \"st\",\n \"signature\": null,\n \"bloodGroup\": null,\n \"photo\": null,\n \"identificationMark\": null,\n \"createdBy\": 23311,\n \"lastModifiedBy\": 1,\n \"tenantId\": \"pb\",\n \"roles\": [\n {\n \"code\": \"CITIZEN\",\n \"name\": \"Citizen\",\n \"tenantId\": \"pb\"\n }\n ],\n \"uuid\": \"530968f3-76b3-4fd1-b09d-9e22eb1f85df\",\n \"createdDate\": \"05-07-2018 11:42:01\",\n \"lastModifiedDate\": \"25-03-2020 01:47:14\",\n \"dob\": \"1993-02-25\",\n \"pwdExpiryDate\": \"04-10-2018 04:12:00\"\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{local}}/rainmaker-pgr/v1/requests/_plainsearch?offset=0&noOfRecords=10&tenantId=pb.phagwara", + "host": [ + "{{local}}" + ], + "path": [ + "rainmaker-pgr", + "v1", + "requests", + "_plainsearch" + ], + "query": [ + { + "key": "offset", + "value": "0" + }, + { + "key": "noOfRecords", + "value": "10" + }, + { + "key": "tenantId", + "value": "pb.phagwara" + } + ] + } + }, + "response": [] + }, + { + "name": "transform", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"ResponseInfo\": {\n \"apiId\": \"Rainmaker\",\n \"ver\": \".01\",\n \"ts\": null,\n \"resMsgId\": \"uief87324\",\n \"msgId\": \"20170310130900|en_IN\",\n \"status\": \"successful\"\n },\n \"services\": [\n {\n \"citizen\": {\n \"id\": 23914,\n \"uuid\": \"206f4c7b-ab04-4730-acc7-4aa0d29506e6\",\n \"name\": \"name .updat\",\n \"mobileNumber\": \"9987106368\",\n \"aadhaarNumber\": null,\n \"pan\": null,\n \"emailId\": \"xvyz@gmail.com\",\n \"userName\": \"9987106368\",\n \"password\": null,\n \"active\": true,\n \"type\": \"CITIZEN\",\n \"gender\": \"MALE\",\n \"tenantId\": \"pb\",\n \"permanentAddress\": \"PB_AMRITSAR_REVENUE_SUN18, amritsar\",\n \"roles\": [\n {\n \"name\": \"Citizen\",\n \"code\": \"CITIZEN\",\n \"tenantId\": \"pb\"\n }\n ]\n },\n \"tenantId\": \"pb.jalandhar\",\n \"serviceCode\": \"DamagedGarbageBin\",\n \"serviceRequestId\": \"04/03/2020/006099\",\n \"description\": \"3\",\n \"addressId\": \"da8af2cd-cdfa-489e-8828-bce515d41f61\",\n \"accountId\": \"23914\",\n \"phone\": \"9987106368\",\n \"addressDetail\": {\n \"uuid\": \"da8af2cd-cdfa-489e-8828-bce515d41f61\",\n \"mohalla\": \"JLC468\",\n \"locality\": \"GTB Nagar\",\n \"city\": \"pb.jalandhar\",\n \"tenantId\": \"pb.jalandhar\"\n },\n \"active\": true,\n \"status\": \"assigned\",\n \"source\": \"whatsapp\",\n \"auditDetails\": {\n \"createdBy\": \"23914\",\n \"lastModifiedBy\": \"23370\",\n \"createdTime\": 1583314541457,\n \"lastModifiedTime\": 1583327412746\n }\n }\n ],\n \"actionHistory\": [\n {\n \"actions\": [\n {\n \"uuid\": \"261f5bea-b293-493c-8572-d4af6b807981\",\n \"tenantId\": \"pb.jalandhar\",\n \"by\": \"23370:GRO\",\n \"when\": 1583327412746,\n \"businessKey\": \"04/03/2020/006099\",\n \"action\": \"assign\",\n \"status\": \"assigned\",\n \"assignee\": \"28258\"\n },\n {\n \"uuid\": \"6c87870a-48ce-4d1d-9fa8-a8649a6e9add\",\n \"tenantId\": \"pb.jalandhar\",\n \"by\": \"23370:GRO\",\n \"when\": 1583327361714,\n \"businessKey\": \"04/03/2020/006099\",\n \"comments\": \"dff\"\n },\n {\n \"uuid\": \"b78255ef-333a-4419-bbbb-962becaa2a5c\",\n \"tenantId\": \"pb.jalandhar\",\n \"by\": \"23914:BPA Architect\",\n \"when\": 1583314541457,\n \"businessKey\": \"04/03/2020/006099\",\n \"action\": \"open\",\n \"status\": \"open\",\n \"media\": [\n \"https://minio-egov-micro-dev.egovernments.org/egov-rainmaker/pb/chatbot/March/4/1583314533928pgr-whatsapp-1583314533825.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20201014%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20201014T052552Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=360c179db1c6d21e95146a31a1b68a39b09e7b96e15cc881357289dac89e8771,https://minio-egov-micro-dev.egovernments.org/egov-rainmaker/pb/chatbot/March/4/1583314533928pgr-whatsapp-1583314533825_large.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20201014%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20201014T052552Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=3188d9d15e1ff94e459cdcef93c116621a26bb34f9b89183192273ebd8b97981,https://minio-egov-micro-dev.egovernments.org/egov-rainmaker/pb/chatbot/March/4/1583314533928pgr-whatsapp-1583314533825_medium.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20201014%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20201014T052552Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=681373c0758c92a6d00e30ef2c36ff58384de030c021599908305909ca70e79e,https://minio-egov-micro-dev.egovernments.org/egov-rainmaker/pb/chatbot/March/4/1583314533928pgr-whatsapp-1583314533825_small.png?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAIOSFODNN7EXAMPLE%2F20201014%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20201014T052552Z&X-Amz-Expires=86400&X-Amz-SignedHeaders=host&X-Amz-Signature=89eab9c8e2e3fdff1039d0a95fce4fce1f3c5d2c6248b9577877a52d14565fc1\"\n ]\n }\n ]\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{local}}/pgr-services/migration/_transform", + "host": [ + "{{local}}" + ], + "path": [ + "pgr-services", + "migration", + "_transform" + ] + } + }, + "response": [] + }, + { + "name": "pgr migration", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"{{devAuth}}\",\n \"userInfo\": {\n \"id\": 23287,\n \"uuid\": \"4632c941-cb1e-4b83-b2d4-200022c1a137\",\n \"userName\": \"PalashS\",\n \"name\": \"Palash S\",\n \"mobileNumber\": \"9949032246\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"PGR Last Mile Employee\",\n \"code\": \"PGR_LME\",\n \"tenantId\": \"pb.amritsar\"\n },\n {\n \"name\": \"Employee\",\n \"code\": \"EMPLOYEE\",\n \"tenantId\": \"pb\"\n },\n {\n \"name\": \"Employee\",\n \"code\": \"EMPLOYEE\",\n \"tenantId\": \"pb.amritsar\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"pb.amritsar\"\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8083/rainmaker-pgr/v2/_migrate?tenantIds=pb.bathinda&serviceRequestIds=17/12/2018/005891", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8083", + "path": [ + "rainmaker-pgr", + "v2", + "_migrate" + ], + "query": [ + { + "key": "tenantIds", + "value": "pb.bathinda" + }, + { + "key": "serviceRequestIds", + "value": "17/12/2018/005891" + } + ] + } + }, + "response": [] + } + ] +} \ No newline at end of file From e1ecf4ffd7c7ac842d5f38306762b0d349d31df9 Mon Sep 17 00:00:00 2001 From: Roopesh Gottipati Date: Wed, 3 May 2023 14:25:19 +0530 Subject: [PATCH 011/283] Add PGR postman collection --- .../{ => resources/postman}/pgr-services.postman_collection.json | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename core-services/pgr-services/src/test/{ => resources/postman}/pgr-services.postman_collection.json (100%) diff --git a/core-services/pgr-services/src/test/pgr-services.postman_collection.json b/core-services/pgr-services/src/test/resources/postman/pgr-services.postman_collection.json similarity index 100% rename from core-services/pgr-services/src/test/pgr-services.postman_collection.json rename to core-services/pgr-services/src/test/resources/postman/pgr-services.postman_collection.json From 2ad7482dbd9ae1551a5697281122fe9ae068357b Mon Sep 17 00:00:00 2001 From: Neelakantan S <118709917+neel-tw@users.noreply.github.com> Date: Wed, 3 May 2023 19:19:51 +0530 Subject: [PATCH 012/283] Fix filler limits for prediction line chart --- .../com/tarento/analytics/handler/LineChartResponseHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/LineChartResponseHandler.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/LineChartResponseHandler.java index e72d706caba..51a956346ad 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/LineChartResponseHandler.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/LineChartResponseHandler.java @@ -240,7 +240,7 @@ public AggregateDto translate(AggregateRequestDto requestDto, ObjectNode aggrega private void appendActualPlot(List actualEpochKeys, Long finalStartDate, Data data, String symbol, boolean isCumulative) { Long actualStartDate = actualEpochKeys.get(0); Double differenceInDays = Math.ceil((actualStartDate - finalStartDate) / Constants.DAY_EPOCH); - for (int i = 0; i < differenceInDays; i++) { + for (int i = 0; i < differenceInDays + 1; i++) { String name = getIntervalKey(String.valueOf(finalStartDate + Constants.DAY_EPOCH*i), Constants.Interval.day); data.getPlots().add(i,new Plot(name,0.0,symbol)); } From 82ba9196e71ad7000002670e61f8ff3126dd7eb3 Mon Sep 17 00:00:00 2001 From: "anu.jaiswal" Date: Wed, 3 May 2023 19:49:14 +0530 Subject: [PATCH 013/283] [hlm-2706]: Added ServiceDefinitionService for transformer service and updated ServiceTaskConsumer --- .../config/TransformerProperties.java | 6 ++ .../consumer/ServiceTaskConsumer.java | 12 +-- .../service/ServiceDefinitionService.java | 84 +++++++++++++++++++ .../ServiceTaskTransformationService.java | 20 +++-- .../src/main/resources/application.properties | 6 +- 5 files changed, 117 insertions(+), 11 deletions(-) create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/service/ServiceDefinitionService.java diff --git a/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java b/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java index 6ba02445332..2801294e64f 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java @@ -47,6 +47,12 @@ public class TransformerProperties { @Value("${egov.search.facility.url}") private String facilitySearchUrl; + @Value("${egov.search.servicedefinition.url}") + private String serviceDefinitionSearchUrl; + + @Value("${egov.servicedefinition.host}") + private String serviceDefinitionHost; + @Value("${search.api.limit:100}") private String searchApiLimit; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/consumer/ServiceTaskConsumer.java b/health-services/transformer/src/main/java/org/egov/transformer/consumer/ServiceTaskConsumer.java index 2987bad952e..7037d3deb90 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/consumer/ServiceTaskConsumer.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/consumer/ServiceTaskConsumer.java @@ -4,6 +4,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.kafka.clients.consumer.ConsumerRecord; import org.egov.servicerequest.web.models.Service; +import org.egov.servicerequest.web.models.ServiceRequest; import org.egov.transformer.enums.Operation; import org.egov.transformer.handler.TransformationHandler; import org.springframework.beans.factory.annotation.Autowired; @@ -15,6 +16,7 @@ import java.util.Arrays; import java.util.List; +import java.util.stream.Collectors; @Component @Slf4j @@ -31,13 +33,13 @@ public ServiceTaskConsumer(TransformationHandler transformationHandler, } @KafkaListener(topics = {"${transformer.consumer.create.service.topic}"}) - public void consumeStaff(ConsumerRecord payload, + public void consumeServiceTask(ConsumerRecord payload, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { - List payloadList = Arrays.asList(objectMapper - .readValue((String) payload.value(), - Service[].class)); - transformationHandler.handle(payloadList, Operation.SERVICE); + List payloadList = Arrays.asList(objectMapper + .readValue((String) payload.value(), ServiceRequest.class)); + List collect = payloadList.stream().map(p -> p.getService()).collect(Collectors.toList()); + transformationHandler.handle(collect, Operation.SERVICE); } catch (Exception exception) { log.error("error in service task consumer", exception); } diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceDefinitionService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceDefinitionService.java new file mode 100644 index 00000000000..e920f7b38bb --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceDefinitionService.java @@ -0,0 +1,84 @@ +package org.egov.transformer.service; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.request.User; +import org.egov.servicerequest.web.models.ServiceDefinition; +import org.egov.servicerequest.web.models.ServiceDefinitionCriteria; +import org.egov.servicerequest.web.models.ServiceDefinitionResponse; +import org.egov.servicerequest.web.models.ServiceDefinitionSearchRequest; +import org.egov.tracer.model.CustomException; +import org.egov.transformer.config.TransformerProperties; +import org.egov.transformer.http.client.ServiceRequestClient; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Component +@Slf4j +public class ServiceDefinitionService { + + + private final TransformerProperties transformerProperties; + private final ServiceRequestClient serviceRequestClient; + private static final Map serviceMap = new ConcurrentHashMap<>(); + + + public ServiceDefinitionService( TransformerProperties transformerProperties, ServiceRequestClient serviceRequestClient) { + + + this.transformerProperties = transformerProperties; + + this.serviceRequestClient = serviceRequestClient; + } + + public ServiceDefinition getServiceDefinition(String serviceDefId, String tenantId) { + + if (serviceMap.containsKey(serviceDefId)) { + log.info("getting project {} from cache",serviceDefId); + return serviceMap.get(serviceDefId); + } + List serviceDefinitionList = searchServiceDefinition(serviceDefId, tenantId); + ServiceDefinition serviceDefinition=null; + if (!serviceDefinitionList.isEmpty()) { + serviceDefinition = serviceDefinitionList.get(0); + serviceMap.put(serviceDefId, serviceDefinition); + } + return serviceDefinition; + } + + private List searchServiceDefinition(String serviceDefId, String tenantId) { + + ServiceDefinitionSearchRequest request = ServiceDefinitionSearchRequest.builder() + .serviceDefinitionCriteria(ServiceDefinitionCriteria.builder().ids(Collections.singletonList(serviceDefId)).tenantId(tenantId).build()) + .requestInfo(RequestInfo.builder() + .userInfo(User.builder() + .uuid("transformer-uuid") + .build()) + .build()) + .build(); + + + ServiceDefinitionResponse response; + try { + StringBuilder uri = new StringBuilder(); + uri.append(transformerProperties.getServiceDefinitionHost()) + .append(transformerProperties.getServiceDefinitionSearchUrl()) + .append("?limit=").append(transformerProperties.getSearchApiLimit()) + .append("&offset=0") + .append("&ids=").append(serviceDefId) + .append("&tenantId=").append(tenantId); + response = serviceRequestClient.fetchResult(uri, + request, + ServiceDefinitionResponse.class); + } catch (Exception e) { + log.error("error while fetching serviceDefinition list", e); + throw new CustomException("ServiceDefinition_FETCH_ERROR", + "error while fetching service details for id: " + serviceDefId); + } + return response.getServiceDefinition(); + } +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java index 7362a4946bc..635c126c887 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java @@ -3,6 +3,7 @@ import lombok.extern.slf4j.Slf4j; import org.egov.servicerequest.web.models.Service; +import org.egov.servicerequest.web.models.ServiceDefinition; import org.egov.transformer.config.TransformerProperties; import org.egov.transformer.enums.Operation; import org.egov.transformer.models.downstream.ServiceTaskIndexV1; @@ -58,28 +59,37 @@ static class ServiceTaskIndexV1Transformer implements Transformer { private final ProjectService projectService; private final TransformerProperties properties; + private final ServiceDefinitionService serviceDefinitionService; @Autowired - ServiceTaskIndexV1Transformer(ProjectService projectService, TransformerProperties properties) { + ServiceTaskIndexV1Transformer(ProjectService projectService, TransformerProperties properties, ServiceDefinitionService serviceDefinitionService) { + this.projectService = projectService; this.properties = properties; + this.serviceDefinitionService = serviceDefinitionService; } @Override public List transform(Service service) { + + ServiceDefinition serviceDefinition = serviceDefinitionService.getServiceDefinition(service.getServiceDefId(), service.getTenantId()); + String[] parts = serviceDefinition.getCode().split("\\."); + String projectId = parts[0]; + String supervisorLevel = parts[2]; Map boundaryLabelToNameMap = projectService - .getBoundaryLabelToNameMap(service.getProjectId(), service.getTenantId()); + .getBoundaryLabelToNameMap(projectId, service.getTenantId()); log.info("boundary labels {}", boundaryLabelToNameMap.toString()); return Collections.singletonList(ServiceTaskIndexV1.builder() .id(service.getId()) - .projectId(service.getProjectId()) + .projectId(projectId) .serviceDefinitionId(service.getServiceDefId()) - .supervisorLevel(service.getSupervisorLevel()) - .checklistName(service.getCheckListName()) + .supervisorLevel(supervisorLevel) + .checklistName(serviceDefinition.getCode()) .province(boundaryLabelToNameMap.get(properties.getProvince())) .district(boundaryLabelToNameMap.get(properties.getDistrict())) .createdTime(service.getAuditDetails().getCreatedTime()) .createdBy(service.getAuditDetails().getCreatedBy()) + .tenantId(service.getTenantId()) .build()); } } diff --git a/health-services/transformer/src/main/resources/application.properties b/health-services/transformer/src/main/resources/application.properties index 1b23bbd7841..d925cc6dc8e 100644 --- a/health-services/transformer/src/main/resources/application.properties +++ b/health-services/transformer/src/main/resources/application.properties @@ -1,5 +1,5 @@ server.servlet.context-path=/transformer -server.port=8080 +server.port=8081 app.timezone=UTC # REDIS CONFIG @@ -79,6 +79,9 @@ transformer.producer.service.task.index.v1.topic=transformer-producer-service-ta egov.project.host=http://localhost:8083 egov.search.project.url=/project/v1/_search +egov.servicedefinition.host=http://localhost:8280 +egov.search.servicedefinition.url=/service-request/service/definition/v1/_search + #egov.location.host=https://health-dev.digit.org egov.location.host=http://localhost:8085 egov.location.endpoint=/egov-location/location/v11/boundarys/_search @@ -91,6 +94,7 @@ project.mdms.module=HCM-PROJECT-TYPES egov.facility.host=http://localhost:8084 egov.search.facility.url=/facility/v1/_search + transformer.consumer.bulk.create.facility.topic=save-facility-topic transformer.consumer.bulk.update.facility.topic=update-facility-topic From dee293873af3bed90f5ba2cd77369d88cb9a7ea8 Mon Sep 17 00:00:00 2001 From: "anu.jaiswal" Date: Thu, 4 May 2023 12:13:33 +0530 Subject: [PATCH 014/283] [hlm-2706]: Updated name of basePackages in MainConfiguration of transformer service --- .../java/org/egov/transformer/config/MainConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java b/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java index 83c3fee5d39..62d56c1dea1 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java @@ -33,7 +33,7 @@ @Import({TracerConfiguration.class}) @Configuration -@ComponentScan(basePackages = {"org.egov"}) +@ComponentScan(basePackages = {"org.egov.transformer.producer"}) @Slf4j public class MainConfiguration { From 70881dc8f7a41de0e4f4e6e0ce911d20f7d41fac Mon Sep 17 00:00:00 2001 From: Shiva Burade Date: Fri, 5 May 2023 13:40:39 +0530 Subject: [PATCH 015/283] [hlm-2706]: Service task transformer --- health-services/transformer/pom.xml | 7 +- .../transformer/config/MainConfiguration.java | 2 +- .../consumer/ServiceTaskConsumer.java | 4 +- .../ServiceTaskTransformationHandler.java | 2 +- ...ceTaskIndexV1.java => ServiceIndexV1.java} | 5 +- .../models/upstream/AttributeDefinition.java | 125 ++++++++++++++++++ .../models/upstream/AttributeValue.java | 47 +++++++ .../models/upstream/Pagination.java | 75 +++++++++++ .../transformer/models/upstream/Service.java | 72 ++++++++++ .../models/upstream/ServiceDefinition.java | 66 +++++++++ .../upstream/ServiceDefinitionCriteria.java | 57 ++++++++ .../upstream/ServiceDefinitionResponse.java | 45 +++++++ .../ServiceDefinitionSearchRequest.java | 37 ++++++ .../models/upstream/ServiceRequest.java | 33 +++++ .../transformer/service/ProjectService.java | 50 +++++++ .../service/ServiceDefinitionService.java | 8 +- ...rviceTaskIndexV1TransformationService.java | 12 +- .../ServiceTaskTransformationService.java | 20 +-- 18 files changed, 635 insertions(+), 32 deletions(-) rename health-services/transformer/src/main/java/org/egov/transformer/models/downstream/{ServiceTaskIndexV1.java => ServiceIndexV1.java} (96%) create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeDefinition.java create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeValue.java create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Pagination.java create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Service.java create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinition.java create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionCriteria.java create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionResponse.java create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionSearchRequest.java create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceRequest.java diff --git a/health-services/transformer/pom.xml b/health-services/transformer/pom.xml index e1ea8e6a417..2707beb0358 100644 --- a/health-services/transformer/pom.xml +++ b/health-services/transformer/pom.xml @@ -75,9 +75,10 @@ validation-api - org.egov - service-request - 1.0.0 + io.swagger.core.v3 + swagger-annotations + 2.2.8 + compile diff --git a/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java b/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java index 62d56c1dea1..82de303328d 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java @@ -12,9 +12,9 @@ import org.egov.common.models.project.ProjectStaff; import org.egov.common.models.project.Task; import org.egov.common.models.stock.Stock; -import org.egov.servicerequest.web.models.Service; import org.egov.tracer.config.TracerConfiguration; import org.egov.transformer.enums.Operation; +import org.egov.transformer.models.upstream.Service; import org.egov.transformer.service.TransformationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/consumer/ServiceTaskConsumer.java b/health-services/transformer/src/main/java/org/egov/transformer/consumer/ServiceTaskConsumer.java index 7037d3deb90..9f710b5a18e 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/consumer/ServiceTaskConsumer.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/consumer/ServiceTaskConsumer.java @@ -3,10 +3,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.apache.kafka.clients.consumer.ConsumerRecord; -import org.egov.servicerequest.web.models.Service; -import org.egov.servicerequest.web.models.ServiceRequest; import org.egov.transformer.enums.Operation; import org.egov.transformer.handler.TransformationHandler; +import org.egov.transformer.models.upstream.Service; +import org.egov.transformer.models.upstream.ServiceRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.kafka.annotation.KafkaListener; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/handler/ServiceTaskTransformationHandler.java b/health-services/transformer/src/main/java/org/egov/transformer/handler/ServiceTaskTransformationHandler.java index 142313ff82b..ec312b14498 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/handler/ServiceTaskTransformationHandler.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/handler/ServiceTaskTransformationHandler.java @@ -1,7 +1,7 @@ package org.egov.transformer.handler; -import org.egov.servicerequest.web.models.Service; import org.egov.transformer.enums.Operation; +import org.egov.transformer.models.upstream.Service; import org.egov.transformer.service.TransformationService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ServiceTaskIndexV1.java b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ServiceIndexV1.java similarity index 96% rename from health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ServiceTaskIndexV1.java rename to health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ServiceIndexV1.java index da9db21ff21..2383bde4eae 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ServiceTaskIndexV1.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ServiceIndexV1.java @@ -12,7 +12,7 @@ @NoArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class ServiceTaskIndexV1 { +public class ServiceIndexV1 { @JsonProperty("id") private String id; @JsonProperty("createdTime") @@ -33,7 +33,4 @@ public class ServiceTaskIndexV1 { private String district; @JsonProperty("tenantId") private String tenantId; - - - } diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeDefinition.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeDefinition.java new file mode 100644 index 00000000000..61158560897 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeDefinition.java @@ -0,0 +1,125 @@ +package org.egov.transformer.models.upstream; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import digit.models.coremodels.AuditDetails; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.ArrayList; +import java.util.List; + +/** + * Hold the attribute definition fields details as json object. + */ +@Schema(description = "Hold the attribute definition fields details as json object.") +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AttributeDefinition { + @JsonProperty("id") + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("referenceId") + @Size(min = 2, max = 64) + private String referenceId = null; + + @JsonProperty("tenantId") + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("code") + @NotNull + @Size(min = 2, max = 64) + private String code = null; + + /** + * defines the attribute type + */ + public enum DataTypeEnum { + STRING("String"), + + NUMBER("Number"), + + TEXT("Text"), + + DATETIME("Datetime"), + + SINGLEVALUELIST("SingleValueList"), + + MULTIVALUELIST("MultiValueList"), + + FILE("File"); + + private String value; + + DataTypeEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static DataTypeEnum fromValue(String text) { + for (DataTypeEnum b : DataTypeEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + + @JsonProperty("dataType") + @NotNull + private DataTypeEnum dataType = null; + + @JsonProperty("values") + private List values = null; + + @JsonProperty("isActive") + @NotNull + private Boolean isActive = true; + + @JsonProperty("required") + private Boolean required = null; + + @JsonProperty("regex") + @Size(min = 2, max = 64) + private String regex = null; + + @JsonProperty("order") + private String order = null; + + @JsonProperty("auditDetails") + @Valid + private AuditDetails auditDetails = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + + public AttributeDefinition addValuesItem(String valuesItem) { + if (this.values == null) { + this.values = new ArrayList<>(); + } + this.values.add(valuesItem); + return this; + } + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeValue.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeValue.java new file mode 100644 index 00000000000..22a1ec2b90a --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeValue.java @@ -0,0 +1,47 @@ +package org.egov.transformer.models.upstream; + +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +/** + * Hold the attribute details as object. + */ +@Schema(description = "Hold the attribute details as object.") +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AttributeValue { + @JsonProperty("id") + private String id = null; + + @JsonProperty("referenceId") + @Size(min = 2, max = 64) + private String referenceId = null; + + @JsonProperty("attributeCode") + @NotNull + private String attributeCode = null; + + @JsonProperty("value") + @NotNull + private Object value = null; + + @JsonProperty("auditDetails") + @Valid + private AuditDetails auditDetails = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Pagination.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Pagination.java new file mode 100644 index 00000000000..85993c9ca34 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Pagination.java @@ -0,0 +1,75 @@ +package org.egov.transformer.models.upstream; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; + +/** + * Pagination details + */ +@Schema(description = "Pagination details") +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Pagination { + @JsonProperty("limit") + @Valid + private Integer limit = new Integer(10); + + @JsonProperty("offset") + @Valid + private Integer offset = new Integer(0); + + @JsonProperty("totalCount") + @Valid + private Long totalCount = null; + + @JsonProperty("sortBy") + private String sortBy = null; + + /** + * Sorting order + */ + public enum OrderEnum { + ASC("asc"), + + DESC("desc"); + + private String value; + + OrderEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static OrderEnum fromValue(String text) { + for (OrderEnum b : OrderEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + + @JsonProperty("order") + private OrderEnum order = null; + + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Service.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Service.java new file mode 100644 index 00000000000..bb57d9835c7 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Service.java @@ -0,0 +1,72 @@ +package org.egov.transformer.models.upstream; + +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.ArrayList; +import java.util.List; + +/** + * Hold the Service field details as json object. + */ +@Schema(description = "Hold the Service field details as json object.") +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Service { + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("serviceDefId") + @NotNull + @Size(min = 2, max = 64) + private String serviceDefId = null; + + @JsonProperty("referenceId") + @Size(min = 2, max = 64) + private String referenceId = null; + + @JsonProperty("attributes") + @NotNull + @Valid + private List attributes = new ArrayList<>(); + + @JsonProperty("auditDetails") + @Valid + private AuditDetails auditDetails = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("accountId") + @NotNull + @Size(max = 64) + private String accountId = null; + + @JsonProperty("clientId") + @Size(max = 64) + private String clientId = null; + + + public Service addAttributesItem(AttributeValue attributesItem) { + this.attributes.add(attributesItem); + return this; + } + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinition.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinition.java new file mode 100644 index 00000000000..b3332ef5aa0 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinition.java @@ -0,0 +1,66 @@ +package org.egov.transformer.models.upstream; + +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.ArrayList; +import java.util.List; + +/** + * Holds the Service Definition details json object. + */ +@Schema(description = "Holds the Service Definition details json object.") +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ServiceDefinition { + @JsonProperty("id") + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("tenantId") + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("code") + @NotNull + @Size(min = 2, max = 64) + private String code = null; + + @JsonProperty("isActive") + private Boolean isActive = true; + + @JsonProperty("attributes") + @NotNull + @Valid + private List attributes = new ArrayList<>(); + + @JsonProperty("auditDetails") + @Valid + private AuditDetails auditDetails = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("clientId") + @Size(max = 64) + private String clientId = null; + + + public ServiceDefinition addAttributesItem(AttributeDefinition attributesItem) { + this.attributes.add(attributesItem); + return this; + } + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionCriteria.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionCriteria.java new file mode 100644 index 00000000000..3fb59965472 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionCriteria.java @@ -0,0 +1,57 @@ +package org.egov.transformer.models.upstream; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.ArrayList; +import java.util.List; + +/** + * The object will contain all the search parameters for Service Definition. + */ +@Schema(description = "The object will contain all the search parameters for Service Definition.") +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ServiceDefinitionCriteria { + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("ids") + private List ids = null; + + @JsonProperty("code") + private List code = null; + + @JsonProperty("clientId") + private String clientId = null; + + + public ServiceDefinitionCriteria addIdsItem(String idsItem) { + if (this.ids == null) { + this.ids = new ArrayList<>(); + } + this.ids.add(idsItem); + return this; + } + + public ServiceDefinitionCriteria addCodeItem(String codeItem) { + if (this.code == null) { + this.code = new ArrayList<>(); + } + this.code.add(codeItem); + return this; + } + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionResponse.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionResponse.java new file mode 100644 index 00000000000..685d05481db --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionResponse.java @@ -0,0 +1,45 @@ +package org.egov.transformer.models.upstream; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * ServiceDefinitionResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ServiceDefinitionResponse { + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("ServiceDefinitions") + @Valid + private List serviceDefinition = null; + + @JsonProperty("Pagination") + @Valid + private Pagination pagination = null; + + + public ServiceDefinitionResponse addServiceDefinitionItem(ServiceDefinition serviceDefinitionItem) { + if (this.serviceDefinition == null) { + this.serviceDefinition = new ArrayList<>(); + } + this.serviceDefinition.add(serviceDefinitionItem); + return this; + } + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionSearchRequest.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionSearchRequest.java new file mode 100644 index 00000000000..639692ad1f4 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionSearchRequest.java @@ -0,0 +1,37 @@ +package org.egov.transformer.models.upstream; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +/** + * ServiceDefinitionSearchRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ServiceDefinitionSearchRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("ServiceDefinitionCriteria") + @Valid + private ServiceDefinitionCriteria serviceDefinitionCriteria = null; + + @JsonProperty("Pagination") + @Valid + private Pagination pagination = null; + + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceRequest.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceRequest.java new file mode 100644 index 00000000000..187a0bc63dc --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceRequest.java @@ -0,0 +1,33 @@ +package org.egov.transformer.models.upstream; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +/** + * ServiceRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ServiceRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Service") + @Valid + private Service service = null; + + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectService.java index f16485605c4..f0d206b1da8 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectService.java @@ -1,5 +1,6 @@ package org.egov.transformer.service; +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; @@ -77,6 +78,20 @@ public Project getProject(String projectId, String tenantId) { return project; } + public Project getProjectByName(String projectName, String tenantId) { + if (projectMap.containsKey(projectName)) { + log.info("getting project {} from cache", projectName); + return projectMap.get(projectName); + } + List projects = searchProjectByName(projectName, tenantId); + Project project = null; + if (!projects.isEmpty()) { + project = projects.get(0); + projectMap.put(projectName, project); + } + return project; + } + public Map getBoundaryLabelToNameMap(String projectId, String tenantId) { Project project = getProject(projectId, tenantId); String locationCode = project.getAddress().getBoundary(); @@ -95,6 +110,41 @@ public Map getBoundaryLabelToNameMap(Project project, String loc return resultMap; } + private List searchProjectByName(String projectName, String tenantId) { + + ProjectRequest request = ProjectRequest.builder() + .requestInfo(RequestInfo.builder(). + userInfo(User.builder() + .uuid("transformer-uuid") + .build()) + .build()) + .projects(Collections.singletonList(Project.builder().name(projectName).tenantId(tenantId).build())) + .build(); + + try { + log.info(objectMapper.writeValueAsString(request)); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + ProjectResponse response; + try { + StringBuilder uri = new StringBuilder(); + uri.append(transformerProperties.getProjectHost()) + .append(transformerProperties.getProjectSearchUrl()) + .append("?limit=").append(transformerProperties.getSearchApiLimit()) + .append("&offset=0") + .append("&tenantId=").append(tenantId); + response = serviceRequestClient.fetchResult(uri, + request, + ProjectResponse.class); + } catch (Exception e) { + log.error("error while fetching project list", e); + throw new CustomException("PROJECT_FETCH_ERROR", + "error while fetching project details for name: " + projectName); + } + return response.getProject(); + } + private List searchProject(String projectId, String tenantId) { ProjectRequest request = ProjectRequest.builder() diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceDefinitionService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceDefinitionService.java index e920f7b38bb..012d95c4687 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceDefinitionService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceDefinitionService.java @@ -3,13 +3,13 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.contract.request.RequestInfo; import org.egov.common.contract.request.User; -import org.egov.servicerequest.web.models.ServiceDefinition; -import org.egov.servicerequest.web.models.ServiceDefinitionCriteria; -import org.egov.servicerequest.web.models.ServiceDefinitionResponse; -import org.egov.servicerequest.web.models.ServiceDefinitionSearchRequest; import org.egov.tracer.model.CustomException; import org.egov.transformer.config.TransformerProperties; import org.egov.transformer.http.client.ServiceRequestClient; +import org.egov.transformer.models.upstream.ServiceDefinition; +import org.egov.transformer.models.upstream.ServiceDefinitionCriteria; +import org.egov.transformer.models.upstream.ServiceDefinitionResponse; +import org.egov.transformer.models.upstream.ServiceDefinitionSearchRequest; import org.springframework.stereotype.Component; import java.util.Collections; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskIndexV1TransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskIndexV1TransformationService.java index ef40feb704f..859cf0f63a6 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskIndexV1TransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskIndexV1TransformationService.java @@ -1,10 +1,9 @@ package org.egov.transformer.service; import lombok.extern.slf4j.Slf4j; -import org.egov.servicerequest.web.models.Service; import org.egov.transformer.config.TransformerProperties; +import org.egov.transformer.models.upstream.Service; import org.egov.transformer.producer.Producer; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.List; @@ -12,20 +11,19 @@ @Component @Slf4j public class ServiceTaskIndexV1TransformationService extends ServiceTaskTransformationService { - @Autowired - public ServiceTaskIndexV1TransformationService(ServiceTaskIndexV1Transformer transformer, - Producer producer, TransformerProperties properties) { + + + protected ServiceTaskIndexV1TransformationService(ServiceTaskIndexV1Transformer transformer, Producer producer, TransformerProperties properties) { super(transformer, producer, properties); } + @Override public void transform(List payloadList) { super.transform(payloadList); } - @Override public String getTopic() { return properties.getTransformerProducerServiceTaskIndexV1Topic(); } - } diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java index 635c126c887..68fcaedcda9 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java @@ -2,11 +2,11 @@ import lombok.extern.slf4j.Slf4j; -import org.egov.servicerequest.web.models.Service; -import org.egov.servicerequest.web.models.ServiceDefinition; import org.egov.transformer.config.TransformerProperties; import org.egov.transformer.enums.Operation; -import org.egov.transformer.models.downstream.ServiceTaskIndexV1; +import org.egov.transformer.models.downstream.ServiceIndexV1; +import org.egov.transformer.models.upstream.Service; +import org.egov.transformer.models.upstream.ServiceDefinition; import org.egov.transformer.producer.Producer; import org.egov.transformer.service.transformer.Transformer; import org.springframework.beans.factory.annotation.Autowired; @@ -38,7 +38,7 @@ protected ServiceTaskTransformationService(ServiceTaskTransformationService.Serv public void transform(List payloadList) { log.info("transforming for ids {}", payloadList.stream() .map(Service::getId).collect(Collectors.toList())); - List transformedPayloadList = payloadList.stream() + List transformedPayloadList = payloadList.stream() .map(transformer::transform) .flatMap(Collection::stream) .collect(Collectors.toList()); @@ -56,7 +56,7 @@ public Operation getOperation() { @Component static class ServiceTaskIndexV1Transformer implements - Transformer { + Transformer { private final ProjectService projectService; private final TransformerProperties properties; private final ServiceDefinitionService serviceDefinitionService; @@ -70,16 +70,16 @@ static class ServiceTaskIndexV1Transformer implements } @Override - public List transform(Service service) { + public List transform(Service service) { ServiceDefinition serviceDefinition = serviceDefinitionService.getServiceDefinition(service.getServiceDefId(), service.getTenantId()); String[] parts = serviceDefinition.getCode().split("\\."); - String projectId = parts[0]; + String projectName = parts[0]; String supervisorLevel = parts[2]; - Map boundaryLabelToNameMap = projectService - .getBoundaryLabelToNameMap(projectId, service.getTenantId()); + String projectId = projectService.getProjectByName(projectName, service.getTenantId()).getId(); + Map boundaryLabelToNameMap = projectService.getBoundaryLabelToNameMap(projectId, service.getTenantId()); log.info("boundary labels {}", boundaryLabelToNameMap.toString()); - return Collections.singletonList(ServiceTaskIndexV1.builder() + return Collections.singletonList(ServiceIndexV1.builder() .id(service.getId()) .projectId(projectId) .serviceDefinitionId(service.getServiceDefId()) From 837e4c7f32f8448f33c7c1f6ceb16550150f90d5 Mon Sep 17 00:00:00 2001 From: Shiva Burade Date: Fri, 5 May 2023 14:23:51 +0530 Subject: [PATCH 016/283] [hlm-2706]: Updated port --- .../transformer/src/main/resources/application.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/transformer/src/main/resources/application.properties b/health-services/transformer/src/main/resources/application.properties index d925cc6dc8e..bfa6972506b 100644 --- a/health-services/transformer/src/main/resources/application.properties +++ b/health-services/transformer/src/main/resources/application.properties @@ -1,5 +1,5 @@ server.servlet.context-path=/transformer -server.port=8081 +server.port=8080 app.timezone=UTC # REDIS CONFIG From b9f615e582c9c1ee737776683e290f52fab7117c Mon Sep 17 00:00:00 2001 From: Shiva Burade Date: Fri, 5 May 2023 15:46:38 +0530 Subject: [PATCH 017/283] [hlm-2301]: Removing audit details as frontend will send it. --- .../src/main/java/org/egov/pgr/service/EnrichmentService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/service/EnrichmentService.java b/core-services/pgr-services/src/main/java/org/egov/pgr/service/EnrichmentService.java index 7615c2ef8d3..1c4e2b16da8 100644 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/service/EnrichmentService.java +++ b/core-services/pgr-services/src/main/java/org/egov/pgr/service/EnrichmentService.java @@ -59,9 +59,9 @@ public void enrichCreateRequest(ServiceRequest serviceRequest){ userService.callUserService(serviceRequest); - AuditDetails auditDetails = utils.getAuditDetails(requestInfo.getUserInfo().getUuid(), service,true); + //AuditDetails auditDetails = utils.getAuditDetails(requestInfo.getUserInfo().getUuid(), service,true); - service.setAuditDetails(auditDetails); + //service.setAuditDetails(auditDetails); service.setId(UUID.randomUUID().toString()); service.getAddress().setId(UUID.randomUUID().toString()); service.getAddress().setTenantId(tenantId); From f1593ba1f6b65c17bc49e53f60861ab761fcfe26 Mon Sep 17 00:00:00 2001 From: Shiva Burade Date: Mon, 8 May 2023 12:25:40 +0530 Subject: [PATCH 018/283] [hlm-2301]: Update identifiers by type and updated test cases. --- .../individual/service/IndividualService.java | 37 +++++++++++++++++-- .../service/IndividualServiceUpdateTest.java | 33 +++++++++++++++-- 2 files changed, 63 insertions(+), 7 deletions(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java index b247e5e4e6f..989e0934329 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java @@ -15,18 +15,43 @@ import org.egov.common.validator.Validator; import org.egov.individual.config.IndividualProperties; import org.egov.individual.repository.IndividualRepository; -import org.egov.individual.validators.*; +import org.egov.individual.validators.AadharNumberValidator; +import org.egov.individual.validators.AadharNumberValidatorForCreate; +import org.egov.individual.validators.AddressTypeValidator; +import org.egov.individual.validators.IsDeletedSubEntityValidator; +import org.egov.individual.validators.IsDeletedValidator; +import org.egov.individual.validators.MobileNumberValidator; +import org.egov.individual.validators.NonExistentEntityValidator; +import org.egov.individual.validators.NullIdValidator; +import org.egov.individual.validators.RowVersionValidator; +import org.egov.individual.validators.UniqueEntityValidator; +import org.egov.individual.validators.UniqueSubEntityValidator; import org.egov.individual.web.models.IndividualSearch; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; import java.util.function.Predicate; import java.util.stream.Collectors; -import static org.egov.common.utils.CommonUtils.*; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdList; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.individual.Constants.SET_INDIVIDUALS; import static org.egov.individual.Constants.VALIDATION_ERROR; @@ -197,7 +222,11 @@ public List update(IndividualBulkRequest request, boolean isBulk) { // this is because we cannot merge masked identifiers with new identifiers which are now encrypted encryptedIndividualList.forEach(encryptedIndividual -> { List newIdentifiers = encryptedIndividual.getIdentifiers(); - List identifierList = existingIdentifiers.get(encryptedIndividual.getId()); + List newIdentifiersIds = getIdList(newIdentifiers); + List identifierList = existingIdentifiers.get(encryptedIndividual.getId()).stream() + .filter(identifier -> !newIdentifiersIds.contains(identifier.getId())) + .collect(Collectors.toList()); + if (identifierList != null) { newIdentifiers.addAll(identifierList); } diff --git a/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceUpdateTest.java b/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceUpdateTest.java index f1bfbe7d97a..fa4d39f7c3b 100644 --- a/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceUpdateTest.java +++ b/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceUpdateTest.java @@ -1,6 +1,7 @@ package org.egov.individual.service; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.individual.Identifier; import org.egov.common.models.individual.Individual; import org.egov.common.models.individual.IndividualBulkRequest; import org.egov.common.models.individual.IndividualRequest; @@ -41,7 +42,10 @@ import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class IndividualServiceUpdateTest { @@ -140,9 +144,14 @@ void shouldThrowExceptionIfEntitiesDoNotExistInDb() { void shouldCheckRowVersionsIfEntitiesAreValid() { Individual requestIndividual = IndividualTestBuilder.builder() .withClientReferenceId() + .withId("some-id") .withName() .withTenantId() .withAddress() + .withIdentifiers(Identifier.builder() + .id("some-id") + .identifierId("some-id") + .identifierType("some-type").build()) .withRowVersion() .build(); IndividualRequest request = IndividualRequestTestBuilder.builder() @@ -152,14 +161,21 @@ void shouldCheckRowVersionsIfEntitiesAreValid() { List individualsInDb = new ArrayList<>(); individualsInDb.add(IndividualTestBuilder.builder() .withClientReferenceId() - .withId() + .withId("some-id") .withName() .withTenantId() .withAddress() + .withIdentifiers(Identifier.builder() + .id("some-id") + .individualId("some-id") + .identifierId("some-id") + .identifierType("some-type").build()) .withRowVersion() .withAuditDetails() .build()); + + when(individualRepository.findById(anyList(),eq("id"),eq(false))).thenReturn(individualsInDb); when(encryptionService.encrypt(any(IndividualBulkRequest.class), anyList(), any(String.class), anyBoolean())).thenReturn(Collections.singletonList(requestIndividual)); @@ -203,6 +219,11 @@ void shouldSaveTheUpdatedEntities() { .withName("some-new-family-name", "some-new-given-name") .withTenantId() .withAddress() + .withId("some-id") + .withIdentifiers(Identifier.builder() + .id("some-id") + .identifierId("some-id") + .identifierType("some-type").build()) .withRowVersion() .build(); IndividualRequest request = IndividualRequestTestBuilder.builder() @@ -212,14 +233,20 @@ void shouldSaveTheUpdatedEntities() { List individualsInDb = new ArrayList<>(); individualsInDb.add(IndividualTestBuilder.builder() .withClientReferenceId() - .withId() + .withId("some-id") .withName() .withTenantId() .withAddress() + .withIdentifiers(Identifier.builder() + .id("some-id") + .individualId("some-id") + .identifierId("some-id") + .identifierType("some-type").build()) .withRowVersion() .withAuditDetails() .build()); + when(individualRepository.findById(anyList(),eq("id"),eq(false))).thenReturn(individualsInDb); when(encryptionService.encrypt(any(IndividualBulkRequest.class), anyList(), any(String.class), anyBoolean())).thenReturn(Collections.singletonList(requestIndividual)); List result = individualService.update(request); From 66e2ec1253957b298998bbc8e178348a484fb1b8 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Mon, 8 May 2023 15:09:43 +0530 Subject: [PATCH 019/283] [hlm-2375]: Added user details --- .../repository/IndividualRepository.java | 4 +++ .../rowmapper/IndividualRowMapper.java | 11 ++++++ .../individual/service/IndividualMapper.java | 18 +++++----- .../web/models/IndividualSearch.java | 4 +++ .../libraries/health-services-models/pom.xml | 2 +- .../common/models/individual/Individual.java | 3 ++ .../models/individual/IndividualSearch.java | 3 ++ .../common/models/individual/UserDetails.java | 35 +++++++++++++++++++ 8 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index e34e5740623..3a732ccf56c 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -170,6 +170,10 @@ private String getQueryForIndividual(IndividualSearch searchObject, Integer limi if (lastChangedSince != null) { query = query + "AND lastModifiedTime>=:lastModifiedTime "; } + if (searchObject.getRoleCode() != null) { + query = query + "AND roles @> '[{\"code\": \"" + ":roleCode" + "\"}]' "; + paramsMap.put("roleCode", searchObject.getRoleCode()); + } query = query + "ORDER BY id ASC LIMIT :limit OFFSET :offset"; paramsMap.put("tenantId", tenantId); paramsMap.put("isDeleted", includeDeleted); diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java index 0d3bffdbd9d..e3474a539df 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java @@ -3,16 +3,19 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; +import digit.models.coremodels.user.enums.UserType; import org.egov.common.models.individual.AdditionalFields; import org.egov.common.models.individual.BloodGroup; import org.egov.common.models.individual.Gender; import org.egov.common.models.individual.Individual; import org.egov.common.models.individual.Name; +import org.egov.common.models.individual.UserDetails; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.List; @Component public class IndividualRowMapper implements RowMapper { @@ -53,6 +56,14 @@ public Individual mapRow(ResultSet resultSet, int i) throws SQLException { .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) .isSystemUser(resultSet.getBoolean("isSystemUser")) + .userDetails(UserDetails.builder() + .username(resultSet.getString("username")) + .password(resultSet.getString("password")) + .userType(UserType.fromValue(resultSet.getString("userType"))) + .roles(resultSet.getString("roles") == null ? null : + objectMapper.readValue(resultSet.getString("roles"), + List.class)) + .build()) .build(); } catch (JsonProcessingException e) { throw new RuntimeException(e); diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java index ae1b5500ffc..14dd456b072 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java @@ -7,10 +7,9 @@ import org.egov.common.models.user.UserType; import org.egov.individual.config.IndividualProperties; -import java.util.Collections; -import java.util.HashSet; import java.util.Random; import java.util.UUID; +import java.util.stream.Collectors; @Slf4j public class IndividualMapper { @@ -23,18 +22,21 @@ public static UserRequest toUserRequest(Individual individual, IndividualPropert return UserRequest.builder() .tenantId(individual.getTenantId()) - .userName(UUID.randomUUID().toString()) .name(String.join(" ", individual.getName().getGivenName(), individual.getName().getFamilyName())) .mobileNumber(generateDummyMobileNumber(individual.getMobileNumber())) .type(UserType.valueOf(properties.getUserServiceUserType())) .accountLocked(properties.isUserServiceAccountLocked()) .active(true) - .roles(new HashSet<>(Collections.singletonList(RoleRequest.builder() - .code(properties.getUserServiceUserType()) - .tenantId(individual.getTenantId()) - .name(properties.getUserServiceUserType()) - .build()))) + .userName(null != individual.getUserDetails().getUsername() ? individual.getUserDetails().getUsername() : UUID.randomUUID().toString()) + .password(null != individual.getUserDetails().getPassword() ? individual.getUserDetails().getPassword() : null) + .roles(individual.getUserDetails().getRoles().stream().map(role -> RoleRequest.builder() + .code(role.getCode()) + .name(role.getName()) + .tenantId(individual.getTenantId()) + .build()) + .collect(Collectors.toSet())) + .type(UserType.valueOf(individual.getUserDetails().getUserType().name())) .build(); } diff --git a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java b/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java index 4de94e41839..91c5e5f095e 100644 --- a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java +++ b/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java @@ -84,5 +84,9 @@ public class IndividualSearch { @JsonProperty("boundaryCode") @Exclude private String boundaryCode = null; + + @JsonProperty("roleCode") + @Exclude + private String roleCode = null; } diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index 1d6eb15e2f0..6f46c21530f 100644 --- a/health-services/libraries/health-services-models/pom.xml +++ b/health-services/libraries/health-services-models/pom.xml @@ -6,7 +6,7 @@ org.egov.common health-services-models - 1.0.3-SNAPSHOT + 1.0.4-SNAPSHOT 8 diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java index 5100d887a98..93f16b8d7aa 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java @@ -130,6 +130,9 @@ public class Individual { @JsonProperty("isSystemUser") private Boolean isSystemUser = Boolean.FALSE; + @JsonProperty("userDetails") + private UserDetails userDetails; + public Individual addAddressItem(Address addressItem) { if (this.address == null) { diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java index 3d37fdf9b40..0cb1ff5c772 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java @@ -73,5 +73,8 @@ public class IndividualSearch { @JsonProperty("boundaryCode") private String boundaryCode = null; + + @JsonProperty("roleCode") + private String roleCode = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java new file mode 100644 index 00000000000..4b476b71c0a --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java @@ -0,0 +1,35 @@ +package org.egov.common.models.individual; + +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.user.Role; +import digit.models.coremodels.user.enums.UserType; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.Valid; +import javax.validation.constraints.Size; +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class UserDetails { + @Size(max=180) + @JsonProperty("username") + private String username; + @Size(max=64) + @JsonProperty("password") + private String password; + @Size(min = 2, max = 1000) + @JsonProperty("tenantId") + private String tenantId; + @JsonProperty("roles") + @Valid + private List roles; + @Size(max=50) + @JsonProperty("type") + private UserType userType; +} From d0891407eeeb3f62a78d1f1f8339e861baa3b82e Mon Sep 17 00:00:00 2001 From: Shiva Burade Date: Mon, 8 May 2023 15:37:28 +0530 Subject: [PATCH 020/283] [hlm-2706]: Review comment fixes. --- health-services/transformer/pom.xml | 6 ------ .../transformer/config/MainConfiguration.java | 2 +- .../models/upstream/AttributeDefinition.java | 15 +-------------- .../models/upstream/AttributeValue.java | 10 ---------- .../transformer/models/upstream/Pagination.java | 7 ------- .../transformer/models/upstream/Service.java | 17 +---------------- .../models/upstream/ServiceDefinition.java | 14 +------------- .../upstream/ServiceDefinitionCriteria.java | 6 ------ .../upstream/ServiceDefinitionResponse.java | 4 ---- .../ServiceDefinitionSearchRequest.java | 9 --------- .../models/upstream/ServiceRequest.java | 8 -------- 11 files changed, 4 insertions(+), 94 deletions(-) diff --git a/health-services/transformer/pom.xml b/health-services/transformer/pom.xml index 2707beb0358..ba2b21ef154 100644 --- a/health-services/transformer/pom.xml +++ b/health-services/transformer/pom.xml @@ -74,12 +74,6 @@ javax.validation validation-api - - io.swagger.core.v3 - swagger-annotations - 2.2.8 - compile - diff --git a/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java b/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java index 82de303328d..9c7debc9f31 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java @@ -33,7 +33,7 @@ @Import({TracerConfiguration.class}) @Configuration -@ComponentScan(basePackages = {"org.egov.transformer.producer"}) +@ComponentScan(basePackages = {"org.egov"}) @Slf4j public class MainConfiguration { diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeDefinition.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeDefinition.java index 61158560897..665c8f91f5a 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeDefinition.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeDefinition.java @@ -4,23 +4,19 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonValue; import digit.models.coremodels.AuditDetails; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; import java.util.ArrayList; import java.util.List; /** * Hold the attribute definition fields details as json object. */ -@Schema(description = "Hold the attribute definition fields details as json object.") + @Validated @Data @AllArgsConstructor @@ -28,20 +24,15 @@ @Builder public class AttributeDefinition { @JsonProperty("id") - @Size(min = 2, max = 64) private String id = null; @JsonProperty("referenceId") - @Size(min = 2, max = 64) private String referenceId = null; @JsonProperty("tenantId") - @Size(min = 2, max = 64) private String tenantId = null; @JsonProperty("code") - @NotNull - @Size(min = 2, max = 64) private String code = null; /** @@ -86,28 +77,24 @@ public static DataTypeEnum fromValue(String text) { } @JsonProperty("dataType") - @NotNull private DataTypeEnum dataType = null; @JsonProperty("values") private List values = null; @JsonProperty("isActive") - @NotNull private Boolean isActive = true; @JsonProperty("required") private Boolean required = null; @JsonProperty("regex") - @Size(min = 2, max = 64) private String regex = null; @JsonProperty("order") private String order = null; @JsonProperty("auditDetails") - @Valid private AuditDetails auditDetails = null; @JsonProperty("additionalDetails") diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeValue.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeValue.java index 22a1ec2b90a..6f69634df23 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeValue.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/AttributeValue.java @@ -2,21 +2,15 @@ import com.fasterxml.jackson.annotation.JsonProperty; import digit.models.coremodels.AuditDetails; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * Hold the attribute details as object. */ -@Schema(description = "Hold the attribute details as object.") @Validated @Data @AllArgsConstructor @@ -27,19 +21,15 @@ public class AttributeValue { private String id = null; @JsonProperty("referenceId") - @Size(min = 2, max = 64) private String referenceId = null; @JsonProperty("attributeCode") - @NotNull private String attributeCode = null; @JsonProperty("value") - @NotNull private Object value = null; @JsonProperty("auditDetails") - @Valid private AuditDetails auditDetails = null; @JsonProperty("additionalDetails") diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Pagination.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Pagination.java index 85993c9ca34..806daa44f15 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Pagination.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Pagination.java @@ -3,19 +3,15 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonValue; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; - /** * Pagination details */ -@Schema(description = "Pagination details") @Validated @Data @AllArgsConstructor @@ -23,15 +19,12 @@ @Builder public class Pagination { @JsonProperty("limit") - @Valid private Integer limit = new Integer(10); @JsonProperty("offset") - @Valid private Integer offset = new Integer(0); @JsonProperty("totalCount") - @Valid private Long totalCount = null; @JsonProperty("sortBy") diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Service.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Service.java index bb57d9835c7..59a9b1a5be7 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Service.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/Service.java @@ -2,23 +2,19 @@ import com.fasterxml.jackson.annotation.JsonProperty; import digit.models.coremodels.AuditDetails; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; import java.util.ArrayList; import java.util.List; /** * Hold the Service field details as json object. */ -@Schema(description = "Hold the Service field details as json object.") + @Validated @Data @AllArgsConstructor @@ -29,38 +25,27 @@ public class Service { private String id = null; @JsonProperty("tenantId") - @NotNull - @Size(min = 2, max = 64) private String tenantId = null; @JsonProperty("serviceDefId") - @NotNull - @Size(min = 2, max = 64) private String serviceDefId = null; @JsonProperty("referenceId") - @Size(min = 2, max = 64) private String referenceId = null; @JsonProperty("attributes") - @NotNull - @Valid private List attributes = new ArrayList<>(); @JsonProperty("auditDetails") - @Valid private AuditDetails auditDetails = null; @JsonProperty("additionalDetails") private Object additionalDetails = null; @JsonProperty("accountId") - @NotNull - @Size(max = 64) private String accountId = null; @JsonProperty("clientId") - @Size(max = 64) private String clientId = null; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinition.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinition.java index b3332ef5aa0..a1fee705612 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinition.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinition.java @@ -2,23 +2,19 @@ import com.fasterxml.jackson.annotation.JsonProperty; import digit.models.coremodels.AuditDetails; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; import java.util.ArrayList; import java.util.List; /** * Holds the Service Definition details json object. */ -@Schema(description = "Holds the Service Definition details json object.") + @Validated @Data @AllArgsConstructor @@ -26,35 +22,27 @@ @Builder public class ServiceDefinition { @JsonProperty("id") - @Size(min = 2, max = 64) private String id = null; @JsonProperty("tenantId") - @Size(min = 2, max = 64) private String tenantId = null; @JsonProperty("code") - @NotNull - @Size(min = 2, max = 64) private String code = null; @JsonProperty("isActive") private Boolean isActive = true; @JsonProperty("attributes") - @NotNull - @Valid private List attributes = new ArrayList<>(); @JsonProperty("auditDetails") - @Valid private AuditDetails auditDetails = null; @JsonProperty("additionalDetails") private Object additionalDetails = null; @JsonProperty("clientId") - @Size(max = 64) private String clientId = null; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionCriteria.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionCriteria.java index 3fb59965472..fda0f1c7369 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionCriteria.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionCriteria.java @@ -1,22 +1,18 @@ package org.egov.transformer.models.upstream; import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.v3.oas.annotations.media.Schema; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; import java.util.ArrayList; import java.util.List; /** * The object will contain all the search parameters for Service Definition. */ -@Schema(description = "The object will contain all the search parameters for Service Definition.") @Validated @Data @AllArgsConstructor @@ -24,8 +20,6 @@ @Builder public class ServiceDefinitionCriteria { @JsonProperty("tenantId") - @NotNull - @Size(min = 2, max = 64) private String tenantId = null; @JsonProperty("ids") diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionResponse.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionResponse.java index 685d05481db..d2ffe04cc25 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionResponse.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionResponse.java @@ -8,7 +8,6 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; import java.util.ArrayList; import java.util.List; @@ -22,15 +21,12 @@ @Builder public class ServiceDefinitionResponse { @JsonProperty("ResponseInfo") - @Valid private ResponseInfo responseInfo = null; @JsonProperty("ServiceDefinitions") - @Valid private List serviceDefinition = null; @JsonProperty("Pagination") - @Valid private Pagination pagination = null; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionSearchRequest.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionSearchRequest.java index 639692ad1f4..ec3fc65dbe3 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionSearchRequest.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceDefinitionSearchRequest.java @@ -8,9 +8,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - /** * ServiceDefinitionSearchRequest */ @@ -21,17 +18,11 @@ @Builder public class ServiceDefinitionSearchRequest { @JsonProperty("RequestInfo") - @NotNull - @Valid private RequestInfo requestInfo = null; @JsonProperty("ServiceDefinitionCriteria") - @Valid private ServiceDefinitionCriteria serviceDefinitionCriteria = null; @JsonProperty("Pagination") - @Valid private Pagination pagination = null; - - } diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceRequest.java b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceRequest.java index 187a0bc63dc..e259cdc1a51 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceRequest.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/upstream/ServiceRequest.java @@ -8,9 +8,6 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - /** * ServiceRequest */ @@ -21,13 +18,8 @@ @Builder public class ServiceRequest { @JsonProperty("RequestInfo") - @NotNull - @Valid private RequestInfo requestInfo = null; @JsonProperty("Service") - @Valid private Service service = null; - - } From d44b11092a2b70f2a6b448768461037e3c4fb7a7 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Mon, 8 May 2023 16:20:28 +0530 Subject: [PATCH 021/283] [hlm-2375]: Support for multiple role codes --- health-services/individual/pom.xml | 2 +- .../individual/repository/IndividualRepository.java | 13 ++++++++++--- .../individual/web/models/IndividualSearch.java | 2 +- .../common/models/individual/IndividualSearch.java | 2 +- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index 7574e2cc721..3517ac53f16 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.3-SNAPSHOT + 1.0.4-SNAPSHOT compile diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index 3a732ccf56c..4d3edb8e48e 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -170,9 +170,16 @@ private String getQueryForIndividual(IndividualSearch searchObject, Integer limi if (lastChangedSince != null) { query = query + "AND lastModifiedTime>=:lastModifiedTime "; } - if (searchObject.getRoleCode() != null) { - query = query + "AND roles @> '[{\"code\": \"" + ":roleCode" + "\"}]' "; - paramsMap.put("roleCode", searchObject.getRoleCode()); + if (searchObject.getRoleCodes() != null && !searchObject.getRoleCodes().isEmpty()) { + query = query + "AND roles @> '["; + for (int i = 0; i < searchObject.getRoleCodes().size(); i++) { + query = query + "{\"code\": \":roleCode\"" + i + "}"; + if (i != searchObject.getRoleCodes().size() - 1) { + query = query + ","; + } + paramsMap.put("roleCode" + i, searchObject.getRoleCodes().get(i)); + } + query = query + "]' "; } query = query + "ORDER BY id ASC LIMIT :limit OFFSET :offset"; paramsMap.put("tenantId", tenantId); diff --git a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java b/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java index 91c5e5f095e..65795d32c5a 100644 --- a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java +++ b/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java @@ -87,6 +87,6 @@ public class IndividualSearch { @JsonProperty("roleCode") @Exclude - private String roleCode = null; + private List roleCodes = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java index 0cb1ff5c772..fe2d75be75e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java @@ -75,6 +75,6 @@ public class IndividualSearch { private String boundaryCode = null; @JsonProperty("roleCode") - private String roleCode = null; + private List roleCodes = null; } From 0d02da95058d7614dbe6d0381c7d8817a703462f Mon Sep 17 00:00:00 2001 From: Shiva Burade Date: Tue, 9 May 2023 14:09:47 +0530 Subject: [PATCH 022/283] [hlm-2631]: Updated code for custom exception --- .../egov/individual/service/IndividualService.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java index 989e0934329..ce8165b8936 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java @@ -4,6 +4,7 @@ import org.apache.commons.lang3.StringUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.ds.Tuple; +import org.egov.common.models.Error; import org.egov.common.models.ErrorDetails; import org.egov.common.models.individual.Identifier; import org.egov.common.models.individual.Individual; @@ -35,9 +36,11 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -161,7 +164,12 @@ private Tuple, Map> validate(List hashset = new HashSet<>(); + for (Map.Entry entry : errorDetailsMap.entrySet()) { + List errors = entry.getValue().getErrors(); + hashset.addAll(errors.stream().map(error -> error.getErrorCode()).collect(Collectors.toSet())); + } + throw new CustomException(String.join(":", hashset), errorDetailsMap.values().toString()); } List validIndividuals = request.getIndividuals().stream() .filter(notHavingErrors()).collect(Collectors.toList()); @@ -180,8 +188,7 @@ public List update(IndividualRequest request) { public List update(IndividualBulkRequest request, boolean isBulk) { Tuple, Map> tuple = validate(validators, isApplicableForUpdate, request, - isBulk); - Map errorDetailsMap = tuple.getY(); + isBulk);Map errorDetailsMap = tuple.getY(); List validIndividuals = tuple.getX(); List encryptedIndividualList = Collections.emptyList(); From 688557d720257a44cfba5d240097bb553d780f8d Mon Sep 17 00:00:00 2001 From: Shiva Burade Date: Tue, 9 May 2023 14:11:25 +0530 Subject: [PATCH 023/283] [hlm-2631]: Minor indentation fix --- .../java/org/egov/individual/service/IndividualService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java index ce8165b8936..fb3259848cb 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java @@ -188,7 +188,8 @@ public List update(IndividualRequest request) { public List update(IndividualBulkRequest request, boolean isBulk) { Tuple, Map> tuple = validate(validators, isApplicableForUpdate, request, - isBulk);Map errorDetailsMap = tuple.getY(); + isBulk); + Map errorDetailsMap = tuple.getY(); List validIndividuals = tuple.getX(); List encryptedIndividualList = Collections.emptyList(); From 73167482a22a5d6e6bc439a2361a9c24a46fd83c Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Wed, 10 May 2023 12:33:55 +0530 Subject: [PATCH 024/283] [hlm-2375]: Updated version to 1.1.0 --- health-services/facility/CHANGELOG.md | 4 +++- health-services/facility/pom.xml | 2 +- health-services/household/CHANGELOG.md | 4 +++- health-services/household/pom.xml | 2 +- health-services/individual/CHANGELOG.md | 4 +++- health-services/individual/pom.xml | 2 +- health-services/product/CHANGELOG.md | 4 +++- health-services/product/pom.xml | 2 +- health-services/project/CHANGELOG.md | 4 +++- health-services/project/pom.xml | 2 +- health-services/stock/CHANGELOG.md | 4 +++- health-services/stock/pom.xml | 2 +- health-services/transformer/CHANGELOG.md | 4 +++- health-services/transformer/pom.xml | 2 +- 14 files changed, 28 insertions(+), 14 deletions(-) diff --git a/health-services/facility/CHANGELOG.md b/health-services/facility/CHANGELOG.md index a27826b5875..645e12b40e1 100644 --- a/health-services/facility/CHANGELOG.md +++ b/health-services/facility/CHANGELOG.md @@ -2,4 +2,6 @@ All notable changes to this module will be documented in this file. ## 1.0.0 -- Base version \ No newline at end of file +- Base version + +## 1.1.0 \ No newline at end of file diff --git a/health-services/facility/pom.xml b/health-services/facility/pom.xml index 0352f386b9b..472e9ea35aa 100644 --- a/health-services/facility/pom.xml +++ b/health-services/facility/pom.xml @@ -5,7 +5,7 @@ facility jar facility - 1.0.1 + 1.1.0 1.8 ${java.version} diff --git a/health-services/household/CHANGELOG.md b/health-services/household/CHANGELOG.md index a27826b5875..645e12b40e1 100644 --- a/health-services/household/CHANGELOG.md +++ b/health-services/household/CHANGELOG.md @@ -2,4 +2,6 @@ All notable changes to this module will be documented in this file. ## 1.0.0 -- Base version \ No newline at end of file +- Base version + +## 1.1.0 \ No newline at end of file diff --git a/health-services/household/pom.xml b/health-services/household/pom.xml index 9d6d7361f09..d6cfb901da8 100644 --- a/health-services/household/pom.xml +++ b/health-services/household/pom.xml @@ -5,7 +5,7 @@ household jar household - 1.0.0 + 1.1.0 1.8 ${java.version} diff --git a/health-services/individual/CHANGELOG.md b/health-services/individual/CHANGELOG.md index a27826b5875..645e12b40e1 100644 --- a/health-services/individual/CHANGELOG.md +++ b/health-services/individual/CHANGELOG.md @@ -2,4 +2,6 @@ All notable changes to this module will be documented in this file. ## 1.0.0 -- Base version \ No newline at end of file +- Base version + +## 1.1.0 \ No newline at end of file diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index 7574e2cc721..69f738f77c0 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -5,7 +5,7 @@ individual jar individual - 1.0.0 + 1.1.0 1.8 ${java.version} diff --git a/health-services/product/CHANGELOG.md b/health-services/product/CHANGELOG.md index a27826b5875..645e12b40e1 100644 --- a/health-services/product/CHANGELOG.md +++ b/health-services/product/CHANGELOG.md @@ -2,4 +2,6 @@ All notable changes to this module will be documented in this file. ## 1.0.0 -- Base version \ No newline at end of file +- Base version + +## 1.1.0 \ No newline at end of file diff --git a/health-services/product/pom.xml b/health-services/product/pom.xml index f8deef3778e..12b9f8c1850 100644 --- a/health-services/product/pom.xml +++ b/health-services/product/pom.xml @@ -5,7 +5,7 @@ product jar product - 1.0.0 + 1.1.0 1.8 ${java.version} diff --git a/health-services/project/CHANGELOG.md b/health-services/project/CHANGELOG.md index a27826b5875..645e12b40e1 100644 --- a/health-services/project/CHANGELOG.md +++ b/health-services/project/CHANGELOG.md @@ -2,4 +2,6 @@ All notable changes to this module will be documented in this file. ## 1.0.0 -- Base version \ No newline at end of file +- Base version + +## 1.1.0 \ No newline at end of file diff --git a/health-services/project/pom.xml b/health-services/project/pom.xml index f0a5c1e5e4b..1b421ad4655 100644 --- a/health-services/project/pom.xml +++ b/health-services/project/pom.xml @@ -5,7 +5,7 @@ project jar project - 1.0.1 + 1.1.0 1.8 ${java.version} diff --git a/health-services/stock/CHANGELOG.md b/health-services/stock/CHANGELOG.md index a27826b5875..645e12b40e1 100644 --- a/health-services/stock/CHANGELOG.md +++ b/health-services/stock/CHANGELOG.md @@ -2,4 +2,6 @@ All notable changes to this module will be documented in this file. ## 1.0.0 -- Base version \ No newline at end of file +- Base version + +## 1.1.0 \ No newline at end of file diff --git a/health-services/stock/pom.xml b/health-services/stock/pom.xml index c9502f91692..87eae09d463 100644 --- a/health-services/stock/pom.xml +++ b/health-services/stock/pom.xml @@ -5,7 +5,7 @@ stock jar stock - 1.0.0 + 1.1.0 1.8 ${java.version} diff --git a/health-services/transformer/CHANGELOG.md b/health-services/transformer/CHANGELOG.md index a27826b5875..645e12b40e1 100644 --- a/health-services/transformer/CHANGELOG.md +++ b/health-services/transformer/CHANGELOG.md @@ -2,4 +2,6 @@ All notable changes to this module will be documented in this file. ## 1.0.0 -- Base version \ No newline at end of file +- Base version + +## 1.1.0 \ No newline at end of file diff --git a/health-services/transformer/pom.xml b/health-services/transformer/pom.xml index ba2b21ef154..ee0123866fe 100644 --- a/health-services/transformer/pom.xml +++ b/health-services/transformer/pom.xml @@ -5,7 +5,7 @@ transformer jar transformer - 1.0.0 + 1.1.0 1.8 ${java.version} From 3789bc1b1d7bfdede01f00227237bd38ba81993e Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Wed, 10 May 2023 16:03:33 +0530 Subject: [PATCH 025/283] [hlm-2375]: Flag based userId validation --- .../project/config/ProjectConfiguration.java | 3 + .../validator/staff/PsUserIdValidator.java | 62 ++++++++++++++----- .../src/main/resources/application.properties | 4 ++ 3 files changed, 54 insertions(+), 15 deletions(-) diff --git a/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java b/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java index a055d380ddb..e90e34ef1d7 100644 --- a/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java +++ b/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java @@ -179,4 +179,7 @@ public class ProjectConfiguration { @Value("${egov.location.hierarchy.type}") private String locationHierarchyType; + + @Value("${egov.user.id.validator}") + private String egovUserIdValidator; } diff --git a/health-services/project/src/main/java/org/egov/project/validator/staff/PsUserIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/staff/PsUserIdValidator.java index 87e00f33266..4326859c0be 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/staff/PsUserIdValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/staff/PsUserIdValidator.java @@ -3,11 +3,17 @@ import digit.models.coremodels.UserSearchRequest; import lombok.extern.slf4j.Slf4j; import org.egov.common.contract.request.User; +import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; +import org.egov.common.models.individual.Individual; +import org.egov.common.models.individual.IndividualBulkResponse; +import org.egov.common.models.individual.IndividualSearch; +import org.egov.common.models.individual.IndividualSearchRequest; import org.egov.common.models.project.ProjectStaff; import org.egov.common.models.project.ProjectStaffBulkRequest; import org.egov.common.service.UserService; import org.egov.common.validator.Validator; +import org.egov.project.config.ProjectConfiguration; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -34,8 +40,16 @@ public class PsUserIdValidator implements Validator> validate(ProjectStaffBulkRequest request) List entities = request.getProjectStaff(); Map> errorDetailsMap = new HashMap<>(); - List userIds = new ArrayList<>(entities.stream() + List userIds = entities.stream() .filter(notHavingErrors()) - .map(ProjectStaff::getUserId) - .collect(Collectors.toSet())); + .map(ProjectStaff::getUserId).distinct().collect(Collectors.toList()); + final String tenantId = getTenantId(entities); + Map uMap = getIdToObjMap(entities, + getMethod(GET_USER_ID, getObjClass(entities))); if (!userIds.isEmpty()) { - UserSearchRequest userSearchRequest = new UserSearchRequest(); - userSearchRequest.setTenantId(getTenantId(entities)); - userSearchRequest.setUuid(userIds); - - Map uMap = getIdToObjMap(entities, - getMethod(GET_USER_ID, getObjClass(entities))); + List validUserIds = new ArrayList<>(); try { - List validUserIds = userService - .search(userSearchRequest) - .stream() - .map(User::getUuid) - .collect(Collectors.toList()); + if ("egov-user".equalsIgnoreCase(projectConfiguration.getEgovUserIdValidator())) { + UserSearchRequest userSearchRequest = new UserSearchRequest(); + userSearchRequest.setTenantId(tenantId); + userSearchRequest.setUuid(userIds); + validUserIds = userService + .search(userSearchRequest) + .stream() + .map(User::getUuid) + .collect(Collectors.toList()); + } else if ("individual".equalsIgnoreCase(projectConfiguration.getEgovUserIdValidator())) { + IndividualSearchRequest individualSearchRequest = IndividualSearchRequest.builder() + .individual(IndividualSearch.builder() + // assuming this is "id" field of the individual payload + .id(userIds) + .build()) + .build(); + validUserIds = serviceRequestClient.fetchResult( + new StringBuilder(projectConfiguration.getIndividualServiceHost() + + projectConfiguration.getIndividualServiceSearchUrl() + + "?limit=" + projectConfiguration.getSearchApiLimit() + + "&offset=0&tenantId=" + tenantId), + individualSearchRequest, + IndividualBulkResponse.class).getIndividual().stream() + .map(Individual::getId) + .collect(Collectors.toList()); + } for (Map.Entry entry : uMap.entrySet()) { if (!validUserIds.contains(entry.getKey())) { ProjectStaff staff = entry.getValue(); diff --git a/health-services/project/src/main/resources/application.properties b/health-services/project/src/main/resources/application.properties index 22fab270490..46cab825873 100644 --- a/health-services/project/src/main/resources/application.properties +++ b/health-services/project/src/main/resources/application.properties @@ -87,6 +87,10 @@ egov.search.household.url=/household/v1/_search egov.individual.host= egov.search.individual.url= +# use the value as "egov-user" to validate against egov-user service +# use the value as "individual" to validate against individual service +egov.user.id.validator=individual + # FACILITY SERVICE egov.facility.host=http://localhost:8083 egov.search.facility.url=/facility/v1/_search From cb701e491619c99d8d418f16d274c797566ff852 Mon Sep 17 00:00:00 2001 From: Shiva Burade Date: Fri, 12 May 2023 13:24:30 +0530 Subject: [PATCH 026/283] [hlm-2831]: Fixed Aadhar error code and added not null to Individual relationship --- .../src/main/java/org/egov/common/utils/CommonUtils.java | 4 +++- .../test/java/org/egov/common/utils/CommonUtilsTest.java | 6 +++--- .../java/org/egov/common/models/individual/Individual.java | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/utils/CommonUtils.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/utils/CommonUtils.java index e19ed5b2023..2ab18e03354 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/utils/CommonUtils.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/utils/CommonUtils.java @@ -800,7 +800,9 @@ public static void handleErrors(Map errorDetailsMap, boolea if (isBulk) { ErrorHandler.exceptionAdviseInstance.exceptionHandler(errorDetailList); } else { - throw new CustomException(getErrorMap(errorDetailList)); + Map getErrorMap = getErrorMap(errorDetailList); + String code = getErrorMap.keySet().stream().collect(Collectors.joining(":")); + throw new CustomException(code, errorDetailsMap.values().toString()); } } } diff --git a/health-services/libraries/health-services-common/src/test/java/org/egov/common/utils/CommonUtilsTest.java b/health-services/libraries/health-services-common/src/test/java/org/egov/common/utils/CommonUtilsTest.java index 59daa554aff..50151260f29 100644 --- a/health-services/libraries/health-services-common/src/test/java/org/egov/common/utils/CommonUtilsTest.java +++ b/health-services/libraries/health-services-common/src/test/java/org/egov/common/utils/CommonUtilsTest.java @@ -805,8 +805,8 @@ void shouldCallExceptionHandlerWithCorrectModel() throws JsonProcessingException } @Test - @DisplayName("should throw custom exception when isBulk flag is true") - void shouldCallCustomExceptionWhenIsBulkFlagIsTrue() throws JsonProcessingException { + @DisplayName("should throw custom exception when isBulk flag is false") + void shouldCallCustomExceptionWhenIsBulkFlagIsFalse() throws JsonProcessingException { Map errorDetailsMap = new HashMap<>(); Exception ex = new Exception(); SomeRequest someRequest = SomeRequest.builder() @@ -832,7 +832,7 @@ void shouldCallCustomExceptionWhenIsBulkFlagIsTrue() throws JsonProcessingExcept try { CommonUtils.handleErrors(errorDetailsMap, false, "some-error-code"); } catch (CustomException e) { - assertEquals(e.getErrors().get("some-error-code"), "some-error-message"); + assertEquals(e.getCode(), "some-error-code"); } } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java index 5100d887a98..268ce6da2fe 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java @@ -96,7 +96,8 @@ public class Individual { private String husbandName = null; @JsonProperty("relationship") - @Size(max = 100) + @Size(max = 100, min = 1) + @NotNull private String relationship = null; @JsonProperty("identifiers") From af8dd71affeba27f7e4f3c9e9b4523bc754e34c0 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Fri, 12 May 2023 18:09:24 +0530 Subject: [PATCH 027/283] Update Individual.java --- .../main/java/org/egov/common/models/individual/Individual.java | 1 - 1 file changed, 1 deletion(-) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java index 268ce6da2fe..68e7f88b0a2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java @@ -97,7 +97,6 @@ public class Individual { @JsonProperty("relationship") @Size(max = 100, min = 1) - @NotNull private String relationship = null; @JsonProperty("identifiers") From 2df4815c301a84f8524a632ed817ec8b5e0152b7 Mon Sep 17 00:00:00 2001 From: Vishal Date: Sun, 14 May 2023 17:25:54 +0530 Subject: [PATCH 028/283] [hlm-1834]: debug transformer changes for boundary --- .../egov/transformer/service/ProjectService.java | 8 ++++---- .../service/ProjectStaffTransformationService.java | 2 +- .../service/ProjectTaskTransformationService.java | 2 +- .../service/ProjectTransformationService.java | 2 +- .../service/ServiceTaskTransformationService.java | 2 +- .../service/StockTransformationService.java | 14 +++++++------- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectService.java index f0d206b1da8..3853e41b460 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectService.java @@ -92,15 +92,15 @@ public Project getProjectByName(String projectName, String tenantId) { return project; } - public Map getBoundaryLabelToNameMap(String projectId, String tenantId) { + public Map getBoundaryLabelToNameMapByProjectId(String projectId, String tenantId) { Project project = getProject(projectId, tenantId); String locationCode = project.getAddress().getBoundary(); - return getBoundaryLabelToNameMap(project, locationCode); + return getBoundaryLabelToNameMap(locationCode, tenantId); } - public Map getBoundaryLabelToNameMap(Project project, String locationCode) { + public Map getBoundaryLabelToNameMap(String locationCode, String tenantId) { List boundaryList = boundaryService.getBoundary(locationCode, "ADMIN", - project.getTenantId()); + tenantId); BoundaryTree boundaryTree = boundaryService.generateTree(boundaryList.get(0)); BoundaryTree locationTree = boundaryService.search(boundaryTree, locationCode); List parentNodes = locationTree.getParentNodes(); diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectStaffTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectStaffTransformationService.java index 05c6e366ed3..9527ee5848a 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectStaffTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectStaffTransformationService.java @@ -67,7 +67,7 @@ static class ProjectStaffIndexV1Transformer implements @Override public List transform(ProjectStaff projectStaff) { Map boundaryLabelToNameMap = projectService - .getBoundaryLabelToNameMap(projectStaff.getProjectId(), projectStaff.getTenantId()); + .getBoundaryLabelToNameMapByProjectId(projectStaff.getProjectId(), projectStaff.getTenantId()); log.info("boundary labels {}", boundaryLabelToNameMap.toString()); return Collections.singletonList(ProjectStaffIndexV1.builder() .id(projectStaff.getId()) diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java index c4ec7c8318a..d19c231f9c0 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java @@ -66,7 +66,7 @@ static class ProjectTaskIndexV1Transformer implements @Override public List transform(Task task) { Map boundaryLabelToNameMap = projectService - .getBoundaryLabelToNameMap(task.getProjectId(), task.getTenantId()); + .getBoundaryLabelToNameMap(task.getAddress().getBoundary(), task.getTenantId()); log.info("boundary labels {}", boundaryLabelToNameMap.toString()); return task.getResources().stream().map(r -> ProjectTaskIndexV1.builder() diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTransformationService.java index d45c82d7c14..fae2d3667f8 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTransformationService.java @@ -70,7 +70,7 @@ static class ProjectIndexV1Transformer implements @Override public List transform(Project project) { Map boundaryLabelToNameMap = projectService - .getBoundaryLabelToNameMap(project, project.getAddress().getBoundary()); + .getBoundaryLabelToNameMap(project.getAddress().getBoundary(), project.getTenantId()); log.info("boundary labels {}", boundaryLabelToNameMap.toString()); List targets = project.getTargets(); if (targets == null || targets.isEmpty()) { diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java index 68fcaedcda9..d5d10e21372 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java @@ -77,7 +77,7 @@ public List transform(Service service) { String projectName = parts[0]; String supervisorLevel = parts[2]; String projectId = projectService.getProjectByName(projectName, service.getTenantId()).getId(); - Map boundaryLabelToNameMap = projectService.getBoundaryLabelToNameMap(projectId, service.getTenantId()); + Map boundaryLabelToNameMap = projectService.getBoundaryLabelToNameMapByProjectId(projectId, service.getTenantId()); log.info("boundary labels {}", boundaryLabelToNameMap.toString()); return Collections.singletonList(ServiceIndexV1.builder() .id(service.getId()) diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java index 761022be6e7..51fb868d6c0 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java @@ -16,8 +16,6 @@ import java.util.Map; import java.util.stream.Collectors; -import static org.egov.transformer.Constants.PROJECT; - @Slf4j public abstract class StockTransformationService implements TransformationService{ protected final StockTransformationService.StockIndexV1Transformer transformer; @@ -74,11 +72,13 @@ static class StockIndexV1Transformer implements @Override public List transform(Stock stock) { Map boundaryLabelToNameMap = null; - if (stock.getReferenceIdType().equals(PROJECT)) { - boundaryLabelToNameMap = projectService - .getBoundaryLabelToNameMap(stock.getReferenceId(), stock.getTenantId()); - } - Facility facility = facilityService.findFacilityById(stock.getFacilityId(), stock.getTenantId());; +// if (stock.getReferenceIdType().equals(PROJECT)) { +// boundaryLabelToNameMap = projectService +// .getBoundaryLabelToNameMap(stock.getReferenceId(), stock.getTenantId()); +// } + Facility facility = facilityService.findFacilityById(stock.getFacilityId(), stock.getTenantId()); + boundaryLabelToNameMap = projectService + .getBoundaryLabelToNameMap(facility.getAddress().getLocality().getCode(), stock.getTenantId()); return Collections.singletonList(StockIndexV1.builder() .id(stock.getId()) From f9c86cd6236c3d55bbe917b89c994c70ead672c2 Mon Sep 17 00:00:00 2001 From: Vishal Date: Sun, 14 May 2023 18:07:06 +0530 Subject: [PATCH 029/283] [hlm-1834]: debug transformer changes for boundary --- .../transformer/service/ProjectTaskTransformationService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java index d19c231f9c0..1b0a212480d 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java @@ -66,7 +66,7 @@ static class ProjectTaskIndexV1Transformer implements @Override public List transform(Task task) { Map boundaryLabelToNameMap = projectService - .getBoundaryLabelToNameMap(task.getAddress().getBoundary(), task.getTenantId()); + .getBoundaryLabelToNameMap(task.getAddress().getLocality().getCode(), task.getTenantId()); log.info("boundary labels {}", boundaryLabelToNameMap.toString()); return task.getResources().stream().map(r -> ProjectTaskIndexV1.builder() From 60039c4abc76652f8e86076bbff65c7c9a17a808 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Mon, 15 May 2023 11:17:25 +0530 Subject: [PATCH 030/283] [hlm-2375]: Added user details columns --- .../V20230515111200__add_userdetails_in_individual_ddl.sql | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 health-services/individual/src/main/resources/db/migration/main/V20230515111200__add_userdetails_in_individual_ddl.sql diff --git a/health-services/individual/src/main/resources/db/migration/main/V20230515111200__add_userdetails_in_individual_ddl.sql b/health-services/individual/src/main/resources/db/migration/main/V20230515111200__add_userdetails_in_individual_ddl.sql new file mode 100644 index 00000000000..6623ced3cd9 --- /dev/null +++ b/health-services/individual/src/main/resources/db/migration/main/V20230515111200__add_userdetails_in_individual_ddl.sql @@ -0,0 +1,4 @@ +ALTER TABLE INDIVIDUAL ADD COLUMN username character varying(64); +ALTER TABLE INDIVIDUAL ADD COLUMN password character varying(200); +ALTER TABLE INDIVIDUAL ADD COLUMN type character varying(64); +ALTER TABLE INDIVIDUAL ADD COLUMN roles jsonb; \ No newline at end of file From c9eb20ba3bf9173eba24932408699d795dfd0ab2 Mon Sep 17 00:00:00 2001 From: Vishal Date: Mon, 15 May 2023 13:13:56 +0530 Subject: [PATCH 031/283] [hlm-1834]: fixed null pointers in transformer --- .../ProjectTaskTransformationService.java | 22 +++++++++++++------ .../service/StockTransformationService.java | 17 +++++++++----- 2 files changed, 26 insertions(+), 13 deletions(-) diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java index 1b0a212480d..ed8bf1574bd 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java @@ -65,9 +65,16 @@ static class ProjectTaskIndexV1Transformer implements @Override public List transform(Task task) { - Map boundaryLabelToNameMap = projectService - .getBoundaryLabelToNameMap(task.getAddress().getLocality().getCode(), task.getTenantId()); + Map boundaryLabelToNameMap = null; + if (task.getAddress().getLocality() != null && task.getAddress().getLocality().getCode() != null) { + boundaryLabelToNameMap = projectService + .getBoundaryLabelToNameMap(task.getAddress().getLocality().getCode(), task.getTenantId()); + } else { + boundaryLabelToNameMap = projectService + .getBoundaryLabelToNameMapByProjectId(task.getProjectId(), task.getTenantId()); + } log.info("boundary labels {}", boundaryLabelToNameMap.toString()); + Map finalBoundaryLabelToNameMap = boundaryLabelToNameMap; return task.getResources().stream().map(r -> ProjectTaskIndexV1.builder() .id(r.getId()) @@ -81,11 +88,12 @@ public List transform(Task task) { .quantity(r.getQuantity()) .deliveredTo("HOUSEHOLD") .deliveryComments(r.getDeliveryComment()) - .province(boundaryLabelToNameMap.get(properties.getProvince())) - .district(boundaryLabelToNameMap.get(properties.getDistrict())) - .administrativeProvince(boundaryLabelToNameMap.get(properties.getAdministrativeProvince())) - .locality(boundaryLabelToNameMap.get(properties.getLocality())) - .village(boundaryLabelToNameMap.get(properties.getVillage())) + .province(finalBoundaryLabelToNameMap != null ? finalBoundaryLabelToNameMap.get(properties.getProvince()) : null) + .district(finalBoundaryLabelToNameMap != null ? finalBoundaryLabelToNameMap.get(properties.getDistrict()) : null) + .administrativeProvince(finalBoundaryLabelToNameMap != null ? + finalBoundaryLabelToNameMap.get(properties.getAdministrativeProvince()) : null) + .locality(finalBoundaryLabelToNameMap != null ? finalBoundaryLabelToNameMap.get(properties.getLocality()) : null) + .village(finalBoundaryLabelToNameMap != null ? finalBoundaryLabelToNameMap.get(properties.getVillage()) : null) .latitude(task.getAddress().getLatitude()) .longitude(task.getAddress().getLongitude()) .createdTime(task.getAuditDetails().getCreatedTime()) diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java index 51fb868d6c0..7e03a9c8e1e 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java @@ -16,6 +16,8 @@ import java.util.Map; import java.util.stream.Collectors; +import static org.egov.transformer.Constants.PROJECT; + @Slf4j public abstract class StockTransformationService implements TransformationService{ protected final StockTransformationService.StockIndexV1Transformer transformer; @@ -72,13 +74,16 @@ static class StockIndexV1Transformer implements @Override public List transform(Stock stock) { Map boundaryLabelToNameMap = null; -// if (stock.getReferenceIdType().equals(PROJECT)) { -// boundaryLabelToNameMap = projectService -// .getBoundaryLabelToNameMap(stock.getReferenceId(), stock.getTenantId()); -// } Facility facility = facilityService.findFacilityById(stock.getFacilityId(), stock.getTenantId()); - boundaryLabelToNameMap = projectService - .getBoundaryLabelToNameMap(facility.getAddress().getLocality().getCode(), stock.getTenantId()); + if (facility.getAddress().getLocality() != null && facility.getAddress().getLocality().getCode() != null) { + boundaryLabelToNameMap = projectService + .getBoundaryLabelToNameMap(facility.getAddress().getLocality().getCode(), stock.getTenantId()); + } else { + if (stock.getReferenceIdType().equals(PROJECT)) { + boundaryLabelToNameMap = projectService + .getBoundaryLabelToNameMapByProjectId(stock.getReferenceId(), stock.getTenantId()); + } + } return Collections.singletonList(StockIndexV1.builder() .id(stock.getId()) From ce31f6e9a1d970c36853cff22f7e760cd89fcba3 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Tue, 16 May 2023 18:17:34 +0530 Subject: [PATCH 032/283] [hlm-2375]: Fixed column name --- .../individual/repository/rowmapper/IndividualRowMapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java index e3474a539df..5014900598a 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java @@ -59,7 +59,7 @@ public Individual mapRow(ResultSet resultSet, int i) throws SQLException { .userDetails(UserDetails.builder() .username(resultSet.getString("username")) .password(resultSet.getString("password")) - .userType(UserType.fromValue(resultSet.getString("userType"))) + .userType(UserType.fromValue(resultSet.getString("type"))) .roles(resultSet.getString("roles") == null ? null : objectMapper.readValue(resultSet.getString("roles"), List.class)) From 844a915c51bc4bef916b33d5a7c096f58f1361ff Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Wed, 17 May 2023 14:49:17 +0530 Subject: [PATCH 033/283] [hlm-2848]: Check bandwidth endpoint --- .../web/controllers/BandwidthController.java | 34 +++++++++++++++++++ .../web/models/BandwidthCheckRequest.java | 30 ++++++++++++++++ .../web/models/BandwidthCheckResponse.java | 30 ++++++++++++++++ 3 files changed, 94 insertions(+) create mode 100644 health-services/project/src/main/java/org/egov/project/web/controllers/BandwidthController.java create mode 100644 health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckRequest.java create mode 100644 health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckResponse.java diff --git a/health-services/project/src/main/java/org/egov/project/web/controllers/BandwidthController.java b/health-services/project/src/main/java/org/egov/project/web/controllers/BandwidthController.java new file mode 100644 index 00000000000..e18a7cc1c41 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/web/controllers/BandwidthController.java @@ -0,0 +1,34 @@ +package org.egov.project.web.controllers; + +import io.swagger.annotations.ApiParam; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.utils.ResponseInfoFactory; +import org.egov.project.web.models.BandwidthCheckRequest; +import org.egov.project.web.models.BandwidthCheckResponse; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.validation.Valid; + +@Controller +@RequestMapping("") +@Validated +@Slf4j +public class BandwidthController { + + + @RequestMapping(value = "/check/bandwidth", method = RequestMethod.POST) + public ResponseEntity checkBandwidth(@ApiParam(value = "Captures dummy json data", required = true) @Valid @RequestBody BandwidthCheckRequest request) { + log.info("Request received: {}", request); + return ResponseEntity.status(HttpStatus.OK).body(BandwidthCheckResponse.builder() + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .additionalFields(request.getAdditionalFields()) + .build()); + } +} diff --git a/health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckRequest.java b/health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckRequest.java new file mode 100644 index 00000000000..ceffcb45320 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckRequest.java @@ -0,0 +1,30 @@ +package org.egov.project.web.models; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.project.AdditionalFields; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +@Validated +@JsonIgnoreProperties(ignoreUnknown = true) + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BandwidthCheckRequest { + + @JsonProperty("RequestInfo") + private @NotNull @Valid RequestInfo requestInfo = null; + + @JsonProperty("additionalFields") + private @Valid AdditionalFields additionalFields = null; +} diff --git a/health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckResponse.java b/health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckResponse.java new file mode 100644 index 00000000000..96b977556fb --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckResponse.java @@ -0,0 +1,30 @@ +package org.egov.project.web.models; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.project.AdditionalFields; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +@Validated +@JsonIgnoreProperties(ignoreUnknown = true) + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BandwidthCheckResponse { + + @JsonProperty("ResponseInfo") + private @NotNull @Valid ResponseInfo responseInfo = null; + + @JsonProperty("additionalFields") + private @Valid AdditionalFields additionalFields = null; +} From db377c0471e7824a262736c6ddefb7cf84ab6c83 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Wed, 17 May 2023 15:32:53 +0530 Subject: [PATCH 034/283] [hlm-2847]: Changing data type from bigint to double --- .../main/V20230517152900__project_address_lat_long_ddl.sql | 1 + 1 file changed, 1 insertion(+) create mode 100644 health-services/project/src/main/resources/db/migration/main/V20230517152900__project_address_lat_long_ddl.sql diff --git a/health-services/project/src/main/resources/db/migration/main/V20230517152900__project_address_lat_long_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20230517152900__project_address_lat_long_ddl.sql new file mode 100644 index 00000000000..97ac5acb894 --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20230517152900__project_address_lat_long_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE project_address ALTER COLUMN latitude TYPE double precision, ALTER COLUMN longitude TYPE double precision; \ No newline at end of file From e5030aacb9fc5ab1b286a7aa7b908c9a3518d480 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Wed, 17 May 2023 17:38:16 +0530 Subject: [PATCH 035/283] [hlm-2375]: Allowing search using username now --- health-services/individual/pom.xml | 2 +- .../org/egov/individual/repository/IndividualRepository.java | 5 +++++ .../org/egov/individual/web/models/IndividualSearch.java | 4 ++++ health-services/libraries/health-services-models/pom.xml | 2 +- .../org/egov/common/models/individual/IndividualSearch.java | 3 +++ 5 files changed, 14 insertions(+), 2 deletions(-) diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index 069eac9b2c9..f601d6ae0a8 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.4-SNAPSHOT + 1.0.5-SNAPSHOT compile diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index 4d3edb8e48e..98d8cb4bd6f 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -181,6 +181,11 @@ private String getQueryForIndividual(IndividualSearch searchObject, Integer limi } query = query + "]' "; } + + if (searchObject.getUsername() != null) { + query = query + "AND username>=:username "; + paramsMap.put("username", searchObject.getUsername()); + } query = query + "ORDER BY id ASC LIMIT :limit OFFSET :offset"; paramsMap.put("tenantId", tenantId); paramsMap.put("isDeleted", includeDeleted); diff --git a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java b/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java index 65795d32c5a..f6d4b159ce2 100644 --- a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java +++ b/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java @@ -88,5 +88,9 @@ public class IndividualSearch { @JsonProperty("roleCode") @Exclude private List roleCodes = null; + + @Exclude + @JsonProperty("username") + private String username; } diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index 6f46c21530f..b0ae32f821f 100644 --- a/health-services/libraries/health-services-models/pom.xml +++ b/health-services/libraries/health-services-models/pom.xml @@ -6,7 +6,7 @@ org.egov.common health-services-models - 1.0.4-SNAPSHOT + 1.0.5-SNAPSHOT 8 diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java index fe2d75be75e..7fb6de373df 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java @@ -76,5 +76,8 @@ public class IndividualSearch { @JsonProperty("roleCode") private List roleCodes = null; + + @JsonProperty("username") + private String username; } From bad218c8e2a4a6b2845e9e872d8a3d4a3f92dfae Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Tue, 23 May 2023 17:33:55 +0530 Subject: [PATCH 036/283] [hlm-2375]: Updated role object --- health-services/individual/pom.xml | 2 +- .../libraries/health-services-models/pom.xml | 2 +- .../org/egov/common/models/core/Role.java | 24 +++++++++++++++++++ .../common/models/individual/UserDetails.java | 2 +- 4 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Role.java diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index f601d6ae0a8..c9a0b440fa9 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.5-SNAPSHOT + 1.0.6-SNAPSHOT compile diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index b0ae32f821f..a7c232f4b52 100644 --- a/health-services/libraries/health-services-models/pom.xml +++ b/health-services/libraries/health-services-models/pom.xml @@ -6,7 +6,7 @@ org.egov.common health-services-models - 1.0.5-SNAPSHOT + 1.0.6-SNAPSHOT 8 diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Role.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Role.java new file mode 100644 index 00000000000..0f8e02ef0ac --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Role.java @@ -0,0 +1,24 @@ +package org.egov.common.models.core; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Role { + private static final String CITIZEN = "CITIZEN"; + private String name; + private String code; + private String description; + private Long createdBy; + private Date createdDate; + private Long lastModifiedBy; + private Date lastModifiedDate; + private String tenantId; +} \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java index 4b476b71c0a..8e7ed0b5980 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java @@ -1,12 +1,12 @@ package org.egov.common.models.individual; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.user.Role; import digit.models.coremodels.user.enums.UserType; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.models.core.Role; import javax.validation.Valid; import javax.validation.constraints.Size; From 8454a057fd39b8e885c2d303e3a082bbaaf333f0 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Wed, 24 May 2023 14:42:36 +0530 Subject: [PATCH 037/283] [hlm-2375]: Mapping tenantId in user details --- .../individual/repository/rowmapper/IndividualRowMapper.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java index 5014900598a..2c19f1b7d82 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java @@ -25,11 +25,12 @@ public class IndividualRowMapper implements RowMapper { @Override public Individual mapRow(ResultSet resultSet, int i) throws SQLException { try { + String tenantId = resultSet.getString("tenantId"); return Individual.builder().id(resultSet.getString("id")) .individualId(resultSet.getString("individualid")) .userId(resultSet.getString("userId")) .clientReferenceId(resultSet.getString("clientReferenceId")) - .tenantId(resultSet.getString("tenantId")) + .tenantId(tenantId) .name(Name.builder().givenName(resultSet.getString("givenName")) .familyName(resultSet.getString("familyName")) .otherNames(resultSet.getString("otherNames")).build()) @@ -63,6 +64,7 @@ public Individual mapRow(ResultSet resultSet, int i) throws SQLException { .roles(resultSet.getString("roles") == null ? null : objectMapper.readValue(resultSet.getString("roles"), List.class)) + .tenantId(tenantId) .build()) .build(); } catch (JsonProcessingException e) { From f41bb505055de2d95ca2a405d6d5097ae42b44f5 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Wed, 24 May 2023 15:11:27 +0530 Subject: [PATCH 038/283] [hlm-2375]: No audit details in Role --- .../src/main/java/org/egov/common/models/core/Role.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Role.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Role.java index 0f8e02ef0ac..f0e582a9a2d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Role.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Role.java @@ -5,8 +5,6 @@ import lombok.Data; import lombok.NoArgsConstructor; -import java.util.Date; - @Data @AllArgsConstructor @NoArgsConstructor @@ -16,9 +14,5 @@ public class Role { private String name; private String code; private String description; - private Long createdBy; - private Date createdDate; - private Long lastModifiedBy; - private Date lastModifiedDate; private String tenantId; } \ No newline at end of file From 9c7b2eaced008b3187d48feb52b49bca5dc9c79e Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Wed, 24 May 2023 17:03:03 +0530 Subject: [PATCH 039/283] [hlm-2375]: Ignore unknown properties --- .../src/main/java/org/egov/common/models/core/Role.java | 2 ++ .../java/org/egov/common/models/individual/UserDetails.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Role.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Role.java index f0e582a9a2d..d5c0da52bc1 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Role.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Role.java @@ -1,5 +1,6 @@ package org.egov.common.models.core; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,6 +10,7 @@ @AllArgsConstructor @NoArgsConstructor @Builder +@JsonIgnoreProperties(ignoreUnknown = true) public class Role { private static final String CITIZEN = "CITIZEN"; private String name; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java index 8e7ed0b5980..e524ab8389e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java @@ -1,5 +1,6 @@ package org.egov.common.models.individual; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import digit.models.coremodels.user.enums.UserType; import lombok.AllArgsConstructor; @@ -16,6 +17,7 @@ @AllArgsConstructor @NoArgsConstructor @Builder +@JsonIgnoreProperties(ignoreUnknown = true) public class UserDetails { @Size(max=180) @JsonProperty("username") From 88b0f04c208c8970d78415c9794ee54ca5da199e Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Wed, 24 May 2023 17:51:32 +0530 Subject: [PATCH 040/283] [hlm-2375]: Fixed query --- .../org/egov/individual/repository/IndividualRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index 98d8cb4bd6f..fd47baec8de 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -173,7 +173,7 @@ private String getQueryForIndividual(IndividualSearch searchObject, Integer limi if (searchObject.getRoleCodes() != null && !searchObject.getRoleCodes().isEmpty()) { query = query + "AND roles @> '["; for (int i = 0; i < searchObject.getRoleCodes().size(); i++) { - query = query + "{\"code\": \":roleCode\"" + i + "}"; + query = query + "{\"code\": \":roleCode" + i + "\"}"; if (i != searchObject.getRoleCodes().size() - 1) { query = query + ","; } From 3e4f1a3aecd609aca54dc03fd73de81d8d217226 Mon Sep 17 00:00:00 2001 From: SumelRattan-eGov Date: Thu, 25 May 2023 12:37:45 +0530 Subject: [PATCH 041/283] PFM-3117-updated-document-filestore-rowMapping --- .../repository/querybuilder/DocumentQueryBuilder.java | 2 +- .../project/repository/rowmapper/DocumentRowMapper.java | 4 ++-- .../project/src/main/resources/application.properties | 9 +++++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/health-services/project/src/main/java/org/egov/project/repository/querybuilder/DocumentQueryBuilder.java b/health-services/project/src/main/java/org/egov/project/repository/querybuilder/DocumentQueryBuilder.java index 0e38e6f1173..3ef8383ab8a 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/querybuilder/DocumentQueryBuilder.java +++ b/health-services/project/src/main/java/org/egov/project/repository/querybuilder/DocumentQueryBuilder.java @@ -10,7 +10,7 @@ public class DocumentQueryBuilder { private static final String FETCH_DOCUMENT_QUERY = "select d.id as documentId, d.projectId as document_projectId, d.documentType as document_documentType, " + - " d.filestoreId as document_filestoreId, d.documentUid as document_documentUid, d.additionalDetails as document_additionalDetails, d.status as document_status, " + + " d.fileStoreId as document_fileStoreId, d.documentUid as document_documentUid, d.additionalDetails as document_additionalDetails, d.status as document_status, " + "d.createdBy as document_createdBy, d.createdTime as document_createdTime, d.lastModifiedBy as document_lastModifiedBy, d.lastModifiedTime as document_lastModifiedTime " + " from project_document d "; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/DocumentRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/DocumentRowMapper.java index 6322ce82673..b9d3f814d7c 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/DocumentRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/DocumentRowMapper.java @@ -34,7 +34,7 @@ public List extractData(ResultSet rs) throws SQLException, DataAccessE String document_id = rs.getString("documentId"); String document_projectId = rs.getString("document_projectId"); String document_documentType = rs.getString("document_documentType"); - String document_filestoreId = rs.getString("document_filestoreId"); + String document_fileStoreId = rs.getString("document_fileStoreId"); String document_documentUid = rs.getString("document_documentUid"); JsonNode document_additionalDetails = getAdditionalDetail("document_additionalDetails", rs); String document_status = rs.getString("document_status"); @@ -51,7 +51,7 @@ public List extractData(ResultSet rs) throws SQLException, DataAccessE .id(document_id) .projectid(document_projectId) .documentType(document_documentType) - .fileStore(document_filestoreId) + .fileStoreId(document_fileStoreId) .documentUid(document_documentUid) .additionalDetails(document_additionalDetails) .status(document_status) diff --git a/health-services/project/src/main/resources/application.properties b/health-services/project/src/main/resources/application.properties index 22fab270490..2f0deb6e459 100644 --- a/health-services/project/src/main/resources/application.properties +++ b/health-services/project/src/main/resources/application.properties @@ -66,13 +66,13 @@ project.resource.idgen.id.format=project.resource.id kafka.topics.consumer=project-consumer-topic # USER CONFIG -egov.user.host=https://dev.digit.org -#egov.user.host=http://localhost:8286 +#egov.user.host=https://dev.digit.org +egov.user.host=http://localhost:8286 egov.search.user.url=/user/_search egov.user.integration.enabled=true # MDMS CONFIG -egov.mdms.host=https://dev.digit.org +egov.mdms.host=http://localhost:8084 egov.mdms.search.endpoint=/egov-mdms-service/v1/_search egov.mdms.master.name=project_master egov.mdms.module.name=project @@ -140,7 +140,8 @@ project.management.system.kafka.create.topic=save-project project.management.system.kafka.update.topic=update-project #location config -egov.location.host=https://works-dev.digit.org +#egov.location.host=https://works-dev.digit.org +egov.location.host=http://localhost:8082 egov.location.context.path=/egov-location/location/v11/ egov.location.endpoint=/boundarys/_search egov.location.code.query.param=codes From 46766739f4cfc7096a95df1a6b95fbcf290af5a1 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Thu, 25 May 2023 15:55:53 +0530 Subject: [PATCH 042/283] [hlm-2375]: Fixed query for username --- .../org/egov/individual/repository/IndividualRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index fd47baec8de..09673806a85 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -183,7 +183,7 @@ private String getQueryForIndividual(IndividualSearch searchObject, Integer limi } if (searchObject.getUsername() != null) { - query = query + "AND username>=:username "; + query = query + "AND username=:username "; paramsMap.put("username", searchObject.getUsername()); } query = query + "ORDER BY id ASC LIMIT :limit OFFSET :offset"; From eb7d509db0bcb9e30f64451af59744c553d635da Mon Sep 17 00:00:00 2001 From: SumelRattan-eGov Date: Thu, 25 May 2023 16:44:05 +0530 Subject: [PATCH 043/283] revert-app-properties-to-original-state --- .../project/src/main/resources/application.properties | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/health-services/project/src/main/resources/application.properties b/health-services/project/src/main/resources/application.properties index 2f0deb6e459..29077bc0741 100644 --- a/health-services/project/src/main/resources/application.properties +++ b/health-services/project/src/main/resources/application.properties @@ -66,13 +66,13 @@ project.resource.idgen.id.format=project.resource.id kafka.topics.consumer=project-consumer-topic # USER CONFIG -#egov.user.host=https://dev.digit.org -egov.user.host=http://localhost:8286 +egov.user.host=https://dev.digit.org +#egov.user.host=http://localhost:8286 egov.search.user.url=/user/_search egov.user.integration.enabled=true # MDMS CONFIG -egov.mdms.host=http://localhost:8084 +egov.mdms.host=https://dev.digit.org egov.mdms.search.endpoint=/egov-mdms-service/v1/_search egov.mdms.master.name=project_master egov.mdms.module.name=project @@ -140,8 +140,8 @@ project.management.system.kafka.create.topic=save-project project.management.system.kafka.update.topic=update-project #location config -#egov.location.host=https://works-dev.digit.org -egov.location.host=http://localhost:8082 +egov.location.host=https://works-dev.digit.org +#egov.location.host=http://localhost:8082 egov.location.context.path=/egov-location/location/v11/ egov.location.endpoint=/boundarys/_search egov.location.code.query.param=codes From 68171fed04b8420ef07b4f031140400cbcd1faf8 Mon Sep 17 00:00:00 2001 From: SumelRattan-eGov Date: Fri, 26 May 2023 13:32:05 +0530 Subject: [PATCH 044/283] PFM-3358-Added-transgender-enum-value --- .../main/java/org/egov/common/models/individual/Gender.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Gender.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Gender.java index d26c5c186d5..06f45867ab5 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Gender.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Gender.java @@ -14,7 +14,9 @@ public enum Gender { FEMALE("FEMALE"), - OTHER("OTHER"); + OTHER("OTHER"), + + TRANSGENDER("TRANSGENDER"); private String value; From 3ce8a992c98a5e294fd7c91097a8c88b6d2e88db Mon Sep 17 00:00:00 2001 From: SumelRattan-eGov Date: Fri, 26 May 2023 16:35:05 +0530 Subject: [PATCH 045/283] updated-db-migration-for-transgender --- .../main/V20230526162410__alter_individual_gender_ddl.sql | 1 + 1 file changed, 1 insertion(+) create mode 100644 health-services/individual/src/main/resources/db/migration/main/V20230526162410__alter_individual_gender_ddl.sql diff --git a/health-services/individual/src/main/resources/db/migration/main/V20230526162410__alter_individual_gender_ddl.sql b/health-services/individual/src/main/resources/db/migration/main/V20230526162410__alter_individual_gender_ddl.sql new file mode 100644 index 00000000000..f8aac1bc467 --- /dev/null +++ b/health-services/individual/src/main/resources/db/migration/main/V20230526162410__alter_individual_gender_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE INDIVIDUAL ALTER COLUMN gender TYPE character varying(20); \ No newline at end of file From ec6a75438a24579d522d7ade3e2f89bd5f3abd9b Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Mon, 29 May 2023 12:33:27 +0530 Subject: [PATCH 046/283] [hlm-2375]: Fixed models --- .../java/org/egov/individual/web/models/IndividualSearch.java | 2 +- .../org/egov/common/models/individual/IndividualSearch.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java b/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java index f6d4b159ce2..16cb07ab3d8 100644 --- a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java +++ b/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java @@ -85,7 +85,7 @@ public class IndividualSearch { @Exclude private String boundaryCode = null; - @JsonProperty("roleCode") + @JsonProperty("roleCodes") @Exclude private List roleCodes = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java index 7fb6de373df..379b24c2360 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java @@ -74,7 +74,7 @@ public class IndividualSearch { @JsonProperty("boundaryCode") private String boundaryCode = null; - @JsonProperty("roleCode") + @JsonProperty("roleCodes") private List roleCodes = null; @JsonProperty("username") From 976a1f74ae3de2cf2c2c23808eb0e067b1e6643b Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Mon, 29 May 2023 12:59:32 +0530 Subject: [PATCH 047/283] [hlm-2375]: Fixed query --- .../org/egov/individual/repository/IndividualRepository.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index 09673806a85..813614fc957 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -173,11 +173,10 @@ private String getQueryForIndividual(IndividualSearch searchObject, Integer limi if (searchObject.getRoleCodes() != null && !searchObject.getRoleCodes().isEmpty()) { query = query + "AND roles @> '["; for (int i = 0; i < searchObject.getRoleCodes().size(); i++) { - query = query + "{\"code\": \":roleCode" + i + "\"}"; + query = query + "{\"code\": \"" + searchObject.getRoleCodes().get(i) + "\"}"; if (i != searchObject.getRoleCodes().size() - 1) { query = query + ","; } - paramsMap.put("roleCode" + i, searchObject.getRoleCodes().get(i)); } query = query + "]' "; } From 1322165bed5a4a6023e5903163120d133e2d0048 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Tue, 30 May 2023 14:35:02 +0530 Subject: [PATCH 048/283] [hlm-2375]: Checks for identifiers --- .../individual/service/IndividualService.java | 71 +++++++++++-------- 1 file changed, 40 insertions(+), 31 deletions(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java index fb3259848cb..977d63fe3ca 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java @@ -197,19 +197,25 @@ public List update(IndividualBulkRequest request, boolean isBulk) { if (!validIndividuals.isEmpty()) { log.info("processing {} valid entities", validIndividuals.size()); enrichmentService.update(validIndividuals, request); - - // get masked identifiers - List maskedIdentifiers = filterMaskedIdentifiers(validIndividuals); - // remove masked identifiers because we cannot encrypt them again - List individualsToEncrypt = validIndividuals.stream().map(individual -> { - if (!maskedIdentifiers.isEmpty()) { - individual.getIdentifiers().removeAll(maskedIdentifiers - .stream().filter(identifier -> - identifier.getIndividualId().equals(individual.getId())) - .collect(Collectors.toList())); - } - return individual; - }).collect(Collectors.toList()); + boolean identifiersPresent = validIndividuals.stream() + .anyMatch(individual -> individual.getIdentifiers() != null + && !individual.getIdentifiers().isEmpty()); + + List individualsToEncrypt = validIndividuals; + if (identifiersPresent) { + // get masked identifiers + List maskedIdentifiers = filterMaskedIdentifiers(validIndividuals); + // remove masked identifiers because we cannot encrypt them again + individualsToEncrypt = validIndividuals.stream().map(individual -> { + if (!maskedIdentifiers.isEmpty()) { + individual.getIdentifiers().removeAll(maskedIdentifiers + .stream().filter(identifier -> + identifier.getIndividualId().equals(individual.getId())) + .collect(Collectors.toList())); + } + return individual; + }).collect(Collectors.toList()); + } // encrypt new data @@ -221,24 +227,27 @@ public List update(IndividualBulkRequest request, boolean isBulk) { // find existing individuals from db List existingIndividuals = individualRepository.findById(new ArrayList<>(idToObjMap.keySet()), "id", false); - // extract existing identifiers (encrypted) from existing individuals - Map> existingIdentifiers = existingIndividuals.stream() - .map(Individual::getIdentifiers) - .filter(Objects::nonNull) - .flatMap(Collection::stream).collect(Collectors.groupingBy(Identifier::getIndividualId)); - // merge existing identifiers with new identifiers such that they all are encrypted alike - // this is because we cannot merge masked identifiers with new identifiers which are now encrypted - encryptedIndividualList.forEach(encryptedIndividual -> { - List newIdentifiers = encryptedIndividual.getIdentifiers(); - List newIdentifiersIds = getIdList(newIdentifiers); - List identifierList = existingIdentifiers.get(encryptedIndividual.getId()).stream() - .filter(identifier -> !newIdentifiersIds.contains(identifier.getId())) - .collect(Collectors.toList()); - - if (identifierList != null) { - newIdentifiers.addAll(identifierList); - } - }); + + if (identifiersPresent) { + // extract existing identifiers (encrypted) from existing individuals + Map> existingIdentifiers = existingIndividuals.stream() + .map(Individual::getIdentifiers) + .filter(Objects::nonNull) + .flatMap(Collection::stream).collect(Collectors.groupingBy(Identifier::getIndividualId)); + // merge existing identifiers with new identifiers such that they all are encrypted alike + // this is because we cannot merge masked identifiers with new identifiers which are now encrypted + encryptedIndividualList.forEach(encryptedIndividual -> { + List newIdentifiers = encryptedIndividual.getIdentifiers(); + List newIdentifiersIds = getIdList(newIdentifiers); + List identifierList = existingIdentifiers.get(encryptedIndividual.getId()).stream() + .filter(identifier -> !newIdentifiersIds.contains(identifier.getId())) + .collect(Collectors.toList()); + + if (identifierList != null) { + newIdentifiers.addAll(identifierList); + } + }); + } // save individualRepository.save(encryptedIndividualList, From 9896cdbfa5195800dbe47f1f882501d64f08f637 Mon Sep 17 00:00:00 2001 From: Shiva Burade Date: Wed, 31 May 2023 10:27:14 +0530 Subject: [PATCH 049/283] [hlm-2879]: Added facility Name and isDeleted --- .../egov/transformer/models/downstream/ProjectTaskIndexV1.java | 2 ++ .../org/egov/transformer/models/downstream/StockIndexV1.java | 3 +++ .../transformer/service/ProjectTaskTransformationService.java | 1 + .../egov/transformer/service/StockTransformationService.java | 1 + 4 files changed, 7 insertions(+) diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ProjectTaskIndexV1.java b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ProjectTaskIndexV1.java index 4fe8a095493..b72398700f3 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ProjectTaskIndexV1.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ProjectTaskIndexV1.java @@ -57,4 +57,6 @@ public class ProjectTaskIndexV1 { private Long createdTime; @JsonProperty("lastModifiedTime") private Long lastModifiedTime; + @JsonProperty("isDeleted") + private boolean isDeleted; } diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/StockIndexV1.java b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/StockIndexV1.java index b43eea1c3e3..c2796ccdf02 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/StockIndexV1.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/StockIndexV1.java @@ -23,6 +23,9 @@ public class StockIndexV1 { @JsonProperty("facilityId") private String facilityId; + @JsonProperty("facilityName") + private String facilityName; + @JsonProperty("productVariant") private String productVariant; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java index ed8bf1574bd..d4aa3898406 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java @@ -100,6 +100,7 @@ public List transform(Task task) { .createdBy(task.getAuditDetails().getCreatedBy()) .lastModifiedTime(task.getAuditDetails().getLastModifiedTime()) .lastModifiedBy(task.getAuditDetails().getLastModifiedBy()) + .isDeleted(task.getIsDeleted()) .build() ).collect(Collectors.toList()); } diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java index 7e03a9c8e1e..c57877fd110 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java @@ -89,6 +89,7 @@ public List transform(Stock stock) { .id(stock.getId()) .productVariant(stock.getProductVariantId()) .facilityId(stock.getFacilityId()) + .facilityName(facility.getName()) .physicalCount(stock.getQuantity()) .eventType(stock.getTransactionType()) .reason(stock.getTransactionReason()) From f72c48f0948ae591034cf2ed4785557b5a1f04cb Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Wed, 31 May 2023 12:00:11 +0530 Subject: [PATCH 050/283] [hlm-2375]: Fixed user type enum --- .../java/org/egov/individual/service/IndividualMapper.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java index 14dd456b072..a2794e176ba 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java @@ -27,7 +27,7 @@ public static UserRequest toUserRequest(Individual individual, IndividualPropert .mobileNumber(generateDummyMobileNumber(individual.getMobileNumber())) .type(UserType.valueOf(properties.getUserServiceUserType())) .accountLocked(properties.isUserServiceAccountLocked()) - .active(true) + .active(!individual.getIsDeleted()) .userName(null != individual.getUserDetails().getUsername() ? individual.getUserDetails().getUsername() : UUID.randomUUID().toString()) .password(null != individual.getUserDetails().getPassword() ? individual.getUserDetails().getPassword() : null) .roles(individual.getUserDetails().getRoles().stream().map(role -> RoleRequest.builder() @@ -36,7 +36,8 @@ public static UserRequest toUserRequest(Individual individual, IndividualPropert .tenantId(individual.getTenantId()) .build()) .collect(Collectors.toSet())) - .type(UserType.valueOf(individual.getUserDetails().getUserType().name())) + .type(UserType.fromValue(individual.getUserDetails().getUserType() != null + ? individual.getUserDetails().getUserType().name() : null)) .build(); } From 6218837a070976f27b29156588cfd3bf192bb4a5 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Wed, 31 May 2023 14:47:31 +0530 Subject: [PATCH 051/283] [hlm-2375]: Added userUuid --- .../egov/individual/service/IndividualMapper.java | 2 ++ .../individual/service/IndividualService.java | 15 +++++++++------ .../service/UserIntegrationService.java | 13 ++++++------- ...0531131000__add_userUuid_in_individual_ddl.sql | 1 + .../egov/common/models/individual/Individual.java | 3 +++ 5 files changed, 21 insertions(+), 13 deletions(-) create mode 100644 health-services/individual/src/main/resources/db/migration/main/V20230531131000__add_userUuid_in_individual_ddl.sql diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java index a2794e176ba..312ef93adc0 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java @@ -21,6 +21,8 @@ private IndividualMapper() {} public static UserRequest toUserRequest(Individual individual, IndividualProperties properties) { return UserRequest.builder() + .id(Long.parseLong(individual.getUserId())) + .uuid(individual.getUserUuid()) .tenantId(individual.getTenantId()) .name(String.join(" ", individual.getName().getGivenName(), individual.getName().getFamilyName())) diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java index 977d63fe3ca..7800b4a787c 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java @@ -391,12 +391,15 @@ private void integrateWithUserService(IndividualBulkRequest request, log.info("successfully updated user for {} individuals", encryptedIndividualList.size()); } else if (apiOperation.equals(ApiOperation.CREATE)) { - Long userId = userIntegrationService.createUser(encryptedIndividualList, - request.getRequestInfo()).map(UserRequest::getId).orElse(null); - encryptedIndividualList.stream().filter(Individual::getIsSystemUser) - .forEach(individual -> - individual.setUserId(userId != null ? - Long.toString(userId) : null)); + List userRequests = userIntegrationService.createUser(encryptedIndividualList, + request.getRequestInfo()); + for (int i = 0; i < encryptedIndividualList.size(); i++) { + if (Boolean.TRUE.equals(encryptedIndividualList.get(i).getIsSystemUser())) { + encryptedIndividualList.get(i) + .setUserId(Long.toString(userRequests.get(i).getId())); + encryptedIndividualList.get(i).setUserUuid(userRequests.get(i).getUuid()); + } + } individualRepository.save(encryptedIndividualList, properties.getUpdateUserIdTopic()); log.info("successfully created user for {} individuals", diff --git a/health-services/individual/src/main/java/org/egov/individual/service/UserIntegrationService.java b/health-services/individual/src/main/java/org/egov/individual/service/UserIntegrationService.java index 74c7fccf103..18e2323cc8d 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/UserIntegrationService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/UserIntegrationService.java @@ -11,7 +11,6 @@ import org.springframework.stereotype.Service; import java.util.List; -import java.util.Optional; import java.util.function.Function; import java.util.stream.Collectors; @@ -29,7 +28,7 @@ public UserIntegrationService(UserService userService, IndividualProperties indi this.individualProperties = individualProperties; } - public Optional createUser(List validIndividuals, + public List createUser(List validIndividuals, RequestInfo requestInfo) { log.info("integrating with user service"); List userRequests = validIndividuals.stream() @@ -37,11 +36,11 @@ public Optional createUser(List validIndividuals, .collect(Collectors.toList()); return userRequests.stream().flatMap(userRequest -> userService.create( new CreateUserRequest(requestInfo, - userRequest)).stream()).collect(Collectors.toList()).stream().findFirst(); + userRequest)).stream()).collect(Collectors.toList()); } - public Optional updateUser(List validIndividuals, + public List updateUser(List validIndividuals, RequestInfo requestInfo) { log.info("updating the user in user service"); List userRequests = validIndividuals.stream() @@ -49,10 +48,10 @@ public Optional updateUser(List validIndividuals, .collect(Collectors.toList()); return userRequests.stream().flatMap(userRequest -> userService.update( new CreateUserRequest(requestInfo, - userRequest)).stream()).collect(Collectors.toList()).stream().findFirst(); + userRequest)).stream()).collect(Collectors.toList()); } - public Optional deleteUser(List validIndividuals, + public List deleteUser(List validIndividuals, RequestInfo requestInfo) { log.info("deleting the user in user service"); List userRequests = validIndividuals.stream() @@ -61,7 +60,7 @@ public Optional deleteUser(List validIndividuals, .collect(Collectors.toList()); return userRequests.stream().flatMap(userRequest -> userService.update( new CreateUserRequest(requestInfo, - userRequest)).stream()).collect(Collectors.toList()).stream().findFirst(); + userRequest)).stream()).collect(Collectors.toList()); } private Function toUserRequest() { diff --git a/health-services/individual/src/main/resources/db/migration/main/V20230531131000__add_userUuid_in_individual_ddl.sql b/health-services/individual/src/main/resources/db/migration/main/V20230531131000__add_userUuid_in_individual_ddl.sql new file mode 100644 index 00000000000..b2ba6fbe1b3 --- /dev/null +++ b/health-services/individual/src/main/resources/db/migration/main/V20230531131000__add_userUuid_in_individual_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE INDIVIDUAL ADD COLUMN userUuid character varying(64); \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java index 93f16b8d7aa..2f43dbc17a4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java @@ -53,6 +53,9 @@ public class Individual { @JsonProperty("userId") private String userId = null; + @JsonProperty("userUuid") + private String userUuid = null; + @JsonProperty("name") @NotNull @Valid From c3aa7d35700d5a3e468f8e15651b8cd758e3d5b8 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Wed, 31 May 2023 15:10:45 +0530 Subject: [PATCH 052/283] [hlm-2375]: NPE fix --- .../java/org/egov/individual/service/IndividualMapper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java index 312ef93adc0..d93fc7e35b2 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java @@ -19,9 +19,9 @@ public class IndividualMapper { private IndividualMapper() {} public static UserRequest toUserRequest(Individual individual, IndividualProperties properties) { - + Long id = individual.getUserId() != null ? Long.parseLong(individual.getUserId()) : null; return UserRequest.builder() - .id(Long.parseLong(individual.getUserId())) + .id(id) .uuid(individual.getUserUuid()) .tenantId(individual.getTenantId()) .name(String.join(" ", individual.getName().getGivenName(), From 8a421d7dd8fafeaa917e51a0a4955b496200eb8a Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Wed, 31 May 2023 17:01:21 +0530 Subject: [PATCH 053/283] [hlm-2375]: UserUuid fix --- .../rowmapper/IndividualRowMapper.java | 1 + .../individual/service/IndividualMapper.java | 1 - .../main/resources/individual-persister.yml | 35 ++++++++++++++++--- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java index 2c19f1b7d82..c56fd0a173c 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java @@ -66,6 +66,7 @@ public Individual mapRow(ResultSet resultSet, int i) throws SQLException { List.class)) .tenantId(tenantId) .build()) + .userUuid(resultSet.getString("userUuid")) .build(); } catch (JsonProcessingException e) { throw new RuntimeException(e); diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java index d93fc7e35b2..0d4c34d511d 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java @@ -22,7 +22,6 @@ public static UserRequest toUserRequest(Individual individual, IndividualPropert Long id = individual.getUserId() != null ? Long.parseLong(individual.getUserId()) : null; return UserRequest.builder() .id(id) - .uuid(individual.getUserUuid()) .tenantId(individual.getTenantId()) .name(String.join(" ", individual.getName().getGivenName(), individual.getName().getFamilyName())) diff --git a/health-services/individual/src/main/resources/individual-persister.yml b/health-services/individual/src/main/resources/individual-persister.yml index de75eee7c94..7e0739d39fc 100644 --- a/health-services/individual/src/main/resources/individual-persister.yml +++ b/health-services/individual/src/main/resources/individual-persister.yml @@ -26,11 +26,12 @@ serviceMaps: - jsonPath: $.*.address.*.street - jsonPath: $.*.address.*.locality.code - jsonPath: $.*.address.*.ward.code - - query: INSERT INTO individual(id, userId, clientReferenceId, tenantId, givenName, familyName, otherNames, dateOfBirth, gender, bloodGroup, mobileNumber, altContactNumber, email, fatherName, husbandName, photo, additionalDetails, createdBy, lastModifiedBy, createdTime, lastModifiedTime, rowVersion, isDeleted, individualId, relationship) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + - query: INSERT INTO individual(id, userId, userUuid, clientReferenceId, tenantId, givenName, familyName, otherNames, dateOfBirth, gender, bloodGroup, mobileNumber, altContactNumber, email, fatherName, husbandName, photo, additionalDetails, createdBy, lastModifiedBy, createdTime, lastModifiedTime, rowVersion, isDeleted, individualId, relationship, isSystemUser, username, password, type, roles) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); basePath: $.* jsonMaps: - jsonPath: $.*.id - jsonPath: $.*.userId + - jsonPath: $.*.userUuid - jsonPath: $.*.clientReferenceId - jsonPath: $.*.tenantId - jsonPath: $.*.name.givenName @@ -57,6 +58,13 @@ serviceMaps: - jsonPath: $.*.isDeleted - jsonPath: $.*.individualId - jsonPath: $.*.relationship + - jsonPath: $.*.isSystemUser + - jsonPath: $.*.userDetails.username + - jsonPath: $.*.userDetails.password + - jsonPath: $.*.userDetails.type + - jsonPath: $.*.userDetails.roles + type: JSON + dbType: JSONB - query: INSERT INTO individual_address(individualId, addressId, type, createdBy, lastModifiedBy, createdTime, lastModifiedTime, isDeleted) VALUES (?, ?, ?, ?, ?, ?, ?, ?); basePath: $.*.address.* jsonMaps: @@ -101,10 +109,11 @@ serviceMaps: fromTopic: update-individual-topic isTransaction: true queryMaps: - - query: UPDATE individual SET userId=?, tenantId=?, givenName=?, familyName=?, otherNames=?, dateOfBirth=?, Gender=?, bloodGroup=?, mobileNumber=?, altContactNumber=?, email=?, fatherName=?, husbandName=?, relationship=?, photo=?, additionalDetails=?, lastModifiedBy=?, lastModifiedTime=?, rowVersion=? WHERE id=? AND isDeleted=false; + - query: UPDATE individual SET userId=?, userUuid=?, tenantId=?, givenName=?, familyName=?, otherNames=?, dateOfBirth=?, Gender=?, bloodGroup=?, mobileNumber=?, altContactNumber=?, email=?, fatherName=?, husbandName=?, relationship=?, photo=?, additionalDetails=?, lastModifiedBy=?, lastModifiedTime=?, rowVersion=?, username = ?, password = ?, type = ?, roles = ? WHERE id=? AND isDeleted=false; basePath: $.* jsonMaps: - jsonPath: $.*.userId + - jsonPath: $.*.userUuid - jsonPath: $.*.tenantId - jsonPath: $.*.name.givenName - jsonPath: $.*.name.familyName @@ -126,6 +135,12 @@ serviceMaps: - jsonPath: $.*.auditDetails.lastModifiedBy - jsonPath: $.*.auditDetails.lastModifiedTime - jsonPath: $.*.rowVersion + - jsonPath: $.*.userDetails.username + - jsonPath: $.*.userDetails.password + - jsonPath: $.*.userDetails.type + - jsonPath: $.*.userDetails.roles + type: JSON + dbType: JSONB - jsonPath: $.*.id - query: INSERT INTO address(id, clientReferenceId, tenantId, doorNo, latitude, longitude, locationAccuracy, type, addressLine1, addressLine2, landmark, city, pincode, buildingName, street, localityCode, wardCode) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (id) DO UPDATE SET doorno=?, latitude=?, longitude=?, locationaccuracy=?, type=?, addressline1=?, addressline2=?, landmark=?, city=?, pincode=?, buildingname=?, street=?, localitycode=?, wardCode=?; basePath: $.*.address.* @@ -174,7 +189,7 @@ serviceMaps: - jsonPath: $.*.address.*.isDeleted - jsonPath: $.*.address.*.auditDetails.lastModifiedBy - jsonPath: $.*.address.*.auditDetails.lastModifiedTime - - query: INSERT INTO individual_identifier(id, clientReferenceId, individualId, identifierType, identifierId, createdBy, lastModifiedBy, createdTime, lastModifiedTime, isDeleted) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (id) WHERE isDeleted=false DO UPDATE SET identifierId = ?, lastModifiedBy = ?, lastModifiedTime = ?; + - query: INSERT INTO individual_identifier(id, clientReferenceId, individualId, identifierType, identifierId, createdBy, lastModifiedBy, createdTime, lastModifiedTime, isDeleted) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (id) WHERE isDeleted=false DO UPDATE SET identifierId = ?, identifierType = ?, lastModifiedBy = ?, lastModifiedTime = ?; basePath: $.*.identifiers.* jsonMaps: - jsonPath: $.*.identifiers.*.id @@ -188,6 +203,7 @@ serviceMaps: - jsonPath: $.*.identifiers.*.auditDetails.lastModifiedTime - jsonPath: $.*.identifiers.*.isDeleted - jsonPath: $.*.identifiers.*.identifierId + - jsonPath: $.*.identifiers.*.identifierType - jsonPath: $.*.identifiers.*.auditDetails.lastModifiedBy - jsonPath: $.*.identifiers.*.auditDetails.lastModifiedTime - query: INSERT INTO individual_skill(id, clientReferenceId, individualId, type, level, experience, createdBy, lastModifiedBy, createdTime, lastModifiedTime, isDeleted) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (id) WHERE isDeleted=false DO UPDATE SET type = ?, level = ?, experience = ?, lastModifiedBy = ?, lastModifiedTime = ?; @@ -244,4 +260,15 @@ serviceMaps: - jsonPath: $.*.skills.*.auditDetails.lastModifiedBy - jsonPath: $.*.skills.*.auditDetails.lastModifiedTime - jsonPath: $.*.skills.*.isDeleted - - jsonPath: $.*.skills.*.id \ No newline at end of file + - jsonPath: $.*.skills.*.id + + - version: 1.0 + description: Updates userId received from user-service into an individual + fromTopic: update-user-id-topic + isTransaction: true + queryMaps: + - query: UPDATE individual SET userId=? WHERE id=?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.userId + - jsonPath: $.*.id \ No newline at end of file From 573f6f8423cb959a956fdf25146f1af882a76100 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Thu, 1 Jun 2023 10:21:53 +0530 Subject: [PATCH 054/283] [hlm-2375]: UserUuid fix --- .../java/org/egov/individual/service/IndividualMapper.java | 1 + .../individual/src/main/resources/individual-persister.yml | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java index 0d4c34d511d..d93fc7e35b2 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java @@ -22,6 +22,7 @@ public static UserRequest toUserRequest(Individual individual, IndividualPropert Long id = individual.getUserId() != null ? Long.parseLong(individual.getUserId()) : null; return UserRequest.builder() .id(id) + .uuid(individual.getUserUuid()) .tenantId(individual.getTenantId()) .name(String.join(" ", individual.getName().getGivenName(), individual.getName().getFamilyName())) diff --git a/health-services/individual/src/main/resources/individual-persister.yml b/health-services/individual/src/main/resources/individual-persister.yml index 7e0739d39fc..de6ff66723b 100644 --- a/health-services/individual/src/main/resources/individual-persister.yml +++ b/health-services/individual/src/main/resources/individual-persister.yml @@ -263,12 +263,13 @@ serviceMaps: - jsonPath: $.*.skills.*.id - version: 1.0 - description: Updates userId received from user-service into an individual + description: Updates userId and userUuid received from user-service into an individual fromTopic: update-user-id-topic isTransaction: true queryMaps: - - query: UPDATE individual SET userId=? WHERE id=?; + - query: UPDATE individual SET userId=?, userUuid=? WHERE id=?; basePath: $.* jsonMaps: - jsonPath: $.*.userId + - jsonPath: $.*.userUuid - jsonPath: $.*.id \ No newline at end of file From c0add8b151e5b69b37b1269b5f473799a973fed9 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Thu, 1 Jun 2023 16:45:30 +0530 Subject: [PATCH 055/283] [hlm-2375]: Added isSystemUserActive field --- .../individual/repository/rowmapper/IndividualRowMapper.java | 1 + ...0230601163900__add_isSystemUserActive_in_individual_ddl.sql | 1 + .../java/org/egov/common/models/individual/Individual.java | 3 +++ 3 files changed, 5 insertions(+) create mode 100644 health-services/individual/src/main/resources/db/migration/main/V20230601163900__add_isSystemUserActive_in_individual_ddl.sql diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java index c56fd0a173c..2176427b64f 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java @@ -57,6 +57,7 @@ public Individual mapRow(ResultSet resultSet, int i) throws SQLException { .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) .isSystemUser(resultSet.getBoolean("isSystemUser")) + .isSystemUserActive(resultSet.getBoolean("isSystemUserActive")) .userDetails(UserDetails.builder() .username(resultSet.getString("username")) .password(resultSet.getString("password")) diff --git a/health-services/individual/src/main/resources/db/migration/main/V20230601163900__add_isSystemUserActive_in_individual_ddl.sql b/health-services/individual/src/main/resources/db/migration/main/V20230601163900__add_isSystemUserActive_in_individual_ddl.sql new file mode 100644 index 00000000000..3aefbd11705 --- /dev/null +++ b/health-services/individual/src/main/resources/db/migration/main/V20230601163900__add_isSystemUserActive_in_individual_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE INDIVIDUAL ADD COLUMN isSystemUserActive boolean; \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java index 2f43dbc17a4..2bef4522ef4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java @@ -133,6 +133,9 @@ public class Individual { @JsonProperty("isSystemUser") private Boolean isSystemUser = Boolean.FALSE; + @JsonProperty("isSystemUserActive") + private Boolean isSystemUserActive = Boolean.TRUE; + @JsonProperty("userDetails") private UserDetails userDetails; From a309077e25078d8bb304b1b6fb5fa423177e76c9 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Thu, 1 Jun 2023 16:54:10 +0530 Subject: [PATCH 056/283] [hlm-2375]: Fix in user request for isSystemUserActive field --- .../main/java/org/egov/individual/service/IndividualMapper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java index d93fc7e35b2..f788d19370b 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java @@ -29,7 +29,7 @@ public static UserRequest toUserRequest(Individual individual, IndividualPropert .mobileNumber(generateDummyMobileNumber(individual.getMobileNumber())) .type(UserType.valueOf(properties.getUserServiceUserType())) .accountLocked(properties.isUserServiceAccountLocked()) - .active(!individual.getIsDeleted()) + .active(individual.getIsSystemUserActive()) .userName(null != individual.getUserDetails().getUsername() ? individual.getUserDetails().getUsername() : UUID.randomUUID().toString()) .password(null != individual.getUserDetails().getPassword() ? individual.getUserDetails().getPassword() : null) .roles(individual.getUserDetails().getRoles().stream().map(role -> RoleRequest.builder() From 1ab49a414e5fbd8b851cd33768c54efd7da2d0dd Mon Sep 17 00:00:00 2001 From: bhanuprakash-egov Date: Thu, 1 Jun 2023 22:22:38 +0530 Subject: [PATCH 057/283] sorting keys in summary reports --- .../AdvanceTableChartResponseHandler.java | 12 +++++++++-- .../analytics/helper/SortingHelper.java | 20 ++++++++++++++++++- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/AdvanceTableChartResponseHandler.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/AdvanceTableChartResponseHandler.java index dd41cca5179..8b81053c58b 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/AdvanceTableChartResponseHandler.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/AdvanceTableChartResponseHandler.java @@ -12,6 +12,7 @@ import com.tarento.analytics.dto.Plot; import com.tarento.analytics.helper.ComputedFieldFactory; import com.tarento.analytics.helper.IComputedField; +import com.tarento.analytics.helper.SortingHelper; import com.tarento.analytics.model.ComputedFields; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -33,6 +34,8 @@ public class AdvanceTableChartResponseHandler implements IResponseHandler { @Autowired private ObjectMapper mapper; + @Autowired + private SortingHelper sortingHelper; @Autowired private ComputedFieldFactory computedFieldFactory; @@ -116,6 +119,7 @@ public AggregateDto translate(AggregateRequestDto requestDto, ObjectNode aggrega }); }); + List finalDataList = dataList; mappings.entrySet().stream().forEach(plotMap -> { List plotList = plotMap.getValue().values().stream().collect(Collectors.toList()); //filter out data object with all zero data. @@ -146,7 +150,7 @@ public AggregateDto translate(AggregateRequestDto requestDto, ObjectNode aggrega logger.error("execution of computed field :"+e.getMessage()); } } - dataList.add(data); + finalDataList.add(data); } }); @@ -168,7 +172,11 @@ public AggregateDto translate(AggregateRequestDto requestDto, ObjectNode aggrega }); } } - + + if (chartNode.has("sort")) { + dataList = sortingHelper.tableSort(dataList, chartNode.get("sort").asText()); + } + return getAggregatedDto(chartNode, dataList, requestDto.getVisualizationCode()); } diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/SortingHelper.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/SortingHelper.java index fcd11c1f943..5101bfa72df 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/SortingHelper.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/SortingHelper.java @@ -2,7 +2,6 @@ import org.springframework.stereotype.Component; import com.tarento.analytics.dto.Data; import com.tarento.analytics.dto.Plot; -import java.util.*; import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -21,6 +20,11 @@ public List sort(String sortingKey, List dataList) { } return dataList; } + public List tableSort(List dataList, String sortingKey) { + Comparator tableSortComparator = tableSortComparator(sortingKey); + dataList.sort(tableSortComparator); + return dataList; + } private static Comparator plotSortComparator(String sortingKey, Boolean isValueSortingApplicable) { return new Comparator() { @@ -48,4 +52,18 @@ public int compare(Plot p1, Plot p2) { }; } + private static Comparator tableSortComparator(String sortingKey) { + return (p1, p2) -> { + String plotName1 = p1.getHeaderName().toUpperCase(); + String plotName2 = p2.getHeaderName().toUpperCase(); + + if (sortingKey.equals(SORT_KEY_ASC)) { + return plotName1.compareTo(plotName2); + } else if (sortingKey.equals(SORT_KEY_DESC)) { + return plotName2.compareTo(plotName1); + } + return 0; + }; + } + } \ No newline at end of file From c9e8a0c1e1f298c7511057b2b88be8bed77cf4ab Mon Sep 17 00:00:00 2001 From: bhanuprakash-egov Date: Fri, 2 Jun 2023 19:07:52 +0530 Subject: [PATCH 058/283] limiting dateRange targetValues to overallTarget --- .../handler/MetricChartResponseHandler.java | 17 +++- .../helper/AdditiveComputedField.java | 9 +- .../analytics/helper/ComputeHelper.java | 3 +- .../analytics/helper/NoOpsComputedField.java | 10 +- .../helper/TargetPerDateComputeHelper.java | 94 +++++++++++++++++-- 5 files changed, 119 insertions(+), 14 deletions(-) diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/MetricChartResponseHandler.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/MetricChartResponseHandler.java index be03e77a56d..c7c7b67a486 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/MetricChartResponseHandler.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/MetricChartResponseHandler.java @@ -59,7 +59,7 @@ public class MetricChartResponseHandler implements IResponseHandler{ @Override public AggregateDto translate(AggregateRequestDto request, ObjectNode aggregations) throws IOException { List dataList = new ArrayList<>(); - String requestId = request.getRequestId(); + String requestId = request.getRequestId(); String visualizationCode = request.getVisualizationCode(); JsonNode aggregationNode = aggregations.get(AGGREGATIONS); @@ -203,9 +203,20 @@ public AggregateDto translate(AggregateRequestDto request, ObjectNode aggregatio data.setPlots( Arrays.asList(latestDateplot,lastUpdatedTime)); request.getResponseRecorder().put(visualizationCode, request.getModuleLevel(), data); dataList.add(data); - if(chartNode.get(POST_AGGREGATION_THEORY) != null) { + if(chartNode.get(POST_AGGREGATION_THEORY) != null) { ComputeHelper computeHelper = computeHelperFactory.getInstance(chartNode.get(POST_AGGREGATION_THEORY).asText()); - computeHelper.compute(request, dataList); +// computeHelper.compute(request, dataList); + List capDataList = new ArrayList<>(); + + if (chartNode.has(IS_CAPPED_BY_CAMPAIGN_PERIOD)) { + List valueNode = aggregationNode.findValues(chartNode.get(IS_CAPPED_BY_CAMPAIGN_PERIOD).get(0).asText()); + if(valueNode.size() > 0) { + Long val = valueNode.get(0).get(IResponseHandler.VALUE).asLong(); + Data dataNode = new Data(aggrsPaths.get(0).asText(), val.doubleValue(), chartNode.get(IResponseHandler.VALUE_TYPE).asText()); + capDataList.add(dataNode); + } + } + computeHelper.compute(request, dataList, capDataList); } }catch (Exception e){ logger.info("data chart name = "+chartName +" ex occurred "+e.getMessage()); diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/AdditiveComputedField.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/AdditiveComputedField.java index 92ba43883b9..4ffae4af906 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/AdditiveComputedField.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/AdditiveComputedField.java @@ -15,6 +15,7 @@ import java.util.stream.Collectors; import static com.tarento.analytics.handler.IResponseHandler.HIDE_HEADER_DENOMINATION; +import static com.tarento.analytics.handler.IResponseHandler.IS_CAPPED_BY_CAMPAIGN_PERIOD; @Component public class AdditiveComputedField implements IComputedField { @@ -40,6 +41,7 @@ public void add(Data data, List fields, String newField,JsonNode chartNo Map plotMap = data.getPlots().stream().collect(Collectors.toMap(Plot::getName, Function.identity())); double total = 0.0; + double capTotal = 0.0; for (String field: fields){ if(plotMap.containsKey(field)){ dataType = plotMap.get(field).getSymbol(); @@ -48,8 +50,13 @@ public void add(Data data, List fields, String newField,JsonNode chartNo } if(postAggrTheoryName != null && !postAggrTheoryName.isEmpty()) { ComputeHelper computeHelper = computeHelperFactory.getInstance(postAggrTheoryName); + if (chartNode.has(IS_CAPPED_BY_CAMPAIGN_PERIOD)) { + if(plotMap.containsKey(chartNode.get(IS_CAPPED_BY_CAMPAIGN_PERIOD).get(0).asText())) { + capTotal = capTotal + plotMap.get(chartNode.get(IS_CAPPED_BY_CAMPAIGN_PERIOD).get(0).asText()).getValue(); + } + } - total = computeHelper.compute(aggregateRequestDto,total ); + total = computeHelper.compute(aggregateRequestDto,total,capTotal ); } diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/ComputeHelper.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/ComputeHelper.java index 3c50469fe94..f6a853dfd35 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/ComputeHelper.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/ComputeHelper.java @@ -12,8 +12,9 @@ * */ public interface ComputeHelper { - public List compute(AggregateRequestDto request, List data); + public List compute(AggregateRequestDto request, List data, List capValues); public Double compute(AggregateRequestDto request, double value); + public Double compute(AggregateRequestDto request, double value, double capTotal); } diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/NoOpsComputedField.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/NoOpsComputedField.java index b9715b43a50..9f6c83b0aca 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/NoOpsComputedField.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/NoOpsComputedField.java @@ -15,6 +15,7 @@ import java.util.List; import static com.tarento.analytics.constant.Constants.PostAggregationTheories.RESPONSE_DIFF_DATES; +import static com.tarento.analytics.handler.IResponseHandler.IS_CAPPED_BY_CAMPAIGN_PERIOD; @Component public class NoOpsComputedField implements IComputedField{ @@ -37,6 +38,7 @@ public void set(AggregateRequestDto requestDto, String postAggrTheoryName){ public void add(ObjectNode data, List fields, String newField, JsonNode chartNode ) { ObjectNode noOpsNode = JsonNodeFactory.instance.objectNode(); List dataList = new ArrayList<>(); + List capDataList = new ArrayList<>(); try { List values = data.findValues(fields.get(0)); if (postAggrTheoryName.equalsIgnoreCase(RESPONSE_DIFF_DATES)) { @@ -45,8 +47,14 @@ public void add(ObjectNode data, List fields, String newField, JsonNode Data dataNode = new Data(fields.get(0), val.doubleValue(), chartNode.get(IResponseHandler.VALUE_TYPE).asText()); dataList.add(dataNode); } + + if (chartNode.has(IS_CAPPED_BY_CAMPAIGN_PERIOD) && data.has((chartNode.get(IS_CAPPED_BY_CAMPAIGN_PERIOD).get(0).asText()))) { + Long capValue = data.findValues(chartNode.get(IS_CAPPED_BY_CAMPAIGN_PERIOD).get(0).asText()).get(0).get(IResponseHandler.VALUE).asLong(); + Data dataNode = new Data(fields.get(0), capValue.doubleValue(), chartNode.get(IResponseHandler.VALUE_TYPE).asText()); + capDataList.add(dataNode); + } ComputeHelper computeHelper = computeHelperFactory.getInstance(RESPONSE_DIFF_DATES); - List computedData = computeHelper.compute(aggregateRequestDto, dataList); + List computedData = computeHelper.compute(aggregateRequestDto, dataList, capDataList); noOpsNode.put(IResponseHandler.VALUE, ((Double) computedData.get(0).getHeaderValue()).longValue()); data.set(newField, noOpsNode); } diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/TargetPerDateComputeHelper.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/TargetPerDateComputeHelper.java index ce05e5c26d4..8c99870ac86 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/TargetPerDateComputeHelper.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/TargetPerDateComputeHelper.java @@ -46,14 +46,6 @@ public List compute(AggregateRequestDto request, List data) { Long dateDifference = TimeUnit.DAYS.convert((eDate - sDate), TimeUnit.MILLISECONDS); if(dateDifference == 0l) dateDifference = dateDifference + 1l ; - if(request.getChartNode().get(IS_CAPPED_BY_CAMPAIGN_PERIOD) != null && request.getChartNode().get(IS_CAPPED_BY_CAMPAIGN_PERIOD).asBoolean()){ - if(request.getFilters()!=null && request.getFilters().containsKey(CAMPAIGN_START_DATE) && request.getFilters().containsKey(CAMPAIGN_END_DATE)) { - Long campaignStartDate = Long.parseLong(String.valueOf(request.getFilters().get(CAMPAIGN_START_DATE))); - Long campaignEndDate = Long.parseLong(String.valueOf(request.getFilters().get(CAMPAIGN_END_DATE))); - Long campaignDateDifference = TimeUnit.DAYS.convert((campaignEndDate - campaignStartDate), TimeUnit.MILLISECONDS); - dateDifference = Math.min(dateDifference, campaignDateDifference); - } - } for(Data eachData : data) { Double value = (Double) eachData.getHeaderValue(); logger.info("Value is : " + value + " :: Date Difference is : " + dateDifference); @@ -67,6 +59,49 @@ public List compute(AggregateRequestDto request, List data) { return data; } + + @Override + public List compute(AggregateRequestDto request, List data, List capValues) { + if(request.getRequestDate()!= null && request.getRequestDate().getStartDate() != null && request.getRequestDate().getEndDate() != null) { + try { + Long sDate = Long.parseLong(request.getRequestDate().getStartDate()); + logger.info("Start Date : " + String.valueOf(sDate)); + Long eDate = Long.parseLong(request.getRequestDate().getEndDate()); + logger.info("End Date : " + String.valueOf(eDate)); + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date(eDate)); + if(cal.get(Calendar.HOUR_OF_DAY) == LAST_HOUR && cal.get(Calendar.MINUTE) == LAST_MINUTE) { + eDate = eDate + ROUND_OFF; + } + logger.info("End Date after Round Off: " + String.valueOf(eDate)); + Long dateDifference = TimeUnit.DAYS.convert((eDate - sDate), TimeUnit.MILLISECONDS); + if(dateDifference == 0l) dateDifference = dateDifference + 1l ; + + for(Data eachData : data) { + Double value = (Double) eachData.getHeaderValue(); + logger.info("Value is : " + value + " :: Date Difference is : " + dateDifference); + if(request.getChartNode().get(IS_CAPPED_BY_CAMPAIGN_PERIOD) != null && capValues.size()>0){ + if(request.getFilters()!=null && request.getFilters().containsKey(CAMPAIGN_START_DATE) && request.getFilters().containsKey(CAMPAIGN_END_DATE)) { + Long campaignStartDate = Long.parseLong(String.valueOf(request.getFilters().get(CAMPAIGN_START_DATE))); + Long campaignEndDate = Long.parseLong(String.valueOf(request.getFilters().get(CAMPAIGN_END_DATE))); + Long campaignDateDifference = TimeUnit.DAYS.convert((campaignEndDate - campaignStartDate), TimeUnit.MILLISECONDS); + if (dateDifference >= campaignDateDifference) { + Double capValue = (Double) capValues.get(0).getHeaderValue(); + eachData.setHeaderValue(capValue); + continue; + } + } + } + value = (value / NUMBER_OF_DAYS) * dateDifference; + eachData.setHeaderValue(value); + } + } catch (Exception ex) { + logger.error("Encountered an error while computing the logic in Target Date Computer : " + ex.getMessage()); + } + } + return data; + } + @Override public Double compute(AggregateRequestDto request, double value){ @@ -97,6 +132,49 @@ public Double compute(AggregateRequestDto request, double value){ + } + + @Override + public Double compute(AggregateRequestDto request, double value, double capTotal){ + + if(request.getRequestDate()!= null && request.getRequestDate().getStartDate() != null && request.getRequestDate().getEndDate() !=null) { + try { + Long sDate = Long.parseLong(request.getRequestDate().getStartDate()); + logger.info("Start Date : " + String.valueOf(sDate)); + Long eDate = Long.parseLong(request.getRequestDate().getEndDate()); + logger.info("End Date : " + String.valueOf(eDate)); + Calendar cal = Calendar.getInstance(); + cal.setTime(new Date(eDate)); + if(cal.get(Calendar.HOUR_OF_DAY) == LAST_HOUR && cal.get(Calendar.MINUTE) == LAST_MINUTE) { + eDate = eDate + ROUND_OFF; + } + logger.info("End Date after Round Off: " + String.valueOf(eDate)); + Long dateDifference = TimeUnit.DAYS.convert((eDate - sDate), TimeUnit.MILLISECONDS); + if(dateDifference == 0l) dateDifference = dateDifference + 1l ; + + value = (value / NUMBER_OF_DAYS) * dateDifference; + + if(request.getChartNode().get(IS_CAPPED_BY_CAMPAIGN_PERIOD) != null ){ + if(request.getFilters()!=null && request.getFilters().containsKey(CAMPAIGN_START_DATE) && request.getFilters().containsKey(CAMPAIGN_END_DATE)) { + Long campaignStartDate = Long.parseLong(String.valueOf(request.getFilters().get(CAMPAIGN_START_DATE))); + Long campaignEndDate = Long.parseLong(String.valueOf(request.getFilters().get(CAMPAIGN_END_DATE))); + Long campaignDateDifference = TimeUnit.DAYS.convert((campaignEndDate - campaignStartDate), TimeUnit.MILLISECONDS); + if (dateDifference >= campaignDateDifference) { + value = capTotal; + } + } + } + logger.info("Value is : " + value + " :: Date Difference is : " + dateDifference); + + } catch (Exception ex) { + logger.error("Encountered an error while computing the logic in Target Date Computer : " + ex.getMessage()); + } + } + + return value; + + + } } From 47a01cf03c4029efbc1a9e12ad50f96a81ed658a Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Mon, 5 Jun 2023 12:49:07 +0530 Subject: [PATCH 059/283] [hlm-2375]: Adding email id --- .../main/java/org/egov/individual/service/IndividualMapper.java | 1 + 1 file changed, 1 insertion(+) diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java index f788d19370b..9fadf6ab00c 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java @@ -26,6 +26,7 @@ public static UserRequest toUserRequest(Individual individual, IndividualPropert .tenantId(individual.getTenantId()) .name(String.join(" ", individual.getName().getGivenName(), individual.getName().getFamilyName())) + .emailId(individual.getEmail()) .mobileNumber(generateDummyMobileNumber(individual.getMobileNumber())) .type(UserType.valueOf(properties.getUserServiceUserType())) .accountLocked(properties.isUserServiceAccountLocked()) From 9bc17e675c5cdec5740e2683938ea8077a39bf18 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Tue, 6 Jun 2023 12:11:42 +0530 Subject: [PATCH 060/283] [hlm-2375]: Address update fix --- .../individual/repository/IndividualRepository.java | 10 +++++++++- .../org/egov/individual/service/IndividualMapper.java | 8 ++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index 813614fc957..b5e6181cbdb 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -202,7 +202,15 @@ private String getIdentifierQuery(Identifier identifier, Map par } private List
getAddressForIndividual(String individualId, Boolean includeDeleted) { - String addressQuery = getQuery("SELECT a.*, ia.individualId, ia.createdBy, ia.lastModifiedBy, ia.createdTime, ia.lastModifiedTime, ia.isDeleted FROM address a, individual_address ia WHERE a.id = ia.addressId and ia.individualId =:individualId", includeDeleted, "ia"); + String addressQuery = getQuery("SELECT a.*, ia.individualId, a.addressId, ia.createdBy, ia.lastModifiedBy, ia.createdTime, ia.lastModifiedTime, ia.isDeleted\n" + + "FROM (\n" + + " SELECT individualId, addressId, type, createdTime, lastModifiedTime, isDeleted\n" + + " ROW_NUMBER() OVER (PARTITION BY individualId, type ORDER BY lastModifiedTime DESC) AS rn\n" + + " FROM individual_address\n" + + " WHERE individualId = :individualId\n" + + ") AS ia\n" + + "JOIN address AS a ON ia.addressId = a.addressId\n" + + "WHERE ia.rn = 1", includeDeleted, "ia"); Map indServerGenIdParamMap = new HashMap<>(); indServerGenIdParamMap.put("individualId", individualId); indServerGenIdParamMap.put("isDeleted", includeDeleted); diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java index 9fadf6ab00c..c670fc29e47 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java @@ -1,6 +1,8 @@ package org.egov.individual.service; import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.individual.Address; +import org.egov.common.models.individual.AddressType; import org.egov.common.models.individual.Individual; import org.egov.common.models.user.RoleRequest; import org.egov.common.models.user.UserRequest; @@ -20,12 +22,18 @@ private IndividualMapper() {} public static UserRequest toUserRequest(Individual individual, IndividualProperties properties) { Long id = individual.getUserId() != null ? Long.parseLong(individual.getUserId()) : null; + String addressLine1 = individual.getAddress() != null && !individual.getAddress().isEmpty() + ? individual.getAddress().stream().filter(address -> address.getType() + .equals(AddressType.CORRESPONDENCE)).findFirst() + .orElse(Address.builder().build()) + .getAddressLine1() : null; return UserRequest.builder() .id(id) .uuid(individual.getUserUuid()) .tenantId(individual.getTenantId()) .name(String.join(" ", individual.getName().getGivenName(), individual.getName().getFamilyName())) + .correspondenceAddress(addressLine1) .emailId(individual.getEmail()) .mobileNumber(generateDummyMobileNumber(individual.getMobileNumber())) .type(UserType.valueOf(properties.getUserServiceUserType())) From fc3981234f971ceb542c998effd3647180c406f2 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Tue, 6 Jun 2023 12:36:26 +0530 Subject: [PATCH 061/283] [hlm-2375]: Query fix --- .../repository/IndividualRepository.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index b5e6181cbdb..24f1298765b 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -202,15 +202,15 @@ private String getIdentifierQuery(Identifier identifier, Map par } private List
getAddressForIndividual(String individualId, Boolean includeDeleted) { - String addressQuery = getQuery("SELECT a.*, ia.individualId, a.addressId, ia.createdBy, ia.lastModifiedBy, ia.createdTime, ia.lastModifiedTime, ia.isDeleted\n" + - "FROM (\n" + - " SELECT individualId, addressId, type, createdTime, lastModifiedTime, isDeleted\n" + - " ROW_NUMBER() OVER (PARTITION BY individualId, type ORDER BY lastModifiedTime DESC) AS rn\n" + - " FROM individual_address\n" + - " WHERE individualId = :individualId\n" + - ") AS ia\n" + - "JOIN address AS a ON ia.addressId = a.addressId\n" + - "WHERE ia.rn = 1", includeDeleted, "ia"); + String addressQuery = getQuery("SELECT a.*, ia.individualId, ia.addressId, ia.createdBy, ia.lastModifiedBy, ia.createdTime, ia.lastModifiedTime, ia.isDeleted" + + " FROM (" + + " SELECT individualId, addressId, type, createdTime, lastModifiedTime, isDeleted" + + " ROW_NUMBER() OVER (PARTITION BY individualId, type ORDER BY lastModifiedTime DESC) AS rn" + + " FROM individual_address" + + " WHERE individualId = :individualId" + + " ) AS ia" + + " JOIN address AS a ON ia.addressId = a.addressId" + + " WHERE ia.rn = 1 ", includeDeleted, "ia"); Map indServerGenIdParamMap = new HashMap<>(); indServerGenIdParamMap.put("individualId", individualId); indServerGenIdParamMap.put("isDeleted", includeDeleted); From 654da3bb8d132b68634dc04b55da7d063022472c Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Tue, 6 Jun 2023 12:50:30 +0530 Subject: [PATCH 062/283] [hlm-2375]: Query fix --- .../org/egov/individual/repository/IndividualRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index 24f1298765b..9606318130d 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -204,7 +204,7 @@ private String getIdentifierQuery(Identifier identifier, Map par private List
getAddressForIndividual(String individualId, Boolean includeDeleted) { String addressQuery = getQuery("SELECT a.*, ia.individualId, ia.addressId, ia.createdBy, ia.lastModifiedBy, ia.createdTime, ia.lastModifiedTime, ia.isDeleted" + " FROM (" + - " SELECT individualId, addressId, type, createdTime, lastModifiedTime, isDeleted" + + " SELECT individualId, addressId, type, createdTime, lastModifiedTime, isDeleted, " + " ROW_NUMBER() OVER (PARTITION BY individualId, type ORDER BY lastModifiedTime DESC) AS rn" + " FROM individual_address" + " WHERE individualId = :individualId" + From dc084b03f4d834f714164df980f1276372da6134 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Tue, 6 Jun 2023 13:02:59 +0530 Subject: [PATCH 063/283] [hlm-2375]: Query fix --- .../org/egov/individual/repository/IndividualRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index 9606318130d..bab62fac618 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -209,7 +209,7 @@ private List
getAddressForIndividual(String individualId, Boolean inclu " FROM individual_address" + " WHERE individualId = :individualId" + " ) AS ia" + - " JOIN address AS a ON ia.addressId = a.addressId" + + " JOIN address AS a ON ia.addressId = a.id" + " WHERE ia.rn = 1 ", includeDeleted, "ia"); Map indServerGenIdParamMap = new HashMap<>(); indServerGenIdParamMap.put("individualId", individualId); From 1bfe91ca48ead7301100f341a69742f1f31ac34d Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Tue, 6 Jun 2023 13:12:22 +0530 Subject: [PATCH 064/283] [hlm-2375]: Query fix --- .../org/egov/individual/repository/IndividualRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index bab62fac618..0231213af04 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -204,7 +204,7 @@ private String getIdentifierQuery(Identifier identifier, Map par private List
getAddressForIndividual(String individualId, Boolean includeDeleted) { String addressQuery = getQuery("SELECT a.*, ia.individualId, ia.addressId, ia.createdBy, ia.lastModifiedBy, ia.createdTime, ia.lastModifiedTime, ia.isDeleted" + " FROM (" + - " SELECT individualId, addressId, type, createdTime, lastModifiedTime, isDeleted, " + + " SELECT individualId, addressId, type, createdBy, lastModifiedBy, createdTime, lastModifiedTime, isDeleted, " + " ROW_NUMBER() OVER (PARTITION BY individualId, type ORDER BY lastModifiedTime DESC) AS rn" + " FROM individual_address" + " WHERE individualId = :individualId" + From b6893f7695225581e0e3fde0b62f7a3d19fd2002 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Tue, 6 Jun 2023 21:36:08 +0530 Subject: [PATCH 065/283] [hlm-2375]: Id fix for user request --- .../main/java/org/egov/individual/service/IndividualMapper.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java index c670fc29e47..20118f4a8ff 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java @@ -34,6 +34,8 @@ public static UserRequest toUserRequest(Individual individual, IndividualPropert .name(String.join(" ", individual.getName().getGivenName(), individual.getName().getFamilyName())) .correspondenceAddress(addressLine1) + .createdBy(id) + .lastModifiedBy(id) .emailId(individual.getEmail()) .mobileNumber(generateDummyMobileNumber(individual.getMobileNumber())) .type(UserType.valueOf(properties.getUserServiceUserType())) From b3d0a62c61e98d8533a07f3b6fe5cb64b3fa0f6e Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Wed, 7 Jun 2023 12:15:08 +0530 Subject: [PATCH 066/283] [hlm-2375]: Revert setting createdBy and lastModifiedBy --- .../main/java/org/egov/individual/service/IndividualMapper.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java index 20118f4a8ff..c670fc29e47 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java @@ -34,8 +34,6 @@ public static UserRequest toUserRequest(Individual individual, IndividualPropert .name(String.join(" ", individual.getName().getGivenName(), individual.getName().getFamilyName())) .correspondenceAddress(addressLine1) - .createdBy(id) - .lastModifiedBy(id) .emailId(individual.getEmail()) .mobileNumber(generateDummyMobileNumber(individual.getMobileNumber())) .type(UserType.valueOf(properties.getUserServiceUserType())) From fdd0a477d97e21c67689b9ea8da28c88e8cd8506 Mon Sep 17 00:00:00 2001 From: Shiva Burade Date: Thu, 8 Jun 2023 14:59:00 +0530 Subject: [PATCH 067/283] [hlm-2953]: Added Attributes and UserId for service request. --- .../transformer/models/downstream/ServiceIndexV1.java | 8 ++++++++ .../service/ServiceTaskTransformationService.java | 3 +++ 2 files changed, 11 insertions(+) diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ServiceIndexV1.java b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ServiceIndexV1.java index 2383bde4eae..55f38bc837a 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ServiceIndexV1.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ServiceIndexV1.java @@ -6,6 +6,10 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.transformer.models.upstream.AttributeValue; + +import java.util.ArrayList; +import java.util.List; @Data @AllArgsConstructor @@ -33,4 +37,8 @@ public class ServiceIndexV1 { private String district; @JsonProperty("tenantId") private String tenantId; + @JsonProperty("userId") + private String userId; + @JsonProperty("attributes") + private List attributes = new ArrayList<>(); } diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java index d5d10e21372..4bdb2ddfd6c 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java @@ -79,6 +79,7 @@ public List transform(Service service) { String projectId = projectService.getProjectByName(projectName, service.getTenantId()).getId(); Map boundaryLabelToNameMap = projectService.getBoundaryLabelToNameMapByProjectId(projectId, service.getTenantId()); log.info("boundary labels {}", boundaryLabelToNameMap.toString()); + return Collections.singletonList(ServiceIndexV1.builder() .id(service.getId()) .projectId(projectId) @@ -90,6 +91,8 @@ public List transform(Service service) { .createdTime(service.getAuditDetails().getCreatedTime()) .createdBy(service.getAuditDetails().getCreatedBy()) .tenantId(service.getTenantId()) + .userId(service.getAccountId()) + .attributes(service.getAttributes()) .build()); } } From e5e21ed01e1a9dd0fe2deb7bcb840034b16ede6a Mon Sep 17 00:00:00 2001 From: Shiva Burade Date: Mon, 12 Jun 2023 13:26:44 +0530 Subject: [PATCH 068/283] [hlm-2953]: Added dateOfEntry column --- .../src/main/java/org/egov/common/models/stock/Stock.java | 3 +++ health-services/stock/pom.xml | 8 +------- .../egov/stock/repository/rowmapper/StockRowMapper.java | 1 + .../V20230612103737__stock_dateOfEntry_column_ddl.sql | 1 + 4 files changed, 6 insertions(+), 7 deletions(-) create mode 100644 health-services/stock/src/main/resources/db/migration/main/V20230612103737__stock_dateOfEntry_column_ddl.sql diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java index 877436da62d..97ac4f3e06e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java @@ -99,5 +99,8 @@ public class Stock { @JsonProperty("auditDetails") @Valid private AuditDetails auditDetails = null; + + @JsonProperty("dateOfEntry") + private Long dateOfEntry = null; } diff --git a/health-services/stock/pom.xml b/health-services/stock/pom.xml index 87eae09d463..340d0f7398f 100644 --- a/health-services/stock/pom.xml +++ b/health-services/stock/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.0-SNAPSHOT + 1.0.3-SNAPSHOT @@ -102,12 +102,6 @@ javax.validation validation-api - - org.egov.common - health-services-models - 1.0.0-SNAPSHOT - compile - diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java index d443b7b4eee..63c20015d69 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java @@ -45,6 +45,7 @@ public Stock mapRow(ResultSet resultSet, int i) throws SQLException { .build()) .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) + .dateOfEntry(resultSet.getLong("dateOfEntry")) .build(); } catch (JsonProcessingException e) { throw new SQLException(e); diff --git a/health-services/stock/src/main/resources/db/migration/main/V20230612103737__stock_dateOfEntry_column_ddl.sql b/health-services/stock/src/main/resources/db/migration/main/V20230612103737__stock_dateOfEntry_column_ddl.sql new file mode 100644 index 00000000000..af90c0d36ef --- /dev/null +++ b/health-services/stock/src/main/resources/db/migration/main/V20230612103737__stock_dateOfEntry_column_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE STOCK ADD COLUMN dateOfEntry bigint; From b4da70a725a591c71eb171ece86a832ea041d6c0 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Mon, 12 Jun 2023 14:02:32 +0530 Subject: [PATCH 069/283] [hlm-2967]: Search by userId --- .../org/egov/individual/repository/IndividualRepository.java | 5 +++++ .../org/egov/individual/web/models/IndividualSearch.java | 4 ++++ .../org/egov/common/models/individual/IndividualSearch.java | 3 +++ 3 files changed, 12 insertions(+) diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index 0231213af04..48d8f01dedf 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -185,6 +185,11 @@ private String getQueryForIndividual(IndividualSearch searchObject, Integer limi query = query + "AND username=:username "; paramsMap.put("username", searchObject.getUsername()); } + + if (searchObject.getUserId() != null) { + query = query + "AND userId=:userId "; + paramsMap.put("userId", String.valueOf(searchObject.getUserId())); + } query = query + "ORDER BY id ASC LIMIT :limit OFFSET :offset"; paramsMap.put("tenantId", tenantId); paramsMap.put("isDeleted", includeDeleted); diff --git a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java b/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java index 16cb07ab3d8..f846d1187f4 100644 --- a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java +++ b/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java @@ -92,5 +92,9 @@ public class IndividualSearch { @Exclude @JsonProperty("username") private String username; + + @Exclude + @JsonProperty("userId") + private Long userId; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java index 379b24c2360..7dff5b261d7 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java @@ -79,5 +79,8 @@ public class IndividualSearch { @JsonProperty("username") private String username; + + @JsonProperty("userId") + private Long userId; } From 59f3cdc0099ae52a180663491c301e1c7080c030 Mon Sep 17 00:00:00 2001 From: Shiva Burade Date: Mon, 12 Jun 2023 16:25:18 +0530 Subject: [PATCH 070/283] [hlm-2953]: Added dateOfEntry --- health-services/transformer/pom.xml | 2 +- .../org/egov/transformer/models/downstream/StockIndexV1.java | 3 +++ .../egov/transformer/service/StockTransformationService.java | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/health-services/transformer/pom.xml b/health-services/transformer/pom.xml index ee0123866fe..ce2e521633b 100644 --- a/health-services/transformer/pom.xml +++ b/health-services/transformer/pom.xml @@ -57,7 +57,7 @@ org.egov.common health-services-models - 1.0.0-SNAPSHOT + 1.0.3-SNAPSHOT compile diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/StockIndexV1.java b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/StockIndexV1.java index c2796ccdf02..060cd3bf659 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/StockIndexV1.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/StockIndexV1.java @@ -41,6 +41,9 @@ public class StockIndexV1 { @JsonProperty("eventTimeStamp") private Long eventTimeStamp; + @JsonProperty("dateOfEntry") + private Long dateOfEntry; + @JsonProperty("province") private String province; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java index c57877fd110..ccd6647f75c 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java @@ -95,6 +95,7 @@ public List transform(Stock stock) { .reason(stock.getTransactionReason()) .eventTimeStamp(stock.getAuditDetails().getLastModifiedTime()) .createdTime(stock.getAuditDetails().getCreatedTime()) + .dateOfEntry(stock.getDateOfEntry()) .createdBy(stock.getAuditDetails().getCreatedBy()) .lastModifiedTime(stock.getAuditDetails().getLastModifiedTime()) .lastModifiedBy(stock.getAuditDetails().getLastModifiedBy()) From 5af8bdc8d35aa1b15eb8e4cd32e266da7e4d1965 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Mon, 12 Jun 2023 16:52:52 +0530 Subject: [PATCH 071/283] [hlm-2967]: Version increment --- health-services/individual/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index c9a0b440fa9..868e7e6d426 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -5,7 +5,7 @@ individual jar individual - 1.1.0 + 1.1.1 1.8 ${java.version} From a922ad261cbfef97a279f976644def6abef3825b Mon Sep 17 00:00:00 2001 From: Shiva Burade Date: Tue, 13 Jun 2023 10:04:10 +0530 Subject: [PATCH 072/283] [hlm-2953]: Update pom.xml --- health-services/stock/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/stock/pom.xml b/health-services/stock/pom.xml index 340d0f7398f..6d7792d83c3 100644 --- a/health-services/stock/pom.xml +++ b/health-services/stock/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.3-SNAPSHOT + 1.0.6-SNAPSHOT From be01a2bc0419d712928496e602d1a83abec000e6 Mon Sep 17 00:00:00 2001 From: Shiva Burade Date: Tue, 13 Jun 2023 10:20:55 +0530 Subject: [PATCH 073/283] [hlm-2953]: Update pom.xml --- health-services/transformer/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/transformer/pom.xml b/health-services/transformer/pom.xml index ce2e521633b..ea3bb03ab4b 100644 --- a/health-services/transformer/pom.xml +++ b/health-services/transformer/pom.xml @@ -57,7 +57,7 @@ org.egov.common health-services-models - 1.0.3-SNAPSHOT + 1.0.6-SNAPSHOT compile From 76eff9be2652659475626e4b7e60a393774a2ba5 Mon Sep 17 00:00:00 2001 From: Shiva Burade Date: Wed, 14 Jun 2023 18:24:01 +0530 Subject: [PATCH 074/283] [hlm-2953]: Updated evenTimeStamp --- .../egov/transformer/service/StockTransformationService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java index ccd6647f75c..2044dbe1658 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java @@ -93,7 +93,8 @@ public List transform(Stock stock) { .physicalCount(stock.getQuantity()) .eventType(stock.getTransactionType()) .reason(stock.getTransactionReason()) - .eventTimeStamp(stock.getAuditDetails().getLastModifiedTime()) + .eventTimeStamp(stock.getDateOfEntry() != null ? + stock.getDateOfEntry() : stock.getAuditDetails().getLastModifiedTime()) .createdTime(stock.getAuditDetails().getCreatedTime()) .dateOfEntry(stock.getDateOfEntry()) .createdBy(stock.getAuditDetails().getCreatedBy()) From e9acdcb87240d792e62b87584c5e247760783991 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Fri, 16 Jun 2023 15:59:42 +0530 Subject: [PATCH 075/283] [hlm-2915]: Added clientAuditDetails --- .../individual/repository/rowmapper/IndividualRowMapper.java | 4 ++++ ...0616153900__add_client_audit_details_in_individual_ddl.sql | 2 ++ .../java/org/egov/common/models/individual/Individual.java | 4 ++++ 3 files changed, 10 insertions(+) create mode 100644 health-services/individual/src/main/resources/db/migration/main/V20230616153900__add_client_audit_details_in_individual_ddl.sql diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java index 2176427b64f..ff42e6821d8 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java @@ -68,6 +68,10 @@ public Individual mapRow(ResultSet resultSet, int i) throws SQLException { .tenantId(tenantId) .build()) .userUuid(resultSet.getString("userUuid")) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .build(); } catch (JsonProcessingException e) { throw new RuntimeException(e); diff --git a/health-services/individual/src/main/resources/db/migration/main/V20230616153900__add_client_audit_details_in_individual_ddl.sql b/health-services/individual/src/main/resources/db/migration/main/V20230616153900__add_client_audit_details_in_individual_ddl.sql new file mode 100644 index 00000000000..b8ed09c5ec7 --- /dev/null +++ b/health-services/individual/src/main/resources/db/migration/main/V20230616153900__add_client_audit_details_in_individual_ddl.sql @@ -0,0 +1,2 @@ +ALTER TABLE INDIVIDUAL ADD COLUMN clientCreatedTime bigint; +ALTER TABLE INDIVIDUAL ADD COLUMN clientLastModifiedTime bigint; \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java index 95958898c93..3bcaf631a4b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java @@ -127,6 +127,10 @@ public class Individual { @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + @JsonIgnore private Boolean hasErrors = Boolean.FALSE; From 75697a42344d2ca1ea8d685415e778f952ee3540 Mon Sep 17 00:00:00 2001 From: bhanuprakash-egov Date: Thu, 29 Jun 2023 02:42:06 +0530 Subject: [PATCH 076/283] restricting data points from date before the campaign start date --- .../analytics/handler/LineChartResponseHandler.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/LineChartResponseHandler.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/LineChartResponseHandler.java index 51a956346ad..b0c9947cb3c 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/LineChartResponseHandler.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/LineChartResponseHandler.java @@ -117,7 +117,7 @@ public AggregateDto translate(AggregateRequestDto requestDto, ObjectNode aggrega Set finalBucketKeys = new LinkedHashSet<>(); // For multi aggr, find all plot keys first - enrichBucketKeys(aggrNodes, finalBucketKeys, interval); + enrichBucketKeys(aggrNodes, finalBucketKeys, interval, startDate); initializeMultiAggrPlotMap(multiAggrPlotMap, finalBucketKeys); for(JsonNode aggrNode : aggrNodes) { @@ -125,6 +125,9 @@ public AggregateDto translate(AggregateRequestDto requestDto, ObjectNode aggrega ArrayNode buckets = (ArrayNode) aggrNode.findValues(IResponseHandler.BUCKETS).get(0); for(JsonNode bucket : buckets){ JsonNode bkey = bucket.findValue(IResponseHandler.KEY); + if (Long.parseLong(bkey.asText()) < startDate) { + continue; + } String key = getIntervalKey(bkey.asText(), Constants.Interval.valueOf(interval)); plotKeys.add(key); if(isPredictionEnabled && !headerPath.equals(predictionPath)){ @@ -354,13 +357,16 @@ private void initializeMultiAggrPlotMap(Map multiAggrPlotMap, Se }); } - private void enrichBucketKeys(List aggrNodes, Set finalBucketKeys, String interval) { + private void enrichBucketKeys(List aggrNodes, Set finalBucketKeys, String interval, Long startDate) { List bkeyList = new ArrayList<>(); for(JsonNode aggrNode : aggrNodes) { if (aggrNode.findValues(IResponseHandler.BUCKETS).size() > 0) { ArrayNode buckets = (ArrayNode) aggrNode.findValues(IResponseHandler.BUCKETS).get(0); for(JsonNode bucket : buckets){ String bkey = bucket.findValue(IResponseHandler.KEY).asText(); + if (Long.parseLong(bkey) < (startDate)) { + continue; + } bkeyList.add(bkey); } } From e6cbc7a03e272e6be1b07c832bc547b3a2aea922 Mon Sep 17 00:00:00 2001 From: bhanuprakash-egov Date: Thu, 29 Jun 2023 03:06:58 +0530 Subject: [PATCH 077/283] excluding past data only for prediction chart --- .../analytics/handler/LineChartResponseHandler.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/LineChartResponseHandler.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/LineChartResponseHandler.java index b0c9947cb3c..3759710ceb2 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/LineChartResponseHandler.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/LineChartResponseHandler.java @@ -117,7 +117,7 @@ public AggregateDto translate(AggregateRequestDto requestDto, ObjectNode aggrega Set finalBucketKeys = new LinkedHashSet<>(); // For multi aggr, find all plot keys first - enrichBucketKeys(aggrNodes, finalBucketKeys, interval, startDate); + enrichBucketKeys(aggrNodes, finalBucketKeys, interval, startDate, isPredictionEnabled); initializeMultiAggrPlotMap(multiAggrPlotMap, finalBucketKeys); for(JsonNode aggrNode : aggrNodes) { @@ -125,7 +125,7 @@ public AggregateDto translate(AggregateRequestDto requestDto, ObjectNode aggrega ArrayNode buckets = (ArrayNode) aggrNode.findValues(IResponseHandler.BUCKETS).get(0); for(JsonNode bucket : buckets){ JsonNode bkey = bucket.findValue(IResponseHandler.KEY); - if (Long.parseLong(bkey.asText()) < startDate) { + if (isPredictionEnabled && Long.parseLong(bkey.asText()) < startDate) { continue; } String key = getIntervalKey(bkey.asText(), Constants.Interval.valueOf(interval)); @@ -357,14 +357,14 @@ private void initializeMultiAggrPlotMap(Map multiAggrPlotMap, Se }); } - private void enrichBucketKeys(List aggrNodes, Set finalBucketKeys, String interval, Long startDate) { + private void enrichBucketKeys(List aggrNodes, Set finalBucketKeys, String interval, Long startDate, Boolean isPredictionEnabled) { List bkeyList = new ArrayList<>(); for(JsonNode aggrNode : aggrNodes) { if (aggrNode.findValues(IResponseHandler.BUCKETS).size() > 0) { ArrayNode buckets = (ArrayNode) aggrNode.findValues(IResponseHandler.BUCKETS).get(0); for(JsonNode bucket : buckets){ String bkey = bucket.findValue(IResponseHandler.KEY).asText(); - if (Long.parseLong(bkey) < (startDate)) { + if (isPredictionEnabled && Long.parseLong(bkey) < (startDate)) { continue; } bkeyList.add(bkey); From 93f4b02b98079661527cff545d0a64224b58ec96 Mon Sep 17 00:00:00 2001 From: Shiva Burade Date: Fri, 30 Jun 2023 10:38:32 +0530 Subject: [PATCH 078/283] [hlm-2915]: Created migrations and added client audit details. --- health-services/facility/pom.xml | 2 +- .../repository/rowmapper/FacilityRowMapper.java | 4 ++++ ...0__add_client_audit_details_in_facility_ddl.sql | 2 ++ health-services/household/pom.xml | 2 +- .../rowmapper/HouseholdMemberRowMapper.java | 4 ++++ .../repository/rowmapper/HouseholdRowMapper.java | 4 ++++ ...__add_client_audit_details_in_household_ddl.sql | 5 +++++ .../org/egov/common/models/facility/Facility.java | 4 ++++ .../egov/common/models/household/Household.java | 4 ++++ .../common/models/household/HouseholdMember.java | 4 ++++ .../org/egov/common/models/product/Product.java | 4 ++++ .../egov/common/models/product/ProductVariant.java | 4 ++++ .../common/models/project/ProjectBeneficiary.java | 4 ++++ .../common/models/project/ProjectFacility.java | 4 ++++ .../common/models/project/ProjectResource.java | 4 ++++ .../egov/common/models/project/ProjectStaff.java | 4 ++++ .../java/org/egov/common/models/project/Task.java | 4 ++++ .../egov/common/models/project/TaskResource.java | 3 +++ .../java/org/egov/common/models/stock/Stock.java | 4 ++++ .../common/models/stock/StockReconciliation.java | 4 ++++ health-services/product/pom.xml | 2 +- .../repository/rowmapper/ProductRowMapper.java | 4 ++++ .../rowmapper/ProductVariantRowMapper.java | 4 ++++ ...00__add_client_audit_details_in_product_ddl.sql | 5 +++++ health-services/project/pom.xml | 2 +- .../rowmapper/ProjectBeneficiaryRowMapper.java | 4 ++++ .../rowmapper/ProjectFacilityRowMapper.java | 4 ++++ .../rowmapper/ProjectResourceRowMapper.java | 4 ++++ .../rowmapper/ProjectStaffRowMapper.java | 4 ++++ .../repository/rowmapper/ProjectTaskRowMapper.java | 4 ++++ ...00__add_client_audit_details_in_project_ddl.sql | 14 ++++++++++++++ health-services/stock/pom.xml | 2 +- .../rowmapper/StockReconciliationRowMapper.java | 4 ++++ .../stock/repository/rowmapper/StockRowMapper.java | 4 ++++ ...1500__add_client_audit_details_in_stock_ddl.sql | 5 +++++ 35 files changed, 135 insertions(+), 5 deletions(-) create mode 100644 health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql create mode 100644 health-services/household/src/main/resources/db/migration/main/V20230628171400__add_client_audit_details_in_household_ddl.sql create mode 100644 health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql create mode 100644 health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql create mode 100644 health-services/stock/src/main/resources/db/migration/main/V20230628181500__add_client_audit_details_in_stock_ddl.sql diff --git a/health-services/facility/pom.xml b/health-services/facility/pom.xml index 472e9ea35aa..9ec8c51c152 100644 --- a/health-services/facility/pom.xml +++ b/health-services/facility/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.1-SNAPSHOT + 1.0.6-SNAPSHOT compile diff --git a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java index eb6c2440792..b525bfb07bc 100644 --- a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java +++ b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java @@ -55,6 +55,10 @@ public Facility mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastModifiedBy")) .lastModifiedTime(resultSet.getLong("lastModifiedTime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) .build(); diff --git a/health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql b/health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql new file mode 100644 index 00000000000..e8267679900 --- /dev/null +++ b/health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql @@ -0,0 +1,2 @@ +ALTER TABLE FACILITY ADD COLUMN clientCreatedTime bigint; +ALTER TABLE FACILITY ADD COLUMN clientLastModifiedTime bigint; \ No newline at end of file diff --git a/health-services/household/pom.xml b/health-services/household/pom.xml index d6cfb901da8..d7d6858761a 100644 --- a/health-services/household/pom.xml +++ b/health-services/household/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.0-SNAPSHOT + 1.0.6-SNAPSHOT compile diff --git a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java index a306509a3c4..e99a280dd63 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java +++ b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java @@ -36,6 +36,10 @@ public HouseholdMember mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastModifiedBy")) .lastModifiedTime(resultSet.getLong("lastModifiedTime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .build(); } catch (JsonProcessingException e) { throw new SQLException(e); diff --git a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java index 6846f9bb3bd..b11547ec8c6 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java +++ b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java @@ -34,6 +34,10 @@ public Household mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastModifiedBy")) .lastModifiedTime(resultSet.getLong("lastModifiedTime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet .getString("additionalDetails"), AdditionalFields.class)) .address(Address.builder() diff --git a/health-services/household/src/main/resources/db/migration/main/V20230628171400__add_client_audit_details_in_household_ddl.sql b/health-services/household/src/main/resources/db/migration/main/V20230628171400__add_client_audit_details_in_household_ddl.sql new file mode 100644 index 00000000000..f20e702d56c --- /dev/null +++ b/health-services/household/src/main/resources/db/migration/main/V20230628171400__add_client_audit_details_in_household_ddl.sql @@ -0,0 +1,5 @@ +ALTER TABLE HOUSEHOLD ADD COLUMN clientCreatedTime bigint; +ALTER TABLE HOUSEHOLD ADD COLUMN clientLastModifiedTime bigint; + +ALTER TABLE HOUSEHOLD_MEMBER ADD COLUMN clientCreatedTime bigint; +ALTER TABLE HOUSEHOLD_MEMBER ADD COLUMN clientLastModifiedTime bigint; \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java index 338afe924b0..1b6f18b870f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java @@ -69,6 +69,10 @@ public class Facility { @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + @JsonIgnore private Boolean hasErrors = Boolean.FALSE; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java index 8cd95af33e9..56cdaeef0a4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java @@ -66,6 +66,10 @@ public class Household { @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + @JsonIgnore private Boolean hasErrors = Boolean.FALSE; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java index a63a0742100..ad103f7f9d0 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java @@ -71,6 +71,10 @@ public class HouseholdMember{ @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + @JsonIgnore private Boolean hasErrors = Boolean.FALSE; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java index 309ed399ecc..8c94529247a 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java @@ -61,5 +61,9 @@ public class Product { @JsonProperty("auditDetails") @Valid private AuditDetails auditDetails = null; + + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java index d0dec276973..bf0d8513fd9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java @@ -82,6 +82,10 @@ public class ProductVariant { private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java index 25b96b211ba..0d060052b72 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java @@ -72,6 +72,10 @@ public class ProjectBeneficiary { @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + @JsonIgnore private Boolean hasErrors = Boolean.FALSE; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java index a8081091e62..ff79f87888b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java @@ -64,4 +64,8 @@ public class ProjectFacility { @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + } \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java index eb74d3ec81c..e9c24173069 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java @@ -64,5 +64,9 @@ public class ProjectResource { @JsonProperty("auditDetails") @Valid private AuditDetails auditDetails = null; + + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java index f7c0f205af7..27f1353c28f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java @@ -75,5 +75,9 @@ public class ProjectStaff { @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java index a3689eb112c..fbbc67ffb33 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java @@ -95,6 +95,10 @@ public class Task { @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + @JsonProperty("status") private String status = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java index 986275799d2..d767a8fa3f2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java @@ -65,5 +65,8 @@ public class TaskResource { @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java index 97ac4f3e06e..102474fae63 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java @@ -102,5 +102,9 @@ public class Stock { @JsonProperty("dateOfEntry") private Long dateOfEntry = null; + + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java index 9b94d58a170..7e3ac004d0f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java @@ -84,5 +84,9 @@ public class StockReconciliation { @JsonProperty("auditDetails") @Valid private AuditDetails auditDetails = null; + + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; } diff --git a/health-services/product/pom.xml b/health-services/product/pom.xml index 12b9f8c1850..e9f818572ed 100644 --- a/health-services/product/pom.xml +++ b/health-services/product/pom.xml @@ -80,7 +80,7 @@ org.egov.common health-services-models - 1.0.0-SNAPSHOT + 1.0.6-SNAPSHOT compile diff --git a/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductRowMapper.java b/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductRowMapper.java index 24c06d1721a..83b82ed59bb 100644 --- a/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductRowMapper.java +++ b/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductRowMapper.java @@ -33,6 +33,10 @@ public Product mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) .build(); } catch (JsonProcessingException e) { diff --git a/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductVariantRowMapper.java b/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductVariantRowMapper.java index 01b1d4d1174..9c3d04d5d3e 100644 --- a/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductVariantRowMapper.java +++ b/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductVariantRowMapper.java @@ -33,6 +33,10 @@ public ProductVariant mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet .getString("additionalDetails"), AdditionalFields.class)) .build(); diff --git a/health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql b/health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql new file mode 100644 index 00000000000..a81e6114250 --- /dev/null +++ b/health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql @@ -0,0 +1,5 @@ +ALTER TABLE PRODUCT ADD COLUMN clientCreatedTime bigint; +ALTER TABLE PRODUCT ADD COLUMN clientLastModifiedTime bigint; + +ALTER TABLE PRODUCT_VARIANT ADD COLUMN clientCreatedTime bigint; +ALTER TABLE PRODUCT_VARIANT ADD COLUMN clientLastModifiedTime bigint; \ No newline at end of file diff --git a/health-services/project/pom.xml b/health-services/project/pom.xml index 1b421ad4655..49c8b5982d2 100644 --- a/health-services/project/pom.xml +++ b/health-services/project/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.0-SNAPSHOT + 1.0.6-SNAPSHOT compile diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java index 64e07258a2f..4c2092c3734 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java @@ -37,6 +37,10 @@ public ProjectBeneficiary mapRow(ResultSet resultSet, int i) throws SQLException .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .rowVersion(resultSet.getInt("rowversion")) .isDeleted(resultSet.getBoolean("isdeleted")) .build(); diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java index bd79efb6583..13886823429 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java @@ -34,6 +34,10 @@ public ProjectFacility mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .rowVersion(resultSet.getInt("rowversion")) .isDeleted(resultSet.getBoolean("isdeleted")) .build(); diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java index 34deb79333a..c3fd116c476 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java @@ -37,6 +37,10 @@ public ProjectResource mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .rowVersion(resultSet.getInt("rowversion")) .isDeleted(resultSet.getBoolean("isdeleted")) .build(); diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java index 5403b3a00cc..91b7648088a 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java @@ -36,6 +36,10 @@ public ProjectStaff mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .rowVersion(resultSet.getInt("rowversion")) .isDeleted(resultSet.getBoolean("isdeleted")) .build(); diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java index f797ac57e70..4f7587b23fa 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java @@ -42,6 +42,10 @@ public Task mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastModifiedBy")) .lastModifiedTime(resultSet.getLong("lastModifiedTime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) .address(Address.builder() diff --git a/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql new file mode 100644 index 00000000000..85b2c6ca59c --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql @@ -0,0 +1,14 @@ +ALTER TABLE PROJECT_TASK ADD COLUMN clientCreatedTime bigint; +ALTER TABLE PROJECT_TASK ADD COLUMN clientLastModifiedTime bigint; + +ALTER TABLE PROJECT_STAFF ADD COLUMN clientCreatedTime bigint; +ALTER TABLE PROJECT_STAFF ADD COLUMN clientLastModifiedTime bigint; + +ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN clientCreatedTime bigint; +ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN clientLastModifiedTime bigint; + +ALTER TABLE PROJECT_RESOURCE ADD COLUMN clientCreatedTime bigint; +ALTER TABLE PROJECT_RESOURCE ADD COLUMN clientLastModifiedTime bigint; + +ALTER TABLE PROJECT_FACILITY ADD COLUMN clientCreatedTime bigint; +ALTER TABLE PROJECT_FACILITY ADD COLUMN clientLastModifiedTime bigint; diff --git a/health-services/stock/pom.xml b/health-services/stock/pom.xml index 340d0f7398f..6d7792d83c3 100644 --- a/health-services/stock/pom.xml +++ b/health-services/stock/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.3-SNAPSHOT + 1.0.6-SNAPSHOT diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java index c8117e60ac6..45b5ce8d748 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java @@ -45,6 +45,10 @@ public StockReconciliation mapRow(ResultSet resultSet, int i) throws SQLExceptio .lastModifiedBy(resultSet.getString("lastModifiedBy")) .lastModifiedTime(resultSet.getLong("lastModifiedTime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .build(); } catch (JsonProcessingException e) { throw new SQLException(e); diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java index 63c20015d69..92df4ab6b2d 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java @@ -43,6 +43,10 @@ public Stock mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastModifiedBy")) .lastModifiedTime(resultSet.getLong("lastModifiedTime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) .dateOfEntry(resultSet.getLong("dateOfEntry")) diff --git a/health-services/stock/src/main/resources/db/migration/main/V20230628181500__add_client_audit_details_in_stock_ddl.sql b/health-services/stock/src/main/resources/db/migration/main/V20230628181500__add_client_audit_details_in_stock_ddl.sql new file mode 100644 index 00000000000..94c9be7e697 --- /dev/null +++ b/health-services/stock/src/main/resources/db/migration/main/V20230628181500__add_client_audit_details_in_stock_ddl.sql @@ -0,0 +1,5 @@ +ALTER TABLE STOCK ADD COLUMN clientCreatedTime bigint; +ALTER TABLE STOCK ADD COLUMN clientLastModifiedTime bigint; + +ALTER TABLE STOCK_RECONCILIATION_LOG ADD COLUMN clientCreatedTime bigint; +ALTER TABLE STOCK_RECONCILIATION_LOG ADD COLUMN clientLastModifiedTime bigint; \ No newline at end of file From c7a505f78c0f82bb6f32445fbd387db84757e896 Mon Sep 17 00:00:00 2001 From: shubhang-egov Date: Mon, 17 Jul 2023 13:01:49 +0530 Subject: [PATCH 079/283] Disabling sms send feature if the role is org_admin --- .../java/org/egov/individual/Constants.java | 1 + .../individual/service/IndividualService.java | 24 +++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/Constants.java b/health-services/individual/src/main/java/org/egov/individual/Constants.java index 8df6088b70b..9db46cf85e9 100644 --- a/health-services/individual/src/main/java/org/egov/individual/Constants.java +++ b/health-services/individual/src/main/java/org/egov/individual/Constants.java @@ -17,4 +17,5 @@ public interface Constants { String INDIVIDUAL_MODULE_CODE = "rainmaker-masters"; String INDIVIDUAL_LOCALIZATION_CODES_JSONPATH = "$.messages.*.code"; String INDIVIDUAL_LOCALIZATION_MSGS_JSONPATH = "$.messages.*.message"; + String ORG_ADMIN_ROLE_CODE = "ORG_ADMIN"; } diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java index 7800b4a787c..685e61a268c 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java @@ -6,6 +6,7 @@ import org.egov.common.ds.Tuple; import org.egov.common.models.Error; import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.Role; import org.egov.common.models.individual.Identifier; import org.egov.common.models.individual.Individual; import org.egov.common.models.individual.IndividualBulkRequest; @@ -55,8 +56,7 @@ import static org.egov.common.utils.CommonUtils.lastChangedSince; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.individual.Constants.SET_INDIVIDUALS; -import static org.egov.individual.Constants.VALIDATION_ERROR; +import static org.egov.individual.Constants.*; @Service @Slf4j @@ -119,7 +119,9 @@ public List create(IndividualRequest request) { IndividualBulkRequest bulkRequest = IndividualBulkRequest.builder().requestInfo(request.getRequestInfo()) .individuals(Collections.singletonList(request.getIndividual())).build(); List individuals = create(bulkRequest, false); - if(properties.getIsSMSEnabled()) + + // check if sms feature is enable for the environment role + if(properties.getIsSMSEnabled() && isSmsEnabledForRole(request)) notificationService.sendNotification(request, true); return individuals; } @@ -180,7 +182,9 @@ public List update(IndividualRequest request) { IndividualBulkRequest bulkRequest = IndividualBulkRequest.builder().requestInfo(request.getRequestInfo()) .individuals(Collections.singletonList(request.getIndividual())).build(); List individuals = update(bulkRequest, false); - if(properties.getIsSMSEnabled()) + + // check if sms feature is enable for the environment role + if(properties.getIsSMSEnabled() && isSmsEnabledForRole(request)) notificationService.sendNotification(request, false); return individuals; } @@ -415,4 +419,16 @@ private void integrateWithUserService(IndividualBulkRequest request, } } } + Boolean isSmsEnabledForRole(IndividualRequest request) { + List roleCodes = new ArrayList<>(); + if(request != null && request.getIndividual() != null && request.getIndividual().getUserDetails() != null + && request.getIndividual().getUserDetails().getRoles() != null) { + // get the role codes from the list of roles + roleCodes = request.getIndividual().getUserDetails().getRoles().stream().map(Role::getCode).collect(Collectors.toList()); + } + if (roleCodes.contains(ORG_ADMIN_ROLE_CODE)) + return false; + + return true; + } } From 38b7320242a36458bd44a37bdd6759ac59f49669 Mon Sep 17 00:00:00 2001 From: shubhang-egov Date: Mon, 17 Jul 2023 16:30:23 +0530 Subject: [PATCH 080/283] Taking list of roles from application.properties --- .../config/IndividualProperties.java | 3 +++ .../individual/service/IndividualService.java | 20 +++++++++---------- .../src/main/resources/application.properties | 1 + 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/config/IndividualProperties.java b/health-services/individual/src/main/java/org/egov/individual/config/IndividualProperties.java index d481b47d5c8..06bf6ea6a89 100644 --- a/health-services/individual/src/main/java/org/egov/individual/config/IndividualProperties.java +++ b/health-services/individual/src/main/java/org/egov/individual/config/IndividualProperties.java @@ -63,6 +63,9 @@ public class IndividualProperties { @Value("${kafka.topics.notification.sms}") private String smsNotifTopic; + @Value("${notification.sms.disabled.roles}") + private String smsDisabledRoles; + //Localization @Value("${egov.localization.host}") private String localizationHost; diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java index 685e61a268c..785fb5c9908 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java @@ -32,16 +32,10 @@ import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; +import java.util.*; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -421,14 +415,18 @@ private void integrateWithUserService(IndividualBulkRequest request, } Boolean isSmsEnabledForRole(IndividualRequest request) { List roleCodes = new ArrayList<>(); + if (StringUtils.isEmpty(properties.getSmsDisabledRoles())) + return true; + String[] smsDisabledRolesArray = properties.getSmsDisabledRoles().split(","); if(request != null && request.getIndividual() != null && request.getIndividual().getUserDetails() != null && request.getIndividual().getUserDetails().getRoles() != null) { // get the role codes from the list of roles roleCodes = request.getIndividual().getUserDetails().getRoles().stream().map(Role::getCode).collect(Collectors.toList()); } - if (roleCodes.contains(ORG_ADMIN_ROLE_CODE)) - return false; - + for (String smsDisabledRole : smsDisabledRolesArray) { + if (roleCodes.contains(smsDisabledRole)) + return false; + } return true; } } diff --git a/health-services/individual/src/main/resources/application.properties b/health-services/individual/src/main/resources/application.properties index 14813237ab4..78db07bc7d0 100644 --- a/health-services/individual/src/main/resources/application.properties +++ b/health-services/individual/src/main/resources/application.properties @@ -91,6 +91,7 @@ user.service.account.locked=false #Notification notification.sms.enabled=true kafka.topics.notification.sms=egov.core.notification.sms +notification.sms.disabled.roles=ORG_ADMIN #Localization config egov.localization.host=https://works-dev.digit.org/ From 3eeebc7a4e394d0fce2e26d1da754bb05efb080c Mon Sep 17 00:00:00 2001 From: shubhang-egov Date: Tue, 18 Jul 2023 12:59:53 +0530 Subject: [PATCH 081/283] Taking list directly from application properties --- .../org/egov/individual/config/IndividualProperties.java | 4 +++- .../org/egov/individual/service/IndividualService.java | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/config/IndividualProperties.java b/health-services/individual/src/main/java/org/egov/individual/config/IndividualProperties.java index 06bf6ea6a89..44f9ed5be70 100644 --- a/health-services/individual/src/main/java/org/egov/individual/config/IndividualProperties.java +++ b/health-services/individual/src/main/java/org/egov/individual/config/IndividualProperties.java @@ -7,6 +7,8 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import java.util.List; + @Data @AllArgsConstructor @NoArgsConstructor @@ -64,7 +66,7 @@ public class IndividualProperties { private String smsNotifTopic; @Value("${notification.sms.disabled.roles}") - private String smsDisabledRoles; + private List smsDisabledRoles; //Localization @Value("${egov.localization.host}") diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java index 785fb5c9908..ac5b061052f 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java @@ -414,16 +414,16 @@ private void integrateWithUserService(IndividualBulkRequest request, } } Boolean isSmsEnabledForRole(IndividualRequest request) { - List roleCodes = new ArrayList<>(); - if (StringUtils.isEmpty(properties.getSmsDisabledRoles())) + if (CollectionUtils.isEmpty(properties.getSmsDisabledRoles())) return true; - String[] smsDisabledRolesArray = properties.getSmsDisabledRoles().split(","); + List smsDisabledRoles = properties.getSmsDisabledRoles(); + List roleCodes = new ArrayList<>(); if(request != null && request.getIndividual() != null && request.getIndividual().getUserDetails() != null && request.getIndividual().getUserDetails().getRoles() != null) { // get the role codes from the list of roles roleCodes = request.getIndividual().getUserDetails().getRoles().stream().map(Role::getCode).collect(Collectors.toList()); } - for (String smsDisabledRole : smsDisabledRolesArray) { + for (String smsDisabledRole : smsDisabledRoles) { if (roleCodes.contains(smsDisabledRole)) return false; } From ac7d503c8a79c53737041adeb4126a07a81e482d Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Tue, 18 Jul 2023 14:42:54 +0530 Subject: [PATCH 082/283] Added changes for HLM-3092 : proximity based search for household --- .../repository/HouseholdRepository.java | 27 +++++++++++++++++++ .../household/service/HouseholdService.java | 13 +++++++++ .../household/web/models/HouseholdSearch.java | 20 ++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java index 6b98b89cb5b..01d0a3c1d83 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java +++ b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java @@ -88,4 +88,31 @@ public List find(HouseholdSearch searchObject, Integer limit, Integer paramsMap.put("offset", offset); return this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); } + + public List findByRadius(HouseholdSearch searchObject, Integer limit, Integer offset, String tenantId, Boolean includeDeleted) throws QueryBuilderException { + String query = "WITH cte_search_criteria_waypoint(s_latitude, s_longitude) AS (VALUES(:s_latitude, :s_longitude))\n" + + "SELECT * FROM (SELECT h.*, a.*, ( 6371.4 * acos (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )\n" + + "+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ) ) ) AS distance \n" + + "FROM public.household h LEFT JOIN public.address a ON h.addressid = a.id AND h.tenantid = a.tenantid, cte_search_criteria_waypoint cte_scw "; + Map paramsMap = new HashMap<>(); + List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); + query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); + query = query.replace("id IN (:id)", "h.id IN (:id)"); + query = query.replace("clientReferenceId IN (:clientReferenceId)", "h.clientReferenceId IN (:clientReferenceId)"); + query = query + " and h.tenantId=:tenantId "; + if (Boolean.FALSE.equals(includeDeleted)) { + query = query + "and isDeleted=:isDeleted "; + } + query = query + " ) AS rt "; + query = query + " WHERE distance < :distance "; + query = query + " ORDER BY distance ASC LIMIT :limit OFFSET :offset "; + paramsMap.put("s_latitude", searchObject.getLatitude()); + paramsMap.put("s_longitude", searchObject.getLongitude()); + paramsMap.put("tenantId", tenantId); + paramsMap.put("isDeleted", includeDeleted); + paramsMap.put("distance", searchObject.getSearchRadius()); + paramsMap.put("limit", limit); + paramsMap.put("offset", offset); + return this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + } } diff --git a/health-services/household/src/main/java/org/egov/household/service/HouseholdService.java b/health-services/household/src/main/java/org/egov/household/service/HouseholdService.java index feada174cd4..ec03d4b07fb 100644 --- a/health-services/household/src/main/java/org/egov/household/service/HouseholdService.java +++ b/health-services/household/src/main/java/org/egov/household/service/HouseholdService.java @@ -125,6 +125,16 @@ public List search(HouseholdSearch householdSearch, Integer limit, In log.info("households found for search by id, size: {}", households.size()); return households; } + if(isProximityBasedSearch(householdSearch)) { + try { + List households = householdRepository.findByRadius(householdSearch, limit, offset, tenantId, includeDeleted); + log.info("households found for search, size: {}", households.size()); + return households; + } catch (QueryBuilderException e) { + log.error("error occurred while searching households", e); + throw new CustomException("ERROR_IN_QUERY", e.getMessage()); + } + } try { List households = householdRepository.find(householdSearch, limit, offset, tenantId, lastChangedSince, includeDeleted); @@ -231,4 +241,7 @@ private Tuple, Map> validate(List(validHouseholds, errorDetailsMap); } + private Boolean isProximityBasedSearch(HouseholdSearch householdSearch) { + return householdSearch.getLatitude() != null && householdSearch.getLongitude() != null && householdSearch.getSearchRadius() != null; + } } diff --git a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearch.java b/health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearch.java index 839a161a859..b946b1a8d5c 100644 --- a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearch.java +++ b/health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearch.java @@ -7,9 +7,12 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.data.query.annotations.Exclude; import org.egov.common.data.query.annotations.Table; import org.springframework.validation.annotation.Validated; +import javax.validation.constraints.DecimalMax; +import javax.validation.constraints.DecimalMin; import java.util.List; /** @@ -38,5 +41,22 @@ public class HouseholdSearch { @JsonProperty("boundaryCode") private String localityCode = null; + + @Exclude + @JsonProperty("latitude") + @DecimalMin("-90") + @DecimalMax("90") + private Double latitude = null; + + @Exclude + @JsonProperty("longitude") + @DecimalMin("-180") + @DecimalMax("180") + private Double longitude = null; + + @Exclude + @JsonProperty("searchRadius") + @DecimalMin("0") + private Double searchRadius = null; } From 5aea581a0fb633f77d2e7ce3da62704960b57689 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 19 Jul 2023 15:51:07 +0530 Subject: [PATCH 083/283] Added changes for HLM-3092 : proximity based search for individual --- .../repository/IndividualRepository.java | 56 +++++++++++++++++++ .../web/models/IndividualSearch.java | 13 +++++ 2 files changed, 69 insertions(+) diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index 48d8f01dedf..4d2bf294186 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -79,6 +79,10 @@ public List find(IndividualSearch searchObject, Integer limit, Integ Map paramsMap = new HashMap<>(); String query = getQueryForIndividual(searchObject, limit, offset, tenantId, lastChangedSince, includeDeleted, paramsMap); + if (isProximityBasedSearch(searchObject)) { + List individuals = findByRadius(query, searchObject, includeDeleted, paramsMap); + return individuals; + } if (searchObject.getIdentifier() == null) { List individuals = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); if (!individuals.isEmpty()) { @@ -113,6 +117,58 @@ public List find(IndividualSearch searchObject, Integer limit, Integ } } + public List findByRadius(String query, IndividualSearch searchObject, Boolean includeDeleted, Map paramsMap) { + String cte_query = "WITH cte_search_criteria_waypoint(s_latitude, s_longitude) AS (VALUES(:s_latitude, :s_longitude))"; + paramsMap.put("s_latitude", searchObject.getLatitude()); + paramsMap.put("s_longitude", searchObject.getLongitude()); + if (searchObject.getIdentifier() != null) { + Map identifierParamMap = new HashMap<>(); + String identifierQuery = getIdentifierQuery(searchObject.getIdentifier(), identifierParamMap); + identifierParamMap.put("isDeleted", includeDeleted); + List identifiers = this.namedParameterJdbcTemplate + .query(identifierQuery, identifierParamMap, new IdentifierRowMapper()); + if (!identifiers.isEmpty()) { + query = query.replace(" tenantId=:tenantId ", " tenantId=:tenantId AND id=:individualId "); + paramsMap.put("individualId", identifiers.stream().findAny().get().getIndividualId()); + List individuals = this.namedParameterJdbcTemplate.query(query, + paramsMap, this.rowMapper); + if (!individuals.isEmpty()) { + individuals.forEach(individual -> { + individual.setIdentifiers(identifiers); + List
addresses = getAddressForIndividual(individual.getId(), includeDeleted); + individual.setAddress(addresses); + Map indServerGenIdParamMap = new HashMap<>(); + indServerGenIdParamMap.put("individualId", individual.getId()); + indServerGenIdParamMap.put("isDeleted", includeDeleted); + enrichSkills(includeDeleted, individual, indServerGenIdParamMap); + }); + } + return individuals; + } + } else { + query = cte_query + ", cte_individual AS (" + query + ")"; + query = query + "SELECT * FROM (SELECT cte_i.*, ( 6371.4 * acos (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )"; + query = query + "+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ) ) ) AS distance FROM cte_individual cte_i LEFT JOIN public.individual_address ia ON ia.individualid = cte_i.id LEFT JOIN public.address a ON ia.addressid = a.id , cte_search_criteria_waypoint cte_scw) rt "; + if(searchObject.getSearchRadius() != null) { + query = query + " WHERE rt.distance < :distance "; + } + query = query + " ORDER BY distance ASC "; + paramsMap.put("distance", searchObject.getSearchRadius()); + List individuals = this.namedParameterJdbcTemplate.query(query, + paramsMap, this.rowMapper); + if (!individuals.isEmpty()) { + enrichIndividuals(individuals, includeDeleted); + } + return individuals; + } + return Collections.emptyList(); + } + + + private Boolean isProximityBasedSearch(IndividualSearch searchObject) { + return searchObject.getLatitude() != null && searchObject.getLongitude() != null && searchObject.getSearchRadius() != null; + } + private void enrichSkills(Boolean includeDeleted, Individual individual, Map indServerGenIdParamMap) { String individualSkillQuery = getQuery("SELECT * FROM individual_skill WHERE individualId =:individualId", includeDeleted); diff --git a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java b/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java index f846d1187f4..c58a72997f9 100644 --- a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java +++ b/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java @@ -96,5 +96,18 @@ public class IndividualSearch { @Exclude @JsonProperty("userId") private Long userId; + + @Exclude + @JsonProperty("latitude") + private Double latitude; + + @Exclude + @JsonProperty("longitude") + private Double longitude; + + @Exclude + @JsonProperty("searchRadius") + private Double searchRadius; + } From 02ea8c8a3531b3a9eb5ad79d57928e9316b6d09f Mon Sep 17 00:00:00 2001 From: bhanuprakash-egov Date: Wed, 19 Jul 2023 23:04:35 +0530 Subject: [PATCH 084/283] ceiling startdate and enddates to the actual day start --- .../tarento/analytics/handler/LineChartResponseHandler.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/LineChartResponseHandler.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/LineChartResponseHandler.java index 3759710ceb2..5863585e956 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/LineChartResponseHandler.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/handler/LineChartResponseHandler.java @@ -85,8 +85,8 @@ public AggregateDto translate(AggregateRequestDto requestDto, ObjectNode aggrega if(isPredictionEnabled ){ List aggrNodes = aggregationNode.findValues(CHART_SPECIFIC); - startDate = aggrNodes.get(0).findValues(START_DATE).get(0).findValues("key").get(0).asLong(); - endDate = aggrNodes.get(0).findValues(END_DATE).get(0).findValues("key").get(0).asLong(); + startDate = (aggrNodes.get(0).findValues(START_DATE).get(0).findValues("key").get(0).asLong()/86400000)*86400000; + endDate = (aggrNodes.get(0).findValues(END_DATE).get(0).findValues("key").get(0).asLong()/86400000)*86400000; interval=Constants.Interval.day.toString(); addTargetDates(startDate, endDate,targetEpochKeys); } @@ -117,6 +117,7 @@ public AggregateDto translate(AggregateRequestDto requestDto, ObjectNode aggrega Set finalBucketKeys = new LinkedHashSet<>(); // For multi aggr, find all plot keys first +// enrichBucketKeys(aggrNodes, finalBucketKeys, interval); enrichBucketKeys(aggrNodes, finalBucketKeys, interval, startDate, isPredictionEnabled); initializeMultiAggrPlotMap(multiAggrPlotMap, finalBucketKeys); From a8f7369c3120b03ea1db1661d4cac829000ada3b Mon Sep 17 00:00:00 2001 From: bhanuprakash-egov Date: Wed, 19 Jul 2023 23:05:25 +0530 Subject: [PATCH 085/283] handling overall targets when date range exceeeds the campaign duration --- .../helper/AdditiveComputedField.java | 27 +++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/AdditiveComputedField.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/AdditiveComputedField.java index 4ffae4af906..7fe4b16eb14 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/AdditiveComputedField.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/AdditiveComputedField.java @@ -1,6 +1,8 @@ package com.tarento.analytics.helper; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; import com.tarento.analytics.dto.AggregateRequestDto; import com.tarento.analytics.dto.Data; import com.tarento.analytics.dto.Plot; @@ -9,6 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.function.Function; @@ -45,14 +48,23 @@ public void add(Data data, List fields, String newField,JsonNode chartNo for (String field: fields){ if(plotMap.containsKey(field)){ dataType = plotMap.get(field).getSymbol(); + if(doesTextExistInArrayNode((ArrayNode) chartNode.get(IS_CAPPED_BY_CAMPAIGN_PERIOD), field)) continue; total = total+ plotMap.get(field).getValue(); } } if(postAggrTheoryName != null && !postAggrTheoryName.isEmpty()) { ComputeHelper computeHelper = computeHelperFactory.getInstance(postAggrTheoryName); if (chartNode.has(IS_CAPPED_BY_CAMPAIGN_PERIOD)) { - if(plotMap.containsKey(chartNode.get(IS_CAPPED_BY_CAMPAIGN_PERIOD).get(0).asText())) { - capTotal = capTotal + plotMap.get(chartNode.get(IS_CAPPED_BY_CAMPAIGN_PERIOD).get(0).asText()).getValue(); + List commonStrings = new ArrayList<>(); + chartNode.get(IS_CAPPED_BY_CAMPAIGN_PERIOD).forEach( + item -> { + if (fields.contains(item.asText())) { + commonStrings.add(item.asText()); + } + } + ); + if(commonStrings.size()>0) { + capTotal = commonStrings.stream().mapToDouble(commonString -> plotMap.get(commonString).getValue()).sum(); } } @@ -69,5 +81,16 @@ public void add(Data data, List fields, String newField,JsonNode chartNo } } + private static boolean doesTextExistInArrayNode(ArrayNode arrayNode, String searchText) { + for (JsonNode element : arrayNode) { + if (element.isTextual()) { + String text = element.asText(); + if (text.equals(searchText)) { + return true; + } + } + } + return false; + } } From cc2d97b4a78fa03fd4a809afd7fbbf7839f51e34 Mon Sep 17 00:00:00 2001 From: bhanuprakash-egov Date: Wed, 19 Jul 2023 23:29:29 +0530 Subject: [PATCH 086/283] additional check if ISCapped field exists --- .../com/tarento/analytics/helper/AdditiveComputedField.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/AdditiveComputedField.java b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/AdditiveComputedField.java index 7fe4b16eb14..bb858e3dd1d 100644 --- a/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/AdditiveComputedField.java +++ b/core-services/dashboard-analytics/src/main/java/com/tarento/analytics/helper/AdditiveComputedField.java @@ -48,7 +48,7 @@ public void add(Data data, List fields, String newField,JsonNode chartNo for (String field: fields){ if(plotMap.containsKey(field)){ dataType = plotMap.get(field).getSymbol(); - if(doesTextExistInArrayNode((ArrayNode) chartNode.get(IS_CAPPED_BY_CAMPAIGN_PERIOD), field)) continue; + if(chartNode.has(IS_CAPPED_BY_CAMPAIGN_PERIOD) && doesTextExistInArrayNode((ArrayNode) chartNode.get(IS_CAPPED_BY_CAMPAIGN_PERIOD), field)) continue; total = total+ plotMap.get(field).getValue(); } } From c968bfd9b29c18b08db86bba2037cd2182930ea9 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 21 Jul 2023 09:38:57 +0530 Subject: [PATCH 087/283] removed changes not required for HLM-2915 --- .../repository/rowmapper/FacilityRowMapper.java | 4 ---- ...200__add_client_audit_details_in_facility_ddl.sql | 4 ++-- .../java/org/egov/common/models/product/Product.java | 3 --- .../egov/common/models/product/ProductVariant.java | 8 -------- .../egov/common/models/project/ProjectFacility.java | 4 ---- .../egov/common/models/project/ProjectResource.java | 3 --- .../org/egov/common/models/project/ProjectStaff.java | 4 ---- .../org/egov/common/models/project/TaskResource.java | 3 --- .../repository/rowmapper/ProductRowMapper.java | 4 ---- .../rowmapper/ProductVariantRowMapper.java | 4 ---- ...3000__add_client_audit_details_in_product_ddl.sql | 8 ++++---- .../rowmapper/ProjectFacilityRowMapper.java | 4 ---- .../rowmapper/ProjectResourceRowMapper.java | 4 ---- .../repository/rowmapper/ProjectStaffRowMapper.java | 4 ---- ...1500__add_client_audit_details_in_project_ddl.sql | 12 ++++++------ 15 files changed, 12 insertions(+), 61 deletions(-) diff --git a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java index b525bfb07bc..eb6c2440792 100644 --- a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java +++ b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java @@ -55,10 +55,6 @@ public Facility mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastModifiedBy")) .lastModifiedTime(resultSet.getLong("lastModifiedTime")) .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) .build(); diff --git a/health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql b/health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql index e8267679900..c607bc2e639 100644 --- a/health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql +++ b/health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql @@ -1,2 +1,2 @@ -ALTER TABLE FACILITY ADD COLUMN clientCreatedTime bigint; -ALTER TABLE FACILITY ADD COLUMN clientLastModifiedTime bigint; \ No newline at end of file +ALTER TABLE FACILITY DROP COLUMN IF EXISTS clientCreatedTime; +ALTER TABLE FACILITY DROP COLUMN IF EXISTS clientLastModifiedTime; \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java index 8c94529247a..32b9ace7565 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java @@ -62,8 +62,5 @@ public class Product { @Valid private AuditDetails auditDetails = null; - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java index bf0d8513fd9..02004d7ce43 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java @@ -76,16 +76,8 @@ public class ProductVariant { private Integer rowVersion = null; @JsonProperty("auditDetails") - @Valid - - private AuditDetails auditDetails = null; - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; - - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java index ff79f87888b..a8081091e62 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java @@ -64,8 +64,4 @@ public class ProjectFacility { @Valid private AuditDetails auditDetails = null; - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; - } \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java index e9c24173069..d3740b5facb 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java @@ -65,8 +65,5 @@ public class ProjectResource { @Valid private AuditDetails auditDetails = null; - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java index 27f1353c28f..f7c0f205af7 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java @@ -75,9 +75,5 @@ public class ProjectStaff { @Valid private AuditDetails auditDetails = null; - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java index d767a8fa3f2..986275799d2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java @@ -65,8 +65,5 @@ public class TaskResource { @Valid private AuditDetails auditDetails = null; - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; } diff --git a/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductRowMapper.java b/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductRowMapper.java index 83b82ed59bb..24c06d1721a 100644 --- a/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductRowMapper.java +++ b/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductRowMapper.java @@ -33,10 +33,6 @@ public Product mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) .build(); } catch (JsonProcessingException e) { diff --git a/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductVariantRowMapper.java b/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductVariantRowMapper.java index 9c3d04d5d3e..01b1d4d1174 100644 --- a/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductVariantRowMapper.java +++ b/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductVariantRowMapper.java @@ -33,10 +33,6 @@ public ProductVariant mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet .getString("additionalDetails"), AdditionalFields.class)) .build(); diff --git a/health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql b/health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql index a81e6114250..21559d4e997 100644 --- a/health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql +++ b/health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql @@ -1,5 +1,5 @@ -ALTER TABLE PRODUCT ADD COLUMN clientCreatedTime bigint; -ALTER TABLE PRODUCT ADD COLUMN clientLastModifiedTime bigint; +ALTER TABLE PRODUCT DROP COLUMN IF EXISTS clientCreatedTime bigint; +ALTER TABLE PRODUCT DROP COLUMN IF EXISTS clientLastModifiedTime bigint; -ALTER TABLE PRODUCT_VARIANT ADD COLUMN clientCreatedTime bigint; -ALTER TABLE PRODUCT_VARIANT ADD COLUMN clientLastModifiedTime bigint; \ No newline at end of file +ALTER TABLE PRODUCT_VARIANT DROP COLUMN IF EXISTS clientCreatedTime bigint; +ALTER TABLE PRODUCT_VARIANT DROP COLUMN IF EXISTS clientLastModifiedTime bigint; \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java index 13886823429..bd79efb6583 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java @@ -34,10 +34,6 @@ public ProjectFacility mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) .rowVersion(resultSet.getInt("rowversion")) .isDeleted(resultSet.getBoolean("isdeleted")) .build(); diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java index c3fd116c476..34deb79333a 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java @@ -37,10 +37,6 @@ public ProjectResource mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) .rowVersion(resultSet.getInt("rowversion")) .isDeleted(resultSet.getBoolean("isdeleted")) .build(); diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java index 91b7648088a..5403b3a00cc 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java @@ -36,10 +36,6 @@ public ProjectStaff mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) .rowVersion(resultSet.getInt("rowversion")) .isDeleted(resultSet.getBoolean("isdeleted")) .build(); diff --git a/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql index 85b2c6ca59c..9434be3d910 100644 --- a/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql +++ b/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql @@ -1,14 +1,14 @@ ALTER TABLE PROJECT_TASK ADD COLUMN clientCreatedTime bigint; ALTER TABLE PROJECT_TASK ADD COLUMN clientLastModifiedTime bigint; -ALTER TABLE PROJECT_STAFF ADD COLUMN clientCreatedTime bigint; -ALTER TABLE PROJECT_STAFF ADD COLUMN clientLastModifiedTime bigint; +ALTER TABLE PROJECT_STAFF DROP COLUMN IF EXISTS clientCreatedTime bigint; +ALTER TABLE PROJECT_STAFF DROP COLUMN IF EXISTS clientLastModifiedTime bigint; ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN clientCreatedTime bigint; ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN clientLastModifiedTime bigint; -ALTER TABLE PROJECT_RESOURCE ADD COLUMN clientCreatedTime bigint; -ALTER TABLE PROJECT_RESOURCE ADD COLUMN clientLastModifiedTime bigint; +ALTER TABLE PROJECT_RESOURCE DROP COLUMN IF EXISTS clientCreatedTime bigint; +ALTER TABLE PROJECT_RESOURCE DROP COLUMN IF EXISTS clientLastModifiedTime bigint; -ALTER TABLE PROJECT_FACILITY ADD COLUMN clientCreatedTime bigint; -ALTER TABLE PROJECT_FACILITY ADD COLUMN clientLastModifiedTime bigint; +ALTER TABLE PROJECT_FACILITY DROP COLUMN IF EXISTS clientCreatedTime bigint; +ALTER TABLE PROJECT_FACILITY DROP COLUMN IF EXISTS clientLastModifiedTime bigint; From ccc34fd35291a624d219b019361a6b66a80ee7ce Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Thu, 27 Jul 2023 15:06:24 +0530 Subject: [PATCH 088/283] Added changes for HLM-3092 : edge cases for acos function used in query --- .../household/repository/HouseholdRepository.java | 4 ++-- .../individual/repository/IndividualRepository.java | 12 ++++++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java index 01d0a3c1d83..023b473c74c 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java +++ b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java @@ -91,8 +91,8 @@ public List find(HouseholdSearch searchObject, Integer limit, Integer public List findByRadius(HouseholdSearch searchObject, Integer limit, Integer offset, String tenantId, Boolean includeDeleted) throws QueryBuilderException { String query = "WITH cte_search_criteria_waypoint(s_latitude, s_longitude) AS (VALUES(:s_latitude, :s_longitude))\n" + - "SELECT * FROM (SELECT h.*, a.*, ( 6371.4 * acos (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )\n" + - "+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ) ) ) AS distance \n" + + "SELECT * FROM (SELECT h.*, a.*, ( 6371.4 * acos (GREATEST (least (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )\n" + + "+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), 1), -1) ) ) AS distance \n" + "FROM public.household h LEFT JOIN public.address a ON h.addressid = a.id AND h.tenantid = a.tenantid, cte_search_criteria_waypoint cte_scw "; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index 4d2bf294186..1f1a2746416 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -130,6 +130,14 @@ public List findByRadius(String query, IndividualSearch searchObject if (!identifiers.isEmpty()) { query = query.replace(" tenantId=:tenantId ", " tenantId=:tenantId AND id=:individualId "); paramsMap.put("individualId", identifiers.stream().findAny().get().getIndividualId()); + query = cte_query + ", cte_individual AS (" + query + ")"; + query = query + "SELECT * FROM (SELECT cte_i.*, ( 6371.4 * acos ( GREATEST ( LEAST (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )"; + query = query + "+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), 1), -1) ) ) AS distance FROM cte_individual cte_i LEFT JOIN public.individual_address ia ON ia.individualid = cte_i.id LEFT JOIN public.address a ON ia.addressid = a.id , cte_search_criteria_waypoint cte_scw) rt "; + if(searchObject.getSearchRadius() != null) { + query = query + " WHERE rt.distance < :distance "; + } + query = query + " ORDER BY distance ASC "; + paramsMap.put("distance", searchObject.getSearchRadius()); List individuals = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); if (!individuals.isEmpty()) { @@ -147,8 +155,8 @@ public List findByRadius(String query, IndividualSearch searchObject } } else { query = cte_query + ", cte_individual AS (" + query + ")"; - query = query + "SELECT * FROM (SELECT cte_i.*, ( 6371.4 * acos (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )"; - query = query + "+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ) ) ) AS distance FROM cte_individual cte_i LEFT JOIN public.individual_address ia ON ia.individualid = cte_i.id LEFT JOIN public.address a ON ia.addressid = a.id , cte_search_criteria_waypoint cte_scw) rt "; + query = query + "SELECT * FROM (SELECT cte_i.*, ( 6371.4 * acos ( GREATEST ( LEAST (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )"; + query = query + "+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), 1), -1) ) ) AS distance FROM cte_individual cte_i LEFT JOIN public.individual_address ia ON ia.individualid = cte_i.id LEFT JOIN public.address a ON ia.addressid = a.id , cte_search_criteria_waypoint cte_scw) rt "; if(searchObject.getSearchRadius() != null) { query = query + " WHERE rt.distance < :distance "; } From 7e72ca5cd165705109ef4c1505bf631eb74e8984 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Thu, 27 Jul 2023 16:45:00 +0530 Subject: [PATCH 089/283] Added changes for HLM-3069 --- .../common/models/project/AdverseEvent.java | 69 ++++++ .../project/AdverseEventBulkRequest.java | 39 +++ .../project/AdverseEventBulkResponse.java | 37 +++ .../models/project/AdverseEventRequest.java | 29 +++ .../models/project/AdverseEventResponse.java | 31 +++ .../models/project/AdverseEventSearch.java | 31 +++ .../project/AdverseEventSearchRequest.java | 28 +++ .../org/egov/common/models/project/Task.java | 11 + .../main/java/org/egov/project/Constants.java | 5 + .../project/config/ProjectConfiguration.java | 18 ++ .../repository/AdverseEventRepository.java | 119 ++++++++++ .../repository/ProjectTaskRepository.java | 15 ++ .../rowmapper/AdverseEventRowMapper.java | 44 ++++ .../project/service/AdverseEventService.java | 224 ++++++++++++++++++ .../AdverseEventEnrichmentService.java | 58 +++++ .../adverseevent/AdIsDeletedValidator.java | 34 +++ .../AdNonExistentEntityValidator.java | 61 +++++ .../adverseevent/AdNullIdValidator.java | 27 +++ .../AdProjectTaskIdValidator.java | 60 +++++ .../adverseevent/AdUniqueEntityValidator.java | 45 ++++ .../AdverseEventApiController.java | 137 +++++++++++ .../src/main/resources/application.properties | 7 + 22 files changed, 1129 insertions(+) create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEvent.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkRequest.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkResponse.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventRequest.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventResponse.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventSearch.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventSearchRequest.java create mode 100644 health-services/project/src/main/java/org/egov/project/repository/AdverseEventRepository.java create mode 100644 health-services/project/src/main/java/org/egov/project/repository/rowmapper/AdverseEventRowMapper.java create mode 100644 health-services/project/src/main/java/org/egov/project/service/AdverseEventService.java create mode 100644 health-services/project/src/main/java/org/egov/project/service/enrichment/AdverseEventEnrichmentService.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdIsDeletedValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNonExistentEntityValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNullIdValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdProjectTaskIdValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdUniqueEntityValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/web/controllers/AdverseEventApiController.java diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEvent.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEvent.java new file mode 100644 index 00000000000..2e8a6d10d40 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEvent.java @@ -0,0 +1,69 @@ +package org.egov.common.models.project; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.Valid; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class AdverseEvent { + + @JsonProperty("id") + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("clientReferenceId") + @Size(min = 2, max = 64) + private String clientReferenceId = null; + + @JsonProperty("taskId") + @Size(min = 2, max = 64) + private String taskId = null; + + @JsonProperty("taskClientReferenceId") + @Size(min = 2, max = 64) + private String taskClientReferenceId = null; + + @JsonProperty("symptoms") + private List symptoms = null; + + @JsonProperty("reAttempts") + @Min(value = 0, message = "Re-Attempts must be greater than or equal to 0") + private Integer reAttempts = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min=2, max = 1000) + private String tenantId = null; + + @JsonProperty("isDeleted") + private Boolean isDeleted = Boolean.FALSE; + + @JsonProperty("rowVersion") + private Integer rowVersion = null; + + @JsonProperty("auditDetails") + @Valid + private AuditDetails auditDetails = null; + + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + + @JsonIgnore + private Boolean hasErrors = Boolean.FALSE; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkRequest.java new file mode 100644 index 00000000000..bb22f7c9561 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkRequest.java @@ -0,0 +1,39 @@ +package org.egov.common.models.project; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.ArrayList; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class AdverseEventBulkRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("AdverseEvent") + @NotNull + @Valid + @Size(min=1) + private List adverseEvents = new ArrayList<>(); + + public AdverseEventBulkRequest addAdverseEventItem(AdverseEvent adverseEventItem) { + this.adverseEvents.add(adverseEventItem); + return this; + } + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkResponse.java new file mode 100644 index 00000000000..7bd1627caa1 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkResponse.java @@ -0,0 +1,37 @@ +package org.egov.common.models.project; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class AdverseEventBulkResponse { + + @JsonProperty("ResponseInfo") + @NotNull + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("AdverseEvent") + @NotNull + @Valid + private List adverseEvents = new ArrayList<>(); + + public AdverseEventBulkResponse addAdverseEventItem(AdverseEvent adverseEventItem) { + this.adverseEvents.add(adverseEventItem); + return this; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventRequest.java new file mode 100644 index 00000000000..511728bc794 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventRequest.java @@ -0,0 +1,29 @@ +package org.egov.common.models.project; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class AdverseEventRequest{ + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("AdverseEvent") + @NotNull + @Valid + private AdverseEvent adverseEvent = null; +} \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventResponse.java new file mode 100644 index 00000000000..b8c0a91396f --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventResponse.java @@ -0,0 +1,31 @@ +package org.egov.common.models.project; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class AdverseEventResponse { + + @JsonProperty("ResponseInfo") + @NotNull + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("AdverseEvent") + @NotNull + @Valid + private AdverseEvent adverseEvent = null; + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventSearch.java new file mode 100644 index 00000000000..2f7c293ecbe --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventSearch.java @@ -0,0 +1,31 @@ +package org.egov.common.models.project; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.validation.constraints.Size; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class AdverseEventSearch { + @JsonProperty("id") + private List id = null; + + @JsonProperty("clientReferenceId") + private List clientReferenceId = null; + + @JsonProperty("taskId") + private String taskId = null; + + @JsonProperty("taskClientReferenceId") + private String taskClientReferenceId = null; + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventSearchRequest.java new file mode 100644 index 00000000000..287dd316dea --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventSearchRequest.java @@ -0,0 +1,28 @@ +package org.egov.common.models.project; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class AdverseEventSearchRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("AdverseEvent") + @Valid + private AdverseEventSearch adverseEvent = null; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java index a3689eb112c..9067ac54285 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java @@ -101,9 +101,20 @@ public class Task { @JsonIgnore private Boolean hasErrors = Boolean.FALSE; + @JsonProperty("adverseEvents") + private List adverseEvents = new ArrayList<>(); + public Task addResourcesItem(TaskResource resourcesItem) { this.resources.add(resourcesItem); return this; } + + public Task addAdverseEventItem(AdverseEvent adverseEventItem) { + if (this.adverseEvents == null) { + this.adverseEvents = new ArrayList<>(); + } + this.adverseEvents.add(adverseEventItem); + return this; + } } diff --git a/health-services/project/src/main/java/org/egov/project/Constants.java b/health-services/project/src/main/java/org/egov/project/Constants.java index fdf557ad07b..e94bcd7e163 100644 --- a/health-services/project/src/main/java/org/egov/project/Constants.java +++ b/health-services/project/src/main/java/org/egov/project/Constants.java @@ -53,4 +53,9 @@ public interface Constants { String PIPE = "||"; String PROJECT_ID = "projectId"; + + String SET_ADVERSE_EVENTS = "setAdverseEvents"; + + String GET_ADVERSE_EVENTS = "getAdverseEvents"; + } diff --git a/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java b/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java index e90e34ef1d7..e6fe7ea8af7 100644 --- a/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java +++ b/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java @@ -182,4 +182,22 @@ public class ProjectConfiguration { @Value("${egov.user.id.validator}") private String egovUserIdValidator; + + @Value("${project.adverseevent.kafka.create.topic}") + private String createAdverseEventTopic; + + @Value("${project.adverseevent.kafka.update.topic}") + private String updateAdverseEventTopic; + + @Value("${project.adverseevent.kafka.delete.topic}") + private String deleteAdverseEventTopic; + + @Value("${project.adverseevent.consumer.bulk.create.topic}") + private String createAdverseEventBulkTopic; + + @Value("${project.adverseevent.consumer.bulk.update.topic}") + private String updateAdverseEventBulkTopic; + + @Value("${project.adverseevent.consumer.bulk.delete.topic}") + private String deleteAdverseEventBulkTopic; } diff --git a/health-services/project/src/main/java/org/egov/project/repository/AdverseEventRepository.java b/health-services/project/src/main/java/org/egov/project/repository/AdverseEventRepository.java new file mode 100644 index 00000000000..bf5eef0ede4 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/repository/AdverseEventRepository.java @@ -0,0 +1,119 @@ +package org.egov.project.repository; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.builder.GenericQueryBuilder; +import org.egov.common.data.query.builder.QueryFieldChecker; +import org.egov.common.data.query.builder.SelectQueryBuilder; +import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.project.AdverseEvent; +import org.egov.common.models.project.AdverseEventSearch; +import org.egov.common.models.project.Task; +import org.egov.common.producer.Producer; +import org.egov.project.repository.rowmapper.AdverseEventRowMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.stereotype.Repository; +import org.springframework.util.ReflectionUtils; + +import java.lang.reflect.Method; +import java.util.*; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.getIdList; +import static org.egov.common.utils.CommonUtils.getIdMethod; + +@Repository +@Slf4j +public class AdverseEventRepository extends GenericRepository { + @Autowired + private AdverseEventRowMapper rowMapper; + + @Autowired + protected AdverseEventRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, + RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, + AdverseEventRowMapper rowMapper) { + super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, rowMapper, Optional.of("adverse_event")); + } + + public Map> fetchAdverseEvents(List taskList) { + if (taskList.isEmpty()) { + return Collections.emptyMap(); + } + List taskIds = getIdList(taskList); + Map resourceParamsMap = new HashMap<>(); + String resourceQuery = "SELECT * FROM adverse_event ae where ae.taskId IN (:taskIds)"; + resourceParamsMap.put("taskIds", taskIds); + List adverseEventList = this.namedParameterJdbcTemplate.query(resourceQuery, resourceParamsMap, + this.rowMapper); + Map> idToObjMap = new HashMap<>(); + + adverseEventList.forEach(adverseEvent -> { + String taskId = adverseEvent.getTaskId(); + if (idToObjMap.containsKey(taskId)) { + idToObjMap.get(taskId).add(adverseEvent); + } else { + List adverseEvents = new ArrayList<>(); + adverseEvents.add(adverseEvent); + idToObjMap.put(taskId, adverseEvents); + } + }); + return idToObjMap; + } + + public List find(AdverseEventSearch searchObject, Integer limit, Integer offset, String tenantId, + Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { + String query = "SELECT * FROM adverse_event ae LEFT JOIN project_task pt ON ae.taskId = pt.id "; + Map paramsMap = new HashMap<>(); + List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, + QueryFieldChecker.isNotNull, paramsMap); + query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); + query = query.replace("id IN (:id)", "ae.id IN (:id)"); + query = query.replace("clientReferenceId IN (:clientReferenceId)", "ae.clientReferenceId IN (:clientReferenceId)"); + + query = query + " and ae.tenantId=:tenantId "; + if (Boolean.FALSE.equals(includeDeleted)) { + query = query + "and ae.isDeleted=:isDeleted "; + } + + if (lastChangedSince != null) { + query = query + "and as.lastModifiedTime>=:lastModifiedTime "; + } + query = query + "ORDER BY ae.id ASC LIMIT :limit OFFSET :offset"; + paramsMap.put("tenantId", tenantId); + paramsMap.put("isDeleted", includeDeleted); + paramsMap.put("lastModifiedTime", lastChangedSince); + paramsMap.put("limit", limit); + paramsMap.put("offset", offset); + List adverseEventList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + return adverseEventList; + } + + public List findById(List ids, String columnName, Boolean includeDeleted) { + List objFound = findInCache(ids).stream() + .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) + .collect(Collectors.toList()); + if (!objFound.isEmpty()) { + Method idMethod = getIdMethod(objFound, columnName); + ids.removeAll(objFound.stream() + .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) + .collect(Collectors.toList())); + if (ids.isEmpty()) { + return objFound; + } + } + + String query = String.format("SELECT * FROM adverse_event ae LEFT JOIN project_task pt ON ae.taskid = pt.id WHERE ae.%s IN (:ids) ", columnName); + if (includeDeleted == null || !includeDeleted) { + query += " AND ae.isDeleted = false "; + } + Map paramMap = new HashMap<>(); + paramMap.put("ids", ids); + List adverseEventList = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + + objFound.addAll(adverseEventList); + putInCache(objFound); + return objFound; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java b/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java index 0da3ea81713..6dfb693069e 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java +++ b/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java @@ -6,10 +6,12 @@ import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.project.AdverseEvent; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskResource; import org.egov.common.models.project.TaskSearch; import org.egov.common.producer.Producer; +import org.egov.project.repository.rowmapper.AdverseEventRowMapper; import org.egov.project.repository.rowmapper.ProjectTaskRowMapper; import org.egov.project.repository.rowmapper.TaskResourceRowMapper; import org.springframework.beans.factory.annotation.Autowired; @@ -36,6 +38,9 @@ public class ProjectTaskRepository extends GenericRepository { @Autowired private TaskResourceRowMapper taskResourceRowMapper; + @Autowired + private AdverseEventRepository adverseEventRepository; + @Autowired protected ProjectTaskRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, @@ -69,6 +74,7 @@ public List find(TaskSearch searchObject, Integer limit, Integer offset, S paramsMap.put("offset", offset); List taskList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); fetchAndSetTaskResource(taskList); + fetchAndSetAdverseEvents(taskList); return taskList; } @@ -120,8 +126,17 @@ public List findById(List ids, String columnName, Boolean includeD List taskList = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); fetchAndSetTaskResource(taskList); + fetchAndSetAdverseEvents(taskList); objFound.addAll(taskList); putInCache(objFound); return objFound; } + + private void fetchAndSetAdverseEvents(List taskList) { + if (taskList.isEmpty()) { + return; + } + Map> idToObjMap = adverseEventRepository.fetchAdverseEvents(taskList); + taskList.forEach(task -> task.setAdverseEvents(idToObjMap.get(task.getId()))); + } } diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/AdverseEventRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/AdverseEventRowMapper.java new file mode 100644 index 00000000000..ca30650fb24 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/AdverseEventRowMapper.java @@ -0,0 +1,44 @@ +package org.egov.project.repository.rowmapper; + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import org.egov.common.models.project.AdverseEvent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Arrays; + +@Component +public class AdverseEventRowMapper implements RowMapper { + + @Autowired + ObjectMapper objectMapper; + + @Override + public AdverseEvent mapRow(ResultSet resultSet, int i) throws SQLException { + return AdverseEvent.builder() + .id(resultSet.getString("id")) + .clientReferenceId(resultSet.getString("clientreferenceid")) + .taskId(resultSet.getString("taskId")) + .taskClientReferenceId(resultSet.getString("taskClientreferenceid")) + .tenantId(resultSet.getString("tenantid")) + .symptoms(Arrays.asList((String[]) resultSet.getArray("adverseEvents").getArray())) + .reAttempts(resultSet.getInt("reAttempts")) + .rowVersion(resultSet.getInt("rowversion")) + .isDeleted(resultSet.getBoolean("isdeleted")) + .auditDetails(AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) + .build(); + } +} diff --git a/health-services/project/src/main/java/org/egov/project/service/AdverseEventService.java b/health-services/project/src/main/java/org/egov/project/service/AdverseEventService.java new file mode 100644 index 00000000000..866ce9a2c36 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/service/AdverseEventService.java @@ -0,0 +1,224 @@ +package org.egov.project.service; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.ds.Tuple; +import org.egov.common.models.ErrorDetails; +import org.egov.common.models.project.*; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.egov.common.validator.Validator; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.repository.AdverseEventRepository; +import org.egov.project.service.enrichment.AdverseEventEnrichmentService; +import org.egov.project.validator.adverseevent.*; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.ReflectionUtils; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.*; +import static org.egov.project.Constants.SET_ADVERSE_EVENTS; +import static org.egov.project.Constants.VALIDATION_ERROR; + +@Service +@Slf4j +public class AdverseEventService { + private final IdGenService idGenService; + + private final AdverseEventRepository adverseEventRepository; + + private final ProjectService projectService; + + private final ProjectConfiguration projectConfiguration; + + private final AdverseEventEnrichmentService adverseEventEnrichmentService; + + private final List> validators; + + private final Predicate> isApplicableForCreate = validator -> + validator.getClass().equals(AdProjectTaskIdValidator.class); + + private final Predicate> isApplicableForUpdate = validator -> + validator.getClass().equals(AdProjectTaskIdValidator.class) + || validator.getClass().equals(AdNullIdValidator.class) + || validator.getClass().equals(AdIsDeletedValidator.class) + || validator.getClass().equals(AdUniqueEntityValidator.class) + || validator.getClass().equals(AdNonExistentEntityValidator.class); + + private final Predicate> isApplicableForDelete = validator -> + validator.getClass().equals(AdNullIdValidator.class) + || validator.getClass().equals(AdNonExistentEntityValidator.class); + + @Autowired + public AdverseEventService( + IdGenService idGenService, + AdverseEventRepository adverseEventRepository, + ProjectService projectService, + ProjectConfiguration projectConfiguration, + AdverseEventEnrichmentService adverseEventEnrichmentService, + List> validators + ) { + this.idGenService = idGenService; + this.adverseEventRepository = adverseEventRepository; + this.projectService = projectService; + this.projectConfiguration = projectConfiguration; + this.adverseEventEnrichmentService = adverseEventEnrichmentService; + this.validators = validators; + } + + public AdverseEvent create(AdverseEventRequest request) { + log.info("received request to create adverse events"); + AdverseEventBulkRequest bulkRequest = AdverseEventBulkRequest.builder().requestInfo(request.getRequestInfo()) + .adverseEvents(Collections.singletonList(request.getAdverseEvent())).build(); + log.info("creating bulk request"); + return create(bulkRequest, false).get(0); + } + + public List create(AdverseEventBulkRequest adverseEventRequest, boolean isBulk) { + log.info("received request to create bulk adverse events"); + Tuple, Map> tuple = validate(validators, + isApplicableForCreate, adverseEventRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validAdverseEvents = tuple.getX(); + + try { + if (!validAdverseEvents.isEmpty()) { + log.info("processing {} valid entities", validAdverseEvents.size()); + adverseEventEnrichmentService.create(validAdverseEvents, adverseEventRequest); + adverseEventRepository.save(validAdverseEvents, + projectConfiguration.getCreateAdverseEventTopic()); + log.info("successfully created adverse events"); + } + } catch (Exception exception) { + log.error("error occurred while creating adverse events: {}", exception.getMessage()); + populateErrorDetails(adverseEventRequest, errorDetailsMap, validAdverseEvents, + exception, SET_ADVERSE_EVENTS); + } + handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); + + return validAdverseEvents; + } + + public AdverseEvent update(AdverseEventRequest request) { + log.info("received request to update adverse event"); + AdverseEventBulkRequest bulkRequest = AdverseEventBulkRequest.builder().requestInfo(request.getRequestInfo()) + .adverseEvents(Collections.singletonList(request.getAdverseEvent())).build(); + log.info("creating bulk request"); + return update(bulkRequest, false).get(0); + } + + public List update(AdverseEventBulkRequest adverseEventRequest, boolean isBulk) { + log.info("received request to update bulk adverse event"); + Tuple, Map> tuple = validate(validators, + isApplicableForUpdate, adverseEventRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validAdverseEvents = tuple.getX(); + + try { + if (!validAdverseEvents.isEmpty()) { + log.info("processing {} valid entities", validAdverseEvents.size()); + adverseEventEnrichmentService.update(validAdverseEvents, adverseEventRequest); + adverseEventRepository.save(validAdverseEvents, + projectConfiguration.getUpdateAdverseEventTopic()); + log.info("successfully updated bulk adverse events"); + } + } catch (Exception exception) { + log.error("error occurred while updating adverse events", exception); + populateErrorDetails(adverseEventRequest, errorDetailsMap, validAdverseEvents, + exception, SET_ADVERSE_EVENTS); + } + handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); + + return validAdverseEvents; + } + + public List search(AdverseEventSearchRequest adverseEventSearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { + log.info("received request to search adverse events"); + String idFieldName = getIdFieldName(adverseEventSearchRequest.getAdverseEvent()); + if (isSearchByIdOnly(adverseEventSearchRequest.getAdverseEvent(), idFieldName)) { + log.info("searching adverse events by id"); + List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections + .singletonList(adverseEventSearchRequest.getAdverseEvent())), + adverseEventSearchRequest.getAdverseEvent()); + log.info("fetching adverse events with ids: {}", ids); + return adverseEventRepository.findById(ids, includeDeleted, idFieldName).stream() + .filter(lastChangedSince(lastChangedSince)) + .filter(havingTenantId(tenantId)) + .filter(includeDeleted(includeDeleted)) + .collect(Collectors.toList()); + } + log.info("searching adverse events using criteria"); + return adverseEventRepository.find(adverseEventSearchRequest.getAdverseEvent(), + limit, offset, tenantId, lastChangedSince, includeDeleted); + } + + public AdverseEvent delete(AdverseEventRequest adverseEventRequest) { + log.info("received request to delete a adverse event"); + AdverseEventBulkRequest bulkRequest = AdverseEventBulkRequest.builder().requestInfo(adverseEventRequest.getRequestInfo()) + .adverseEvents(Collections.singletonList(adverseEventRequest.getAdverseEvent())).build(); + log.info("creating bulk request"); + return delete(bulkRequest, false).get(0); + } + + public List delete(AdverseEventBulkRequest adverseEventRequest, boolean isBulk) { + Tuple, Map> tuple = validate(validators, + isApplicableForDelete, adverseEventRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validAdverseEvents = tuple.getX(); + + try { + if (!validAdverseEvents.isEmpty()) { + log.info("processing {} valid entities", validAdverseEvents.size()); + adverseEventEnrichmentService.delete(validAdverseEvents, adverseEventRequest); + adverseEventRepository.save(validAdverseEvents, + projectConfiguration.getDeleteAdverseEventTopic()); + log.info("successfully deleted entities"); + } + } catch (Exception exception) { + log.error("error occurred while deleting entities: {}", exception); + populateErrorDetails(adverseEventRequest, errorDetailsMap, validAdverseEvents, + exception, SET_ADVERSE_EVENTS); + } + handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); + + return validAdverseEvents; + } + + public void putInCache(List adverseEvents) { + log.info("putting {} adverse events in cache", adverseEvents.size()); + adverseEventRepository.putInCache(adverseEvents); + log.info("successfully put adverse events in cache"); + } + + private Tuple, Map> validate( + List> validators, + Predicate> isApplicable, + AdverseEventBulkRequest request, + boolean isBulk + ) { + log.info("validating request"); + Map errorDetailsMap = CommonUtils.validate(validators, + isApplicable, request, + SET_ADVERSE_EVENTS); + if (!errorDetailsMap.isEmpty() && !isBulk) { + log.error("validation error occurred. error details: {}", errorDetailsMap.values().toString()); + throw new CustomException(VALIDATION_ERROR, errorDetailsMap.values().toString()); + } + List validAdverseEvents = request.getAdverseEvents().stream() + .filter(notHavingErrors()).collect(Collectors.toList()); + log.info("validation successful, found valid adverse events"); + return new Tuple<>(validAdverseEvents, errorDetailsMap); + } + +} diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/AdverseEventEnrichmentService.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/AdverseEventEnrichmentService.java new file mode 100644 index 00000000000..01cc1911222 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/AdverseEventEnrichmentService.java @@ -0,0 +1,58 @@ +package org.egov.project.service.enrichment; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.project.AdverseEvent; +import org.egov.common.models.project.AdverseEventBulkRequest; +import org.egov.common.models.project.ProjectResourceBulkRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.egov.project.config.ProjectConfiguration; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.egov.common.utils.CommonUtils.enrichForCreate; +import static org.egov.common.utils.CommonUtils.enrichForDelete; +import static org.egov.common.utils.CommonUtils.enrichForUpdate; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.getTenantId; + +@Component +@Slf4j +public class AdverseEventEnrichmentService { + + private final IdGenService idGenService; + + private final ProjectConfiguration projectConfiguration; + + public AdverseEventEnrichmentService(IdGenService idGenService, ProjectConfiguration projectConfiguration) { + this.idGenService = idGenService; + this.projectConfiguration = projectConfiguration; + } + + public void create(List entities, AdverseEventBulkRequest request) throws Exception { + log.info("starting the enrichment for create adverse event"); + log.info("generating IDs using UUID"); + List idList = CommonUtils.uuidSupplier().apply(entities.size()); + log.info("enriching adverse events with generated IDs"); + enrichForCreate(entities, idList, request.getRequestInfo()); + log.info("enrichment done"); + } + + public void update(List entities, AdverseEventBulkRequest request) { + log.info("starting the enrichment for create adverse event"); + Map adverseEventMap = getIdToObjMap(entities); + enrichForUpdate(adverseEventMap, entities, request); + log.info("enrichment done"); + } + + public void delete(List entities, AdverseEventBulkRequest request) { + log.info("starting the enrichment for delete adverse event"); + enrichForDelete(entities, request.getRequestInfo(), true); + log.info("enrichment done"); + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdIsDeletedValidator.java b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdIsDeletedValidator.java new file mode 100644 index 00000000000..744f3b49fbb --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdIsDeletedValidator.java @@ -0,0 +1,34 @@ +package org.egov.project.validator.adverseevent; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.AdverseEvent; +import org.egov.common.models.project.AdverseEventBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForIsDelete; + +@Component +@Order(2) +@Slf4j +public class AdIsDeletedValidator implements Validator { + + @Override + public Map> validate(AdverseEventBulkRequest request) { + log.info("validating isDeleted field"); + HashMap> errorDetailsMap = new HashMap<>(); + List validIndividuals = request.getAdverseEvents(); + validIndividuals.stream().filter(AdverseEvent::getIsDeleted).forEach(individual -> { + Error error = getErrorForIsDelete(); + populateErrorDetails(individual, error, errorDetailsMap); + }); + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNonExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNonExistentEntityValidator.java new file mode 100644 index 00000000000..268ddd78631 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNonExistentEntityValidator.java @@ -0,0 +1,61 @@ +package org.egov.project.validator.adverseevent; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.AdverseEvent; +import org.egov.common.models.project.AdverseEventBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.project.repository.AdverseEventRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.*; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; +import static org.egov.project.Constants.GET_ID; + +@Component +@Order(value = 4) +@Slf4j +public class AdNonExistentEntityValidator implements Validator { + + private final AdverseEventRepository adverseEventRepository; + + @Autowired + public AdNonExistentEntityValidator(AdverseEventRepository adverseEventRepository) { + this.adverseEventRepository = adverseEventRepository; + } + + + @Override + public Map> validate(AdverseEventBulkRequest request) { + log.info("validating for existence of entity"); + Map> errorDetailsMap = new HashMap<>(); + List adverseEvents = request.getAdverseEvents(); + Class objClass = getObjClass(adverseEvents); + Method idMethod = getMethod(GET_ID, objClass); + Map iMap = getIdToObjMap(adverseEvents + .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + if (!iMap.isEmpty()) { + List beneficiaryIds = new ArrayList<>(iMap.keySet()); + List existingAdverseEvents = adverseEventRepository + .findById(beneficiaryIds, false, getIdFieldName(idMethod)); + List nonExistentIndividuals = checkNonExistentEntities(iMap, + existingAdverseEvents, idMethod); + nonExistentIndividuals.forEach(adverseEvent -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(adverseEvent, error, errorDetailsMap); + }); + } + + return errorDetailsMap; + } +} + diff --git a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNullIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNullIdValidator.java new file mode 100644 index 00000000000..b9716429da5 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNullIdValidator.java @@ -0,0 +1,27 @@ +package org.egov.project.validator.adverseevent; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.AdverseEvent; +import org.egov.common.models.project.AdverseEventBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +import static org.egov.common.utils.CommonUtils.validateForNullId; +import static org.egov.project.Constants.GET_ADVERSE_EVENTS; + + +@Component +@Order(value = 1) +@Slf4j +public class AdNullIdValidator implements Validator { + @Override + public Map> validate(AdverseEventBulkRequest request) { + log.info("validating for null id"); + return validateForNullId(request, GET_ADVERSE_EVENTS); + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdProjectTaskIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdProjectTaskIdValidator.java new file mode 100644 index 00000000000..743461d0f04 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdProjectTaskIdValidator.java @@ -0,0 +1,60 @@ +package org.egov.project.validator.adverseevent; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.AdverseEvent; +import org.egov.common.models.project.AdverseEventBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.project.repository.ProjectTaskRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.*; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + + +@Component +@Order(value = 3) +@Slf4j +public class AdProjectTaskIdValidator implements Validator { + private final ProjectTaskRepository projectTaskRepository; + + @Autowired + public AdProjectTaskIdValidator(ProjectTaskRepository projectTaskRepository) { + this.projectTaskRepository = projectTaskRepository; + } + + + @Override + public Map> validate(AdverseEventBulkRequest request) { + log.info("validating project task id"); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getAdverseEvents(); + Class objClass = getObjClass(entities); + Method idMethod = getMethod("getTaskId", objClass); + Map eMap = getIdToObjMap(entities + .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + if (!eMap.isEmpty()) { + List entityIds = new ArrayList<>(eMap.keySet()); + List existingProjectTaskIds = projectTaskRepository.validateIds(entityIds, + getIdFieldName(idMethod)); + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + !existingProjectTaskIds.contains(entity.getTaskId())) + .collect(Collectors.toList()); + invalidEntities.forEach(adverseEvent -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(adverseEvent, error, errorDetailsMap); + }); + } + + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdUniqueEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdUniqueEntityValidator.java new file mode 100644 index 00000000000..e11d14d8d64 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdUniqueEntityValidator.java @@ -0,0 +1,45 @@ +package org.egov.project.validator.adverseevent; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.AdverseEvent; +import org.egov.common.models.project.AdverseEventBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.*; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +@Component +@Order(value = 2) +@Slf4j +public class AdUniqueEntityValidator implements Validator { + + @Override + public Map> validate(AdverseEventBulkRequest request) { + log.info("validating unique entity"); + Map> errorDetailsMap = new HashMap<>(); + List validEntities = request.getAdverseEvents() + .stream().filter(notHavingErrors()).collect(Collectors.toList()); + if (!validEntities.isEmpty()) { + Map eMap = getIdToObjMap(validEntities); + if (eMap.keySet().size() != validEntities.size()) { + List duplicates = eMap.keySet().stream().filter(id -> + validEntities.stream() + .filter(entity -> entity.getId().equals(id)).count() > 1 + ).collect(Collectors.toList()); + for (String key : duplicates) { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(eMap.get(key), error, errorDetailsMap); + } + } + } + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/web/controllers/AdverseEventApiController.java b/health-services/project/src/main/java/org/egov/project/web/controllers/AdverseEventApiController.java new file mode 100644 index 00000000000..278e496667a --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/web/controllers/AdverseEventApiController.java @@ -0,0 +1,137 @@ +package org.egov.project.web.controllers; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.annotations.ApiParam; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.project.*; +import org.egov.common.producer.Producer; +import org.egov.common.utils.ResponseInfoFactory; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.service.*; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Controller +@RequestMapping("") +@Validated +public class AdverseEventApiController { + + private final HttpServletRequest httpServletRequest; + + private final AdverseEventService adverseEventService; + + private final Producer producer; + + private final ProjectConfiguration projectConfiguration; + + public AdverseEventApiController( + HttpServletRequest httpServletRequest, + AdverseEventService adverseEventService, + Producer producer, + ProjectConfiguration projectConfiguration + ) { + this.httpServletRequest = httpServletRequest; + this.adverseEventService = adverseEventService; + this.producer = producer; + this.projectConfiguration = projectConfiguration; + } + + @RequestMapping(value = "/task/adverse_event/v1/_create", method = RequestMethod.POST) + public ResponseEntity adverseEventV1CreatePost(@ApiParam(value = "Capture details of Adverse Event", required = true) @Valid @RequestBody AdverseEventRequest request) { + + AdverseEvent adverseEvent = adverseEventService.create(request); + AdverseEventResponse response = AdverseEventResponse.builder() + .adverseEvent(adverseEvent) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } + + + + @RequestMapping(value = "/task/adverse_event/v1/bulk/_create", method = RequestMethod.POST) + public ResponseEntity adverseEventBulkV1CreatePost(@ApiParam(value = "Capture details of Adverse Event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + adverseEventService.putInCache(request.getAdverseEvents()); + producer.push(projectConfiguration.getCreateAdverseEventBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + + @RequestMapping(value = "/task/adverse_event/v1/_search", method = RequestMethod.POST) + public ResponseEntity adverseEventV1SearchPost(@ApiParam(value = "Adverse Event Search.", required = true) @Valid @RequestBody AdverseEventSearchRequest request, + @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, + @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, + @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, + @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, + @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { + + List households = adverseEventService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); + AdverseEventBulkResponse response = AdverseEventBulkResponse.builder().responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)).adverseEvents(households).build(); + + return ResponseEntity.status(HttpStatus.OK).body(response); + } + + @RequestMapping(value = "/task/adverse_event/v1/_update", method = RequestMethod.POST) + public ResponseEntity adverseEventV1UpdatePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventRequest request) { + AdverseEvent adverseEvent = adverseEventService.update(request); + + AdverseEventResponse response = AdverseEventResponse.builder() + .adverseEvent(adverseEvent) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + + } + + @RequestMapping(value = "/task/adverse_event/v1/bulk/_update", method = RequestMethod.POST) + public ResponseEntity adverseEventV1BulkUpdatePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + producer.push(projectConfiguration.getUpdateAdverseEventBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + + @RequestMapping(value = "/task/adverse_event/v1/_delete", method = RequestMethod.POST) + public ResponseEntity adverseEventV1DeletePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventRequest request) { + AdverseEvent adverseEvent = adverseEventService.delete(request); + + AdverseEventResponse response = AdverseEventResponse.builder() + .adverseEvent(adverseEvent) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + + } + + @RequestMapping(value = "/task/adverse_event/v1/bulk/_delete", method = RequestMethod.POST) + public ResponseEntity adverseEventV1BulkDeletePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + producer.push(projectConfiguration.getDeleteAdverseEventBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } +} diff --git a/health-services/project/src/main/resources/application.properties b/health-services/project/src/main/resources/application.properties index dc9d0bf08f8..460d24b6554 100644 --- a/health-services/project/src/main/resources/application.properties +++ b/health-services/project/src/main/resources/application.properties @@ -164,5 +164,12 @@ project.resource.consumer.bulk.delete.topic=delete-project-resource-bulk-topic project.mdms.module=HCM-PROJECT-TYPES egov.location.hierarchy.type=ADMIN +project.adverseevent.kafka.create.topic=save-adverse-event-topic +project.adverseevent.kafka.update.topic=update-adverse-event-topic +project.adverseevent.kafka.delete.topic=delete-adverse-event-topic + +project.adverseevent.consumer.bulk.create.topic=save-adverse-event-bulk-topic +project.adverseevent.consumer.bulk.update.topic=update-adverse-event-bulk-topic +project.adverseevent.consumer.bulk.delete.topic=delete-adverse-event-bulk-topic From 3e97f8fcb5e658f1a3d5190f5b9a7e37ea78bed1 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 31 Jul 2023 16:05:19 +0530 Subject: [PATCH 090/283] HLM-2915 : increase health-service-model version to 1.0.7 --- health-services/facility/pom.xml | 2 +- health-services/household/pom.xml | 2 +- health-services/individual/pom.xml | 2 +- health-services/libraries/health-services-models/pom.xml | 2 +- health-services/product/pom.xml | 2 +- health-services/project/pom.xml | 2 +- health-services/stock/pom.xml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/health-services/facility/pom.xml b/health-services/facility/pom.xml index 9ec8c51c152..586f4742499 100644 --- a/health-services/facility/pom.xml +++ b/health-services/facility/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT compile diff --git a/health-services/household/pom.xml b/health-services/household/pom.xml index d7d6858761a..ee09d2ed4e3 100644 --- a/health-services/household/pom.xml +++ b/health-services/household/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT compile diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index 868e7e6d426..600dedc103e 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT compile diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index a7c232f4b52..202e7ac2a58 100644 --- a/health-services/libraries/health-services-models/pom.xml +++ b/health-services/libraries/health-services-models/pom.xml @@ -6,7 +6,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT 8 diff --git a/health-services/product/pom.xml b/health-services/product/pom.xml index e9f818572ed..02edf69f5fc 100644 --- a/health-services/product/pom.xml +++ b/health-services/product/pom.xml @@ -80,7 +80,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT compile diff --git a/health-services/project/pom.xml b/health-services/project/pom.xml index 49c8b5982d2..564e18f6d1d 100644 --- a/health-services/project/pom.xml +++ b/health-services/project/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT compile diff --git a/health-services/stock/pom.xml b/health-services/stock/pom.xml index 6d7792d83c3..edaaf44102e 100644 --- a/health-services/stock/pom.xml +++ b/health-services/stock/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT From d3b53f0b0f83ac81cdd54595fe7b81a3ecd7a2ed Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Tue, 1 Aug 2023 17:20:48 +0530 Subject: [PATCH 091/283] fixed null point issue : HLM-3092 --- .../egov/household/repository/HouseholdRepository.java | 4 ++-- .../egov/individual/repository/IndividualRepository.java | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java index 023b473c74c..48dd9413cc6 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java +++ b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java @@ -91,8 +91,8 @@ public List find(HouseholdSearch searchObject, Integer limit, Integer public List findByRadius(HouseholdSearch searchObject, Integer limit, Integer offset, String tenantId, Boolean includeDeleted) throws QueryBuilderException { String query = "WITH cte_search_criteria_waypoint(s_latitude, s_longitude) AS (VALUES(:s_latitude, :s_longitude))\n" + - "SELECT * FROM (SELECT h.*, a.*, ( 6371.4 * acos (GREATEST (least (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )\n" + - "+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), 1), -1) ) ) AS distance \n" + + "SELECT * FROM (SELECT h.*, a.*, ( 6371.4 * acos (LEAST (GREATEST (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )\n" + + "+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), -1), 1) ) ) AS distance \n" + "FROM public.household h LEFT JOIN public.address a ON h.addressid = a.id AND h.tenantid = a.tenantid, cte_search_criteria_waypoint cte_scw "; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index 1f1a2746416..c4a23bf4334 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -131,8 +131,8 @@ public List findByRadius(String query, IndividualSearch searchObject query = query.replace(" tenantId=:tenantId ", " tenantId=:tenantId AND id=:individualId "); paramsMap.put("individualId", identifiers.stream().findAny().get().getIndividualId()); query = cte_query + ", cte_individual AS (" + query + ")"; - query = query + "SELECT * FROM (SELECT cte_i.*, ( 6371.4 * acos ( GREATEST ( LEAST (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )"; - query = query + "+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), 1), -1) ) ) AS distance FROM cte_individual cte_i LEFT JOIN public.individual_address ia ON ia.individualid = cte_i.id LEFT JOIN public.address a ON ia.addressid = a.id , cte_search_criteria_waypoint cte_scw) rt "; + query = query + "SELECT * FROM (SELECT cte_i.*, ( 6371.4 * acos ( LEAST ( GREATEST (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )"; + query = query + "+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), -1), 1) ) ) AS distance FROM cte_individual cte_i LEFT JOIN public.individual_address ia ON ia.individualid = cte_i.id LEFT JOIN public.address a ON ia.addressid = a.id , cte_search_criteria_waypoint cte_scw) rt "; if(searchObject.getSearchRadius() != null) { query = query + " WHERE rt.distance < :distance "; } @@ -155,8 +155,8 @@ public List findByRadius(String query, IndividualSearch searchObject } } else { query = cte_query + ", cte_individual AS (" + query + ")"; - query = query + "SELECT * FROM (SELECT cte_i.*, ( 6371.4 * acos ( GREATEST ( LEAST (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )"; - query = query + "+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), 1), -1) ) ) AS distance FROM cte_individual cte_i LEFT JOIN public.individual_address ia ON ia.individualid = cte_i.id LEFT JOIN public.address a ON ia.addressid = a.id , cte_search_criteria_waypoint cte_scw) rt "; + query = query + "SELECT * FROM (SELECT cte_i.*, ( 6371.4 * acos ( LEAST ( GREATEST (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )"; + query = query + "+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), -1), 1) ) ) AS distance FROM cte_individual cte_i LEFT JOIN public.individual_address ia ON ia.individualid = cte_i.id LEFT JOIN public.address a ON ia.addressid = a.id , cte_search_criteria_waypoint cte_scw) rt "; if(searchObject.getSearchRadius() != null) { query = query + " WHERE rt.distance < :distance "; } From bd25b79554f33ca9091bd308110046cb50f3e95e Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Thu, 3 Aug 2023 11:17:52 +0530 Subject: [PATCH 092/283] HLM-3092 : fixed address null issue due to client audit detail changes --- .../household/repository/rowmapper/HouseholdRowMapper.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java index 6846f9bb3bd..bcf6eebca9e 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java +++ b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java @@ -37,9 +37,9 @@ public Household mapRow(ResultSet resultSet, int i) throws SQLException { .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet .getString("additionalDetails"), AdditionalFields.class)) .address(Address.builder() - .id(resultSet.getString(13)) - .clientReferenceId(resultSet.getString(28)) - .tenantId(resultSet.getString(14)) + .id(resultSet.getString(15)) + .clientReferenceId(resultSet.getString(30)) + .tenantId(resultSet.getString(16)) .doorNo(resultSet.getString("doorNo")) .latitude(resultSet.getDouble("latitude")) .longitude(resultSet.getDouble("longitude")) From 47217dd6211a1c88f85a2f9f94372f04aa7f4589 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 4 Aug 2023 10:29:45 +0530 Subject: [PATCH 093/283] added kafka topic in persister for HLM-3069 --- health-services/project/README.md | 6 ++ .../main/resources/project-task-persister.yml | 61 ++++++++++++++++++- 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/health-services/project/README.md b/health-services/project/README.md index 518e8b8653a..13961132999 100644 --- a/health-services/project/README.md +++ b/health-services/project/README.md @@ -130,6 +130,9 @@ Project service APIs - contains create, update, delete and search end point - update-project-resource-bulk-topic - delete-project-resource-bulk-topic +- save-adverse-event-bulk-topic +- update-adverse-event-bulk-topic +- delete-adverse-event-bulk-topic ### Kafka Producers @@ -153,6 +156,9 @@ Project service APIs - contains create, update, delete and search end point - update-project-resource-topic - delete-project-resource-topic +- save-adverse-event-topic +- update-adverse-event-topic +- delete-adverse-event-topic ## Pre commit script diff --git a/health-services/project/src/main/resources/project-task-persister.yml b/health-services/project/src/main/resources/project-task-persister.yml index e8e2a62dcd5..5dedf60c50e 100644 --- a/health-services/project/src/main/resources/project-task-persister.yml +++ b/health-services/project/src/main/resources/project-task-persister.yml @@ -155,4 +155,63 @@ serviceMaps: - jsonPath: $.*.auditDetails.lastModifiedBy - jsonPath: $.*.auditDetails.lastModifiedTime - jsonPath: $.*.isDeleted - - jsonPath: $.*.id \ No newline at end of file + - jsonPath: $.*.id + + - version: 1.0 + description: Saves a adverse event + fromTopic: save-adverse-event-topic + isTransaction: true + queryMaps: + - query: INSERT INTO ADVERSE_EVENT(id, clientReferenceId, tenantId, taskId, taskClientReferenceId, symptoms, reAttempts, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedTime, clientLastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); + basePath: $.* + jsonMaps: + - jsonPath: $.*.id + - jsonPath: $.*.clientReferenceId + - jsonPath: $.*.tenantId + - jsonPath: $.*.taskId + - jsonPath: $.*.taskClientReferenceId + - jsonPath: $.*.symptoms + - jsonPath: $.*.reAttempts + - jsonPath: $.*.auditDetails.createdBy + - jsonPath: $.*.auditDetails.createdTime + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.createdTime + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + + - version: 1.0 + description: Updates a adverse event + fromTopic: update-adverse-event-topic + isTransaction: true + queryMaps: + - query: UPDATE ADVERSE_EVENT SET tenantId = ?, taskId = ?, taskClientReferenceId = ?, symptoms = ?, reAttempts = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.tenantId + - jsonPath: $.*.taskId + - jsonPath: $.*.taskClientReferenceId + - jsonPath: $.*.symptoms + - jsonPath: $.*.reAttempts + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - jsonPath: $.*.id + + - version: 1.0 + description: Deletes a adverse event + fromTopic: delete-project-task-topic + isTransaction: true + queryMaps: + - query: UPDATE ADVERSE_EVENT SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - jsonPath: $.*.id From 1c7aed8471a02ec0e8375f3b7f31f32d60b20273 Mon Sep 17 00:00:00 2001 From: shubhang-egov Date: Fri, 4 Aug 2023 14:31:47 +0530 Subject: [PATCH 094/283] Removed throwing exception in service request client and instead throwing custom exception --- .../org/egov/common/http/client/ServiceRequestClient.java | 5 ++++- .../src/main/java/org/egov/common/service/IdGenService.java | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/http/client/ServiceRequestClient.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/http/client/ServiceRequestClient.java index b41df36a4af..22d2b64c296 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/http/client/ServiceRequestClient.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/http/client/ServiceRequestClient.java @@ -28,7 +28,7 @@ public ServiceRequestClient(@Qualifier("objectMapper") ObjectMapper objectMapper public T fetchResult(StringBuilder uri, Object request, Class - clazz) throws Exception { + clazz) { objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); T response; try { @@ -36,6 +36,9 @@ public T fetchResult(StringBuilder uri, Object request, Class } catch (HttpClientErrorException e) { throw new CustomException("HTTP_CLIENT_ERROR", String.format("%s - %s", e.getMessage(), e.getResponseBodyAsString())); + }catch (Exception exception) { + throw new CustomException("SERVICE_REQUEST_CLIENT_ERROR", + exception.getMessage()); } return response; } diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/IdGenService.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/IdGenService.java index ec6e1a814f9..c693e8f6788 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/IdGenService.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/IdGenService.java @@ -37,7 +37,7 @@ public IdGenService(ServiceRequestClient restRepo, } public List getIdList(RequestInfo requestInfo, String tenantId, String idName, - String idFormat, Integer count) throws Exception { + String idFormat, Integer count) { List reqList = new ArrayList<>(); for (int i = 0; i < count; i++) { reqList.add(IdRequest.builder().idName(idName).format(idFormat).tenantId(tenantId).build()); From b167e61b9e06f8750469536f184252667578d831 Mon Sep 17 00:00:00 2001 From: shubhang-egov Date: Fri, 4 Aug 2023 14:37:05 +0530 Subject: [PATCH 095/283] Updated pom.xml --- health-services/libraries/health-services-common/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/libraries/health-services-common/pom.xml b/health-services/libraries/health-services-common/pom.xml index f3afea7a2a6..bb50d4a90d6 100644 --- a/health-services/libraries/health-services-common/pom.xml +++ b/health-services/libraries/health-services-common/pom.xml @@ -8,7 +8,7 @@ health-services-common jar health-services-common - 1.0.11-SNAPSHOT + 1.0.12-SNAPSHOT Shared classes among services From 9f7d1e8413fed60bb80520d2428ab6301edafbe1 Mon Sep 17 00:00:00 2001 From: shubhang-egov Date: Fri, 4 Aug 2023 14:44:11 +0530 Subject: [PATCH 096/283] Added CHANGELOG.md --- .../libraries/health-services-common/CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 health-services/libraries/health-services-common/CHANGELOG.md diff --git a/health-services/libraries/health-services-common/CHANGELOG.md b/health-services/libraries/health-services-common/CHANGELOG.md new file mode 100644 index 00000000000..b1087e36aa8 --- /dev/null +++ b/health-services/libraries/health-services-common/CHANGELOG.md @@ -0,0 +1,9 @@ +All notable changes to this module will be documented in this file. + +## 1.0.0 + +- Base version + +## 1.0.12 + +- Replaced throwing Exception with CustomException in service request client. \ No newline at end of file From c04f80e7bb130be9f828f262c730d5fe336b1e7f Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Fri, 4 Aug 2023 14:46:09 +0530 Subject: [PATCH 097/283] Update CHANGELOG.md --- .../libraries/health-services-common/CHANGELOG.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/health-services/libraries/health-services-common/CHANGELOG.md b/health-services/libraries/health-services-common/CHANGELOG.md index b1087e36aa8..bc1ac9c3606 100644 --- a/health-services/libraries/health-services-common/CHANGELOG.md +++ b/health-services/libraries/health-services-common/CHANGELOG.md @@ -1,9 +1,8 @@ All notable changes to this module will be documented in this file. -## 1.0.0 - -- Base version - ## 1.0.12 +- Replaced throwing Exception with CustomException in service request client. -- Replaced throwing Exception with CustomException in service request client. \ No newline at end of file + +## 1.0.0 +- Base version From 29f33324d1d5cb4b1f87e7eb5744a85a22d143a4 Mon Sep 17 00:00:00 2001 From: shubhang-egov Date: Fri, 4 Aug 2023 15:49:34 +0530 Subject: [PATCH 098/283] Individual service change for getting correct error code --- health-services/individual/pom.xml | 2 +- .../java/org/egov/individual/service/EnrichmentService.java | 2 +- .../java/org/egov/individual/service/IndividualService.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index 868e7e6d426..a496ab45909 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -44,7 +44,7 @@ org.egov.common health-services-common - 1.0.11-SNAPSHOT + 1.0.12-SNAPSHOT org.egov.common diff --git a/health-services/individual/src/main/java/org/egov/individual/service/EnrichmentService.java b/health-services/individual/src/main/java/org/egov/individual/service/EnrichmentService.java index ec40a40633c..188a5fe3af9 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/EnrichmentService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/EnrichmentService.java @@ -49,7 +49,7 @@ public EnrichmentService(IdGenService idGenService, this.properties = properties; } - public void create(List validIndividuals, IndividualBulkRequest request) throws Exception { + public void create(List validIndividuals, IndividualBulkRequest request) { log.info("starting the enrichment for create individuals"); log.info("extracting tenantId"); diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java index 7800b4a787c..198c8714f0b 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java @@ -142,7 +142,7 @@ public List create(IndividualBulkRequest request, boolean isBulk) { individualRepository.save(encryptedIndividualList, properties.getSaveIndividualTopic()); } - } catch (Exception exception) { + } catch (CustomException exception) { log.error("error occurred", exception); populateErrorDetails(request, errorDetailsMap, validIndividuals, exception, SET_INDIVIDUALS); } From 3166bd12c4c944a08b75eafa1ee06faf7f0ccbd9 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 4 Aug 2023 18:48:02 +0530 Subject: [PATCH 099/283] HLM-3092: fixed bug, incorrect placement of limit in query --- .../org/egov/individual/repository/IndividualRepository.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index c4a23bf4334..ac752e3c66f 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -118,6 +118,7 @@ public List find(IndividualSearch searchObject, Integer limit, Integ } public List findByRadius(String query, IndividualSearch searchObject, Boolean includeDeleted, Map paramsMap) { + query = query.replace("LIMIT :limit OFFSET :offset", ""); String cte_query = "WITH cte_search_criteria_waypoint(s_latitude, s_longitude) AS (VALUES(:s_latitude, :s_longitude))"; paramsMap.put("s_latitude", searchObject.getLatitude()); paramsMap.put("s_longitude", searchObject.getLongitude()); @@ -137,6 +138,7 @@ public List findByRadius(String query, IndividualSearch searchObject query = query + " WHERE rt.distance < :distance "; } query = query + " ORDER BY distance ASC "; + query = query + "LIMIT :limit OFFSET :offset"; paramsMap.put("distance", searchObject.getSearchRadius()); List individuals = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); @@ -161,6 +163,7 @@ public List findByRadius(String query, IndividualSearch searchObject query = query + " WHERE rt.distance < :distance "; } query = query + " ORDER BY distance ASC "; + query = query + "LIMIT :limit OFFSET :offset"; paramsMap.put("distance", searchObject.getSearchRadius()); List individuals = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); From ce4d90de7fef6ed90ad133bb717466bccc913583 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 7 Aug 2023 09:07:18 +0530 Subject: [PATCH 100/283] added swagger documentation for HLM-3069 --- docs/health-api-specs/contracts/project.yml | 313 +++++++++++++++++- .../project/AdverseEventBulkRequest.java | 2 +- .../project/AdverseEventBulkResponse.java | 2 +- ...230801130400__adverse_event_create_ddl.sql | 19 ++ 4 files changed, 333 insertions(+), 3 deletions(-) create mode 100644 health-services/project/src/main/resources/db/migration/main/V20230801130400__adverse_event_create_ddl.sql diff --git a/docs/health-api-specs/contracts/project.yml b/docs/health-api-specs/contracts/project.yml index 69c19b24a0a..360bf6f8a3f 100644 --- a/docs/health-api-specs/contracts/project.yml +++ b/docs/health-api-specs/contracts/project.yml @@ -174,7 +174,7 @@ paths: schema: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - + /project/beneficiary/v1/bulk/_update: post: @@ -1029,6 +1029,193 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + /project/task/adverse_event/v1/_create: + post: + summary: >- + Create adverse event for the project + description: >- + Create adverse event for the project + parameters: + - name: AdverseEvent + in: body + description: Capture details of Adverse Event + required: true + schema: + $ref: '#/definitions/AdverseEventRequest' + tags: + - Adverse Event + responses: + '202': + description: Create adverse event request has been accepted for creation. + schema: + $ref: '#/definitions/AdverseEventResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + + /project/task/adverse_event/v1/bulk/_create: + post: + summary: >- + Create adverse events for the project in bulk + description: >- + Create adverse events for the project in bulk + parameters: + - name: AdverseEvent + in: body + description: Capture details of Task + required: true + schema: + $ref: '#/definitions/AdverseEventBulkRequest' + tags: + - Adverse Event + responses: + '202': + description: Create adverse event request has been accepted for creation. + schema: + $ref: '#/definitions/BulkAcceptedResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + + /project/task/adverse_event/v1/_update: + post: + summary: >- + Adverse Event Request + description: >- + Adverse Event Request + parameters: + - name: AdverseEvent + in: body + description: Capture details of Existing adverse event + required: true + schema: + $ref: '#/definitions/AdverseEventRequest' + tags: + - Adverse Event + responses: + '202': + description: update averse event request has been accepted for update. + schema: + $ref: '#/definitions/AdverseEventResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + + /project/task/adverse_event/v1/bulk/_update: + post: + summary: >- + Adverse Event Request in bulk for a project + description: >- + Adverse Event Request in bulk for a project + parameters: + - name: AdverseEvent + in: body + description: Capture details of Existing Adverse Events + required: true + schema: + $ref: '#/definitions/AdverseEventBulkRequest' + tags: + - Adverse Event + responses: + '202': + description: update Adverse Events bulk request has been accepted for update. + schema: + $ref: '#/definitions/BulkAcceptedResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + + /project/task/adverse_event/v1/_delete: + post: + summary: >- + Soft delete Adverse Event for a project + description: >- + Soft delete Adverse Event for a project + parameters: + - name: AdverseEvent + in: body + description: Capture details of Existing Adverse Event + required: true + schema: + $ref: '#/definitions/AdverseEventRequest' + tags: + - Adverse Event + responses: + '202': + description: delete Adverse Event request has been accepted for deletion. + schema: + $ref: '#/definitions/AdverseEventResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + + /project/task/adverse_event/v1/bulk/_delete: + post: + summary: >- + Soft delete Adverse Events for a project + description: >- + Soft delete Adverse Events for a project + parameters: + - name: AdverseEvent + in: body + description: Capture details of Existing Adverse Event + required: true + schema: + $ref: '#/definitions/AdverseEventRequest' + tags: + - Adverse Event + responses: + '202': + description: delete bulk Adverse Event request has been accepted for deletion. + schema: + $ref: '#/definitions/BulkAcceptedResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + + /project/task/adverse_event/v1/_search: + post: + summary: >- + Search Adverse Event for Project + description: >- + Search Adverse Event for Project + parameters: + - name: AdverseEvent + in: body + description: Adverse Event Search. + required: true + schema: + $ref: '#/definitions/AdverseEventSearchRequest' + - $ref: '#/parameters/limit' + - $ref: '#/parameters/offset' + - $ref: '#/parameters/tenantId' + - $ref: '#/parameters/lastChangedSince' + - $ref: '#/parameters/includeDeleted' + tags: + - Adverse Event + responses: + '200': + description: Adverse Events. + schema: + $ref: '#/definitions/AdverseEventBulkResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + parameters: #TODO is tenantId required as a query param if it can be determine from requestInfo->userInfo @@ -2202,3 +2389,127 @@ definitions: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo required: - ResponseInfo + + AdverseEvent: + type: object + required: + - tenantId + - taskId + - symptoms + properties: + id: + $ref: '#/definitions/id' + clientReferenceId: + $ref: '#/definitions/clientReferenceId' + tenantId: + $ref: '#/definitions/tenantId' + taskId: + type: string + minLength: 2 + maxLength: 64 + description: Unique TaskId + taskClientReferenceId: + type: string + example: "R-ID-1" + description: Unique Task Client Reference Id + symptoms: + type: array + items: + type: string + reAttempts: + type: integer + format: int64 + description: Re-Attempts + isDeleted: + $ref: '#/definitions/isDeleted' + rowVersion: + $ref: '#/definitions/rowVersion' + auditDetails: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails + clientAuditDetails: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails + + AdverseEventRequest: + type: object + properties: + RequestInfo: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + AdverseEvent: + type: object + $ref: '#/definitions/AdverseEvent' + required: + - RequestInfo + - AdverseEvent + + AdverseEventBulkRequest: + type: object + properties: + RequestInfo: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + AdverseEvents: + type: array + minItems: 1 + items: + $ref: '#/definitions/AdverseEvent' + required: + - RequestInfo + - AdverseEvents + + AdverseEventSearch: + type: object + properties: + id: + $ref: '#/definitions/idForSearch' + clientReferenceId: + $ref: '#/definitions/clientReferenceIdForSearch' + taskId: + type: string + minLength: 2 + maxLength: 64 + description: Unique TaskId + taskClientReferenceId: + type: string + example: "R-ID-1" + + AdverseEventSearchRequest: + type: object + properties: + RequestInfo: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + AdverseEvent: + $ref: '#/definitions/AdverseEventSearch' + required: + - RequestInfo + - AdverseEvent + + AdverseEventResponse: + type: object + properties: + ResponseInfo: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo + AdverseEvent: + type: object + $ref: '#/definitions/AdverseEvent' + required: + - ResponseInfo + - AdverseEvent + + AdverseEventBulkResponse: + type: object + properties: + ResponseInfo: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo + AdverseEvents: + type: array + items: + $ref: '#/definitions/AdverseEvent' + required: + - ResponseInfo + - AdverseEvents \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkRequest.java index bb22f7c9561..c85903f53a2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkRequest.java @@ -25,7 +25,7 @@ public class AdverseEventBulkRequest { @Valid private RequestInfo requestInfo = null; - @JsonProperty("AdverseEvent") + @JsonProperty("AdverseEvents") @NotNull @Valid @Size(min=1) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkResponse.java index 7bd1627caa1..08054d08f71 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkResponse.java @@ -25,7 +25,7 @@ public class AdverseEventBulkResponse { @Valid private ResponseInfo responseInfo = null; - @JsonProperty("AdverseEvent") + @JsonProperty("AdverseEvents") @NotNull @Valid private List adverseEvents = new ArrayList<>(); diff --git a/health-services/project/src/main/resources/db/migration/main/V20230801130400__adverse_event_create_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20230801130400__adverse_event_create_ddl.sql new file mode 100644 index 00000000000..ceada8dac4b --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20230801130400__adverse_event_create_ddl.sql @@ -0,0 +1,19 @@ +CREATE TABLE ADVERSE_EVENT( + id character varchar(64), + clientReferenceId character varchar(64), + tenantId character varchar(1000), + taskId character varchar(64), + taskClientReferenceId character varchar(64), + symptoms array, + reAttempts bigint, + createdBy character varchar(64), + createdTime bigint, + lastModifiedBy character varchar(64), + lastModifiedTime bigint, + clientCreatedTime bigint, + clientLastModifiedTime bigint, + rowVersion bigint, + isDeleted bool, + CONSTRAINT uk_adverse_event PRIMARY KEY (id), + CONSTRAINT uk_adverse_event_clientReference_id unique (clientReferenceId) +); From 2d078d715c86e4899e400081ebd83abdbf126260 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 31 Jul 2023 16:05:19 +0530 Subject: [PATCH 101/283] HLM-2915 : increase health-service-model version to 1.0.7 --- health-services/facility/pom.xml | 2 +- health-services/household/pom.xml | 2 +- health-services/individual/pom.xml | 2 +- health-services/libraries/health-services-models/pom.xml | 2 +- .../main/java/org/egov/common/models/facility/Facility.java | 4 ---- health-services/product/pom.xml | 2 +- health-services/project/pom.xml | 2 +- health-services/stock/pom.xml | 2 +- 8 files changed, 7 insertions(+), 11 deletions(-) diff --git a/health-services/facility/pom.xml b/health-services/facility/pom.xml index 9ec8c51c152..586f4742499 100644 --- a/health-services/facility/pom.xml +++ b/health-services/facility/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT compile diff --git a/health-services/household/pom.xml b/health-services/household/pom.xml index d7d6858761a..ee09d2ed4e3 100644 --- a/health-services/household/pom.xml +++ b/health-services/household/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT compile diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index 868e7e6d426..600dedc103e 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT compile diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index a7c232f4b52..202e7ac2a58 100644 --- a/health-services/libraries/health-services-models/pom.xml +++ b/health-services/libraries/health-services-models/pom.xml @@ -6,7 +6,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT 8 diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java index 1b6f18b870f..338afe924b0 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java @@ -69,10 +69,6 @@ public class Facility { @Valid private AuditDetails auditDetails = null; - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; - @JsonIgnore private Boolean hasErrors = Boolean.FALSE; diff --git a/health-services/product/pom.xml b/health-services/product/pom.xml index e9f818572ed..02edf69f5fc 100644 --- a/health-services/product/pom.xml +++ b/health-services/product/pom.xml @@ -80,7 +80,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT compile diff --git a/health-services/project/pom.xml b/health-services/project/pom.xml index 49c8b5982d2..564e18f6d1d 100644 --- a/health-services/project/pom.xml +++ b/health-services/project/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT compile diff --git a/health-services/stock/pom.xml b/health-services/stock/pom.xml index 6d7792d83c3..edaaf44102e 100644 --- a/health-services/stock/pom.xml +++ b/health-services/stock/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT From 01772ef7616f0b07f992d5dfbd7f68bf4b27b22f Mon Sep 17 00:00:00 2001 From: shubhang-egov Date: Fri, 4 Aug 2023 14:31:47 +0530 Subject: [PATCH 102/283] Removed throwing exception in service request client and instead throwing custom exception --- .../org/egov/common/http/client/ServiceRequestClient.java | 5 ++++- .../src/main/java/org/egov/common/service/IdGenService.java | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/http/client/ServiceRequestClient.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/http/client/ServiceRequestClient.java index b41df36a4af..22d2b64c296 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/http/client/ServiceRequestClient.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/http/client/ServiceRequestClient.java @@ -28,7 +28,7 @@ public ServiceRequestClient(@Qualifier("objectMapper") ObjectMapper objectMapper public T fetchResult(StringBuilder uri, Object request, Class - clazz) throws Exception { + clazz) { objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); T response; try { @@ -36,6 +36,9 @@ public T fetchResult(StringBuilder uri, Object request, Class } catch (HttpClientErrorException e) { throw new CustomException("HTTP_CLIENT_ERROR", String.format("%s - %s", e.getMessage(), e.getResponseBodyAsString())); + }catch (Exception exception) { + throw new CustomException("SERVICE_REQUEST_CLIENT_ERROR", + exception.getMessage()); } return response; } diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/IdGenService.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/IdGenService.java index ec6e1a814f9..c693e8f6788 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/IdGenService.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/IdGenService.java @@ -37,7 +37,7 @@ public IdGenService(ServiceRequestClient restRepo, } public List getIdList(RequestInfo requestInfo, String tenantId, String idName, - String idFormat, Integer count) throws Exception { + String idFormat, Integer count) { List reqList = new ArrayList<>(); for (int i = 0; i < count; i++) { reqList.add(IdRequest.builder().idName(idName).format(idFormat).tenantId(tenantId).build()); From 97c0a1c5c5e3094522ff86cbeecca96d3d21d979 Mon Sep 17 00:00:00 2001 From: shubhang-egov Date: Fri, 4 Aug 2023 14:37:05 +0530 Subject: [PATCH 103/283] Updated pom.xml --- health-services/libraries/health-services-common/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/libraries/health-services-common/pom.xml b/health-services/libraries/health-services-common/pom.xml index f3afea7a2a6..bb50d4a90d6 100644 --- a/health-services/libraries/health-services-common/pom.xml +++ b/health-services/libraries/health-services-common/pom.xml @@ -8,7 +8,7 @@ health-services-common jar health-services-common - 1.0.11-SNAPSHOT + 1.0.12-SNAPSHOT Shared classes among services From bbff72982d02f778ebbfb3ce24bd7358196e0569 Mon Sep 17 00:00:00 2001 From: shubhang-egov Date: Fri, 4 Aug 2023 14:44:11 +0530 Subject: [PATCH 104/283] Added CHANGELOG.md --- .../libraries/health-services-common/CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 health-services/libraries/health-services-common/CHANGELOG.md diff --git a/health-services/libraries/health-services-common/CHANGELOG.md b/health-services/libraries/health-services-common/CHANGELOG.md new file mode 100644 index 00000000000..b1087e36aa8 --- /dev/null +++ b/health-services/libraries/health-services-common/CHANGELOG.md @@ -0,0 +1,9 @@ +All notable changes to this module will be documented in this file. + +## 1.0.0 + +- Base version + +## 1.0.12 + +- Replaced throwing Exception with CustomException in service request client. \ No newline at end of file From fc17cca6019a59c82d29555e86a4298fc2bbdc69 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Fri, 4 Aug 2023 14:46:09 +0530 Subject: [PATCH 105/283] Update CHANGELOG.md --- .../libraries/health-services-common/CHANGELOG.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/health-services/libraries/health-services-common/CHANGELOG.md b/health-services/libraries/health-services-common/CHANGELOG.md index b1087e36aa8..bc1ac9c3606 100644 --- a/health-services/libraries/health-services-common/CHANGELOG.md +++ b/health-services/libraries/health-services-common/CHANGELOG.md @@ -1,9 +1,8 @@ All notable changes to this module will be documented in this file. -## 1.0.0 - -- Base version - ## 1.0.12 +- Replaced throwing Exception with CustomException in service request client. -- Replaced throwing Exception with CustomException in service request client. \ No newline at end of file + +## 1.0.0 +- Base version From d3e49ee2e31f7aa45c521f2dfb43b3760fbf3919 Mon Sep 17 00:00:00 2001 From: shubhang-egov Date: Fri, 4 Aug 2023 15:49:34 +0530 Subject: [PATCH 106/283] Individual service change for getting correct error code --- health-services/individual/pom.xml | 2 +- .../java/org/egov/individual/service/EnrichmentService.java | 2 +- .../java/org/egov/individual/service/IndividualService.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index 868e7e6d426..a496ab45909 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -44,7 +44,7 @@ org.egov.common health-services-common - 1.0.11-SNAPSHOT + 1.0.12-SNAPSHOT org.egov.common diff --git a/health-services/individual/src/main/java/org/egov/individual/service/EnrichmentService.java b/health-services/individual/src/main/java/org/egov/individual/service/EnrichmentService.java index ec40a40633c..188a5fe3af9 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/EnrichmentService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/EnrichmentService.java @@ -49,7 +49,7 @@ public EnrichmentService(IdGenService idGenService, this.properties = properties; } - public void create(List validIndividuals, IndividualBulkRequest request) throws Exception { + public void create(List validIndividuals, IndividualBulkRequest request) { log.info("starting the enrichment for create individuals"); log.info("extracting tenantId"); diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java index ac5b061052f..65559c99b76 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java @@ -138,7 +138,7 @@ public List create(IndividualBulkRequest request, boolean isBulk) { individualRepository.save(encryptedIndividualList, properties.getSaveIndividualTopic()); } - } catch (Exception exception) { + } catch (CustomException exception) { log.error("error occurred", exception); populateErrorDetails(request, errorDetailsMap, validIndividuals, exception, SET_INDIVIDUALS); } From 04aeb20570937db6ec269bbf919584aa4e1c691f Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 7 Aug 2023 12:49:29 +0530 Subject: [PATCH 107/283] changed health-config-models version --- health-services/libraries/health-services-models/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index a7c232f4b52..4a43db87be4 100644 --- a/health-services/libraries/health-services-models/pom.xml +++ b/health-services/libraries/health-services-models/pom.xml @@ -6,7 +6,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.6-SNAPSHOT_dev_temp 8 From a3eb758037c850457d8d1465d7ddaae618856ee2 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 7 Aug 2023 12:49:29 +0530 Subject: [PATCH 108/283] changed health-config-models version and added adverse_event migration script for HLM-3069 --- .../libraries/health-services-models/pom.xml | 2 +- ...V20230801130400__adverse_event_create_ddl.sql | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index a7c232f4b52..4a43db87be4 100644 --- a/health-services/libraries/health-services-models/pom.xml +++ b/health-services/libraries/health-services-models/pom.xml @@ -6,7 +6,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.6-SNAPSHOT_dev_temp 8 diff --git a/health-services/project/src/main/resources/db/migration/main/V20230801130400__adverse_event_create_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20230801130400__adverse_event_create_ddl.sql index ceada8dac4b..df8ddcb4564 100644 --- a/health-services/project/src/main/resources/db/migration/main/V20230801130400__adverse_event_create_ddl.sql +++ b/health-services/project/src/main/resources/db/migration/main/V20230801130400__adverse_event_create_ddl.sql @@ -1,14 +1,14 @@ CREATE TABLE ADVERSE_EVENT( - id character varchar(64), - clientReferenceId character varchar(64), - tenantId character varchar(1000), - taskId character varchar(64), - taskClientReferenceId character varchar(64), - symptoms array, + id character varying(64), + clientReferenceId character varying(64), + tenantId character varying(1000), + taskId character varying(64), + taskClientReferenceId character varying(64), + symptoms text[], reAttempts bigint, - createdBy character varchar(64), + createdBy character varying(64), createdTime bigint, - lastModifiedBy character varchar(64), + lastModifiedBy character varying(64), lastModifiedTime bigint, clientCreatedTime bigint, clientLastModifiedTime bigint, From e3e9cd39aca64722c682c7ffddb8af45527913d6 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 7 Aug 2023 14:47:18 +0530 Subject: [PATCH 109/283] changed models versions --- health-services/project/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/project/pom.xml b/health-services/project/pom.xml index 1b421ad4655..0dd29754cd6 100644 --- a/health-services/project/pom.xml +++ b/health-services/project/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.0-SNAPSHOT + 1.0.6-SNAPSHOT_dev_temp compile From ab8c3c0f6f9a22c322f91d40a85bcca2c09966c1 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Tue, 8 Aug 2023 08:56:57 +0530 Subject: [PATCH 110/283] Added test cases for HLM-3069 --- .../AdverseEventRequestTestBuilder.java | 60 +++++ .../helper/AdverseEventTestBuilder.java | 79 ++++++ .../AdverseEventApiControllerTest.java | 252 ++++++++++++++++++ 3 files changed, 391 insertions(+) create mode 100644 health-services/project/src/test/java/org/egov/project/helper/AdverseEventRequestTestBuilder.java create mode 100644 health-services/project/src/test/java/org/egov/project/helper/AdverseEventTestBuilder.java create mode 100644 health-services/project/src/test/java/org/egov/project/web/controllers/AdverseEventApiControllerTest.java diff --git a/health-services/project/src/test/java/org/egov/project/helper/AdverseEventRequestTestBuilder.java b/health-services/project/src/test/java/org/egov/project/helper/AdverseEventRequestTestBuilder.java new file mode 100644 index 00000000000..f2824526307 --- /dev/null +++ b/health-services/project/src/test/java/org/egov/project/helper/AdverseEventRequestTestBuilder.java @@ -0,0 +1,60 @@ +package org.egov.project.helper; + +import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.project.AdverseEventRequest; + +import java.util.ArrayList; + +public class AdverseEventRequestTestBuilder { + private AdverseEventRequest.AdverseEventRequestBuilder builder; + + private ArrayList adverseEvent = new ArrayList(); + + public AdverseEventRequestTestBuilder() { + this.builder = AdverseEventRequest.builder(); + } + + public static AdverseEventRequestTestBuilder builder() { + return new AdverseEventRequestTestBuilder(); + } + + public AdverseEventRequest build() { + return this.builder.build(); + } + + public AdverseEventRequestTestBuilder withOneAdverseEvent() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .adverseEvent(AdverseEventTestBuilder.builder().withId().withAuditDetails().build()); + return this; + } + + public AdverseEventRequestTestBuilder withApiOperationNotNullAndNotCreate() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .adverseEvent(AdverseEventTestBuilder.builder().withIdNull().build()); + return this; + } + + public AdverseEventRequestTestBuilder withApiOperationNotUpdate() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .adverseEvent(AdverseEventTestBuilder.builder().withIdNull().build()); + return this; + } + + public AdverseEventRequestTestBuilder withOneAdverseEventHavingId() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .adverseEvent(AdverseEventTestBuilder.builder().withId().withAuditDetails().build()); + return this; + } + + public AdverseEventRequestTestBuilder withBadTenantIdInOneAdverseEvent() { + + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .adverseEvent(AdverseEventTestBuilder.builder().withIdNull().withBadTenantId().build()); + return this; + } + + public AdverseEventRequestTestBuilder withRequestInfo(){ + this.builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()); + return this; + } +} diff --git a/health-services/project/src/test/java/org/egov/project/helper/AdverseEventTestBuilder.java b/health-services/project/src/test/java/org/egov/project/helper/AdverseEventTestBuilder.java new file mode 100644 index 00000000000..e276b573eee --- /dev/null +++ b/health-services/project/src/test/java/org/egov/project/helper/AdverseEventTestBuilder.java @@ -0,0 +1,79 @@ +package org.egov.project.helper; + +import org.egov.common.helper.AuditDetailsTestBuilder; +import org.egov.common.models.project.AdverseEvent; + +import java.util.ArrayList; +import java.util.Arrays; + +public class AdverseEventTestBuilder { + + private AdverseEvent.AdverseEventBuilder builder; + + public AdverseEventTestBuilder() { + this.builder = AdverseEvent.builder(); + } + + public static AdverseEventTestBuilder builder() { + return new AdverseEventTestBuilder(); + } + + public AdverseEvent build() { + return this.builder.hasErrors(false).build(); + } + + public AdverseEventTestBuilder withIdNull() { + this.builder.taskId("some-task-id") + .clientReferenceId("adverseEventClientReferenceId") + .id(null) + .taskClientReferenceId("null") + .symptoms(new ArrayList<>(Arrays.asList("fever"))) + .reAttempts(1) + .tenantId("some-tenant-id") + .rowVersion(1); + return this; + } + + public AdverseEventTestBuilder withId() { + withIdNull().builder.id("some-id").taskId("some-task-id") + .clientReferenceId("adverseEventClientReferenceId") + .taskClientReferenceId("null") + .symptoms(new ArrayList<>(Arrays.asList("fever"))) + .reAttempts(1) + .tenantId("some-tenant-id"); + return this; + } + + public AdverseEventTestBuilder withId(String id) { + this.builder.id(id); + return this; + } + + public AdverseEventTestBuilder withBadTenantId() { + this.builder.tenantId(null); + return this; + } + + public AdverseEventTestBuilder goodAdverseEvent() { + this.builder.id("some-id").taskId("some-task-id") + .clientReferenceId("adverseEventClientReferenceId") + .taskClientReferenceId("null") + .symptoms(new ArrayList<>(Arrays.asList("fever"))) + .reAttempts(1) + .tenantId("some-tenant-id") + .rowVersion(1) + .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()) + .clientAuditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); + return this; + } + + public AdverseEventTestBuilder withAuditDetails() { + this.builder.auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); + return this; + } + + public AdverseEventTestBuilder withDeleted() { + this.builder.isDeleted(true); + return this; + } +} diff --git a/health-services/project/src/test/java/org/egov/project/web/controllers/AdverseEventApiControllerTest.java b/health-services/project/src/test/java/org/egov/project/web/controllers/AdverseEventApiControllerTest.java new file mode 100644 index 00000000000..c245374768c --- /dev/null +++ b/health-services/project/src/test/java/org/egov/project/web/controllers/AdverseEventApiControllerTest.java @@ -0,0 +1,252 @@ +package org.egov.project.web.controllers; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.project.*; +import org.egov.common.producer.Producer; +import org.egov.project.TestConfiguration; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.helper.AdverseEventRequestTestBuilder; +import org.egov.project.helper.AdverseEventTestBuilder; +import org.egov.project.service.AdverseEventService; +import org.egov.project.service.ProjectService; +import org.egov.project.service.ProjectTaskService; +import org.egov.tracer.model.CustomException; +import org.egov.tracer.model.ErrorRes; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(AdverseEventApiController.class) +@Import(TestConfiguration.class) +public class AdverseEventApiControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private AdverseEventService adverseEventService; + + @MockBean + private ProjectTaskService projectTaskService; + + @MockBean + private Producer producer; + + @MockBean + private ProjectConfiguration projectConfiguration; + + @MockBean + private ProjectService projectService; + + @Test + @DisplayName("should create adverse event and return with 202 accepted") + void shouldCreateAdverseEventAndReturnWith202Accepted() throws Exception { + AdverseEventRequest request = AdverseEventRequestTestBuilder.builder() + .withOneAdverseEvent() + .withApiOperationNotUpdate() + .build(); + List adverseEvents = getAdverseEvents(); + when(adverseEventService.create(any(AdverseEventRequest.class))).thenReturn(adverseEvents.get(0)); + + final MvcResult result = mockMvc.perform(post("/task/adverse_event/v1/_create") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isAccepted()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + AdverseEventResponse response = objectMapper.readValue(responseStr, AdverseEventResponse.class); + + assertNotNull(response.getAdverseEvent()); + assertNotNull(response.getAdverseEvent().getId()); + assertEquals("successful", response.getResponseInfo().getStatus()); + } + + private List getAdverseEvents() { + AdverseEvent adverseEvent = AdverseEventTestBuilder.builder().withId().build(); + List adverseEvents = new ArrayList<>(); + adverseEvents.add(adverseEvent); + return adverseEvents; + } + + + @Test + @DisplayName("should send error response with error details with 400 bad request for create") + void shouldSendErrorResWithErrorDetailsWith400BadRequestForCreate() throws Exception { + final MvcResult result = mockMvc.perform(post("/task/adverse_event/v1/_create") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(AdverseEventRequestTestBuilder.builder() + .withOneAdverseEvent() + .withBadTenantIdInOneAdverseEvent() + .build()))) + .andExpect(status().isBadRequest()) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + ErrorRes response = objectMapper.readValue(responseStr, ErrorRes.class); + + assertEquals(1, response.getErrors().size()); + assertTrue(response.getErrors().get(0).getCode().contains("tenantId")); + } + + + @Test + @DisplayName("should send 400 bad request in case of incorrect api operation for create") + void shouldSend400BadRequestInCaseOfIncorrectApiOperationForCreate() throws Exception { + final MvcResult result = mockMvc.perform(post("/task/adverse_event/v1/_create") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(AdverseEventRequestTestBuilder.builder() + .withOneAdverseEvent() + .withApiOperationNotNullAndNotCreate() + .build()))) + .andExpect(status().isBadRequest()) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + ErrorRes response = objectMapper.readValue(responseStr, + ErrorRes.class); + + assertEquals(1, response.getErrors().size()); + } + + + @Test + @DisplayName("should update adverse event and return with 202 accepted") + void shouldUpdateAdverseEventAndReturnWith202Accepted() throws Exception { + AdverseEventRequest request = AdverseEventRequestTestBuilder.builder() + .withOneAdverseEventHavingId() + .withApiOperationNotNullAndNotCreate() + .build(); + AdverseEvent adverseEvent = AdverseEventTestBuilder.builder().withId().build(); + when(adverseEventService.update(any(AdverseEventRequest.class))).thenReturn(adverseEvent); + + final MvcResult result = mockMvc.perform(post("/task/adverse_event/v1/_update") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(status().isAccepted()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + AdverseEventResponse response = objectMapper.readValue(responseStr, AdverseEventResponse.class); + + assertNotNull(response.getAdverseEvent()); + assertNotNull(response.getAdverseEvent().getId()); + assertEquals("successful", response.getResponseInfo().getStatus()); + } + + @Test + @DisplayName("should send error response with error details with 400 bad request for update") + void shouldSendErrorResWithErrorDetailsWith400BadRequestForUpdate() throws Exception { + final MvcResult result = mockMvc.perform(post("/task/adverse_event/v1/_update") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(AdverseEventRequestTestBuilder.builder() + .withOneAdverseEventHavingId() + .withBadTenantIdInOneAdverseEvent() + .build()))) + .andExpect(status().isBadRequest()) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + ErrorRes response = objectMapper.readValue(responseStr, + ErrorRes.class); + + assertEquals(1, response.getErrors().size()); + assertTrue(response.getErrors().get(0).getCode().contains("tenantId")); + } + + @Test + @DisplayName("should send 400 bad request in case of incorrect api operation for update") + void shouldSend400BadRequestInCaseOfIncorrectApiOperationForUpdate() throws Exception { + final MvcResult result = mockMvc.perform(post("/task/adverse_event/v1/_update") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(AdverseEventRequestTestBuilder.builder() + .withOneAdverseEventHavingId() + .withApiOperationNotUpdate() + .build()))) + .andExpect(status().isBadRequest()) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + ErrorRes response = objectMapper.readValue(responseStr, + ErrorRes.class); + + assertEquals(1, response.getErrors().size()); + } + + + @Test + @DisplayName("Should accept search request and return response as accepted") + void shouldAcceptSearchRequestAndReturnAdverseEvent() throws Exception { + + AdverseEventSearchRequest adverseEventSearchRequest = AdverseEventSearchRequest.builder().adverseEvent( + AdverseEventSearch.builder().taskId("some-task-id").build() + ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); + + when(adverseEventService.search(any(AdverseEventSearchRequest.class), + any(Integer.class), + any(Integer.class), + any(String.class), + any(Long.class), + any(Boolean.class))).thenReturn(Arrays.asList(AdverseEventTestBuilder.builder().withId().withAuditDetails().build())); + + final MvcResult result = mockMvc.perform(post( + "/task/adverse_event/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(adverseEventSearchRequest))) + .andExpect(status().isOk()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + AdverseEventBulkResponse response = objectMapper.readValue(responseStr, + AdverseEventBulkResponse.class); + + assertEquals(response.getAdverseEvents().size(), 1); + } + + @Test + @DisplayName("Should accept search request and return response as accepted") + void shouldThrowExceptionIfNoResultFound() throws Exception { + + AdverseEventSearchRequest adverseEventSearchRequest = AdverseEventSearchRequest.builder().adverseEvent( + AdverseEventSearch.builder().taskId("some-task-id").build() + ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); + + when(adverseEventService.search(any(AdverseEventSearchRequest.class), + any(Integer.class), + any(Integer.class), + any(String.class), + any(Long.class), + any(Boolean.class))).thenThrow(new CustomException("NO_RESULT_FOUND", "No Adverse Event found.")); + + + final MvcResult result = mockMvc.perform(post("/task/adverse_event/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(adverseEventSearchRequest))) + .andExpect(status().isBadRequest()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + ErrorRes response = objectMapper.readValue(responseStr, + ErrorRes.class); + + assertEquals(response.getErrors().size(), 1); + } + +} From f49f325e31a2989ad0c4a938650c28dd3447facf Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Tue, 8 Aug 2023 16:37:51 +0530 Subject: [PATCH 111/283] added change for HLM-3069 : db type change for symptoms --- .../rowmapper/AdverseEventRowMapper.java | 48 +++++++++++-------- .../AdProjectTaskIdValidator.java | 5 +- ...30807130400__adverse_event_create_ddl.sql} | 2 +- 3 files changed, 31 insertions(+), 24 deletions(-) rename health-services/project/src/main/resources/db/migration/main/{V20230801130400__adverse_event_create_ddl.sql => V20230807130400__adverse_event_create_ddl.sql} (95%) diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/AdverseEventRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/AdverseEventRowMapper.java index ca30650fb24..4ca1ba298bf 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/AdverseEventRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/AdverseEventRowMapper.java @@ -1,5 +1,6 @@ package org.egov.project.repository.rowmapper; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; import org.egov.common.models.project.AdverseEvent; @@ -9,6 +10,7 @@ import java.sql.ResultSet; import java.sql.SQLException; +import java.util.ArrayList; import java.util.Arrays; @Component @@ -19,26 +21,30 @@ public class AdverseEventRowMapper implements RowMapper { @Override public AdverseEvent mapRow(ResultSet resultSet, int i) throws SQLException { - return AdverseEvent.builder() - .id(resultSet.getString("id")) - .clientReferenceId(resultSet.getString("clientreferenceid")) - .taskId(resultSet.getString("taskId")) - .taskClientReferenceId(resultSet.getString("taskClientreferenceid")) - .tenantId(resultSet.getString("tenantid")) - .symptoms(Arrays.asList((String[]) resultSet.getArray("adverseEvents").getArray())) - .reAttempts(resultSet.getInt("reAttempts")) - .rowVersion(resultSet.getInt("rowversion")) - .isDeleted(resultSet.getBoolean("isdeleted")) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) - .build(); + try { + return AdverseEvent.builder() + .id(resultSet.getString("id")) + .clientReferenceId(resultSet.getString("clientreferenceid")) + .taskId(resultSet.getString("taskId")) + .taskClientReferenceId(resultSet.getString("taskClientreferenceid")) + .tenantId(resultSet.getString("tenantid")) + .symptoms(resultSet.getString("symptoms") == null ? null : objectMapper.readValue(resultSet.getString("symptoms"), ArrayList.class)) + .reAttempts(resultSet.getInt("reAttempts")) + .rowVersion(resultSet.getInt("rowversion")) + .isDeleted(resultSet.getBoolean("isdeleted")) + .auditDetails(AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) + .build(); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } } } diff --git a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdProjectTaskIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdProjectTaskIdValidator.java index 743461d0f04..b4886e483b2 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdProjectTaskIdValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdProjectTaskIdValidator.java @@ -44,8 +44,9 @@ public Map> validate(AdverseEventBulkRequest request) .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); if (!eMap.isEmpty()) { List entityIds = new ArrayList<>(eMap.keySet()); - List existingProjectTaskIds = projectTaskRepository.validateIds(entityIds, - getIdFieldName(idMethod)); + List existingProjectTaskIds = projectTaskRepository.findById(entityIds, getIdFieldName(idMethod),Boolean.FALSE) + .stream().map(t -> t.getId()) + .collect(Collectors.toList()); List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> !existingProjectTaskIds.contains(entity.getTaskId())) .collect(Collectors.toList()); diff --git a/health-services/project/src/main/resources/db/migration/main/V20230801130400__adverse_event_create_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20230807130400__adverse_event_create_ddl.sql similarity index 95% rename from health-services/project/src/main/resources/db/migration/main/V20230801130400__adverse_event_create_ddl.sql rename to health-services/project/src/main/resources/db/migration/main/V20230807130400__adverse_event_create_ddl.sql index df8ddcb4564..7102792ecde 100644 --- a/health-services/project/src/main/resources/db/migration/main/V20230801130400__adverse_event_create_ddl.sql +++ b/health-services/project/src/main/resources/db/migration/main/V20230807130400__adverse_event_create_ddl.sql @@ -4,7 +4,7 @@ CREATE TABLE ADVERSE_EVENT( tenantId character varying(1000), taskId character varying(64), taskClientReferenceId character varying(64), - symptoms text[], + symptoms jsonb, reAttempts bigint, createdBy character varying(64), createdTime bigint, From 5bc19096420b1d3fc6e5dc4ef5ca94ad57a4973a Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 9 Aug 2023 12:15:37 +0530 Subject: [PATCH 112/283] removing non-relavent test case for HLM-3069 --- .../main/resources/project-task-persister.yml | 6 ++- .../AdverseEventApiControllerTest.java | 41 +------------------ 2 files changed, 6 insertions(+), 41 deletions(-) diff --git a/health-services/project/src/main/resources/project-task-persister.yml b/health-services/project/src/main/resources/project-task-persister.yml index 5dedf60c50e..807961df6f7 100644 --- a/health-services/project/src/main/resources/project-task-persister.yml +++ b/health-services/project/src/main/resources/project-task-persister.yml @@ -171,6 +171,8 @@ serviceMaps: - jsonPath: $.*.taskId - jsonPath: $.*.taskClientReferenceId - jsonPath: $.*.symptoms + type: JSON + dbType: JSONB - jsonPath: $.*.reAttempts - jsonPath: $.*.auditDetails.createdBy - jsonPath: $.*.auditDetails.createdTime @@ -193,6 +195,8 @@ serviceMaps: - jsonPath: $.*.taskId - jsonPath: $.*.taskClientReferenceId - jsonPath: $.*.symptoms + type: JSON + dbType: JSONB - jsonPath: $.*.reAttempts - jsonPath: $.*.auditDetails.lastModifiedBy - jsonPath: $.*.auditDetails.lastModifiedTime @@ -203,7 +207,7 @@ serviceMaps: - version: 1.0 description: Deletes a adverse event - fromTopic: delete-project-task-topic + fromTopic: delete-adverse-event-topic isTransaction: true queryMaps: - query: UPDATE ADVERSE_EVENT SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; diff --git a/health-services/project/src/test/java/org/egov/project/web/controllers/AdverseEventApiControllerTest.java b/health-services/project/src/test/java/org/egov/project/web/controllers/AdverseEventApiControllerTest.java index c245374768c..440e4d0ff3f 100644 --- a/health-services/project/src/test/java/org/egov/project/web/controllers/AdverseEventApiControllerTest.java +++ b/health-services/project/src/test/java/org/egov/project/web/controllers/AdverseEventApiControllerTest.java @@ -109,26 +109,6 @@ void shouldSendErrorResWithErrorDetailsWith400BadRequestForCreate() throws Excep assertTrue(response.getErrors().get(0).getCode().contains("tenantId")); } - - @Test - @DisplayName("should send 400 bad request in case of incorrect api operation for create") - void shouldSend400BadRequestInCaseOfIncorrectApiOperationForCreate() throws Exception { - final MvcResult result = mockMvc.perform(post("/task/adverse_event/v1/_create") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(AdverseEventRequestTestBuilder.builder() - .withOneAdverseEvent() - .withApiOperationNotNullAndNotCreate() - .build()))) - .andExpect(status().isBadRequest()) - .andReturn(); - String responseStr = result.getResponse().getContentAsString(); - ErrorRes response = objectMapper.readValue(responseStr, - ErrorRes.class); - - assertEquals(1, response.getErrors().size()); - } - - @Test @DisplayName("should update adverse event and return with 202 accepted") void shouldUpdateAdverseEventAndReturnWith202Accepted() throws Exception { @@ -171,26 +151,7 @@ void shouldSendErrorResWithErrorDetailsWith400BadRequestForUpdate() throws Excep assertEquals(1, response.getErrors().size()); assertTrue(response.getErrors().get(0).getCode().contains("tenantId")); } - - @Test - @DisplayName("should send 400 bad request in case of incorrect api operation for update") - void shouldSend400BadRequestInCaseOfIncorrectApiOperationForUpdate() throws Exception { - final MvcResult result = mockMvc.perform(post("/task/adverse_event/v1/_update") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(AdverseEventRequestTestBuilder.builder() - .withOneAdverseEventHavingId() - .withApiOperationNotUpdate() - .build()))) - .andExpect(status().isBadRequest()) - .andReturn(); - String responseStr = result.getResponse().getContentAsString(); - ErrorRes response = objectMapper.readValue(responseStr, - ErrorRes.class); - - assertEquals(1, response.getErrors().size()); - } - - + @Test @DisplayName("Should accept search request and return response as accepted") void shouldAcceptSearchRequestAndReturnAdverseEvent() throws Exception { From 4b222e395247d0586db125b6e84da83278380f7c Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 9 Aug 2023 16:14:24 +0530 Subject: [PATCH 113/283] HLM-3069 : missing bulk request consumer added --- .../consumer/AdverseEventConsumer.java | 69 +++++++++++++++++++ .../AdNonExistentEntityValidator.java | 16 ++++- 2 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 health-services/project/src/main/java/org/egov/project/consumer/AdverseEventConsumer.java diff --git a/health-services/project/src/main/java/org/egov/project/consumer/AdverseEventConsumer.java b/health-services/project/src/main/java/org/egov/project/consumer/AdverseEventConsumer.java new file mode 100644 index 00000000000..b343cb4cbaf --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/consumer/AdverseEventConsumer.java @@ -0,0 +1,69 @@ +package org.egov.project.consumer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.project.AdverseEvent; +import org.egov.common.models.project.AdverseEventBulkRequest; +import org.egov.project.service.AdverseEventService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +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.Collections; +import java.util.List; +import java.util.Map; + +@Component +@Slf4j +public class AdverseEventConsumer { + + private final AdverseEventService adverseEventService; + + private final ObjectMapper objectMapper; + + @Autowired + public AdverseEventConsumer(AdverseEventService adverseEventService, + @Qualifier("objectMapper") ObjectMapper objectMapper) { + this.adverseEventService = adverseEventService; + this.objectMapper = objectMapper; + } + + @KafkaListener(topics = "${project.adverseevent.consumer.bulk.create.topic}") + public List bulkCreate(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + AdverseEventBulkRequest request = objectMapper.convertValue(consumerRecord, AdverseEventBulkRequest.class); + return adverseEventService.create(request, true); + } catch (Exception exception) { + log.error("error in adverse event consumer bulk create", exception); + return Collections.emptyList(); + } + } + + @KafkaListener(topics = "${project.adverseevent.consumer.bulk.update.topic}") + public List bulkUpdate(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + AdverseEventBulkRequest request = objectMapper.convertValue(consumerRecord, AdverseEventBulkRequest.class); + return adverseEventService.update(request, true); + } catch (Exception exception) { + log.error("error in adverse event consumer bulk update", exception); + return Collections.emptyList(); + } + } + + @KafkaListener(topics = "${project.adverseevent.consumer.bulk.delete.topic}") + public List bulkDelete(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + AdverseEventBulkRequest request = objectMapper.convertValue(consumerRecord, AdverseEventBulkRequest.class); + return adverseEventService.delete(request, true); + } catch (Exception exception) { + log.error("error in adverse event consumer bulk delete", exception); + return Collections.emptyList(); + } + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNonExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNonExistentEntityValidator.java index 268ddd78631..9cc27090909 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNonExistentEntityValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNonExistentEntityValidator.java @@ -1,5 +1,7 @@ package org.egov.project.validator.adverseevent; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; import org.egov.common.models.project.AdverseEvent; @@ -28,9 +30,12 @@ public class AdNonExistentEntityValidator implements Validator> validate(AdverseEventBulkRequest request) Map iMap = getIdToObjMap(adverseEvents .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); if (!iMap.isEmpty()) { - List beneficiaryIds = new ArrayList<>(iMap.keySet()); + List adverseEventIds = new ArrayList<>(iMap.keySet()); List existingAdverseEvents = adverseEventRepository - .findById(beneficiaryIds, false, getIdFieldName(idMethod)); + .findById(adverseEventIds, false, getIdFieldName(idMethod)); + existingAdverseEvents.forEach(eAD -> { + if(iMap.containsKey(eAD.getId())) { + iMap.get(eAD.getId()).setRowVersion(eAD.getRowVersion()); + } + }); List nonExistentIndividuals = checkNonExistentEntities(iMap, existingAdverseEvents, idMethod); nonExistentIndividuals.forEach(adverseEvent -> { From 39832f3a2998c55d4eee6fd4dc25a245d4dc4b0d Mon Sep 17 00:00:00 2001 From: shubhang-egov Date: Wed, 9 Aug 2023 18:24:58 +0530 Subject: [PATCH 114/283] PFM-4292-fixed User lastname is set to null --- .../java/org/egov/individual/service/IndividualMapper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java index c670fc29e47..421cca22696 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java @@ -31,8 +31,8 @@ public static UserRequest toUserRequest(Individual individual, IndividualPropert .id(id) .uuid(individual.getUserUuid()) .tenantId(individual.getTenantId()) - .name(String.join(" ", individual.getName().getGivenName(), - individual.getName().getFamilyName())) + .name(individual.getName().getFamilyName() != null ? String.join(" ", individual.getName().getGivenName(), + individual.getName().getFamilyName()) : individual.getName().getGivenName()) .correspondenceAddress(addressLine1) .emailId(individual.getEmail()) .mobileNumber(generateDummyMobileNumber(individual.getMobileNumber())) From 6c6afa0a831eddda2514a8e8530b5b364fbdb67e Mon Sep 17 00:00:00 2001 From: shubhang-egov Date: Wed, 9 Aug 2023 18:24:58 +0530 Subject: [PATCH 115/283] PFM-4292-fixed User lastname is set to null --- .../java/org/egov/individual/service/IndividualMapper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java index c670fc29e47..421cca22696 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java @@ -31,8 +31,8 @@ public static UserRequest toUserRequest(Individual individual, IndividualPropert .id(id) .uuid(individual.getUserUuid()) .tenantId(individual.getTenantId()) - .name(String.join(" ", individual.getName().getGivenName(), - individual.getName().getFamilyName())) + .name(individual.getName().getFamilyName() != null ? String.join(" ", individual.getName().getGivenName(), + individual.getName().getFamilyName()) : individual.getName().getGivenName()) .correspondenceAddress(addressLine1) .emailId(individual.getEmail()) .mobileNumber(generateDummyMobileNumber(individual.getMobileNumber())) From 0f6e001e913692c68b030ca2095f2272b05e3f1b Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Thu, 10 Aug 2023 15:19:54 +0530 Subject: [PATCH 116/283] Added changed logic for delete api for HLM-3069 --- .../egov/project/service/AdverseEventService.java | 7 +++++-- .../enrichment/AdverseEventEnrichmentService.java | 13 +++++++------ .../adverseevent/AdNonExistentEntityValidator.java | 5 ----- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/health-services/project/src/main/java/org/egov/project/service/AdverseEventService.java b/health-services/project/src/main/java/org/egov/project/service/AdverseEventService.java index 866ce9a2c36..72168147849 100644 --- a/health-services/project/src/main/java/org/egov/project/service/AdverseEventService.java +++ b/health-services/project/src/main/java/org/egov/project/service/AdverseEventService.java @@ -180,8 +180,11 @@ public List delete(AdverseEventBulkRequest adverseEventRequest, bo try { if (!validAdverseEvents.isEmpty()) { log.info("processing {} valid entities", validAdverseEvents.size()); - adverseEventEnrichmentService.delete(validAdverseEvents, adverseEventRequest); - adverseEventRepository.save(validAdverseEvents, + List adverseEventIds = validAdverseEvents.stream().map(entity -> entity.getId()).collect(Collectors.toSet()).stream().collect(Collectors.toList()); + List existingAdverseEvents = adverseEventRepository + .findById(adverseEventIds, false); + adverseEventEnrichmentService.delete(existingAdverseEvents, adverseEventRequest); + adverseEventRepository.save(existingAdverseEvents, projectConfiguration.getDeleteAdverseEventTopic()); log.info("successfully deleted entities"); } diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/AdverseEventEnrichmentService.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/AdverseEventEnrichmentService.java index 01cc1911222..a4c61029a74 100644 --- a/health-services/project/src/main/java/org/egov/project/service/enrichment/AdverseEventEnrichmentService.java +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/AdverseEventEnrichmentService.java @@ -7,6 +7,8 @@ import org.egov.common.service.IdGenService; import org.egov.common.utils.CommonUtils; import org.egov.project.config.ProjectConfiguration; +import org.egov.project.repository.AdverseEventRepository; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.List; @@ -15,11 +17,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static org.egov.common.utils.CommonUtils.enrichForCreate; -import static org.egov.common.utils.CommonUtils.enrichForDelete; -import static org.egov.common.utils.CommonUtils.enrichForUpdate; -import static org.egov.common.utils.CommonUtils.getIdToObjMap; -import static org.egov.common.utils.CommonUtils.getTenantId; +import static org.egov.common.utils.CommonUtils.*; @Component @Slf4j @@ -29,9 +27,12 @@ public class AdverseEventEnrichmentService { private final ProjectConfiguration projectConfiguration; - public AdverseEventEnrichmentService(IdGenService idGenService, ProjectConfiguration projectConfiguration) { + private final AdverseEventRepository adverseEventRepository; + + public AdverseEventEnrichmentService(IdGenService idGenService, ProjectConfiguration projectConfiguration, AdverseEventRepository adverseEventRepository) { this.idGenService = idGenService; this.projectConfiguration = projectConfiguration; + this.adverseEventRepository = adverseEventRepository; } public void create(List entities, AdverseEventBulkRequest request) throws Exception { diff --git a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNonExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNonExistentEntityValidator.java index 9cc27090909..cdb588371ce 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNonExistentEntityValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNonExistentEntityValidator.java @@ -52,11 +52,6 @@ public Map> validate(AdverseEventBulkRequest request) List adverseEventIds = new ArrayList<>(iMap.keySet()); List existingAdverseEvents = adverseEventRepository .findById(adverseEventIds, false, getIdFieldName(idMethod)); - existingAdverseEvents.forEach(eAD -> { - if(iMap.containsKey(eAD.getId())) { - iMap.get(eAD.getId()).setRowVersion(eAD.getRowVersion()); - } - }); List nonExistentIndividuals = checkNonExistentEntities(iMap, existingAdverseEvents, idMethod); nonExistentIndividuals.forEach(adverseEvent -> { From db34cc352dcbcacddd079726a0b7022fbfb75f26 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Sun, 13 Aug 2023 01:18:54 +0530 Subject: [PATCH 117/283] Update build-config.yml --- build/build-config.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build/build-config.yml b/build/build-config.yml index 4ab442bf983..b0f4bbfcd16 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -57,6 +57,11 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "health-services/household/src/main/resources/db" image-name: "household-db" + - name: "builds/health-campaign-services/core-services/error-handler" + build: + - work-dir: "core-services/error-handler" + image-name: "error-handler" + dockerfile: "build/maven/Dockerfile" - name: "builds/health-campaign-services/core-services/dashboard-analytics" build: - work-dir: "core-services/dashboard-analytics" From f74fa03a1ecaab330f75c8ef79e2bf66323ff709 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Tue, 15 Aug 2023 23:36:18 +0530 Subject: [PATCH 118/283] Create codacy.yml --- .github/workflows/codacy.yml | 61 ++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 .github/workflows/codacy.yml diff --git a/.github/workflows/codacy.yml b/.github/workflows/codacy.yml new file mode 100644 index 00000000000..509eb451a59 --- /dev/null +++ b/.github/workflows/codacy.yml @@ -0,0 +1,61 @@ +# This workflow uses actions that are not certified by GitHub. +# They are provided by a third-party and are governed by +# separate terms of service, privacy policy, and support +# documentation. + +# This workflow checks out code, performs a Codacy security scan +# and integrates the results with the +# GitHub Advanced Security code scanning feature. For more information on +# the Codacy security scan action usage and parameters, see +# https://github.com/codacy/codacy-analysis-cli-action. +# For more information on Codacy Analysis CLI in general, see +# https://github.com/codacy/codacy-analysis-cli. + +name: Codacy Security Scan + +on: + push: + branches: [ "master", "master|hlm-[0-9]+.*" ] + pull_request: + # The branches below must be a subset of the branches above + branches: [ "master" ] + schedule: + - cron: '30 13 * * 1' + +permissions: + contents: read + +jobs: + codacy-security-scan: + permissions: + contents: read # for actions/checkout to fetch code + security-events: write # for github/codeql-action/upload-sarif to upload SARIF results + actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status + name: Codacy Security Scan + runs-on: ubuntu-latest + steps: + # Checkout the repository to the GitHub Actions runner + - name: Checkout code + uses: actions/checkout@v3 + + # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis + - name: Run Codacy Analysis CLI + uses: codacy/codacy-analysis-cli-action@d840f886c4bd4edc059706d09c6a1586111c540b + with: + # Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository + # You can also omit the token and run the tools that support default configurations + project-token: ${{ secrets.CODACY_PROJECT_TOKEN }} + verbose: true + output: results.sarif + format: sarif + # Adjust severity of non-security issues + gh-code-scanning-compat: true + # Force 0 exit code to allow SARIF file generation + # This will handover control about PR rejection to the GitHub side + max-allowed-issues: 2147483647 + + # Upload the SARIF file generated in the previous step + - name: Upload SARIF results file + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: results.sarif From bb7db4dfc3641e26e93e482b347079b3d6a762b7 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Tue, 15 Aug 2023 23:41:51 +0530 Subject: [PATCH 119/283] Update codacy.yml --- .github/workflows/codacy.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codacy.yml b/.github/workflows/codacy.yml index 509eb451a59..37a5171543e 100644 --- a/.github/workflows/codacy.yml +++ b/.github/workflows/codacy.yml @@ -15,10 +15,10 @@ name: Codacy Security Scan on: push: - branches: [ "master", "master|hlm-[0-9]+.*" ] + branches: [ "master", "master|hlm-[0-9]+.*", "dev" ] pull_request: # The branches below must be a subset of the branches above - branches: [ "master" ] + branches: [ "master", "dev" ] schedule: - cron: '30 13 * * 1' From 5cad388881d5112047ca3200d59f7bc2403d10bd Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 23 Aug 2023 16:15:42 +0530 Subject: [PATCH 120/283] Removed Not Required migration files from HLM-2915 changes --- ...d_client_audit_details_in_facility_ddl.sql | 2 -- .../rowmapper/HouseholdMemberRowMapper.java | 22 ++++++++-------- .../rowmapper/HouseholdRowMapper.java | 22 ++++++++-------- .../rowmapper/IndividualRowMapper.java | 25 +++++++++++-------- ...dd_client_audit_details_in_product_ddl.sql | 5 ---- .../ProjectBeneficiaryRowMapper.java | 22 ++++++++-------- .../rowmapper/ProjectTaskRowMapper.java | 22 ++++++++-------- ...dd_client_audit_details_in_project_ddl.sql | 16 +++--------- .../StockReconciliationRowMapper.java | 22 ++++++++-------- .../repository/rowmapper/StockRowMapper.java | 22 ++++++++-------- 10 files changed, 90 insertions(+), 90 deletions(-) delete mode 100644 health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql delete mode 100644 health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql diff --git a/health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql b/health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql deleted file mode 100644 index c607bc2e639..00000000000 --- a/health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE FACILITY DROP COLUMN IF EXISTS clientCreatedTime; -ALTER TABLE FACILITY DROP COLUMN IF EXISTS clientLastModifiedTime; \ No newline at end of file diff --git a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java index e99a280dd63..e7d9e0c668b 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java +++ b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java @@ -18,6 +18,16 @@ public class HouseholdMemberRowMapper implements RowMapper { @Override public HouseholdMember mapRow(ResultSet resultSet, int i) throws SQLException { try { + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build(); return HouseholdMember.builder() .id(resultSet.getString("id")) .householdId(resultSet.getString("householdId")) @@ -30,16 +40,8 @@ public HouseholdMember mapRow(ResultSet resultSet, int i) throws SQLException { .getString("additionalDetails"), AdditionalFields.class)) .isDeleted(resultSet.getBoolean("isDeleted")) .rowVersion(resultSet.getInt("rowVersion")) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) .build(); } catch (JsonProcessingException e) { throw new SQLException(e); diff --git a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java index b11547ec8c6..dd72b6d8b53 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java +++ b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java @@ -21,6 +21,16 @@ public class HouseholdRowMapper implements RowMapper { @Override public Household mapRow(ResultSet resultSet, int i) throws SQLException { try { + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build(); Household household = Household.builder() .id(resultSet.getString("id")) .rowVersion(resultSet.getInt("rowVersion")) @@ -28,16 +38,8 @@ public Household mapRow(ResultSet resultSet, int i) throws SQLException { .tenantId(resultSet.getString("tenantId")) .memberCount(resultSet.getInt("numberOfMembers")) .clientReferenceId(resultSet.getString("clientReferenceId")) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet .getString("additionalDetails"), AdditionalFields.class)) .address(Address.builder() diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java index ff42e6821d8..487b96d5470 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java @@ -26,6 +26,16 @@ public class IndividualRowMapper implements RowMapper { public Individual mapRow(ResultSet resultSet, int i) throws SQLException { try { String tenantId = resultSet.getString("tenantId"); + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build(); return Individual.builder().id(resultSet.getString("id")) .individualId(resultSet.getString("individualid")) .userId(resultSet.getString("userId")) @@ -47,13 +57,9 @@ public Individual mapRow(ResultSet resultSet, int i) throws SQLException { .photo(resultSet.getString("photo")) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet.getString("additionalDetails"), - AdditionalFields.class)) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) + AdditionalFields.class) + ) + .auditDetails(auditDetails) .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) .isSystemUser(resultSet.getBoolean("isSystemUser")) @@ -68,10 +74,7 @@ public Individual mapRow(ResultSet resultSet, int i) throws SQLException { .tenantId(tenantId) .build()) .userUuid(resultSet.getString("userUuid")) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) + .clientAuditDetails(clientAuditDetails) .build(); } catch (JsonProcessingException e) { throw new RuntimeException(e); diff --git a/health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql b/health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql deleted file mode 100644 index 21559d4e997..00000000000 --- a/health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql +++ /dev/null @@ -1,5 +0,0 @@ -ALTER TABLE PRODUCT DROP COLUMN IF EXISTS clientCreatedTime bigint; -ALTER TABLE PRODUCT DROP COLUMN IF EXISTS clientLastModifiedTime bigint; - -ALTER TABLE PRODUCT_VARIANT DROP COLUMN IF EXISTS clientCreatedTime bigint; -ALTER TABLE PRODUCT_VARIANT DROP COLUMN IF EXISTS clientLastModifiedTime bigint; \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java index 4c2092c3734..633378ebbf2 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java @@ -19,6 +19,16 @@ public class ProjectBeneficiaryRowMapper implements RowMapper { @Override public Task mapRow(ResultSet resultSet, int i) throws SQLException { try { + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build(); Task task = Task.builder() .id(resultSet.getString("id")) .rowVersion(resultSet.getInt("rowVersion")) @@ -36,16 +46,8 @@ public Task mapRow(ResultSet resultSet, int i) throws SQLException { .actualStartDate(resultSet.getLong("actualStartDate")) .actualEndDate(resultSet.getLong("actualEndDate")) .status(resultSet.getString("status")) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) .address(Address.builder() diff --git a/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql index 9434be3d910..d2b0da3ef3e 100644 --- a/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql +++ b/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql @@ -1,14 +1,6 @@ -ALTER TABLE PROJECT_TASK ADD COLUMN clientCreatedTime bigint; -ALTER TABLE PROJECT_TASK ADD COLUMN clientLastModifiedTime bigint; +ALTER TABLE PROJECT_TASK ADD COLUMN IF NOT EXISTS clientCreatedTime bigint; +ALTER TABLE PROJECT_TASK ADD COLUMN IF NOT EXISTS clientLastModifiedTime bigint; -ALTER TABLE PROJECT_STAFF DROP COLUMN IF EXISTS clientCreatedTime bigint; -ALTER TABLE PROJECT_STAFF DROP COLUMN IF EXISTS clientLastModifiedTime bigint; +ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN IF NOT EXISTS clientCreatedTime bigint; +ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN IF NOT EXISTS clientLastModifiedTime bigint; -ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN clientCreatedTime bigint; -ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN clientLastModifiedTime bigint; - -ALTER TABLE PROJECT_RESOURCE DROP COLUMN IF EXISTS clientCreatedTime bigint; -ALTER TABLE PROJECT_RESOURCE DROP COLUMN IF EXISTS clientLastModifiedTime bigint; - -ALTER TABLE PROJECT_FACILITY DROP COLUMN IF EXISTS clientCreatedTime bigint; -ALTER TABLE PROJECT_FACILITY DROP COLUMN IF EXISTS clientLastModifiedTime bigint; diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java index 45b5ce8d748..dec882f630e 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java @@ -23,6 +23,16 @@ public StockReconciliationRowMapper(ObjectMapper objectMapper) { @Override public StockReconciliation mapRow(ResultSet resultSet, int i) throws SQLException { try { + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build(); return StockReconciliation.builder() .id(resultSet.getString("id")) .clientReferenceId(resultSet.getString("clientReferenceId")) @@ -39,16 +49,8 @@ public StockReconciliation mapRow(ResultSet resultSet, int i) throws SQLExceptio .isDeleted(resultSet.getBoolean("isDeleted")) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) .build(); } catch (JsonProcessingException e) { throw new SQLException(e); diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java index 92df4ab6b2d..02e4869d74d 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java @@ -21,6 +21,16 @@ public class StockRowMapper implements RowMapper { @Override public Stock mapRow(ResultSet resultSet, int i) throws SQLException { try { + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build(); return Stock.builder() .id(resultSet.getString("id")) .clientReferenceId(resultSet.getString("clientReferenceId")) @@ -37,16 +47,8 @@ public Stock mapRow(ResultSet resultSet, int i) throws SQLException { .transactingPartyType(resultSet.getString("transactingPartyType")) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) .dateOfEntry(resultSet.getLong("dateOfEntry")) From 8ca46ca1fbe7eaac826ccee9babebed00c5c728c Mon Sep 17 00:00:00 2001 From: SumelRattan-eGov Date: Fri, 26 May 2023 16:35:05 +0530 Subject: [PATCH 121/283] updated-db-migration-for-transgender --- .../main/V20230526162410__alter_individual_gender_ddl.sql | 1 + 1 file changed, 1 insertion(+) create mode 100644 health-services/individual/src/main/resources/db/migration/main/V20230526162410__alter_individual_gender_ddl.sql diff --git a/health-services/individual/src/main/resources/db/migration/main/V20230526162410__alter_individual_gender_ddl.sql b/health-services/individual/src/main/resources/db/migration/main/V20230526162410__alter_individual_gender_ddl.sql new file mode 100644 index 00000000000..f8aac1bc467 --- /dev/null +++ b/health-services/individual/src/main/resources/db/migration/main/V20230526162410__alter_individual_gender_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE INDIVIDUAL ALTER COLUMN gender TYPE character varying(20); \ No newline at end of file From b0e166fda8d32702d7ddc3e4f252b60c1468d334 Mon Sep 17 00:00:00 2001 From: "jayant.porwal" Date: Fri, 16 Jun 2023 15:59:42 +0530 Subject: [PATCH 122/283] [hlm-2915]: Added clientAuditDetails --- .../individual/repository/rowmapper/IndividualRowMapper.java | 4 ++++ ...0616153900__add_client_audit_details_in_individual_ddl.sql | 2 ++ .../java/org/egov/common/models/individual/Individual.java | 4 ++++ 3 files changed, 10 insertions(+) create mode 100644 health-services/individual/src/main/resources/db/migration/main/V20230616153900__add_client_audit_details_in_individual_ddl.sql diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java index 2176427b64f..ff42e6821d8 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java @@ -68,6 +68,10 @@ public Individual mapRow(ResultSet resultSet, int i) throws SQLException { .tenantId(tenantId) .build()) .userUuid(resultSet.getString("userUuid")) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .build(); } catch (JsonProcessingException e) { throw new RuntimeException(e); diff --git a/health-services/individual/src/main/resources/db/migration/main/V20230616153900__add_client_audit_details_in_individual_ddl.sql b/health-services/individual/src/main/resources/db/migration/main/V20230616153900__add_client_audit_details_in_individual_ddl.sql new file mode 100644 index 00000000000..b8ed09c5ec7 --- /dev/null +++ b/health-services/individual/src/main/resources/db/migration/main/V20230616153900__add_client_audit_details_in_individual_ddl.sql @@ -0,0 +1,2 @@ +ALTER TABLE INDIVIDUAL ADD COLUMN clientCreatedTime bigint; +ALTER TABLE INDIVIDUAL ADD COLUMN clientLastModifiedTime bigint; \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java index 95958898c93..3bcaf631a4b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java @@ -127,6 +127,10 @@ public class Individual { @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + @JsonIgnore private Boolean hasErrors = Boolean.FALSE; From e4edb7e886d3bdefe37ec6a4869fbca5496eda95 Mon Sep 17 00:00:00 2001 From: Shiva Burade Date: Fri, 30 Jun 2023 10:38:32 +0530 Subject: [PATCH 123/283] [hlm-2915]: Created migrations and added client audit details. --- health-services/facility/pom.xml | 2 +- .../repository/rowmapper/FacilityRowMapper.java | 4 ++++ ...0__add_client_audit_details_in_facility_ddl.sql | 2 ++ health-services/household/pom.xml | 2 +- .../rowmapper/HouseholdMemberRowMapper.java | 4 ++++ .../repository/rowmapper/HouseholdRowMapper.java | 4 ++++ ...__add_client_audit_details_in_household_ddl.sql | 5 +++++ .../org/egov/common/models/facility/Facility.java | 4 ++++ .../egov/common/models/household/Household.java | 4 ++++ .../common/models/household/HouseholdMember.java | 4 ++++ .../org/egov/common/models/product/Product.java | 4 ++++ .../egov/common/models/product/ProductVariant.java | 4 ++++ .../common/models/project/ProjectBeneficiary.java | 4 ++++ .../common/models/project/ProjectFacility.java | 4 ++++ .../common/models/project/ProjectResource.java | 4 ++++ .../egov/common/models/project/ProjectStaff.java | 4 ++++ .../java/org/egov/common/models/project/Task.java | 4 ++++ .../egov/common/models/project/TaskResource.java | 3 +++ .../java/org/egov/common/models/stock/Stock.java | 4 ++++ .../common/models/stock/StockReconciliation.java | 4 ++++ health-services/product/pom.xml | 2 +- .../repository/rowmapper/ProductRowMapper.java | 4 ++++ .../rowmapper/ProductVariantRowMapper.java | 4 ++++ ...00__add_client_audit_details_in_product_ddl.sql | 5 +++++ health-services/project/pom.xml | 2 +- .../rowmapper/ProjectBeneficiaryRowMapper.java | 4 ++++ .../rowmapper/ProjectFacilityRowMapper.java | 4 ++++ .../rowmapper/ProjectResourceRowMapper.java | 4 ++++ .../rowmapper/ProjectStaffRowMapper.java | 4 ++++ .../repository/rowmapper/ProjectTaskRowMapper.java | 4 ++++ ...00__add_client_audit_details_in_project_ddl.sql | 14 ++++++++++++++ .../rowmapper/StockReconciliationRowMapper.java | 4 ++++ .../stock/repository/rowmapper/StockRowMapper.java | 4 ++++ ...1500__add_client_audit_details_in_stock_ddl.sql | 5 +++++ 34 files changed, 134 insertions(+), 4 deletions(-) create mode 100644 health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql create mode 100644 health-services/household/src/main/resources/db/migration/main/V20230628171400__add_client_audit_details_in_household_ddl.sql create mode 100644 health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql create mode 100644 health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql create mode 100644 health-services/stock/src/main/resources/db/migration/main/V20230628181500__add_client_audit_details_in_stock_ddl.sql diff --git a/health-services/facility/pom.xml b/health-services/facility/pom.xml index 472e9ea35aa..9ec8c51c152 100644 --- a/health-services/facility/pom.xml +++ b/health-services/facility/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.1-SNAPSHOT + 1.0.6-SNAPSHOT compile diff --git a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java index eb6c2440792..b525bfb07bc 100644 --- a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java +++ b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java @@ -55,6 +55,10 @@ public Facility mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastModifiedBy")) .lastModifiedTime(resultSet.getLong("lastModifiedTime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) .build(); diff --git a/health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql b/health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql new file mode 100644 index 00000000000..e8267679900 --- /dev/null +++ b/health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql @@ -0,0 +1,2 @@ +ALTER TABLE FACILITY ADD COLUMN clientCreatedTime bigint; +ALTER TABLE FACILITY ADD COLUMN clientLastModifiedTime bigint; \ No newline at end of file diff --git a/health-services/household/pom.xml b/health-services/household/pom.xml index d6cfb901da8..d7d6858761a 100644 --- a/health-services/household/pom.xml +++ b/health-services/household/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.0-SNAPSHOT + 1.0.6-SNAPSHOT compile diff --git a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java index a306509a3c4..e99a280dd63 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java +++ b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java @@ -36,6 +36,10 @@ public HouseholdMember mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastModifiedBy")) .lastModifiedTime(resultSet.getLong("lastModifiedTime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .build(); } catch (JsonProcessingException e) { throw new SQLException(e); diff --git a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java index 6846f9bb3bd..b11547ec8c6 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java +++ b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java @@ -34,6 +34,10 @@ public Household mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastModifiedBy")) .lastModifiedTime(resultSet.getLong("lastModifiedTime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet .getString("additionalDetails"), AdditionalFields.class)) .address(Address.builder() diff --git a/health-services/household/src/main/resources/db/migration/main/V20230628171400__add_client_audit_details_in_household_ddl.sql b/health-services/household/src/main/resources/db/migration/main/V20230628171400__add_client_audit_details_in_household_ddl.sql new file mode 100644 index 00000000000..f20e702d56c --- /dev/null +++ b/health-services/household/src/main/resources/db/migration/main/V20230628171400__add_client_audit_details_in_household_ddl.sql @@ -0,0 +1,5 @@ +ALTER TABLE HOUSEHOLD ADD COLUMN clientCreatedTime bigint; +ALTER TABLE HOUSEHOLD ADD COLUMN clientLastModifiedTime bigint; + +ALTER TABLE HOUSEHOLD_MEMBER ADD COLUMN clientCreatedTime bigint; +ALTER TABLE HOUSEHOLD_MEMBER ADD COLUMN clientLastModifiedTime bigint; \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java index 338afe924b0..1b6f18b870f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java @@ -69,6 +69,10 @@ public class Facility { @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + @JsonIgnore private Boolean hasErrors = Boolean.FALSE; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java index 8cd95af33e9..56cdaeef0a4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java @@ -66,6 +66,10 @@ public class Household { @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + @JsonIgnore private Boolean hasErrors = Boolean.FALSE; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java index a63a0742100..ad103f7f9d0 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java @@ -71,6 +71,10 @@ public class HouseholdMember{ @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + @JsonIgnore private Boolean hasErrors = Boolean.FALSE; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java index 309ed399ecc..8c94529247a 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java @@ -61,5 +61,9 @@ public class Product { @JsonProperty("auditDetails") @Valid private AuditDetails auditDetails = null; + + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java index d0dec276973..bf0d8513fd9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java @@ -82,6 +82,10 @@ public class ProductVariant { private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java index 25b96b211ba..0d060052b72 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java @@ -72,6 +72,10 @@ public class ProjectBeneficiary { @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + @JsonIgnore private Boolean hasErrors = Boolean.FALSE; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java index a8081091e62..ff79f87888b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java @@ -64,4 +64,8 @@ public class ProjectFacility { @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + } \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java index eb74d3ec81c..e9c24173069 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java @@ -64,5 +64,9 @@ public class ProjectResource { @JsonProperty("auditDetails") @Valid private AuditDetails auditDetails = null; + + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java index f7c0f205af7..27f1353c28f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java @@ -75,5 +75,9 @@ public class ProjectStaff { @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java index a3689eb112c..fbbc67ffb33 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java @@ -95,6 +95,10 @@ public class Task { @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + @JsonProperty("status") private String status = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java index 986275799d2..d767a8fa3f2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java @@ -65,5 +65,8 @@ public class TaskResource { @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java index 97ac4f3e06e..102474fae63 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java @@ -102,5 +102,9 @@ public class Stock { @JsonProperty("dateOfEntry") private Long dateOfEntry = null; + + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java index 9b94d58a170..7e3ac004d0f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java @@ -84,5 +84,9 @@ public class StockReconciliation { @JsonProperty("auditDetails") @Valid private AuditDetails auditDetails = null; + + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; } diff --git a/health-services/product/pom.xml b/health-services/product/pom.xml index 12b9f8c1850..e9f818572ed 100644 --- a/health-services/product/pom.xml +++ b/health-services/product/pom.xml @@ -80,7 +80,7 @@ org.egov.common health-services-models - 1.0.0-SNAPSHOT + 1.0.6-SNAPSHOT compile diff --git a/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductRowMapper.java b/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductRowMapper.java index 24c06d1721a..83b82ed59bb 100644 --- a/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductRowMapper.java +++ b/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductRowMapper.java @@ -33,6 +33,10 @@ public Product mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) .build(); } catch (JsonProcessingException e) { diff --git a/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductVariantRowMapper.java b/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductVariantRowMapper.java index 01b1d4d1174..9c3d04d5d3e 100644 --- a/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductVariantRowMapper.java +++ b/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductVariantRowMapper.java @@ -33,6 +33,10 @@ public ProductVariant mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet .getString("additionalDetails"), AdditionalFields.class)) .build(); diff --git a/health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql b/health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql new file mode 100644 index 00000000000..a81e6114250 --- /dev/null +++ b/health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql @@ -0,0 +1,5 @@ +ALTER TABLE PRODUCT ADD COLUMN clientCreatedTime bigint; +ALTER TABLE PRODUCT ADD COLUMN clientLastModifiedTime bigint; + +ALTER TABLE PRODUCT_VARIANT ADD COLUMN clientCreatedTime bigint; +ALTER TABLE PRODUCT_VARIANT ADD COLUMN clientLastModifiedTime bigint; \ No newline at end of file diff --git a/health-services/project/pom.xml b/health-services/project/pom.xml index 1b421ad4655..49c8b5982d2 100644 --- a/health-services/project/pom.xml +++ b/health-services/project/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.0-SNAPSHOT + 1.0.6-SNAPSHOT compile diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java index 64e07258a2f..4c2092c3734 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java @@ -37,6 +37,10 @@ public ProjectBeneficiary mapRow(ResultSet resultSet, int i) throws SQLException .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .rowVersion(resultSet.getInt("rowversion")) .isDeleted(resultSet.getBoolean("isdeleted")) .build(); diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java index bd79efb6583..13886823429 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java @@ -34,6 +34,10 @@ public ProjectFacility mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .rowVersion(resultSet.getInt("rowversion")) .isDeleted(resultSet.getBoolean("isdeleted")) .build(); diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java index 34deb79333a..c3fd116c476 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java @@ -37,6 +37,10 @@ public ProjectResource mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .rowVersion(resultSet.getInt("rowversion")) .isDeleted(resultSet.getBoolean("isdeleted")) .build(); diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java index 5403b3a00cc..91b7648088a 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java @@ -36,6 +36,10 @@ public ProjectStaff mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .rowVersion(resultSet.getInt("rowversion")) .isDeleted(resultSet.getBoolean("isdeleted")) .build(); diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java index f797ac57e70..4f7587b23fa 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java @@ -42,6 +42,10 @@ public Task mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastModifiedBy")) .lastModifiedTime(resultSet.getLong("lastModifiedTime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) .address(Address.builder() diff --git a/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql new file mode 100644 index 00000000000..85b2c6ca59c --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql @@ -0,0 +1,14 @@ +ALTER TABLE PROJECT_TASK ADD COLUMN clientCreatedTime bigint; +ALTER TABLE PROJECT_TASK ADD COLUMN clientLastModifiedTime bigint; + +ALTER TABLE PROJECT_STAFF ADD COLUMN clientCreatedTime bigint; +ALTER TABLE PROJECT_STAFF ADD COLUMN clientLastModifiedTime bigint; + +ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN clientCreatedTime bigint; +ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN clientLastModifiedTime bigint; + +ALTER TABLE PROJECT_RESOURCE ADD COLUMN clientCreatedTime bigint; +ALTER TABLE PROJECT_RESOURCE ADD COLUMN clientLastModifiedTime bigint; + +ALTER TABLE PROJECT_FACILITY ADD COLUMN clientCreatedTime bigint; +ALTER TABLE PROJECT_FACILITY ADD COLUMN clientLastModifiedTime bigint; diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java index c8117e60ac6..45b5ce8d748 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java @@ -45,6 +45,10 @@ public StockReconciliation mapRow(ResultSet resultSet, int i) throws SQLExceptio .lastModifiedBy(resultSet.getString("lastModifiedBy")) .lastModifiedTime(resultSet.getLong("lastModifiedTime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .build(); } catch (JsonProcessingException e) { throw new SQLException(e); diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java index 63c20015d69..92df4ab6b2d 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java @@ -43,6 +43,10 @@ public Stock mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastModifiedBy")) .lastModifiedTime(resultSet.getLong("lastModifiedTime")) .build()) + .clientAuditDetails(AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build()) .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) .dateOfEntry(resultSet.getLong("dateOfEntry")) diff --git a/health-services/stock/src/main/resources/db/migration/main/V20230628181500__add_client_audit_details_in_stock_ddl.sql b/health-services/stock/src/main/resources/db/migration/main/V20230628181500__add_client_audit_details_in_stock_ddl.sql new file mode 100644 index 00000000000..94c9be7e697 --- /dev/null +++ b/health-services/stock/src/main/resources/db/migration/main/V20230628181500__add_client_audit_details_in_stock_ddl.sql @@ -0,0 +1,5 @@ +ALTER TABLE STOCK ADD COLUMN clientCreatedTime bigint; +ALTER TABLE STOCK ADD COLUMN clientLastModifiedTime bigint; + +ALTER TABLE STOCK_RECONCILIATION_LOG ADD COLUMN clientCreatedTime bigint; +ALTER TABLE STOCK_RECONCILIATION_LOG ADD COLUMN clientLastModifiedTime bigint; \ No newline at end of file From 81bead51dec51ef300d7f8d673ed43730d0f16ed Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 21 Jul 2023 09:38:57 +0530 Subject: [PATCH 124/283] removed changes not required for HLM-2915 --- .../repository/rowmapper/FacilityRowMapper.java | 4 ---- ...200__add_client_audit_details_in_facility_ddl.sql | 4 ++-- .../java/org/egov/common/models/product/Product.java | 3 --- .../egov/common/models/product/ProductVariant.java | 8 -------- .../egov/common/models/project/ProjectFacility.java | 4 ---- .../egov/common/models/project/ProjectResource.java | 3 --- .../org/egov/common/models/project/ProjectStaff.java | 4 ---- .../org/egov/common/models/project/TaskResource.java | 3 --- .../repository/rowmapper/ProductRowMapper.java | 4 ---- .../rowmapper/ProductVariantRowMapper.java | 4 ---- ...3000__add_client_audit_details_in_product_ddl.sql | 8 ++++---- .../rowmapper/ProjectFacilityRowMapper.java | 4 ---- .../rowmapper/ProjectResourceRowMapper.java | 4 ---- .../repository/rowmapper/ProjectStaffRowMapper.java | 4 ---- ...1500__add_client_audit_details_in_project_ddl.sql | 12 ++++++------ 15 files changed, 12 insertions(+), 61 deletions(-) diff --git a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java index b525bfb07bc..eb6c2440792 100644 --- a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java +++ b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java @@ -55,10 +55,6 @@ public Facility mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastModifiedBy")) .lastModifiedTime(resultSet.getLong("lastModifiedTime")) .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) .build(); diff --git a/health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql b/health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql index e8267679900..c607bc2e639 100644 --- a/health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql +++ b/health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql @@ -1,2 +1,2 @@ -ALTER TABLE FACILITY ADD COLUMN clientCreatedTime bigint; -ALTER TABLE FACILITY ADD COLUMN clientLastModifiedTime bigint; \ No newline at end of file +ALTER TABLE FACILITY DROP COLUMN IF EXISTS clientCreatedTime; +ALTER TABLE FACILITY DROP COLUMN IF EXISTS clientLastModifiedTime; \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java index 8c94529247a..32b9ace7565 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java @@ -62,8 +62,5 @@ public class Product { @Valid private AuditDetails auditDetails = null; - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java index bf0d8513fd9..02004d7ce43 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java @@ -76,16 +76,8 @@ public class ProductVariant { private Integer rowVersion = null; @JsonProperty("auditDetails") - @Valid - - private AuditDetails auditDetails = null; - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; - - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java index ff79f87888b..a8081091e62 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java @@ -64,8 +64,4 @@ public class ProjectFacility { @Valid private AuditDetails auditDetails = null; - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; - } \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java index e9c24173069..d3740b5facb 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java @@ -65,8 +65,5 @@ public class ProjectResource { @Valid private AuditDetails auditDetails = null; - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java index 27f1353c28f..f7c0f205af7 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java @@ -75,9 +75,5 @@ public class ProjectStaff { @Valid private AuditDetails auditDetails = null; - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java index d767a8fa3f2..986275799d2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java @@ -65,8 +65,5 @@ public class TaskResource { @Valid private AuditDetails auditDetails = null; - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; } diff --git a/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductRowMapper.java b/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductRowMapper.java index 83b82ed59bb..24c06d1721a 100644 --- a/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductRowMapper.java +++ b/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductRowMapper.java @@ -33,10 +33,6 @@ public Product mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) .build(); } catch (JsonProcessingException e) { diff --git a/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductVariantRowMapper.java b/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductVariantRowMapper.java index 9c3d04d5d3e..01b1d4d1174 100644 --- a/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductVariantRowMapper.java +++ b/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductVariantRowMapper.java @@ -33,10 +33,6 @@ public ProductVariant mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet .getString("additionalDetails"), AdditionalFields.class)) .build(); diff --git a/health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql b/health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql index a81e6114250..21559d4e997 100644 --- a/health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql +++ b/health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql @@ -1,5 +1,5 @@ -ALTER TABLE PRODUCT ADD COLUMN clientCreatedTime bigint; -ALTER TABLE PRODUCT ADD COLUMN clientLastModifiedTime bigint; +ALTER TABLE PRODUCT DROP COLUMN IF EXISTS clientCreatedTime bigint; +ALTER TABLE PRODUCT DROP COLUMN IF EXISTS clientLastModifiedTime bigint; -ALTER TABLE PRODUCT_VARIANT ADD COLUMN clientCreatedTime bigint; -ALTER TABLE PRODUCT_VARIANT ADD COLUMN clientLastModifiedTime bigint; \ No newline at end of file +ALTER TABLE PRODUCT_VARIANT DROP COLUMN IF EXISTS clientCreatedTime bigint; +ALTER TABLE PRODUCT_VARIANT DROP COLUMN IF EXISTS clientLastModifiedTime bigint; \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java index 13886823429..bd79efb6583 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java @@ -34,10 +34,6 @@ public ProjectFacility mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) .rowVersion(resultSet.getInt("rowversion")) .isDeleted(resultSet.getBoolean("isdeleted")) .build(); diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java index c3fd116c476..34deb79333a 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectResourceRowMapper.java @@ -37,10 +37,6 @@ public ProjectResource mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) .rowVersion(resultSet.getInt("rowversion")) .isDeleted(resultSet.getBoolean("isdeleted")) .build(); diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java index 91b7648088a..5403b3a00cc 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java @@ -36,10 +36,6 @@ public ProjectStaff mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("lastmodifiedby")) .lastModifiedTime(resultSet.getLong("lastmodifiedtime")) .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) .rowVersion(resultSet.getInt("rowversion")) .isDeleted(resultSet.getBoolean("isdeleted")) .build(); diff --git a/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql index 85b2c6ca59c..9434be3d910 100644 --- a/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql +++ b/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql @@ -1,14 +1,14 @@ ALTER TABLE PROJECT_TASK ADD COLUMN clientCreatedTime bigint; ALTER TABLE PROJECT_TASK ADD COLUMN clientLastModifiedTime bigint; -ALTER TABLE PROJECT_STAFF ADD COLUMN clientCreatedTime bigint; -ALTER TABLE PROJECT_STAFF ADD COLUMN clientLastModifiedTime bigint; +ALTER TABLE PROJECT_STAFF DROP COLUMN IF EXISTS clientCreatedTime bigint; +ALTER TABLE PROJECT_STAFF DROP COLUMN IF EXISTS clientLastModifiedTime bigint; ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN clientCreatedTime bigint; ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN clientLastModifiedTime bigint; -ALTER TABLE PROJECT_RESOURCE ADD COLUMN clientCreatedTime bigint; -ALTER TABLE PROJECT_RESOURCE ADD COLUMN clientLastModifiedTime bigint; +ALTER TABLE PROJECT_RESOURCE DROP COLUMN IF EXISTS clientCreatedTime bigint; +ALTER TABLE PROJECT_RESOURCE DROP COLUMN IF EXISTS clientLastModifiedTime bigint; -ALTER TABLE PROJECT_FACILITY ADD COLUMN clientCreatedTime bigint; -ALTER TABLE PROJECT_FACILITY ADD COLUMN clientLastModifiedTime bigint; +ALTER TABLE PROJECT_FACILITY DROP COLUMN IF EXISTS clientCreatedTime bigint; +ALTER TABLE PROJECT_FACILITY DROP COLUMN IF EXISTS clientLastModifiedTime bigint; From 4b0c42713a0cc549821306905db93419c5c372ae Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 31 Jul 2023 16:05:19 +0530 Subject: [PATCH 125/283] HLM-2915 : increase health-service-model version to 1.0.7 --- health-services/facility/pom.xml | 2 +- health-services/household/pom.xml | 2 +- health-services/individual/pom.xml | 2 +- health-services/libraries/health-services-models/pom.xml | 2 +- .../main/java/org/egov/common/models/facility/Facility.java | 4 ---- health-services/product/pom.xml | 2 +- health-services/project/pom.xml | 2 +- health-services/stock/pom.xml | 2 +- 8 files changed, 7 insertions(+), 11 deletions(-) diff --git a/health-services/facility/pom.xml b/health-services/facility/pom.xml index 9ec8c51c152..586f4742499 100644 --- a/health-services/facility/pom.xml +++ b/health-services/facility/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT compile diff --git a/health-services/household/pom.xml b/health-services/household/pom.xml index d7d6858761a..ee09d2ed4e3 100644 --- a/health-services/household/pom.xml +++ b/health-services/household/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT compile diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index a496ab45909..40a071672a4 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT compile diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index a7c232f4b52..202e7ac2a58 100644 --- a/health-services/libraries/health-services-models/pom.xml +++ b/health-services/libraries/health-services-models/pom.xml @@ -6,7 +6,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT 8 diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java index 1b6f18b870f..338afe924b0 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java @@ -69,10 +69,6 @@ public class Facility { @Valid private AuditDetails auditDetails = null; - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; - @JsonIgnore private Boolean hasErrors = Boolean.FALSE; diff --git a/health-services/product/pom.xml b/health-services/product/pom.xml index e9f818572ed..02edf69f5fc 100644 --- a/health-services/product/pom.xml +++ b/health-services/product/pom.xml @@ -80,7 +80,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT compile diff --git a/health-services/project/pom.xml b/health-services/project/pom.xml index 49c8b5982d2..564e18f6d1d 100644 --- a/health-services/project/pom.xml +++ b/health-services/project/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT compile diff --git a/health-services/stock/pom.xml b/health-services/stock/pom.xml index 6d7792d83c3..edaaf44102e 100644 --- a/health-services/stock/pom.xml +++ b/health-services/stock/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.7-SNAPSHOT From d928b37b189bf3a0e25ad702c61ea7b1100de961 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 23 Aug 2023 16:15:42 +0530 Subject: [PATCH 126/283] Removed Not Required migration files from HLM-2915 changes --- ...d_client_audit_details_in_facility_ddl.sql | 2 -- .../rowmapper/HouseholdMemberRowMapper.java | 22 ++++++++-------- .../rowmapper/HouseholdRowMapper.java | 22 ++++++++-------- .../rowmapper/IndividualRowMapper.java | 25 +++++++++++-------- ...dd_client_audit_details_in_product_ddl.sql | 5 ---- .../ProjectBeneficiaryRowMapper.java | 22 ++++++++-------- .../rowmapper/ProjectTaskRowMapper.java | 22 ++++++++-------- ...dd_client_audit_details_in_project_ddl.sql | 16 +++--------- .../StockReconciliationRowMapper.java | 22 ++++++++-------- .../repository/rowmapper/StockRowMapper.java | 22 ++++++++-------- 10 files changed, 90 insertions(+), 90 deletions(-) delete mode 100644 health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql delete mode 100644 health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql diff --git a/health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql b/health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql deleted file mode 100644 index c607bc2e639..00000000000 --- a/health-services/facility/src/main/resources/db/migration/main/V20230628144200__add_client_audit_details_in_facility_ddl.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE FACILITY DROP COLUMN IF EXISTS clientCreatedTime; -ALTER TABLE FACILITY DROP COLUMN IF EXISTS clientLastModifiedTime; \ No newline at end of file diff --git a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java index e99a280dd63..e7d9e0c668b 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java +++ b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java @@ -18,6 +18,16 @@ public class HouseholdMemberRowMapper implements RowMapper { @Override public HouseholdMember mapRow(ResultSet resultSet, int i) throws SQLException { try { + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build(); return HouseholdMember.builder() .id(resultSet.getString("id")) .householdId(resultSet.getString("householdId")) @@ -30,16 +40,8 @@ public HouseholdMember mapRow(ResultSet resultSet, int i) throws SQLException { .getString("additionalDetails"), AdditionalFields.class)) .isDeleted(resultSet.getBoolean("isDeleted")) .rowVersion(resultSet.getInt("rowVersion")) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) .build(); } catch (JsonProcessingException e) { throw new SQLException(e); diff --git a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java index b11547ec8c6..dd72b6d8b53 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java +++ b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java @@ -21,6 +21,16 @@ public class HouseholdRowMapper implements RowMapper { @Override public Household mapRow(ResultSet resultSet, int i) throws SQLException { try { + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build(); Household household = Household.builder() .id(resultSet.getString("id")) .rowVersion(resultSet.getInt("rowVersion")) @@ -28,16 +38,8 @@ public Household mapRow(ResultSet resultSet, int i) throws SQLException { .tenantId(resultSet.getString("tenantId")) .memberCount(resultSet.getInt("numberOfMembers")) .clientReferenceId(resultSet.getString("clientReferenceId")) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet .getString("additionalDetails"), AdditionalFields.class)) .address(Address.builder() diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java index ff42e6821d8..487b96d5470 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java @@ -26,6 +26,16 @@ public class IndividualRowMapper implements RowMapper { public Individual mapRow(ResultSet resultSet, int i) throws SQLException { try { String tenantId = resultSet.getString("tenantId"); + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build(); return Individual.builder().id(resultSet.getString("id")) .individualId(resultSet.getString("individualid")) .userId(resultSet.getString("userId")) @@ -47,13 +57,9 @@ public Individual mapRow(ResultSet resultSet, int i) throws SQLException { .photo(resultSet.getString("photo")) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet.getString("additionalDetails"), - AdditionalFields.class)) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) + AdditionalFields.class) + ) + .auditDetails(auditDetails) .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) .isSystemUser(resultSet.getBoolean("isSystemUser")) @@ -68,10 +74,7 @@ public Individual mapRow(ResultSet resultSet, int i) throws SQLException { .tenantId(tenantId) .build()) .userUuid(resultSet.getString("userUuid")) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) + .clientAuditDetails(clientAuditDetails) .build(); } catch (JsonProcessingException e) { throw new RuntimeException(e); diff --git a/health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql b/health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql deleted file mode 100644 index 21559d4e997..00000000000 --- a/health-services/product/src/main/resources/db/migration/main/V20230628173000__add_client_audit_details_in_product_ddl.sql +++ /dev/null @@ -1,5 +0,0 @@ -ALTER TABLE PRODUCT DROP COLUMN IF EXISTS clientCreatedTime bigint; -ALTER TABLE PRODUCT DROP COLUMN IF EXISTS clientLastModifiedTime bigint; - -ALTER TABLE PRODUCT_VARIANT DROP COLUMN IF EXISTS clientCreatedTime bigint; -ALTER TABLE PRODUCT_VARIANT DROP COLUMN IF EXISTS clientLastModifiedTime bigint; \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java index 4c2092c3734..633378ebbf2 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java @@ -19,6 +19,16 @@ public class ProjectBeneficiaryRowMapper implements RowMapper { @Override public Task mapRow(ResultSet resultSet, int i) throws SQLException { try { + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build(); Task task = Task.builder() .id(resultSet.getString("id")) .rowVersion(resultSet.getInt("rowVersion")) @@ -36,16 +46,8 @@ public Task mapRow(ResultSet resultSet, int i) throws SQLException { .actualStartDate(resultSet.getLong("actualStartDate")) .actualEndDate(resultSet.getLong("actualEndDate")) .status(resultSet.getString("status")) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) .address(Address.builder() diff --git a/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql index 9434be3d910..d2b0da3ef3e 100644 --- a/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql +++ b/health-services/project/src/main/resources/db/migration/main/V20230628191500__add_client_audit_details_in_project_ddl.sql @@ -1,14 +1,6 @@ -ALTER TABLE PROJECT_TASK ADD COLUMN clientCreatedTime bigint; -ALTER TABLE PROJECT_TASK ADD COLUMN clientLastModifiedTime bigint; +ALTER TABLE PROJECT_TASK ADD COLUMN IF NOT EXISTS clientCreatedTime bigint; +ALTER TABLE PROJECT_TASK ADD COLUMN IF NOT EXISTS clientLastModifiedTime bigint; -ALTER TABLE PROJECT_STAFF DROP COLUMN IF EXISTS clientCreatedTime bigint; -ALTER TABLE PROJECT_STAFF DROP COLUMN IF EXISTS clientLastModifiedTime bigint; +ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN IF NOT EXISTS clientCreatedTime bigint; +ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN IF NOT EXISTS clientLastModifiedTime bigint; -ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN clientCreatedTime bigint; -ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN clientLastModifiedTime bigint; - -ALTER TABLE PROJECT_RESOURCE DROP COLUMN IF EXISTS clientCreatedTime bigint; -ALTER TABLE PROJECT_RESOURCE DROP COLUMN IF EXISTS clientLastModifiedTime bigint; - -ALTER TABLE PROJECT_FACILITY DROP COLUMN IF EXISTS clientCreatedTime bigint; -ALTER TABLE PROJECT_FACILITY DROP COLUMN IF EXISTS clientLastModifiedTime bigint; diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java index 45b5ce8d748..dec882f630e 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java @@ -23,6 +23,16 @@ public StockReconciliationRowMapper(ObjectMapper objectMapper) { @Override public StockReconciliation mapRow(ResultSet resultSet, int i) throws SQLException { try { + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build(); return StockReconciliation.builder() .id(resultSet.getString("id")) .clientReferenceId(resultSet.getString("clientReferenceId")) @@ -39,16 +49,8 @@ public StockReconciliation mapRow(ResultSet resultSet, int i) throws SQLExceptio .isDeleted(resultSet.getBoolean("isDeleted")) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) .build(); } catch (JsonProcessingException e) { throw new SQLException(e); diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java index 92df4ab6b2d..02e4869d74d 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java @@ -21,6 +21,16 @@ public class StockRowMapper implements RowMapper { @Override public Stock mapRow(ResultSet resultSet, int i) throws SQLException { try { + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build(); return Stock.builder() .id(resultSet.getString("id")) .clientReferenceId(resultSet.getString("clientReferenceId")) @@ -37,16 +47,8 @@ public Stock mapRow(ResultSet resultSet, int i) throws SQLException { .transactingPartyType(resultSet.getString("transactingPartyType")) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) .dateOfEntry(resultSet.getLong("dateOfEntry")) From 20a94f0e9cf974ca066d0f03b31620d9df42007e Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 30 Aug 2023 14:01:34 +0530 Subject: [PATCH 127/283] HLM-2915: Added clientCreatedBy and clientLastModifiedBy --- .../repository/rowmapper/HouseholdMemberRowMapper.java | 2 ++ .../household/repository/rowmapper/HouseholdRowMapper.java | 2 ++ ...0830122000__add_client_audit_details_in_household_ddl.sql | 5 +++++ .../individual/repository/rowmapper/IndividualRowMapper.java | 2 ++ ...830122000__add_client_audit_details_in_individual_ddl.sql | 2 ++ .../repository/rowmapper/ProjectBeneficiaryRowMapper.java | 2 ++ .../project/repository/rowmapper/ProjectTaskRowMapper.java | 2 ++ ...230830122000__add_client_audit_details_in_project_ddl.sql | 5 +++++ .../repository/rowmapper/StockReconciliationRowMapper.java | 2 ++ .../org/egov/stock/repository/rowmapper/StockRowMapper.java | 2 ++ ...20230830122000__add_client_audit_details_in_stock_ddl.sql | 5 +++++ 11 files changed, 31 insertions(+) create mode 100644 health-services/household/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_household_ddl.sql create mode 100644 health-services/individual/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_individual_ddl.sql create mode 100644 health-services/project/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_project_ddl.sql create mode 100644 health-services/stock/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_stock_ddl.sql diff --git a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java index e7d9e0c668b..7601fa0b624 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java +++ b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java @@ -26,7 +26,9 @@ public HouseholdMember mapRow(ResultSet resultSet, int i) throws SQLException { .build(); AuditDetails clientAuditDetails = AuditDetails.builder() .createdTime(resultSet.getLong("clientCreatedTime")) + .createdBy(resultSet.getString("clientCreatedBy")) .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) .build(); return HouseholdMember.builder() .id(resultSet.getString("id")) diff --git a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java index dd72b6d8b53..5669c06734b 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java +++ b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java @@ -29,7 +29,9 @@ public Household mapRow(ResultSet resultSet, int i) throws SQLException { .build(); AuditDetails clientAuditDetails = AuditDetails.builder() .createdTime(resultSet.getLong("clientCreatedTime")) + .createdBy(resultSet.getString("clientCreatedBy")) .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) .build(); Household household = Household.builder() .id(resultSet.getString("id")) diff --git a/health-services/household/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_household_ddl.sql b/health-services/household/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_household_ddl.sql new file mode 100644 index 00000000000..f2fe18e299f --- /dev/null +++ b/health-services/household/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_household_ddl.sql @@ -0,0 +1,5 @@ +ALTER TABLE HOUSEHOLD ADD COLUMN IF NOT EXISTS clientCreatedBy character varying(64); +ALTER TABLE HOUSEHOLD ADD COLUMN IF NOT EXISTS clientLastModifiedBy character varying(64); + +ALTER TABLE HOUSEHOLD_MEMBER ADD COLUMN IF NOT EXISTS clientCreatedBy character varying(64); +ALTER TABLE HOUSEHOLD_MEMBER ADD COLUMN IF NOT EXISTS clientLastModifiedBy character varying(64); \ No newline at end of file diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java index 487b96d5470..a7f0fbbb279 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java @@ -34,7 +34,9 @@ public Individual mapRow(ResultSet resultSet, int i) throws SQLException { .build(); AuditDetails clientAuditDetails = AuditDetails.builder() .createdTime(resultSet.getLong("clientCreatedTime")) + .createdBy(resultSet.getString("clientCreatedBy")) .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) .build(); return Individual.builder().id(resultSet.getString("id")) .individualId(resultSet.getString("individualid")) diff --git a/health-services/individual/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_individual_ddl.sql b/health-services/individual/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_individual_ddl.sql new file mode 100644 index 00000000000..b4c0706bf30 --- /dev/null +++ b/health-services/individual/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_individual_ddl.sql @@ -0,0 +1,2 @@ +ALTER TABLE INDIVIDUAL ADD COLUMN IF NOT EXISTS clientCreatedBy character varying(64); +ALTER TABLE INDIVIDUAL ADD COLUMN IF NOT EXISTS clientLastModifiedBy character varying(64); diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java index 633378ebbf2..f596a1eb68a 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java @@ -27,7 +27,9 @@ public ProjectBeneficiary mapRow(ResultSet resultSet, int i) throws SQLException .build(); AuditDetails clientAuditDetails = AuditDetails.builder() .createdTime(resultSet.getLong("clientCreatedTime")) + .createdBy(resultSet.getString("clientCreatedBy")) .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) .build(); return ProjectBeneficiary.builder() .id(resultSet.getString("id")) diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java index a6098b9c445..c9893dbb45e 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java @@ -30,7 +30,9 @@ public Task mapRow(ResultSet resultSet, int i) throws SQLException { .build(); AuditDetails clientAuditDetails = AuditDetails.builder() .createdTime(resultSet.getLong("clientCreatedTime")) + .createdBy(resultSet.getString("clientCreatedBy")) .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) .build(); Task task = Task.builder() .id(resultSet.getString("id")) diff --git a/health-services/project/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_project_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_project_ddl.sql new file mode 100644 index 00000000000..bab9c9abdab --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_project_ddl.sql @@ -0,0 +1,5 @@ +ALTER TABLE PROJECT_TASK ADD COLUMN IF NOT EXISTS clientCreatedBy character varying(64); +ALTER TABLE PROJECT_TASK ADD COLUMN IF NOT EXISTS clientLastModifiedBy character varying(64); + +ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN IF NOT EXISTS clientCreatedBy character varying(64); +ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN IF NOT EXISTS clientLastModifiedBy character varying(64); diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java index dec882f630e..831c8f4e331 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java @@ -31,7 +31,9 @@ public StockReconciliation mapRow(ResultSet resultSet, int i) throws SQLExceptio .build(); AuditDetails clientAuditDetails = AuditDetails.builder() .createdTime(resultSet.getLong("clientCreatedTime")) + .createdBy(resultSet.getString("clientCreatedBy")) .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) .build(); return StockReconciliation.builder() .id(resultSet.getString("id")) diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java index 02e4869d74d..94b430ae45b 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java @@ -29,7 +29,9 @@ public Stock mapRow(ResultSet resultSet, int i) throws SQLException { .build(); AuditDetails clientAuditDetails = AuditDetails.builder() .createdTime(resultSet.getLong("clientCreatedTime")) + .createdBy(resultSet.getString("clientCreatedBy")) .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) .build(); return Stock.builder() .id(resultSet.getString("id")) diff --git a/health-services/stock/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_stock_ddl.sql b/health-services/stock/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_stock_ddl.sql new file mode 100644 index 00000000000..97b8cdd0688 --- /dev/null +++ b/health-services/stock/src/main/resources/db/migration/main/V20230830122000__add_client_audit_details_in_stock_ddl.sql @@ -0,0 +1,5 @@ +ALTER TABLE STOCK ADD COLUMN IF NOT EXISTS clientCreatedBy character varying(64); +ALTER TABLE STOCK ADD COLUMN IF NOT EXISTS clientLastModifiedBy character varying(64); + +ALTER TABLE STOCK_RECONCILIATION_LOG ADD COLUMN IF NOT EXISTS clientCreatedBy character varying(64); +ALTER TABLE STOCK_RECONCILIATION_LOG ADD COLUMN IF NOT EXISTS clientLastModifiedBy character varying(64); From a34d620626538f4d22a58d6d41c3512b30439564 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 1 Sep 2023 17:45:34 +0530 Subject: [PATCH 128/283] HLM-3069 : add mandatory to clientreferenceId --- .../AdProjectTaskIdValidator.java | 55 +++++++++++++------ ...V20230901150100__adverse_event_ref_ddl.sql | 2 + 2 files changed, 40 insertions(+), 17 deletions(-) create mode 100644 health-services/project/src/main/resources/db/migration/main/V20230901150100__adverse_event_ref_ddl.sql diff --git a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdProjectTaskIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdProjectTaskIdValidator.java index b4886e483b2..fbb8632ce25 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdProjectTaskIdValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdProjectTaskIdValidator.java @@ -1,9 +1,12 @@ package org.egov.project.validator.adverseevent; import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.models.Error; import org.egov.common.models.project.AdverseEvent; import org.egov.common.models.project.AdverseEventBulkRequest; +import org.egov.common.models.project.Task; +import org.egov.common.models.project.TaskSearch; import org.egov.common.validator.Validator; import org.egov.project.repository.ProjectTaskRepository; import org.springframework.beans.factory.annotation.Autowired; @@ -12,9 +15,12 @@ import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.stream.Collectors; import static org.egov.common.utils.CommonUtils.*; @@ -38,23 +44,38 @@ public Map> validate(AdverseEventBulkRequest request) log.info("validating project task id"); Map> errorDetailsMap = new HashMap<>(); List entities = request.getAdverseEvents(); - Class objClass = getObjClass(entities); - Method idMethod = getMethod("getTaskId", objClass); - Map eMap = getIdToObjMap(entities - .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); - if (!eMap.isEmpty()) { - List entityIds = new ArrayList<>(eMap.keySet()); - List existingProjectTaskIds = projectTaskRepository.findById(entityIds, getIdFieldName(idMethod),Boolean.FALSE) - .stream().map(t -> t.getId()) - .collect(Collectors.toList()); - List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> - !existingProjectTaskIds.contains(entity.getTaskId())) - .collect(Collectors.toList()); - invalidEntities.forEach(adverseEvent -> { - Error error = getErrorForNonExistentEntity(); - populateErrorDetails(adverseEvent, error, errorDetailsMap); - }); - } + Map> tenantIdTaskIdMap = entities.stream().collect(Collectors.toMap(ad -> ad.getTenantId(), ad -> Arrays.asList(ad.getTaskId()), (e, d) -> { e.addAll(d); return e;})); + Map> tenantIdTaskReferenceIdMap = entities.stream().collect(Collectors.toMap(ad -> ad.getTenantId(), ad -> Arrays.asList(ad.getTaskClientReferenceId()), (e, d) -> { e.addAll(d); return e;})); + List tenantIds = new ArrayList<>(tenantIdTaskIdMap.keySet()); + tenantIds.forEach(tenantId -> { + List taskIdList = tenantIdTaskIdMap.get(tenantId); + List taskReferenceIdList = tenantIdTaskReferenceIdMap.get(tenantId); + if (!taskIdList.isEmpty() || !taskReferenceIdList.isEmpty()) { + List existingTasks; + try { + taskIdList = taskIdList.stream().filter(Objects::nonNull).collect(Collectors.toList()); + taskReferenceIdList = taskReferenceIdList.stream().filter(Objects::nonNull).collect(Collectors.toList()); + TaskSearch taskSearch = TaskSearch.builder() + .id(taskIdList.isEmpty() ? null : taskIdList) + .clientReferenceId(taskReferenceIdList.isEmpty() ? null : taskReferenceIdList).build(); + existingTasks = projectTaskRepository.find( + taskSearch, + taskReferenceIdList.size(), 0, tenantId,null, Boolean.TRUE + ); + } catch (QueryBuilderException e) { + existingTasks = Collections.emptyList(); + } + List existingProjectTaskIds = existingTasks.stream().map(t -> t.getId()).collect(Collectors.toList()); + List existingProjectReferenceTaskIds = existingTasks.stream().map(t -> t.getClientReferenceId()).collect(Collectors.toList()); + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + !existingProjectTaskIds.contains(entity.getTaskId()) && !existingProjectReferenceTaskIds.contains(entity.getTaskClientReferenceId()) ) + .collect(Collectors.toList()); + invalidEntities.forEach(adverseEvent -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(adverseEvent, error, errorDetailsMap); + }); + } + }); return errorDetailsMap; } diff --git a/health-services/project/src/main/resources/db/migration/main/V20230901150100__adverse_event_ref_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20230901150100__adverse_event_ref_ddl.sql new file mode 100644 index 00000000000..92680165b50 --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20230901150100__adverse_event_ref_ddl.sql @@ -0,0 +1,2 @@ +ALTER TABLE ADVERSE_EVENT ALTER COLUMN clientReferenceId SET NOT NULL; +ALTER TABLE ADVERSE_EVENT ALTER COLUMN taskClientReferenceId SET NOT NULL; \ No newline at end of file From b6a7073ccf1938e1966ff9a2600959e47de2bab3 Mon Sep 17 00:00:00 2001 From: Vishal Date: Fri, 1 Sep 2023 22:09:46 +0530 Subject: [PATCH 129/283] fixing address fields position in row mapper --- .../facility/repository/rowmapper/FacilityRowMapper.java | 4 ++-- .../household/repository/rowmapper/HouseholdRowMapper.java | 6 +++--- .../project/repository/rowmapper/ProjectTaskRowMapper.java | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java index eb6c2440792..d88f0674f8d 100644 --- a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java +++ b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java @@ -31,8 +31,8 @@ public Facility mapRow(ResultSet resultSet, int i) throws SQLException { .usage(resultSet.getString("usage")) .storageCapacity(resultSet.getInt("storageCapacity")) .address(Address.builder() - .id(resultSet.getString(15)) - .tenantId(resultSet.getString(16)) + .id(resultSet.getString(16)) + .tenantId(resultSet.getString(17)) .doorNo(resultSet.getString("doorNo")) .latitude(resultSet.getDouble("latitude")) .longitude(resultSet.getDouble("longitude")) diff --git a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java index 5669c06734b..a213a5f1a29 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java +++ b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java @@ -45,9 +45,9 @@ public Household mapRow(ResultSet resultSet, int i) throws SQLException { .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet .getString("additionalDetails"), AdditionalFields.class)) .address(Address.builder() - .id(resultSet.getString(13)) - .clientReferenceId(resultSet.getString(28)) - .tenantId(resultSet.getString(14)) + .id(resultSet.getString(17)) + .clientReferenceId(resultSet.getString(32)) + .tenantId(resultSet.getString(18)) .doorNo(resultSet.getString("doorNo")) .latitude(resultSet.getDouble("latitude")) .longitude(resultSet.getDouble("longitude")) diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java index c9893dbb45e..7a6cc85fce0 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java @@ -53,9 +53,9 @@ public Task mapRow(ResultSet resultSet, int i) throws SQLException { .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) .address(Address.builder() - .id(resultSet.getString(20)) - .tenantId(resultSet.getString(21)) - .clientReferenceId(resultSet.getString(35)) + .id(resultSet.getString(24)) + .tenantId(resultSet.getString(25)) + .clientReferenceId(resultSet.getString(39)) .doorNo(resultSet.getString("doorNo")) .latitude(resultSet.getDouble("latitude")) .longitude(resultSet.getDouble("longitude")) From 6b07134088986df6369471e43f69a4665d3b4ab5 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Sat, 2 Sep 2023 15:31:38 +0530 Subject: [PATCH 130/283] Update FacilityRowMapper.java --- .../egov/facility/repository/rowmapper/FacilityRowMapper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java index d88f0674f8d..053bd6dc376 100644 --- a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java +++ b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java @@ -31,8 +31,8 @@ public Facility mapRow(ResultSet resultSet, int i) throws SQLException { .usage(resultSet.getString("usage")) .storageCapacity(resultSet.getInt("storageCapacity")) .address(Address.builder() - .id(resultSet.getString(16)) - .tenantId(resultSet.getString(17)) + .id(resultSet.getString("a.id")) + .tenantId(resultSet.getString("a.tenantid")) .doorNo(resultSet.getString("doorNo")) .latitude(resultSet.getDouble("latitude")) .longitude(resultSet.getDouble("longitude")) From b3f7069d45c7402d2a5104e6cd1eb5d37003cfca Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Sat, 2 Sep 2023 15:32:32 +0530 Subject: [PATCH 131/283] Update HouseholdRowMapper.java --- .../household/repository/rowmapper/HouseholdRowMapper.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java index a213a5f1a29..363a2e140ea 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java +++ b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java @@ -45,9 +45,9 @@ public Household mapRow(ResultSet resultSet, int i) throws SQLException { .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet .getString("additionalDetails"), AdditionalFields.class)) .address(Address.builder() - .id(resultSet.getString(17)) - .clientReferenceId(resultSet.getString(32)) - .tenantId(resultSet.getString(18)) + .id(resultSet.getString("a.id")) + .clientReferenceId(resultSet.getString("a.clientreferenceid")) + .tenantId(resultSet.getString("a.tenantid")) .doorNo(resultSet.getString("doorNo")) .latitude(resultSet.getDouble("latitude")) .longitude(resultSet.getDouble("longitude")) From aaa7e5710c1690536301c9978737113a0007791f Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Sat, 2 Sep 2023 15:33:15 +0530 Subject: [PATCH 132/283] Update ProjectTaskRowMapper.java --- .../repository/rowmapper/ProjectTaskRowMapper.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java index 7a6cc85fce0..2a06d35ed35 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java @@ -53,9 +53,9 @@ public Task mapRow(ResultSet resultSet, int i) throws SQLException { .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) .address(Address.builder() - .id(resultSet.getString(24)) - .tenantId(resultSet.getString(25)) - .clientReferenceId(resultSet.getString(39)) + .id(resultSet.getString("a.id")) + .tenantId(resultSet.getString("a.tenantid")) + .clientReferenceId(resultSet.getString("a.clientreferenceid")) .doorNo(resultSet.getString("doorNo")) .latitude(resultSet.getDouble("latitude")) .longitude(resultSet.getDouble("longitude")) @@ -80,4 +80,4 @@ public Task mapRow(ResultSet resultSet, int i) throws SQLException { throw new SQLException(e); } } -} \ No newline at end of file +} From 00692e60715fd1ab87efb2e5742028b5422da440 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Sat, 2 Sep 2023 16:03:38 +0530 Subject: [PATCH 133/283] Update FacilityRepository.java --- .../org/egov/facility/repository/FacilityRepository.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/health-services/facility/src/main/java/org/egov/facility/repository/FacilityRepository.java b/health-services/facility/src/main/java/org/egov/facility/repository/FacilityRepository.java index 9555237132a..9c67b1e6be2 100644 --- a/health-services/facility/src/main/java/org/egov/facility/repository/FacilityRepository.java +++ b/health-services/facility/src/main/java/org/egov/facility/repository/FacilityRepository.java @@ -48,9 +48,9 @@ public List findById(List ids, String columnName, Boolean incl } } - String query = String.format("SELECT * FROM facility f LEFT JOIN address a ON f.addressid = a.id WHERE f.%s IN (:ids) AND isDeleted = false", columnName); + String query = String.format("SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM facility f LEFT JOIN address a ON f.addressid = a.id WHERE f.%s IN (:ids) AND isDeleted = false", columnName); if (null != includeDeleted && includeDeleted) { - query = String.format("SELECT * FROM facility f LEFT JOIN address a ON f.addressid = a.id WHERE f.%s IN (:ids)", columnName); + query = String.format("SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM facility f LEFT JOIN address a ON f.addressid = a.id WHERE f.%s IN (:ids)", columnName); } Map paramMap = new HashMap(); paramMap.put("ids", ids); @@ -61,7 +61,7 @@ public List findById(List ids, String columnName, Boolean incl } public List find(FacilitySearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { - String query = "SELECT * FROM facility f LEFT JOIN address a ON f.addressid = a.id"; + String query = "SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM facility f LEFT JOIN address a ON f.addressid = a.id"; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); From 6fcd2af833b292efff401715e55e6d4b24f54f43 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Sat, 2 Sep 2023 16:06:37 +0530 Subject: [PATCH 134/283] Update FacilityRowMapper.java --- .../egov/facility/repository/rowmapper/FacilityRowMapper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java index 053bd6dc376..4ab51ba5ed3 100644 --- a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java +++ b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java @@ -31,8 +31,8 @@ public Facility mapRow(ResultSet resultSet, int i) throws SQLException { .usage(resultSet.getString("usage")) .storageCapacity(resultSet.getInt("storageCapacity")) .address(Address.builder() - .id(resultSet.getString("a.id")) - .tenantId(resultSet.getString("a.tenantid")) + .id(resultSet.getString("aid")) + .tenantId(resultSet.getString("atenantid")) .doorNo(resultSet.getString("doorNo")) .latitude(resultSet.getDouble("latitude")) .longitude(resultSet.getDouble("longitude")) From 04113c5a1370d7775d2a811354401e45a72cc538 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Sat, 2 Sep 2023 16:07:22 +0530 Subject: [PATCH 135/283] Update HouseholdRowMapper.java --- .../household/repository/rowmapper/HouseholdRowMapper.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java index 363a2e140ea..fe90675a387 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java +++ b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java @@ -45,9 +45,9 @@ public Household mapRow(ResultSet resultSet, int i) throws SQLException { .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper.readValue(resultSet .getString("additionalDetails"), AdditionalFields.class)) .address(Address.builder() - .id(resultSet.getString("a.id")) - .clientReferenceId(resultSet.getString("a.clientreferenceid")) - .tenantId(resultSet.getString("a.tenantid")) + .id(resultSet.getString("aid")) + .clientReferenceId(resultSet.getString("aclientreferenceid")) + .tenantId(resultSet.getString("atenantid")) .doorNo(resultSet.getString("doorNo")) .latitude(resultSet.getDouble("latitude")) .longitude(resultSet.getDouble("longitude")) From faefa310141a23952ec59eb53f5861d083f47ff1 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Sat, 2 Sep 2023 16:08:20 +0530 Subject: [PATCH 136/283] Update HouseholdRepository.java --- .../org/egov/household/repository/HouseholdRepository.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java index 6b98b89cb5b..6190d4e7d7c 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java +++ b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java @@ -52,9 +52,9 @@ public List findById(List ids, String columnName, Boolean inc } } - String query = String.format("SELECT * FROM household h LEFT JOIN address a ON h.addressid = a.id WHERE h.%s IN (:ids) AND isDeleted = false", columnName); + String query = String.format("SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM household h LEFT JOIN address a ON h.addressid = a.id WHERE h.%s IN (:ids) AND isDeleted = false", columnName); if (null != includeDeleted && includeDeleted) { - query = String.format("SELECT * FROM household h LEFT JOIN address a ON h.addressid = a.id WHERE h.%s IN (:ids)", columnName); + query = String.format("SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM household h LEFT JOIN address a ON h.addressid = a.id WHERE h.%s IN (:ids)", columnName); } Map paramMap = new HashMap(); paramMap.put("ids", ids); @@ -65,7 +65,7 @@ public List findById(List ids, String columnName, Boolean inc } public List find(HouseholdSearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { - String query = "SELECT * FROM household h LEFT JOIN address a ON h.addressid = a.id"; + String query = "SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM household h LEFT JOIN address a ON h.addressid = a.id"; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); From 0f078af695cf849f0dc0d9a9cc11db6b5da4d475 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Sat, 2 Sep 2023 16:09:55 +0530 Subject: [PATCH 137/283] Update ProjectTaskRowMapper.java --- .../project/repository/rowmapper/ProjectTaskRowMapper.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java index 2a06d35ed35..8d064981b7c 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java @@ -53,9 +53,9 @@ public Task mapRow(ResultSet resultSet, int i) throws SQLException { .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) .address(Address.builder() - .id(resultSet.getString("a.id")) - .tenantId(resultSet.getString("a.tenantid")) - .clientReferenceId(resultSet.getString("a.clientreferenceid")) + .id(resultSet.getString("aid")) + .tenantId(resultSet.getString("atenantid")) + .clientReferenceId(resultSet.getString("aclientreferenceid")) .doorNo(resultSet.getString("doorNo")) .latitude(resultSet.getDouble("latitude")) .longitude(resultSet.getDouble("longitude")) From cfc45c54e48abe434bc6a2627fed6e5c2d64b04e Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Sat, 2 Sep 2023 16:11:03 +0530 Subject: [PATCH 138/283] Update ProjectTaskRepository.java --- .../org/egov/project/repository/ProjectTaskRepository.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java b/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java index 0da3ea81713..ca8e598b50e 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java +++ b/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java @@ -45,7 +45,7 @@ protected ProjectTaskRepository(Producer producer, NamedParameterJdbcTemplate na public List find(TaskSearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { - String query = "SELECT * FROM project_task pt LEFT JOIN address a ON pt.addressid = a.id"; + String query = "SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM project_task pt LEFT JOIN address a ON pt.addressid = a.id"; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); @@ -111,9 +111,9 @@ public List findById(List ids, String columnName, Boolean includeD } } - String query = String.format("SELECT * FROM project_task pt LEFT JOIN address a ON pt.addressid = a.id WHERE pt.%s IN (:ids) AND isDeleted = false", columnName); + String query = String.format("SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM project_task pt LEFT JOIN address a ON pt.addressid = a.id WHERE pt.%s IN (:ids) AND isDeleted = false", columnName); if (null != includeDeleted && includeDeleted) { - query = String.format("SELECT * FROM project_task pt LEFT JOIN address a ON pt.addressid = a.id WHERE pt.%s IN (:ids)", columnName); + query = String.format("SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM project_task pt LEFT JOIN address a ON pt.addressid = a.id WHERE pt.%s IN (:ids)", columnName); } Map paramMap = new HashMap<>(); paramMap.put("ids", ids); From d4e07476c204d2fc8ceaa5935ee8fe52e1f5e362 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 6 Sep 2023 15:06:07 +0530 Subject: [PATCH 139/283] HLM-3069 : Changes as per code review comments : moved adverse events models inside project.adverseevent package, removed reAttempt from adverseEvent, added custom exceptions --- docs/health-api-specs/contracts/project.yml | 4 --- .../org/egov/common/models/project/Task.java | 11 ------ .../{ => adverseevent}/AdverseEvent.java | 8 ++--- .../AdverseEventBulkRequest.java | 2 +- .../AdverseEventBulkResponse.java | 2 +- .../AdverseEventRequest.java | 3 +- .../AdverseEventResponse.java | 3 +- .../AdverseEventSearch.java | 2 +- .../AdverseEventSearchRequest.java | 2 +- .../consumer/AdverseEventConsumer.java | 34 ++++++++++--------- .../repository/AdverseEventRepository.java | 4 +-- .../repository/ProjectTaskRepository.java | 11 ------ .../rowmapper/AdverseEventRowMapper.java | 4 +-- .../project/service/AdverseEventService.java | 15 ++++---- .../AdverseEventEnrichmentService.java | 9 ++--- .../adverseevent/AdIsDeletedValidator.java | 4 +-- .../AdNonExistentEntityValidator.java | 5 ++- .../adverseevent/AdNullIdValidator.java | 4 +-- .../AdProjectTaskIdValidator.java | 5 ++- .../adverseevent/AdUniqueEntityValidator.java | 4 +-- .../AdverseEventApiController.java | 18 ++++++---- ...0906144900__adverse_event_col_drop_ddl.sql | 1 + .../main/resources/project-task-persister.yml | 6 ++-- .../AdverseEventRequestTestBuilder.java | 2 +- .../helper/AdverseEventTestBuilder.java | 5 +-- .../AdverseEventApiControllerTest.java | 7 +++- 26 files changed, 75 insertions(+), 100 deletions(-) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/{ => adverseevent}/AdverseEvent.java (89%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/{ => adverseevent}/AdverseEventBulkRequest.java (94%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/{ => adverseevent}/AdverseEventBulkResponse.java (94%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/{ => adverseevent}/AdverseEventRequest.java (85%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/{ => adverseevent}/AdverseEventResponse.java (85%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/{ => adverseevent}/AdverseEventSearch.java (93%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/{ => adverseevent}/AdverseEventSearchRequest.java (92%) create mode 100644 health-services/project/src/main/resources/db/migration/main/V20230906144900__adverse_event_col_drop_ddl.sql diff --git a/docs/health-api-specs/contracts/project.yml b/docs/health-api-specs/contracts/project.yml index 360bf6f8a3f..aa95a723cb1 100644 --- a/docs/health-api-specs/contracts/project.yml +++ b/docs/health-api-specs/contracts/project.yml @@ -2416,10 +2416,6 @@ definitions: type: array items: type: string - reAttempts: - type: integer - format: int64 - description: Re-Attempts isDeleted: $ref: '#/definitions/isDeleted' rowVersion: diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java index 9067ac54285..a3689eb112c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java @@ -101,20 +101,9 @@ public class Task { @JsonIgnore private Boolean hasErrors = Boolean.FALSE; - @JsonProperty("adverseEvents") - private List adverseEvents = new ArrayList<>(); - public Task addResourcesItem(TaskResource resourcesItem) { this.resources.add(resourcesItem); return this; } - - public Task addAdverseEventItem(AdverseEvent adverseEventItem) { - if (this.adverseEvents == null) { - this.adverseEvents = new ArrayList<>(); - } - this.adverseEvents.add(adverseEventItem); - return this; - } } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEvent.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEvent.java similarity index 89% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEvent.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEvent.java index 2e8a6d10d40..a005aa32dde 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEvent.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEvent.java @@ -1,4 +1,4 @@ -package org.egov.common.models.project; +package org.egov.common.models.project.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -39,12 +39,10 @@ public class AdverseEvent { private String taskClientReferenceId = null; @JsonProperty("symptoms") + @NotNull + @Min(1) private List symptoms = null; - @JsonProperty("reAttempts") - @Min(value = 0, message = "Re-Attempts must be greater than or equal to 0") - private Integer reAttempts = null; - @JsonProperty("tenantId") @NotNull @Size(min=2, max = 1000) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventBulkRequest.java similarity index 94% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventBulkRequest.java index c85903f53a2..6ceacad4bd3 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventBulkRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.project; +package org.egov.common.models.project.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventBulkResponse.java similarity index 94% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkResponse.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventBulkResponse.java index 08054d08f71..6795c08982a 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventBulkResponse.java @@ -1,4 +1,4 @@ -package org.egov.common.models.project; +package org.egov.common.models.project.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventRequest.java similarity index 85% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventRequest.java index 511728bc794..491e44caaf9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.project; +package org.egov.common.models.project.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -7,6 +7,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.project.adverseevent.AdverseEvent; import javax.validation.Valid; import javax.validation.constraints.NotNull; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventResponse.java similarity index 85% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventResponse.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventResponse.java index b8c0a91396f..2f6c90ece47 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventResponse.java @@ -1,4 +1,4 @@ -package org.egov.common.models.project; +package org.egov.common.models.project.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -7,6 +7,7 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.project.adverseevent.AdverseEvent; import javax.validation.Valid; import javax.validation.constraints.NotNull; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventSearch.java similarity index 93% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventSearch.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventSearch.java index 2f7c293ecbe..239db8fd4e5 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventSearch.java @@ -1,4 +1,4 @@ -package org.egov.common.models.project; +package org.egov.common.models.project.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventSearchRequest.java similarity index 92% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventSearchRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventSearchRequest.java index 287dd316dea..a87a9d71cd4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdverseEventSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventSearchRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.project; +package org.egov.common.models.project.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/project/src/main/java/org/egov/project/consumer/AdverseEventConsumer.java b/health-services/project/src/main/java/org/egov/project/consumer/AdverseEventConsumer.java index b343cb4cbaf..dc6ff243ca1 100644 --- a/health-services/project/src/main/java/org/egov/project/consumer/AdverseEventConsumer.java +++ b/health-services/project/src/main/java/org/egov/project/consumer/AdverseEventConsumer.java @@ -2,9 +2,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; -import org.egov.common.models.project.AdverseEvent; -import org.egov.common.models.project.AdverseEventBulkRequest; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; import org.egov.project.service.AdverseEventService; +import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.kafka.annotation.KafkaListener; @@ -12,8 +13,6 @@ import org.springframework.messaging.handler.annotation.Header; import org.springframework.stereotype.Component; -import java.util.Collections; -import java.util.List; import java.util.Map; @Component @@ -32,38 +31,41 @@ public AdverseEventConsumer(AdverseEventService adverseEventService, } @KafkaListener(topics = "${project.adverseevent.consumer.bulk.create.topic}") - public List bulkCreate(Map consumerRecord, + public void bulkCreate(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { AdverseEventBulkRequest request = objectMapper.convertValue(consumerRecord, AdverseEventBulkRequest.class); - return adverseEventService.create(request, true); + adverseEventService.create(request, true); } catch (Exception exception) { - log.error("error in adverse event consumer bulk create", exception); - return Collections.emptyList(); + log.error("Error in Adverse Event consumer bulk create", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_PROJECT_ADVERSE_EVENT_CREATE", exception.getMessage()); } } @KafkaListener(topics = "${project.adverseevent.consumer.bulk.update.topic}") - public List bulkUpdate(Map consumerRecord, + public void bulkUpdate(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { AdverseEventBulkRequest request = objectMapper.convertValue(consumerRecord, AdverseEventBulkRequest.class); - return adverseEventService.update(request, true); + adverseEventService.update(request, true); } catch (Exception exception) { - log.error("error in adverse event consumer bulk update", exception); - return Collections.emptyList(); + log.error("Error in Adverse Event consumer bulk update", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_PROJECT_ADVERSE_EVENT_CREATE", exception.getMessage()); } } @KafkaListener(topics = "${project.adverseevent.consumer.bulk.delete.topic}") - public List bulkDelete(Map consumerRecord, + public void bulkDelete(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { AdverseEventBulkRequest request = objectMapper.convertValue(consumerRecord, AdverseEventBulkRequest.class); - return adverseEventService.delete(request, true); + adverseEventService.delete(request, true); } catch (Exception exception) { - log.error("error in adverse event consumer bulk delete", exception); - return Collections.emptyList(); + log.error("Error in Adverse Event consumer bulk delete", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_PROJECT_ADVERSE_EVENT_CREATE", exception.getMessage()); } } } diff --git a/health-services/project/src/main/java/org/egov/project/repository/AdverseEventRepository.java b/health-services/project/src/main/java/org/egov/project/repository/AdverseEventRepository.java index bf5eef0ede4..5ea09f918c4 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/AdverseEventRepository.java +++ b/health-services/project/src/main/java/org/egov/project/repository/AdverseEventRepository.java @@ -6,8 +6,8 @@ import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; -import org.egov.common.models.project.AdverseEvent; -import org.egov.common.models.project.AdverseEventSearch; +import org.egov.common.models.project.adverseevent.AdverseEvent; +import org.egov.common.models.project.adverseevent.AdverseEventSearch; import org.egov.common.models.project.Task; import org.egov.common.producer.Producer; import org.egov.project.repository.rowmapper.AdverseEventRowMapper; diff --git a/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java b/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java index 6dfb693069e..54febb70abe 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java +++ b/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java @@ -6,12 +6,10 @@ import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; -import org.egov.common.models.project.AdverseEvent; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskResource; import org.egov.common.models.project.TaskSearch; import org.egov.common.producer.Producer; -import org.egov.project.repository.rowmapper.AdverseEventRowMapper; import org.egov.project.repository.rowmapper.ProjectTaskRowMapper; import org.egov.project.repository.rowmapper.TaskResourceRowMapper; import org.springframework.beans.factory.annotation.Autowired; @@ -74,7 +72,6 @@ public List find(TaskSearch searchObject, Integer limit, Integer offset, S paramsMap.put("offset", offset); List taskList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); fetchAndSetTaskResource(taskList); - fetchAndSetAdverseEvents(taskList); return taskList; } @@ -126,17 +123,9 @@ public List findById(List ids, String columnName, Boolean includeD List taskList = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); fetchAndSetTaskResource(taskList); - fetchAndSetAdverseEvents(taskList); objFound.addAll(taskList); putInCache(objFound); return objFound; } - private void fetchAndSetAdverseEvents(List taskList) { - if (taskList.isEmpty()) { - return; - } - Map> idToObjMap = adverseEventRepository.fetchAdverseEvents(taskList); - taskList.forEach(task -> task.setAdverseEvents(idToObjMap.get(task.getId()))); - } } diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/AdverseEventRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/AdverseEventRowMapper.java index 4ca1ba298bf..0e97bbca5b5 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/AdverseEventRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/AdverseEventRowMapper.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.project.AdverseEvent; +import org.egov.common.models.project.adverseevent.AdverseEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; @@ -11,7 +11,6 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; -import java.util.Arrays; @Component public class AdverseEventRowMapper implements RowMapper { @@ -29,7 +28,6 @@ public AdverseEvent mapRow(ResultSet resultSet, int i) throws SQLException { .taskClientReferenceId(resultSet.getString("taskClientreferenceid")) .tenantId(resultSet.getString("tenantid")) .symptoms(resultSet.getString("symptoms") == null ? null : objectMapper.readValue(resultSet.getString("symptoms"), ArrayList.class)) - .reAttempts(resultSet.getInt("reAttempts")) .rowVersion(resultSet.getInt("rowversion")) .isDeleted(resultSet.getBoolean("isdeleted")) .auditDetails(AuditDetails.builder() diff --git a/health-services/project/src/main/java/org/egov/project/service/AdverseEventService.java b/health-services/project/src/main/java/org/egov/project/service/AdverseEventService.java index 72168147849..0b72be56ec2 100644 --- a/health-services/project/src/main/java/org/egov/project/service/AdverseEventService.java +++ b/health-services/project/src/main/java/org/egov/project/service/AdverseEventService.java @@ -3,7 +3,10 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; -import org.egov.common.models.project.*; +import org.egov.common.models.project.adverseevent.AdverseEvent; +import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.project.adverseevent.AdverseEventRequest; +import org.egov.common.models.project.adverseevent.AdverseEventSearchRequest; import org.egov.common.service.IdGenService; import org.egov.common.utils.CommonUtils; import org.egov.common.validator.Validator; @@ -139,11 +142,11 @@ public List update(AdverseEventBulkRequest adverseEventRequest, bo } public List search(AdverseEventSearchRequest adverseEventSearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { log.info("received request to search adverse events"); String idFieldName = getIdFieldName(adverseEventSearchRequest.getAdverseEvent()); if (isSearchByIdOnly(adverseEventSearchRequest.getAdverseEvent(), idFieldName)) { diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/AdverseEventEnrichmentService.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/AdverseEventEnrichmentService.java index a4c61029a74..1ddfbc2a96a 100644 --- a/health-services/project/src/main/java/org/egov/project/service/enrichment/AdverseEventEnrichmentService.java +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/AdverseEventEnrichmentService.java @@ -1,21 +1,16 @@ package org.egov.project.service.enrichment; import lombok.extern.slf4j.Slf4j; -import org.egov.common.models.project.AdverseEvent; -import org.egov.common.models.project.AdverseEventBulkRequest; -import org.egov.common.models.project.ProjectResourceBulkRequest; +import org.egov.common.models.project.adverseevent.AdverseEvent; +import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; import org.egov.common.service.IdGenService; import org.egov.common.utils.CommonUtils; import org.egov.project.config.ProjectConfiguration; import org.egov.project.repository.AdverseEventRepository; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.List; import java.util.Map; -import java.util.UUID; -import java.util.stream.Collectors; -import java.util.stream.Stream; import static org.egov.common.utils.CommonUtils.*; diff --git a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdIsDeletedValidator.java b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdIsDeletedValidator.java index 744f3b49fbb..06a8ad2bdf5 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdIsDeletedValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdIsDeletedValidator.java @@ -2,8 +2,8 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; -import org.egov.common.models.project.AdverseEvent; -import org.egov.common.models.project.AdverseEventBulkRequest; +import org.egov.common.models.project.adverseevent.AdverseEvent; +import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; diff --git a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNonExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNonExistentEntityValidator.java index cdb588371ce..5545a268df6 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNonExistentEntityValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNonExistentEntityValidator.java @@ -1,11 +1,10 @@ package org.egov.project.validator.adverseevent; -import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; -import org.egov.common.models.project.AdverseEvent; -import org.egov.common.models.project.AdverseEventBulkRequest; +import org.egov.common.models.project.adverseevent.AdverseEvent; +import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; import org.egov.project.repository.AdverseEventRepository; import org.springframework.beans.factory.annotation.Autowired; diff --git a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNullIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNullIdValidator.java index b9716429da5..f4bfa4de299 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNullIdValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNullIdValidator.java @@ -2,8 +2,8 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; -import org.egov.common.models.project.AdverseEvent; -import org.egov.common.models.project.AdverseEventBulkRequest; +import org.egov.common.models.project.adverseevent.AdverseEvent; +import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; diff --git a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdProjectTaskIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdProjectTaskIdValidator.java index fbb8632ce25..da2e4107031 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdProjectTaskIdValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdProjectTaskIdValidator.java @@ -3,8 +3,8 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.models.Error; -import org.egov.common.models.project.AdverseEvent; -import org.egov.common.models.project.AdverseEventBulkRequest; +import org.egov.common.models.project.adverseevent.AdverseEvent; +import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskSearch; import org.egov.common.validator.Validator; @@ -13,7 +13,6 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; -import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; diff --git a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdUniqueEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdUniqueEntityValidator.java index e11d14d8d64..cc404f25824 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdUniqueEntityValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdUniqueEntityValidator.java @@ -2,8 +2,8 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; -import org.egov.common.models.project.AdverseEvent; -import org.egov.common.models.project.AdverseEventBulkRequest; +import org.egov.common.models.project.adverseevent.AdverseEvent; +import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; diff --git a/health-services/project/src/main/java/org/egov/project/web/controllers/AdverseEventApiController.java b/health-services/project/src/main/java/org/egov/project/web/controllers/AdverseEventApiController.java index 278e496667a..20e80519408 100644 --- a/health-services/project/src/main/java/org/egov/project/web/controllers/AdverseEventApiController.java +++ b/health-services/project/src/main/java/org/egov/project/web/controllers/AdverseEventApiController.java @@ -1,9 +1,13 @@ package org.egov.project.web.controllers; -import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.annotations.ApiParam; import org.egov.common.contract.response.ResponseInfo; -import org.egov.common.models.project.*; +import org.egov.common.models.project.adverseevent.AdverseEvent; +import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.project.adverseevent.AdverseEventBulkResponse; +import org.egov.common.models.project.adverseevent.AdverseEventRequest; +import org.egov.common.models.project.adverseevent.AdverseEventResponse; +import org.egov.common.models.project.adverseevent.AdverseEventSearchRequest; import org.egov.common.producer.Producer; import org.egov.common.utils.ResponseInfoFactory; import org.egov.project.config.ProjectConfiguration; @@ -76,11 +80,11 @@ public ResponseEntity adverseEventBulkV1CreatePost(@ApiParam(value @RequestMapping(value = "/task/adverse_event/v1/_search", method = RequestMethod.POST) public ResponseEntity adverseEventV1SearchPost(@ApiParam(value = "Adverse Event Search.", required = true) @Valid @RequestBody AdverseEventSearchRequest request, - @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, - @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, - @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, - @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, - @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { + @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, + @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, + @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, + @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, + @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { List households = adverseEventService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); AdverseEventBulkResponse response = AdverseEventBulkResponse.builder().responseInfo(ResponseInfoFactory diff --git a/health-services/project/src/main/resources/db/migration/main/V20230906144900__adverse_event_col_drop_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20230906144900__adverse_event_col_drop_ddl.sql new file mode 100644 index 00000000000..c5781bdd32c --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20230906144900__adverse_event_col_drop_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE ADVERSE_EVENT DROP COLUMN IF EXISTS reAttempts; \ No newline at end of file diff --git a/health-services/project/src/main/resources/project-task-persister.yml b/health-services/project/src/main/resources/project-task-persister.yml index 807961df6f7..a177dacedf1 100644 --- a/health-services/project/src/main/resources/project-task-persister.yml +++ b/health-services/project/src/main/resources/project-task-persister.yml @@ -162,7 +162,7 @@ serviceMaps: fromTopic: save-adverse-event-topic isTransaction: true queryMaps: - - query: INSERT INTO ADVERSE_EVENT(id, clientReferenceId, tenantId, taskId, taskClientReferenceId, symptoms, reAttempts, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedTime, clientLastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); + - query: INSERT INTO ADVERSE_EVENT(id, clientReferenceId, tenantId, taskId, taskClientReferenceId, symptoms, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedTime, clientLastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?); basePath: $.* jsonMaps: - jsonPath: $.*.id @@ -173,7 +173,6 @@ serviceMaps: - jsonPath: $.*.symptoms type: JSON dbType: JSONB - - jsonPath: $.*.reAttempts - jsonPath: $.*.auditDetails.createdBy - jsonPath: $.*.auditDetails.createdTime - jsonPath: $.*.auditDetails.lastModifiedBy @@ -188,7 +187,7 @@ serviceMaps: fromTopic: update-adverse-event-topic isTransaction: true queryMaps: - - query: UPDATE ADVERSE_EVENT SET tenantId = ?, taskId = ?, taskClientReferenceId = ?, symptoms = ?, reAttempts = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + - query: UPDATE ADVERSE_EVENT SET tenantId = ?, taskId = ?, taskClientReferenceId = ?, symptoms = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; basePath: $.* jsonMaps: - jsonPath: $.*.tenantId @@ -197,7 +196,6 @@ serviceMaps: - jsonPath: $.*.symptoms type: JSON dbType: JSONB - - jsonPath: $.*.reAttempts - jsonPath: $.*.auditDetails.lastModifiedBy - jsonPath: $.*.auditDetails.lastModifiedTime - jsonPath: $.*.clientAuditDetails.lastModifiedTime diff --git a/health-services/project/src/test/java/org/egov/project/helper/AdverseEventRequestTestBuilder.java b/health-services/project/src/test/java/org/egov/project/helper/AdverseEventRequestTestBuilder.java index f2824526307..463355e4d88 100644 --- a/health-services/project/src/test/java/org/egov/project/helper/AdverseEventRequestTestBuilder.java +++ b/health-services/project/src/test/java/org/egov/project/helper/AdverseEventRequestTestBuilder.java @@ -1,7 +1,7 @@ package org.egov.project.helper; import org.egov.common.helper.RequestInfoTestBuilder; -import org.egov.common.models.project.AdverseEventRequest; +import org.egov.common.models.project.adverseevent.AdverseEventRequest; import java.util.ArrayList; diff --git a/health-services/project/src/test/java/org/egov/project/helper/AdverseEventTestBuilder.java b/health-services/project/src/test/java/org/egov/project/helper/AdverseEventTestBuilder.java index e276b573eee..421381a2b55 100644 --- a/health-services/project/src/test/java/org/egov/project/helper/AdverseEventTestBuilder.java +++ b/health-services/project/src/test/java/org/egov/project/helper/AdverseEventTestBuilder.java @@ -1,7 +1,7 @@ package org.egov.project.helper; import org.egov.common.helper.AuditDetailsTestBuilder; -import org.egov.common.models.project.AdverseEvent; +import org.egov.common.models.project.adverseevent.AdverseEvent; import java.util.ArrayList; import java.util.Arrays; @@ -28,7 +28,6 @@ public AdverseEventTestBuilder withIdNull() { .id(null) .taskClientReferenceId("null") .symptoms(new ArrayList<>(Arrays.asList("fever"))) - .reAttempts(1) .tenantId("some-tenant-id") .rowVersion(1); return this; @@ -39,7 +38,6 @@ public AdverseEventTestBuilder withId() { .clientReferenceId("adverseEventClientReferenceId") .taskClientReferenceId("null") .symptoms(new ArrayList<>(Arrays.asList("fever"))) - .reAttempts(1) .tenantId("some-tenant-id"); return this; } @@ -59,7 +57,6 @@ public AdverseEventTestBuilder goodAdverseEvent() { .clientReferenceId("adverseEventClientReferenceId") .taskClientReferenceId("null") .symptoms(new ArrayList<>(Arrays.asList("fever"))) - .reAttempts(1) .tenantId("some-tenant-id") .rowVersion(1) .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()) diff --git a/health-services/project/src/test/java/org/egov/project/web/controllers/AdverseEventApiControllerTest.java b/health-services/project/src/test/java/org/egov/project/web/controllers/AdverseEventApiControllerTest.java index 440e4d0ff3f..022387b7ff7 100644 --- a/health-services/project/src/test/java/org/egov/project/web/controllers/AdverseEventApiControllerTest.java +++ b/health-services/project/src/test/java/org/egov/project/web/controllers/AdverseEventApiControllerTest.java @@ -2,7 +2,12 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.egov.common.helper.RequestInfoTestBuilder; -import org.egov.common.models.project.*; +import org.egov.common.models.project.adverseevent.AdverseEvent; +import org.egov.common.models.project.adverseevent.AdverseEventBulkResponse; +import org.egov.common.models.project.adverseevent.AdverseEventRequest; +import org.egov.common.models.project.adverseevent.AdverseEventResponse; +import org.egov.common.models.project.adverseevent.AdverseEventSearch; +import org.egov.common.models.project.adverseevent.AdverseEventSearchRequest; import org.egov.common.producer.Producer; import org.egov.project.TestConfiguration; import org.egov.project.config.ProjectConfiguration; From 7b2e49227935c205e768c7efc85cf13e2bf49328 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 6 Sep 2023 16:19:10 +0530 Subject: [PATCH 140/283] HLM-3069 : changed version to 1.0.8 in health-services-models --- health-services/libraries/health-services-models/pom.xml | 2 +- health-services/project/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index 4a43db87be4..db7bac4c188 100644 --- a/health-services/libraries/health-services-models/pom.xml +++ b/health-services/libraries/health-services-models/pom.xml @@ -6,7 +6,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT_dev_temp + 1.0.8-SNAPSHOT 8 diff --git a/health-services/project/pom.xml b/health-services/project/pom.xml index 0dd29754cd6..b15e8282b3d 100644 --- a/health-services/project/pom.xml +++ b/health-services/project/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT_dev_temp + 1.0.8-SNAPSHOT compile From 61c2529cdabc7b48cb2dcf4a1e589232ea40de7f Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Tue, 12 Sep 2023 14:11:41 +0530 Subject: [PATCH 141/283] HLM-3069 : moved adverse event changes to new module adrm --- health-services/adrm/pom.xml | 135 ++++++++++++++++++ .../java/org/egov/adrm/AdrmApplication.java | 18 +++ .../main/java/org/egov/adrm/Constants.java | 12 ++ .../egov/adrm/config/AdrmConfiguration.java | 35 +++++ .../adrm}/consumer/AdverseEventConsumer.java | 4 +- .../repository/AdverseEventRepository.java | 4 +- .../rowmapper/AdverseEventRowMapper.java | 2 +- .../adrm}/service/AdverseEventService.java | 48 +++---- .../AdverseEventEnrichmentService.java | 12 +- .../adverseevent/AdIsDeletedValidator.java | 2 +- .../AdNonExistentEntityValidator.java | 14 +- .../adverseevent/AdNullIdValidator.java | 4 +- .../AdProjectTaskIdValidator.java | 2 +- .../adverseevent/AdUniqueEntityValidator.java | 2 +- .../AdverseEventApiController.java | 18 +-- .../src/main/resources/application.properties | 133 +++++++++++++++++ .../src/test/java/org/egov/adrm/AppTest.java | 20 +++ .../main/java/org/egov/project/Constants.java | 4 - 18 files changed, 411 insertions(+), 58 deletions(-) create mode 100644 health-services/adrm/pom.xml create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/AdrmApplication.java create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/Constants.java create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java rename health-services/{project/src/main/java/org/egov/project => adrm/src/main/java/org/egov/adrm}/consumer/AdverseEventConsumer.java (97%) rename health-services/{project/src/main/java/org/egov/project => adrm/src/main/java/org/egov/adrm}/repository/AdverseEventRepository.java (98%) rename health-services/{project/src/main/java/org/egov/project => adrm/src/main/java/org/egov/adrm}/repository/rowmapper/AdverseEventRowMapper.java (97%) rename health-services/{project/src/main/java/org/egov/project => adrm/src/main/java/org/egov/adrm}/service/AdverseEventService.java (88%) rename health-services/{project/src/main/java/org/egov/project => adrm/src/main/java/org/egov/adrm}/service/enrichment/AdverseEventEnrichmentService.java (83%) rename health-services/{project/src/main/java/org/egov/project => adrm/src/main/java/org/egov/adrm}/validator/adverseevent/AdIsDeletedValidator.java (96%) rename health-services/{project/src/main/java/org/egov/project => adrm/src/main/java/org/egov/adrm}/validator/adverseevent/AdNonExistentEntityValidator.java (80%) rename health-services/{project/src/main/java/org/egov/project => adrm/src/main/java/org/egov/adrm}/validator/adverseevent/AdNullIdValidator.java (88%) rename health-services/{project/src/main/java/org/egov/project => adrm/src/main/java/org/egov/adrm}/validator/adverseevent/AdProjectTaskIdValidator.java (98%) rename health-services/{project/src/main/java/org/egov/project => adrm/src/main/java/org/egov/adrm}/validator/adverseevent/AdUniqueEntityValidator.java (97%) rename health-services/{project/src/main/java/org/egov/project => adrm/src/main/java/org/egov/adrm}/web/controllers/AdverseEventApiController.java (93%) create mode 100644 health-services/adrm/src/main/resources/application.properties create mode 100644 health-services/adrm/src/test/java/org/egov/adrm/AppTest.java diff --git a/health-services/adrm/pom.xml b/health-services/adrm/pom.xml new file mode 100644 index 00000000000..391bede4da1 --- /dev/null +++ b/health-services/adrm/pom.xml @@ -0,0 +1,135 @@ + + + + 4.0.0 + + org.egov.adrm + adrm + jar + adrm + 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-jdbc + + + org.egov.common + health-services-common + 1.0.8-SNAPSHOT + + + org.egov.common + health-services-models + 1.0.8-SNAPSHOT + compile + + + org.springframework.boot + spring-boot-starter-data-redis + + + io.lettuce + lettuce-core + + + + + redis.clients + jedis + + + org.flywaydb + flyway-core + + + org.postgresql + postgresql + 42.2.2.jre7 + + + org.springframework.boot + spring-boot-starter-test + test + + + + io.swagger + swagger-core + 1.5.18 + + + + org.egov.services + digit-models + 1.0.0-SNAPSHOT + + + org.projectlombok + lombok + true + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + javax.validation + validation-api + + + + + 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/ + + + \ No newline at end of file diff --git a/health-services/adrm/src/main/java/org/egov/adrm/AdrmApplication.java b/health-services/adrm/src/main/java/org/egov/adrm/AdrmApplication.java new file mode 100644 index 00000000000..f034b325dd8 --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/AdrmApplication.java @@ -0,0 +1,18 @@ +package org.egov.adrm; + + +import org.egov.tracer.config.TracerConfiguration; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Import; + +@SpringBootApplication +@EnableCaching +@Import({ TracerConfiguration.class }) +public class AdrmApplication +{ + public static void main(String[] args) throws Exception { + SpringApplication.run(AdrmApplication.class, args); + } +} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/Constants.java b/health-services/adrm/src/main/java/org/egov/adrm/Constants.java new file mode 100644 index 00000000000..5077f0f5d96 --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/Constants.java @@ -0,0 +1,12 @@ +package org.egov.adrm; + +public interface Constants { + String SET_ADVERSE_EVENTS = "setAdverseEvents"; + String GET_ADVERSE_EVENTS = "getAdverseEvents"; + String VALIDATION_ERROR = "VALIDATION_ERROR"; + String PROJECT_TYPES = "projectTypes"; + String MDMS_RESPONSE = "MdmsRes"; + String INTERNAL_SERVER_ERROR = "INTERNAL_SERVER_ERROR"; + String GET_ID = "getId"; + +} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java b/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java new file mode 100644 index 00000000000..b5e6e01fe47 --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java @@ -0,0 +1,35 @@ +package org.egov.adrm.config; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@Component +public class AdrmConfiguration { + @Value("${project.adverseevent.kafka.create.topic}") + private String createAdverseEventTopic; + + @Value("${project.adverseevent.kafka.update.topic}") + private String updateAdverseEventTopic; + + @Value("${project.adverseevent.kafka.delete.topic}") + private String deleteAdverseEventTopic; + + @Value("${project.adverseevent.consumer.bulk.create.topic}") + private String createAdverseEventBulkTopic; + + @Value("${project.adverseevent.consumer.bulk.update.topic}") + private String updateAdverseEventBulkTopic; + + @Value("${project.adverseevent.consumer.bulk.delete.topic}") + private String deleteAdverseEventBulkTopic; +} diff --git a/health-services/project/src/main/java/org/egov/project/consumer/AdverseEventConsumer.java b/health-services/adrm/src/main/java/org/egov/adrm/consumer/AdverseEventConsumer.java similarity index 97% rename from health-services/project/src/main/java/org/egov/project/consumer/AdverseEventConsumer.java rename to health-services/adrm/src/main/java/org/egov/adrm/consumer/AdverseEventConsumer.java index dc6ff243ca1..49900fea211 100644 --- a/health-services/project/src/main/java/org/egov/project/consumer/AdverseEventConsumer.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/consumer/AdverseEventConsumer.java @@ -1,10 +1,10 @@ -package org.egov.project.consumer; +package org.egov.adrm.consumer; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; -import org.egov.project.service.AdverseEventService; +import org.egov.adrm.service.AdverseEventService; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; diff --git a/health-services/project/src/main/java/org/egov/project/repository/AdverseEventRepository.java b/health-services/adrm/src/main/java/org/egov/adrm/repository/AdverseEventRepository.java similarity index 98% rename from health-services/project/src/main/java/org/egov/project/repository/AdverseEventRepository.java rename to health-services/adrm/src/main/java/org/egov/adrm/repository/AdverseEventRepository.java index 5ea09f918c4..64aa427dd0b 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/AdverseEventRepository.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/repository/AdverseEventRepository.java @@ -1,4 +1,4 @@ -package org.egov.project.repository; +package org.egov.adrm.repository; import lombok.extern.slf4j.Slf4j; import org.egov.common.data.query.builder.GenericQueryBuilder; @@ -10,7 +10,7 @@ import org.egov.common.models.project.adverseevent.AdverseEventSearch; import org.egov.common.models.project.Task; import org.egov.common.producer.Producer; -import org.egov.project.repository.rowmapper.AdverseEventRowMapper; +import org.egov.adrm.repository.rowmapper.AdverseEventRowMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/AdverseEventRowMapper.java b/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/AdverseEventRowMapper.java similarity index 97% rename from health-services/project/src/main/java/org/egov/project/repository/rowmapper/AdverseEventRowMapper.java rename to health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/AdverseEventRowMapper.java index 0e97bbca5b5..3c411ba3a7c 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/AdverseEventRowMapper.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/AdverseEventRowMapper.java @@ -1,4 +1,4 @@ -package org.egov.project.repository.rowmapper; +package org.egov.adrm.repository.rowmapper; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; diff --git a/health-services/project/src/main/java/org/egov/project/service/AdverseEventService.java b/health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java similarity index 88% rename from health-services/project/src/main/java/org/egov/project/service/AdverseEventService.java rename to health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java index 0b72be56ec2..bff41744b05 100644 --- a/health-services/project/src/main/java/org/egov/project/service/AdverseEventService.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java @@ -1,6 +1,7 @@ -package org.egov.project.service; +package org.egov.adrm.service; import lombok.extern.slf4j.Slf4j; +import org.egov.adrm.Constants; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.project.adverseevent.AdverseEvent; @@ -10,10 +11,11 @@ import org.egov.common.service.IdGenService; import org.egov.common.utils.CommonUtils; import org.egov.common.validator.Validator; -import org.egov.project.config.ProjectConfiguration; -import org.egov.project.repository.AdverseEventRepository; -import org.egov.project.service.enrichment.AdverseEventEnrichmentService; -import org.egov.project.validator.adverseevent.*; +import org.egov.adrm.config.AdrmConfiguration; +import org.egov.adrm.repository.AdverseEventRepository; +import org.egov.adrm.service.enrichment.AdverseEventEnrichmentService; +import org.egov.adrm.validator.adverseevent.*; +import org.egov.project.service.ProjectService; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -26,8 +28,8 @@ import java.util.stream.Collectors; import static org.egov.common.utils.CommonUtils.*; -import static org.egov.project.Constants.SET_ADVERSE_EVENTS; -import static org.egov.project.Constants.VALIDATION_ERROR; +import static org.egov.adrm.Constants.SET_ADVERSE_EVENTS; +import static org.egov.adrm.Constants.VALIDATION_ERROR; @Service @Slf4j @@ -36,9 +38,7 @@ public class AdverseEventService { private final AdverseEventRepository adverseEventRepository; - private final ProjectService projectService; - - private final ProjectConfiguration projectConfiguration; + private final AdrmConfiguration adrmConfiguration; private final AdverseEventEnrichmentService adverseEventEnrichmentService; @@ -62,15 +62,13 @@ public class AdverseEventService { public AdverseEventService( IdGenService idGenService, AdverseEventRepository adverseEventRepository, - ProjectService projectService, - ProjectConfiguration projectConfiguration, + AdrmConfiguration adrmConfiguration, AdverseEventEnrichmentService adverseEventEnrichmentService, List> validators ) { this.idGenService = idGenService; this.adverseEventRepository = adverseEventRepository; - this.projectService = projectService; - this.projectConfiguration = projectConfiguration; + this.adrmConfiguration = adrmConfiguration; this.adverseEventEnrichmentService = adverseEventEnrichmentService; this.validators = validators; } @@ -95,15 +93,15 @@ public List create(AdverseEventBulkRequest adverseEventRequest, bo log.info("processing {} valid entities", validAdverseEvents.size()); adverseEventEnrichmentService.create(validAdverseEvents, adverseEventRequest); adverseEventRepository.save(validAdverseEvents, - projectConfiguration.getCreateAdverseEventTopic()); + adrmConfiguration.getCreateAdverseEventTopic()); log.info("successfully created adverse events"); } } catch (Exception exception) { log.error("error occurred while creating adverse events: {}", exception.getMessage()); populateErrorDetails(adverseEventRequest, errorDetailsMap, validAdverseEvents, - exception, SET_ADVERSE_EVENTS); + exception, Constants.SET_ADVERSE_EVENTS); } - handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); return validAdverseEvents; } @@ -128,15 +126,15 @@ public List update(AdverseEventBulkRequest adverseEventRequest, bo log.info("processing {} valid entities", validAdverseEvents.size()); adverseEventEnrichmentService.update(validAdverseEvents, adverseEventRequest); adverseEventRepository.save(validAdverseEvents, - projectConfiguration.getUpdateAdverseEventTopic()); + adrmConfiguration.getUpdateAdverseEventTopic()); log.info("successfully updated bulk adverse events"); } } catch (Exception exception) { log.error("error occurred while updating adverse events", exception); populateErrorDetails(adverseEventRequest, errorDetailsMap, validAdverseEvents, - exception, SET_ADVERSE_EVENTS); + exception, Constants.SET_ADVERSE_EVENTS); } - handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); return validAdverseEvents; } @@ -188,15 +186,15 @@ public List delete(AdverseEventBulkRequest adverseEventRequest, bo .findById(adverseEventIds, false); adverseEventEnrichmentService.delete(existingAdverseEvents, adverseEventRequest); adverseEventRepository.save(existingAdverseEvents, - projectConfiguration.getDeleteAdverseEventTopic()); + adrmConfiguration.getDeleteAdverseEventTopic()); log.info("successfully deleted entities"); } } catch (Exception exception) { log.error("error occurred while deleting entities: {}", exception); populateErrorDetails(adverseEventRequest, errorDetailsMap, validAdverseEvents, - exception, SET_ADVERSE_EVENTS); + exception, Constants.SET_ADVERSE_EVENTS); } - handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); return validAdverseEvents; } @@ -216,10 +214,10 @@ private Tuple, Map> validate( log.info("validating request"); Map errorDetailsMap = CommonUtils.validate(validators, isApplicable, request, - SET_ADVERSE_EVENTS); + Constants.SET_ADVERSE_EVENTS); if (!errorDetailsMap.isEmpty() && !isBulk) { log.error("validation error occurred. error details: {}", errorDetailsMap.values().toString()); - throw new CustomException(VALIDATION_ERROR, errorDetailsMap.values().toString()); + throw new CustomException(Constants.VALIDATION_ERROR, errorDetailsMap.values().toString()); } List validAdverseEvents = request.getAdverseEvents().stream() .filter(notHavingErrors()).collect(Collectors.toList()); diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/AdverseEventEnrichmentService.java b/health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/AdverseEventEnrichmentService.java similarity index 83% rename from health-services/project/src/main/java/org/egov/project/service/enrichment/AdverseEventEnrichmentService.java rename to health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/AdverseEventEnrichmentService.java index 1ddfbc2a96a..663ccd9840e 100644 --- a/health-services/project/src/main/java/org/egov/project/service/enrichment/AdverseEventEnrichmentService.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/AdverseEventEnrichmentService.java @@ -1,12 +1,12 @@ -package org.egov.project.service.enrichment; +package org.egov.adrm.service.enrichment; import lombok.extern.slf4j.Slf4j; +import org.egov.adrm.config.AdrmConfiguration; import org.egov.common.models.project.adverseevent.AdverseEvent; import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; import org.egov.common.service.IdGenService; import org.egov.common.utils.CommonUtils; -import org.egov.project.config.ProjectConfiguration; -import org.egov.project.repository.AdverseEventRepository; +import org.egov.adrm.repository.AdverseEventRepository; import org.springframework.stereotype.Component; import java.util.List; @@ -20,13 +20,13 @@ public class AdverseEventEnrichmentService { private final IdGenService idGenService; - private final ProjectConfiguration projectConfiguration; + private final AdrmConfiguration adrmConfiguration; private final AdverseEventRepository adverseEventRepository; - public AdverseEventEnrichmentService(IdGenService idGenService, ProjectConfiguration projectConfiguration, AdverseEventRepository adverseEventRepository) { + public AdverseEventEnrichmentService(IdGenService idGenService, AdrmConfiguration adrmConfiguration, AdverseEventRepository adverseEventRepository) { this.idGenService = idGenService; - this.projectConfiguration = projectConfiguration; + this.adrmConfiguration = adrmConfiguration; this.adverseEventRepository = adverseEventRepository; } diff --git a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdIsDeletedValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdIsDeletedValidator.java similarity index 96% rename from health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdIsDeletedValidator.java rename to health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdIsDeletedValidator.java index 06a8ad2bdf5..facb6593dde 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdIsDeletedValidator.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdIsDeletedValidator.java @@ -1,4 +1,4 @@ -package org.egov.project.validator.adverseevent; +package org.egov.adrm.validator.adverseevent; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; diff --git a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNonExistentEntityValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNonExistentEntityValidator.java similarity index 80% rename from health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNonExistentEntityValidator.java rename to health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNonExistentEntityValidator.java index 5545a268df6..0d509f837a3 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNonExistentEntityValidator.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNonExistentEntityValidator.java @@ -1,12 +1,12 @@ -package org.egov.project.validator.adverseevent; +package org.egov.adrm.validator.adverseevent; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.egov.adrm.repository.AdverseEventRepository; import org.egov.common.models.Error; import org.egov.common.models.project.adverseevent.AdverseEvent; import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; -import org.egov.project.repository.AdverseEventRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -18,9 +18,15 @@ import java.util.Map; import java.util.stream.Collectors; -import static org.egov.common.utils.CommonUtils.*; +import static org.egov.adrm.Constants.GET_ID; +import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.getObjClass; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; -import static org.egov.project.Constants.GET_ID; @Component @Order(value = 4) diff --git a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNullIdValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNullIdValidator.java similarity index 88% rename from health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNullIdValidator.java rename to health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNullIdValidator.java index f4bfa4de299..6607d7b6d53 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdNullIdValidator.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNullIdValidator.java @@ -1,4 +1,4 @@ -package org.egov.project.validator.adverseevent; +package org.egov.adrm.validator.adverseevent; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; @@ -11,8 +11,8 @@ import java.util.List; import java.util.Map; +import static org.egov.adrm.Constants.GET_ADVERSE_EVENTS; import static org.egov.common.utils.CommonUtils.validateForNullId; -import static org.egov.project.Constants.GET_ADVERSE_EVENTS; @Component diff --git a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdProjectTaskIdValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java similarity index 98% rename from health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdProjectTaskIdValidator.java rename to health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java index da2e4107031..f425def9407 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdProjectTaskIdValidator.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java @@ -1,4 +1,4 @@ -package org.egov.project.validator.adverseevent; +package org.egov.adrm.validator.adverseevent; import lombok.extern.slf4j.Slf4j; import org.egov.common.data.query.exception.QueryBuilderException; diff --git a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdUniqueEntityValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdUniqueEntityValidator.java similarity index 97% rename from health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdUniqueEntityValidator.java rename to health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdUniqueEntityValidator.java index cc404f25824..aa7be4b5eb0 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/adverseevent/AdUniqueEntityValidator.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdUniqueEntityValidator.java @@ -1,4 +1,4 @@ -package org.egov.project.validator.adverseevent; +package org.egov.adrm.validator.adverseevent; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; diff --git a/health-services/project/src/main/java/org/egov/project/web/controllers/AdverseEventApiController.java b/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java similarity index 93% rename from health-services/project/src/main/java/org/egov/project/web/controllers/AdverseEventApiController.java rename to health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java index 20e80519408..ada116b5ec6 100644 --- a/health-services/project/src/main/java/org/egov/project/web/controllers/AdverseEventApiController.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java @@ -1,6 +1,8 @@ -package org.egov.project.web.controllers; +package org.egov.adrm.web.controllers; import io.swagger.annotations.ApiParam; +import org.egov.adrm.config.AdrmConfiguration; +import org.egov.adrm.service.AdverseEventService; import org.egov.common.contract.response.ResponseInfo; import org.egov.common.models.project.adverseevent.AdverseEvent; import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; @@ -10,8 +12,6 @@ import org.egov.common.models.project.adverseevent.AdverseEventSearchRequest; import org.egov.common.producer.Producer; import org.egov.common.utils.ResponseInfoFactory; -import org.egov.project.config.ProjectConfiguration; -import org.egov.project.service.*; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; @@ -39,18 +39,18 @@ public class AdverseEventApiController { private final Producer producer; - private final ProjectConfiguration projectConfiguration; + private final AdrmConfiguration adrmConfiguration; public AdverseEventApiController( HttpServletRequest httpServletRequest, AdverseEventService adverseEventService, Producer producer, - ProjectConfiguration projectConfiguration + AdrmConfiguration adrmConfiguration ) { this.httpServletRequest = httpServletRequest; this.adverseEventService = adverseEventService; this.producer = producer; - this.projectConfiguration = projectConfiguration; + this.adrmConfiguration = adrmConfiguration; } @RequestMapping(value = "/task/adverse_event/v1/_create", method = RequestMethod.POST) @@ -72,7 +72,7 @@ public ResponseEntity adverseEventV1CreatePost(@ApiParam(v public ResponseEntity adverseEventBulkV1CreatePost(@ApiParam(value = "Capture details of Adverse Event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); adverseEventService.putInCache(request.getAdverseEvents()); - producer.push(projectConfiguration.getCreateAdverseEventBulkTopic(), request); + producer.push(adrmConfiguration.getCreateAdverseEventBulkTopic(), request); return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory .createResponseInfo(request.getRequestInfo(), true)); @@ -110,7 +110,7 @@ public ResponseEntity adverseEventV1UpdatePost(@ApiParam(v @RequestMapping(value = "/task/adverse_event/v1/bulk/_update", method = RequestMethod.POST) public ResponseEntity adverseEventV1BulkUpdatePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); - producer.push(projectConfiguration.getUpdateAdverseEventBulkTopic(), request); + producer.push(adrmConfiguration.getUpdateAdverseEventBulkTopic(), request); return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory .createResponseInfo(request.getRequestInfo(), true)); @@ -133,7 +133,7 @@ public ResponseEntity adverseEventV1DeletePost(@ApiParam(v @RequestMapping(value = "/task/adverse_event/v1/bulk/_delete", method = RequestMethod.POST) public ResponseEntity adverseEventV1BulkDeletePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); - producer.push(projectConfiguration.getDeleteAdverseEventBulkTopic(), request); + producer.push(adrmConfiguration.getDeleteAdverseEventBulkTopic(), request); return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory .createResponseInfo(request.getRequestInfo(), true)); diff --git a/health-services/adrm/src/main/resources/application.properties b/health-services/adrm/src/main/resources/application.properties new file mode 100644 index 00000000000..32e7bcd698c --- /dev/null +++ b/health-services/adrm/src/main/resources/application.properties @@ -0,0 +1,133 @@ +server.servlet.context-path=/adrm +server.port=8080 +app.timezone=UTC + +# REDIS CONFIG +spring.redis.host=localhost +spring.redis.port=6379 +spring.cache.type=redis +# Seconds +spring.cache.redis.time-to-live=60 +spring.cache.autoexpiry=true + +# DATABASE CONFIG +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/postgres +spring.datasource.username=postgres +spring.datasource.password=postgres + +# FLYWAY CONFIG +spring.flyway.url=jdbc:postgresql://localhost:5432/postgres +spring.flyway.user=postgres +spring.flyway.password=postgres +spring.flyway.table=public +spring.flyway.baseline-on-migrate=true +spring.flyway.outOfOrder=true +spring.flyway.locations=classpath:/db/migration/main +spring.flyway.enabled=true + +# TRACER CONFIG +# KAFKA SERVER CONFIG +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=project +spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer +spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer +spring.kafka.listener.missing-topics-fatal=false +spring.kafka.consumer.properties.spring.json.use.type.headers=false + +# KAFKA CONSUMER CONFIG +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 CONFIG +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 + +# IDGEN CONFIG +# egov.idgen.host=https://dev.digit.org/ +#egov.idgen.host=https://health-dev.digit.org/ +egov.idgen.host=http://localhost:8081/ +egov.idgen.path=egov-idgen/id/_generate +egov.idgen.integration.enabled=true +project.task.idgen.id.format=project.task.id +idgen.project.beneficiary.id.format=project.beneficiary.id +project.staff.idgen.id.format=project.staff.id +project.facility.idgen.id.format=project.facility.id +egov.idgen.project.number.name=project.number +project.resource.idgen.id.format=project.resource.id + +# The value of the following field should be changed to service specific name +kafka.topics.consumer=project-consumer-topic + +# USER CONFIG +egov.user.host=https://dev.digit.org +#egov.user.host=http://localhost:8286 +egov.search.user.url=/user/_search +egov.user.integration.enabled=true + +# MDMS CONFIG +egov.mdms.host=https://dev.digit.org +egov.mdms.search.endpoint=/egov-mdms-service/v1/_search +egov.mdms.master.name=project_master +egov.mdms.module.name=project +egov.mdms.integration.enabled=true + + +# HOUSEHOLD SERVICE +egov.household.host=http://localhost:9100 +egov.search.household.url=/household/v1/_search + +# INDIVIDUAL SERVICE +egov.individual.host= +egov.search.individual.url= + +# use the value as "egov-user" to validate against egov-user service +# use the value as "individual" to validate against individual service +egov.user.id.validator=individual + +# FACILITY SERVICE +egov.facility.host=http://localhost:8083 +egov.search.facility.url=/facility/v1/_search + +# Product Config +egov.product.host=http://localhost:8082 +egov.search.product.variant.url=/product/variant/v1/_search + +# PROJECT KAFKA CONFIG +project.adverseevent.kafka.create.topic=save-adverse-event-topic +project.adverseevent.kafka.update.topic=update-adverse-event-topic +project.adverseevent.kafka.delete.topic=delete-adverse-event-topic + +project.adverseevent.consumer.bulk.create.topic=save-adverse-event-bulk-topic +project.adverseevent.consumer.bulk.update.topic=update-adverse-event-bulk-topic +project.adverseevent.consumer.bulk.delete.topic=delete-adverse-event-bulk-topic + +search.api.limit=1000 + +project.default.offset=0 +project.default.limit=100 +project.search.max.limit=200 + + +#location config +egov.location.host=https://works-dev.digit.org +#egov.location.host=http://localhost:8082 +egov.location.context.path=/egov-location/location/v11/ +egov.location.endpoint=/boundarys/_search +egov.location.code.query.param=codes + +project.document.id.verification.required=false + + +project.mdms.module=HCM-PROJECT-TYPES +egov.location.hierarchy.type=ADMIN + + + + diff --git a/health-services/adrm/src/test/java/org/egov/adrm/AppTest.java b/health-services/adrm/src/test/java/org/egov/adrm/AppTest.java new file mode 100644 index 00000000000..d76b5eea977 --- /dev/null +++ b/health-services/adrm/src/test/java/org/egov/adrm/AppTest.java @@ -0,0 +1,20 @@ +package org.egov.adrm; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +/** + * Unit test for simple App. + */ +public class AppTest +{ + /** + * Rigorous Test :-) + */ + @Test + public void shouldAnswerWithTrue() + { + assertTrue( true ); + } +} diff --git a/health-services/project/src/main/java/org/egov/project/Constants.java b/health-services/project/src/main/java/org/egov/project/Constants.java index e94bcd7e163..42b730bbd11 100644 --- a/health-services/project/src/main/java/org/egov/project/Constants.java +++ b/health-services/project/src/main/java/org/egov/project/Constants.java @@ -54,8 +54,4 @@ public interface Constants { String PROJECT_ID = "projectId"; - String SET_ADVERSE_EVENTS = "setAdverseEvents"; - - String GET_ADVERSE_EVENTS = "getAdverseEvents"; - } From db66e4f427f1d9b1ac15eccf4f96f75a639db704 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Tue, 12 Sep 2023 14:55:45 +0530 Subject: [PATCH 142/283] HLM-3069 : addded project service in application.properties --- .../egov/adrm/config/AdrmConfiguration.java | 6 ++++ .../adrm/service/AdverseEventService.java | 25 +++++++++----- .../AdProjectTaskIdValidator.java | 33 ++++++++++++------- .../src/main/resources/application.properties | 13 +++----- 4 files changed, 50 insertions(+), 27 deletions(-) diff --git a/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java b/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java index b5e6e01fe47..145616a6255 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java @@ -32,4 +32,10 @@ public class AdrmConfiguration { @Value("${project.adverseevent.consumer.bulk.delete.topic}") private String deleteAdverseEventBulkTopic; + + @Value("${egov.project.task.host}") + private String projectTaskHost; + + @Value("${egov.search.project.task.url}") + private String projectTaskSearchUrl; } diff --git a/health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java b/health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java index bff41744b05..ff5d56da5a2 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java @@ -2,6 +2,14 @@ import lombok.extern.slf4j.Slf4j; import org.egov.adrm.Constants; +import org.egov.adrm.config.AdrmConfiguration; +import org.egov.adrm.repository.AdverseEventRepository; +import org.egov.adrm.service.enrichment.AdverseEventEnrichmentService; +import org.egov.adrm.validator.adverseevent.AdIsDeletedValidator; +import org.egov.adrm.validator.adverseevent.AdNonExistentEntityValidator; +import org.egov.adrm.validator.adverseevent.AdNullIdValidator; +import org.egov.adrm.validator.adverseevent.AdProjectTaskIdValidator; +import org.egov.adrm.validator.adverseevent.AdUniqueEntityValidator; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.project.adverseevent.AdverseEvent; @@ -11,11 +19,6 @@ import org.egov.common.service.IdGenService; import org.egov.common.utils.CommonUtils; import org.egov.common.validator.Validator; -import org.egov.adrm.config.AdrmConfiguration; -import org.egov.adrm.repository.AdverseEventRepository; -import org.egov.adrm.service.enrichment.AdverseEventEnrichmentService; -import org.egov.adrm.validator.adverseevent.*; -import org.egov.project.service.ProjectService; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -27,9 +30,15 @@ import java.util.function.Predicate; import java.util.stream.Collectors; -import static org.egov.common.utils.CommonUtils.*; -import static org.egov.adrm.Constants.SET_ADVERSE_EVENTS; -import static org.egov.adrm.Constants.VALIDATION_ERROR; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; @Service @Slf4j diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java index f425def9407..f88f14ce0eb 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java @@ -1,14 +1,17 @@ package org.egov.adrm.validator.adverseevent; import lombok.extern.slf4j.Slf4j; +import org.egov.adrm.config.AdrmConfiguration; import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; -import org.egov.common.models.project.adverseevent.AdverseEvent; -import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; import org.egov.common.models.project.Task; +import org.egov.common.models.project.TaskBulkResponse; import org.egov.common.models.project.TaskSearch; +import org.egov.common.models.project.TaskSearchRequest; +import org.egov.common.models.project.adverseevent.AdverseEvent; +import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; -import org.egov.project.repository.ProjectTaskRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -22,7 +25,8 @@ import java.util.Objects; import java.util.stream.Collectors; -import static org.egov.common.utils.CommonUtils.*; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; @@ -30,11 +34,13 @@ @Order(value = 3) @Slf4j public class AdProjectTaskIdValidator implements Validator { - private final ProjectTaskRepository projectTaskRepository; + private final ServiceRequestClient serviceRequestClient; + private final AdrmConfiguration adrmConfiguration; @Autowired - public AdProjectTaskIdValidator(ProjectTaskRepository projectTaskRepository) { - this.projectTaskRepository = projectTaskRepository; + public AdProjectTaskIdValidator(ServiceRequestClient serviceRequestClient, AdrmConfiguration adrmConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.adrmConfiguration = adrmConfiguration; } @@ -57,12 +63,17 @@ public Map> validate(AdverseEventBulkRequest request) TaskSearch taskSearch = TaskSearch.builder() .id(taskIdList.isEmpty() ? null : taskIdList) .clientReferenceId(taskReferenceIdList.isEmpty() ? null : taskReferenceIdList).build(); - existingTasks = projectTaskRepository.find( - taskSearch, - taskReferenceIdList.size(), 0, tenantId,null, Boolean.TRUE - ); + TaskBulkResponse response = serviceRequestClient.fetchResult( + new StringBuilder(adrmConfiguration.getProjectTaskHost() + + adrmConfiguration.getProjectTaskSearchUrl() + + "&offset=0&tenantId=" + tenantId), + TaskSearchRequest.builder().requestInfo(request.getRequestInfo()).task(taskSearch).build(), + TaskBulkResponse.class); + existingTasks = response.getTasks(); } catch (QueryBuilderException e) { existingTasks = Collections.emptyList(); + } catch (Exception e) { + throw new RuntimeException(e); } List existingProjectTaskIds = existingTasks.stream().map(t -> t.getId()).collect(Collectors.toList()); List existingProjectReferenceTaskIds = existingTasks.stream().map(t -> t.getClientReferenceId()).collect(Collectors.toList()); diff --git a/health-services/adrm/src/main/resources/application.properties b/health-services/adrm/src/main/resources/application.properties index 32e7bcd698c..934a16f9ff1 100644 --- a/health-services/adrm/src/main/resources/application.properties +++ b/health-services/adrm/src/main/resources/application.properties @@ -80,7 +80,7 @@ egov.mdms.integration.enabled=true # HOUSEHOLD SERVICE -egov.household.host=http://localhost:9100 +egov.household.host= egov.search.household.url=/household/v1/_search # INDIVIDUAL SERVICE @@ -91,13 +91,11 @@ egov.search.individual.url= # use the value as "individual" to validate against individual service egov.user.id.validator=individual -# FACILITY SERVICE -egov.facility.host=http://localhost:8083 -egov.search.facility.url=/facility/v1/_search +# PROJECT SERVICE +egov.project.task.host=https://unified-dev.digit.org +egov.search.project.task.url=/project/task/v1/_search + -# Product Config -egov.product.host=http://localhost:8082 -egov.search.product.variant.url=/product/variant/v1/_search # PROJECT KAFKA CONFIG project.adverseevent.kafka.create.topic=save-adverse-event-topic @@ -117,7 +115,6 @@ project.search.max.limit=200 #location config egov.location.host=https://works-dev.digit.org -#egov.location.host=http://localhost:8082 egov.location.context.path=/egov-location/location/v11/ egov.location.endpoint=/boundarys/_search egov.location.code.query.param=codes From fb7fe7618e6af0dd2e89de57ea8292547a1c9b89 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Tue, 12 Sep 2023 15:26:37 +0530 Subject: [PATCH 143/283] HLM-3069 : copied changes from HLM-2915 for health-services-models changes for v1.0.8 --- .../main/java/org/egov/common/models/household/Household.java | 4 ++++ .../org/egov/common/models/household/HouseholdMember.java | 4 ++++ .../java/org/egov/common/models/individual/Individual.java | 4 ++++ .../java/org/egov/common/models/product/ProductVariant.java | 4 ---- .../org/egov/common/models/project/ProjectBeneficiary.java | 4 ++++ .../src/main/java/org/egov/common/models/project/Task.java | 4 ++++ .../src/main/java/org/egov/common/models/stock/Stock.java | 4 ++++ .../org/egov/common/models/stock/StockReconciliation.java | 4 ++++ 8 files changed, 28 insertions(+), 4 deletions(-) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java index 8cd95af33e9..56cdaeef0a4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java @@ -66,6 +66,10 @@ public class Household { @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + @JsonIgnore private Boolean hasErrors = Boolean.FALSE; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java index a63a0742100..ad103f7f9d0 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java @@ -71,6 +71,10 @@ public class HouseholdMember{ @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + @JsonIgnore private Boolean hasErrors = Boolean.FALSE; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java index 95958898c93..3bcaf631a4b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java @@ -127,6 +127,10 @@ public class Individual { @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + @JsonIgnore private Boolean hasErrors = Boolean.FALSE; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java index d0dec276973..02004d7ce43 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java @@ -76,12 +76,8 @@ public class ProductVariant { private Integer rowVersion = null; @JsonProperty("auditDetails") - @Valid - - private AuditDetails auditDetails = null; - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java index 25b96b211ba..0d060052b72 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java @@ -72,6 +72,10 @@ public class ProjectBeneficiary { @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + @JsonIgnore private Boolean hasErrors = Boolean.FALSE; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java index a3689eb112c..fbbc67ffb33 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java @@ -95,6 +95,10 @@ public class Task { @Valid private AuditDetails auditDetails = null; + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + @JsonProperty("status") private String status = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java index 97ac4f3e06e..102474fae63 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java @@ -102,5 +102,9 @@ public class Stock { @JsonProperty("dateOfEntry") private Long dateOfEntry = null; + + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java index 9b94d58a170..7e3ac004d0f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java @@ -84,5 +84,9 @@ public class StockReconciliation { @JsonProperty("auditDetails") @Valid private AuditDetails auditDetails = null; + + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; } From b2176c1fc14212dece0843363648dfc7ba701301 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 18 Sep 2023 15:04:22 +0530 Subject: [PATCH 144/283] HLM-3069 : changes in adverse event test, refactor adverse event code in health-services-models --- health-services/adrm/pom.xml | 6 + .../adrm/consumer/AdverseEventConsumer.java | 2 +- .../repository/AdverseEventRepository.java | 4 +- .../rowmapper/AdverseEventRowMapper.java | 2 +- .../adrm/service/AdverseEventService.java | 8 +- .../AdverseEventEnrichmentService.java | 4 +- .../adverseevent/AdIsDeletedValidator.java | 4 +- .../AdNonExistentEntityValidator.java | 4 +- .../adverseevent/AdNullIdValidator.java | 4 +- .../AdProjectTaskIdValidator.java | 4 +- .../adverseevent/AdUniqueEntityValidator.java | 4 +- .../AdverseEventApiController.java | 12 +- .../java/org/egov/adrm/TestConfiguration.java | 16 +++ .../AdverseEventRequestTestBuilder.java | 4 +- .../adrm}/helper/AdverseEventTestBuilder.java | 4 +- .../AdverseEventApiControllerTest.java | 130 ++++++++---------- .../adverseevent/AdverseEvent.java | 4 +- .../adverseevent/AdverseEventBulkRequest.java | 2 +- .../AdverseEventBulkResponse.java | 2 +- .../adverseevent/AdverseEventRequest.java | 3 +- .../adverseevent/AdverseEventResponse.java | 3 +- .../adverseevent/AdverseEventSearch.java | 2 +- .../AdverseEventSearchRequest.java | 2 +- .../repository/ProjectTaskRepository.java | 3 - 24 files changed, 120 insertions(+), 113 deletions(-) create mode 100644 health-services/adrm/src/test/java/org/egov/adrm/TestConfiguration.java rename health-services/{project/src/test/java/org/egov/project => adrm/src/test/java/org/egov/adrm}/helper/AdverseEventRequestTestBuilder.java (95%) rename health-services/{project/src/test/java/org/egov/project => adrm/src/test/java/org/egov/adrm}/helper/AdverseEventTestBuilder.java (96%) rename health-services/{project/src/test/java/org/egov/project => adrm/src/test/java/org/egov/adrm}/web/controllers/AdverseEventApiControllerTest.java (58%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{project => adrm}/adverseevent/AdverseEvent.java (96%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{project => adrm}/adverseevent/AdverseEventBulkRequest.java (94%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{project => adrm}/adverseevent/AdverseEventBulkResponse.java (94%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{project => adrm}/adverseevent/AdverseEventRequest.java (85%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{project => adrm}/adverseevent/AdverseEventResponse.java (85%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{project => adrm}/adverseevent/AdverseEventSearch.java (93%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{project => adrm}/adverseevent/AdverseEventSearchRequest.java (92%) diff --git a/health-services/adrm/pom.xml b/health-services/adrm/pom.xml index 391bede4da1..843e62de8af 100644 --- a/health-services/adrm/pom.xml +++ b/health-services/adrm/pom.xml @@ -109,7 +109,13 @@ javax.validation validation-api + + org.springframework.boot + spring-boot-starter-test + test + + repo.egovernments.org diff --git a/health-services/adrm/src/main/java/org/egov/adrm/consumer/AdverseEventConsumer.java b/health-services/adrm/src/main/java/org/egov/adrm/consumer/AdverseEventConsumer.java index 49900fea211..c5c761c6fa8 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/consumer/AdverseEventConsumer.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/consumer/AdverseEventConsumer.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; -import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; import org.egov.adrm.service.AdverseEventService; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/repository/AdverseEventRepository.java b/health-services/adrm/src/main/java/org/egov/adrm/repository/AdverseEventRepository.java index 64aa427dd0b..5cac554ce5c 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/repository/AdverseEventRepository.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/repository/AdverseEventRepository.java @@ -6,8 +6,8 @@ import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; -import org.egov.common.models.project.adverseevent.AdverseEvent; -import org.egov.common.models.project.adverseevent.AdverseEventSearch; +import org.egov.common.models.adrm.adverseevent.AdverseEvent; +import org.egov.common.models.adrm.adverseevent.AdverseEventSearch; import org.egov.common.models.project.Task; import org.egov.common.producer.Producer; import org.egov.adrm.repository.rowmapper.AdverseEventRowMapper; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/AdverseEventRowMapper.java b/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/AdverseEventRowMapper.java index 3c411ba3a7c..77dc8aed3e9 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/AdverseEventRowMapper.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/AdverseEventRowMapper.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.project.adverseevent.AdverseEvent; +import org.egov.common.models.adrm.adverseevent.AdverseEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java b/health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java index ff5d56da5a2..54b754ca746 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java @@ -12,10 +12,10 @@ import org.egov.adrm.validator.adverseevent.AdUniqueEntityValidator; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; -import org.egov.common.models.project.adverseevent.AdverseEvent; -import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; -import org.egov.common.models.project.adverseevent.AdverseEventRequest; -import org.egov.common.models.project.adverseevent.AdverseEventSearchRequest; +import org.egov.common.models.adrm.adverseevent.AdverseEvent; +import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.adrm.adverseevent.AdverseEventRequest; +import org.egov.common.models.adrm.adverseevent.AdverseEventSearchRequest; import org.egov.common.service.IdGenService; import org.egov.common.utils.CommonUtils; import org.egov.common.validator.Validator; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/AdverseEventEnrichmentService.java b/health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/AdverseEventEnrichmentService.java index 663ccd9840e..03c7506461b 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/AdverseEventEnrichmentService.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/AdverseEventEnrichmentService.java @@ -2,8 +2,8 @@ import lombok.extern.slf4j.Slf4j; import org.egov.adrm.config.AdrmConfiguration; -import org.egov.common.models.project.adverseevent.AdverseEvent; -import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.adrm.adverseevent.AdverseEvent; +import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; import org.egov.common.service.IdGenService; import org.egov.common.utils.CommonUtils; import org.egov.adrm.repository.AdverseEventRepository; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdIsDeletedValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdIsDeletedValidator.java index facb6593dde..1e66ad39329 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdIsDeletedValidator.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdIsDeletedValidator.java @@ -2,8 +2,8 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; -import org.egov.common.models.project.adverseevent.AdverseEvent; -import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.adrm.adverseevent.AdverseEvent; +import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNonExistentEntityValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNonExistentEntityValidator.java index 0d509f837a3..dca45c7b2a1 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNonExistentEntityValidator.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNonExistentEntityValidator.java @@ -4,8 +4,8 @@ import lombok.extern.slf4j.Slf4j; import org.egov.adrm.repository.AdverseEventRepository; import org.egov.common.models.Error; -import org.egov.common.models.project.adverseevent.AdverseEvent; -import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.adrm.adverseevent.AdverseEvent; +import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNullIdValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNullIdValidator.java index 6607d7b6d53..97712959369 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNullIdValidator.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNullIdValidator.java @@ -2,8 +2,8 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; -import org.egov.common.models.project.adverseevent.AdverseEvent; -import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.adrm.adverseevent.AdverseEvent; +import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java index f88f14ce0eb..2bb4ae054ad 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java @@ -9,8 +9,8 @@ import org.egov.common.models.project.TaskBulkResponse; import org.egov.common.models.project.TaskSearch; import org.egov.common.models.project.TaskSearchRequest; -import org.egov.common.models.project.adverseevent.AdverseEvent; -import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.adrm.adverseevent.AdverseEvent; +import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdUniqueEntityValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdUniqueEntityValidator.java index aa7be4b5eb0..823e1932938 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdUniqueEntityValidator.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdUniqueEntityValidator.java @@ -2,8 +2,8 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; -import org.egov.common.models.project.adverseevent.AdverseEvent; -import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.adrm.adverseevent.AdverseEvent; +import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java b/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java index ada116b5ec6..fc03ae0ab6e 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java @@ -4,12 +4,12 @@ import org.egov.adrm.config.AdrmConfiguration; import org.egov.adrm.service.AdverseEventService; import org.egov.common.contract.response.ResponseInfo; -import org.egov.common.models.project.adverseevent.AdverseEvent; -import org.egov.common.models.project.adverseevent.AdverseEventBulkRequest; -import org.egov.common.models.project.adverseevent.AdverseEventBulkResponse; -import org.egov.common.models.project.adverseevent.AdverseEventRequest; -import org.egov.common.models.project.adverseevent.AdverseEventResponse; -import org.egov.common.models.project.adverseevent.AdverseEventSearchRequest; +import org.egov.common.models.adrm.adverseevent.AdverseEvent; +import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.adrm.adverseevent.AdverseEventBulkResponse; +import org.egov.common.models.adrm.adverseevent.AdverseEventRequest; +import org.egov.common.models.adrm.adverseevent.AdverseEventResponse; +import org.egov.common.models.adrm.adverseevent.AdverseEventSearchRequest; import org.egov.common.producer.Producer; import org.egov.common.utils.ResponseInfoFactory; import org.springframework.http.HttpStatus; diff --git a/health-services/adrm/src/test/java/org/egov/adrm/TestConfiguration.java b/health-services/adrm/src/test/java/org/egov/adrm/TestConfiguration.java new file mode 100644 index 00000000000..591f0b3dbfc --- /dev/null +++ b/health-services/adrm/src/test/java/org/egov/adrm/TestConfiguration.java @@ -0,0 +1,16 @@ +package org.egov.adrm; + +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/health-services/project/src/test/java/org/egov/project/helper/AdverseEventRequestTestBuilder.java b/health-services/adrm/src/test/java/org/egov/adrm/helper/AdverseEventRequestTestBuilder.java similarity index 95% rename from health-services/project/src/test/java/org/egov/project/helper/AdverseEventRequestTestBuilder.java rename to health-services/adrm/src/test/java/org/egov/adrm/helper/AdverseEventRequestTestBuilder.java index 463355e4d88..10bbe9b574a 100644 --- a/health-services/project/src/test/java/org/egov/project/helper/AdverseEventRequestTestBuilder.java +++ b/health-services/adrm/src/test/java/org/egov/adrm/helper/AdverseEventRequestTestBuilder.java @@ -1,7 +1,7 @@ -package org.egov.project.helper; +package org.egov.adrm.helper; import org.egov.common.helper.RequestInfoTestBuilder; -import org.egov.common.models.project.adverseevent.AdverseEventRequest; +import org.egov.common.models.adrm.adverseevent.AdverseEventRequest; import java.util.ArrayList; diff --git a/health-services/project/src/test/java/org/egov/project/helper/AdverseEventTestBuilder.java b/health-services/adrm/src/test/java/org/egov/adrm/helper/AdverseEventTestBuilder.java similarity index 96% rename from health-services/project/src/test/java/org/egov/project/helper/AdverseEventTestBuilder.java rename to health-services/adrm/src/test/java/org/egov/adrm/helper/AdverseEventTestBuilder.java index 421381a2b55..aed221446cf 100644 --- a/health-services/project/src/test/java/org/egov/project/helper/AdverseEventTestBuilder.java +++ b/health-services/adrm/src/test/java/org/egov/adrm/helper/AdverseEventTestBuilder.java @@ -1,7 +1,7 @@ -package org.egov.project.helper; +package org.egov.adrm.helper; import org.egov.common.helper.AuditDetailsTestBuilder; -import org.egov.common.models.project.adverseevent.AdverseEvent; +import org.egov.common.models.adrm.adverseevent.AdverseEvent; import java.util.ArrayList; import java.util.Arrays; diff --git a/health-services/project/src/test/java/org/egov/project/web/controllers/AdverseEventApiControllerTest.java b/health-services/adrm/src/test/java/org/egov/adrm/web/controllers/AdverseEventApiControllerTest.java similarity index 58% rename from health-services/project/src/test/java/org/egov/project/web/controllers/AdverseEventApiControllerTest.java rename to health-services/adrm/src/test/java/org/egov/adrm/web/controllers/AdverseEventApiControllerTest.java index 022387b7ff7..5a44a77ecde 100644 --- a/health-services/project/src/test/java/org/egov/project/web/controllers/AdverseEventApiControllerTest.java +++ b/health-services/adrm/src/test/java/org/egov/adrm/web/controllers/AdverseEventApiControllerTest.java @@ -1,25 +1,26 @@ -package org.egov.project.web.controllers; +package org.egov.adrm.web.controllers; import com.fasterxml.jackson.databind.ObjectMapper; +import org.egov.adrm.TestConfiguration; +import org.egov.adrm.config.AdrmConfiguration; +import org.egov.adrm.helper.AdverseEventRequestTestBuilder; +import org.egov.adrm.helper.AdverseEventTestBuilder; +import org.egov.adrm.service.AdverseEventService; import org.egov.common.helper.RequestInfoTestBuilder; -import org.egov.common.models.project.adverseevent.AdverseEvent; -import org.egov.common.models.project.adverseevent.AdverseEventBulkResponse; -import org.egov.common.models.project.adverseevent.AdverseEventRequest; -import org.egov.common.models.project.adverseevent.AdverseEventResponse; -import org.egov.common.models.project.adverseevent.AdverseEventSearch; -import org.egov.common.models.project.adverseevent.AdverseEventSearchRequest; +import org.egov.common.models.adrm.adverseevent.AdverseEvent; +import org.egov.common.models.adrm.adverseevent.AdverseEventBulkResponse; +import org.egov.common.models.adrm.adverseevent.AdverseEventRequest; +import org.egov.common.models.adrm.adverseevent.AdverseEventResponse; +import org.egov.common.models.adrm.adverseevent.AdverseEventSearch; +import org.egov.common.models.adrm.adverseevent.AdverseEventSearchRequest; import org.egov.common.producer.Producer; -import org.egov.project.TestConfiguration; -import org.egov.project.config.ProjectConfiguration; -import org.egov.project.helper.AdverseEventRequestTestBuilder; -import org.egov.project.helper.AdverseEventTestBuilder; -import org.egov.project.service.AdverseEventService; -import org.egov.project.service.ProjectService; -import org.egov.project.service.ProjectTaskService; import org.egov.tracer.model.CustomException; import org.egov.tracer.model.ErrorRes; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -27,18 +28,13 @@ import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import static org.junit.jupiter.api.Assertions.*; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - @WebMvcTest(AdverseEventApiController.class) @Import(TestConfiguration.class) public class AdverseEventApiControllerTest { @@ -52,17 +48,11 @@ public class AdverseEventApiControllerTest { @MockBean private AdverseEventService adverseEventService; - @MockBean - private ProjectTaskService projectTaskService; - @MockBean private Producer producer; @MockBean - private ProjectConfiguration projectConfiguration; - - @MockBean - private ProjectService projectService; + AdrmConfiguration adrmConfiguration; @Test @DisplayName("should create adverse event and return with 202 accepted") @@ -72,20 +62,20 @@ void shouldCreateAdverseEventAndReturnWith202Accepted() throws Exception { .withApiOperationNotUpdate() .build(); List adverseEvents = getAdverseEvents(); - when(adverseEventService.create(any(AdverseEventRequest.class))).thenReturn(adverseEvents.get(0)); + Mockito.when(adverseEventService.create(ArgumentMatchers.any(AdverseEventRequest.class))).thenReturn(adverseEvents.get(0)); - final MvcResult result = mockMvc.perform(post("/task/adverse_event/v1/_create") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/task/adverse_event/v1/_create") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) - .andExpect(status().isAccepted()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.status().isAccepted()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andReturn(); String responseStr = result.getResponse().getContentAsString(); AdverseEventResponse response = objectMapper.readValue(responseStr, AdverseEventResponse.class); - assertNotNull(response.getAdverseEvent()); - assertNotNull(response.getAdverseEvent().getId()); - assertEquals("successful", response.getResponseInfo().getStatus()); + Assertions.assertNotNull(response.getAdverseEvent()); + Assertions.assertNotNull(response.getAdverseEvent().getId()); + Assertions.assertEquals("successful", response.getResponseInfo().getStatus()); } private List getAdverseEvents() { @@ -99,19 +89,19 @@ private List getAdverseEvents() { @Test @DisplayName("should send error response with error details with 400 bad request for create") void shouldSendErrorResWithErrorDetailsWith400BadRequestForCreate() throws Exception { - final MvcResult result = mockMvc.perform(post("/task/adverse_event/v1/_create") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/task/adverse_event/v1/_create") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(AdverseEventRequestTestBuilder.builder() .withOneAdverseEvent() .withBadTenantIdInOneAdverseEvent() .build()))) - .andExpect(status().isBadRequest()) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) .andReturn(); String responseStr = result.getResponse().getContentAsString(); ErrorRes response = objectMapper.readValue(responseStr, ErrorRes.class); - assertEquals(1, response.getErrors().size()); - assertTrue(response.getErrors().get(0).getCode().contains("tenantId")); + Assertions.assertEquals(1, response.getErrors().size()); + Assertions.assertTrue(response.getErrors().get(0).getCode().contains("tenantId")); } @Test @@ -122,39 +112,39 @@ void shouldUpdateAdverseEventAndReturnWith202Accepted() throws Exception { .withApiOperationNotNullAndNotCreate() .build(); AdverseEvent adverseEvent = AdverseEventTestBuilder.builder().withId().build(); - when(adverseEventService.update(any(AdverseEventRequest.class))).thenReturn(adverseEvent); + Mockito.when(adverseEventService.update(ArgumentMatchers.any(AdverseEventRequest.class))).thenReturn(adverseEvent); - final MvcResult result = mockMvc.perform(post("/task/adverse_event/v1/_update") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/task/adverse_event/v1/_update") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) - .andExpect(status().isAccepted()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.status().isAccepted()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andReturn(); String responseStr = result.getResponse().getContentAsString(); AdverseEventResponse response = objectMapper.readValue(responseStr, AdverseEventResponse.class); - assertNotNull(response.getAdverseEvent()); - assertNotNull(response.getAdverseEvent().getId()); - assertEquals("successful", response.getResponseInfo().getStatus()); + Assertions.assertNotNull(response.getAdverseEvent()); + Assertions.assertNotNull(response.getAdverseEvent().getId()); + Assertions.assertEquals("successful", response.getResponseInfo().getStatus()); } @Test @DisplayName("should send error response with error details with 400 bad request for update") void shouldSendErrorResWithErrorDetailsWith400BadRequestForUpdate() throws Exception { - final MvcResult result = mockMvc.perform(post("/task/adverse_event/v1/_update") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/task/adverse_event/v1/_update") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(AdverseEventRequestTestBuilder.builder() .withOneAdverseEventHavingId() .withBadTenantIdInOneAdverseEvent() .build()))) - .andExpect(status().isBadRequest()) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) .andReturn(); String responseStr = result.getResponse().getContentAsString(); ErrorRes response = objectMapper.readValue(responseStr, ErrorRes.class); - assertEquals(1, response.getErrors().size()); - assertTrue(response.getErrors().get(0).getCode().contains("tenantId")); + Assertions.assertEquals(1, response.getErrors().size()); + Assertions.assertTrue(response.getErrors().get(0).getCode().contains("tenantId")); } @Test @@ -165,25 +155,25 @@ void shouldAcceptSearchRequestAndReturnAdverseEvent() throws Exception { AdverseEventSearch.builder().taskId("some-task-id").build() ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); - when(adverseEventService.search(any(AdverseEventSearchRequest.class), - any(Integer.class), - any(Integer.class), - any(String.class), - any(Long.class), - any(Boolean.class))).thenReturn(Arrays.asList(AdverseEventTestBuilder.builder().withId().withAuditDetails().build())); + Mockito.when(adverseEventService.search(ArgumentMatchers.any(AdverseEventSearchRequest.class), + ArgumentMatchers.any(Integer.class), + ArgumentMatchers.any(Integer.class), + ArgumentMatchers.any(String.class), + ArgumentMatchers.any(Long.class), + ArgumentMatchers.any(Boolean.class))).thenReturn(Arrays.asList(AdverseEventTestBuilder.builder().withId().withAuditDetails().build())); - final MvcResult result = mockMvc.perform(post( + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post( "/task/adverse_event/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(adverseEventSearchRequest))) - .andExpect(status().isOk()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andReturn(); String responseStr = result.getResponse().getContentAsString(); AdverseEventBulkResponse response = objectMapper.readValue(responseStr, AdverseEventBulkResponse.class); - assertEquals(response.getAdverseEvents().size(), 1); + Assertions.assertEquals(response.getAdverseEvents().size(), 1); } @Test @@ -194,25 +184,25 @@ void shouldThrowExceptionIfNoResultFound() throws Exception { AdverseEventSearch.builder().taskId("some-task-id").build() ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); - when(adverseEventService.search(any(AdverseEventSearchRequest.class), - any(Integer.class), - any(Integer.class), - any(String.class), - any(Long.class), - any(Boolean.class))).thenThrow(new CustomException("NO_RESULT_FOUND", "No Adverse Event found.")); + Mockito.when(adverseEventService.search(ArgumentMatchers.any(AdverseEventSearchRequest.class), + ArgumentMatchers.any(Integer.class), + ArgumentMatchers.any(Integer.class), + ArgumentMatchers.any(String.class), + ArgumentMatchers.any(Long.class), + ArgumentMatchers.any(Boolean.class))).thenThrow(new CustomException("NO_RESULT_FOUND", "No Adverse Event found.")); - final MvcResult result = mockMvc.perform(post("/task/adverse_event/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/task/adverse_event/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(adverseEventSearchRequest))) - .andExpect(status().isBadRequest()) - .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andReturn(); String responseStr = result.getResponse().getContentAsString(); ErrorRes response = objectMapper.readValue(responseStr, ErrorRes.class); - assertEquals(response.getErrors().size(), 1); + Assertions.assertEquals(response.getErrors().size(), 1); } } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEvent.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEvent.java similarity index 96% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEvent.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEvent.java index a005aa32dde..f4552075402 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEvent.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEvent.java @@ -1,4 +1,4 @@ -package org.egov.common.models.project.adverseevent; +package org.egov.common.models.adrm.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -40,7 +40,7 @@ public class AdverseEvent { @JsonProperty("symptoms") @NotNull - @Min(1) + @Size(min=1) private List symptoms = null; @JsonProperty("tenantId") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventBulkRequest.java similarity index 94% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventBulkRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventBulkRequest.java index 6ceacad4bd3..a305d176c09 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventBulkRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.project.adverseevent; +package org.egov.common.models.adrm.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventBulkResponse.java similarity index 94% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventBulkResponse.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventBulkResponse.java index 6795c08982a..175bac96780 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventBulkResponse.java @@ -1,4 +1,4 @@ -package org.egov.common.models.project.adverseevent; +package org.egov.common.models.adrm.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventRequest.java similarity index 85% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventRequest.java index 491e44caaf9..af3404edfc5 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.project.adverseevent; +package org.egov.common.models.adrm.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -7,7 +7,6 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.egov.common.contract.request.RequestInfo; -import org.egov.common.models.project.adverseevent.AdverseEvent; import javax.validation.Valid; import javax.validation.constraints.NotNull; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventResponse.java similarity index 85% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventResponse.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventResponse.java index 2f6c90ece47..ce8612a20cf 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventResponse.java @@ -1,4 +1,4 @@ -package org.egov.common.models.project.adverseevent; +package org.egov.common.models.adrm.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -7,7 +7,6 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.egov.common.contract.response.ResponseInfo; -import org.egov.common.models.project.adverseevent.AdverseEvent; import javax.validation.Valid; import javax.validation.constraints.NotNull; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventSearch.java similarity index 93% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventSearch.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventSearch.java index 239db8fd4e5..bbf5d764698 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventSearch.java @@ -1,4 +1,4 @@ -package org.egov.common.models.project.adverseevent; +package org.egov.common.models.adrm.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventSearchRequest.java similarity index 92% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventSearchRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventSearchRequest.java index a87a9d71cd4..63fafd7a860 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/adverseevent/AdverseEventSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventSearchRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.project.adverseevent; +package org.egov.common.models.adrm.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java b/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java index 54febb70abe..9662f5318e6 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java +++ b/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java @@ -36,9 +36,6 @@ public class ProjectTaskRepository extends GenericRepository { @Autowired private TaskResourceRowMapper taskResourceRowMapper; - @Autowired - private AdverseEventRepository adverseEventRepository; - @Autowired protected ProjectTaskRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, From d700104837c5019ead52e87fdd2e50ea073bb9fa Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 20 Sep 2023 15:18:44 +0530 Subject: [PATCH 145/283] HLM-3069: HLM-4007 bug fixes --- .../adrm/validator/adverseevent/AdProjectTaskIdValidator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java index 2bb4ae054ad..c251edea29f 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java @@ -49,8 +49,8 @@ public Map> validate(AdverseEventBulkRequest request) log.info("validating project task id"); Map> errorDetailsMap = new HashMap<>(); List entities = request.getAdverseEvents(); - Map> tenantIdTaskIdMap = entities.stream().collect(Collectors.toMap(ad -> ad.getTenantId(), ad -> Arrays.asList(ad.getTaskId()), (e, d) -> { e.addAll(d); return e;})); - Map> tenantIdTaskReferenceIdMap = entities.stream().collect(Collectors.toMap(ad -> ad.getTenantId(), ad -> Arrays.asList(ad.getTaskClientReferenceId()), (e, d) -> { e.addAll(d); return e;})); + Map> tenantIdTaskIdMap = entities.stream().collect(Collectors.groupingBy(AdverseEvent::getTenantId, Collectors.mapping(AdverseEvent::getTaskId, Collectors.toList()))); + Map> tenantIdTaskReferenceIdMap = entities.stream().collect(Collectors.groupingBy(AdverseEvent::getTenantId, Collectors.mapping(AdverseEvent::getTaskClientReferenceId, Collectors.toList()))); List tenantIds = new ArrayList<>(tenantIdTaskIdMap.keySet()); tenantIds.forEach(tenantId -> { List taskIdList = tenantIdTaskIdMap.get(tenantId); From ea43860e747479aaf4172997b0b1e6b4907d10dc Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 20 Sep 2023 18:30:59 +0530 Subject: [PATCH 146/283] HLM-3069: added adverse event specs --- .../adverse-event-referral-management.yml | 446 ++++++++++++++++++ docs/health-api-specs/contracts/project.yml | 307 ------------ .../AdverseEventApiController.java | 16 +- .../AdverseEventApiControllerTest.java | 12 +- 4 files changed, 460 insertions(+), 321 deletions(-) create mode 100644 docs/health-api-specs/contracts/adverse-event-referral-management.yml diff --git a/docs/health-api-specs/contracts/adverse-event-referral-management.yml b/docs/health-api-specs/contracts/adverse-event-referral-management.yml new file mode 100644 index 00000000000..ecb327974ff --- /dev/null +++ b/docs/health-api-specs/contracts/adverse-event-referral-management.yml @@ -0,0 +1,446 @@ +swagger: '2.0' +info: + version: 1.0.0 + title: Adverse Event and Referral Management System + contact: + name: egovernments foundation + email: info@egovernments.org +schemes: + - https +x-common-path: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-0-0.yml +paths: + /adrm/adverse_event/v1/_create: + post: + summary: >- + Create adverse event for the project + description: >- + Create adverse event for the project + parameters: + - name: AdverseEvent + in: body + description: Capture details of Adverse Event + required: true + schema: + $ref: '#/definitions/AdverseEventRequest' + tags: + - Adverse Event + responses: + '202': + description: Create adverse event request has been accepted for creation. + schema: + $ref: '#/definitions/AdverseEventResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + + /adrm/adverse_event/v1/bulk/_create: + post: + summary: >- + Create adverse events for the project in bulk + description: >- + Create adverse events for the project in bulk + parameters: + - name: AdverseEvent + in: body + description: Capture details of Task + required: true + schema: + $ref: '#/definitions/AdverseEventBulkRequest' + tags: + - Adverse Event + responses: + '202': + description: Create adverse event request has been accepted for creation. + schema: + $ref: '#/definitions/BulkAcceptedResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + + /adrm/adverse_event/v1/_update: + post: + summary: >- + Adverse Event Request + description: >- + Adverse Event Request + parameters: + - name: AdverseEvent + in: body + description: Capture details of Existing adverse event + required: true + schema: + $ref: '#/definitions/AdverseEventRequest' + tags: + - Adverse Event + responses: + '202': + description: update averse event request has been accepted for update. + schema: + $ref: '#/definitions/AdverseEventResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + + /adrm/adverse_event/v1/bulk/_update: + post: + summary: >- + Adverse Event Request in bulk for a project + description: >- + Adverse Event Request in bulk for a project + parameters: + - name: AdverseEvent + in: body + description: Capture details of Existing Adverse Events + required: true + schema: + $ref: '#/definitions/AdverseEventBulkRequest' + tags: + - Adverse Event + responses: + '202': + description: update Adverse Events bulk request has been accepted for update. + schema: + $ref: '#/definitions/BulkAcceptedResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + + /adrm/adverse_event/v1/_delete: + post: + summary: >- + Soft delete Adverse Event for a project + description: >- + Soft delete Adverse Event for a project + parameters: + - name: AdverseEvent + in: body + description: Capture details of Existing Adverse Event + required: true + schema: + $ref: '#/definitions/AdverseEventRequest' + tags: + - Adverse Event + responses: + '202': + description: delete Adverse Event request has been accepted for deletion. + schema: + $ref: '#/definitions/AdverseEventResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + + /adrm/adverse_event/v1/bulk/_delete: + post: + summary: >- + Soft delete Adverse Events for a project + description: >- + Soft delete Adverse Events for a project + parameters: + - name: AdverseEvent + in: body + description: Capture details of Existing Adverse Event + required: true + schema: + $ref: '#/definitions/AdverseEventRequest' + tags: + - Adverse Event + responses: + '202': + description: delete bulk Adverse Event request has been accepted for deletion. + schema: + $ref: '#/definitions/BulkAcceptedResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + + /adrm/adverse_event/v1/_search: + post: + summary: >- + Search Adverse Event for Project + description: >- + Search Adverse Event for Project + parameters: + - name: AdverseEvent + in: body + description: Adverse Event Search. + required: true + schema: + $ref: '#/definitions/AdverseEventSearchRequest' + - $ref: '#/parameters/limit' + - $ref: '#/parameters/offset' + - $ref: '#/parameters/tenantId' + - $ref: '#/parameters/lastChangedSince' + - $ref: '#/parameters/includeDeleted' + tags: + - Adverse Event + responses: + '200': + description: Adverse Events. + schema: + $ref: '#/definitions/AdverseEventBulkResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + +parameters: + #TODO is tenantId required as a query param if it can be determine from requestInfo->userInfo + tenantId: + name: tenantId + in: query + description: Unique id for a tenant. + required: true + type: string + format: varchar + + lastChangedSince: + name: lastChangedSince + description: | + epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. + in: query + required: false + type: integer + format: int64 + + echoResource: + name: echoResource + in: query + type: boolean + required: false + default: true + description: Client can specify if the resource in request body needs to be sent back in the response. This is being used to limit amount of data that needs to flow back from the server to the client in low bandwidth scenarios. Server will always send the server generated id for validated requests. + + serverHandlesErrors: + name: serverHandlesErrors + in: query + type: boolean + required: false + default: false + description: Client can specify that it is incapable of handling any errors with the requests and server should route these for manual intervention if required. + + limit: + name: limit + description: Pagination - limit records in response + in: query + type: integer + minimum: 0 + maximum: 1000 #TODO review + required: true + + offset: + name: offset + description: Pagination - offset from which records should be returned in response + in: query + type: integer + minimum: 0 + required: true + + includeDeleted: + name: includeDeleted + description: Used in search APIs to specify if (soft) deleted records should be included in search results. + in: query + type: boolean + default: false + required: false + + includeEnded: + name: includeEnded + description: Used in project search API to specify if records past end date should be included in search results. + in: query + type: boolean + default: false + required: false + + includeAncestors: + name: includeAncestors + description: Used in project search API to specify if response should include project elements that are in the preceding hierarchy of matched projects. + in: query + type: boolean + default: false + required: false + + includeDescendants: + name: includeDescendants + description: Used in project search API to specify if response should include project elements that are in the following hierarchy of matched projects. + in: query + type: boolean + default: false + required: false + + createdFrom: + name: createdFrom + description: | + Used in project search API to limit the search results to only those projects whose creation date is after the specified 'createdFrom' date. + in: query + required: false + type: integer + format: int64 + + createdTo: + name: createdTo + description: | + Used in project search API to limit the search results to only those projects whose creation date is before the specified 'createdTo' date. + in: query + required: false + type: integer + format: int64 + +definitions: + boundaryCode: + $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/boundaryCode' + id: + $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/id' + idForSearch: + $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/idForSearch' + clientReferenceIdForSearch: + $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/clientReferenceIdForSearch' + clientReferenceId: + $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/clientReferenceId' + tenantId: + $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/tenantId' + eventTimestamp: + $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/eventTimestamp' + isDeleted: + $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/isDeleted' + rowVersion: + $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/rowVersion' + apiOperation: + $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/apiOperation' + additionalFields: + $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/additionalFields' + Address: + $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/Address' + + AdverseEvent: + type: object + required: + - tenantId + - taskId + - symptoms + properties: + id: + $ref: '#/definitions/id' + clientReferenceId: + $ref: '#/definitions/clientReferenceId' + tenantId: + $ref: '#/definitions/tenantId' + taskId: + type: string + minLength: 2 + maxLength: 64 + description: Unique TaskId + taskClientReferenceId: + type: string + example: "R-ID-1" + description: Unique Task Client Reference Id + symptoms: + type: array + items: + type: string + isDeleted: + $ref: '#/definitions/isDeleted' + rowVersion: + $ref: '#/definitions/rowVersion' + auditDetails: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails + clientAuditDetails: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails + + AdverseEventRequest: + type: object + properties: + RequestInfo: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + AdverseEvent: + type: object + $ref: '#/definitions/AdverseEvent' + required: + - RequestInfo + - AdverseEvent + + AdverseEventBulkRequest: + type: object + properties: + RequestInfo: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + AdverseEvents: + type: array + minItems: 1 + items: + $ref: '#/definitions/AdverseEvent' + required: + - RequestInfo + - AdverseEvents + + AdverseEventSearch: + type: object + properties: + id: + $ref: '#/definitions/idForSearch' + clientReferenceId: + $ref: '#/definitions/clientReferenceIdForSearch' + taskId: + type: string + minLength: 2 + maxLength: 64 + description: Unique TaskId + taskClientReferenceId: + type: string + example: "R-ID-1" + + AdverseEventSearchRequest: + type: object + properties: + RequestInfo: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + AdverseEvent: + $ref: '#/definitions/AdverseEventSearch' + required: + - RequestInfo + - AdverseEvent + + AdverseEventResponse: + type: object + properties: + ResponseInfo: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo + AdverseEvent: + type: object + $ref: '#/definitions/AdverseEvent' + required: + - ResponseInfo + - AdverseEvent + + AdverseEventBulkResponse: + type: object + properties: + ResponseInfo: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo + AdverseEvents: + type: array + items: + $ref: '#/definitions/AdverseEvent' + required: + - ResponseInfo + - AdverseEvents \ No newline at end of file diff --git a/docs/health-api-specs/contracts/project.yml b/docs/health-api-specs/contracts/project.yml index aa95a723cb1..5989673ca43 100644 --- a/docs/health-api-specs/contracts/project.yml +++ b/docs/health-api-specs/contracts/project.yml @@ -1029,193 +1029,6 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /project/task/adverse_event/v1/_create: - post: - summary: >- - Create adverse event for the project - description: >- - Create adverse event for the project - parameters: - - name: AdverseEvent - in: body - description: Capture details of Adverse Event - required: true - schema: - $ref: '#/definitions/AdverseEventRequest' - tags: - - Adverse Event - responses: - '202': - description: Create adverse event request has been accepted for creation. - schema: - $ref: '#/definitions/AdverseEventResponse' - '400': - description: Invalid Input body. - schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - - /project/task/adverse_event/v1/bulk/_create: - post: - summary: >- - Create adverse events for the project in bulk - description: >- - Create adverse events for the project in bulk - parameters: - - name: AdverseEvent - in: body - description: Capture details of Task - required: true - schema: - $ref: '#/definitions/AdverseEventBulkRequest' - tags: - - Adverse Event - responses: - '202': - description: Create adverse event request has been accepted for creation. - schema: - $ref: '#/definitions/BulkAcceptedResponse' - '400': - description: Invalid Input body. - schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - - /project/task/adverse_event/v1/_update: - post: - summary: >- - Adverse Event Request - description: >- - Adverse Event Request - parameters: - - name: AdverseEvent - in: body - description: Capture details of Existing adverse event - required: true - schema: - $ref: '#/definitions/AdverseEventRequest' - tags: - - Adverse Event - responses: - '202': - description: update averse event request has been accepted for update. - schema: - $ref: '#/definitions/AdverseEventResponse' - '400': - description: Invalid Input body. - schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - - /project/task/adverse_event/v1/bulk/_update: - post: - summary: >- - Adverse Event Request in bulk for a project - description: >- - Adverse Event Request in bulk for a project - parameters: - - name: AdverseEvent - in: body - description: Capture details of Existing Adverse Events - required: true - schema: - $ref: '#/definitions/AdverseEventBulkRequest' - tags: - - Adverse Event - responses: - '202': - description: update Adverse Events bulk request has been accepted for update. - schema: - $ref: '#/definitions/BulkAcceptedResponse' - '400': - description: Invalid Input body. - schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - - /project/task/adverse_event/v1/_delete: - post: - summary: >- - Soft delete Adverse Event for a project - description: >- - Soft delete Adverse Event for a project - parameters: - - name: AdverseEvent - in: body - description: Capture details of Existing Adverse Event - required: true - schema: - $ref: '#/definitions/AdverseEventRequest' - tags: - - Adverse Event - responses: - '202': - description: delete Adverse Event request has been accepted for deletion. - schema: - $ref: '#/definitions/AdverseEventResponse' - '400': - description: Invalid Input body. - schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - - /project/task/adverse_event/v1/bulk/_delete: - post: - summary: >- - Soft delete Adverse Events for a project - description: >- - Soft delete Adverse Events for a project - parameters: - - name: AdverseEvent - in: body - description: Capture details of Existing Adverse Event - required: true - schema: - $ref: '#/definitions/AdverseEventRequest' - tags: - - Adverse Event - responses: - '202': - description: delete bulk Adverse Event request has been accepted for deletion. - schema: - $ref: '#/definitions/BulkAcceptedResponse' - '400': - description: Invalid Input body. - schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - - /project/task/adverse_event/v1/_search: - post: - summary: >- - Search Adverse Event for Project - description: >- - Search Adverse Event for Project - parameters: - - name: AdverseEvent - in: body - description: Adverse Event Search. - required: true - schema: - $ref: '#/definitions/AdverseEventSearchRequest' - - $ref: '#/parameters/limit' - - $ref: '#/parameters/offset' - - $ref: '#/parameters/tenantId' - - $ref: '#/parameters/lastChangedSince' - - $ref: '#/parameters/includeDeleted' - tags: - - Adverse Event - responses: - '200': - description: Adverse Events. - schema: - $ref: '#/definitions/AdverseEventBulkResponse' - '400': - description: Invalid Input body. - schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - parameters: #TODO is tenantId required as a query param if it can be determine from requestInfo->userInfo @@ -2389,123 +2202,3 @@ definitions: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo required: - ResponseInfo - - AdverseEvent: - type: object - required: - - tenantId - - taskId - - symptoms - properties: - id: - $ref: '#/definitions/id' - clientReferenceId: - $ref: '#/definitions/clientReferenceId' - tenantId: - $ref: '#/definitions/tenantId' - taskId: - type: string - minLength: 2 - maxLength: 64 - description: Unique TaskId - taskClientReferenceId: - type: string - example: "R-ID-1" - description: Unique Task Client Reference Id - symptoms: - type: array - items: - type: string - isDeleted: - $ref: '#/definitions/isDeleted' - rowVersion: - $ref: '#/definitions/rowVersion' - auditDetails: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails - clientAuditDetails: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails - - AdverseEventRequest: - type: object - properties: - RequestInfo: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo - AdverseEvent: - type: object - $ref: '#/definitions/AdverseEvent' - required: - - RequestInfo - - AdverseEvent - - AdverseEventBulkRequest: - type: object - properties: - RequestInfo: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo - AdverseEvents: - type: array - minItems: 1 - items: - $ref: '#/definitions/AdverseEvent' - required: - - RequestInfo - - AdverseEvents - - AdverseEventSearch: - type: object - properties: - id: - $ref: '#/definitions/idForSearch' - clientReferenceId: - $ref: '#/definitions/clientReferenceIdForSearch' - taskId: - type: string - minLength: 2 - maxLength: 64 - description: Unique TaskId - taskClientReferenceId: - type: string - example: "R-ID-1" - - AdverseEventSearchRequest: - type: object - properties: - RequestInfo: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo - AdverseEvent: - $ref: '#/definitions/AdverseEventSearch' - required: - - RequestInfo - - AdverseEvent - - AdverseEventResponse: - type: object - properties: - ResponseInfo: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo - AdverseEvent: - type: object - $ref: '#/definitions/AdverseEvent' - required: - - ResponseInfo - - AdverseEvent - - AdverseEventBulkResponse: - type: object - properties: - ResponseInfo: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo - AdverseEvents: - type: array - items: - $ref: '#/definitions/AdverseEvent' - required: - - ResponseInfo - - AdverseEvents \ No newline at end of file diff --git a/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java b/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java index fc03ae0ab6e..a5be033a6e9 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java @@ -29,7 +29,7 @@ import java.util.List; @Controller -@RequestMapping("") +@RequestMapping("/adverse_event") @Validated public class AdverseEventApiController { @@ -53,7 +53,7 @@ public AdverseEventApiController( this.adrmConfiguration = adrmConfiguration; } - @RequestMapping(value = "/task/adverse_event/v1/_create", method = RequestMethod.POST) + @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) public ResponseEntity adverseEventV1CreatePost(@ApiParam(value = "Capture details of Adverse Event", required = true) @Valid @RequestBody AdverseEventRequest request) { AdverseEvent adverseEvent = adverseEventService.create(request); @@ -68,7 +68,7 @@ public ResponseEntity adverseEventV1CreatePost(@ApiParam(v - @RequestMapping(value = "/task/adverse_event/v1/bulk/_create", method = RequestMethod.POST) + @RequestMapping(value = "/v1/bulk/_create", method = RequestMethod.POST) public ResponseEntity adverseEventBulkV1CreatePost(@ApiParam(value = "Capture details of Adverse Event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); adverseEventService.putInCache(request.getAdverseEvents()); @@ -78,7 +78,7 @@ public ResponseEntity adverseEventBulkV1CreatePost(@ApiParam(value .createResponseInfo(request.getRequestInfo(), true)); } - @RequestMapping(value = "/task/adverse_event/v1/_search", method = RequestMethod.POST) + @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) public ResponseEntity adverseEventV1SearchPost(@ApiParam(value = "Adverse Event Search.", required = true) @Valid @RequestBody AdverseEventSearchRequest request, @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, @@ -93,7 +93,7 @@ public ResponseEntity adverseEventV1SearchPost(@ApiPar return ResponseEntity.status(HttpStatus.OK).body(response); } - @RequestMapping(value = "/task/adverse_event/v1/_update", method = RequestMethod.POST) + @RequestMapping(value = "/v1/_update", method = RequestMethod.POST) public ResponseEntity adverseEventV1UpdatePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventRequest request) { AdverseEvent adverseEvent = adverseEventService.update(request); @@ -107,7 +107,7 @@ public ResponseEntity adverseEventV1UpdatePost(@ApiParam(v } - @RequestMapping(value = "/task/adverse_event/v1/bulk/_update", method = RequestMethod.POST) + @RequestMapping(value = "/v1/bulk/_update", method = RequestMethod.POST) public ResponseEntity adverseEventV1BulkUpdatePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); producer.push(adrmConfiguration.getUpdateAdverseEventBulkTopic(), request); @@ -116,7 +116,7 @@ public ResponseEntity adverseEventV1BulkUpdatePost(@ApiParam(value .createResponseInfo(request.getRequestInfo(), true)); } - @RequestMapping(value = "/task/adverse_event/v1/_delete", method = RequestMethod.POST) + @RequestMapping(value = "/v1/_delete", method = RequestMethod.POST) public ResponseEntity adverseEventV1DeletePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventRequest request) { AdverseEvent adverseEvent = adverseEventService.delete(request); @@ -130,7 +130,7 @@ public ResponseEntity adverseEventV1DeletePost(@ApiParam(v } - @RequestMapping(value = "/task/adverse_event/v1/bulk/_delete", method = RequestMethod.POST) + @RequestMapping(value = "/v1/bulk/_delete", method = RequestMethod.POST) public ResponseEntity adverseEventV1BulkDeletePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); producer.push(adrmConfiguration.getDeleteAdverseEventBulkTopic(), request); diff --git a/health-services/adrm/src/test/java/org/egov/adrm/web/controllers/AdverseEventApiControllerTest.java b/health-services/adrm/src/test/java/org/egov/adrm/web/controllers/AdverseEventApiControllerTest.java index 5a44a77ecde..f6c95c063fc 100644 --- a/health-services/adrm/src/test/java/org/egov/adrm/web/controllers/AdverseEventApiControllerTest.java +++ b/health-services/adrm/src/test/java/org/egov/adrm/web/controllers/AdverseEventApiControllerTest.java @@ -64,7 +64,7 @@ void shouldCreateAdverseEventAndReturnWith202Accepted() throws Exception { List adverseEvents = getAdverseEvents(); Mockito.when(adverseEventService.create(ArgumentMatchers.any(AdverseEventRequest.class))).thenReturn(adverseEvents.get(0)); - final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/task/adverse_event/v1/_create") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/adverse_event/v1/_create") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andExpect(MockMvcResultMatchers.status().isAccepted()) @@ -89,7 +89,7 @@ private List getAdverseEvents() { @Test @DisplayName("should send error response with error details with 400 bad request for create") void shouldSendErrorResWithErrorDetailsWith400BadRequestForCreate() throws Exception { - final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/task/adverse_event/v1/_create") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/adverse_event/v1/_create") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(AdverseEventRequestTestBuilder.builder() .withOneAdverseEvent() @@ -114,7 +114,7 @@ void shouldUpdateAdverseEventAndReturnWith202Accepted() throws Exception { AdverseEvent adverseEvent = AdverseEventTestBuilder.builder().withId().build(); Mockito.when(adverseEventService.update(ArgumentMatchers.any(AdverseEventRequest.class))).thenReturn(adverseEvent); - final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/task/adverse_event/v1/_update") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/adverse_event/v1/_update") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andExpect(MockMvcResultMatchers.status().isAccepted()) @@ -131,7 +131,7 @@ void shouldUpdateAdverseEventAndReturnWith202Accepted() throws Exception { @Test @DisplayName("should send error response with error details with 400 bad request for update") void shouldSendErrorResWithErrorDetailsWith400BadRequestForUpdate() throws Exception { - final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/task/adverse_event/v1/_update") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/adverse_event/v1/_update") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(AdverseEventRequestTestBuilder.builder() .withOneAdverseEventHavingId() @@ -163,7 +163,7 @@ void shouldAcceptSearchRequestAndReturnAdverseEvent() throws Exception { ArgumentMatchers.any(Boolean.class))).thenReturn(Arrays.asList(AdverseEventTestBuilder.builder().withId().withAuditDetails().build())); final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post( - "/task/adverse_event/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") + "/adverse_event/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(adverseEventSearchRequest))) .andExpect(MockMvcResultMatchers.status().isOk()) @@ -192,7 +192,7 @@ void shouldThrowExceptionIfNoResultFound() throws Exception { ArgumentMatchers.any(Boolean.class))).thenThrow(new CustomException("NO_RESULT_FOUND", "No Adverse Event found.")); - final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/task/adverse_event/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/adverse_event/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(adverseEventSearchRequest))) .andExpect(MockMvcResultMatchers.status().isBadRequest()) From 982066216f53f3be796fea22cd0cc5ee0b59ebcf Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Thu, 21 Sep 2023 16:44:43 +0530 Subject: [PATCH 147/283] HLM-3069: dockerfile, migration.sh, adrm persister added, new fields in adverse event project beneficiary, client createby lastmodifiedby added. added mainconfig --- .../egov/adrm/config/AdrmConfiguration.java | 7 +- .../egov/adrm/config/MainConfiguration.java | 93 +++++++++++++++++++ .../rowmapper/AdverseEventRowMapper.java | 28 +++--- .../AdProjectTaskIdValidator.java | 79 ++++++++++++---- .../AdverseEventApiController.java | 4 +- .../src/main/resources/adrm-persister.yml | 71 ++++++++++++++ .../src/main/resources/application.properties | 33 +++---- .../adrm/src/main/resources/db/Dockerfile | 9 ++ .../adrm/src/main/resources/db/migrate.sh | 3 + .../adrm/adverseevent/AdverseEvent.java | 9 +- .../main/resources/project-task-persister.yml | 61 ------------ 11 files changed, 285 insertions(+), 112 deletions(-) create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/config/MainConfiguration.java create mode 100644 health-services/adrm/src/main/resources/adrm-persister.yml create mode 100644 health-services/adrm/src/main/resources/db/Dockerfile create mode 100644 health-services/adrm/src/main/resources/db/migrate.sh diff --git a/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java b/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java index 145616a6255..3231a4df589 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java @@ -33,9 +33,12 @@ public class AdrmConfiguration { @Value("${project.adverseevent.consumer.bulk.delete.topic}") private String deleteAdverseEventBulkTopic; - @Value("${egov.project.task.host}") - private String projectTaskHost; + @Value("${egov.project.host}") + private String projectHost; @Value("${egov.search.project.task.url}") private String projectTaskSearchUrl; + + @Value("${egov.search.project.beneficiary.url}") + private String projectBeneficiarySearchUrl; } diff --git a/health-services/adrm/src/main/java/org/egov/adrm/config/MainConfiguration.java b/health-services/adrm/src/main/java/org/egov/adrm/config/MainConfiguration.java new file mode 100644 index 00000000000..49e709427b8 --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/config/MainConfiguration.java @@ -0,0 +1,93 @@ +package org.egov.adrm.config; + +import com.fasterxml.jackson.annotation.JsonAutoDetect; +import com.fasterxml.jackson.annotation.JsonTypeInfo; +import com.fasterxml.jackson.annotation.PropertyAccessor; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; +import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import org.egov.tracer.config.TracerConfiguration; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.RedisStandaloneConfiguration; +import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; + +import javax.annotation.PostConstruct; +import java.util.TimeZone; + +@Import({TracerConfiguration.class}) +@Configuration +@ComponentScan(basePackages = {"org.egov"}) +public class MainConfiguration { + + @Value("${app.timezone}") + private String timeZone; + + @Value("${spring.redis.host}") + private String redisHost; + + @PostConstruct + public void initialize() { + TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); + } + + @Bean + @Qualifier("objectMapper") + public ObjectMapper objectMapper(){ + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).setTimeZone(TimeZone.getTimeZone(timeZone)); + objectMapper.registerModule(new JavaTimeModule()); + return objectMapper; + } + + @Bean + @Qualifier("redisObjectMapper") + public ObjectMapper redisObjectMapper() { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); + objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, + ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY); + objectMapper.registerModule(new JavaTimeModule()); + return objectMapper; + } + + @Bean + public MappingJackson2HttpMessageConverter jacksonConverter(ObjectMapper objectMapper) { + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); + converter.setObjectMapper(objectMapper); + return converter; + } + + @Bean + public RedisConnectionFactory redisConnectionFactory() { + RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(); + redisStandaloneConfiguration.setHostName(redisHost); + return new JedisConnectionFactory(redisStandaloneConfiguration); + } + + + @Bean + public RedisTemplate redisTemplate(@Qualifier("redisObjectMapper") ObjectMapper redisObjectMapper, + RedisConnectionFactory redisConnectionFactory) { + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(Object.class); + serializer.setObjectMapper(redisObjectMapper); + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(serializer); + redisTemplate.setHashKeySerializer(new StringRedisSerializer()); + redisTemplate.setHashValueSerializer(serializer); + redisTemplate.afterPropertiesSet(); + return redisTemplate; + } +} \ No newline at end of file diff --git a/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/AdverseEventRowMapper.java b/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/AdverseEventRowMapper.java index 77dc8aed3e9..edbf7e23af6 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/AdverseEventRowMapper.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/AdverseEventRowMapper.java @@ -21,28 +21,34 @@ public class AdverseEventRowMapper implements RowMapper { @Override public AdverseEvent mapRow(ResultSet resultSet, int i) throws SQLException { try { + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("clientCreatedBy")) + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build(); return AdverseEvent.builder() .id(resultSet.getString("id")) .clientReferenceId(resultSet.getString("clientreferenceid")) .taskId(resultSet.getString("taskId")) .taskClientReferenceId(resultSet.getString("taskClientreferenceid")) + .projectBeneficiaryId(resultSet.getString("projectBeneficiaryId")) + .projectBeneficiaryClientReferenceId(resultSet.getString("projectBeneficiaryClientReferenceId")) .tenantId(resultSet.getString("tenantid")) .symptoms(resultSet.getString("symptoms") == null ? null : objectMapper.readValue(resultSet.getString("symptoms"), ArrayList.class)) .rowVersion(resultSet.getInt("rowversion")) .isDeleted(resultSet.getBoolean("isdeleted")) - .auditDetails(AuditDetails.builder() - .createdBy(resultSet.getString("createdBy")) - .createdTime(resultSet.getLong("createdTime")) - .lastModifiedBy(resultSet.getString("lastModifiedBy")) - .lastModifiedTime(resultSet.getLong("lastModifiedTime")) - .build()) - .clientAuditDetails(AuditDetails.builder() - .createdTime(resultSet.getLong("clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) - .build()) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) .build(); } catch (JsonProcessingException e) { - throw new RuntimeException(e); + throw new SQLException(e); } } } diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java index c251edea29f..f6798411721 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java @@ -5,6 +5,12 @@ import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; +import org.egov.common.models.project.BeneficiaryBulkRequest; +import org.egov.common.models.project.BeneficiaryBulkResponse; +import org.egov.common.models.project.BeneficiaryResponse; +import org.egov.common.models.project.BeneficiarySearchRequest; +import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.models.project.ProjectBeneficiarySearch; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskBulkResponse; import org.egov.common.models.project.TaskSearch; @@ -49,44 +55,79 @@ public Map> validate(AdverseEventBulkRequest request) log.info("validating project task id"); Map> errorDetailsMap = new HashMap<>(); List entities = request.getAdverseEvents(); - Map> tenantIdTaskIdMap = entities.stream().collect(Collectors.groupingBy(AdverseEvent::getTenantId, Collectors.mapping(AdverseEvent::getTaskId, Collectors.toList()))); - Map> tenantIdTaskReferenceIdMap = entities.stream().collect(Collectors.groupingBy(AdverseEvent::getTenantId, Collectors.mapping(AdverseEvent::getTaskClientReferenceId, Collectors.toList()))); - List tenantIds = new ArrayList<>(tenantIdTaskIdMap.keySet()); + Map> tenantIdAdverseEventMap = entities.stream().collect(Collectors.groupingBy(AdverseEvent::getTenantId)); + List tenantIds = new ArrayList<>(tenantIdAdverseEventMap.keySet()); tenantIds.forEach(tenantId -> { - List taskIdList = tenantIdTaskIdMap.get(tenantId); - List taskReferenceIdList = tenantIdTaskReferenceIdMap.get(tenantId); - if (!taskIdList.isEmpty() || !taskReferenceIdList.isEmpty()) { - List existingTasks; + List adverseEventList = tenantIdAdverseEventMap.get(tenantId); + if (!adverseEventList.isEmpty()) { + List existingTasks = null; + List existingProjectBeneficiaries = null; + final List projectBeneficiaryIdList = new ArrayList<>(); + final List projectBeneficiaryClientReferenceIdList = new ArrayList<>(); + final List taskIdList = new ArrayList<>(); + final List taskClientReferenceIdList = new ArrayList<>(); try { - taskIdList = taskIdList.stream().filter(Objects::nonNull).collect(Collectors.toList()); - taskReferenceIdList = taskReferenceIdList.stream().filter(Objects::nonNull).collect(Collectors.toList()); + adverseEventList.forEach(adverseEvent -> { + addIgnoreNull(projectBeneficiaryIdList, adverseEvent.getProjectBeneficiaryId()); + addIgnoreNull(projectBeneficiaryClientReferenceIdList, adverseEvent.getProjectBeneficiaryClientReferenceId()); + addIgnoreNull(taskIdList, adverseEvent.getTaskId()); + addIgnoreNull(taskClientReferenceIdList, adverseEvent.getTaskClientReferenceId()); + }); TaskSearch taskSearch = TaskSearch.builder() .id(taskIdList.isEmpty() ? null : taskIdList) - .clientReferenceId(taskReferenceIdList.isEmpty() ? null : taskReferenceIdList).build(); - TaskBulkResponse response = serviceRequestClient.fetchResult( - new StringBuilder(adrmConfiguration.getProjectTaskHost() + .clientReferenceId(taskClientReferenceIdList.isEmpty() ? null : taskClientReferenceIdList).build(); + TaskBulkResponse taskBulkResponse = serviceRequestClient.fetchResult( + new StringBuilder(adrmConfiguration.getProjectHost() + adrmConfiguration.getProjectTaskSearchUrl() + "&offset=0&tenantId=" + tenantId), TaskSearchRequest.builder().requestInfo(request.getRequestInfo()).task(taskSearch).build(), - TaskBulkResponse.class); - existingTasks = response.getTasks(); + TaskBulkResponse.class + ); + existingTasks = taskBulkResponse.getTasks(); + ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() + .id(projectBeneficiaryIdList.isEmpty() ? null : projectBeneficiaryIdList) + .clientReferenceId(projectBeneficiaryClientReferenceIdList.isEmpty() ? null : projectBeneficiaryClientReferenceIdList) + .build(); + BeneficiaryBulkResponse beneficiaryBulkResponse = serviceRequestClient.fetchResult( + new StringBuilder(adrmConfiguration.getProjectHost() + + adrmConfiguration.getProjectBeneficiarySearchUrl() + + "&offset=0&tenantId=" + tenantId), + BeneficiarySearchRequest.builder().requestInfo(request.getRequestInfo()).projectBeneficiary(projectBeneficiarySearch).build(), + BeneficiaryBulkResponse.class + ); + existingProjectBeneficiaries = beneficiaryBulkResponse.getProjectBeneficiaries(); } catch (QueryBuilderException e) { - existingTasks = Collections.emptyList(); + if(existingTasks == null) existingTasks = Collections.emptyList(); + existingProjectBeneficiaries = Collections.emptyList(); } catch (Exception e) { throw new RuntimeException(e); } - List existingProjectTaskIds = existingTasks.stream().map(t -> t.getId()).collect(Collectors.toList()); - List existingProjectReferenceTaskIds = existingTasks.stream().map(t -> t.getClientReferenceId()).collect(Collectors.toList()); + final List existingProjectBeneficiaryIds = new ArrayList<>(); + final List existingProjectBeneficiaryClientReferenceIds = new ArrayList<>(); + existingProjectBeneficiaries.forEach(projectBeneficiary -> { + existingProjectBeneficiaryIds.add(projectBeneficiary.getId()); + existingProjectBeneficiaryClientReferenceIds.add(projectBeneficiary.getClientReferenceId()); + }); + final List existingProjectTaskIds = existingTasks.stream().map(Task::getId).collect(Collectors.toList()); + final List existingProjectReferenceTaskIds = existingTasks.stream().map(Task::getClientReferenceId).collect(Collectors.toList()); List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> - !existingProjectTaskIds.contains(entity.getTaskId()) && !existingProjectReferenceTaskIds.contains(entity.getTaskClientReferenceId()) ) - .collect(Collectors.toList()); + !existingProjectTaskIds.contains(entity.getTaskId()) + && !existingProjectReferenceTaskIds.contains(entity.getTaskClientReferenceId()) + && !existingProjectBeneficiaryIds.contains(entity.getProjectBeneficiaryId()) + && !existingProjectBeneficiaryClientReferenceIds.contains(entity.getProjectBeneficiaryClientReferenceId()) + ).collect(Collectors.toList()); invalidEntities.forEach(adverseEvent -> { Error error = getErrorForNonExistentEntity(); populateErrorDetails(adverseEvent, error, errorDetailsMap); }); + } }); return errorDetailsMap; } + + private void addIgnoreNull(List list, String item) { + if(Objects.nonNull(item)) list.add(item); + } } diff --git a/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java b/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java index a5be033a6e9..68f3963ff63 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java @@ -86,9 +86,9 @@ public ResponseEntity adverseEventV1SearchPost(@ApiPar @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { - List households = adverseEventService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); + List adverseEvents = adverseEventService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); AdverseEventBulkResponse response = AdverseEventBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).adverseEvents(households).build(); + .createResponseInfo(request.getRequestInfo(), true)).adverseEvents(adverseEvents).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/adrm/src/main/resources/adrm-persister.yml b/health-services/adrm/src/main/resources/adrm-persister.yml new file mode 100644 index 00000000000..f1780c39448 --- /dev/null +++ b/health-services/adrm/src/main/resources/adrm-persister.yml @@ -0,0 +1,71 @@ +serviceMaps: + serviceName: adrm + mappings: + - version: 1.0 + description: Saves a adverse event + fromTopic: save-adverse-event-topic + isTransaction: true + queryMaps: + - query: INSERT INTO ADVERSE_EVENT(id, clientReferenceId, tenantId, taskId, taskClientReferenceId, projectBeneficiaryId, projectBeneficiaryClientReferenceId,symptoms, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedBy, clientCreatedTime, clientLastModifiedBy, clientLastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); + basePath: $.* + jsonMaps: + - jsonPath: $.*.id + - jsonPath: $.*.clientReferenceId + - jsonPath: $.*.tenantId + - jsonPath: $.*.taskId + - jsonPath: $.*.taskClientReferenceId + - jsonPath: $.*.projectBeneficiaryId + - jsonPath: $.*.projectBeneficiaryClientReferenceId + - jsonPath: $.*.symptoms + type: JSON + dbType: JSONB + - jsonPath: $.*.auditDetails.createdBy + - jsonPath: $.*.auditDetails.createdTime + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.createdBy + - jsonPath: $.*.clientAuditDetails.createdTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + + - version: 1.0 + description: Updates a adverse event + fromTopic: update-adverse-event-topic + isTransaction: true + queryMaps: + - query: UPDATE ADVERSE_EVENT SET tenantId = ?, taskId = ?, taskClientReferenceId = ?, projectBeneficiaryId = ?, projectBeneficiaryClientReferenceId = ?, symptoms = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.tenantId + - jsonPath: $.*.taskId + - jsonPath: $.*.taskClientReferenceId + - jsonPath: $.*.projectBeneficiaryId + - jsonPath: $.*.projectBeneficiaryClientReferenceId + - jsonPath: $.*.symptoms + type: JSON + dbType: JSONB + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - jsonPath: $.*.id + + - version: 1.0 + description: Deletes a adverse event + fromTopic: delete-adverse-event-topic + isTransaction: true + queryMaps: + - query: UPDATE ADVERSE_EVENT SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - jsonPath: $.*.id diff --git a/health-services/adrm/src/main/resources/application.properties b/health-services/adrm/src/main/resources/application.properties index 934a16f9ff1..18f90dea65a 100644 --- a/health-services/adrm/src/main/resources/application.properties +++ b/health-services/adrm/src/main/resources/application.properties @@ -24,7 +24,7 @@ spring.flyway.table=public spring.flyway.baseline-on-migrate=true spring.flyway.outOfOrder=true spring.flyway.locations=classpath:/db/migration/main -spring.flyway.enabled=true +spring.flyway.enabled=false # TRACER CONFIG # KAFKA SERVER CONFIG @@ -55,7 +55,8 @@ kafka.producer.config.buffer_memory_config=33554432 egov.idgen.host=http://localhost:8081/ egov.idgen.path=egov-idgen/id/_generate egov.idgen.integration.enabled=true -project.task.idgen.id.format=project.task.id +adrm.adverseevent.idgen.id.format=adrm.adverseevent.id +adrm.referral.idgen.id.format=adrm.referral.id idgen.project.beneficiary.id.format=project.beneficiary.id project.staff.idgen.id.format=project.staff.id project.facility.idgen.id.format=project.facility.id @@ -66,13 +67,13 @@ project.resource.idgen.id.format=project.resource.id kafka.topics.consumer=project-consumer-topic # USER CONFIG -egov.user.host=https://dev.digit.org +egov.user.host=https://unified-dev.digit.org #egov.user.host=http://localhost:8286 egov.search.user.url=/user/_search egov.user.integration.enabled=true # MDMS CONFIG -egov.mdms.host=https://dev.digit.org +egov.mdms.host=https://unified-dev.digit.org egov.mdms.search.endpoint=/egov-mdms-service/v1/_search egov.mdms.master.name=project_master egov.mdms.module.name=project @@ -92,25 +93,25 @@ egov.search.individual.url= egov.user.id.validator=individual # PROJECT SERVICE -egov.project.task.host=https://unified-dev.digit.org +egov.project.host=https://unified-dev.digit.org egov.search.project.task.url=/project/task/v1/_search +egov.search.project.beneficiary.url=/project/beneficiary/v1/_search +# ADRM KAFKA CONFIG +adrm.adverseevent.kafka.create.topic=save-adverse-event-topic +adrm.adverseevent.kafka.update.topic=update-adverse-event-topic +adrm.adverseevent.kafka.delete.topic=delete-adverse-event-topic -# PROJECT KAFKA CONFIG -project.adverseevent.kafka.create.topic=save-adverse-event-topic -project.adverseevent.kafka.update.topic=update-adverse-event-topic -project.adverseevent.kafka.delete.topic=delete-adverse-event-topic - -project.adverseevent.consumer.bulk.create.topic=save-adverse-event-bulk-topic -project.adverseevent.consumer.bulk.update.topic=update-adverse-event-bulk-topic -project.adverseevent.consumer.bulk.delete.topic=delete-adverse-event-bulk-topic +adrm.adverseevent.consumer.bulk.create.topic=save-adverse-event-bulk-topic +adrm.adverseevent.consumer.bulk.update.topic=update-adverse-event-bulk-topic +adrm.adverseevent.consumer.bulk.delete.topic=delete-adverse-event-bulk-topic search.api.limit=1000 -project.default.offset=0 -project.default.limit=100 -project.search.max.limit=200 +adrm.default.offset=0 +adrm.default.limit=100 +adrm.search.max.limit=200 #location config diff --git a/health-services/adrm/src/main/resources/db/Dockerfile b/health-services/adrm/src/main/resources/db/Dockerfile new file mode 100644 index 00000000000..60fc07ce69f --- /dev/null +++ b/health-services/adrm/src/main/resources/db/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"] \ No newline at end of file diff --git a/health-services/adrm/src/main/resources/db/migrate.sh b/health-services/adrm/src/main/resources/db/migrate.sh new file mode 100644 index 00000000000..43960b25cdb --- /dev/null +++ b/health-services/adrm/src/main/resources/db/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/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEvent.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEvent.java index f4552075402..a85c8b89170 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEvent.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEvent.java @@ -10,7 +10,6 @@ import lombok.NoArgsConstructor; import javax.validation.Valid; -import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import java.util.List; @@ -38,6 +37,14 @@ public class AdverseEvent { @Size(min = 2, max = 64) private String taskClientReferenceId = null; + @JsonProperty("projectBeneficiaryId") + @Size(min = 2, max = 64) + private String projectBeneficiaryId = null; + + @JsonProperty("projectBeneficiaryClientReferenceId") + @Size(min = 2, max = 64) + private String projectBeneficiaryClientReferenceId = null; + @JsonProperty("symptoms") @NotNull @Size(min=1) diff --git a/health-services/project/src/main/resources/project-task-persister.yml b/health-services/project/src/main/resources/project-task-persister.yml index a177dacedf1..76b7b467397 100644 --- a/health-services/project/src/main/resources/project-task-persister.yml +++ b/health-services/project/src/main/resources/project-task-persister.yml @@ -156,64 +156,3 @@ serviceMaps: - jsonPath: $.*.auditDetails.lastModifiedTime - jsonPath: $.*.isDeleted - jsonPath: $.*.id - - - version: 1.0 - description: Saves a adverse event - fromTopic: save-adverse-event-topic - isTransaction: true - queryMaps: - - query: INSERT INTO ADVERSE_EVENT(id, clientReferenceId, tenantId, taskId, taskClientReferenceId, symptoms, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedTime, clientLastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?); - basePath: $.* - jsonMaps: - - jsonPath: $.*.id - - jsonPath: $.*.clientReferenceId - - jsonPath: $.*.tenantId - - jsonPath: $.*.taskId - - jsonPath: $.*.taskClientReferenceId - - jsonPath: $.*.symptoms - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.createdBy - - jsonPath: $.*.auditDetails.createdTime - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.clientAuditDetails.createdTime - - jsonPath: $.*.clientAuditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - - version: 1.0 - description: Updates a adverse event - fromTopic: update-adverse-event-topic - isTransaction: true - queryMaps: - - query: UPDATE ADVERSE_EVENT SET tenantId = ?, taskId = ?, taskClientReferenceId = ?, symptoms = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.tenantId - - jsonPath: $.*.taskId - - jsonPath: $.*.taskClientReferenceId - - jsonPath: $.*.symptoms - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.clientAuditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id - - - version: 1.0 - description: Deletes a adverse event - fromTopic: delete-adverse-event-topic - isTransaction: true - queryMaps: - - query: UPDATE ADVERSE_EVENT SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.clientAuditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id From 49417961f34fe525a2d69d8e69d185d2376778cd Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 22 Sep 2023 16:30:04 +0530 Subject: [PATCH 148/283] HLM-3069: updated AdrmConfiguration.java --- .../java/org/egov/adrm/config/AdrmConfiguration.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java b/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java index 3231a4df589..cb98a038c73 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java @@ -15,22 +15,22 @@ @Builder @Component public class AdrmConfiguration { - @Value("${project.adverseevent.kafka.create.topic}") + @Value("${adrm.adverseevent.kafka.create.topic}") private String createAdverseEventTopic; - @Value("${project.adverseevent.kafka.update.topic}") + @Value("${adrm.adverseevent.kafka.update.topic}") private String updateAdverseEventTopic; - @Value("${project.adverseevent.kafka.delete.topic}") + @Value("${adrm.adverseevent.kafka.delete.topic}") private String deleteAdverseEventTopic; - @Value("${project.adverseevent.consumer.bulk.create.topic}") + @Value("${adrm.adverseevent.consumer.bulk.create.topic}") private String createAdverseEventBulkTopic; - @Value("${project.adverseevent.consumer.bulk.update.topic}") + @Value("${adrm.adverseevent.consumer.bulk.update.topic}") private String updateAdverseEventBulkTopic; - @Value("${project.adverseevent.consumer.bulk.delete.topic}") + @Value("${adrm.adverseevent.consumer.bulk.delete.topic}") private String deleteAdverseEventBulkTopic; @Value("${egov.project.host}") From 8a5c715dc04c26f86daf5b46957a24509dc0aa31 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 22 Sep 2023 16:51:33 +0530 Subject: [PATCH 149/283] HLM-3069: updated AdverseEventConsumer.java --- .../java/org/egov/adrm/consumer/AdverseEventConsumer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/health-services/adrm/src/main/java/org/egov/adrm/consumer/AdverseEventConsumer.java b/health-services/adrm/src/main/java/org/egov/adrm/consumer/AdverseEventConsumer.java index c5c761c6fa8..96e424019d3 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/consumer/AdverseEventConsumer.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/consumer/AdverseEventConsumer.java @@ -30,7 +30,7 @@ public AdverseEventConsumer(AdverseEventService adverseEventService, this.objectMapper = objectMapper; } - @KafkaListener(topics = "${project.adverseevent.consumer.bulk.create.topic}") + @KafkaListener(topics = "${adrm.adverseevent.consumer.bulk.create.topic}") public void bulkCreate(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { @@ -43,7 +43,7 @@ public void bulkCreate(Map consumerRecord, } } - @KafkaListener(topics = "${project.adverseevent.consumer.bulk.update.topic}") + @KafkaListener(topics = "${adrm.adverseevent.consumer.bulk.update.topic}") public void bulkUpdate(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { @@ -56,7 +56,7 @@ public void bulkUpdate(Map consumerRecord, } } - @KafkaListener(topics = "${project.adverseevent.consumer.bulk.delete.topic}") + @KafkaListener(topics = "${adrm.adverseevent.consumer.bulk.delete.topic}") public void bulkDelete(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { From aa008451c012d4330f4c12a11da9249be2a4a7b1 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 22 Sep 2023 17:51:51 +0530 Subject: [PATCH 150/283] HLM-3069: bug fixes --- .../adrm/validator/adverseevent/AdProjectTaskIdValidator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java index f6798411721..74abfee8468 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java @@ -79,7 +79,7 @@ public Map> validate(AdverseEventBulkRequest request) TaskBulkResponse taskBulkResponse = serviceRequestClient.fetchResult( new StringBuilder(adrmConfiguration.getProjectHost() + adrmConfiguration.getProjectTaskSearchUrl() - + "&offset=0&tenantId=" + tenantId), + + "?offset=0&tenantId=" + tenantId), TaskSearchRequest.builder().requestInfo(request.getRequestInfo()).task(taskSearch).build(), TaskBulkResponse.class ); @@ -91,7 +91,7 @@ public Map> validate(AdverseEventBulkRequest request) BeneficiaryBulkResponse beneficiaryBulkResponse = serviceRequestClient.fetchResult( new StringBuilder(adrmConfiguration.getProjectHost() + adrmConfiguration.getProjectBeneficiarySearchUrl() - + "&offset=0&tenantId=" + tenantId), + + "?offset=0&tenantId=" + tenantId), BeneficiarySearchRequest.builder().requestInfo(request.getRequestInfo()).projectBeneficiary(projectBeneficiarySearch).build(), BeneficiaryBulkResponse.class ); From 30bb0901764c563dbff64f9122a22fe415b36812 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 25 Sep 2023 11:46:34 +0530 Subject: [PATCH 151/283] HLM-3069: added limit parameter for project beneficiary search call --- .../validator/adverseevent/AdProjectTaskIdValidator.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java index 74abfee8468..16865894baf 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java @@ -79,7 +79,8 @@ public Map> validate(AdverseEventBulkRequest request) TaskBulkResponse taskBulkResponse = serviceRequestClient.fetchResult( new StringBuilder(adrmConfiguration.getProjectHost() + adrmConfiguration.getProjectTaskSearchUrl() - + "?offset=0&tenantId=" + tenantId), + +"?limit=" + entities.size() + + "&offset=0&tenantId=" + tenantId), TaskSearchRequest.builder().requestInfo(request.getRequestInfo()).task(taskSearch).build(), TaskBulkResponse.class ); @@ -91,7 +92,8 @@ public Map> validate(AdverseEventBulkRequest request) BeneficiaryBulkResponse beneficiaryBulkResponse = serviceRequestClient.fetchResult( new StringBuilder(adrmConfiguration.getProjectHost() + adrmConfiguration.getProjectBeneficiarySearchUrl() - + "?offset=0&tenantId=" + tenantId), + +"?limit=" + entities.size() + + "&offset=0&tenantId=" + tenantId), BeneficiarySearchRequest.builder().requestInfo(request.getRequestInfo()).projectBeneficiary(projectBeneficiarySearch).build(), BeneficiaryBulkResponse.class ); From e20d9da46b75897356aa5a63e6266c6dc06843dd Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 25 Sep 2023 11:53:07 +0530 Subject: [PATCH 152/283] HLM-3376: Added changes for referral management --- .../adverse-event-referral-management.yml | 344 +++++++++++++++++- .../egov/adrm/config/AdrmConfiguration.java | 18 + .../consumer/ReferralManagementConsumer.java | 71 ++++ .../ReferralManagementRepository.java | 101 +++++ .../rowmapper/ReferralRowMapper.java | 85 +++++ .../service/ReferralManagementService.java | 229 ++++++++++++ .../ReferralManagementEnrichmentService.java | 56 +++ .../ReferralManagementApiController.java | 141 +++++++ .../src/main/resources/application.properties | 8 + .../adrm/referralmanagement/Referral.java | 89 +++++ .../ReferralBulkRequest.java | 38 ++ .../ReferralBulkResponse.java | 36 ++ .../referralmanagement/ReferralRequest.java | 29 ++ .../referralmanagement/ReferralResponse.java | 29 ++ .../referralmanagement/ReferralSearch.java | 29 ++ .../ReferralSearchRequest.java | 28 ++ 16 files changed, 1329 insertions(+), 2 deletions(-) create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/consumer/ReferralManagementConsumer.java create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/repository/ReferralManagementRepository.java create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/ReferralRowMapper.java create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/ReferralManagementEnrichmentService.java create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/web/controllers/ReferralManagementApiController.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkRequest.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkResponse.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralRequest.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralResponse.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearch.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearchRequest.java diff --git a/docs/health-api-specs/contracts/adverse-event-referral-management.yml b/docs/health-api-specs/contracts/adverse-event-referral-management.yml index ecb327974ff..88436973115 100644 --- a/docs/health-api-specs/contracts/adverse-event-referral-management.yml +++ b/docs/health-api-specs/contracts/adverse-event-referral-management.yml @@ -79,7 +79,7 @@ paths: - Adverse Event responses: '202': - description: update averse event request has been accepted for update. + description: update adverse event request has been accepted for update. schema: $ref: '#/definitions/AdverseEventResponse' '400': @@ -197,6 +197,193 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + /adrm/referral-management/v1/_create: + post: + summary: >- + Create referral for the project beneficiary + description: >- + Create referral for the project benefiaciary + parameters: + - name: Referral + in: body + description: Capture details of Referral + required: true + schema: + $ref: '#/definitions/ReferralRequest' + tags: + - Referral + responses: + '202': + description: Create referral request has been accepted for creation. + schema: + $ref: '#/definitions/ReferralResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + + /adrm/referral-management/v1/bulk/_create: + post: + summary: >- + Create referrals for the project beneficiary in bulk + description: >- + Create referrals for the project beneficiary in bulk + parameters: + - name: Referral + in: body + description: Capture details of Task + required: true + schema: + $ref: '#/definitions/ReferralBulkRequest' + tags: + - Referral + responses: + '202': + description: Create referral request has been accepted for creation. + schema: + $ref: '#/definitions/BulkAcceptedResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + + /adrm/referral-management/v1/_update: + post: + summary: >- + Referral Request + description: >- + Referral Request + parameters: + - name: Referral + in: body + description: Capture details of Existing referral + required: true + schema: + $ref: '#/definitions/ReferralRequest' + tags: + - Referral + responses: + '202': + description: update referral request has been accepted for update. + schema: + $ref: '#/definitions/ReferralResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + + /adrm/referral-management/v1/bulk/_update: + post: + summary: >- + Referral Request in bulk for a project beneficiary + description: >- + Referral Request in bulk for a project beneficiary + parameters: + - name: Referral + in: body + description: Capture details of Existing Referrals + required: true + schema: + $ref: '#/definitions/ReferralBulkRequest' + tags: + - Referral + responses: + '202': + description: update Referrals bulk request has been accepted for update. + schema: + $ref: '#/definitions/BulkAcceptedResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + + /adrm/referral-management/v1/_delete: + post: + summary: >- + Soft delete Referral for a project beneficiary + description: >- + Soft delete Referral for a project beneficiary + parameters: + - name: Referral + in: body + description: Capture details of Existing Referral + required: true + schema: + $ref: '#/definitions/ReferralRequest' + tags: + - Referral + responses: + '202': + description: delete Referral request has been accepted for deletion. + schema: + $ref: '#/definitions/ReferralResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + + /adrm/referral-management/v1/bulk/_delete: + post: + summary: >- + Soft delete Referrals for a project beneficiary + description: >- + Soft delete Referrals for a project beneficiary + parameters: + - name: Referral + in: body + description: Capture details of Existing Referral + required: true + schema: + $ref: '#/definitions/ReferralRequest' + tags: + - Referral + responses: + '202': + description: delete bulk Referral request has been accepted for deletion. + schema: + $ref: '#/definitions/BulkAcceptedResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + + /adrm/referral-management/v1/_search: + post: + summary: >- + Search Referral for Project + description: >- + Search Referral for Project + parameters: + - name: Referral + in: body + description: Referral Search. + required: true + schema: + $ref: '#/definitions/ReferralSearchRequest' + - $ref: '#/parameters/limit' + - $ref: '#/parameters/offset' + - $ref: '#/parameters/tenantId' + - $ref: '#/parameters/lastChangedSince' + - $ref: '#/parameters/includeDeleted' + tags: + - Referral + responses: + '200': + description: Referrals. + schema: + $ref: '#/definitions/ReferralBulkResponse' + '400': + description: Invalid Input body. + schema: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + parameters: #TODO is tenantId required as a query param if it can be determine from requestInfo->userInfo tenantId: @@ -443,4 +630,157 @@ definitions: $ref: '#/definitions/AdverseEvent' required: - ResponseInfo - - AdverseEvents \ No newline at end of file + - AdverseEvents + + Referral: + type: object + required: + - tenantId + properties: + id: + $ref: '#/definitions/id' + clientReferenceId: + $ref: '#/definitions/clientReferenceId' + tenantId: + $ref: '#/definitions/tenantId' + projectBeneficiaryId: + type: string + minLength: 2 + maxLength: 64 + description: Project Beneficiary Id + projectBeneficiaryClientReferenceId: + type: string + minLength: 2 + maxLength: 64 + description: Project Beneficiary Client Reference Id + referringPartyId: + type: string + minLength: 2 + maxLength: 64 + description: Worker Id that is referring the Beneficiary + referringPartyClientReferenceId: + type: string + minLength: 2 + maxLength: 64 + description: Worker Client Reference Id that is referring the Beneficiary + referredToId: + type: string + minLength: 2 + maxLength: 64 + description: Individual or Facility Id whom the Beneficiary is referred to. + referredToClientReferenceId: + type: string + minLength: 2 + maxLength: 64 + description: Individual or Facility Client Reference Id whom the Beneficiary is Referred To. + referredToType: + type: string + description: Individual or Facility + reasons: + type: array + items: + type: string + adverseEvent: + $ref: '#/definition/AdverseEvent' + isDeleted: + $ref: '#/definitions/isDeleted' + rowVersion: + $ref: '#/definitions/rowVersion' + auditDetails: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails + clientAuditDetails: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails + + ReferralRequest: + type: object + properties: + RequestInfo: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + Referral: + type: object + $ref: '#/definitions/Referral' + required: + - RequestInfo + - Referral + + ReferralBulkRequest: + type: object + properties: + RequestInfo: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + Referrals: + type: array + minItems: 1 + items: + $ref: '#/definitions/Referral' + required: + - RequestInfo + - Referrals + + ReferralSearch: + type: object + properties: + id: + $ref: '#/definitions/idForSearch' + clientReferenceId: + $ref: '#/definitions/clientReferenceIdForSearch' + projectBeneficiaryId: + type: array + items: + type: string + projectBeneficiaryClientReferenceId: + type: array + items: + type: string + + ReferralSearchRequest: + type: object + properties: + RequestInfo: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + Referral: + $ref: '#/definitions/ReferralSearch' + required: + - RequestInfo + - Referral + + ReferralResponse: + type: object + properties: + ResponseInfo: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo + Referral: + type: object + $ref: '#/definitions/Referral' + required: + - ResponseInfo + - Referral + + ReferralBulkResponse: + type: object + properties: + ResponseInfo: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo + Referrals: + type: array + items: + $ref: '#/definitions/Referral' + required: + - ResponseInfo + - Referrals + + BulkAcceptedResponse: + type: object + properties: + ResponseInfo: + $ref: >- + https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo + required: + - ResponseInfo \ No newline at end of file diff --git a/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java b/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java index cb98a038c73..ba66447d28c 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java @@ -41,4 +41,22 @@ public class AdrmConfiguration { @Value("${egov.search.project.beneficiary.url}") private String projectBeneficiarySearchUrl; + + @Value("${adrm.referralmanagement.kafka.create.topic}") + private String createReferralTopic; + + @Value("${adrm.referralmanagement.kafka.update.topic}") + private String updateReferralTopic; + + @Value("${adrm.referralmanagement.kafka.delete.topic}") + private String deleteReferralTopic; + + @Value("${adrm.referralmanagement.consumer.bulk.create.topic}") + private String createReferralBulkTopic; + + @Value("${adrm.referralmanagement.consumer.bulk.update.topic}") + private String updateReferralBulkTopic; + + @Value("${adrm.referralmanagement.consumer.bulk.delete.topic}") + private String deleteReferralBulkTopic; } diff --git a/health-services/adrm/src/main/java/org/egov/adrm/consumer/ReferralManagementConsumer.java b/health-services/adrm/src/main/java/org/egov/adrm/consumer/ReferralManagementConsumer.java new file mode 100644 index 00000000000..190ae112765 --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/consumer/ReferralManagementConsumer.java @@ -0,0 +1,71 @@ +package org.egov.adrm.consumer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.adrm.service.ReferralManagementService; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +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 ReferralManagementConsumer { + + private final ReferralManagementService referralManagementService; + + private final ObjectMapper objectMapper; + + @Autowired + public ReferralManagementConsumer(ReferralManagementService referralManagementService, + @Qualifier("objectMapper") ObjectMapper objectMapper) { + this.referralManagementService = referralManagementService; + this.objectMapper = objectMapper; + } + + @KafkaListener(topics = "${adrm.referralmanagement.consumer.bulk.create.topic}") + public void bulkCreate(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + ReferralBulkRequest request = objectMapper.convertValue(consumerRecord, ReferralBulkRequest.class); + referralManagementService.create(request, true); + } catch (Exception exception) { + log.error("Error in Referral consumer bulk create", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_ADRM_REFERRAL_MANAGEMENT_CREATE", exception.getMessage()); + } + } + + @KafkaListener(topics = "${adrm.referralmanagement.consumer.bulk.update.topic}") + public void bulkUpdate(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + ReferralBulkRequest request = objectMapper.convertValue(consumerRecord, ReferralBulkRequest.class); + referralManagementService.update(request, true); + } catch (Exception exception) { + log.error("Error in Referral consumer bulk update", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_ADRM_REFERRAL_MANAGEMENT_CREATE", exception.getMessage()); + } + } + + @KafkaListener(topics = "${adrm.referralmanagement.consumer.bulk.delete.topic}") + public void bulkDelete(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + ReferralBulkRequest request = objectMapper.convertValue(consumerRecord, ReferralBulkRequest.class); + referralManagementService.delete(request, true); + } catch (Exception exception) { + log.error("Error in Referral consumer bulk delete", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_ADRM_REFERRAL_MANAGEMENT_CREATE", exception.getMessage()); + } + } +} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/repository/ReferralManagementRepository.java b/health-services/adrm/src/main/java/org/egov/adrm/repository/ReferralManagementRepository.java new file mode 100644 index 00000000000..ab8ce6de641 --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/repository/ReferralManagementRepository.java @@ -0,0 +1,101 @@ +package org.egov.adrm.repository; + +import lombok.extern.slf4j.Slf4j; +import org.egov.adrm.repository.rowmapper.ReferralRowMapper; +import org.egov.common.data.query.builder.GenericQueryBuilder; +import org.egov.common.data.query.builder.QueryFieldChecker; +import org.egov.common.data.query.builder.SelectQueryBuilder; +import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.adrm.referralmanagement.Referral; +import org.egov.common.models.adrm.referralmanagement.ReferralSearch; +import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.models.project.Task; +import org.egov.common.models.project.TaskResource; +import org.egov.common.producer.Producer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.stereotype.Repository; +import org.springframework.util.ReflectionUtils; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.getIdList; +import static org.egov.common.utils.CommonUtils.getIdMethod; + +@Repository +@Slf4j +public class ReferralManagementRepository extends GenericRepository { + @Autowired + private ReferralRowMapper rowMapper; + + @Autowired + protected ReferralManagementRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, + RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, + ReferralRowMapper rowMapper) { + super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, rowMapper, Optional.of("adverse_event")); + } + + public List find(ReferralSearch searchObject, Integer limit, Integer offset, String tenantId, + Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { + String query = "SELECT r.*, ae.id, ae.clientreferenceid, ae.tenantid, ae.taskid, ae.taskclientreferenceid, ae.symptoms, ae.reattempts, ae.createdby, ae.createdtime, ae.lastmodifiedby, ae.lastmodifiedtime, ae.clientcreatedtime, ae.clientlastmodifiedtime, ae.rowversion, ae.isdeleted FROM referral r left join adverse_event ae on r.adverseEventclientReferenceid = ae.clientreferenceid"; + Map paramsMap = new HashMap<>(); + List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, + QueryFieldChecker.isNotNull, paramsMap); + query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); + query = query.replace("id IN (:id)", "r.id IN (:id)"); + query = query.replace("clientReferenceId IN (:clientReferenceId)", "r.clientReferenceId IN (:clientReferenceId)"); + + query = query + " and r.tenantId=:tenantId "; + if (Boolean.FALSE.equals(includeDeleted)) { + query = query + "and r.isDeleted=:isDeleted "; + } + + if (lastChangedSince != null) { + query = query + "and r.lastModifiedTime>=:lastModifiedTime "; + } + query = query + "ORDER BY r.id ASC LIMIT :limit OFFSET :offset"; + paramsMap.put("tenantId", tenantId); + paramsMap.put("isDeleted", includeDeleted); + paramsMap.put("lastModifiedTime", lastChangedSince); + paramsMap.put("limit", limit); + paramsMap.put("offset", offset); + List referralList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + return referralList; + } + + public List findById(List ids, String columnName, Boolean includeDeleted) { + List objFound = findInCache(ids).stream() + .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) + .collect(Collectors.toList()); + if (!objFound.isEmpty()) { + Method idMethod = getIdMethod(objFound, columnName); + ids.removeAll(objFound.stream() + .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) + .collect(Collectors.toList())); + if (ids.isEmpty()) { + return objFound; + } + } + + String query = String.format("SELECT r.*, ae.id, ae.clientreferenceid, ae.tenantid, ae.taskid, ae.taskclientreferenceid, ae.symptoms, ae.reattempts, ae.createdby, ae.createdtime, ae.lastmodifiedby, ae.lastmodifiedtime, ae.clientcreatedtime, ae.clientlastmodifiedtime, ae.rowversion, ae.isdeleted FROM referral r left join adverse_event ae on r.adverseEventclientReferenceid = ae.clientreferenceid WHERE r.%s IN (:ids) ", columnName); + if (includeDeleted == null || !includeDeleted) { + query += " AND r.isDeleted = false "; + } + Map paramMap = new HashMap<>(); + paramMap.put("ids", ids); + List referralList = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + + objFound.addAll(referralList); + putInCache(objFound); + return objFound; + } +} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/ReferralRowMapper.java b/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/ReferralRowMapper.java new file mode 100644 index 00000000000..5b8336f0941 --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/ReferralRowMapper.java @@ -0,0 +1,85 @@ +package org.egov.adrm.repository.rowmapper; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import org.egov.common.models.adrm.adverseevent.AdverseEvent; +import org.egov.common.models.adrm.referralmanagement.Referral; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; + +@Component +public class ReferralRowMapper implements RowMapper { + + @Autowired + ObjectMapper objectMapper; + + @Override + public Referral mapRow(ResultSet resultSet, int i) throws SQLException { + try { + AdverseEvent adverseEvent = null; + String adverseEventClientReferenceId = resultSet.getString("adverseEventClientReferenceId"); + if(adverseEventClientReferenceId != null) { + AuditDetails adverseEventAuditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("ae.createdBy")) + .createdTime(resultSet.getLong("ae.createdTime")) + .lastModifiedBy(resultSet.getString("ae.lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("ae.lastModifiedTime")) + .build(); + AuditDetails adverseEventClientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("ae.clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("ae.clientLastModifiedTime")) + .build(); + adverseEvent = AdverseEvent.builder() + .id(resultSet.getString("ae.id")) + .clientReferenceId(resultSet.getString("ae.clientreferenceid")) + .taskId(resultSet.getString("ae.taskId")) + .taskClientReferenceId(resultSet.getString("ae.taskClientreferenceid")) + .tenantId(resultSet.getString("ae.tenantid")) + .symptoms(resultSet.getString("ae.symptoms") == null ? null : objectMapper.readValue(resultSet.getString("ae.symptoms"), ArrayList.class)) + .rowVersion(resultSet.getInt("ae.rowversion")) + .isDeleted(resultSet.getBoolean("ae.isdeleted")) + .auditDetails(adverseEventAuditDetails) + .clientAuditDetails(adverseEventClientAuditDetails) + .build(); + } + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + AuditDetails clientAuditDetails= AuditDetails.builder() + .createdBy(resultSet.getString("clientCreatedBy")) + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build(); + return Referral.builder() + .id(resultSet.getString("id")) + .clientReferenceId(resultSet.getString("clientreferenceid")) + .projectBeneficiaryId(resultSet.getString("projectBeneficiaryId")) + .projectBeneficiaryClientReferenceId(resultSet.getString("projectbeneficiaryclientreferenceid")) + .referringPartyId(resultSet.getString("referrringpartyid")) + .referringPartyClientReferenceId(resultSet.getString("referringpartyclientreferenceid")) + .referredToId(resultSet.getString("referredToId")) + .referredToClientReferenceId(resultSet.getString("referredtoclientreferenceid")) + .referredToType(resultSet.getString("referredToType")) + .adverseEvent(adverseEvent) + .tenantId(resultSet.getString("tenantid")) + .reasons(resultSet.getString("reasons") == null ? null : objectMapper.readValue(resultSet.getString("reasons"), ArrayList.class)) + .rowVersion(resultSet.getInt("rowversion")) + .isDeleted(resultSet.getBoolean("isdeleted")) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) + .build(); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } +} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java b/health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java new file mode 100644 index 00000000000..db88aafc42b --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java @@ -0,0 +1,229 @@ +package org.egov.adrm.service; + +import lombok.extern.slf4j.Slf4j; +import org.egov.adrm.Constants; +import org.egov.adrm.config.AdrmConfiguration; +import org.egov.adrm.repository.ReferralManagementRepository; +import org.egov.adrm.service.enrichment.ReferralManagementEnrichmentService; +import org.egov.adrm.validator.adverseevent.AdIsDeletedValidator; +import org.egov.adrm.validator.adverseevent.AdNonExistentEntityValidator; +import org.egov.adrm.validator.adverseevent.AdNullIdValidator; +import org.egov.adrm.validator.adverseevent.AdProjectTaskIdValidator; +import org.egov.adrm.validator.adverseevent.AdUniqueEntityValidator; +import org.egov.common.ds.Tuple; +import org.egov.common.models.ErrorDetails; +import org.egov.common.models.adrm.referralmanagement.Referral; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.adrm.referralmanagement.ReferralRequest; +import org.egov.common.models.adrm.referralmanagement.ReferralSearchRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.egov.common.validator.Validator; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Service; +import org.springframework.util.ReflectionUtils; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +@Service +@Slf4j +public class ReferralManagementService { + private final IdGenService idGenService; + + private final ReferralManagementRepository referralManagementRepository; + + private final AdrmConfiguration adrmConfiguration; + + private final ReferralManagementEnrichmentService referralManagementEnrichmentService; + + private final List> validators; + + private final Predicate> isApplicableForCreate = validator -> + validator.getClass().equals(AdProjectTaskIdValidator.class); + + private final Predicate> isApplicableForUpdate = validator -> + validator.getClass().equals(AdProjectTaskIdValidator.class) + || validator.getClass().equals(AdNullIdValidator.class) + || validator.getClass().equals(AdIsDeletedValidator.class) + || validator.getClass().equals(AdUniqueEntityValidator.class) + || validator.getClass().equals(AdNonExistentEntityValidator.class); + + private final Predicate> isApplicableForDelete = validator -> + validator.getClass().equals(AdNullIdValidator.class) + || validator.getClass().equals(AdNonExistentEntityValidator.class); + + + public ReferralManagementService(IdGenService idGenService, ReferralManagementRepository referralManagementRepository, AdrmConfiguration adrmConfiguration, ReferralManagementEnrichmentService referralManagementEnrichmentService, List> validators) { + this.idGenService = idGenService; + this.referralManagementRepository = referralManagementRepository; + this.adrmConfiguration = adrmConfiguration; + this.referralManagementEnrichmentService = referralManagementEnrichmentService; + this.validators = validators; + } + + public Referral create(ReferralRequest request) { + log.info("received request to create adverse events"); + ReferralBulkRequest bulkRequest = ReferralBulkRequest.builder().requestInfo(request.getRequestInfo()) + .referrals(Collections.singletonList(request.getReferral())).build(); + log.info("creating bulk request"); + return create(bulkRequest, false).get(0); + } + + public List create(ReferralBulkRequest referralRequest, boolean isBulk) { + log.info("received request to create bulk adverse events"); + Tuple, Map> tuple = validate(validators, + isApplicableForCreate, referralRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validReferrals = tuple.getX(); + + try { + if (!validReferrals.isEmpty()) { + log.info("processing {} valid entities", validReferrals.size()); + referralManagementEnrichmentService.create(validReferrals, referralRequest); + referralManagementRepository.save(validReferrals, + adrmConfiguration.getCreateReferralTopic()); + log.info("successfully created adverse events"); + } + } catch (Exception exception) { + log.error("error occurred while creating adverse events: {}", exception.getMessage()); + populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, + exception, Constants.SET_ADVERSE_EVENTS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validReferrals; + } + + public Referral update(ReferralRequest request) { + log.info("received request to update adverse event"); + ReferralBulkRequest bulkRequest = ReferralBulkRequest.builder().requestInfo(request.getRequestInfo()) + .referrals(Collections.singletonList(request.getReferral())).build(); + log.info("creating bulk request"); + return update(bulkRequest, false).get(0); + } + + public List update(ReferralBulkRequest referralRequest, boolean isBulk) { + log.info("received request to update bulk adverse event"); + Tuple, Map> tuple = validate(validators, + isApplicableForUpdate, referralRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validReferrals = tuple.getX(); + + try { + if (!validReferrals.isEmpty()) { + log.info("processing {} valid entities", validReferrals.size()); + referralManagementEnrichmentService.update(validReferrals, referralRequest); + referralManagementRepository.save(validReferrals, + adrmConfiguration.getUpdateReferralTopic()); + log.info("successfully updated bulk adverse events"); + } + } catch (Exception exception) { + log.error("error occurred while updating adverse events", exception); + populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, + exception, Constants.SET_ADVERSE_EVENTS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validReferrals; + } + + public List search(ReferralSearchRequest referralSearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { + log.info("received request to search adverse events"); + String idFieldName = getIdFieldName(referralSearchRequest.getReferral()); + if (isSearchByIdOnly(referralSearchRequest.getReferral(), idFieldName)) { + log.info("searching adverse events by id"); + List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections + .singletonList(referralSearchRequest.getReferral())), + referralSearchRequest.getReferral()); + log.info("fetching adverse events with ids: {}", ids); + return referralManagementRepository.findById(ids, includeDeleted, idFieldName).stream() + .filter(lastChangedSince(lastChangedSince)) + .filter(havingTenantId(tenantId)) + .filter(includeDeleted(includeDeleted)) + .collect(Collectors.toList()); + } + log.info("searching adverse events using criteria"); + return referralManagementRepository.find(referralSearchRequest.getReferral(), + limit, offset, tenantId, lastChangedSince, includeDeleted); + } + + public Referral delete(ReferralRequest referralRequest) { + log.info("received request to delete a adverse event"); + ReferralBulkRequest bulkRequest = ReferralBulkRequest.builder().requestInfo(referralRequest.getRequestInfo()) + .referrals(Collections.singletonList(referralRequest.getReferral())).build(); + log.info("creating bulk request"); + return delete(bulkRequest, false).get(0); + } + + public List delete(ReferralBulkRequest referralRequest, boolean isBulk) { + Tuple, Map> tuple = validate(validators, + isApplicableForDelete, referralRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validReferrals = tuple.getX(); + + try { + if (!validReferrals.isEmpty()) { + log.info("processing {} valid entities", validReferrals.size()); + List referralIds = validReferrals.stream().map(entity -> entity.getId()).collect(Collectors.toSet()).stream().collect(Collectors.toList()); + List existingReferrals = referralManagementRepository + .findById(referralIds, false); + referralManagementEnrichmentService.delete(existingReferrals, referralRequest); + referralManagementRepository.save(existingReferrals, + adrmConfiguration.getDeleteReferralTopic()); + log.info("successfully deleted entities"); + } + } catch (Exception exception) { + log.error("error occurred while deleting entities: {}", exception); + populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, + exception, Constants.SET_ADVERSE_EVENTS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validReferrals; + } + + public void putInCache(List referrals) { + log.info("putting {} adverse events in cache", referrals.size()); + referralManagementRepository.putInCache(referrals); + log.info("successfully put adverse events in cache"); + } + + private Tuple, Map> validate( + List> validators, + Predicate> isApplicable, + ReferralBulkRequest request, + boolean isBulk + ) { + log.info("validating request"); + Map errorDetailsMap = CommonUtils.validate(validators, + isApplicable, request, + Constants.SET_ADVERSE_EVENTS); + if (!errorDetailsMap.isEmpty() && !isBulk) { + log.error("validation error occurred. error details: {}", errorDetailsMap.values().toString()); + throw new CustomException(Constants.VALIDATION_ERROR, errorDetailsMap.values().toString()); + } + List validReferrals = request.getReferrals().stream() + .filter(notHavingErrors()).collect(Collectors.toList()); + log.info("validation successful, found valid adverse events"); + return new Tuple<>(validReferrals, errorDetailsMap); + } +} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/ReferralManagementEnrichmentService.java b/health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/ReferralManagementEnrichmentService.java new file mode 100644 index 00000000000..552136b678c --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/ReferralManagementEnrichmentService.java @@ -0,0 +1,56 @@ +package org.egov.adrm.service.enrichment; + +import lombok.extern.slf4j.Slf4j; +import org.egov.adrm.config.AdrmConfiguration; +import org.egov.adrm.repository.ReferralManagementRepository; +import org.egov.common.models.adrm.referralmanagement.Referral; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +import static org.egov.common.utils.CommonUtils.enrichForCreate; +import static org.egov.common.utils.CommonUtils.enrichForDelete; +import static org.egov.common.utils.CommonUtils.enrichForUpdate; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; + +@Component +@Slf4j +public class ReferralManagementEnrichmentService { + private final IdGenService idGenService; + + private final AdrmConfiguration adrmConfiguration; + + private final ReferralManagementRepository referralManagementRepository; + + public ReferralManagementEnrichmentService(IdGenService idGenService, AdrmConfiguration adrmConfiguration, ReferralManagementRepository referralManagementRepository) { + this.idGenService = idGenService; + this.adrmConfiguration = adrmConfiguration; + this.referralManagementRepository = referralManagementRepository; + } + + public void create(List entities, ReferralBulkRequest request) throws Exception { + log.info("starting the enrichment for create referrals"); + log.info("generating IDs using UUID"); + List idList = CommonUtils.uuidSupplier().apply(entities.size()); + log.info("enriching referrals with generated IDs"); + enrichForCreate(entities, idList, request.getRequestInfo()); + log.info("enrichment done"); + } + + public void update(List entities, ReferralBulkRequest request) { + log.info("starting the enrichment for create referrals"); + Map referralMap = getIdToObjMap(entities); + enrichForUpdate(referralMap, entities, request); + log.info("enrichment done"); + } + + public void delete(List entities, ReferralBulkRequest request) { + log.info("starting the enrichment for delete referrals"); + enrichForDelete(entities, request.getRequestInfo(), true); + log.info("enrichment done"); + } +} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/ReferralManagementApiController.java b/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/ReferralManagementApiController.java new file mode 100644 index 00000000000..42604fa739f --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/ReferralManagementApiController.java @@ -0,0 +1,141 @@ +package org.egov.adrm.web.controllers; + +import io.swagger.annotations.ApiParam; +import org.egov.adrm.config.AdrmConfiguration; +import org.egov.adrm.service.ReferralManagementService; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.adrm.referralmanagement.Referral; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkResponse; +import org.egov.common.models.adrm.referralmanagement.ReferralRequest; +import org.egov.common.models.adrm.referralmanagement.ReferralResponse; +import org.egov.common.models.adrm.referralmanagement.ReferralSearchRequest; +import org.egov.common.producer.Producer; +import org.egov.common.utils.ResponseInfoFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Controller +@RequestMapping("/referral-management") +@Validated +public class ReferralManagementApiController { + private final HttpServletRequest httpServletRequest; + + private final ReferralManagementService referralManagementService; + + private final Producer producer; + + private final AdrmConfiguration adrmConfiguration; + + public ReferralManagementApiController( + HttpServletRequest httpServletRequest, + ReferralManagementService referralManagementService, + Producer producer, + AdrmConfiguration adrmConfiguration + ) { + this.httpServletRequest = httpServletRequest; + this.referralManagementService = referralManagementService; + this.producer = producer; + this.adrmConfiguration = adrmConfiguration; + } + + @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) + public ResponseEntity referralV1CreatePost(@ApiParam(value = "Capture details of Referral", required = true) @Valid @RequestBody ReferralRequest request) { + + Referral referral = referralManagementService.create(request); + ReferralResponse response = ReferralResponse.builder() + .referral(referral) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } + + + + @RequestMapping(value = "/v1/bulk/_create", method = RequestMethod.POST) + public ResponseEntity referralBulkV1CreatePost(@ApiParam(value = "Capture details of Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + referralManagementService.putInCache(request.getReferrals()); + producer.push(adrmConfiguration.getCreateReferralBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + + @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) + public ResponseEntity referralV1SearchPost(@ApiParam(value = "Referral Search.", required = true) @Valid @RequestBody ReferralSearchRequest request, + @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, + @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, + @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, + @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, + @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { + + List referrals = referralManagementService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); + ReferralBulkResponse response = ReferralBulkResponse.builder().responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)).referrals(referrals).build(); + + return ResponseEntity.status(HttpStatus.OK).body(response); + } + + @RequestMapping(value = "/v1/_update", method = RequestMethod.POST) + public ResponseEntity referralV1UpdatePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralRequest request) { + Referral referral = referralManagementService.update(request); + + ReferralResponse response = ReferralResponse.builder() + .referral(referral) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + + } + + @RequestMapping(value = "/v1/bulk/_update", method = RequestMethod.POST) + public ResponseEntity referralV1BulkUpdatePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + producer.push(adrmConfiguration.getUpdateReferralBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + + @RequestMapping(value = "/v1/_delete", method = RequestMethod.POST) + public ResponseEntity referralV1DeletePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralRequest request) { + Referral referral = referralManagementService.delete(request); + + ReferralResponse response = ReferralResponse.builder() + .referral(referral) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + + } + + @RequestMapping(value = "/v1/bulk/_delete", method = RequestMethod.POST) + public ResponseEntity referralV1BulkDeletePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + producer.push(adrmConfiguration.getDeleteReferralBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + +} diff --git a/health-services/adrm/src/main/resources/application.properties b/health-services/adrm/src/main/resources/application.properties index 18f90dea65a..93fe8732234 100644 --- a/health-services/adrm/src/main/resources/application.properties +++ b/health-services/adrm/src/main/resources/application.properties @@ -107,6 +107,14 @@ adrm.adverseevent.consumer.bulk.create.topic=save-adverse-event-bulk-topic adrm.adverseevent.consumer.bulk.update.topic=update-adverse-event-bulk-topic adrm.adverseevent.consumer.bulk.delete.topic=delete-adverse-event-bulk-topic +adrm.referralmanagement.kafka.create.topic=save-referral-management-topic +adrm.referralmanagement.kafka.update.topic=update-referral-management-topic +adrm.referralmanagement.kafka.delete.topic=delete-referral-management-topic + +adrm.referralmanagement.consumer.bulk.create.topic=save-referral-management-bulk-topic +adrm.referralmanagement.consumer.bulk.update.topic=update-referral-management-bulk-topic +adrm.referralmanagement.consumer.bulk.delete.topic=delete-referral-management-bulk-topic + search.api.limit=1000 adrm.default.offset=0 diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java new file mode 100644 index 00000000000..b7fbf6deff4 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java @@ -0,0 +1,89 @@ +package org.egov.common.models.adrm.referralmanagement; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.models.adrm.adverseevent.AdverseEvent; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class Referral { + + @JsonProperty("id") + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("clientReferenceId") + @Size(min = 2, max = 64) + private String clientReferenceId = null; + + @JsonProperty("projectBeneficiaryId") + @Size(min = 2, max = 64) + private String projectBeneficiaryId = null; + + @JsonProperty("projectBeneficiaryClientReferenceId") + @Size(min = 2, max = 64) + private String projectBeneficiaryClientReferenceId = null; + + @JsonProperty("referringPartyId") + @Size(min = 2, max = 64) + private String referringPartyId = null; + + @JsonProperty("referringPartyClientReferenceId") + @Size(min = 2, max = 64) + private String referringPartyClientReferenceId = null; + + @JsonProperty("referredToType") + private String referredToType = null; + + @JsonProperty("referredToId") + @Size(min = 2, max = 64) + private String referredToId = null; + + @JsonProperty("referredToClientReferenceId") + @Size(min = 2, max = 64) + private String referredToClientReferenceId = null; + + @JsonProperty("reasons") + @NotNull + @Size(min=1) + private List reasons = null; + + @JsonProperty("adverseEvent") + private AdverseEvent adverseEvent = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min=2, max = 1000) + private String tenantId = null; + + @JsonProperty("isDeleted") + private Boolean isDeleted = Boolean.FALSE; + + @JsonProperty("rowVersion") + private Integer rowVersion = null; + + @JsonProperty("auditDetails") + @Valid + private AuditDetails auditDetails = null; + + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + + @JsonIgnore + private Boolean hasErrors = Boolean.FALSE; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkRequest.java new file mode 100644 index 00000000000..752c8bfdb26 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkRequest.java @@ -0,0 +1,38 @@ +package org.egov.common.models.adrm.referralmanagement; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.ArrayList; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ReferralBulkRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Referrals") + @NotNull + @Valid + @Size(min = 1) + private List referrals = new ArrayList<>(); + + public ReferralBulkRequest addReferralItem(Referral referralItem) { + this.referrals.add(referralItem); + return this; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkResponse.java new file mode 100644 index 00000000000..f34d1df7ae0 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkResponse.java @@ -0,0 +1,36 @@ +package org.egov.common.models.adrm.referralmanagement; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ReferralBulkResponse { + @JsonProperty("ResponseInfo") + @NotNull + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Referrals") + @NotNull + @Valid + private List referrals = new ArrayList<>(); + + public ReferralBulkResponse addReferralItem(Referral referralItem) { + this.referrals.add(referralItem); + return this; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralRequest.java new file mode 100644 index 00000000000..ead7cedd3a2 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralRequest.java @@ -0,0 +1,29 @@ +package org.egov.common.models.adrm.referralmanagement; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ReferralRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Referral") + @NotNull + @Valid + private Referral referral = null; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralResponse.java new file mode 100644 index 00000000000..8bcae0afb31 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralResponse.java @@ -0,0 +1,29 @@ +package org.egov.common.models.adrm.referralmanagement; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ReferralResponse { + @JsonProperty("ResponseInfo") + @NotNull + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Referral") + @NotNull + @Valid + private Referral referral = null; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearch.java new file mode 100644 index 00000000000..c54be75749b --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearch.java @@ -0,0 +1,29 @@ +package org.egov.common.models.adrm.referralmanagement; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ReferralSearch { + @JsonProperty("id") + private List id = null; + + @JsonProperty("clientReferenceId") + private List clientReferenceId = null; + + @JsonProperty("projectBeneficiaryId") + private List projectBeneficiaryId = null; + + @JsonProperty("projectBeneficiaryClientReferenceId") + private List projectBeneficiaryClientReferenceId = null; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearchRequest.java new file mode 100644 index 00000000000..c87c2265dd9 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearchRequest.java @@ -0,0 +1,28 @@ +package org.egov.common.models.adrm.referralmanagement; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ReferralSearchRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Referral") + @Valid + private ReferralSearch referral = null; +} From d3bfc7fe97b3672535971f856259127a101d718c Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 25 Sep 2023 12:16:15 +0530 Subject: [PATCH 153/283] HLM-3069: updated build.config.yml --- build/build-config.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/build-config.yml b/build/build-config.yml index b0f4bbfcd16..f0d399747aa 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -36,6 +36,13 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "health-services/project/src/main/resources/db" image-name: "project-db" + - name: "builds/health-campaign-services/health-services/adrm" + build: + - work-dir: "health-services/adrm" + image-name: "adrm" + dockerfile: "build/maven/Dockerfile" + - work-dir: "health-services/adrm/src/main/resources/db" + image-name: "adrm-db" - name: "builds/health-campaign-services/health-services/household" build: - work-dir: "health-services/household" From cdbdcc1fa482b62097e79ade9d2cb641e7aa3e4e Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 25 Sep 2023 18:09:42 +0530 Subject: [PATCH 154/283] HLM-3376: Added Validators, updated Referral.java --- .../main/java/org/egov/adrm/Constants.java | 4 + .../egov/adrm/config/AdrmConfiguration.java | 9 ++ .../adrm/service/AdverseEventService.java | 8 +- .../service/ReferralManagementService.java | 29 ++-- .../rm/RmFacilityEntitiesIdValidator.java | 100 +++++++++++++ .../validator/rm/RmIsDeletedValidator.java | 34 +++++ .../rm/RmNonExistentEntityValidator.java | 71 ++++++++++ .../adrm/validator/rm/RmNullIdValidator.java | 27 ++++ .../rm/RmProjectEntitiesIdValidator.java | 134 ++++++++++++++++++ .../validator/rm/RmUniqueEntityValidator.java | 47 ++++++ .../src/main/resources/application.properties | 4 + .../adrm/referralmanagement/Referral.java | 8 -- 12 files changed, 450 insertions(+), 25 deletions(-) create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmFacilityEntitiesIdValidator.java create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmIsDeletedValidator.java create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNonExistentEntityValidator.java create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNullIdValidator.java create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmProjectEntitiesIdValidator.java create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmUniqueEntityValidator.java diff --git a/health-services/adrm/src/main/java/org/egov/adrm/Constants.java b/health-services/adrm/src/main/java/org/egov/adrm/Constants.java index 5077f0f5d96..74d6eb8bda6 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/Constants.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/Constants.java @@ -3,10 +3,14 @@ public interface Constants { String SET_ADVERSE_EVENTS = "setAdverseEvents"; String GET_ADVERSE_EVENTS = "getAdverseEvents"; + String SET_REFERRALS = "setReferrals"; + String GET_REFERRALS = "getReferrals"; String VALIDATION_ERROR = "VALIDATION_ERROR"; String PROJECT_TYPES = "projectTypes"; String MDMS_RESPONSE = "MdmsRes"; String INTERNAL_SERVER_ERROR = "INTERNAL_SERVER_ERROR"; String GET_ID = "getId"; + String PROJECT_STAFF = "project_staff"; + String FACILITY = "facility"; } diff --git a/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java b/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java index ba66447d28c..05e03ab718d 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java @@ -59,4 +59,13 @@ public class AdrmConfiguration { @Value("${adrm.referralmanagement.consumer.bulk.delete.topic}") private String deleteReferralBulkTopic; + + @Value("${egov.search.project.staff.url}") + private String projectStaffSearchUrl; + + @Value("${egov.facility.host}") + private String facilityHost; + + @Value("${egov.search.facility.url}") + private String facilitySearchUrl; } diff --git a/health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java b/health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java index 54b754ca746..5bf0585d61b 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java @@ -108,7 +108,7 @@ public List create(AdverseEventBulkRequest adverseEventRequest, bo } catch (Exception exception) { log.error("error occurred while creating adverse events: {}", exception.getMessage()); populateErrorDetails(adverseEventRequest, errorDetailsMap, validAdverseEvents, - exception, Constants.SET_ADVERSE_EVENTS); + exception, Constants.SET_REFERRALS); } handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); @@ -141,7 +141,7 @@ public List update(AdverseEventBulkRequest adverseEventRequest, bo } catch (Exception exception) { log.error("error occurred while updating adverse events", exception); populateErrorDetails(adverseEventRequest, errorDetailsMap, validAdverseEvents, - exception, Constants.SET_ADVERSE_EVENTS); + exception, Constants.SET_REFERRALS); } handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); @@ -201,7 +201,7 @@ public List delete(AdverseEventBulkRequest adverseEventRequest, bo } catch (Exception exception) { log.error("error occurred while deleting entities: {}", exception); populateErrorDetails(adverseEventRequest, errorDetailsMap, validAdverseEvents, - exception, Constants.SET_ADVERSE_EVENTS); + exception, Constants.SET_REFERRALS); } handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); @@ -223,7 +223,7 @@ private Tuple, Map> validate( log.info("validating request"); Map errorDetailsMap = CommonUtils.validate(validators, isApplicable, request, - Constants.SET_ADVERSE_EVENTS); + Constants.SET_REFERRALS); if (!errorDetailsMap.isEmpty() && !isBulk) { log.error("validation error occurred. error details: {}", errorDetailsMap.values().toString()); throw new CustomException(Constants.VALIDATION_ERROR, errorDetailsMap.values().toString()); diff --git a/health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java b/health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java index db88aafc42b..0bd69750a27 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java @@ -5,11 +5,12 @@ import org.egov.adrm.config.AdrmConfiguration; import org.egov.adrm.repository.ReferralManagementRepository; import org.egov.adrm.service.enrichment.ReferralManagementEnrichmentService; -import org.egov.adrm.validator.adverseevent.AdIsDeletedValidator; -import org.egov.adrm.validator.adverseevent.AdNonExistentEntityValidator; -import org.egov.adrm.validator.adverseevent.AdNullIdValidator; -import org.egov.adrm.validator.adverseevent.AdProjectTaskIdValidator; -import org.egov.adrm.validator.adverseevent.AdUniqueEntityValidator; +import org.egov.adrm.validator.rm.RmFacilityEntitiesIdValidator; +import org.egov.adrm.validator.rm.RmIsDeletedValidator; +import org.egov.adrm.validator.rm.RmNonExistentEntityValidator; +import org.egov.adrm.validator.rm.RmNullIdValidator; +import org.egov.adrm.validator.rm.RmProjectEntitiesIdValidator; +import org.egov.adrm.validator.rm.RmUniqueEntityValidator; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.adrm.referralmanagement.Referral; @@ -53,18 +54,20 @@ public class ReferralManagementService { private final List> validators; private final Predicate> isApplicableForCreate = validator -> - validator.getClass().equals(AdProjectTaskIdValidator.class); + validator.getClass().equals(RmProjectEntitiesIdValidator.class) + || validator.getClass().equals(RmFacilityEntitiesIdValidator.class); private final Predicate> isApplicableForUpdate = validator -> - validator.getClass().equals(AdProjectTaskIdValidator.class) - || validator.getClass().equals(AdNullIdValidator.class) - || validator.getClass().equals(AdIsDeletedValidator.class) - || validator.getClass().equals(AdUniqueEntityValidator.class) - || validator.getClass().equals(AdNonExistentEntityValidator.class); + validator.getClass().equals(RmProjectEntitiesIdValidator.class) + || validator.getClass().equals(RmFacilityEntitiesIdValidator.class) + || validator.getClass().equals(RmNullIdValidator.class) + || validator.getClass().equals(RmIsDeletedValidator.class) + || validator.getClass().equals(RmUniqueEntityValidator.class) + || validator.getClass().equals(RmNonExistentEntityValidator.class); private final Predicate> isApplicableForDelete = validator -> - validator.getClass().equals(AdNullIdValidator.class) - || validator.getClass().equals(AdNonExistentEntityValidator.class); + validator.getClass().equals(RmNullIdValidator.class) + || validator.getClass().equals(RmNonExistentEntityValidator.class); public ReferralManagementService(IdGenService idGenService, ReferralManagementRepository referralManagementRepository, AdrmConfiguration adrmConfiguration, ReferralManagementEnrichmentService referralManagementEnrichmentService, List> validators) { diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmFacilityEntitiesIdValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmFacilityEntitiesIdValidator.java new file mode 100644 index 00000000000..340fc531ca3 --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmFacilityEntitiesIdValidator.java @@ -0,0 +1,100 @@ +package org.egov.adrm.validator.rm; + +import lombok.extern.slf4j.Slf4j; +import org.egov.adrm.config.AdrmConfiguration; +import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.adrm.referralmanagement.Referral; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.facility.Facility; +import org.egov.common.models.facility.FacilityBulkResponse; +import org.egov.common.models.facility.FacilitySearch; +import org.egov.common.models.facility.FacilitySearchRequest; +import org.egov.common.validator.Validator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.egov.adrm.Constants.FACILITY; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + + +@Component +@Order(value = 3) +@Slf4j +public class RmFacilityEntitiesIdValidator implements Validator { + private final ServiceRequestClient serviceRequestClient; + private final AdrmConfiguration adrmConfiguration; + + @Autowired + public RmFacilityEntitiesIdValidator(ServiceRequestClient serviceRequestClient, AdrmConfiguration adrmConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.adrmConfiguration = adrmConfiguration; + } + + + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating facility id"); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getReferrals(); + Map> tenantIdReferralMap = entities.stream().collect(Collectors.groupingBy(Referral::getTenantId)); + List tenantIds = new ArrayList<>(tenantIdReferralMap.keySet()); + tenantIds.forEach(tenantId -> { + List referralList = tenantIdReferralMap.get(tenantId); + if (!referralList.isEmpty()) { + List existingFacilityList = null; + final List facilityIdList = new ArrayList<>(); + try { + referralList.forEach(referral -> { + if(referral.getReferredToType().equals(FACILITY)){ + addIgnoreNull(facilityIdList, referral.getReferredToId()); + } + }); + FacilitySearch facilitySearch = FacilitySearch.builder() + .id(facilityIdList.isEmpty() ? null : facilityIdList) + .build(); + FacilityBulkResponse facilityBulkResponse = serviceRequestClient.fetchResult( + new StringBuilder(adrmConfiguration.getFacilityHost() + + adrmConfiguration.getFacilitySearchUrl() + +"?limit=" + entities.size() + + "&offset=0&tenantId=" + tenantId), + FacilitySearchRequest.builder().requestInfo(request.getRequestInfo()).facility(facilitySearch).build(), + FacilityBulkResponse.class + ); + existingFacilityList = facilityBulkResponse.getFacilities(); + } catch (QueryBuilderException e) { + existingFacilityList = Collections.emptyList(); + } catch (Exception e) { + throw new RuntimeException(e); + } + final List existingFacilityIds = new ArrayList<>(); + existingFacilityList.forEach(facility -> existingFacilityIds.add(facility.getId())); + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + (!entity.getReferredToType().equals(FACILITY) || !existingFacilityIds.contains(entity.getReferredToId())) + ).collect(Collectors.toList()); + invalidEntities.forEach(referral -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(referral, error, errorDetailsMap); + }); + + } + }); + return errorDetailsMap; + } + + private void addIgnoreNull(List list, String item) { + if(Objects.nonNull(item)) list.add(item); + } +} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmIsDeletedValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmIsDeletedValidator.java new file mode 100644 index 00000000000..00dd7156d42 --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmIsDeletedValidator.java @@ -0,0 +1,34 @@ +package org.egov.adrm.validator.rm; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.adrm.referralmanagement.Referral; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForIsDelete; + +@Component +@Order(2) +@Slf4j +public class RmIsDeletedValidator implements Validator { + + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating isDeleted field"); + HashMap> errorDetailsMap = new HashMap<>(); + List validEntities = request.getReferrals(); + validEntities.stream().filter(Referral::getIsDeleted).forEach(referral -> { + Error error = getErrorForIsDelete(); + populateErrorDetails(referral, error, errorDetailsMap); + }); + return errorDetailsMap; + } +} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNonExistentEntityValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNonExistentEntityValidator.java new file mode 100644 index 00000000000..5a4e881370b --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNonExistentEntityValidator.java @@ -0,0 +1,71 @@ +package org.egov.adrm.validator.rm; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.adrm.repository.ReferralManagementRepository; +import org.egov.common.models.Error; +import org.egov.common.models.adrm.referralmanagement.Referral; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.egov.adrm.Constants.GET_ID; +import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.getObjClass; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + +@Component +@Order(value = 4) +@Slf4j +public class RmNonExistentEntityValidator implements Validator { + + private final ReferralManagementRepository referralManagementRepository; + + private final ObjectMapper objectMapper; + + @Autowired + public RmNonExistentEntityValidator(ReferralManagementRepository referralManagementRepository, ObjectMapper objectMapper) { + this.referralManagementRepository = referralManagementRepository; + this.objectMapper = objectMapper; + } + + + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating for existence of entity"); + Map> errorDetailsMap = new HashMap<>(); + List referrals = request.getReferrals(); + Class objClass = getObjClass(referrals); + Method idMethod = getMethod(GET_ID, objClass); + Map iMap = getIdToObjMap(referrals + .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + if (!iMap.isEmpty()) { + List adverseEventIds = new ArrayList<>(iMap.keySet()); + List existingReferrals = referralManagementRepository + .findById(adverseEventIds, false, getIdFieldName(idMethod)); + List nonExistentReferrals = checkNonExistentEntities(iMap, + existingReferrals, idMethod); + nonExistentReferrals.forEach(adverseEvent -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(adverseEvent, error, errorDetailsMap); + }); + } + + return errorDetailsMap; + } +} + diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNullIdValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNullIdValidator.java new file mode 100644 index 00000000000..5324a12270b --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNullIdValidator.java @@ -0,0 +1,27 @@ +package org.egov.adrm.validator.rm; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.adrm.referralmanagement.Referral; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +import static org.egov.adrm.Constants.GET_REFERRALS; +import static org.egov.common.utils.CommonUtils.validateForNullId; + + +@Component +@Order(value = 1) +@Slf4j +public class RmNullIdValidator implements Validator { + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating for null id"); + return validateForNullId(request, GET_REFERRALS); + } +} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmProjectEntitiesIdValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmProjectEntitiesIdValidator.java new file mode 100644 index 00000000000..05c4670c7ec --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmProjectEntitiesIdValidator.java @@ -0,0 +1,134 @@ +package org.egov.adrm.validator.rm; + +import lombok.extern.slf4j.Slf4j; +import org.egov.adrm.config.AdrmConfiguration; +import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.adrm.referralmanagement.Referral; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.project.BeneficiaryBulkResponse; +import org.egov.common.models.project.BeneficiarySearchRequest; +import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.models.project.ProjectBeneficiarySearch; +import org.egov.common.models.project.ProjectStaff; +import org.egov.common.models.project.ProjectStaffBulkResponse; +import org.egov.common.models.project.ProjectStaffSearch; +import org.egov.common.models.project.ProjectStaffSearchRequest; +import org.egov.common.validator.Validator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.egov.adrm.Constants.PROJECT_STAFF; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + + +@Component +@Order(value = 3) +@Slf4j +public class RmProjectEntitiesIdValidator implements Validator { + private final ServiceRequestClient serviceRequestClient; + private final AdrmConfiguration adrmConfiguration; + + @Autowired + public RmProjectEntitiesIdValidator(ServiceRequestClient serviceRequestClient, AdrmConfiguration adrmConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.adrmConfiguration = adrmConfiguration; + } + + + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating project beneficiary id, project staff id"); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getReferrals(); + Map> tenantIdReferralMap = entities.stream().collect(Collectors.groupingBy(Referral::getTenantId)); + List tenantIds = new ArrayList<>(tenantIdReferralMap.keySet()); + tenantIds.forEach(tenantId -> { + List referralList = tenantIdReferralMap.get(tenantId); + if (!referralList.isEmpty()) { + List existingProjectBeneficiaries = null; + List existingProjectStaffList = null; + final List projectBeneficiaryIdList = new ArrayList<>(); + final List projectBeneficiaryClientReferenceIdList = new ArrayList<>(); + final List projectStaffIdList = new ArrayList<>(); + try { + referralList.forEach(referral -> { + addIgnoreNull(projectBeneficiaryIdList, referral.getProjectBeneficiaryId()); + addIgnoreNull(projectBeneficiaryClientReferenceIdList, referral.getProjectBeneficiaryClientReferenceId()); + addIgnoreNull(projectStaffIdList, referral.getReferringPartyId()); + if(referral.getReferredToType().equals(PROJECT_STAFF)){ + addIgnoreNull(projectStaffIdList, referral.getReferredToId()); + } + }); + ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() + .id(projectBeneficiaryIdList.isEmpty() ? null : projectBeneficiaryIdList) + .clientReferenceId(projectBeneficiaryClientReferenceIdList.isEmpty() ? null : projectBeneficiaryClientReferenceIdList) + .build(); + BeneficiaryBulkResponse beneficiaryBulkResponse = serviceRequestClient.fetchResult( + new StringBuilder(adrmConfiguration.getProjectHost() + + adrmConfiguration.getProjectBeneficiarySearchUrl() + +"?limit=" + entities.size() + + "&offset=0&tenantId=" + tenantId), + BeneficiarySearchRequest.builder().requestInfo(request.getRequestInfo()).projectBeneficiary(projectBeneficiarySearch).build(), + BeneficiaryBulkResponse.class + ); + existingProjectBeneficiaries = beneficiaryBulkResponse.getProjectBeneficiaries(); + ProjectStaffSearch projectStaffSearch = ProjectStaffSearch.builder() + .id(projectStaffIdList.isEmpty() ? null : projectStaffIdList) + .build(); + ProjectStaffBulkResponse projectStaffBulkResponse = serviceRequestClient.fetchResult( + new StringBuilder(adrmConfiguration.getProjectHost() + + adrmConfiguration.getProjectStaffSearchUrl() + +"?limit=" + entities.size() + + "&offset=0&tenantId=" + tenantId), + ProjectStaffSearchRequest.builder().requestInfo(request.getRequestInfo()).projectStaff(projectStaffSearch).build(), + ProjectStaffBulkResponse.class + ); + existingProjectStaffList = projectStaffBulkResponse.getProjectStaff(); + + } catch (QueryBuilderException e) { + if(existingProjectBeneficiaries == null) existingProjectBeneficiaries = Collections.emptyList(); + existingProjectStaffList = Collections.emptyList(); + } catch (Exception e) { + throw new RuntimeException(e); + } + final List existingProjectBeneficiaryIds = new ArrayList<>(); + final List existingProjectBeneficiaryClientReferenceIds = new ArrayList<>(); + existingProjectBeneficiaries.forEach(projectBeneficiary -> { + existingProjectBeneficiaryIds.add(projectBeneficiary.getId()); + existingProjectBeneficiaryClientReferenceIds.add(projectBeneficiary.getClientReferenceId()); + }); + final List existingProjectStaffIds = new ArrayList<>(); + existingProjectStaffList.forEach(projectStaff -> existingProjectStaffIds.add(projectStaff.getId())); + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + !existingProjectStaffIds.contains(entity.getReferringPartyId()) + && !existingProjectBeneficiaryIds.contains(entity.getProjectBeneficiaryId()) + && !existingProjectBeneficiaryClientReferenceIds.contains(entity.getProjectBeneficiaryClientReferenceId()) + && (!entity.getReferredToType().equals(PROJECT_STAFF) || !existingProjectStaffIds.contains(entity.getReferredToId())) + ).collect(Collectors.toList()); + invalidEntities.forEach(referral -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(referral, error, errorDetailsMap); + }); + + } + }); + return errorDetailsMap; + } + + private void addIgnoreNull(List list, String item) { + if(Objects.nonNull(item)) list.add(item); + } +} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmUniqueEntityValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmUniqueEntityValidator.java new file mode 100644 index 00000000000..8a73836a870 --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmUniqueEntityValidator.java @@ -0,0 +1,47 @@ +package org.egov.adrm.validator.rm; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.adrm.referralmanagement.Referral; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +@Component +@Order(value = 2) +@Slf4j +public class RmUniqueEntityValidator implements Validator { + + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating unique entity"); + Map> errorDetailsMap = new HashMap<>(); + List validEntities = request.getReferrals() + .stream().filter(notHavingErrors()).collect(Collectors.toList()); + if (!validEntities.isEmpty()) { + Map eMap = getIdToObjMap(validEntities); + if (eMap.keySet().size() != validEntities.size()) { + List duplicates = eMap.keySet().stream().filter(id -> + validEntities.stream() + .filter(entity -> entity.getId().equals(id)).count() > 1 + ).collect(Collectors.toList()); + for (String key : duplicates) { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(eMap.get(key), error, errorDetailsMap); + } + } + } + return errorDetailsMap; + } +} diff --git a/health-services/adrm/src/main/resources/application.properties b/health-services/adrm/src/main/resources/application.properties index 93fe8732234..877b6c47da8 100644 --- a/health-services/adrm/src/main/resources/application.properties +++ b/health-services/adrm/src/main/resources/application.properties @@ -79,6 +79,9 @@ egov.mdms.master.name=project_master egov.mdms.module.name=project egov.mdms.integration.enabled=true +# FACILITY SERVICE +egov.facility.host=http://localhost:8083 +egov.search.facility.url=/facility/v1/_search # HOUSEHOLD SERVICE egov.household.host= @@ -96,6 +99,7 @@ egov.user.id.validator=individual egov.project.host=https://unified-dev.digit.org egov.search.project.task.url=/project/task/v1/_search egov.search.project.beneficiary.url=/project/beneficiary/v1/_search +egov.search.project.staff.url=/project/staff/v1/_search # ADRM KAFKA CONFIG diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java index b7fbf6deff4..668ea353ac3 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java @@ -42,10 +42,6 @@ public class Referral { @Size(min = 2, max = 64) private String referringPartyId = null; - @JsonProperty("referringPartyClientReferenceId") - @Size(min = 2, max = 64) - private String referringPartyClientReferenceId = null; - @JsonProperty("referredToType") private String referredToType = null; @@ -53,10 +49,6 @@ public class Referral { @Size(min = 2, max = 64) private String referredToId = null; - @JsonProperty("referredToClientReferenceId") - @Size(min = 2, max = 64) - private String referredToClientReferenceId = null; - @JsonProperty("reasons") @NotNull @Size(min=1) From 62a3b7aabed5f31389bcf8ef7fc204ba524cf13a Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 27 Sep 2023 10:32:46 +0530 Subject: [PATCH 155/283] HLM-3376: changed contract yaml and rowmapper --- .../contracts/adverse-event-referral-management.yml | 10 ---------- .../adrm/repository/rowmapper/ReferralRowMapper.java | 2 -- 2 files changed, 12 deletions(-) diff --git a/docs/health-api-specs/contracts/adverse-event-referral-management.yml b/docs/health-api-specs/contracts/adverse-event-referral-management.yml index 88436973115..926ea2ca85e 100644 --- a/docs/health-api-specs/contracts/adverse-event-referral-management.yml +++ b/docs/health-api-specs/contracts/adverse-event-referral-management.yml @@ -658,21 +658,11 @@ definitions: minLength: 2 maxLength: 64 description: Worker Id that is referring the Beneficiary - referringPartyClientReferenceId: - type: string - minLength: 2 - maxLength: 64 - description: Worker Client Reference Id that is referring the Beneficiary referredToId: type: string minLength: 2 maxLength: 64 description: Individual or Facility Id whom the Beneficiary is referred to. - referredToClientReferenceId: - type: string - minLength: 2 - maxLength: 64 - description: Individual or Facility Client Reference Id whom the Beneficiary is Referred To. referredToType: type: string description: Individual or Facility diff --git a/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/ReferralRowMapper.java b/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/ReferralRowMapper.java index 5b8336f0941..125eeed1b37 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/ReferralRowMapper.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/ReferralRowMapper.java @@ -66,9 +66,7 @@ public Referral mapRow(ResultSet resultSet, int i) throws SQLException { .projectBeneficiaryId(resultSet.getString("projectBeneficiaryId")) .projectBeneficiaryClientReferenceId(resultSet.getString("projectbeneficiaryclientreferenceid")) .referringPartyId(resultSet.getString("referrringpartyid")) - .referringPartyClientReferenceId(resultSet.getString("referringpartyclientreferenceid")) .referredToId(resultSet.getString("referredToId")) - .referredToClientReferenceId(resultSet.getString("referredtoclientreferenceid")) .referredToType(resultSet.getString("referredToType")) .adverseEvent(adverseEvent) .tenantId(resultSet.getString("tenantid")) From 6a2985e6405f7570dc4f76896987b27f2d4e3b50 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 27 Sep 2023 15:00:40 +0530 Subject: [PATCH 156/283] HLM-3069: changed module name to referral management --- build/build-config.yml | 7 ++++ .../adverseevent/AdverseEvent.java | 2 +- .../adverseevent/AdverseEventBulkRequest.java | 2 +- .../AdverseEventBulkResponse.java | 2 +- .../adverseevent/AdverseEventRequest.java | 2 +- .../adverseevent/AdverseEventResponse.java | 2 +- .../adverseevent/AdverseEventSearch.java | 2 +- .../AdverseEventSearchRequest.java | 2 +- .../{adrm => referralmanagement}/pom.xml | 11 ++--- .../egov/referralmanagement}/Constants.java | 2 +- .../ReferralManagementApplication.java} | 6 +-- .../config/MainConfiguration.java | 2 +- .../ReferralManagementConfiguration.java} | 16 ++++---- .../consumer/AdverseEventConsumer.java | 12 +++--- .../repository/AdverseEventRepository.java | 8 ++-- .../rowmapper/AdverseEventRowMapper.java | 4 +- .../service/AdverseEventService.java | 40 +++++++++---------- .../AdverseEventEnrichmentService.java | 16 ++++---- .../adverseevent/AdIsDeletedValidator.java | 6 +-- .../AdNonExistentEntityValidator.java | 10 ++--- .../adverseevent/AdNullIdValidator.java | 8 ++-- .../AdProjectTaskIdValidator.java | 25 +++++------- .../adverseevent/AdUniqueEntityValidator.java | 6 +-- .../AdverseEventApiController.java | 30 +++++++------- .../src/main/resources/application.properties | 24 +++++------ .../src/main/resources/db/Dockerfile | 0 .../src/main/resources/db/migrate.sh | 0 .../referral-management-persister.yml} | 2 +- .../org/egov/referralmanagement}/AppTest.java | 2 +- .../TestConfiguration.java | 2 +- .../AdverseEventRequestTestBuilder.java | 4 +- .../helper/AdverseEventTestBuilder.java | 4 +- .../AdverseEventApiControllerTest.java | 26 ++++++------ 33 files changed, 143 insertions(+), 144 deletions(-) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => referralmanagement}/adverseevent/AdverseEvent.java (96%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => referralmanagement}/adverseevent/AdverseEventBulkRequest.java (93%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => referralmanagement}/adverseevent/AdverseEventBulkResponse.java (93%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => referralmanagement}/adverseevent/AdverseEventRequest.java (91%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => referralmanagement}/adverseevent/AdverseEventResponse.java (91%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => referralmanagement}/adverseevent/AdverseEventSearch.java (92%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => referralmanagement}/adverseevent/AdverseEventSearchRequest.java (91%) rename health-services/{adrm => referralmanagement}/pom.xml (94%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/Constants.java (90%) rename health-services/{adrm/src/main/java/org/egov/adrm/AdrmApplication.java => referralmanagement/src/main/java/org/egov/referralmanagement/ReferralManagementApplication.java} (73%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/config/MainConfiguration.java (98%) rename health-services/{adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java => referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java} (62%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/consumer/AdverseEventConsumer.java (86%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/repository/AdverseEventRepository.java (95%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/repository/rowmapper/AdverseEventRowMapper.java (94%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/service/AdverseEventService.java (87%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/service/enrichment/AdverseEventEnrichmentService.java (72%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/validator/adverseevent/AdIsDeletedValidator.java (83%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/validator/adverseevent/AdNonExistentEntityValidator.java (88%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/validator/adverseevent/AdNullIdValidator.java (69%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/validator/adverseevent/AdProjectTaskIdValidator.java (88%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/validator/adverseevent/AdUniqueEntityValidator.java (88%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/web/controllers/AdverseEventApiController.java (85%) rename health-services/{adrm => referralmanagement}/src/main/resources/application.properties (81%) rename health-services/{adrm => referralmanagement}/src/main/resources/db/Dockerfile (100%) rename health-services/{adrm => referralmanagement}/src/main/resources/db/migrate.sh (100%) rename health-services/{adrm/src/main/resources/adrm-persister.yml => referralmanagement/src/main/resources/referral-management-persister.yml} (99%) rename health-services/{adrm/src/test/java/org/egov/adrm => referralmanagement/src/test/java/org/egov/referralmanagement}/AppTest.java (87%) rename health-services/{adrm/src/test/java/org/egov/adrm => referralmanagement/src/test/java/org/egov/referralmanagement}/TestConfiguration.java (91%) rename health-services/{adrm/src/test/java/org/egov/adrm => referralmanagement/src/test/java/org/egov/referralmanagement}/helper/AdverseEventRequestTestBuilder.java (94%) rename health-services/{adrm/src/test/java/org/egov/adrm => referralmanagement/src/test/java/org/egov/referralmanagement}/helper/AdverseEventTestBuilder.java (95%) rename health-services/{adrm/src/test/java/org/egov/adrm => referralmanagement/src/test/java/org/egov/referralmanagement}/web/controllers/AdverseEventApiControllerTest.java (91%) diff --git a/build/build-config.yml b/build/build-config.yml index 4ab442bf983..dd6f68f8512 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -36,6 +36,13 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "health-services/project/src/main/resources/db" image-name: "project-db" + - name: "builds/health-campaign-services/health-services/referralmanagement" + build: + - work-dir: "health-services/referralmanagement" + image-name: "referralmanagement" + dockerfile: "build/maven/Dockerfile" + - work-dir: "health-services/referralmanagement/src/main/resources/db" + image-name: "referralmanagement-db" - name: "builds/health-campaign-services/health-services/household" build: - work-dir: "health-services/household" diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEvent.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEvent.java similarity index 96% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEvent.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEvent.java index a85c8b89170..fbaf7c00736 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEvent.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEvent.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.adverseevent; +package org.egov.common.models.referralmanagement.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkRequest.java similarity index 93% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventBulkRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkRequest.java index a305d176c09..fa9248d1e1e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.adverseevent; +package org.egov.common.models.referralmanagement.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkResponse.java similarity index 93% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventBulkResponse.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkResponse.java index 175bac96780..880cc07875d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkResponse.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.adverseevent; +package org.egov.common.models.referralmanagement.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventRequest.java similarity index 91% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventRequest.java index af3404edfc5..6e470f9f435 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.adverseevent; +package org.egov.common.models.referralmanagement.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventResponse.java similarity index 91% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventResponse.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventResponse.java index ce8612a20cf..90851c1dcf7 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventResponse.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.adverseevent; +package org.egov.common.models.referralmanagement.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearch.java similarity index 92% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventSearch.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearch.java index bbf5d764698..19a8cd94e99 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearch.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.adverseevent; +package org.egov.common.models.referralmanagement.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearchRequest.java similarity index 91% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventSearchRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearchRequest.java index 63fafd7a860..68b546c3dac 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearchRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.adverseevent; +package org.egov.common.models.referralmanagement.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/adrm/pom.xml b/health-services/referralmanagement/pom.xml similarity index 94% rename from health-services/adrm/pom.xml rename to health-services/referralmanagement/pom.xml index 843e62de8af..fa6ecfea3cc 100644 --- a/health-services/adrm/pom.xml +++ b/health-services/referralmanagement/pom.xml @@ -4,10 +4,10 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.egov.adrm - adrm + org.egov + referralmanagement jar - adrm + referralmanagement 1.0.0 1.8 @@ -109,11 +109,6 @@ javax.validation validation-api - - org.springframework.boot - spring-boot-starter-test - test - diff --git a/health-services/adrm/src/main/java/org/egov/adrm/Constants.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java similarity index 90% rename from health-services/adrm/src/main/java/org/egov/adrm/Constants.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java index 5077f0f5d96..5598f4fa526 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/Constants.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java @@ -1,4 +1,4 @@ -package org.egov.adrm; +package org.egov.referralmanagement; public interface Constants { String SET_ADVERSE_EVENTS = "setAdverseEvents"; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/AdrmApplication.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/ReferralManagementApplication.java similarity index 73% rename from health-services/adrm/src/main/java/org/egov/adrm/AdrmApplication.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/ReferralManagementApplication.java index f034b325dd8..03494a4c86b 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/AdrmApplication.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/ReferralManagementApplication.java @@ -1,4 +1,4 @@ -package org.egov.adrm; +package org.egov.referralmanagement; import org.egov.tracer.config.TracerConfiguration; @@ -10,9 +10,9 @@ @SpringBootApplication @EnableCaching @Import({ TracerConfiguration.class }) -public class AdrmApplication +public class ReferralManagementApplication { public static void main(String[] args) throws Exception { - SpringApplication.run(AdrmApplication.class, args); + SpringApplication.run(ReferralManagementApplication.class, args); } } diff --git a/health-services/adrm/src/main/java/org/egov/adrm/config/MainConfiguration.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/MainConfiguration.java similarity index 98% rename from health-services/adrm/src/main/java/org/egov/adrm/config/MainConfiguration.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/MainConfiguration.java index 49e709427b8..86310611791 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/config/MainConfiguration.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/MainConfiguration.java @@ -1,4 +1,4 @@ -package org.egov.adrm.config; +package org.egov.referralmanagement.config; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonTypeInfo; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java similarity index 62% rename from health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java index cb98a038c73..a5d377e8bff 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java @@ -1,4 +1,4 @@ -package org.egov.adrm.config; +package org.egov.referralmanagement.config; import lombok.AllArgsConstructor; import lombok.Builder; @@ -14,23 +14,23 @@ @NoArgsConstructor @Builder @Component -public class AdrmConfiguration { - @Value("${adrm.adverseevent.kafka.create.topic}") +public class ReferralManagementConfiguration { + @Value("${referralmanagement.adverseevent.kafka.create.topic}") private String createAdverseEventTopic; - @Value("${adrm.adverseevent.kafka.update.topic}") + @Value("${referralmanagement.adverseevent.kafka.update.topic}") private String updateAdverseEventTopic; - @Value("${adrm.adverseevent.kafka.delete.topic}") + @Value("${referralmanagement.adverseevent.kafka.delete.topic}") private String deleteAdverseEventTopic; - @Value("${adrm.adverseevent.consumer.bulk.create.topic}") + @Value("${referralmanagement.adverseevent.consumer.bulk.create.topic}") private String createAdverseEventBulkTopic; - @Value("${adrm.adverseevent.consumer.bulk.update.topic}") + @Value("${referralmanagement.adverseevent.consumer.bulk.update.topic}") private String updateAdverseEventBulkTopic; - @Value("${adrm.adverseevent.consumer.bulk.delete.topic}") + @Value("${referralmanagement.adverseevent.consumer.bulk.delete.topic}") private String deleteAdverseEventBulkTopic; @Value("${egov.project.host}") diff --git a/health-services/adrm/src/main/java/org/egov/adrm/consumer/AdverseEventConsumer.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/AdverseEventConsumer.java similarity index 86% rename from health-services/adrm/src/main/java/org/egov/adrm/consumer/AdverseEventConsumer.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/AdverseEventConsumer.java index 96e424019d3..e1290be9810 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/consumer/AdverseEventConsumer.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/AdverseEventConsumer.java @@ -1,10 +1,10 @@ -package org.egov.adrm.consumer; +package org.egov.referralmanagement.consumer; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; -import org.egov.adrm.service.AdverseEventService; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; +import org.egov.referralmanagement.service.AdverseEventService; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -30,7 +30,7 @@ public AdverseEventConsumer(AdverseEventService adverseEventService, this.objectMapper = objectMapper; } - @KafkaListener(topics = "${adrm.adverseevent.consumer.bulk.create.topic}") + @KafkaListener(topics = "${referralmanagement.adverseevent.consumer.bulk.create.topic}") public void bulkCreate(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { @@ -43,7 +43,7 @@ public void bulkCreate(Map consumerRecord, } } - @KafkaListener(topics = "${adrm.adverseevent.consumer.bulk.update.topic}") + @KafkaListener(topics = "${referralmanagement.adverseevent.consumer.bulk.update.topic}") public void bulkUpdate(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { @@ -56,7 +56,7 @@ public void bulkUpdate(Map consumerRecord, } } - @KafkaListener(topics = "${adrm.adverseevent.consumer.bulk.delete.topic}") + @KafkaListener(topics = "${referralmanagement.adverseevent.consumer.bulk.delete.topic}") public void bulkDelete(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { diff --git a/health-services/adrm/src/main/java/org/egov/adrm/repository/AdverseEventRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/AdverseEventRepository.java similarity index 95% rename from health-services/adrm/src/main/java/org/egov/adrm/repository/AdverseEventRepository.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/AdverseEventRepository.java index 5cac554ce5c..5db9f77f424 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/repository/AdverseEventRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/AdverseEventRepository.java @@ -1,4 +1,4 @@ -package org.egov.adrm.repository; +package org.egov.referralmanagement.repository; import lombok.extern.slf4j.Slf4j; import org.egov.common.data.query.builder.GenericQueryBuilder; @@ -6,11 +6,11 @@ import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.adverseevent.AdverseEventSearch; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearch; import org.egov.common.models.project.Task; import org.egov.common.producer.Producer; -import org.egov.adrm.repository.rowmapper.AdverseEventRowMapper; +import org.egov.referralmanagement.repository.rowmapper.AdverseEventRowMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/AdverseEventRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/AdverseEventRowMapper.java similarity index 94% rename from health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/AdverseEventRowMapper.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/AdverseEventRowMapper.java index edbf7e23af6..6dd6ff19472 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/AdverseEventRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/AdverseEventRowMapper.java @@ -1,9 +1,9 @@ -package org.egov.adrm.repository.rowmapper; +package org.egov.referralmanagement.repository.rowmapper; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/AdverseEventService.java similarity index 87% rename from health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/AdverseEventService.java index 54b754ca746..a67272c4267 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/AdverseEventService.java @@ -1,21 +1,21 @@ -package org.egov.adrm.service; +package org.egov.referralmanagement.service; import lombok.extern.slf4j.Slf4j; -import org.egov.adrm.Constants; -import org.egov.adrm.config.AdrmConfiguration; -import org.egov.adrm.repository.AdverseEventRepository; -import org.egov.adrm.service.enrichment.AdverseEventEnrichmentService; -import org.egov.adrm.validator.adverseevent.AdIsDeletedValidator; -import org.egov.adrm.validator.adverseevent.AdNonExistentEntityValidator; -import org.egov.adrm.validator.adverseevent.AdNullIdValidator; -import org.egov.adrm.validator.adverseevent.AdProjectTaskIdValidator; -import org.egov.adrm.validator.adverseevent.AdUniqueEntityValidator; +import org.egov.referralmanagement.Constants; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.repository.AdverseEventRepository; +import org.egov.referralmanagement.service.enrichment.AdverseEventEnrichmentService; +import org.egov.referralmanagement.validator.adverseevent.AdIsDeletedValidator; +import org.egov.referralmanagement.validator.adverseevent.AdNonExistentEntityValidator; +import org.egov.referralmanagement.validator.adverseevent.AdNullIdValidator; +import org.egov.referralmanagement.validator.adverseevent.AdProjectTaskIdValidator; +import org.egov.referralmanagement.validator.adverseevent.AdUniqueEntityValidator; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; -import org.egov.common.models.adrm.adverseevent.AdverseEventRequest; -import org.egov.common.models.adrm.adverseevent.AdverseEventSearchRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearchRequest; import org.egov.common.service.IdGenService; import org.egov.common.utils.CommonUtils; import org.egov.common.validator.Validator; @@ -47,7 +47,7 @@ public class AdverseEventService { private final AdverseEventRepository adverseEventRepository; - private final AdrmConfiguration adrmConfiguration; + private final ReferralManagementConfiguration referralManagementConfiguration; private final AdverseEventEnrichmentService adverseEventEnrichmentService; @@ -71,13 +71,13 @@ public class AdverseEventService { public AdverseEventService( IdGenService idGenService, AdverseEventRepository adverseEventRepository, - AdrmConfiguration adrmConfiguration, + ReferralManagementConfiguration referralManagementConfiguration, AdverseEventEnrichmentService adverseEventEnrichmentService, List> validators ) { this.idGenService = idGenService; this.adverseEventRepository = adverseEventRepository; - this.adrmConfiguration = adrmConfiguration; + this.referralManagementConfiguration = referralManagementConfiguration; this.adverseEventEnrichmentService = adverseEventEnrichmentService; this.validators = validators; } @@ -102,7 +102,7 @@ public List create(AdverseEventBulkRequest adverseEventRequest, bo log.info("processing {} valid entities", validAdverseEvents.size()); adverseEventEnrichmentService.create(validAdverseEvents, adverseEventRequest); adverseEventRepository.save(validAdverseEvents, - adrmConfiguration.getCreateAdverseEventTopic()); + referralManagementConfiguration.getCreateAdverseEventTopic()); log.info("successfully created adverse events"); } } catch (Exception exception) { @@ -135,7 +135,7 @@ public List update(AdverseEventBulkRequest adverseEventRequest, bo log.info("processing {} valid entities", validAdverseEvents.size()); adverseEventEnrichmentService.update(validAdverseEvents, adverseEventRequest); adverseEventRepository.save(validAdverseEvents, - adrmConfiguration.getUpdateAdverseEventTopic()); + referralManagementConfiguration.getUpdateAdverseEventTopic()); log.info("successfully updated bulk adverse events"); } } catch (Exception exception) { @@ -195,7 +195,7 @@ public List delete(AdverseEventBulkRequest adverseEventRequest, bo .findById(adverseEventIds, false); adverseEventEnrichmentService.delete(existingAdverseEvents, adverseEventRequest); adverseEventRepository.save(existingAdverseEvents, - adrmConfiguration.getDeleteAdverseEventTopic()); + referralManagementConfiguration.getDeleteAdverseEventTopic()); log.info("successfully deleted entities"); } } catch (Exception exception) { diff --git a/health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/AdverseEventEnrichmentService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/AdverseEventEnrichmentService.java similarity index 72% rename from health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/AdverseEventEnrichmentService.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/AdverseEventEnrichmentService.java index 03c7506461b..f8a28ddc0a6 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/AdverseEventEnrichmentService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/AdverseEventEnrichmentService.java @@ -1,12 +1,12 @@ -package org.egov.adrm.service.enrichment; +package org.egov.referralmanagement.service.enrichment; import lombok.extern.slf4j.Slf4j; -import org.egov.adrm.config.AdrmConfiguration; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; import org.egov.common.service.IdGenService; import org.egov.common.utils.CommonUtils; -import org.egov.adrm.repository.AdverseEventRepository; +import org.egov.referralmanagement.repository.AdverseEventRepository; import org.springframework.stereotype.Component; import java.util.List; @@ -20,13 +20,13 @@ public class AdverseEventEnrichmentService { private final IdGenService idGenService; - private final AdrmConfiguration adrmConfiguration; + private final ReferralManagementConfiguration referralManagementConfiguration; private final AdverseEventRepository adverseEventRepository; - public AdverseEventEnrichmentService(IdGenService idGenService, AdrmConfiguration adrmConfiguration, AdverseEventRepository adverseEventRepository) { + public AdverseEventEnrichmentService(IdGenService idGenService, ReferralManagementConfiguration referralManagementConfiguration, AdverseEventRepository adverseEventRepository) { this.idGenService = idGenService; - this.adrmConfiguration = adrmConfiguration; + this.referralManagementConfiguration = referralManagementConfiguration; this.adverseEventRepository = adverseEventRepository; } diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdIsDeletedValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdIsDeletedValidator.java similarity index 83% rename from health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdIsDeletedValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdIsDeletedValidator.java index 1e66ad39329..b4ae9c3c17d 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdIsDeletedValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdIsDeletedValidator.java @@ -1,9 +1,9 @@ -package org.egov.adrm.validator.adverseevent; +package org.egov.referralmanagement.validator.adverseevent; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNonExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNonExistentEntityValidator.java similarity index 88% rename from health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNonExistentEntityValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNonExistentEntityValidator.java index dca45c7b2a1..8fea8a00e6e 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNonExistentEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNonExistentEntityValidator.java @@ -1,11 +1,11 @@ -package org.egov.adrm.validator.adverseevent; +package org.egov.referralmanagement.validator.adverseevent; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; -import org.egov.adrm.repository.AdverseEventRepository; +import org.egov.referralmanagement.repository.AdverseEventRepository; import org.egov.common.models.Error; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; @@ -18,7 +18,7 @@ import java.util.Map; import java.util.stream.Collectors; -import static org.egov.adrm.Constants.GET_ID; +import static org.egov.referralmanagement.Constants.GET_ID; import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.getIdToObjMap; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNullIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNullIdValidator.java similarity index 69% rename from health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNullIdValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNullIdValidator.java index 97712959369..f051349ee82 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNullIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNullIdValidator.java @@ -1,9 +1,9 @@ -package org.egov.adrm.validator.adverseevent; +package org.egov.referralmanagement.validator.adverseevent; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -11,7 +11,7 @@ import java.util.List; import java.util.Map; -import static org.egov.adrm.Constants.GET_ADVERSE_EVENTS; +import static org.egov.referralmanagement.Constants.GET_ADVERSE_EVENTS; import static org.egov.common.utils.CommonUtils.validateForNullId; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdProjectTaskIdValidator.java similarity index 88% rename from health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdProjectTaskIdValidator.java index 16865894baf..90cb6639da4 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdProjectTaskIdValidator.java @@ -1,13 +1,11 @@ -package org.egov.adrm.validator.adverseevent; +package org.egov.referralmanagement.validator.adverseevent; import lombok.extern.slf4j.Slf4j; -import org.egov.adrm.config.AdrmConfiguration; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; -import org.egov.common.models.project.BeneficiaryBulkRequest; import org.egov.common.models.project.BeneficiaryBulkResponse; -import org.egov.common.models.project.BeneficiaryResponse; import org.egov.common.models.project.BeneficiarySearchRequest; import org.egov.common.models.project.ProjectBeneficiary; import org.egov.common.models.project.ProjectBeneficiarySearch; @@ -15,15 +13,14 @@ import org.egov.common.models.project.TaskBulkResponse; import org.egov.common.models.project.TaskSearch; import org.egov.common.models.project.TaskSearchRequest; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -41,12 +38,12 @@ @Slf4j public class AdProjectTaskIdValidator implements Validator { private final ServiceRequestClient serviceRequestClient; - private final AdrmConfiguration adrmConfiguration; + private final ReferralManagementConfiguration referralManagementConfiguration; @Autowired - public AdProjectTaskIdValidator(ServiceRequestClient serviceRequestClient, AdrmConfiguration adrmConfiguration) { + public AdProjectTaskIdValidator(ServiceRequestClient serviceRequestClient, ReferralManagementConfiguration referralManagementConfiguration) { this.serviceRequestClient = serviceRequestClient; - this.adrmConfiguration = adrmConfiguration; + this.referralManagementConfiguration = referralManagementConfiguration; } @@ -77,8 +74,8 @@ public Map> validate(AdverseEventBulkRequest request) .id(taskIdList.isEmpty() ? null : taskIdList) .clientReferenceId(taskClientReferenceIdList.isEmpty() ? null : taskClientReferenceIdList).build(); TaskBulkResponse taskBulkResponse = serviceRequestClient.fetchResult( - new StringBuilder(adrmConfiguration.getProjectHost() - + adrmConfiguration.getProjectTaskSearchUrl() + new StringBuilder(referralManagementConfiguration.getProjectHost() + + referralManagementConfiguration.getProjectTaskSearchUrl() +"?limit=" + entities.size() + "&offset=0&tenantId=" + tenantId), TaskSearchRequest.builder().requestInfo(request.getRequestInfo()).task(taskSearch).build(), @@ -90,8 +87,8 @@ public Map> validate(AdverseEventBulkRequest request) .clientReferenceId(projectBeneficiaryClientReferenceIdList.isEmpty() ? null : projectBeneficiaryClientReferenceIdList) .build(); BeneficiaryBulkResponse beneficiaryBulkResponse = serviceRequestClient.fetchResult( - new StringBuilder(adrmConfiguration.getProjectHost() - + adrmConfiguration.getProjectBeneficiarySearchUrl() + new StringBuilder(referralManagementConfiguration.getProjectHost() + + referralManagementConfiguration.getProjectBeneficiarySearchUrl() +"?limit=" + entities.size() + "&offset=0&tenantId=" + tenantId), BeneficiarySearchRequest.builder().requestInfo(request.getRequestInfo()).projectBeneficiary(projectBeneficiarySearch).build(), diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdUniqueEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdUniqueEntityValidator.java similarity index 88% rename from health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdUniqueEntityValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdUniqueEntityValidator.java index 823e1932938..8e06b42a9a2 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdUniqueEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdUniqueEntityValidator.java @@ -1,9 +1,9 @@ -package org.egov.adrm.validator.adverseevent; +package org.egov.referralmanagement.validator.adverseevent; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/AdverseEventApiController.java similarity index 85% rename from health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/AdverseEventApiController.java index 68f3963ff63..d7409965f65 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/AdverseEventApiController.java @@ -1,15 +1,15 @@ -package org.egov.adrm.web.controllers; +package org.egov.referralmanagement.web.controllers; import io.swagger.annotations.ApiParam; -import org.egov.adrm.config.AdrmConfiguration; -import org.egov.adrm.service.AdverseEventService; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.service.AdverseEventService; import org.egov.common.contract.response.ResponseInfo; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkResponse; -import org.egov.common.models.adrm.adverseevent.AdverseEventRequest; -import org.egov.common.models.adrm.adverseevent.AdverseEventResponse; -import org.egov.common.models.adrm.adverseevent.AdverseEventSearchRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkResponse; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventResponse; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearchRequest; import org.egov.common.producer.Producer; import org.egov.common.utils.ResponseInfoFactory; import org.springframework.http.HttpStatus; @@ -39,18 +39,18 @@ public class AdverseEventApiController { private final Producer producer; - private final AdrmConfiguration adrmConfiguration; + private final ReferralManagementConfiguration referralManagementConfiguration; public AdverseEventApiController( HttpServletRequest httpServletRequest, AdverseEventService adverseEventService, Producer producer, - AdrmConfiguration adrmConfiguration + ReferralManagementConfiguration referralManagementConfiguration ) { this.httpServletRequest = httpServletRequest; this.adverseEventService = adverseEventService; this.producer = producer; - this.adrmConfiguration = adrmConfiguration; + this.referralManagementConfiguration = referralManagementConfiguration; } @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) @@ -72,7 +72,7 @@ public ResponseEntity adverseEventV1CreatePost(@ApiParam(v public ResponseEntity adverseEventBulkV1CreatePost(@ApiParam(value = "Capture details of Adverse Event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); adverseEventService.putInCache(request.getAdverseEvents()); - producer.push(adrmConfiguration.getCreateAdverseEventBulkTopic(), request); + producer.push(referralManagementConfiguration.getCreateAdverseEventBulkTopic(), request); return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory .createResponseInfo(request.getRequestInfo(), true)); @@ -110,7 +110,7 @@ public ResponseEntity adverseEventV1UpdatePost(@ApiParam(v @RequestMapping(value = "/v1/bulk/_update", method = RequestMethod.POST) public ResponseEntity adverseEventV1BulkUpdatePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); - producer.push(adrmConfiguration.getUpdateAdverseEventBulkTopic(), request); + producer.push(referralManagementConfiguration.getUpdateAdverseEventBulkTopic(), request); return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory .createResponseInfo(request.getRequestInfo(), true)); @@ -133,7 +133,7 @@ public ResponseEntity adverseEventV1DeletePost(@ApiParam(v @RequestMapping(value = "/v1/bulk/_delete", method = RequestMethod.POST) public ResponseEntity adverseEventV1BulkDeletePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); - producer.push(adrmConfiguration.getDeleteAdverseEventBulkTopic(), request); + producer.push(referralManagementConfiguration.getDeleteAdverseEventBulkTopic(), request); return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory .createResponseInfo(request.getRequestInfo(), true)); diff --git a/health-services/adrm/src/main/resources/application.properties b/health-services/referralmanagement/src/main/resources/application.properties similarity index 81% rename from health-services/adrm/src/main/resources/application.properties rename to health-services/referralmanagement/src/main/resources/application.properties index 18f90dea65a..4beef1d24b0 100644 --- a/health-services/adrm/src/main/resources/application.properties +++ b/health-services/referralmanagement/src/main/resources/application.properties @@ -1,4 +1,4 @@ -server.servlet.context-path=/adrm +server.servlet.context-path=/referralmanagement server.port=8080 app.timezone=UTC @@ -55,8 +55,8 @@ kafka.producer.config.buffer_memory_config=33554432 egov.idgen.host=http://localhost:8081/ egov.idgen.path=egov-idgen/id/_generate egov.idgen.integration.enabled=true -adrm.adverseevent.idgen.id.format=adrm.adverseevent.id -adrm.referral.idgen.id.format=adrm.referral.id +referralmanagement.adverseevent.idgen.id.format=referralmanagement.adverseevent.id +referralmanagement.referral.idgen.id.format=referralmanagement.referral.id idgen.project.beneficiary.id.format=project.beneficiary.id project.staff.idgen.id.format=project.staff.id project.facility.idgen.id.format=project.facility.id @@ -99,19 +99,19 @@ egov.search.project.beneficiary.url=/project/beneficiary/v1/_search # ADRM KAFKA CONFIG -adrm.adverseevent.kafka.create.topic=save-adverse-event-topic -adrm.adverseevent.kafka.update.topic=update-adverse-event-topic -adrm.adverseevent.kafka.delete.topic=delete-adverse-event-topic +referralmanagement.adverseevent.kafka.create.topic=save-adverse-event-topic +referralmanagement.adverseevent.kafka.update.topic=update-adverse-event-topic +referralmanagement.adverseevent.kafka.delete.topic=delete-adverse-event-topic -adrm.adverseevent.consumer.bulk.create.topic=save-adverse-event-bulk-topic -adrm.adverseevent.consumer.bulk.update.topic=update-adverse-event-bulk-topic -adrm.adverseevent.consumer.bulk.delete.topic=delete-adverse-event-bulk-topic +referralmanagement.adverseevent.consumer.bulk.create.topic=save-adverse-event-bulk-topic +referralmanagement.adverseevent.consumer.bulk.update.topic=update-adverse-event-bulk-topic +referralmanagement.adverseevent.consumer.bulk.delete.topic=delete-adverse-event-bulk-topic search.api.limit=1000 -adrm.default.offset=0 -adrm.default.limit=100 -adrm.search.max.limit=200 +referralmanagement.default.offset=0 +referralmanagement.default.limit=100 +referralmanagement.search.max.limit=200 #location config diff --git a/health-services/adrm/src/main/resources/db/Dockerfile b/health-services/referralmanagement/src/main/resources/db/Dockerfile similarity index 100% rename from health-services/adrm/src/main/resources/db/Dockerfile rename to health-services/referralmanagement/src/main/resources/db/Dockerfile diff --git a/health-services/adrm/src/main/resources/db/migrate.sh b/health-services/referralmanagement/src/main/resources/db/migrate.sh similarity index 100% rename from health-services/adrm/src/main/resources/db/migrate.sh rename to health-services/referralmanagement/src/main/resources/db/migrate.sh diff --git a/health-services/adrm/src/main/resources/adrm-persister.yml b/health-services/referralmanagement/src/main/resources/referral-management-persister.yml similarity index 99% rename from health-services/adrm/src/main/resources/adrm-persister.yml rename to health-services/referralmanagement/src/main/resources/referral-management-persister.yml index f1780c39448..49fb3454ed8 100644 --- a/health-services/adrm/src/main/resources/adrm-persister.yml +++ b/health-services/referralmanagement/src/main/resources/referral-management-persister.yml @@ -1,5 +1,5 @@ serviceMaps: - serviceName: adrm + serviceName: referralmanagement mappings: - version: 1.0 description: Saves a adverse event diff --git a/health-services/adrm/src/test/java/org/egov/adrm/AppTest.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/AppTest.java similarity index 87% rename from health-services/adrm/src/test/java/org/egov/adrm/AppTest.java rename to health-services/referralmanagement/src/test/java/org/egov/referralmanagement/AppTest.java index d76b5eea977..48b5fb750f6 100644 --- a/health-services/adrm/src/test/java/org/egov/adrm/AppTest.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/AppTest.java @@ -1,4 +1,4 @@ -package org.egov.adrm; +package org.egov.referralmanagement; import static org.junit.Assert.assertTrue; diff --git a/health-services/adrm/src/test/java/org/egov/adrm/TestConfiguration.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/TestConfiguration.java similarity index 91% rename from health-services/adrm/src/test/java/org/egov/adrm/TestConfiguration.java rename to health-services/referralmanagement/src/test/java/org/egov/referralmanagement/TestConfiguration.java index 591f0b3dbfc..c27d6693d1c 100644 --- a/health-services/adrm/src/test/java/org/egov/adrm/TestConfiguration.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/TestConfiguration.java @@ -1,4 +1,4 @@ -package org.egov.adrm; +package org.egov.referralmanagement; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/health-services/adrm/src/test/java/org/egov/adrm/helper/AdverseEventRequestTestBuilder.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventRequestTestBuilder.java similarity index 94% rename from health-services/adrm/src/test/java/org/egov/adrm/helper/AdverseEventRequestTestBuilder.java rename to health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventRequestTestBuilder.java index 10bbe9b574a..983b5dee405 100644 --- a/health-services/adrm/src/test/java/org/egov/adrm/helper/AdverseEventRequestTestBuilder.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventRequestTestBuilder.java @@ -1,7 +1,7 @@ -package org.egov.adrm.helper; +package org.egov.referralmanagement.helper; import org.egov.common.helper.RequestInfoTestBuilder; -import org.egov.common.models.adrm.adverseevent.AdverseEventRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventRequest; import java.util.ArrayList; diff --git a/health-services/adrm/src/test/java/org/egov/adrm/helper/AdverseEventTestBuilder.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventTestBuilder.java similarity index 95% rename from health-services/adrm/src/test/java/org/egov/adrm/helper/AdverseEventTestBuilder.java rename to health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventTestBuilder.java index aed221446cf..1af8b9e9d10 100644 --- a/health-services/adrm/src/test/java/org/egov/adrm/helper/AdverseEventTestBuilder.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventTestBuilder.java @@ -1,7 +1,7 @@ -package org.egov.adrm.helper; +package org.egov.referralmanagement.helper; import org.egov.common.helper.AuditDetailsTestBuilder; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; import java.util.ArrayList; import java.util.Arrays; diff --git a/health-services/adrm/src/test/java/org/egov/adrm/web/controllers/AdverseEventApiControllerTest.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/AdverseEventApiControllerTest.java similarity index 91% rename from health-services/adrm/src/test/java/org/egov/adrm/web/controllers/AdverseEventApiControllerTest.java rename to health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/AdverseEventApiControllerTest.java index f6c95c063fc..e6a7ad40b98 100644 --- a/health-services/adrm/src/test/java/org/egov/adrm/web/controllers/AdverseEventApiControllerTest.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/AdverseEventApiControllerTest.java @@ -1,18 +1,18 @@ -package org.egov.adrm.web.controllers; +package org.egov.referralmanagement.web.controllers; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.adrm.TestConfiguration; -import org.egov.adrm.config.AdrmConfiguration; -import org.egov.adrm.helper.AdverseEventRequestTestBuilder; -import org.egov.adrm.helper.AdverseEventTestBuilder; -import org.egov.adrm.service.AdverseEventService; +import org.egov.referralmanagement.TestConfiguration; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.helper.AdverseEventRequestTestBuilder; +import org.egov.referralmanagement.helper.AdverseEventTestBuilder; +import org.egov.referralmanagement.service.AdverseEventService; import org.egov.common.helper.RequestInfoTestBuilder; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkResponse; -import org.egov.common.models.adrm.adverseevent.AdverseEventRequest; -import org.egov.common.models.adrm.adverseevent.AdverseEventResponse; -import org.egov.common.models.adrm.adverseevent.AdverseEventSearch; -import org.egov.common.models.adrm.adverseevent.AdverseEventSearchRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkResponse; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventResponse; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearch; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearchRequest; import org.egov.common.producer.Producer; import org.egov.tracer.model.CustomException; import org.egov.tracer.model.ErrorRes; @@ -52,7 +52,7 @@ public class AdverseEventApiControllerTest { private Producer producer; @MockBean - AdrmConfiguration adrmConfiguration; + ReferralManagementConfiguration referralManagementConfiguration; @Test @DisplayName("should create adverse event and return with 202 accepted") From 51cd6f64683171dfcd4bb4b3eef2a5caaaea3cd4 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 27 Sep 2023 15:00:40 +0530 Subject: [PATCH 157/283] HLM-3069: changed module name to referral management --- build/build-config.yml | 7 ++++ .../adverseevent/AdverseEvent.java | 2 +- .../adverseevent/AdverseEventBulkRequest.java | 2 +- .../AdverseEventBulkResponse.java | 2 +- .../adverseevent/AdverseEventRequest.java | 2 +- .../adverseevent/AdverseEventResponse.java | 2 +- .../adverseevent/AdverseEventSearch.java | 2 +- .../AdverseEventSearchRequest.java | 2 +- .../{adrm => referralmanagement}/pom.xml | 11 ++--- .../egov/referralmanagement}/Constants.java | 2 +- .../ReferralManagementApplication.java} | 6 +-- .../config/MainConfiguration.java | 2 +- .../ReferralManagementConfiguration.java} | 16 ++++---- .../consumer/AdverseEventConsumer.java | 12 +++--- .../consumer/ReferralManagementConsumer.java | 0 .../repository/AdverseEventRepository.java | 8 ++-- .../ReferralManagementRepository.java | 0 .../rowmapper/AdverseEventRowMapper.java | 4 +- .../rowmapper/ReferralRowMapper.java | 0 .../service/AdverseEventService.java | 40 +++++++++---------- .../service/ReferralManagementService.java | 0 .../AdverseEventEnrichmentService.java | 16 ++++---- .../ReferralManagementEnrichmentService.java | 0 .../adverseevent/AdIsDeletedValidator.java | 6 +-- .../AdNonExistentEntityValidator.java | 10 ++--- .../adverseevent/AdNullIdValidator.java | 8 ++-- .../AdProjectTaskIdValidator.java | 25 +++++------- .../adverseevent/AdUniqueEntityValidator.java | 6 +-- .../AdverseEventApiController.java | 30 +++++++------- .../ReferralManagementApiController.java | 0 .../src/main/resources/application.properties | 24 +++++------ .../src/main/resources/db/Dockerfile | 0 .../src/main/resources/db/migrate.sh | 0 .../referral-management-persister.yml} | 2 +- .../org/egov/referralmanagement}/AppTest.java | 2 +- .../TestConfiguration.java | 2 +- .../AdverseEventRequestTestBuilder.java | 4 +- .../helper/AdverseEventTestBuilder.java | 4 +- .../AdverseEventApiControllerTest.java | 26 ++++++------ 39 files changed, 143 insertions(+), 144 deletions(-) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => referralmanagement}/adverseevent/AdverseEvent.java (96%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => referralmanagement}/adverseevent/AdverseEventBulkRequest.java (93%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => referralmanagement}/adverseevent/AdverseEventBulkResponse.java (93%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => referralmanagement}/adverseevent/AdverseEventRequest.java (91%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => referralmanagement}/adverseevent/AdverseEventResponse.java (91%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => referralmanagement}/adverseevent/AdverseEventSearch.java (92%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => referralmanagement}/adverseevent/AdverseEventSearchRequest.java (91%) rename health-services/{adrm => referralmanagement}/pom.xml (94%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/Constants.java (93%) rename health-services/{adrm/src/main/java/org/egov/adrm/AdrmApplication.java => referralmanagement/src/main/java/org/egov/referralmanagement/ReferralManagementApplication.java} (73%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/config/MainConfiguration.java (98%) rename health-services/{adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java => referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java} (76%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/consumer/AdverseEventConsumer.java (86%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/consumer/ReferralManagementConsumer.java (100%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/repository/AdverseEventRepository.java (95%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/repository/ReferralManagementRepository.java (100%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/repository/rowmapper/AdverseEventRowMapper.java (94%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/repository/rowmapper/ReferralRowMapper.java (100%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/service/AdverseEventService.java (87%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/service/ReferralManagementService.java (100%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/service/enrichment/AdverseEventEnrichmentService.java (72%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/service/enrichment/ReferralManagementEnrichmentService.java (100%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/validator/adverseevent/AdIsDeletedValidator.java (83%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/validator/adverseevent/AdNonExistentEntityValidator.java (88%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/validator/adverseevent/AdNullIdValidator.java (69%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/validator/adverseevent/AdProjectTaskIdValidator.java (88%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/validator/adverseevent/AdUniqueEntityValidator.java (88%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/web/controllers/AdverseEventApiController.java (85%) rename health-services/{adrm/src/main/java/org/egov/adrm => referralmanagement/src/main/java/org/egov/referralmanagement}/web/controllers/ReferralManagementApiController.java (100%) rename health-services/{adrm => referralmanagement}/src/main/resources/application.properties (83%) rename health-services/{adrm => referralmanagement}/src/main/resources/db/Dockerfile (100%) rename health-services/{adrm => referralmanagement}/src/main/resources/db/migrate.sh (100%) rename health-services/{adrm/src/main/resources/adrm-persister.yml => referralmanagement/src/main/resources/referral-management-persister.yml} (99%) rename health-services/{adrm/src/test/java/org/egov/adrm => referralmanagement/src/test/java/org/egov/referralmanagement}/AppTest.java (87%) rename health-services/{adrm/src/test/java/org/egov/adrm => referralmanagement/src/test/java/org/egov/referralmanagement}/TestConfiguration.java (91%) rename health-services/{adrm/src/test/java/org/egov/adrm => referralmanagement/src/test/java/org/egov/referralmanagement}/helper/AdverseEventRequestTestBuilder.java (94%) rename health-services/{adrm/src/test/java/org/egov/adrm => referralmanagement/src/test/java/org/egov/referralmanagement}/helper/AdverseEventTestBuilder.java (95%) rename health-services/{adrm/src/test/java/org/egov/adrm => referralmanagement/src/test/java/org/egov/referralmanagement}/web/controllers/AdverseEventApiControllerTest.java (91%) diff --git a/build/build-config.yml b/build/build-config.yml index 4ab442bf983..dd6f68f8512 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -36,6 +36,13 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "health-services/project/src/main/resources/db" image-name: "project-db" + - name: "builds/health-campaign-services/health-services/referralmanagement" + build: + - work-dir: "health-services/referralmanagement" + image-name: "referralmanagement" + dockerfile: "build/maven/Dockerfile" + - work-dir: "health-services/referralmanagement/src/main/resources/db" + image-name: "referralmanagement-db" - name: "builds/health-campaign-services/health-services/household" build: - work-dir: "health-services/household" diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEvent.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEvent.java similarity index 96% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEvent.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEvent.java index a85c8b89170..fbaf7c00736 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEvent.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEvent.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.adverseevent; +package org.egov.common.models.referralmanagement.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkRequest.java similarity index 93% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventBulkRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkRequest.java index a305d176c09..fa9248d1e1e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.adverseevent; +package org.egov.common.models.referralmanagement.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkResponse.java similarity index 93% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventBulkResponse.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkResponse.java index 175bac96780..880cc07875d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkResponse.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.adverseevent; +package org.egov.common.models.referralmanagement.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventRequest.java similarity index 91% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventRequest.java index af3404edfc5..6e470f9f435 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.adverseevent; +package org.egov.common.models.referralmanagement.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventResponse.java similarity index 91% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventResponse.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventResponse.java index ce8612a20cf..90851c1dcf7 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventResponse.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.adverseevent; +package org.egov.common.models.referralmanagement.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearch.java similarity index 92% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventSearch.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearch.java index bbf5d764698..19a8cd94e99 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearch.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.adverseevent; +package org.egov.common.models.referralmanagement.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearchRequest.java similarity index 91% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventSearchRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearchRequest.java index 63fafd7a860..68b546c3dac 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/adverseevent/AdverseEventSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearchRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.adverseevent; +package org.egov.common.models.referralmanagement.adverseevent; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/adrm/pom.xml b/health-services/referralmanagement/pom.xml similarity index 94% rename from health-services/adrm/pom.xml rename to health-services/referralmanagement/pom.xml index 843e62de8af..fa6ecfea3cc 100644 --- a/health-services/adrm/pom.xml +++ b/health-services/referralmanagement/pom.xml @@ -4,10 +4,10 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - org.egov.adrm - adrm + org.egov + referralmanagement jar - adrm + referralmanagement 1.0.0 1.8 @@ -109,11 +109,6 @@ javax.validation validation-api - - org.springframework.boot - spring-boot-starter-test - test - diff --git a/health-services/adrm/src/main/java/org/egov/adrm/Constants.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java similarity index 93% rename from health-services/adrm/src/main/java/org/egov/adrm/Constants.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java index 74d6eb8bda6..b343825766e 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/Constants.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java @@ -1,4 +1,4 @@ -package org.egov.adrm; +package org.egov.referralmanagement; public interface Constants { String SET_ADVERSE_EVENTS = "setAdverseEvents"; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/AdrmApplication.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/ReferralManagementApplication.java similarity index 73% rename from health-services/adrm/src/main/java/org/egov/adrm/AdrmApplication.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/ReferralManagementApplication.java index f034b325dd8..03494a4c86b 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/AdrmApplication.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/ReferralManagementApplication.java @@ -1,4 +1,4 @@ -package org.egov.adrm; +package org.egov.referralmanagement; import org.egov.tracer.config.TracerConfiguration; @@ -10,9 +10,9 @@ @SpringBootApplication @EnableCaching @Import({ TracerConfiguration.class }) -public class AdrmApplication +public class ReferralManagementApplication { public static void main(String[] args) throws Exception { - SpringApplication.run(AdrmApplication.class, args); + SpringApplication.run(ReferralManagementApplication.class, args); } } diff --git a/health-services/adrm/src/main/java/org/egov/adrm/config/MainConfiguration.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/MainConfiguration.java similarity index 98% rename from health-services/adrm/src/main/java/org/egov/adrm/config/MainConfiguration.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/MainConfiguration.java index 49e709427b8..86310611791 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/config/MainConfiguration.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/MainConfiguration.java @@ -1,4 +1,4 @@ -package org.egov.adrm.config; +package org.egov.referralmanagement.config; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonTypeInfo; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java similarity index 76% rename from health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java index 05e03ab718d..37c9fea3df4 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/config/AdrmConfiguration.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java @@ -1,4 +1,4 @@ -package org.egov.adrm.config; +package org.egov.referralmanagement.config; import lombok.AllArgsConstructor; import lombok.Builder; @@ -14,23 +14,23 @@ @NoArgsConstructor @Builder @Component -public class AdrmConfiguration { - @Value("${adrm.adverseevent.kafka.create.topic}") +public class ReferralManagementConfiguration { + @Value("${referralmanagement.adverseevent.kafka.create.topic}") private String createAdverseEventTopic; - @Value("${adrm.adverseevent.kafka.update.topic}") + @Value("${referralmanagement.adverseevent.kafka.update.topic}") private String updateAdverseEventTopic; - @Value("${adrm.adverseevent.kafka.delete.topic}") + @Value("${referralmanagement.adverseevent.kafka.delete.topic}") private String deleteAdverseEventTopic; - @Value("${adrm.adverseevent.consumer.bulk.create.topic}") + @Value("${referralmanagement.adverseevent.consumer.bulk.create.topic}") private String createAdverseEventBulkTopic; - @Value("${adrm.adverseevent.consumer.bulk.update.topic}") + @Value("${referralmanagement.adverseevent.consumer.bulk.update.topic}") private String updateAdverseEventBulkTopic; - @Value("${adrm.adverseevent.consumer.bulk.delete.topic}") + @Value("${referralmanagement.adverseevent.consumer.bulk.delete.topic}") private String deleteAdverseEventBulkTopic; @Value("${egov.project.host}") diff --git a/health-services/adrm/src/main/java/org/egov/adrm/consumer/AdverseEventConsumer.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/AdverseEventConsumer.java similarity index 86% rename from health-services/adrm/src/main/java/org/egov/adrm/consumer/AdverseEventConsumer.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/AdverseEventConsumer.java index 96e424019d3..e1290be9810 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/consumer/AdverseEventConsumer.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/AdverseEventConsumer.java @@ -1,10 +1,10 @@ -package org.egov.adrm.consumer; +package org.egov.referralmanagement.consumer; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; -import org.egov.adrm.service.AdverseEventService; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; +import org.egov.referralmanagement.service.AdverseEventService; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -30,7 +30,7 @@ public AdverseEventConsumer(AdverseEventService adverseEventService, this.objectMapper = objectMapper; } - @KafkaListener(topics = "${adrm.adverseevent.consumer.bulk.create.topic}") + @KafkaListener(topics = "${referralmanagement.adverseevent.consumer.bulk.create.topic}") public void bulkCreate(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { @@ -43,7 +43,7 @@ public void bulkCreate(Map consumerRecord, } } - @KafkaListener(topics = "${adrm.adverseevent.consumer.bulk.update.topic}") + @KafkaListener(topics = "${referralmanagement.adverseevent.consumer.bulk.update.topic}") public void bulkUpdate(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { @@ -56,7 +56,7 @@ public void bulkUpdate(Map consumerRecord, } } - @KafkaListener(topics = "${adrm.adverseevent.consumer.bulk.delete.topic}") + @KafkaListener(topics = "${referralmanagement.adverseevent.consumer.bulk.delete.topic}") public void bulkDelete(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { diff --git a/health-services/adrm/src/main/java/org/egov/adrm/consumer/ReferralManagementConsumer.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java similarity index 100% rename from health-services/adrm/src/main/java/org/egov/adrm/consumer/ReferralManagementConsumer.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java diff --git a/health-services/adrm/src/main/java/org/egov/adrm/repository/AdverseEventRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/AdverseEventRepository.java similarity index 95% rename from health-services/adrm/src/main/java/org/egov/adrm/repository/AdverseEventRepository.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/AdverseEventRepository.java index 5cac554ce5c..5db9f77f424 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/repository/AdverseEventRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/AdverseEventRepository.java @@ -1,4 +1,4 @@ -package org.egov.adrm.repository; +package org.egov.referralmanagement.repository; import lombok.extern.slf4j.Slf4j; import org.egov.common.data.query.builder.GenericQueryBuilder; @@ -6,11 +6,11 @@ import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.adverseevent.AdverseEventSearch; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearch; import org.egov.common.models.project.Task; import org.egov.common.producer.Producer; -import org.egov.adrm.repository.rowmapper.AdverseEventRowMapper; +import org.egov.referralmanagement.repository.rowmapper.AdverseEventRowMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/repository/ReferralManagementRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralManagementRepository.java similarity index 100% rename from health-services/adrm/src/main/java/org/egov/adrm/repository/ReferralManagementRepository.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralManagementRepository.java diff --git a/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/AdverseEventRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/AdverseEventRowMapper.java similarity index 94% rename from health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/AdverseEventRowMapper.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/AdverseEventRowMapper.java index edbf7e23af6..6dd6ff19472 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/AdverseEventRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/AdverseEventRowMapper.java @@ -1,9 +1,9 @@ -package org.egov.adrm.repository.rowmapper; +package org.egov.referralmanagement.repository.rowmapper; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/ReferralRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java similarity index 100% rename from health-services/adrm/src/main/java/org/egov/adrm/repository/rowmapper/ReferralRowMapper.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java diff --git a/health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/AdverseEventService.java similarity index 87% rename from health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/AdverseEventService.java index 5bf0585d61b..d91637882c3 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/service/AdverseEventService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/AdverseEventService.java @@ -1,21 +1,21 @@ -package org.egov.adrm.service; +package org.egov.referralmanagement.service; import lombok.extern.slf4j.Slf4j; -import org.egov.adrm.Constants; -import org.egov.adrm.config.AdrmConfiguration; -import org.egov.adrm.repository.AdverseEventRepository; -import org.egov.adrm.service.enrichment.AdverseEventEnrichmentService; -import org.egov.adrm.validator.adverseevent.AdIsDeletedValidator; -import org.egov.adrm.validator.adverseevent.AdNonExistentEntityValidator; -import org.egov.adrm.validator.adverseevent.AdNullIdValidator; -import org.egov.adrm.validator.adverseevent.AdProjectTaskIdValidator; -import org.egov.adrm.validator.adverseevent.AdUniqueEntityValidator; +import org.egov.referralmanagement.Constants; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.repository.AdverseEventRepository; +import org.egov.referralmanagement.service.enrichment.AdverseEventEnrichmentService; +import org.egov.referralmanagement.validator.adverseevent.AdIsDeletedValidator; +import org.egov.referralmanagement.validator.adverseevent.AdNonExistentEntityValidator; +import org.egov.referralmanagement.validator.adverseevent.AdNullIdValidator; +import org.egov.referralmanagement.validator.adverseevent.AdProjectTaskIdValidator; +import org.egov.referralmanagement.validator.adverseevent.AdUniqueEntityValidator; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; -import org.egov.common.models.adrm.adverseevent.AdverseEventRequest; -import org.egov.common.models.adrm.adverseevent.AdverseEventSearchRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearchRequest; import org.egov.common.service.IdGenService; import org.egov.common.utils.CommonUtils; import org.egov.common.validator.Validator; @@ -47,7 +47,7 @@ public class AdverseEventService { private final AdverseEventRepository adverseEventRepository; - private final AdrmConfiguration adrmConfiguration; + private final ReferralManagementConfiguration referralManagementConfiguration; private final AdverseEventEnrichmentService adverseEventEnrichmentService; @@ -71,13 +71,13 @@ public class AdverseEventService { public AdverseEventService( IdGenService idGenService, AdverseEventRepository adverseEventRepository, - AdrmConfiguration adrmConfiguration, + ReferralManagementConfiguration referralManagementConfiguration, AdverseEventEnrichmentService adverseEventEnrichmentService, List> validators ) { this.idGenService = idGenService; this.adverseEventRepository = adverseEventRepository; - this.adrmConfiguration = adrmConfiguration; + this.referralManagementConfiguration = referralManagementConfiguration; this.adverseEventEnrichmentService = adverseEventEnrichmentService; this.validators = validators; } @@ -102,7 +102,7 @@ public List create(AdverseEventBulkRequest adverseEventRequest, bo log.info("processing {} valid entities", validAdverseEvents.size()); adverseEventEnrichmentService.create(validAdverseEvents, adverseEventRequest); adverseEventRepository.save(validAdverseEvents, - adrmConfiguration.getCreateAdverseEventTopic()); + referralManagementConfiguration.getCreateAdverseEventTopic()); log.info("successfully created adverse events"); } } catch (Exception exception) { @@ -135,7 +135,7 @@ public List update(AdverseEventBulkRequest adverseEventRequest, bo log.info("processing {} valid entities", validAdverseEvents.size()); adverseEventEnrichmentService.update(validAdverseEvents, adverseEventRequest); adverseEventRepository.save(validAdverseEvents, - adrmConfiguration.getUpdateAdverseEventTopic()); + referralManagementConfiguration.getUpdateAdverseEventTopic()); log.info("successfully updated bulk adverse events"); } } catch (Exception exception) { @@ -195,7 +195,7 @@ public List delete(AdverseEventBulkRequest adverseEventRequest, bo .findById(adverseEventIds, false); adverseEventEnrichmentService.delete(existingAdverseEvents, adverseEventRequest); adverseEventRepository.save(existingAdverseEvents, - adrmConfiguration.getDeleteAdverseEventTopic()); + referralManagementConfiguration.getDeleteAdverseEventTopic()); log.info("successfully deleted entities"); } } catch (Exception exception) { diff --git a/health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java similarity index 100% rename from health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java diff --git a/health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/AdverseEventEnrichmentService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/AdverseEventEnrichmentService.java similarity index 72% rename from health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/AdverseEventEnrichmentService.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/AdverseEventEnrichmentService.java index 03c7506461b..f8a28ddc0a6 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/AdverseEventEnrichmentService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/AdverseEventEnrichmentService.java @@ -1,12 +1,12 @@ -package org.egov.adrm.service.enrichment; +package org.egov.referralmanagement.service.enrichment; import lombok.extern.slf4j.Slf4j; -import org.egov.adrm.config.AdrmConfiguration; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; import org.egov.common.service.IdGenService; import org.egov.common.utils.CommonUtils; -import org.egov.adrm.repository.AdverseEventRepository; +import org.egov.referralmanagement.repository.AdverseEventRepository; import org.springframework.stereotype.Component; import java.util.List; @@ -20,13 +20,13 @@ public class AdverseEventEnrichmentService { private final IdGenService idGenService; - private final AdrmConfiguration adrmConfiguration; + private final ReferralManagementConfiguration referralManagementConfiguration; private final AdverseEventRepository adverseEventRepository; - public AdverseEventEnrichmentService(IdGenService idGenService, AdrmConfiguration adrmConfiguration, AdverseEventRepository adverseEventRepository) { + public AdverseEventEnrichmentService(IdGenService idGenService, ReferralManagementConfiguration referralManagementConfiguration, AdverseEventRepository adverseEventRepository) { this.idGenService = idGenService; - this.adrmConfiguration = adrmConfiguration; + this.referralManagementConfiguration = referralManagementConfiguration; this.adverseEventRepository = adverseEventRepository; } diff --git a/health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/ReferralManagementEnrichmentService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java similarity index 100% rename from health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/ReferralManagementEnrichmentService.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdIsDeletedValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdIsDeletedValidator.java similarity index 83% rename from health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdIsDeletedValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdIsDeletedValidator.java index 1e66ad39329..b4ae9c3c17d 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdIsDeletedValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdIsDeletedValidator.java @@ -1,9 +1,9 @@ -package org.egov.adrm.validator.adverseevent; +package org.egov.referralmanagement.validator.adverseevent; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNonExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNonExistentEntityValidator.java similarity index 88% rename from health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNonExistentEntityValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNonExistentEntityValidator.java index dca45c7b2a1..8fea8a00e6e 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNonExistentEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNonExistentEntityValidator.java @@ -1,11 +1,11 @@ -package org.egov.adrm.validator.adverseevent; +package org.egov.referralmanagement.validator.adverseevent; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; -import org.egov.adrm.repository.AdverseEventRepository; +import org.egov.referralmanagement.repository.AdverseEventRepository; import org.egov.common.models.Error; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; @@ -18,7 +18,7 @@ import java.util.Map; import java.util.stream.Collectors; -import static org.egov.adrm.Constants.GET_ID; +import static org.egov.referralmanagement.Constants.GET_ID; import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.getIdToObjMap; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNullIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNullIdValidator.java similarity index 69% rename from health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNullIdValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNullIdValidator.java index 97712959369..f051349ee82 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdNullIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNullIdValidator.java @@ -1,9 +1,9 @@ -package org.egov.adrm.validator.adverseevent; +package org.egov.referralmanagement.validator.adverseevent; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -11,7 +11,7 @@ import java.util.List; import java.util.Map; -import static org.egov.adrm.Constants.GET_ADVERSE_EVENTS; +import static org.egov.referralmanagement.Constants.GET_ADVERSE_EVENTS; import static org.egov.common.utils.CommonUtils.validateForNullId; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdProjectTaskIdValidator.java similarity index 88% rename from health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdProjectTaskIdValidator.java index 16865894baf..90cb6639da4 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdProjectTaskIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdProjectTaskIdValidator.java @@ -1,13 +1,11 @@ -package org.egov.adrm.validator.adverseevent; +package org.egov.referralmanagement.validator.adverseevent; import lombok.extern.slf4j.Slf4j; -import org.egov.adrm.config.AdrmConfiguration; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; -import org.egov.common.models.project.BeneficiaryBulkRequest; import org.egov.common.models.project.BeneficiaryBulkResponse; -import org.egov.common.models.project.BeneficiaryResponse; import org.egov.common.models.project.BeneficiarySearchRequest; import org.egov.common.models.project.ProjectBeneficiary; import org.egov.common.models.project.ProjectBeneficiarySearch; @@ -15,15 +13,14 @@ import org.egov.common.models.project.TaskBulkResponse; import org.egov.common.models.project.TaskSearch; import org.egov.common.models.project.TaskSearchRequest; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -41,12 +38,12 @@ @Slf4j public class AdProjectTaskIdValidator implements Validator { private final ServiceRequestClient serviceRequestClient; - private final AdrmConfiguration adrmConfiguration; + private final ReferralManagementConfiguration referralManagementConfiguration; @Autowired - public AdProjectTaskIdValidator(ServiceRequestClient serviceRequestClient, AdrmConfiguration adrmConfiguration) { + public AdProjectTaskIdValidator(ServiceRequestClient serviceRequestClient, ReferralManagementConfiguration referralManagementConfiguration) { this.serviceRequestClient = serviceRequestClient; - this.adrmConfiguration = adrmConfiguration; + this.referralManagementConfiguration = referralManagementConfiguration; } @@ -77,8 +74,8 @@ public Map> validate(AdverseEventBulkRequest request) .id(taskIdList.isEmpty() ? null : taskIdList) .clientReferenceId(taskClientReferenceIdList.isEmpty() ? null : taskClientReferenceIdList).build(); TaskBulkResponse taskBulkResponse = serviceRequestClient.fetchResult( - new StringBuilder(adrmConfiguration.getProjectHost() - + adrmConfiguration.getProjectTaskSearchUrl() + new StringBuilder(referralManagementConfiguration.getProjectHost() + + referralManagementConfiguration.getProjectTaskSearchUrl() +"?limit=" + entities.size() + "&offset=0&tenantId=" + tenantId), TaskSearchRequest.builder().requestInfo(request.getRequestInfo()).task(taskSearch).build(), @@ -90,8 +87,8 @@ public Map> validate(AdverseEventBulkRequest request) .clientReferenceId(projectBeneficiaryClientReferenceIdList.isEmpty() ? null : projectBeneficiaryClientReferenceIdList) .build(); BeneficiaryBulkResponse beneficiaryBulkResponse = serviceRequestClient.fetchResult( - new StringBuilder(adrmConfiguration.getProjectHost() - + adrmConfiguration.getProjectBeneficiarySearchUrl() + new StringBuilder(referralManagementConfiguration.getProjectHost() + + referralManagementConfiguration.getProjectBeneficiarySearchUrl() +"?limit=" + entities.size() + "&offset=0&tenantId=" + tenantId), BeneficiarySearchRequest.builder().requestInfo(request.getRequestInfo()).projectBeneficiary(projectBeneficiarySearch).build(), diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdUniqueEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdUniqueEntityValidator.java similarity index 88% rename from health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdUniqueEntityValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdUniqueEntityValidator.java index 823e1932938..8e06b42a9a2 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/adverseevent/AdUniqueEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdUniqueEntityValidator.java @@ -1,9 +1,9 @@ -package org.egov.adrm.validator.adverseevent; +package org.egov.referralmanagement.validator.adverseevent; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/AdverseEventApiController.java similarity index 85% rename from health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/AdverseEventApiController.java index 68f3963ff63..d7409965f65 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/AdverseEventApiController.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/AdverseEventApiController.java @@ -1,15 +1,15 @@ -package org.egov.adrm.web.controllers; +package org.egov.referralmanagement.web.controllers; import io.swagger.annotations.ApiParam; -import org.egov.adrm.config.AdrmConfiguration; -import org.egov.adrm.service.AdverseEventService; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.service.AdverseEventService; import org.egov.common.contract.response.ResponseInfo; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkRequest; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkResponse; -import org.egov.common.models.adrm.adverseevent.AdverseEventRequest; -import org.egov.common.models.adrm.adverseevent.AdverseEventResponse; -import org.egov.common.models.adrm.adverseevent.AdverseEventSearchRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkResponse; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventResponse; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearchRequest; import org.egov.common.producer.Producer; import org.egov.common.utils.ResponseInfoFactory; import org.springframework.http.HttpStatus; @@ -39,18 +39,18 @@ public class AdverseEventApiController { private final Producer producer; - private final AdrmConfiguration adrmConfiguration; + private final ReferralManagementConfiguration referralManagementConfiguration; public AdverseEventApiController( HttpServletRequest httpServletRequest, AdverseEventService adverseEventService, Producer producer, - AdrmConfiguration adrmConfiguration + ReferralManagementConfiguration referralManagementConfiguration ) { this.httpServletRequest = httpServletRequest; this.adverseEventService = adverseEventService; this.producer = producer; - this.adrmConfiguration = adrmConfiguration; + this.referralManagementConfiguration = referralManagementConfiguration; } @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) @@ -72,7 +72,7 @@ public ResponseEntity adverseEventV1CreatePost(@ApiParam(v public ResponseEntity adverseEventBulkV1CreatePost(@ApiParam(value = "Capture details of Adverse Event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); adverseEventService.putInCache(request.getAdverseEvents()); - producer.push(adrmConfiguration.getCreateAdverseEventBulkTopic(), request); + producer.push(referralManagementConfiguration.getCreateAdverseEventBulkTopic(), request); return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory .createResponseInfo(request.getRequestInfo(), true)); @@ -110,7 +110,7 @@ public ResponseEntity adverseEventV1UpdatePost(@ApiParam(v @RequestMapping(value = "/v1/bulk/_update", method = RequestMethod.POST) public ResponseEntity adverseEventV1BulkUpdatePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); - producer.push(adrmConfiguration.getUpdateAdverseEventBulkTopic(), request); + producer.push(referralManagementConfiguration.getUpdateAdverseEventBulkTopic(), request); return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory .createResponseInfo(request.getRequestInfo(), true)); @@ -133,7 +133,7 @@ public ResponseEntity adverseEventV1DeletePost(@ApiParam(v @RequestMapping(value = "/v1/bulk/_delete", method = RequestMethod.POST) public ResponseEntity adverseEventV1BulkDeletePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); - producer.push(adrmConfiguration.getDeleteAdverseEventBulkTopic(), request); + producer.push(referralManagementConfiguration.getDeleteAdverseEventBulkTopic(), request); return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory .createResponseInfo(request.getRequestInfo(), true)); diff --git a/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/ReferralManagementApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java similarity index 100% rename from health-services/adrm/src/main/java/org/egov/adrm/web/controllers/ReferralManagementApiController.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java diff --git a/health-services/adrm/src/main/resources/application.properties b/health-services/referralmanagement/src/main/resources/application.properties similarity index 83% rename from health-services/adrm/src/main/resources/application.properties rename to health-services/referralmanagement/src/main/resources/application.properties index 877b6c47da8..8911227c63d 100644 --- a/health-services/adrm/src/main/resources/application.properties +++ b/health-services/referralmanagement/src/main/resources/application.properties @@ -1,4 +1,4 @@ -server.servlet.context-path=/adrm +server.servlet.context-path=/referralmanagement server.port=8080 app.timezone=UTC @@ -55,8 +55,8 @@ kafka.producer.config.buffer_memory_config=33554432 egov.idgen.host=http://localhost:8081/ egov.idgen.path=egov-idgen/id/_generate egov.idgen.integration.enabled=true -adrm.adverseevent.idgen.id.format=adrm.adverseevent.id -adrm.referral.idgen.id.format=adrm.referral.id +referralmanagement.adverseevent.idgen.id.format=referralmanagement.adverseevent.id +referralmanagement.referral.idgen.id.format=referralmanagement.referral.id idgen.project.beneficiary.id.format=project.beneficiary.id project.staff.idgen.id.format=project.staff.id project.facility.idgen.id.format=project.facility.id @@ -103,13 +103,13 @@ egov.search.project.staff.url=/project/staff/v1/_search # ADRM KAFKA CONFIG -adrm.adverseevent.kafka.create.topic=save-adverse-event-topic -adrm.adverseevent.kafka.update.topic=update-adverse-event-topic -adrm.adverseevent.kafka.delete.topic=delete-adverse-event-topic +referralmanagement.adverseevent.kafka.create.topic=save-adverse-event-topic +referralmanagement.adverseevent.kafka.update.topic=update-adverse-event-topic +referralmanagement.adverseevent.kafka.delete.topic=delete-adverse-event-topic -adrm.adverseevent.consumer.bulk.create.topic=save-adverse-event-bulk-topic -adrm.adverseevent.consumer.bulk.update.topic=update-adverse-event-bulk-topic -adrm.adverseevent.consumer.bulk.delete.topic=delete-adverse-event-bulk-topic +referralmanagement.adverseevent.consumer.bulk.create.topic=save-adverse-event-bulk-topic +referralmanagement.adverseevent.consumer.bulk.update.topic=update-adverse-event-bulk-topic +referralmanagement.adverseevent.consumer.bulk.delete.topic=delete-adverse-event-bulk-topic adrm.referralmanagement.kafka.create.topic=save-referral-management-topic adrm.referralmanagement.kafka.update.topic=update-referral-management-topic @@ -121,9 +121,9 @@ adrm.referralmanagement.consumer.bulk.delete.topic=delete-referral-management-bu search.api.limit=1000 -adrm.default.offset=0 -adrm.default.limit=100 -adrm.search.max.limit=200 +referralmanagement.default.offset=0 +referralmanagement.default.limit=100 +referralmanagement.search.max.limit=200 #location config diff --git a/health-services/adrm/src/main/resources/db/Dockerfile b/health-services/referralmanagement/src/main/resources/db/Dockerfile similarity index 100% rename from health-services/adrm/src/main/resources/db/Dockerfile rename to health-services/referralmanagement/src/main/resources/db/Dockerfile diff --git a/health-services/adrm/src/main/resources/db/migrate.sh b/health-services/referralmanagement/src/main/resources/db/migrate.sh similarity index 100% rename from health-services/adrm/src/main/resources/db/migrate.sh rename to health-services/referralmanagement/src/main/resources/db/migrate.sh diff --git a/health-services/adrm/src/main/resources/adrm-persister.yml b/health-services/referralmanagement/src/main/resources/referral-management-persister.yml similarity index 99% rename from health-services/adrm/src/main/resources/adrm-persister.yml rename to health-services/referralmanagement/src/main/resources/referral-management-persister.yml index f1780c39448..49fb3454ed8 100644 --- a/health-services/adrm/src/main/resources/adrm-persister.yml +++ b/health-services/referralmanagement/src/main/resources/referral-management-persister.yml @@ -1,5 +1,5 @@ serviceMaps: - serviceName: adrm + serviceName: referralmanagement mappings: - version: 1.0 description: Saves a adverse event diff --git a/health-services/adrm/src/test/java/org/egov/adrm/AppTest.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/AppTest.java similarity index 87% rename from health-services/adrm/src/test/java/org/egov/adrm/AppTest.java rename to health-services/referralmanagement/src/test/java/org/egov/referralmanagement/AppTest.java index d76b5eea977..48b5fb750f6 100644 --- a/health-services/adrm/src/test/java/org/egov/adrm/AppTest.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/AppTest.java @@ -1,4 +1,4 @@ -package org.egov.adrm; +package org.egov.referralmanagement; import static org.junit.Assert.assertTrue; diff --git a/health-services/adrm/src/test/java/org/egov/adrm/TestConfiguration.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/TestConfiguration.java similarity index 91% rename from health-services/adrm/src/test/java/org/egov/adrm/TestConfiguration.java rename to health-services/referralmanagement/src/test/java/org/egov/referralmanagement/TestConfiguration.java index 591f0b3dbfc..c27d6693d1c 100644 --- a/health-services/adrm/src/test/java/org/egov/adrm/TestConfiguration.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/TestConfiguration.java @@ -1,4 +1,4 @@ -package org.egov.adrm; +package org.egov.referralmanagement; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/health-services/adrm/src/test/java/org/egov/adrm/helper/AdverseEventRequestTestBuilder.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventRequestTestBuilder.java similarity index 94% rename from health-services/adrm/src/test/java/org/egov/adrm/helper/AdverseEventRequestTestBuilder.java rename to health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventRequestTestBuilder.java index 10bbe9b574a..983b5dee405 100644 --- a/health-services/adrm/src/test/java/org/egov/adrm/helper/AdverseEventRequestTestBuilder.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventRequestTestBuilder.java @@ -1,7 +1,7 @@ -package org.egov.adrm.helper; +package org.egov.referralmanagement.helper; import org.egov.common.helper.RequestInfoTestBuilder; -import org.egov.common.models.adrm.adverseevent.AdverseEventRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventRequest; import java.util.ArrayList; diff --git a/health-services/adrm/src/test/java/org/egov/adrm/helper/AdverseEventTestBuilder.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventTestBuilder.java similarity index 95% rename from health-services/adrm/src/test/java/org/egov/adrm/helper/AdverseEventTestBuilder.java rename to health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventTestBuilder.java index aed221446cf..1af8b9e9d10 100644 --- a/health-services/adrm/src/test/java/org/egov/adrm/helper/AdverseEventTestBuilder.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventTestBuilder.java @@ -1,7 +1,7 @@ -package org.egov.adrm.helper; +package org.egov.referralmanagement.helper; import org.egov.common.helper.AuditDetailsTestBuilder; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; import java.util.ArrayList; import java.util.Arrays; diff --git a/health-services/adrm/src/test/java/org/egov/adrm/web/controllers/AdverseEventApiControllerTest.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/AdverseEventApiControllerTest.java similarity index 91% rename from health-services/adrm/src/test/java/org/egov/adrm/web/controllers/AdverseEventApiControllerTest.java rename to health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/AdverseEventApiControllerTest.java index f6c95c063fc..e6a7ad40b98 100644 --- a/health-services/adrm/src/test/java/org/egov/adrm/web/controllers/AdverseEventApiControllerTest.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/AdverseEventApiControllerTest.java @@ -1,18 +1,18 @@ -package org.egov.adrm.web.controllers; +package org.egov.referralmanagement.web.controllers; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.adrm.TestConfiguration; -import org.egov.adrm.config.AdrmConfiguration; -import org.egov.adrm.helper.AdverseEventRequestTestBuilder; -import org.egov.adrm.helper.AdverseEventTestBuilder; -import org.egov.adrm.service.AdverseEventService; +import org.egov.referralmanagement.TestConfiguration; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.helper.AdverseEventRequestTestBuilder; +import org.egov.referralmanagement.helper.AdverseEventTestBuilder; +import org.egov.referralmanagement.service.AdverseEventService; import org.egov.common.helper.RequestInfoTestBuilder; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.adverseevent.AdverseEventBulkResponse; -import org.egov.common.models.adrm.adverseevent.AdverseEventRequest; -import org.egov.common.models.adrm.adverseevent.AdverseEventResponse; -import org.egov.common.models.adrm.adverseevent.AdverseEventSearch; -import org.egov.common.models.adrm.adverseevent.AdverseEventSearchRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkResponse; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventResponse; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearch; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearchRequest; import org.egov.common.producer.Producer; import org.egov.tracer.model.CustomException; import org.egov.tracer.model.ErrorRes; @@ -52,7 +52,7 @@ public class AdverseEventApiControllerTest { private Producer producer; @MockBean - AdrmConfiguration adrmConfiguration; + ReferralManagementConfiguration referralManagementConfiguration; @Test @DisplayName("should create adverse event and return with 202 accepted") From 898af191da42778812e676b7102175c9312895e8 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 25 Sep 2023 11:53:07 +0530 Subject: [PATCH 158/283] HLM-3376: Added changes for referral management --- .../adverse-event-referral-management.yml | 10 +++++++ .../adrm/referralmanagement/Referral.java | 8 +++++ .../consumer/ReferralManagementConsumer.java | 4 +-- .../ReferralManagementRepository.java | 3 +- .../rowmapper/ReferralRowMapper.java | 2 ++ .../service/ReferralManagementService.java | 29 +++++++++---------- .../ReferralManagementEnrichmentService.java | 12 ++++---- .../ReferralManagementApiController.java | 20 ++++++------- 8 files changed, 53 insertions(+), 35 deletions(-) diff --git a/docs/health-api-specs/contracts/adverse-event-referral-management.yml b/docs/health-api-specs/contracts/adverse-event-referral-management.yml index 926ea2ca85e..88436973115 100644 --- a/docs/health-api-specs/contracts/adverse-event-referral-management.yml +++ b/docs/health-api-specs/contracts/adverse-event-referral-management.yml @@ -658,11 +658,21 @@ definitions: minLength: 2 maxLength: 64 description: Worker Id that is referring the Beneficiary + referringPartyClientReferenceId: + type: string + minLength: 2 + maxLength: 64 + description: Worker Client Reference Id that is referring the Beneficiary referredToId: type: string minLength: 2 maxLength: 64 description: Individual or Facility Id whom the Beneficiary is referred to. + referredToClientReferenceId: + type: string + minLength: 2 + maxLength: 64 + description: Individual or Facility Client Reference Id whom the Beneficiary is Referred To. referredToType: type: string description: Individual or Facility diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java index 668ea353ac3..b7fbf6deff4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java @@ -42,6 +42,10 @@ public class Referral { @Size(min = 2, max = 64) private String referringPartyId = null; + @JsonProperty("referringPartyClientReferenceId") + @Size(min = 2, max = 64) + private String referringPartyClientReferenceId = null; + @JsonProperty("referredToType") private String referredToType = null; @@ -49,6 +53,10 @@ public class Referral { @Size(min = 2, max = 64) private String referredToId = null; + @JsonProperty("referredToClientReferenceId") + @Size(min = 2, max = 64) + private String referredToClientReferenceId = null; + @JsonProperty("reasons") @NotNull @Size(min=1) diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java index 190ae112765..ce71a41dcdb 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java @@ -1,9 +1,9 @@ -package org.egov.adrm.consumer; +package org.egov.referralmanagement.consumer; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; -import org.egov.adrm.service.ReferralManagementService; +import org.egov.referralmanagement.service.ReferralManagementService; import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralManagementRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralManagementRepository.java index ab8ce6de641..fbb389e4521 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralManagementRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralManagementRepository.java @@ -1,4 +1,4 @@ -package org.egov.adrm.repository; +package org.egov.referralmanagement.repository; import lombok.extern.slf4j.Slf4j; import org.egov.adrm.repository.rowmapper.ReferralRowMapper; @@ -28,7 +28,6 @@ import java.util.Optional; import java.util.stream.Collectors; -import static org.egov.common.utils.CommonUtils.getIdList; import static org.egov.common.utils.CommonUtils.getIdMethod; @Repository diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java index 125eeed1b37..5b8336f0941 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java @@ -66,7 +66,9 @@ public Referral mapRow(ResultSet resultSet, int i) throws SQLException { .projectBeneficiaryId(resultSet.getString("projectBeneficiaryId")) .projectBeneficiaryClientReferenceId(resultSet.getString("projectbeneficiaryclientreferenceid")) .referringPartyId(resultSet.getString("referrringpartyid")) + .referringPartyClientReferenceId(resultSet.getString("referringpartyclientreferenceid")) .referredToId(resultSet.getString("referredToId")) + .referredToClientReferenceId(resultSet.getString("referredtoclientreferenceid")) .referredToType(resultSet.getString("referredToType")) .adverseEvent(adverseEvent) .tenantId(resultSet.getString("tenantid")) diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java index 0bd69750a27..cdcd3175449 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java @@ -1,16 +1,15 @@ -package org.egov.adrm.service; +package org.egov.referralmanagement.service; import lombok.extern.slf4j.Slf4j; -import org.egov.adrm.Constants; -import org.egov.adrm.config.AdrmConfiguration; -import org.egov.adrm.repository.ReferralManagementRepository; -import org.egov.adrm.service.enrichment.ReferralManagementEnrichmentService; -import org.egov.adrm.validator.rm.RmFacilityEntitiesIdValidator; -import org.egov.adrm.validator.rm.RmIsDeletedValidator; -import org.egov.adrm.validator.rm.RmNonExistentEntityValidator; -import org.egov.adrm.validator.rm.RmNullIdValidator; -import org.egov.adrm.validator.rm.RmProjectEntitiesIdValidator; -import org.egov.adrm.validator.rm.RmUniqueEntityValidator; +import org.egov.referralmanagement.Constants; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.repository.ReferralManagementRepository; +import org.egov.referralmanagement.service.enrichment.ReferralManagementEnrichmentService; +import org.egov.referralmanagement.validator.adverseevent.AdIsDeletedValidator; +import org.egov.referralmanagement.validator.adverseevent.AdNonExistentEntityValidator; +import org.egov.referralmanagement.validator.adverseevent.AdNullIdValidator; +import org.egov.referralmanagement.validator.adverseevent.AdProjectTaskIdValidator; +import org.egov.referralmanagement.validator.adverseevent.AdUniqueEntityValidator; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.adrm.referralmanagement.Referral; @@ -47,7 +46,7 @@ public class ReferralManagementService { private final ReferralManagementRepository referralManagementRepository; - private final AdrmConfiguration adrmConfiguration; + private final ReferralManagementConfiguration referralManagementConfiguration; private final ReferralManagementEnrichmentService referralManagementEnrichmentService; @@ -98,7 +97,7 @@ public List create(ReferralBulkRequest referralRequest, boolean isBulk log.info("processing {} valid entities", validReferrals.size()); referralManagementEnrichmentService.create(validReferrals, referralRequest); referralManagementRepository.save(validReferrals, - adrmConfiguration.getCreateReferralTopic()); + referralManagementConfiguration.getCreateReferralTopic()); log.info("successfully created adverse events"); } } catch (Exception exception) { @@ -131,7 +130,7 @@ public List update(ReferralBulkRequest referralRequest, boolean isBulk log.info("processing {} valid entities", validReferrals.size()); referralManagementEnrichmentService.update(validReferrals, referralRequest); referralManagementRepository.save(validReferrals, - adrmConfiguration.getUpdateReferralTopic()); + referralManagementConfiguration.getUpdateReferralTopic()); log.info("successfully updated bulk adverse events"); } } catch (Exception exception) { @@ -191,7 +190,7 @@ public List delete(ReferralBulkRequest referralRequest, boolean isBulk .findById(referralIds, false); referralManagementEnrichmentService.delete(existingReferrals, referralRequest); referralManagementRepository.save(existingReferrals, - adrmConfiguration.getDeleteReferralTopic()); + referralManagementConfiguration.getDeleteReferralTopic()); log.info("successfully deleted entities"); } } catch (Exception exception) { diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java index 552136b678c..eebe695dc25 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java @@ -1,12 +1,12 @@ -package org.egov.adrm.service.enrichment; +package org.egov.referralmanagement.service.enrichment; import lombok.extern.slf4j.Slf4j; -import org.egov.adrm.config.AdrmConfiguration; -import org.egov.adrm.repository.ReferralManagementRepository; +import org.egov.referralmanagement.repository.ReferralManagementRepository; import org.egov.common.models.adrm.referralmanagement.Referral; import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; import org.egov.common.service.IdGenService; import org.egov.common.utils.CommonUtils; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; import org.springframework.stereotype.Component; import java.util.List; @@ -22,13 +22,13 @@ public class ReferralManagementEnrichmentService { private final IdGenService idGenService; - private final AdrmConfiguration adrmConfiguration; + private final ReferralManagementConfiguration referralManagementConfiguration; private final ReferralManagementRepository referralManagementRepository; - public ReferralManagementEnrichmentService(IdGenService idGenService, AdrmConfiguration adrmConfiguration, ReferralManagementRepository referralManagementRepository) { + public ReferralManagementEnrichmentService(IdGenService idGenService, ReferralManagementConfiguration referralManagementConfiguration, ReferralManagementRepository referralManagementRepository) { this.idGenService = idGenService; - this.adrmConfiguration = adrmConfiguration; + this.referralManagementConfiguration = referralManagementConfiguration; this.referralManagementRepository = referralManagementRepository; } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java index 42604fa739f..346973d93c4 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java @@ -1,8 +1,7 @@ -package org.egov.adrm.web.controllers; +package org.egov.referralmanagement.web.controllers; import io.swagger.annotations.ApiParam; -import org.egov.adrm.config.AdrmConfiguration; -import org.egov.adrm.service.ReferralManagementService; +import org.egov.referralmanagement.service.ReferralManagementService; import org.egov.common.contract.response.ResponseInfo; import org.egov.common.models.adrm.referralmanagement.Referral; import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; @@ -12,6 +11,7 @@ import org.egov.common.models.adrm.referralmanagement.ReferralSearchRequest; import org.egov.common.producer.Producer; import org.egov.common.utils.ResponseInfoFactory; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; @@ -38,18 +38,18 @@ public class ReferralManagementApiController { private final Producer producer; - private final AdrmConfiguration adrmConfiguration; + private final ReferralManagementConfiguration referralManagementConfiguration; public ReferralManagementApiController( HttpServletRequest httpServletRequest, ReferralManagementService referralManagementService, - Producer producer, - AdrmConfiguration adrmConfiguration + Producer producer, + ReferralManagementConfiguration referralManagementConfiguration ) { this.httpServletRequest = httpServletRequest; this.referralManagementService = referralManagementService; this.producer = producer; - this.adrmConfiguration = adrmConfiguration; + this.referralManagementConfiguration = referralManagementConfiguration; } @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) @@ -71,7 +71,7 @@ public ResponseEntity referralV1CreatePost(@ApiParam(value = " public ResponseEntity referralBulkV1CreatePost(@ApiParam(value = "Capture details of Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); referralManagementService.putInCache(request.getReferrals()); - producer.push(adrmConfiguration.getCreateReferralBulkTopic(), request); + producer.push(referralManagementConfiguration.getCreateReferralBulkTopic(), request); return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory .createResponseInfo(request.getRequestInfo(), true)); @@ -109,7 +109,7 @@ public ResponseEntity referralV1UpdatePost(@ApiParam(value = " @RequestMapping(value = "/v1/bulk/_update", method = RequestMethod.POST) public ResponseEntity referralV1BulkUpdatePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); - producer.push(adrmConfiguration.getUpdateReferralBulkTopic(), request); + producer.push(referralManagementConfiguration.getUpdateReferralBulkTopic(), request); return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory .createResponseInfo(request.getRequestInfo(), true)); @@ -132,7 +132,7 @@ public ResponseEntity referralV1DeletePost(@ApiParam(value = " @RequestMapping(value = "/v1/bulk/_delete", method = RequestMethod.POST) public ResponseEntity referralV1BulkDeletePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); - producer.push(adrmConfiguration.getDeleteReferralBulkTopic(), request); + producer.push(referralManagementConfiguration.getDeleteReferralBulkTopic(), request); return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory .createResponseInfo(request.getRequestInfo(), true)); From 006f5c60fc47d5980f640299347f330c9b15ee25 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 25 Sep 2023 18:09:42 +0530 Subject: [PATCH 159/283] HLM-3376: Added Validators, updated Referral.java --- .../adrm/referralmanagement/Referral.java | 8 ----- .../service/ReferralManagementService.java | 29 ++++++++++--------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java index b7fbf6deff4..668ea353ac3 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java @@ -42,10 +42,6 @@ public class Referral { @Size(min = 2, max = 64) private String referringPartyId = null; - @JsonProperty("referringPartyClientReferenceId") - @Size(min = 2, max = 64) - private String referringPartyClientReferenceId = null; - @JsonProperty("referredToType") private String referredToType = null; @@ -53,10 +49,6 @@ public class Referral { @Size(min = 2, max = 64) private String referredToId = null; - @JsonProperty("referredToClientReferenceId") - @Size(min = 2, max = 64) - private String referredToClientReferenceId = null; - @JsonProperty("reasons") @NotNull @Size(min=1) diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java index cdcd3175449..0bd69750a27 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java @@ -1,15 +1,16 @@ -package org.egov.referralmanagement.service; +package org.egov.adrm.service; import lombok.extern.slf4j.Slf4j; -import org.egov.referralmanagement.Constants; -import org.egov.referralmanagement.config.ReferralManagementConfiguration; -import org.egov.referralmanagement.repository.ReferralManagementRepository; -import org.egov.referralmanagement.service.enrichment.ReferralManagementEnrichmentService; -import org.egov.referralmanagement.validator.adverseevent.AdIsDeletedValidator; -import org.egov.referralmanagement.validator.adverseevent.AdNonExistentEntityValidator; -import org.egov.referralmanagement.validator.adverseevent.AdNullIdValidator; -import org.egov.referralmanagement.validator.adverseevent.AdProjectTaskIdValidator; -import org.egov.referralmanagement.validator.adverseevent.AdUniqueEntityValidator; +import org.egov.adrm.Constants; +import org.egov.adrm.config.AdrmConfiguration; +import org.egov.adrm.repository.ReferralManagementRepository; +import org.egov.adrm.service.enrichment.ReferralManagementEnrichmentService; +import org.egov.adrm.validator.rm.RmFacilityEntitiesIdValidator; +import org.egov.adrm.validator.rm.RmIsDeletedValidator; +import org.egov.adrm.validator.rm.RmNonExistentEntityValidator; +import org.egov.adrm.validator.rm.RmNullIdValidator; +import org.egov.adrm.validator.rm.RmProjectEntitiesIdValidator; +import org.egov.adrm.validator.rm.RmUniqueEntityValidator; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.adrm.referralmanagement.Referral; @@ -46,7 +47,7 @@ public class ReferralManagementService { private final ReferralManagementRepository referralManagementRepository; - private final ReferralManagementConfiguration referralManagementConfiguration; + private final AdrmConfiguration adrmConfiguration; private final ReferralManagementEnrichmentService referralManagementEnrichmentService; @@ -97,7 +98,7 @@ public List create(ReferralBulkRequest referralRequest, boolean isBulk log.info("processing {} valid entities", validReferrals.size()); referralManagementEnrichmentService.create(validReferrals, referralRequest); referralManagementRepository.save(validReferrals, - referralManagementConfiguration.getCreateReferralTopic()); + adrmConfiguration.getCreateReferralTopic()); log.info("successfully created adverse events"); } } catch (Exception exception) { @@ -130,7 +131,7 @@ public List update(ReferralBulkRequest referralRequest, boolean isBulk log.info("processing {} valid entities", validReferrals.size()); referralManagementEnrichmentService.update(validReferrals, referralRequest); referralManagementRepository.save(validReferrals, - referralManagementConfiguration.getUpdateReferralTopic()); + adrmConfiguration.getUpdateReferralTopic()); log.info("successfully updated bulk adverse events"); } } catch (Exception exception) { @@ -190,7 +191,7 @@ public List delete(ReferralBulkRequest referralRequest, boolean isBulk .findById(referralIds, false); referralManagementEnrichmentService.delete(existingReferrals, referralRequest); referralManagementRepository.save(existingReferrals, - referralManagementConfiguration.getDeleteReferralTopic()); + adrmConfiguration.getDeleteReferralTopic()); log.info("successfully deleted entities"); } } catch (Exception exception) { From 38fb1e054d0ebead4fcb775b1a52c89bfda27b1d Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 27 Sep 2023 10:32:46 +0530 Subject: [PATCH 160/283] HLM-3376: changed contract yaml and rowmapper --- .../contracts/adverse-event-referral-management.yml | 10 ---------- .../repository/rowmapper/ReferralRowMapper.java | 2 -- 2 files changed, 12 deletions(-) diff --git a/docs/health-api-specs/contracts/adverse-event-referral-management.yml b/docs/health-api-specs/contracts/adverse-event-referral-management.yml index 88436973115..926ea2ca85e 100644 --- a/docs/health-api-specs/contracts/adverse-event-referral-management.yml +++ b/docs/health-api-specs/contracts/adverse-event-referral-management.yml @@ -658,21 +658,11 @@ definitions: minLength: 2 maxLength: 64 description: Worker Id that is referring the Beneficiary - referringPartyClientReferenceId: - type: string - minLength: 2 - maxLength: 64 - description: Worker Client Reference Id that is referring the Beneficiary referredToId: type: string minLength: 2 maxLength: 64 description: Individual or Facility Id whom the Beneficiary is referred to. - referredToClientReferenceId: - type: string - minLength: 2 - maxLength: 64 - description: Individual or Facility Client Reference Id whom the Beneficiary is Referred To. referredToType: type: string description: Individual or Facility diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java index 5b8336f0941..125eeed1b37 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java @@ -66,9 +66,7 @@ public Referral mapRow(ResultSet resultSet, int i) throws SQLException { .projectBeneficiaryId(resultSet.getString("projectBeneficiaryId")) .projectBeneficiaryClientReferenceId(resultSet.getString("projectbeneficiaryclientreferenceid")) .referringPartyId(resultSet.getString("referrringpartyid")) - .referringPartyClientReferenceId(resultSet.getString("referringpartyclientreferenceid")) .referredToId(resultSet.getString("referredToId")) - .referredToClientReferenceId(resultSet.getString("referredtoclientreferenceid")) .referredToType(resultSet.getString("referredToType")) .adverseEvent(adverseEvent) .tenantId(resultSet.getString("tenantid")) From b4536eccbb4a3592f99f350655627b165f6ec57b Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 27 Sep 2023 15:45:18 +0530 Subject: [PATCH 161/283] HLM-3376: changed module to referral management --- .../referralmanagement/Referral.java | 4 +- .../ReferralBulkRequest.java | 2 +- .../ReferralBulkResponse.java | 2 +- .../referralmanagement/ReferralRequest.java | 2 +- .../referralmanagement/ReferralResponse.java | 2 +- .../referralmanagement/ReferralSearch.java | 2 +- .../ReferralSearchRequest.java | 2 +- .../ReferralManagementConfiguration.java | 12 +++--- .../consumer/ReferralManagementConsumer.java | 8 ++-- .../ReferralManagementRepository.java | 9 ++-- .../rowmapper/ReferralRowMapper.java | 6 +-- .../service/ReferralManagementService.java | 42 +++++++++---------- .../ReferralManagementEnrichmentService.java | 4 +- .../RmFacilityEntitiesIdValidator.java | 20 ++++----- .../validator}/RmIsDeletedValidator.java | 6 +-- .../RmNonExistentEntityValidator.java | 2 +- .../validator}/RmNullIdValidator.java | 8 ++-- .../RmProjectEntitiesIdValidator.java | 2 +- .../validator}/RmUniqueEntityValidator.java | 6 +-- .../ReferralManagementApiController.java | 26 ++++++------ 20 files changed, 82 insertions(+), 85 deletions(-) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => }/referralmanagement/Referral.java (94%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => }/referralmanagement/ReferralBulkRequest.java (94%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => }/referralmanagement/ReferralBulkResponse.java (94%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => }/referralmanagement/ReferralRequest.java (92%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => }/referralmanagement/ReferralResponse.java (92%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => }/referralmanagement/ReferralSearch.java (93%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/{adrm => }/referralmanagement/ReferralSearchRequest.java (92%) rename health-services/{adrm/src/main/java/org/egov/adrm/validator/rm => referralmanagement/src/main/java/org/egov/referralmanagement/validator}/RmFacilityEntitiesIdValidator.java (85%) rename health-services/{adrm/src/main/java/org/egov/adrm/validator/rm => referralmanagement/src/main/java/org/egov/referralmanagement/validator}/RmIsDeletedValidator.java (85%) rename health-services/{adrm/src/main/java/org/egov/adrm/validator/rm => referralmanagement/src/main/java/org/egov/referralmanagement/validator}/RmNonExistentEntityValidator.java (98%) rename health-services/{adrm/src/main/java/org/egov/adrm/validator/rm => referralmanagement/src/main/java/org/egov/referralmanagement/validator}/RmNullIdValidator.java (72%) rename health-services/{adrm/src/main/java/org/egov/adrm/validator/rm => referralmanagement/src/main/java/org/egov/referralmanagement/validator}/RmProjectEntitiesIdValidator.java (99%) rename health-services/{adrm/src/main/java/org/egov/adrm/validator/rm => referralmanagement/src/main/java/org/egov/referralmanagement/validator}/RmUniqueEntityValidator.java (91%) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java similarity index 94% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java index 668ea353ac3..45771c0b566 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.referralmanagement; +package org.egov.common.models.referralmanagement; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -8,7 +8,7 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; import javax.validation.Valid; import javax.validation.constraints.NotNull; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkRequest.java similarity index 94% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkRequest.java index 752c8bfdb26..fd5621197ed 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.referralmanagement; +package org.egov.common.models.referralmanagement; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkResponse.java similarity index 94% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkResponse.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkResponse.java index f34d1df7ae0..3dfbd9dff25 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkResponse.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.referralmanagement; +package org.egov.common.models.referralmanagement; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralRequest.java similarity index 92% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralRequest.java index ead7cedd3a2..8ad1990acc9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.referralmanagement; +package org.egov.common.models.referralmanagement; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralResponse.java similarity index 92% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralResponse.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralResponse.java index 8bcae0afb31..b367fb35a98 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralResponse.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.referralmanagement; +package org.egov.common.models.referralmanagement; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearch.java similarity index 93% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearch.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearch.java index c54be75749b..31c9a223704 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearch.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.referralmanagement; +package org.egov.common.models.referralmanagement; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearchRequest.java similarity index 92% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearchRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearchRequest.java index c87c2265dd9..d6ae41f8f01 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearchRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.adrm.referralmanagement; +package org.egov.common.models.referralmanagement; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java index 37c9fea3df4..bb06348aa74 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java @@ -42,22 +42,22 @@ public class ReferralManagementConfiguration { @Value("${egov.search.project.beneficiary.url}") private String projectBeneficiarySearchUrl; - @Value("${adrm.referralmanagement.kafka.create.topic}") + @Value("${referralmanagement.referralmanagement.kafka.create.topic}") private String createReferralTopic; - @Value("${adrm.referralmanagement.kafka.update.topic}") + @Value("${referralmanagement.referralmanagement.kafka.update.topic}") private String updateReferralTopic; - @Value("${adrm.referralmanagement.kafka.delete.topic}") + @Value("${referralmanagement.referralmanagement.kafka.delete.topic}") private String deleteReferralTopic; - @Value("${adrm.referralmanagement.consumer.bulk.create.topic}") + @Value("${referralmanagement.referralmanagement.consumer.bulk.create.topic}") private String createReferralBulkTopic; - @Value("${adrm.referralmanagement.consumer.bulk.update.topic}") + @Value("${referralmanagement.referralmanagement.consumer.bulk.update.topic}") private String updateReferralBulkTopic; - @Value("${adrm.referralmanagement.consumer.bulk.delete.topic}") + @Value("${referralmanagement.referralmanagement.consumer.bulk.delete.topic}") private String deleteReferralBulkTopic; @Value("${egov.search.project.staff.url}") diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java index ce71a41dcdb..cd6f8007f71 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java @@ -4,7 +4,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.referralmanagement.service.ReferralManagementService; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -30,7 +30,7 @@ public ReferralManagementConsumer(ReferralManagementService referralManagementSe this.objectMapper = objectMapper; } - @KafkaListener(topics = "${adrm.referralmanagement.consumer.bulk.create.topic}") + @KafkaListener(topics = "${referralmanagement.referralmanagement.consumer.bulk.create.topic}") public void bulkCreate(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { @@ -43,7 +43,7 @@ public void bulkCreate(Map consumerRecord, } } - @KafkaListener(topics = "${adrm.referralmanagement.consumer.bulk.update.topic}") + @KafkaListener(topics = "${referralmanagement.referralmanagement.consumer.bulk.update.topic}") public void bulkUpdate(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { @@ -56,7 +56,7 @@ public void bulkUpdate(Map consumerRecord, } } - @KafkaListener(topics = "${adrm.referralmanagement.consumer.bulk.delete.topic}") + @KafkaListener(topics = "${referralmanagement.referralmanagement.consumer.bulk.delete.topic}") public void bulkDelete(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralManagementRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralManagementRepository.java index fbb389e4521..d25b5124cdd 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralManagementRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralManagementRepository.java @@ -1,17 +1,14 @@ package org.egov.referralmanagement.repository; import lombok.extern.slf4j.Slf4j; -import org.egov.adrm.repository.rowmapper.ReferralRowMapper; +import org.egov.referralmanagement.repository.rowmapper.ReferralRowMapper; import org.egov.common.data.query.builder.GenericQueryBuilder; import org.egov.common.data.query.builder.QueryFieldChecker; import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; -import org.egov.common.models.adrm.referralmanagement.Referral; -import org.egov.common.models.adrm.referralmanagement.ReferralSearch; -import org.egov.common.models.project.ProjectBeneficiary; -import org.egov.common.models.project.Task; -import org.egov.common.models.project.TaskResource; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralSearch; import org.egov.common.producer.Producer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java index 125eeed1b37..8fb133b851f 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java @@ -1,10 +1,10 @@ -package org.egov.adrm.repository.rowmapper; +package org.egov.referralmanagement.repository.rowmapper; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; -import org.egov.common.models.adrm.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.Referral; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java index 0bd69750a27..2568bde9f62 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java @@ -1,22 +1,22 @@ -package org.egov.adrm.service; +package org.egov.referralmanagement.service; import lombok.extern.slf4j.Slf4j; -import org.egov.adrm.Constants; -import org.egov.adrm.config.AdrmConfiguration; -import org.egov.adrm.repository.ReferralManagementRepository; -import org.egov.adrm.service.enrichment.ReferralManagementEnrichmentService; -import org.egov.adrm.validator.rm.RmFacilityEntitiesIdValidator; -import org.egov.adrm.validator.rm.RmIsDeletedValidator; -import org.egov.adrm.validator.rm.RmNonExistentEntityValidator; -import org.egov.adrm.validator.rm.RmNullIdValidator; -import org.egov.adrm.validator.rm.RmProjectEntitiesIdValidator; -import org.egov.adrm.validator.rm.RmUniqueEntityValidator; +import org.egov.referralmanagement.Constants; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.repository.ReferralManagementRepository; +import org.egov.referralmanagement.service.enrichment.ReferralManagementEnrichmentService; +import org.egov.referralmanagement.validator.RmFacilityEntitiesIdValidator; +import org.egov.referralmanagement.validator.RmIsDeletedValidator; +import org.egov.referralmanagement.validator.RmNonExistentEntityValidator; +import org.egov.referralmanagement.validator.RmNullIdValidator; +import org.egov.referralmanagement.validator.RmProjectEntitiesIdValidator; +import org.egov.referralmanagement.validator.RmUniqueEntityValidator; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; -import org.egov.common.models.adrm.referralmanagement.Referral; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; -import org.egov.common.models.adrm.referralmanagement.ReferralRequest; -import org.egov.common.models.adrm.referralmanagement.ReferralSearchRequest; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.referralmanagement.ReferralRequest; +import org.egov.common.models.referralmanagement.ReferralSearchRequest; import org.egov.common.service.IdGenService; import org.egov.common.utils.CommonUtils; import org.egov.common.validator.Validator; @@ -47,7 +47,7 @@ public class ReferralManagementService { private final ReferralManagementRepository referralManagementRepository; - private final AdrmConfiguration adrmConfiguration; + private final ReferralManagementConfiguration referralManagementConfiguration; private final ReferralManagementEnrichmentService referralManagementEnrichmentService; @@ -70,10 +70,10 @@ public class ReferralManagementService { || validator.getClass().equals(RmNonExistentEntityValidator.class); - public ReferralManagementService(IdGenService idGenService, ReferralManagementRepository referralManagementRepository, AdrmConfiguration adrmConfiguration, ReferralManagementEnrichmentService referralManagementEnrichmentService, List> validators) { + public ReferralManagementService(IdGenService idGenService, ReferralManagementRepository referralManagementRepository, ReferralManagementConfiguration referralManagementConfiguration, ReferralManagementEnrichmentService referralManagementEnrichmentService, List> validators) { this.idGenService = idGenService; this.referralManagementRepository = referralManagementRepository; - this.adrmConfiguration = adrmConfiguration; + this.referralManagementConfiguration = referralManagementConfiguration; this.referralManagementEnrichmentService = referralManagementEnrichmentService; this.validators = validators; } @@ -98,7 +98,7 @@ public List create(ReferralBulkRequest referralRequest, boolean isBulk log.info("processing {} valid entities", validReferrals.size()); referralManagementEnrichmentService.create(validReferrals, referralRequest); referralManagementRepository.save(validReferrals, - adrmConfiguration.getCreateReferralTopic()); + referralManagementConfiguration.getCreateReferralTopic()); log.info("successfully created adverse events"); } } catch (Exception exception) { @@ -131,7 +131,7 @@ public List update(ReferralBulkRequest referralRequest, boolean isBulk log.info("processing {} valid entities", validReferrals.size()); referralManagementEnrichmentService.update(validReferrals, referralRequest); referralManagementRepository.save(validReferrals, - adrmConfiguration.getUpdateReferralTopic()); + referralManagementConfiguration.getUpdateReferralTopic()); log.info("successfully updated bulk adverse events"); } } catch (Exception exception) { @@ -191,7 +191,7 @@ public List delete(ReferralBulkRequest referralRequest, boolean isBulk .findById(referralIds, false); referralManagementEnrichmentService.delete(existingReferrals, referralRequest); referralManagementRepository.save(existingReferrals, - adrmConfiguration.getDeleteReferralTopic()); + referralManagementConfiguration.getDeleteReferralTopic()); log.info("successfully deleted entities"); } } catch (Exception exception) { diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java index eebe695dc25..1d083c13446 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java @@ -2,8 +2,8 @@ import lombok.extern.slf4j.Slf4j; import org.egov.referralmanagement.repository.ReferralManagementRepository; -import org.egov.common.models.adrm.referralmanagement.Referral; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; import org.egov.common.service.IdGenService; import org.egov.common.utils.CommonUtils; import org.egov.referralmanagement.config.ReferralManagementConfiguration; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmFacilityEntitiesIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmFacilityEntitiesIdValidator.java similarity index 85% rename from health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmFacilityEntitiesIdValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmFacilityEntitiesIdValidator.java index 340fc531ca3..83d4377ee0c 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmFacilityEntitiesIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmFacilityEntitiesIdValidator.java @@ -1,17 +1,17 @@ -package org.egov.adrm.validator.rm; +package org.egov.referralmanagement.validator; import lombok.extern.slf4j.Slf4j; -import org.egov.adrm.config.AdrmConfiguration; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; -import org.egov.common.models.adrm.referralmanagement.Referral; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; import org.egov.common.models.facility.Facility; import org.egov.common.models.facility.FacilityBulkResponse; import org.egov.common.models.facility.FacilitySearch; import org.egov.common.models.facility.FacilitySearchRequest; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; import org.egov.common.validator.Validator; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -24,10 +24,10 @@ import java.util.Objects; import java.util.stream.Collectors; -import static org.egov.adrm.Constants.FACILITY; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; +import static org.egov.referralmanagement.Constants.FACILITY; @Component @@ -35,12 +35,12 @@ @Slf4j public class RmFacilityEntitiesIdValidator implements Validator { private final ServiceRequestClient serviceRequestClient; - private final AdrmConfiguration adrmConfiguration; + private final ReferralManagementConfiguration referralManagementConfiguration; @Autowired - public RmFacilityEntitiesIdValidator(ServiceRequestClient serviceRequestClient, AdrmConfiguration adrmConfiguration) { + public RmFacilityEntitiesIdValidator(ServiceRequestClient serviceRequestClient, ReferralManagementConfiguration referralManagementConfiguration) { this.serviceRequestClient = serviceRequestClient; - this.adrmConfiguration = adrmConfiguration; + this.referralManagementConfiguration = referralManagementConfiguration; } @@ -66,8 +66,8 @@ public Map> validate(ReferralBulkRequest request) { .id(facilityIdList.isEmpty() ? null : facilityIdList) .build(); FacilityBulkResponse facilityBulkResponse = serviceRequestClient.fetchResult( - new StringBuilder(adrmConfiguration.getFacilityHost() - + adrmConfiguration.getFacilitySearchUrl() + new StringBuilder(referralManagementConfiguration.getFacilityHost() + + referralManagementConfiguration.getFacilitySearchUrl() +"?limit=" + entities.size() + "&offset=0&tenantId=" + tenantId), FacilitySearchRequest.builder().requestInfo(request.getRequestInfo()).facility(facilitySearch).build(), diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmIsDeletedValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmIsDeletedValidator.java similarity index 85% rename from health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmIsDeletedValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmIsDeletedValidator.java index 00dd7156d42..ca58f6deb30 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmIsDeletedValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmIsDeletedValidator.java @@ -1,9 +1,9 @@ -package org.egov.adrm.validator.rm; +package org.egov.referralmanagement.validator; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; -import org.egov.common.models.adrm.referralmanagement.Referral; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNonExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java similarity index 98% rename from health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNonExistentEntityValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java index 5a4e881370b..b52332d738d 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNonExistentEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java @@ -1,4 +1,4 @@ -package org.egov.adrm.validator.rm; +package org.egov.referralmanagement.validator; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNullIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNullIdValidator.java similarity index 72% rename from health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNullIdValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNullIdValidator.java index 5324a12270b..07df0399a64 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNullIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNullIdValidator.java @@ -1,9 +1,9 @@ -package org.egov.adrm.validator.rm; +package org.egov.referralmanagement.validator; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; -import org.egov.common.models.adrm.referralmanagement.Referral; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -11,7 +11,7 @@ import java.util.List; import java.util.Map; -import static org.egov.adrm.Constants.GET_REFERRALS; +import static org.egov.referralmanagement.Constants.GET_REFERRALS; import static org.egov.common.utils.CommonUtils.validateForNullId; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmProjectEntitiesIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectEntitiesIdValidator.java similarity index 99% rename from health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmProjectEntitiesIdValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectEntitiesIdValidator.java index 05c4670c7ec..ad45d193cf9 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmProjectEntitiesIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectEntitiesIdValidator.java @@ -1,4 +1,4 @@ -package org.egov.adrm.validator.rm; +package org.egov.referralmanagement.validator; import lombok.extern.slf4j.Slf4j; import org.egov.adrm.config.AdrmConfiguration; diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmUniqueEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmUniqueEntityValidator.java similarity index 91% rename from health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmUniqueEntityValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmUniqueEntityValidator.java index 8a73836a870..e35159b57f7 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmUniqueEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmUniqueEntityValidator.java @@ -1,9 +1,9 @@ -package org.egov.adrm.validator.rm; +package org.egov.referralmanagement.validator; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; -import org.egov.common.models.adrm.referralmanagement.Referral; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java index 346973d93c4..499760f0f78 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java @@ -3,12 +3,12 @@ import io.swagger.annotations.ApiParam; import org.egov.referralmanagement.service.ReferralManagementService; import org.egov.common.contract.response.ResponseInfo; -import org.egov.common.models.adrm.referralmanagement.Referral; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkResponse; -import org.egov.common.models.adrm.referralmanagement.ReferralRequest; -import org.egov.common.models.adrm.referralmanagement.ReferralResponse; -import org.egov.common.models.adrm.referralmanagement.ReferralSearchRequest; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.referralmanagement.ReferralBulkResponse; +import org.egov.common.models.referralmanagement.ReferralRequest; +import org.egov.common.models.referralmanagement.ReferralResponse; +import org.egov.common.models.referralmanagement.ReferralSearchRequest; import org.egov.common.producer.Producer; import org.egov.common.utils.ResponseInfoFactory; import org.egov.referralmanagement.config.ReferralManagementConfiguration; @@ -29,7 +29,7 @@ import java.util.List; @Controller -@RequestMapping("/referral-management") +@RequestMapping("") @Validated public class ReferralManagementApiController { private final HttpServletRequest httpServletRequest; @@ -52,7 +52,7 @@ public ReferralManagementApiController( this.referralManagementConfiguration = referralManagementConfiguration; } - @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) + @RequestMapping(value = "/referral/v1/_create", method = RequestMethod.POST) public ResponseEntity referralV1CreatePost(@ApiParam(value = "Capture details of Referral", required = true) @Valid @RequestBody ReferralRequest request) { Referral referral = referralManagementService.create(request); @@ -67,7 +67,7 @@ public ResponseEntity referralV1CreatePost(@ApiParam(value = " - @RequestMapping(value = "/v1/bulk/_create", method = RequestMethod.POST) + @RequestMapping(value = "/referral/v1/bulk/_create", method = RequestMethod.POST) public ResponseEntity referralBulkV1CreatePost(@ApiParam(value = "Capture details of Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); referralManagementService.putInCache(request.getReferrals()); @@ -77,7 +77,7 @@ public ResponseEntity referralBulkV1CreatePost(@ApiParam(value = " .createResponseInfo(request.getRequestInfo(), true)); } - @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) + @RequestMapping(value = "/referral/v1/_search", method = RequestMethod.POST) public ResponseEntity referralV1SearchPost(@ApiParam(value = "Referral Search.", required = true) @Valid @RequestBody ReferralSearchRequest request, @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, @@ -92,7 +92,7 @@ public ResponseEntity referralV1SearchPost(@ApiParam(value return ResponseEntity.status(HttpStatus.OK).body(response); } - @RequestMapping(value = "/v1/_update", method = RequestMethod.POST) + @RequestMapping(value = "/referral/v1/_update", method = RequestMethod.POST) public ResponseEntity referralV1UpdatePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralRequest request) { Referral referral = referralManagementService.update(request); @@ -106,7 +106,7 @@ public ResponseEntity referralV1UpdatePost(@ApiParam(value = " } - @RequestMapping(value = "/v1/bulk/_update", method = RequestMethod.POST) + @RequestMapping(value = "/referral/v1/bulk/_update", method = RequestMethod.POST) public ResponseEntity referralV1BulkUpdatePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); producer.push(referralManagementConfiguration.getUpdateReferralBulkTopic(), request); @@ -115,7 +115,7 @@ public ResponseEntity referralV1BulkUpdatePost(@ApiParam(value = " .createResponseInfo(request.getRequestInfo(), true)); } - @RequestMapping(value = "/v1/_delete", method = RequestMethod.POST) + @RequestMapping(value = "/referral/v1/_delete", method = RequestMethod.POST) public ResponseEntity referralV1DeletePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralRequest request) { Referral referral = referralManagementService.delete(request); From b52928046a49a9705d58198585e215c1e771f425 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Thu, 28 Sep 2023 12:14:31 +0530 Subject: [PATCH 162/283] HLM-3376: added db migration script, rename for referral-management module --- .../adverse-event-referral-management.yml | 30 ++++---- .../models/referralmanagement/Referral.java | 4 +- .../ReferralManagementConfiguration.java | 12 +-- .../consumer/ReferralManagementConsumer.java | 6 +- ...epository.java => ReferralRepository.java} | 8 +- .../rowmapper/ReferralRowMapper.java | 2 +- .../service/ReferralManagementService.java | 22 +++--- .../ReferralManagementEnrichmentService.java | 8 +- .../RmNonExistentEntityValidator.java | 16 ++-- .../RmProjectEntitiesIdValidator.java | 26 +++---- .../src/main/resources/application.properties | 16 ++-- .../V20230928113400__referral_create_ddl.sql | 25 +++++++ .../referral-management-persister.yml | 75 +++++++++++++++++++ 13 files changed, 174 insertions(+), 76 deletions(-) rename health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/{ReferralManagementRepository.java => ReferralRepository.java} (93%) create mode 100644 health-services/referralmanagement/src/main/resources/db/migration/main/V20230928113400__referral_create_ddl.sql diff --git a/docs/health-api-specs/contracts/adverse-event-referral-management.yml b/docs/health-api-specs/contracts/adverse-event-referral-management.yml index 926ea2ca85e..991a8a12dec 100644 --- a/docs/health-api-specs/contracts/adverse-event-referral-management.yml +++ b/docs/health-api-specs/contracts/adverse-event-referral-management.yml @@ -10,7 +10,7 @@ schemes: x-common-path: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-0-0.yml paths: - /adrm/adverse_event/v1/_create: + /referral-management/adverse_event/v1/_create: post: summary: >- Create adverse event for the project @@ -36,7 +36,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/adverse_event/v1/bulk/_create: + /referral-management/adverse_event/v1/bulk/_create: post: summary: >- Create adverse events for the project in bulk @@ -62,7 +62,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/adverse_event/v1/_update: + /referral-management/adverse_event/v1/_update: post: summary: >- Adverse Event Request @@ -88,7 +88,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/adverse_event/v1/bulk/_update: + /referral-management/adverse_event/v1/bulk/_update: post: summary: >- Adverse Event Request in bulk for a project @@ -114,7 +114,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/adverse_event/v1/_delete: + /referral-management/adverse_event/v1/_delete: post: summary: >- Soft delete Adverse Event for a project @@ -140,7 +140,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/adverse_event/v1/bulk/_delete: + /referral-management/adverse_event/v1/bulk/_delete: post: summary: >- Soft delete Adverse Events for a project @@ -166,7 +166,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/adverse_event/v1/_search: + /referral-management/adverse_event/v1/_search: post: summary: >- Search Adverse Event for Project @@ -197,7 +197,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/referral-management/v1/_create: + /referral-management/referral/v1/_create: post: summary: >- Create referral for the project beneficiary @@ -223,7 +223,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/referral-management/v1/bulk/_create: + /referral-management/referral/v1/bulk/_create: post: summary: >- Create referrals for the project beneficiary in bulk @@ -249,7 +249,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/referral-management/v1/_update: + /referral-management/referral/v1/_update: post: summary: >- Referral Request @@ -275,7 +275,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/referral-management/v1/bulk/_update: + /referral-management/referral/v1/bulk/_update: post: summary: >- Referral Request in bulk for a project beneficiary @@ -301,7 +301,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/referral-management/v1/_delete: + /referral-management/referral/v1/_delete: post: summary: >- Soft delete Referral for a project beneficiary @@ -327,7 +327,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/referral-management/v1/bulk/_delete: + /referral-management/referral/v1/bulk/_delete: post: summary: >- Soft delete Referrals for a project beneficiary @@ -353,7 +353,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/referral-management/v1/_search: + /referral-management/referral/v1/_search: post: summary: >- Search Referral for Project @@ -653,7 +653,7 @@ definitions: minLength: 2 maxLength: 64 description: Project Beneficiary Client Reference Id - referringPartyId: + referringById: type: string minLength: 2 maxLength: 64 diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java index 45771c0b566..172cc0339e0 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java @@ -38,9 +38,9 @@ public class Referral { @Size(min = 2, max = 64) private String projectBeneficiaryClientReferenceId = null; - @JsonProperty("referringPartyId") + @JsonProperty("referredById") @Size(min = 2, max = 64) - private String referringPartyId = null; + private String referredById = null; @JsonProperty("referredToType") private String referredToType = null; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java index bb06348aa74..67561b31d39 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java @@ -42,22 +42,22 @@ public class ReferralManagementConfiguration { @Value("${egov.search.project.beneficiary.url}") private String projectBeneficiarySearchUrl; - @Value("${referralmanagement.referralmanagement.kafka.create.topic}") + @Value("${referralmanagement.referral.kafka.create.topic}") private String createReferralTopic; - @Value("${referralmanagement.referralmanagement.kafka.update.topic}") + @Value("${referralmanagement.referral.kafka.update.topic}") private String updateReferralTopic; - @Value("${referralmanagement.referralmanagement.kafka.delete.topic}") + @Value("${referralmanagement.referral.kafka.delete.topic}") private String deleteReferralTopic; - @Value("${referralmanagement.referralmanagement.consumer.bulk.create.topic}") + @Value("${referralmanagement.referral.consumer.bulk.create.topic}") private String createReferralBulkTopic; - @Value("${referralmanagement.referralmanagement.consumer.bulk.update.topic}") + @Value("${referralmanagement.referral.consumer.bulk.update.topic}") private String updateReferralBulkTopic; - @Value("${referralmanagement.referralmanagement.consumer.bulk.delete.topic}") + @Value("${referralmanagement.referral.consumer.bulk.delete.topic}") private String deleteReferralBulkTopic; @Value("${egov.search.project.staff.url}") diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java index cd6f8007f71..d4902d7ea33 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java @@ -30,7 +30,7 @@ public ReferralManagementConsumer(ReferralManagementService referralManagementSe this.objectMapper = objectMapper; } - @KafkaListener(topics = "${referralmanagement.referralmanagement.consumer.bulk.create.topic}") + @KafkaListener(topics = "${referralmanagement.referral.consumer.bulk.create.topic}") public void bulkCreate(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { @@ -43,7 +43,7 @@ public void bulkCreate(Map consumerRecord, } } - @KafkaListener(topics = "${referralmanagement.referralmanagement.consumer.bulk.update.topic}") + @KafkaListener(topics = "${referralmanagement.referral.consumer.bulk.update.topic}") public void bulkUpdate(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { @@ -56,7 +56,7 @@ public void bulkUpdate(Map consumerRecord, } } - @KafkaListener(topics = "${referralmanagement.referralmanagement.consumer.bulk.delete.topic}") + @KafkaListener(topics = "${referralmanagement.referral.consumer.bulk.delete.topic}") public void bulkDelete(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { try { diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralManagementRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java similarity index 93% rename from health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralManagementRepository.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java index d25b5124cdd..dd016da5a2e 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralManagementRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java @@ -17,8 +17,6 @@ import org.springframework.util.ReflectionUtils; import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -29,15 +27,15 @@ @Repository @Slf4j -public class ReferralManagementRepository extends GenericRepository { +public class ReferralRepository extends GenericRepository { @Autowired private ReferralRowMapper rowMapper; @Autowired - protected ReferralManagementRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, + protected ReferralRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, ReferralRowMapper rowMapper) { - super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, rowMapper, Optional.of("adverse_event")); + super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, rowMapper, Optional.of("referral")); } public List find(ReferralSearch searchObject, Integer limit, Integer offset, String tenantId, diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java index 8fb133b851f..1895e0829cc 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java @@ -65,7 +65,7 @@ public Referral mapRow(ResultSet resultSet, int i) throws SQLException { .clientReferenceId(resultSet.getString("clientreferenceid")) .projectBeneficiaryId(resultSet.getString("projectBeneficiaryId")) .projectBeneficiaryClientReferenceId(resultSet.getString("projectbeneficiaryclientreferenceid")) - .referringPartyId(resultSet.getString("referrringpartyid")) + .referredById(resultSet.getString("referredById")) .referredToId(resultSet.getString("referredToId")) .referredToType(resultSet.getString("referredToType")) .adverseEvent(adverseEvent) diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java index 2568bde9f62..4f064c6698a 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java @@ -3,7 +3,7 @@ import lombok.extern.slf4j.Slf4j; import org.egov.referralmanagement.Constants; import org.egov.referralmanagement.config.ReferralManagementConfiguration; -import org.egov.referralmanagement.repository.ReferralManagementRepository; +import org.egov.referralmanagement.repository.ReferralRepository; import org.egov.referralmanagement.service.enrichment.ReferralManagementEnrichmentService; import org.egov.referralmanagement.validator.RmFacilityEntitiesIdValidator; import org.egov.referralmanagement.validator.RmIsDeletedValidator; @@ -45,7 +45,7 @@ public class ReferralManagementService { private final IdGenService idGenService; - private final ReferralManagementRepository referralManagementRepository; + private final ReferralRepository referralRepository; private final ReferralManagementConfiguration referralManagementConfiguration; @@ -70,9 +70,9 @@ public class ReferralManagementService { || validator.getClass().equals(RmNonExistentEntityValidator.class); - public ReferralManagementService(IdGenService idGenService, ReferralManagementRepository referralManagementRepository, ReferralManagementConfiguration referralManagementConfiguration, ReferralManagementEnrichmentService referralManagementEnrichmentService, List> validators) { + public ReferralManagementService(IdGenService idGenService, ReferralRepository referralRepository, ReferralManagementConfiguration referralManagementConfiguration, ReferralManagementEnrichmentService referralManagementEnrichmentService, List> validators) { this.idGenService = idGenService; - this.referralManagementRepository = referralManagementRepository; + this.referralRepository = referralRepository; this.referralManagementConfiguration = referralManagementConfiguration; this.referralManagementEnrichmentService = referralManagementEnrichmentService; this.validators = validators; @@ -97,7 +97,7 @@ public List create(ReferralBulkRequest referralRequest, boolean isBulk if (!validReferrals.isEmpty()) { log.info("processing {} valid entities", validReferrals.size()); referralManagementEnrichmentService.create(validReferrals, referralRequest); - referralManagementRepository.save(validReferrals, + referralRepository.save(validReferrals, referralManagementConfiguration.getCreateReferralTopic()); log.info("successfully created adverse events"); } @@ -130,7 +130,7 @@ public List update(ReferralBulkRequest referralRequest, boolean isBulk if (!validReferrals.isEmpty()) { log.info("processing {} valid entities", validReferrals.size()); referralManagementEnrichmentService.update(validReferrals, referralRequest); - referralManagementRepository.save(validReferrals, + referralRepository.save(validReferrals, referralManagementConfiguration.getUpdateReferralTopic()); log.info("successfully updated bulk adverse events"); } @@ -158,14 +158,14 @@ public List search(ReferralSearchRequest referralSearchRequest, .singletonList(referralSearchRequest.getReferral())), referralSearchRequest.getReferral()); log.info("fetching adverse events with ids: {}", ids); - return referralManagementRepository.findById(ids, includeDeleted, idFieldName).stream() + return referralRepository.findById(ids, includeDeleted, idFieldName).stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); } log.info("searching adverse events using criteria"); - return referralManagementRepository.find(referralSearchRequest.getReferral(), + return referralRepository.find(referralSearchRequest.getReferral(), limit, offset, tenantId, lastChangedSince, includeDeleted); } @@ -187,10 +187,10 @@ public List delete(ReferralBulkRequest referralRequest, boolean isBulk if (!validReferrals.isEmpty()) { log.info("processing {} valid entities", validReferrals.size()); List referralIds = validReferrals.stream().map(entity -> entity.getId()).collect(Collectors.toSet()).stream().collect(Collectors.toList()); - List existingReferrals = referralManagementRepository + List existingReferrals = referralRepository .findById(referralIds, false); referralManagementEnrichmentService.delete(existingReferrals, referralRequest); - referralManagementRepository.save(existingReferrals, + referralRepository.save(existingReferrals, referralManagementConfiguration.getDeleteReferralTopic()); log.info("successfully deleted entities"); } @@ -206,7 +206,7 @@ public List delete(ReferralBulkRequest referralRequest, boolean isBulk public void putInCache(List referrals) { log.info("putting {} adverse events in cache", referrals.size()); - referralManagementRepository.putInCache(referrals); + referralRepository.putInCache(referrals); log.info("successfully put adverse events in cache"); } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java index 1d083c13446..659e54eb280 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java @@ -1,7 +1,7 @@ package org.egov.referralmanagement.service.enrichment; import lombok.extern.slf4j.Slf4j; -import org.egov.referralmanagement.repository.ReferralManagementRepository; +import org.egov.referralmanagement.repository.ReferralRepository; import org.egov.common.models.referralmanagement.Referral; import org.egov.common.models.referralmanagement.ReferralBulkRequest; import org.egov.common.service.IdGenService; @@ -24,12 +24,12 @@ public class ReferralManagementEnrichmentService { private final ReferralManagementConfiguration referralManagementConfiguration; - private final ReferralManagementRepository referralManagementRepository; + private final ReferralRepository referralRepository; - public ReferralManagementEnrichmentService(IdGenService idGenService, ReferralManagementConfiguration referralManagementConfiguration, ReferralManagementRepository referralManagementRepository) { + public ReferralManagementEnrichmentService(IdGenService idGenService, ReferralManagementConfiguration referralManagementConfiguration, ReferralRepository referralRepository) { this.idGenService = idGenService; this.referralManagementConfiguration = referralManagementConfiguration; - this.referralManagementRepository = referralManagementRepository; + this.referralRepository = referralRepository; } public void create(List entities, ReferralBulkRequest request) throws Exception { diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java index b52332d738d..7f970822522 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java @@ -2,11 +2,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; -import org.egov.adrm.repository.ReferralManagementRepository; import org.egov.common.models.Error; -import org.egov.common.models.adrm.referralmanagement.Referral; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; import org.egov.common.validator.Validator; +import org.egov.referralmanagement.repository.ReferralRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -18,7 +18,7 @@ import java.util.Map; import java.util.stream.Collectors; -import static org.egov.adrm.Constants.GET_ID; +import static org.egov.referralmanagement.Constants.GET_ID; import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.getIdToObjMap; @@ -33,13 +33,13 @@ @Slf4j public class RmNonExistentEntityValidator implements Validator { - private final ReferralManagementRepository referralManagementRepository; + private final ReferralRepository referralRepository; private final ObjectMapper objectMapper; @Autowired - public RmNonExistentEntityValidator(ReferralManagementRepository referralManagementRepository, ObjectMapper objectMapper) { - this.referralManagementRepository = referralManagementRepository; + public RmNonExistentEntityValidator(ReferralRepository referralRepository, ObjectMapper objectMapper) { + this.referralRepository = referralRepository; this.objectMapper = objectMapper; } @@ -55,7 +55,7 @@ public Map> validate(ReferralBulkRequest request) { .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); if (!iMap.isEmpty()) { List adverseEventIds = new ArrayList<>(iMap.keySet()); - List existingReferrals = referralManagementRepository + List existingReferrals = referralRepository .findById(adverseEventIds, false, getIdFieldName(idMethod)); List nonExistentReferrals = checkNonExistentEntities(iMap, existingReferrals, idMethod); diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectEntitiesIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectEntitiesIdValidator.java index ad45d193cf9..61c87b9f4ab 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectEntitiesIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectEntitiesIdValidator.java @@ -1,12 +1,9 @@ package org.egov.referralmanagement.validator; import lombok.extern.slf4j.Slf4j; -import org.egov.adrm.config.AdrmConfiguration; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; -import org.egov.common.models.adrm.referralmanagement.Referral; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; import org.egov.common.models.project.BeneficiaryBulkResponse; import org.egov.common.models.project.BeneficiarySearchRequest; import org.egov.common.models.project.ProjectBeneficiary; @@ -15,7 +12,10 @@ import org.egov.common.models.project.ProjectStaffBulkResponse; import org.egov.common.models.project.ProjectStaffSearch; import org.egov.common.models.project.ProjectStaffSearchRequest; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; import org.egov.common.validator.Validator; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -28,7 +28,7 @@ import java.util.Objects; import java.util.stream.Collectors; -import static org.egov.adrm.Constants.PROJECT_STAFF; +import static org.egov.referralmanagement.Constants.PROJECT_STAFF; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; @@ -39,12 +39,12 @@ @Slf4j public class RmProjectEntitiesIdValidator implements Validator { private final ServiceRequestClient serviceRequestClient; - private final AdrmConfiguration adrmConfiguration; + private final ReferralManagementConfiguration referralManagementConfiguration; @Autowired - public RmProjectEntitiesIdValidator(ServiceRequestClient serviceRequestClient, AdrmConfiguration adrmConfiguration) { + public RmProjectEntitiesIdValidator(ServiceRequestClient serviceRequestClient, ReferralManagementConfiguration referralManagementConfiguration) { this.serviceRequestClient = serviceRequestClient; - this.adrmConfiguration = adrmConfiguration; + this.referralManagementConfiguration = referralManagementConfiguration; } @@ -67,7 +67,7 @@ public Map> validate(ReferralBulkRequest request) { referralList.forEach(referral -> { addIgnoreNull(projectBeneficiaryIdList, referral.getProjectBeneficiaryId()); addIgnoreNull(projectBeneficiaryClientReferenceIdList, referral.getProjectBeneficiaryClientReferenceId()); - addIgnoreNull(projectStaffIdList, referral.getReferringPartyId()); + addIgnoreNull(projectStaffIdList, referral.getReferredById()); if(referral.getReferredToType().equals(PROJECT_STAFF)){ addIgnoreNull(projectStaffIdList, referral.getReferredToId()); } @@ -77,8 +77,8 @@ public Map> validate(ReferralBulkRequest request) { .clientReferenceId(projectBeneficiaryClientReferenceIdList.isEmpty() ? null : projectBeneficiaryClientReferenceIdList) .build(); BeneficiaryBulkResponse beneficiaryBulkResponse = serviceRequestClient.fetchResult( - new StringBuilder(adrmConfiguration.getProjectHost() - + adrmConfiguration.getProjectBeneficiarySearchUrl() + new StringBuilder(referralManagementConfiguration.getProjectHost() + + referralManagementConfiguration.getProjectBeneficiarySearchUrl() +"?limit=" + entities.size() + "&offset=0&tenantId=" + tenantId), BeneficiarySearchRequest.builder().requestInfo(request.getRequestInfo()).projectBeneficiary(projectBeneficiarySearch).build(), @@ -89,8 +89,8 @@ public Map> validate(ReferralBulkRequest request) { .id(projectStaffIdList.isEmpty() ? null : projectStaffIdList) .build(); ProjectStaffBulkResponse projectStaffBulkResponse = serviceRequestClient.fetchResult( - new StringBuilder(adrmConfiguration.getProjectHost() - + adrmConfiguration.getProjectStaffSearchUrl() + new StringBuilder(referralManagementConfiguration.getProjectHost() + + referralManagementConfiguration.getProjectStaffSearchUrl() +"?limit=" + entities.size() + "&offset=0&tenantId=" + tenantId), ProjectStaffSearchRequest.builder().requestInfo(request.getRequestInfo()).projectStaff(projectStaffSearch).build(), @@ -113,7 +113,7 @@ public Map> validate(ReferralBulkRequest request) { final List existingProjectStaffIds = new ArrayList<>(); existingProjectStaffList.forEach(projectStaff -> existingProjectStaffIds.add(projectStaff.getId())); List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> - !existingProjectStaffIds.contains(entity.getReferringPartyId()) + !existingProjectStaffIds.contains(entity.getReferredById()) && !existingProjectBeneficiaryIds.contains(entity.getProjectBeneficiaryId()) && !existingProjectBeneficiaryClientReferenceIds.contains(entity.getProjectBeneficiaryClientReferenceId()) && (!entity.getReferredToType().equals(PROJECT_STAFF) || !existingProjectStaffIds.contains(entity.getReferredToId())) diff --git a/health-services/referralmanagement/src/main/resources/application.properties b/health-services/referralmanagement/src/main/resources/application.properties index 8911227c63d..cbbc0f825f3 100644 --- a/health-services/referralmanagement/src/main/resources/application.properties +++ b/health-services/referralmanagement/src/main/resources/application.properties @@ -1,4 +1,4 @@ -server.servlet.context-path=/referralmanagement +server.servlet.context-path=/referral-management server.port=8080 app.timezone=UTC @@ -24,7 +24,7 @@ spring.flyway.table=public spring.flyway.baseline-on-migrate=true spring.flyway.outOfOrder=true spring.flyway.locations=classpath:/db/migration/main -spring.flyway.enabled=false +spring.flyway.enabled=true # TRACER CONFIG # KAFKA SERVER CONFIG @@ -111,13 +111,13 @@ referralmanagement.adverseevent.consumer.bulk.create.topic=save-adverse-event-bu referralmanagement.adverseevent.consumer.bulk.update.topic=update-adverse-event-bulk-topic referralmanagement.adverseevent.consumer.bulk.delete.topic=delete-adverse-event-bulk-topic -adrm.referralmanagement.kafka.create.topic=save-referral-management-topic -adrm.referralmanagement.kafka.update.topic=update-referral-management-topic -adrm.referralmanagement.kafka.delete.topic=delete-referral-management-topic +referralmanagement.referral.kafka.create.topic=save-referral-topic +referralmanagement.referral.kafka.update.topic=update-referral-topic +referralmanagement.referral.kafka.delete.topic=delete-referral-topic -adrm.referralmanagement.consumer.bulk.create.topic=save-referral-management-bulk-topic -adrm.referralmanagement.consumer.bulk.update.topic=update-referral-management-bulk-topic -adrm.referralmanagement.consumer.bulk.delete.topic=delete-referral-management-bulk-topic +referralmanagement.referral.consumer.bulk.create.topic=save-referral-bulk-topic +referralmanagement.referral.consumer.bulk.update.topic=update-referral-bulk-topic +referralmanagement.referral.consumer.bulk.delete.topic=delete-referral-bulk-topic search.api.limit=1000 diff --git a/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928113400__referral_create_ddl.sql b/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928113400__referral_create_ddl.sql new file mode 100644 index 00000000000..a18383c453f --- /dev/null +++ b/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928113400__referral_create_ddl.sql @@ -0,0 +1,25 @@ +CREATE TABLE REFERRAL +( + id character varying(64), + clientReferenceId character varying(64), + tenantId character varying(1000), + projectBeneficiaryId character varying(64), + projectBeneficiaryClientReferenceId character varying(64), + referredById character varying(100), + referredToId character varying(100), + referredToType character varying(100), + reasons jsonb, + adverseEventId character varying(100), + createdBy character varying(64), + createdTime bigint, + lastModifiedBy character varying(64), + lastModifiedTime bigint, + clientCreatedBy character varying(64), + clientCreatedTime bigint, + clientLastModifiedBy character varying(64), + clientLastModifiedTime bigint, + rowVersion bigint, + isDeleted boolean, + CONSTRAINT uk_referral_id PRIMARY KEY (id), + CONSTRAINT uk_referral_clientReferenceId UNIQUE (clientReferenceId) +); diff --git a/health-services/referralmanagement/src/main/resources/referral-management-persister.yml b/health-services/referralmanagement/src/main/resources/referral-management-persister.yml index 49fb3454ed8..331152b0b5c 100644 --- a/health-services/referralmanagement/src/main/resources/referral-management-persister.yml +++ b/health-services/referralmanagement/src/main/resources/referral-management-persister.yml @@ -69,3 +69,78 @@ serviceMaps: - jsonPath: $.*.rowVersion - jsonPath: $.*.isDeleted - jsonPath: $.*.id + + - version: 1.0 + description: Saves a referral + fromTopic: save-referral-topic + isTransaction: true + queryMaps: + - query: INSERT INTO REFERRAL(id, clientReferenceId, tenantId, projectBeneficiaryId, projectBeneficiaryClientReferenceId, referredById, referredToId, referredToType, reasons, adverseEventId, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedBy, clientCreatedTime, clientLastModifiedBy, clientLastModifiedTime, rowVersion, isDeleted) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); + basePath: $.* + jsonMaps: + - jsonPath: $.*.id + - jsonPath: $.*.clientReferenceId + - jsonPath: $.*.tenantId + - jsonPath: $.*.projectBeneficiaryId + - jsonPath: $.*.projectBeneficiaryClientReferenceId + - jsonPath: $.*.referredById + - jsonPath: $.*.referredToId + - jsonPath: $.*.referredToType + - jsonPath: $.*.reasons + type: JSON + dbType: JSONB + - jsonPath: $.*.adverseEvent.id + - jsonPath: $.*.auditDetails.createdBy + - jsonPath: $.*.auditDetails.createdTime + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.createdBy + - jsonPath: $.*.clientAuditDetails.createdTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + + - version: 1.0 + description: Updates a referral + fromTopic: update-referral-topic + isTransaction: true + queryMaps: + - query: UPDATE REFERRAL SET tenantId = ?, projectBeneficiaryId = ?, projectBeneficiaryClientReferenceId = ?, referredById = ?, referredToId = ?, referredToType = ?, reasons = ?, adverseEventId = ?, createdBy = ?, createdTime = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientCreatedBy = ?, clientCreatedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted WHERE ID = ?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.tenantId + - jsonPath: $.*.projectBeneficiaryId + - jsonPath: $.*.projectBeneficiaryClientReferenceId + - jsonPath: $.*.referredById + - jsonPath: $.*.referredToId + - jsonPath: $.*.referredToType + - jsonPath: $.*.reasons + type: JSON + dbType: JSONB + - jsonPath: $.*.adverseEvent.id + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - jsonPath: $.*.id + + - version: 1.0 + description: Deletes a referral + fromTopic: delete-referral-topic + isTransaction: true + queryMaps: + - query: UPDATE REFERRAL SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - jsonPath: $.*.id + + From cc45e4e9d1ff7ccfc69f8799673dfbeda50ba514 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Thu, 28 Sep 2023 14:00:18 +0530 Subject: [PATCH 163/283] HLM-3069: adverse event renamed to side effect --- ...management.yml => referral-management.yml} | 162 ++++++------ .../SideEffect.java} | 4 +- .../SideEffectBulkRequest.java} | 12 +- .../SideEffectBulkResponse.java} | 12 +- .../SideEffectRequest.java} | 8 +- .../SideEffectResponse.java} | 8 +- .../SideEffectSearch.java} | 5 +- .../SideEffectSearchRequest.java} | 8 +- health-services/project/README.md | 8 - .../project/config/ProjectConfiguration.java | 17 -- .../src/main/resources/application.properties | 10 - ...V20230901150100__adverse_event_ref_ddl.sql | 2 - ...0906144900__adverse_event_col_drop_ddl.sql | 1 - .../egov/referralmanagement/Constants.java | 4 +- .../ReferralManagementConfiguration.java | 24 +- .../consumer/AdverseEventConsumer.java | 71 ------ .../consumer/SideEffectConsumer.java | 71 ++++++ ...ository.java => SideEffectRepository.java} | 58 ++--- ...owMapper.java => SideEffectRowMapper.java} | 8 +- .../service/AdverseEventService.java | 237 ------------------ .../service/SideEffectService.java | 237 ++++++++++++++++++ .../AdverseEventEnrichmentService.java | 54 ---- .../SideEffectEnrichmentService.java | 54 ++++ .../adverseevent/AdNullIdValidator.java | 27 -- .../SeIsDeletedValidator.java} | 16 +- .../SeNonExistentEntityValidator.java} | 40 +-- .../sideeffect/SeNullIdValidator.java | 27 ++ .../SeProjectTaskIdValidator.java} | 40 +-- .../SeUniqueEntityValidator.java} | 16 +- .../AdverseEventApiController.java | 141 ----------- .../controllers/SideEffectApiController.java | 141 +++++++++++ .../src/main/resources/application.properties | 14 +- ...0230928120100__side_effect_create_ddl.sql} | 13 +- .../referral-management-persister.yml | 18 +- .../AdverseEventRequestTestBuilder.java | 60 ----- .../helper/SideEffectRequestTestBuilder.java | 60 +++++ ...uilder.java => SideEffectTestBuilder.java} | 36 +-- ....java => SideEffectApiControllerTest.java} | 122 ++++----- 38 files changed, 903 insertions(+), 943 deletions(-) rename docs/health-api-specs/contracts/{adverse-event-referral-management.yml => referral-management.yml} (77%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/{adverseevent/AdverseEvent.java => sideeffect/SideEffect.java} (95%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/{adverseevent/AdverseEventBulkRequest.java => sideeffect/SideEffectBulkRequest.java} (67%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/{adverseevent/AdverseEventBulkResponse.java => sideeffect/SideEffectBulkResponse.java} (66%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/{adverseevent/AdverseEventRequest.java => sideeffect/SideEffectRequest.java} (76%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/{adverseevent/AdverseEventResponse.java => sideeffect/SideEffectResponse.java} (76%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/{adverseevent/AdverseEventSearch.java => sideeffect/SideEffectSearch.java} (82%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/{adverseevent/AdverseEventSearchRequest.java => sideeffect/SideEffectSearchRequest.java} (74%) delete mode 100644 health-services/project/src/main/resources/db/migration/main/V20230901150100__adverse_event_ref_ddl.sql delete mode 100644 health-services/project/src/main/resources/db/migration/main/V20230906144900__adverse_event_col_drop_ddl.sql delete mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/AdverseEventConsumer.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/SideEffectConsumer.java rename health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/{AdverseEventRepository.java => SideEffectRepository.java} (58%) rename health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/{AdverseEventRowMapper.java => SideEffectRowMapper.java} (89%) delete mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/AdverseEventService.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java delete mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/AdverseEventEnrichmentService.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/SideEffectEnrichmentService.java delete mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNullIdValidator.java rename health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/{adverseevent/AdIsDeletedValidator.java => sideeffect/SeIsDeletedValidator.java} (51%) rename health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/{adverseevent/AdNonExistentEntityValidator.java => sideeffect/SeNonExistentEntityValidator.java} (51%) create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNullIdValidator.java rename health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/{adverseevent/AdProjectTaskIdValidator.java => sideeffect/SeProjectTaskIdValidator.java} (81%) rename health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/{adverseevent/AdUniqueEntityValidator.java => sideeffect/SeUniqueEntityValidator.java} (66%) delete mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/AdverseEventApiController.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/SideEffectApiController.java rename health-services/{project/src/main/resources/db/migration/main/V20230807130400__adverse_event_create_ddl.sql => referralmanagement/src/main/resources/db/migration/main/V20230928120100__side_effect_create_ddl.sql} (62%) delete mode 100644 health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventRequestTestBuilder.java create mode 100644 health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectRequestTestBuilder.java rename health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/{AdverseEventTestBuilder.java => SideEffectTestBuilder.java} (61%) rename health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/{AdverseEventApiControllerTest.java => SideEffectApiControllerTest.java} (60%) diff --git a/docs/health-api-specs/contracts/adverse-event-referral-management.yml b/docs/health-api-specs/contracts/referral-management.yml similarity index 77% rename from docs/health-api-specs/contracts/adverse-event-referral-management.yml rename to docs/health-api-specs/contracts/referral-management.yml index ecb327974ff..10d0e7b0d8d 100644 --- a/docs/health-api-specs/contracts/adverse-event-referral-management.yml +++ b/docs/health-api-specs/contracts/referral-management.yml @@ -1,7 +1,7 @@ swagger: '2.0' info: version: 1.0.0 - title: Adverse Event and Referral Management System + title: Referral Management System contact: name: egovernments foundation email: info@egovernments.org @@ -10,50 +10,50 @@ schemes: x-common-path: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-0-0.yml paths: - /adrm/adverse_event/v1/_create: + /adrm/side_effect/v1/_create: post: summary: >- - Create adverse event for the project + Create side effect for the project description: >- - Create adverse event for the project + Create side effect for the project parameters: - - name: AdverseEvent + - name: SideEffect in: body - description: Capture details of Adverse Event + description: Capture details of Side Effect required: true schema: - $ref: '#/definitions/AdverseEventRequest' + $ref: '#/definitions/SideEffectRequest' tags: - - Adverse Event + - Side Effect responses: '202': - description: Create adverse event request has been accepted for creation. + description: Create side effect request has been accepted for creation. schema: - $ref: '#/definitions/AdverseEventResponse' + $ref: '#/definitions/SideEffectResponse' '400': description: Invalid Input body. schema: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/adverse_event/v1/bulk/_create: + /adrm/side_effect/v1/bulk/_create: post: summary: >- - Create adverse events for the project in bulk + Create side effects for the project in bulk description: >- - Create adverse events for the project in bulk + Create side effects for the project in bulk parameters: - - name: AdverseEvent + - name: SideEffect in: body description: Capture details of Task required: true schema: - $ref: '#/definitions/AdverseEventBulkRequest' + $ref: '#/definitions/SideEffectBulkRequest' tags: - - Adverse Event + - Side Effect responses: '202': - description: Create adverse event request has been accepted for creation. + description: Create side effect request has been accepted for creation. schema: $ref: '#/definitions/BulkAcceptedResponse' '400': @@ -62,50 +62,50 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/adverse_event/v1/_update: + /adrm/side-effect/v1/_update: post: summary: >- - Adverse Event Request + Side Effect Request description: >- - Adverse Event Request + Side Effect Request parameters: - - name: AdverseEvent + - name: SideEffect in: body - description: Capture details of Existing adverse event + description: Capture details of Existing side effect required: true schema: - $ref: '#/definitions/AdverseEventRequest' + $ref: '#/definitions/SideEffectRequest' tags: - - Adverse Event + - Side Effect responses: '202': description: update averse event request has been accepted for update. schema: - $ref: '#/definitions/AdverseEventResponse' + $ref: '#/definitions/SideEffectResponse' '400': description: Invalid Input body. schema: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/adverse_event/v1/bulk/_update: + /adrm/side-effect/v1/bulk/_update: post: summary: >- - Adverse Event Request in bulk for a project + Side Effect Request in bulk for a project description: >- - Adverse Event Request in bulk for a project + Side Effect Request in bulk for a project parameters: - - name: AdverseEvent + - name: SideEffect in: body - description: Capture details of Existing Adverse Events + description: Capture details of Existing Side Effects required: true schema: - $ref: '#/definitions/AdverseEventBulkRequest' + $ref: '#/definitions/SideEffectBulkRequest' tags: - - Adverse Event + - Side Effect responses: '202': - description: update Adverse Events bulk request has been accepted for update. + description: update Side Effects bulk request has been accepted for update. schema: $ref: '#/definitions/BulkAcceptedResponse' '400': @@ -114,50 +114,50 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/adverse_event/v1/_delete: + /adrm/side-effect/v1/_delete: post: summary: >- - Soft delete Adverse Event for a project + Soft delete Side Effect for a project description: >- - Soft delete Adverse Event for a project + Soft delete Side Effect for a project parameters: - - name: AdverseEvent + - name: SideEffect in: body - description: Capture details of Existing Adverse Event + description: Capture details of Existing Side Effect required: true schema: - $ref: '#/definitions/AdverseEventRequest' + $ref: '#/definitions/SideEffectRequest' tags: - - Adverse Event + - Side Effect responses: '202': - description: delete Adverse Event request has been accepted for deletion. + description: delete Side Effect request has been accepted for deletion. schema: - $ref: '#/definitions/AdverseEventResponse' + $ref: '#/definitions/SideEffectResponse' '400': description: Invalid Input body. schema: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/adverse_event/v1/bulk/_delete: + /adrm/side-effect/v1/bulk/_delete: post: summary: >- - Soft delete Adverse Events for a project + Soft delete Side Effects for a project description: >- - Soft delete Adverse Events for a project + Soft delete Side Effects for a project parameters: - - name: AdverseEvent + - name: SideEffect in: body - description: Capture details of Existing Adverse Event + description: Capture details of Existing Side Effect required: true schema: - $ref: '#/definitions/AdverseEventRequest' + $ref: '#/definitions/SideEffectRequest' tags: - - Adverse Event + - Side Effect responses: '202': - description: delete bulk Adverse Event request has been accepted for deletion. + description: delete bulk Side Effect request has been accepted for deletion. schema: $ref: '#/definitions/BulkAcceptedResponse' '400': @@ -166,31 +166,31 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/adverse_event/v1/_search: + /adrm/side-effect/v1/_search: post: summary: >- - Search Adverse Event for Project + Search Side Effect for Project description: >- - Search Adverse Event for Project + Search Side Effect for Project parameters: - - name: AdverseEvent + - name: SideEffect in: body - description: Adverse Event Search. + description: Side Effect Search. required: true schema: - $ref: '#/definitions/AdverseEventSearchRequest' + $ref: '#/definitions/SideEffectSearchRequest' - $ref: '#/parameters/limit' - $ref: '#/parameters/offset' - $ref: '#/parameters/tenantId' - $ref: '#/parameters/lastChangedSince' - $ref: '#/parameters/includeDeleted' tags: - - Adverse Event + - Side Effect responses: '200': - description: Adverse Events. + description: Side Effects. schema: - $ref: '#/definitions/AdverseEventBulkResponse' + $ref: '#/definitions/SideEffectBulkResponse' '400': description: Invalid Input body. schema: @@ -325,7 +325,7 @@ definitions: Address: $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/Address' - AdverseEvent: + SideEffect: type: object required: - tenantId @@ -362,35 +362,35 @@ definitions: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails - AdverseEventRequest: + SideEffectRequest: type: object properties: RequestInfo: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo - AdverseEvent: + SideEffect: type: object - $ref: '#/definitions/AdverseEvent' + $ref: '#/definitions/SideEffect' required: - RequestInfo - - AdverseEvent + - SideEffect - AdverseEventBulkRequest: + SideEffectBulkRequest: type: object properties: RequestInfo: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo - AdverseEvents: + SideEffects: type: array minItems: 1 items: - $ref: '#/definitions/AdverseEvent' + $ref: '#/definitions/SideEffect' required: - RequestInfo - - AdverseEvents + - SideEffects - AdverseEventSearch: + SideEffectSearch: type: object properties: id: @@ -406,41 +406,41 @@ definitions: type: string example: "R-ID-1" - AdverseEventSearchRequest: + SideEffectSearchRequest: type: object properties: RequestInfo: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo - AdverseEvent: - $ref: '#/definitions/AdverseEventSearch' + SideEffect: + $ref: '#/definitions/SideEffectSearch' required: - RequestInfo - - AdverseEvent + - SideEffect - AdverseEventResponse: + SideEffectResponse: type: object properties: ResponseInfo: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo - AdverseEvent: + SideEffect: type: object - $ref: '#/definitions/AdverseEvent' + $ref: '#/definitions/SideEffect' required: - ResponseInfo - - AdverseEvent + - SideEffect - AdverseEventBulkResponse: + SideEffectBulkResponse: type: object properties: ResponseInfo: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo - AdverseEvents: + SideEffects: type: array items: - $ref: '#/definitions/AdverseEvent' + $ref: '#/definitions/SideEffect' required: - ResponseInfo - - AdverseEvents \ No newline at end of file + - SideEffects \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEvent.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java similarity index 95% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEvent.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java index fbaf7c00736..a078844a2dc 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEvent.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java @@ -1,4 +1,4 @@ -package org.egov.common.models.referralmanagement.adverseevent; +package org.egov.common.models.referralmanagement.sideeffect; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -19,7 +19,7 @@ @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class AdverseEvent { +public class SideEffect { @JsonProperty("id") @Size(min = 2, max = 64) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java similarity index 67% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java index fa9248d1e1e..51319d73b51 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.referralmanagement.adverseevent; +package org.egov.common.models.referralmanagement.sideeffect; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -19,20 +19,20 @@ @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class AdverseEventBulkRequest { +public class SideEffectBulkRequest { @JsonProperty("RequestInfo") @NotNull @Valid private RequestInfo requestInfo = null; - @JsonProperty("AdverseEvents") + @JsonProperty("SideEffects") @NotNull @Valid @Size(min=1) - private List adverseEvents = new ArrayList<>(); + private List sideEffects = new ArrayList<>(); - public AdverseEventBulkRequest addAdverseEventItem(AdverseEvent adverseEventItem) { - this.adverseEvents.add(adverseEventItem); + public SideEffectBulkRequest addSideEffectItem(SideEffect sideEffectItem) { + this.sideEffects.add(sideEffectItem); return this; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java similarity index 66% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkResponse.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java index 880cc07875d..bfcfda3dae4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java @@ -1,4 +1,4 @@ -package org.egov.common.models.referralmanagement.adverseevent; +package org.egov.common.models.referralmanagement.sideeffect; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -18,20 +18,20 @@ @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class AdverseEventBulkResponse { +public class SideEffectBulkResponse { @JsonProperty("ResponseInfo") @NotNull @Valid private ResponseInfo responseInfo = null; - @JsonProperty("AdverseEvents") + @JsonProperty("SideEffects") @NotNull @Valid - private List adverseEvents = new ArrayList<>(); + private List sideEffects = new ArrayList<>(); - public AdverseEventBulkResponse addAdverseEventItem(AdverseEvent adverseEventItem) { - this.adverseEvents.add(adverseEventItem); + public SideEffectBulkResponse addSideEffectItem(SideEffect sideEffectItem) { + this.sideEffects.add(sideEffectItem); return this; } } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java similarity index 76% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java index 6e470f9f435..9de2e92b66e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.referralmanagement.adverseevent; +package org.egov.common.models.referralmanagement.sideeffect; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -16,14 +16,14 @@ @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class AdverseEventRequest{ +public class SideEffectRequest { @JsonProperty("RequestInfo") @NotNull @Valid private RequestInfo requestInfo = null; - @JsonProperty("AdverseEvent") + @JsonProperty("SideEffect") @NotNull @Valid - private AdverseEvent adverseEvent = null; + private SideEffect sideEffect = null; } \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java similarity index 76% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventResponse.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java index 90851c1dcf7..9e96194482c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java @@ -1,4 +1,4 @@ -package org.egov.common.models.referralmanagement.adverseevent; +package org.egov.common.models.referralmanagement.sideeffect; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -16,16 +16,16 @@ @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class AdverseEventResponse { +public class SideEffectResponse { @JsonProperty("ResponseInfo") @NotNull @Valid private ResponseInfo responseInfo = null; - @JsonProperty("AdverseEvent") + @JsonProperty("SideEffect") @NotNull @Valid - private AdverseEvent adverseEvent = null; + private SideEffect sideEffect = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java similarity index 82% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearch.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java index 19a8cd94e99..3183a2533d6 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java @@ -1,4 +1,4 @@ -package org.egov.common.models.referralmanagement.adverseevent; +package org.egov.common.models.referralmanagement.sideeffect; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -7,7 +7,6 @@ import lombok.Data; import lombok.NoArgsConstructor; -import javax.validation.constraints.Size; import java.util.List; @Data @@ -15,7 +14,7 @@ @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class AdverseEventSearch { +public class SideEffectSearch { @JsonProperty("id") private List id = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java similarity index 74% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearchRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java index 68b546c3dac..69cc688f884 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.referralmanagement.adverseevent; +package org.egov.common.models.referralmanagement.sideeffect; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -16,13 +16,13 @@ @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class AdverseEventSearchRequest { +public class SideEffectSearchRequest { @JsonProperty("RequestInfo") @NotNull @Valid private RequestInfo requestInfo = null; - @JsonProperty("AdverseEvent") + @JsonProperty("SideEffect") @Valid - private AdverseEventSearch adverseEvent = null; + private SideEffectSearch sideEffect = null; } diff --git a/health-services/project/README.md b/health-services/project/README.md index 13961132999..89424d22e48 100644 --- a/health-services/project/README.md +++ b/health-services/project/README.md @@ -130,10 +130,6 @@ Project service APIs - contains create, update, delete and search end point - update-project-resource-bulk-topic - delete-project-resource-bulk-topic -- save-adverse-event-bulk-topic -- update-adverse-event-bulk-topic -- delete-adverse-event-bulk-topic - ### Kafka Producers - save-project-staff-topic @@ -156,10 +152,6 @@ Project service APIs - contains create, update, delete and search end point - update-project-resource-topic - delete-project-resource-topic -- save-adverse-event-topic -- update-adverse-event-topic -- delete-adverse-event-topic - ## Pre commit script [commit-msg](https://gist.github.com/jayantp-egov/14f55deb344f1648503c6be7e580fa12) diff --git a/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java b/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java index e6fe7ea8af7..fe9291ab137 100644 --- a/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java +++ b/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java @@ -183,21 +183,4 @@ public class ProjectConfiguration { @Value("${egov.user.id.validator}") private String egovUserIdValidator; - @Value("${project.adverseevent.kafka.create.topic}") - private String createAdverseEventTopic; - - @Value("${project.adverseevent.kafka.update.topic}") - private String updateAdverseEventTopic; - - @Value("${project.adverseevent.kafka.delete.topic}") - private String deleteAdverseEventTopic; - - @Value("${project.adverseevent.consumer.bulk.create.topic}") - private String createAdverseEventBulkTopic; - - @Value("${project.adverseevent.consumer.bulk.update.topic}") - private String updateAdverseEventBulkTopic; - - @Value("${project.adverseevent.consumer.bulk.delete.topic}") - private String deleteAdverseEventBulkTopic; } diff --git a/health-services/project/src/main/resources/application.properties b/health-services/project/src/main/resources/application.properties index 460d24b6554..81fc4cd7f12 100644 --- a/health-services/project/src/main/resources/application.properties +++ b/health-services/project/src/main/resources/application.properties @@ -163,13 +163,3 @@ project.resource.consumer.bulk.delete.topic=delete-project-resource-bulk-topic project.mdms.module=HCM-PROJECT-TYPES egov.location.hierarchy.type=ADMIN - -project.adverseevent.kafka.create.topic=save-adverse-event-topic -project.adverseevent.kafka.update.topic=update-adverse-event-topic -project.adverseevent.kafka.delete.topic=delete-adverse-event-topic - -project.adverseevent.consumer.bulk.create.topic=save-adverse-event-bulk-topic -project.adverseevent.consumer.bulk.update.topic=update-adverse-event-bulk-topic -project.adverseevent.consumer.bulk.delete.topic=delete-adverse-event-bulk-topic - - diff --git a/health-services/project/src/main/resources/db/migration/main/V20230901150100__adverse_event_ref_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20230901150100__adverse_event_ref_ddl.sql deleted file mode 100644 index 92680165b50..00000000000 --- a/health-services/project/src/main/resources/db/migration/main/V20230901150100__adverse_event_ref_ddl.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE ADVERSE_EVENT ALTER COLUMN clientReferenceId SET NOT NULL; -ALTER TABLE ADVERSE_EVENT ALTER COLUMN taskClientReferenceId SET NOT NULL; \ No newline at end of file diff --git a/health-services/project/src/main/resources/db/migration/main/V20230906144900__adverse_event_col_drop_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20230906144900__adverse_event_col_drop_ddl.sql deleted file mode 100644 index c5781bdd32c..00000000000 --- a/health-services/project/src/main/resources/db/migration/main/V20230906144900__adverse_event_col_drop_ddl.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE ADVERSE_EVENT DROP COLUMN IF EXISTS reAttempts; \ No newline at end of file diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java index 5598f4fa526..441a171a63a 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java @@ -1,8 +1,8 @@ package org.egov.referralmanagement; public interface Constants { - String SET_ADVERSE_EVENTS = "setAdverseEvents"; - String GET_ADVERSE_EVENTS = "getAdverseEvents"; + String SET_SIDE_EFFECTS = "setSideEffects"; + String GET_SIDE_EFFECTS = "getSideEffects"; String VALIDATION_ERROR = "VALIDATION_ERROR"; String PROJECT_TYPES = "projectTypes"; String MDMS_RESPONSE = "MdmsRes"; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java index a5d377e8bff..462cc99ce46 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java @@ -15,23 +15,23 @@ @Builder @Component public class ReferralManagementConfiguration { - @Value("${referralmanagement.adverseevent.kafka.create.topic}") - private String createAdverseEventTopic; + @Value("${referralmanagement.sideeffect.kafka.create.topic}") + private String createSideEffectTopic; - @Value("${referralmanagement.adverseevent.kafka.update.topic}") - private String updateAdverseEventTopic; + @Value("${referralmanagement.sideeffect.kafka.update.topic}") + private String updateSideEffectTopic; - @Value("${referralmanagement.adverseevent.kafka.delete.topic}") - private String deleteAdverseEventTopic; + @Value("${referralmanagement.sideeffect.kafka.delete.topic}") + private String deleteSideEffectTopic; - @Value("${referralmanagement.adverseevent.consumer.bulk.create.topic}") - private String createAdverseEventBulkTopic; + @Value("${referralmanagement.sideeffect.consumer.bulk.create.topic}") + private String createSideEffectBulkTopic; - @Value("${referralmanagement.adverseevent.consumer.bulk.update.topic}") - private String updateAdverseEventBulkTopic; + @Value("${referralmanagement.sideeffect.consumer.bulk.update.topic}") + private String updateSideEffectBulkTopic; - @Value("${referralmanagement.adverseevent.consumer.bulk.delete.topic}") - private String deleteAdverseEventBulkTopic; + @Value("${referralmanagement.sideeffect.consumer.bulk.delete.topic}") + private String deleteSideEffectBulkTopic; @Value("${egov.project.host}") private String projectHost; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/AdverseEventConsumer.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/AdverseEventConsumer.java deleted file mode 100644 index e1290be9810..00000000000 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/AdverseEventConsumer.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.egov.referralmanagement.consumer; - -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; -import org.egov.referralmanagement.service.AdverseEventService; -import org.egov.tracer.model.CustomException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -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 AdverseEventConsumer { - - private final AdverseEventService adverseEventService; - - private final ObjectMapper objectMapper; - - @Autowired - public AdverseEventConsumer(AdverseEventService adverseEventService, - @Qualifier("objectMapper") ObjectMapper objectMapper) { - this.adverseEventService = adverseEventService; - this.objectMapper = objectMapper; - } - - @KafkaListener(topics = "${referralmanagement.adverseevent.consumer.bulk.create.topic}") - public void bulkCreate(Map consumerRecord, - @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { - try { - AdverseEventBulkRequest request = objectMapper.convertValue(consumerRecord, AdverseEventBulkRequest.class); - adverseEventService.create(request, true); - } catch (Exception exception) { - log.error("Error in Adverse Event consumer bulk create", exception); - log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); - throw new CustomException("HCM_PROJECT_ADVERSE_EVENT_CREATE", exception.getMessage()); - } - } - - @KafkaListener(topics = "${referralmanagement.adverseevent.consumer.bulk.update.topic}") - public void bulkUpdate(Map consumerRecord, - @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { - try { - AdverseEventBulkRequest request = objectMapper.convertValue(consumerRecord, AdverseEventBulkRequest.class); - adverseEventService.update(request, true); - } catch (Exception exception) { - log.error("Error in Adverse Event consumer bulk update", exception); - log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); - throw new CustomException("HCM_PROJECT_ADVERSE_EVENT_CREATE", exception.getMessage()); - } - } - - @KafkaListener(topics = "${referralmanagement.adverseevent.consumer.bulk.delete.topic}") - public void bulkDelete(Map consumerRecord, - @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { - try { - AdverseEventBulkRequest request = objectMapper.convertValue(consumerRecord, AdverseEventBulkRequest.class); - adverseEventService.delete(request, true); - } catch (Exception exception) { - log.error("Error in Adverse Event consumer bulk delete", exception); - log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); - throw new CustomException("HCM_PROJECT_ADVERSE_EVENT_CREATE", exception.getMessage()); - } - } -} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/SideEffectConsumer.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/SideEffectConsumer.java new file mode 100644 index 00000000000..e1d8204cb06 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/SideEffectConsumer.java @@ -0,0 +1,71 @@ +package org.egov.referralmanagement.consumer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.referralmanagement.service.SideEffectService; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +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 SideEffectConsumer { + + private final SideEffectService sideEffectService; + + private final ObjectMapper objectMapper; + + @Autowired + public SideEffectConsumer(SideEffectService sideEffectService, + @Qualifier("objectMapper") ObjectMapper objectMapper) { + this.sideEffectService = sideEffectService; + this.objectMapper = objectMapper; + } + + @KafkaListener(topics = "${referralmanagement.sideeffect.consumer.bulk.create.topic}") + public void bulkCreate(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + SideEffectBulkRequest request = objectMapper.convertValue(consumerRecord, SideEffectBulkRequest.class); + sideEffectService.create(request, true); + } catch (Exception exception) { + log.error("Error in Side Effect consumer bulk create", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_PROJECT_SIDE_EFFECT_CREATE", exception.getMessage()); + } + } + + @KafkaListener(topics = "${referralmanagement.sideeffect.consumer.bulk.update.topic}") + public void bulkUpdate(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + SideEffectBulkRequest request = objectMapper.convertValue(consumerRecord, SideEffectBulkRequest.class); + sideEffectService.update(request, true); + } catch (Exception exception) { + log.error("Error in Side Effect consumer bulk update", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_PROJECT_SIDE_EFFECT_CREATE", exception.getMessage()); + } + } + + @KafkaListener(topics = "${referralmanagement.sideeffect.consumer.bulk.delete.topic}") + public void bulkDelete(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + SideEffectBulkRequest request = objectMapper.convertValue(consumerRecord, SideEffectBulkRequest.class); + sideEffectService.delete(request, true); + } catch (Exception exception) { + log.error("Error in Side Effect consumer bulk delete", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_PROJECT_SIDE_EFFECT_CREATE", exception.getMessage()); + } + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/AdverseEventRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java similarity index 58% rename from health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/AdverseEventRepository.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java index 5db9f77f424..c3ce7ea000b 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/AdverseEventRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java @@ -6,11 +6,11 @@ import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearch; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearch; import org.egov.common.models.project.Task; import org.egov.common.producer.Producer; -import org.egov.referralmanagement.repository.rowmapper.AdverseEventRowMapper; +import org.egov.referralmanagement.repository.rowmapper.SideEffectRowMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; @@ -26,45 +26,45 @@ @Repository @Slf4j -public class AdverseEventRepository extends GenericRepository { +public class SideEffectRepository extends GenericRepository { @Autowired - private AdverseEventRowMapper rowMapper; + private SideEffectRowMapper rowMapper; @Autowired - protected AdverseEventRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, - RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, - AdverseEventRowMapper rowMapper) { - super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, rowMapper, Optional.of("adverse_event")); + protected SideEffectRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, + RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, + SideEffectRowMapper rowMapper) { + super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, rowMapper, Optional.of("side_effect")); } - public Map> fetchAdverseEvents(List taskList) { + public Map> fetchSideEffects(List taskList) { if (taskList.isEmpty()) { return Collections.emptyMap(); } List taskIds = getIdList(taskList); Map resourceParamsMap = new HashMap<>(); - String resourceQuery = "SELECT * FROM adverse_event ae where ae.taskId IN (:taskIds)"; + String resourceQuery = "SELECT * FROM side_effect ae where ae.taskId IN (:taskIds)"; resourceParamsMap.put("taskIds", taskIds); - List adverseEventList = this.namedParameterJdbcTemplate.query(resourceQuery, resourceParamsMap, + List sideEffectList = this.namedParameterJdbcTemplate.query(resourceQuery, resourceParamsMap, this.rowMapper); - Map> idToObjMap = new HashMap<>(); + Map> idToObjMap = new HashMap<>(); - adverseEventList.forEach(adverseEvent -> { - String taskId = adverseEvent.getTaskId(); + sideEffectList.forEach(sideEffect -> { + String taskId = sideEffect.getTaskId(); if (idToObjMap.containsKey(taskId)) { - idToObjMap.get(taskId).add(adverseEvent); + idToObjMap.get(taskId).add(sideEffect); } else { - List adverseEvents = new ArrayList<>(); - adverseEvents.add(adverseEvent); - idToObjMap.put(taskId, adverseEvents); + List sideEffects = new ArrayList<>(); + sideEffects.add(sideEffect); + idToObjMap.put(taskId, sideEffects); } }); return idToObjMap; } - public List find(AdverseEventSearch searchObject, Integer limit, Integer offset, String tenantId, - Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { - String query = "SELECT * FROM adverse_event ae LEFT JOIN project_task pt ON ae.taskId = pt.id "; + public List find(SideEffectSearch searchObject, Integer limit, Integer offset, String tenantId, + Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { + String query = "SELECT * FROM side_effect ae LEFT JOIN project_task pt ON ae.taskId = pt.id "; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); @@ -86,12 +86,12 @@ public List find(AdverseEventSearch searchObject, Integer limit, I paramsMap.put("lastModifiedTime", lastChangedSince); paramsMap.put("limit", limit); paramsMap.put("offset", offset); - List adverseEventList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); - return adverseEventList; + List sideEffectList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + return sideEffectList; } - public List findById(List ids, String columnName, Boolean includeDeleted) { - List objFound = findInCache(ids).stream() + public List findById(List ids, String columnName, Boolean includeDeleted) { + List objFound = findInCache(ids).stream() .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) .collect(Collectors.toList()); if (!objFound.isEmpty()) { @@ -104,15 +104,15 @@ public List findById(List ids, String columnName, Boolean } } - String query = String.format("SELECT * FROM adverse_event ae LEFT JOIN project_task pt ON ae.taskid = pt.id WHERE ae.%s IN (:ids) ", columnName); + String query = String.format("SELECT * FROM side_effect ae LEFT JOIN project_task pt ON ae.taskid = pt.id WHERE ae.%s IN (:ids) ", columnName); if (includeDeleted == null || !includeDeleted) { query += " AND ae.isDeleted = false "; } Map paramMap = new HashMap<>(); paramMap.put("ids", ids); - List adverseEventList = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + List sideEffectList = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); - objFound.addAll(adverseEventList); + objFound.addAll(sideEffectList); putInCache(objFound); return objFound; } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/AdverseEventRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java similarity index 89% rename from health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/AdverseEventRowMapper.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java index 6dd6ff19472..7a49ceef93e 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/AdverseEventRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; @@ -13,13 +13,13 @@ import java.util.ArrayList; @Component -public class AdverseEventRowMapper implements RowMapper { +public class SideEffectRowMapper implements RowMapper { @Autowired ObjectMapper objectMapper; @Override - public AdverseEvent mapRow(ResultSet resultSet, int i) throws SQLException { + public SideEffect mapRow(ResultSet resultSet, int i) throws SQLException { try { AuditDetails auditDetails = AuditDetails.builder() .createdBy(resultSet.getString("createdBy")) @@ -33,7 +33,7 @@ public AdverseEvent mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) .build(); - return AdverseEvent.builder() + return SideEffect.builder() .id(resultSet.getString("id")) .clientReferenceId(resultSet.getString("clientreferenceid")) .taskId(resultSet.getString("taskId")) diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/AdverseEventService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/AdverseEventService.java deleted file mode 100644 index a67272c4267..00000000000 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/AdverseEventService.java +++ /dev/null @@ -1,237 +0,0 @@ -package org.egov.referralmanagement.service; - -import lombok.extern.slf4j.Slf4j; -import org.egov.referralmanagement.Constants; -import org.egov.referralmanagement.config.ReferralManagementConfiguration; -import org.egov.referralmanagement.repository.AdverseEventRepository; -import org.egov.referralmanagement.service.enrichment.AdverseEventEnrichmentService; -import org.egov.referralmanagement.validator.adverseevent.AdIsDeletedValidator; -import org.egov.referralmanagement.validator.adverseevent.AdNonExistentEntityValidator; -import org.egov.referralmanagement.validator.adverseevent.AdNullIdValidator; -import org.egov.referralmanagement.validator.adverseevent.AdProjectTaskIdValidator; -import org.egov.referralmanagement.validator.adverseevent.AdUniqueEntityValidator; -import org.egov.common.ds.Tuple; -import org.egov.common.models.ErrorDetails; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventRequest; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearchRequest; -import org.egov.common.service.IdGenService; -import org.egov.common.utils.CommonUtils; -import org.egov.common.validator.Validator; -import org.egov.tracer.model.CustomException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.util.ReflectionUtils; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.getIdFieldName; -import static org.egov.common.utils.CommonUtils.getIdMethod; -import static org.egov.common.utils.CommonUtils.handleErrors; -import static org.egov.common.utils.CommonUtils.havingTenantId; -import static org.egov.common.utils.CommonUtils.includeDeleted; -import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; -import static org.egov.common.utils.CommonUtils.lastChangedSince; -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; - -@Service -@Slf4j -public class AdverseEventService { - private final IdGenService idGenService; - - private final AdverseEventRepository adverseEventRepository; - - private final ReferralManagementConfiguration referralManagementConfiguration; - - private final AdverseEventEnrichmentService adverseEventEnrichmentService; - - private final List> validators; - - private final Predicate> isApplicableForCreate = validator -> - validator.getClass().equals(AdProjectTaskIdValidator.class); - - private final Predicate> isApplicableForUpdate = validator -> - validator.getClass().equals(AdProjectTaskIdValidator.class) - || validator.getClass().equals(AdNullIdValidator.class) - || validator.getClass().equals(AdIsDeletedValidator.class) - || validator.getClass().equals(AdUniqueEntityValidator.class) - || validator.getClass().equals(AdNonExistentEntityValidator.class); - - private final Predicate> isApplicableForDelete = validator -> - validator.getClass().equals(AdNullIdValidator.class) - || validator.getClass().equals(AdNonExistentEntityValidator.class); - - @Autowired - public AdverseEventService( - IdGenService idGenService, - AdverseEventRepository adverseEventRepository, - ReferralManagementConfiguration referralManagementConfiguration, - AdverseEventEnrichmentService adverseEventEnrichmentService, - List> validators - ) { - this.idGenService = idGenService; - this.adverseEventRepository = adverseEventRepository; - this.referralManagementConfiguration = referralManagementConfiguration; - this.adverseEventEnrichmentService = adverseEventEnrichmentService; - this.validators = validators; - } - - public AdverseEvent create(AdverseEventRequest request) { - log.info("received request to create adverse events"); - AdverseEventBulkRequest bulkRequest = AdverseEventBulkRequest.builder().requestInfo(request.getRequestInfo()) - .adverseEvents(Collections.singletonList(request.getAdverseEvent())).build(); - log.info("creating bulk request"); - return create(bulkRequest, false).get(0); - } - - public List create(AdverseEventBulkRequest adverseEventRequest, boolean isBulk) { - log.info("received request to create bulk adverse events"); - Tuple, Map> tuple = validate(validators, - isApplicableForCreate, adverseEventRequest, isBulk); - Map errorDetailsMap = tuple.getY(); - List validAdverseEvents = tuple.getX(); - - try { - if (!validAdverseEvents.isEmpty()) { - log.info("processing {} valid entities", validAdverseEvents.size()); - adverseEventEnrichmentService.create(validAdverseEvents, adverseEventRequest); - adverseEventRepository.save(validAdverseEvents, - referralManagementConfiguration.getCreateAdverseEventTopic()); - log.info("successfully created adverse events"); - } - } catch (Exception exception) { - log.error("error occurred while creating adverse events: {}", exception.getMessage()); - populateErrorDetails(adverseEventRequest, errorDetailsMap, validAdverseEvents, - exception, Constants.SET_ADVERSE_EVENTS); - } - handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); - - return validAdverseEvents; - } - - public AdverseEvent update(AdverseEventRequest request) { - log.info("received request to update adverse event"); - AdverseEventBulkRequest bulkRequest = AdverseEventBulkRequest.builder().requestInfo(request.getRequestInfo()) - .adverseEvents(Collections.singletonList(request.getAdverseEvent())).build(); - log.info("creating bulk request"); - return update(bulkRequest, false).get(0); - } - - public List update(AdverseEventBulkRequest adverseEventRequest, boolean isBulk) { - log.info("received request to update bulk adverse event"); - Tuple, Map> tuple = validate(validators, - isApplicableForUpdate, adverseEventRequest, isBulk); - Map errorDetailsMap = tuple.getY(); - List validAdverseEvents = tuple.getX(); - - try { - if (!validAdverseEvents.isEmpty()) { - log.info("processing {} valid entities", validAdverseEvents.size()); - adverseEventEnrichmentService.update(validAdverseEvents, adverseEventRequest); - adverseEventRepository.save(validAdverseEvents, - referralManagementConfiguration.getUpdateAdverseEventTopic()); - log.info("successfully updated bulk adverse events"); - } - } catch (Exception exception) { - log.error("error occurred while updating adverse events", exception); - populateErrorDetails(adverseEventRequest, errorDetailsMap, validAdverseEvents, - exception, Constants.SET_ADVERSE_EVENTS); - } - handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); - - return validAdverseEvents; - } - - public List search(AdverseEventSearchRequest adverseEventSearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { - log.info("received request to search adverse events"); - String idFieldName = getIdFieldName(adverseEventSearchRequest.getAdverseEvent()); - if (isSearchByIdOnly(adverseEventSearchRequest.getAdverseEvent(), idFieldName)) { - log.info("searching adverse events by id"); - List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections - .singletonList(adverseEventSearchRequest.getAdverseEvent())), - adverseEventSearchRequest.getAdverseEvent()); - log.info("fetching adverse events with ids: {}", ids); - return adverseEventRepository.findById(ids, includeDeleted, idFieldName).stream() - .filter(lastChangedSince(lastChangedSince)) - .filter(havingTenantId(tenantId)) - .filter(includeDeleted(includeDeleted)) - .collect(Collectors.toList()); - } - log.info("searching adverse events using criteria"); - return adverseEventRepository.find(adverseEventSearchRequest.getAdverseEvent(), - limit, offset, tenantId, lastChangedSince, includeDeleted); - } - - public AdverseEvent delete(AdverseEventRequest adverseEventRequest) { - log.info("received request to delete a adverse event"); - AdverseEventBulkRequest bulkRequest = AdverseEventBulkRequest.builder().requestInfo(adverseEventRequest.getRequestInfo()) - .adverseEvents(Collections.singletonList(adverseEventRequest.getAdverseEvent())).build(); - log.info("creating bulk request"); - return delete(bulkRequest, false).get(0); - } - - public List delete(AdverseEventBulkRequest adverseEventRequest, boolean isBulk) { - Tuple, Map> tuple = validate(validators, - isApplicableForDelete, adverseEventRequest, isBulk); - Map errorDetailsMap = tuple.getY(); - List validAdverseEvents = tuple.getX(); - - try { - if (!validAdverseEvents.isEmpty()) { - log.info("processing {} valid entities", validAdverseEvents.size()); - List adverseEventIds = validAdverseEvents.stream().map(entity -> entity.getId()).collect(Collectors.toSet()).stream().collect(Collectors.toList()); - List existingAdverseEvents = adverseEventRepository - .findById(adverseEventIds, false); - adverseEventEnrichmentService.delete(existingAdverseEvents, adverseEventRequest); - adverseEventRepository.save(existingAdverseEvents, - referralManagementConfiguration.getDeleteAdverseEventTopic()); - log.info("successfully deleted entities"); - } - } catch (Exception exception) { - log.error("error occurred while deleting entities: {}", exception); - populateErrorDetails(adverseEventRequest, errorDetailsMap, validAdverseEvents, - exception, Constants.SET_ADVERSE_EVENTS); - } - handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); - - return validAdverseEvents; - } - - public void putInCache(List adverseEvents) { - log.info("putting {} adverse events in cache", adverseEvents.size()); - adverseEventRepository.putInCache(adverseEvents); - log.info("successfully put adverse events in cache"); - } - - private Tuple, Map> validate( - List> validators, - Predicate> isApplicable, - AdverseEventBulkRequest request, - boolean isBulk - ) { - log.info("validating request"); - Map errorDetailsMap = CommonUtils.validate(validators, - isApplicable, request, - Constants.SET_ADVERSE_EVENTS); - if (!errorDetailsMap.isEmpty() && !isBulk) { - log.error("validation error occurred. error details: {}", errorDetailsMap.values().toString()); - throw new CustomException(Constants.VALIDATION_ERROR, errorDetailsMap.values().toString()); - } - List validAdverseEvents = request.getAdverseEvents().stream() - .filter(notHavingErrors()).collect(Collectors.toList()); - log.info("validation successful, found valid adverse events"); - return new Tuple<>(validAdverseEvents, errorDetailsMap); - } - -} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java new file mode 100644 index 00000000000..8f8d63d9ed0 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java @@ -0,0 +1,237 @@ +package org.egov.referralmanagement.service; + +import lombok.extern.slf4j.Slf4j; +import org.egov.referralmanagement.Constants; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.repository.SideEffectRepository; +import org.egov.referralmanagement.service.enrichment.SideEffectEnrichmentService; +import org.egov.referralmanagement.validator.sideeffect.SeIsDeletedValidator; +import org.egov.referralmanagement.validator.sideeffect.SeNonExistentEntityValidator; +import org.egov.referralmanagement.validator.sideeffect.SeNullIdValidator; +import org.egov.referralmanagement.validator.sideeffect.SeProjectTaskIdValidator; +import org.egov.referralmanagement.validator.sideeffect.SeUniqueEntityValidator; +import org.egov.common.ds.Tuple; +import org.egov.common.models.ErrorDetails; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearchRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.egov.common.validator.Validator; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.ReflectionUtils; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +@Service +@Slf4j +public class SideEffectService { + private final IdGenService idGenService; + + private final SideEffectRepository sideEffectRepository; + + private final ReferralManagementConfiguration referralManagementConfiguration; + + private final SideEffectEnrichmentService sideEffectEnrichmentService; + + private final List> validators; + + private final Predicate> isApplicableForCreate = validator -> + validator.getClass().equals(SeProjectTaskIdValidator.class); + + private final Predicate> isApplicableForUpdate = validator -> + validator.getClass().equals(SeProjectTaskIdValidator.class) + || validator.getClass().equals(SeNullIdValidator.class) + || validator.getClass().equals(SeIsDeletedValidator.class) + || validator.getClass().equals(SeUniqueEntityValidator.class) + || validator.getClass().equals(SeNonExistentEntityValidator.class); + + private final Predicate> isApplicableForDelete = validator -> + validator.getClass().equals(SeNullIdValidator.class) + || validator.getClass().equals(SeNonExistentEntityValidator.class); + + @Autowired + public SideEffectService( + IdGenService idGenService, + SideEffectRepository sideEffectRepository, + ReferralManagementConfiguration referralManagementConfiguration, + SideEffectEnrichmentService sideEffectEnrichmentService, + List> validators + ) { + this.idGenService = idGenService; + this.sideEffectRepository = sideEffectRepository; + this.referralManagementConfiguration = referralManagementConfiguration; + this.sideEffectEnrichmentService = sideEffectEnrichmentService; + this.validators = validators; + } + + public SideEffect create(SideEffectRequest request) { + log.info("received request to create side effects"); + SideEffectBulkRequest bulkRequest = SideEffectBulkRequest.builder().requestInfo(request.getRequestInfo()) + .sideEffects(Collections.singletonList(request.getSideEffect())).build(); + log.info("creating bulk request"); + return create(bulkRequest, false).get(0); + } + + public List create(SideEffectBulkRequest sideEffectRequest, boolean isBulk) { + log.info("received request to create bulk side effects"); + Tuple, Map> tuple = validate(validators, + isApplicableForCreate, sideEffectRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validSideEffects = tuple.getX(); + + try { + if (!validSideEffects.isEmpty()) { + log.info("processing {} valid entities", validSideEffects.size()); + sideEffectEnrichmentService.create(validSideEffects, sideEffectRequest); + sideEffectRepository.save(validSideEffects, + referralManagementConfiguration.getCreateSideEffectTopic()); + log.info("successfully created side effects"); + } + } catch (Exception exception) { + log.error("error occurred while creating side effects: {}", exception.getMessage()); + populateErrorDetails(sideEffectRequest, errorDetailsMap, validSideEffects, + exception, Constants.SET_SIDE_EFFECTS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validSideEffects; + } + + public SideEffect update(SideEffectRequest request) { + log.info("received request to update side effect"); + SideEffectBulkRequest bulkRequest = SideEffectBulkRequest.builder().requestInfo(request.getRequestInfo()) + .sideEffects(Collections.singletonList(request.getSideEffect())).build(); + log.info("creating bulk request"); + return update(bulkRequest, false).get(0); + } + + public List update(SideEffectBulkRequest sideEffectRequest, boolean isBulk) { + log.info("received request to update bulk side effect"); + Tuple, Map> tuple = validate(validators, + isApplicableForUpdate, sideEffectRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validSideEffects = tuple.getX(); + + try { + if (!validSideEffects.isEmpty()) { + log.info("processing {} valid entities", validSideEffects.size()); + sideEffectEnrichmentService.update(validSideEffects, sideEffectRequest); + sideEffectRepository.save(validSideEffects, + referralManagementConfiguration.getUpdateSideEffectTopic()); + log.info("successfully updated bulk side effects"); + } + } catch (Exception exception) { + log.error("error occurred while updating side effects", exception); + populateErrorDetails(sideEffectRequest, errorDetailsMap, validSideEffects, + exception, Constants.SET_SIDE_EFFECTS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validSideEffects; + } + + public List search(SideEffectSearchRequest sideEffectSearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { + log.info("received request to search side effects"); + String idFieldName = getIdFieldName(sideEffectSearchRequest.getSideEffect()); + if (isSearchByIdOnly(sideEffectSearchRequest.getSideEffect(), idFieldName)) { + log.info("searching side effects by id"); + List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections + .singletonList(sideEffectSearchRequest.getSideEffect())), + sideEffectSearchRequest.getSideEffect()); + log.info("fetching side effects with ids: {}", ids); + return sideEffectRepository.findById(ids, includeDeleted, idFieldName).stream() + .filter(lastChangedSince(lastChangedSince)) + .filter(havingTenantId(tenantId)) + .filter(includeDeleted(includeDeleted)) + .collect(Collectors.toList()); + } + log.info("searching side effects using criteria"); + return sideEffectRepository.find(sideEffectSearchRequest.getSideEffect(), + limit, offset, tenantId, lastChangedSince, includeDeleted); + } + + public SideEffect delete(SideEffectRequest sideEffectRequest) { + log.info("received request to delete a side effect"); + SideEffectBulkRequest bulkRequest = SideEffectBulkRequest.builder().requestInfo(sideEffectRequest.getRequestInfo()) + .sideEffects(Collections.singletonList(sideEffectRequest.getSideEffect())).build(); + log.info("creating bulk request"); + return delete(bulkRequest, false).get(0); + } + + public List delete(SideEffectBulkRequest sideEffectRequest, boolean isBulk) { + Tuple, Map> tuple = validate(validators, + isApplicableForDelete, sideEffectRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validSideEffects = tuple.getX(); + + try { + if (!validSideEffects.isEmpty()) { + log.info("processing {} valid entities", validSideEffects.size()); + List sideEffectIds = validSideEffects.stream().map(entity -> entity.getId()).collect(Collectors.toSet()).stream().collect(Collectors.toList()); + List existingSideEffects = sideEffectRepository + .findById(sideEffectIds, false); + sideEffectEnrichmentService.delete(existingSideEffects, sideEffectRequest); + sideEffectRepository.save(existingSideEffects, + referralManagementConfiguration.getDeleteSideEffectTopic()); + log.info("successfully deleted entities"); + } + } catch (Exception exception) { + log.error("error occurred while deleting entities: {}", exception); + populateErrorDetails(sideEffectRequest, errorDetailsMap, validSideEffects, + exception, Constants.SET_SIDE_EFFECTS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validSideEffects; + } + + public void putInCache(List sideEffects) { + log.info("putting {} side effects in cache", sideEffects.size()); + sideEffectRepository.putInCache(sideEffects); + log.info("successfully put side effects in cache"); + } + + private Tuple, Map> validate( + List> validators, + Predicate> isApplicable, + SideEffectBulkRequest request, + boolean isBulk + ) { + log.info("validating request"); + Map errorDetailsMap = CommonUtils.validate(validators, + isApplicable, request, + Constants.SET_SIDE_EFFECTS); + if (!errorDetailsMap.isEmpty() && !isBulk) { + log.error("validation error occurred. error details: {}", errorDetailsMap.values().toString()); + throw new CustomException(Constants.VALIDATION_ERROR, errorDetailsMap.values().toString()); + } + List validSideEffects = request.getSideEffects().stream() + .filter(notHavingErrors()).collect(Collectors.toList()); + log.info("validation successful, found valid side effects"); + return new Tuple<>(validSideEffects, errorDetailsMap); + } + +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/AdverseEventEnrichmentService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/AdverseEventEnrichmentService.java deleted file mode 100644 index f8a28ddc0a6..00000000000 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/AdverseEventEnrichmentService.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.egov.referralmanagement.service.enrichment; - -import lombok.extern.slf4j.Slf4j; -import org.egov.referralmanagement.config.ReferralManagementConfiguration; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; -import org.egov.common.service.IdGenService; -import org.egov.common.utils.CommonUtils; -import org.egov.referralmanagement.repository.AdverseEventRepository; -import org.springframework.stereotype.Component; - -import java.util.List; -import java.util.Map; - -import static org.egov.common.utils.CommonUtils.*; - -@Component -@Slf4j -public class AdverseEventEnrichmentService { - - private final IdGenService idGenService; - - private final ReferralManagementConfiguration referralManagementConfiguration; - - private final AdverseEventRepository adverseEventRepository; - - public AdverseEventEnrichmentService(IdGenService idGenService, ReferralManagementConfiguration referralManagementConfiguration, AdverseEventRepository adverseEventRepository) { - this.idGenService = idGenService; - this.referralManagementConfiguration = referralManagementConfiguration; - this.adverseEventRepository = adverseEventRepository; - } - - public void create(List entities, AdverseEventBulkRequest request) throws Exception { - log.info("starting the enrichment for create adverse event"); - log.info("generating IDs using UUID"); - List idList = CommonUtils.uuidSupplier().apply(entities.size()); - log.info("enriching adverse events with generated IDs"); - enrichForCreate(entities, idList, request.getRequestInfo()); - log.info("enrichment done"); - } - - public void update(List entities, AdverseEventBulkRequest request) { - log.info("starting the enrichment for create adverse event"); - Map adverseEventMap = getIdToObjMap(entities); - enrichForUpdate(adverseEventMap, entities, request); - log.info("enrichment done"); - } - - public void delete(List entities, AdverseEventBulkRequest request) { - log.info("starting the enrichment for delete adverse event"); - enrichForDelete(entities, request.getRequestInfo(), true); - log.info("enrichment done"); - } -} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/SideEffectEnrichmentService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/SideEffectEnrichmentService.java new file mode 100644 index 00000000000..d86132e06a3 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/SideEffectEnrichmentService.java @@ -0,0 +1,54 @@ +package org.egov.referralmanagement.service.enrichment; + +import lombok.extern.slf4j.Slf4j; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.egov.referralmanagement.repository.SideEffectRepository; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +import static org.egov.common.utils.CommonUtils.*; + +@Component +@Slf4j +public class SideEffectEnrichmentService { + + private final IdGenService idGenService; + + private final ReferralManagementConfiguration referralManagementConfiguration; + + private final SideEffectRepository sideEffectRepository; + + public SideEffectEnrichmentService(IdGenService idGenService, ReferralManagementConfiguration referralManagementConfiguration, SideEffectRepository sideEffectRepository) { + this.idGenService = idGenService; + this.referralManagementConfiguration = referralManagementConfiguration; + this.sideEffectRepository = sideEffectRepository; + } + + public void create(List entities, SideEffectBulkRequest request) throws Exception { + log.info("starting the enrichment for create side effect"); + log.info("generating IDs using UUID"); + List idList = CommonUtils.uuidSupplier().apply(entities.size()); + log.info("enriching side effects with generated IDs"); + enrichForCreate(entities, idList, request.getRequestInfo()); + log.info("enrichment done"); + } + + public void update(List entities, SideEffectBulkRequest request) { + log.info("starting the enrichment for create side effect"); + Map sideEffectMap = getIdToObjMap(entities); + enrichForUpdate(sideEffectMap, entities, request); + log.info("enrichment done"); + } + + public void delete(List entities, SideEffectBulkRequest request) { + log.info("starting the enrichment for delete side effect"); + enrichForDelete(entities, request.getRequestInfo(), true); + log.info("enrichment done"); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNullIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNullIdValidator.java deleted file mode 100644 index f051349ee82..00000000000 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNullIdValidator.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.egov.referralmanagement.validator.adverseevent; - -import lombok.extern.slf4j.Slf4j; -import org.egov.common.models.Error; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; -import org.egov.common.validator.Validator; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import java.util.List; -import java.util.Map; - -import static org.egov.referralmanagement.Constants.GET_ADVERSE_EVENTS; -import static org.egov.common.utils.CommonUtils.validateForNullId; - - -@Component -@Order(value = 1) -@Slf4j -public class AdNullIdValidator implements Validator { - @Override - public Map> validate(AdverseEventBulkRequest request) { - log.info("validating for null id"); - return validateForNullId(request, GET_ADVERSE_EVENTS); - } -} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdIsDeletedValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeIsDeletedValidator.java similarity index 51% rename from health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdIsDeletedValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeIsDeletedValidator.java index b4ae9c3c17d..b6e4d3f94f3 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdIsDeletedValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeIsDeletedValidator.java @@ -1,9 +1,9 @@ -package org.egov.referralmanagement.validator.adverseevent; +package org.egov.referralmanagement.validator.sideeffect; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -18,14 +18,14 @@ @Component @Order(2) @Slf4j -public class AdIsDeletedValidator implements Validator { +public class SeIsDeletedValidator implements Validator { @Override - public Map> validate(AdverseEventBulkRequest request) { + public Map> validate(SideEffectBulkRequest request) { log.info("validating isDeleted field"); - HashMap> errorDetailsMap = new HashMap<>(); - List validIndividuals = request.getAdverseEvents(); - validIndividuals.stream().filter(AdverseEvent::getIsDeleted).forEach(individual -> { + HashMap> errorDetailsMap = new HashMap<>(); + List validIndividuals = request.getSideEffects(); + validIndividuals.stream().filter(SideEffect::getIsDeleted).forEach(individual -> { Error error = getErrorForIsDelete(); populateErrorDetails(individual, error, errorDetailsMap); }); diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNonExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNonExistentEntityValidator.java similarity index 51% rename from health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNonExistentEntityValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNonExistentEntityValidator.java index 8fea8a00e6e..5f70cd0fef5 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNonExistentEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNonExistentEntityValidator.java @@ -1,11 +1,11 @@ -package org.egov.referralmanagement.validator.adverseevent; +package org.egov.referralmanagement.validator.sideeffect; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; -import org.egov.referralmanagement.repository.AdverseEventRepository; +import org.egov.referralmanagement.repository.SideEffectRepository; import org.egov.common.models.Error; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; import org.egov.common.validator.Validator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; @@ -31,37 +31,37 @@ @Component @Order(value = 4) @Slf4j -public class AdNonExistentEntityValidator implements Validator { +public class SeNonExistentEntityValidator implements Validator { - private final AdverseEventRepository adverseEventRepository; + private final SideEffectRepository sideEffectRepository; private final ObjectMapper objectMapper; @Autowired - public AdNonExistentEntityValidator(AdverseEventRepository adverseEventRepository, ObjectMapper objectMapper) { - this.adverseEventRepository = adverseEventRepository; + public SeNonExistentEntityValidator(SideEffectRepository sideEffectRepository, ObjectMapper objectMapper) { + this.sideEffectRepository = sideEffectRepository; this.objectMapper = objectMapper; } @Override - public Map> validate(AdverseEventBulkRequest request) { + public Map> validate(SideEffectBulkRequest request) { log.info("validating for existence of entity"); - Map> errorDetailsMap = new HashMap<>(); - List adverseEvents = request.getAdverseEvents(); - Class objClass = getObjClass(adverseEvents); + Map> errorDetailsMap = new HashMap<>(); + List sideEffects = request.getSideEffects(); + Class objClass = getObjClass(sideEffects); Method idMethod = getMethod(GET_ID, objClass); - Map iMap = getIdToObjMap(adverseEvents + Map iMap = getIdToObjMap(sideEffects .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); if (!iMap.isEmpty()) { - List adverseEventIds = new ArrayList<>(iMap.keySet()); - List existingAdverseEvents = adverseEventRepository - .findById(adverseEventIds, false, getIdFieldName(idMethod)); - List nonExistentIndividuals = checkNonExistentEntities(iMap, - existingAdverseEvents, idMethod); - nonExistentIndividuals.forEach(adverseEvent -> { + List sideEffectIds = new ArrayList<>(iMap.keySet()); + List existingSideEffects = sideEffectRepository + .findById(sideEffectIds, false, getIdFieldName(idMethod)); + List nonExistentIndividuals = checkNonExistentEntities(iMap, + existingSideEffects, idMethod); + nonExistentIndividuals.forEach(sideEffect -> { Error error = getErrorForNonExistentEntity(); - populateErrorDetails(adverseEvent, error, errorDetailsMap); + populateErrorDetails(sideEffect, error, errorDetailsMap); }); } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNullIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNullIdValidator.java new file mode 100644 index 00000000000..f27f88830c4 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNullIdValidator.java @@ -0,0 +1,27 @@ +package org.egov.referralmanagement.validator.sideeffect; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +import static org.egov.referralmanagement.Constants.GET_SIDE_EFFECTS; +import static org.egov.common.utils.CommonUtils.validateForNullId; + + +@Component +@Order(value = 1) +@Slf4j +public class SeNullIdValidator implements Validator { + @Override + public Map> validate(SideEffectBulkRequest request) { + log.info("validating for null id"); + return validateForNullId(request, GET_SIDE_EFFECTS); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdProjectTaskIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java similarity index 81% rename from health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdProjectTaskIdValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java index 90cb6639da4..4d1b2609c26 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdProjectTaskIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java @@ -1,4 +1,4 @@ -package org.egov.referralmanagement.validator.adverseevent; +package org.egov.referralmanagement.validator.sideeffect; import lombok.extern.slf4j.Slf4j; import org.egov.referralmanagement.config.ReferralManagementConfiguration; @@ -13,8 +13,8 @@ import org.egov.common.models.project.TaskBulkResponse; import org.egov.common.models.project.TaskSearch; import org.egov.common.models.project.TaskSearchRequest; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; import org.egov.common.validator.Validator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; @@ -36,27 +36,27 @@ @Component @Order(value = 3) @Slf4j -public class AdProjectTaskIdValidator implements Validator { +public class SeProjectTaskIdValidator implements Validator { private final ServiceRequestClient serviceRequestClient; private final ReferralManagementConfiguration referralManagementConfiguration; @Autowired - public AdProjectTaskIdValidator(ServiceRequestClient serviceRequestClient, ReferralManagementConfiguration referralManagementConfiguration) { + public SeProjectTaskIdValidator(ServiceRequestClient serviceRequestClient, ReferralManagementConfiguration referralManagementConfiguration) { this.serviceRequestClient = serviceRequestClient; this.referralManagementConfiguration = referralManagementConfiguration; } @Override - public Map> validate(AdverseEventBulkRequest request) { + public Map> validate(SideEffectBulkRequest request) { log.info("validating project task id"); - Map> errorDetailsMap = new HashMap<>(); - List entities = request.getAdverseEvents(); - Map> tenantIdAdverseEventMap = entities.stream().collect(Collectors.groupingBy(AdverseEvent::getTenantId)); - List tenantIds = new ArrayList<>(tenantIdAdverseEventMap.keySet()); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getSideEffects(); + Map> tenantIdSideEffectMap = entities.stream().collect(Collectors.groupingBy(SideEffect::getTenantId)); + List tenantIds = new ArrayList<>(tenantIdSideEffectMap.keySet()); tenantIds.forEach(tenantId -> { - List adverseEventList = tenantIdAdverseEventMap.get(tenantId); - if (!adverseEventList.isEmpty()) { + List sideEffectList = tenantIdSideEffectMap.get(tenantId); + if (!sideEffectList.isEmpty()) { List existingTasks = null; List existingProjectBeneficiaries = null; final List projectBeneficiaryIdList = new ArrayList<>(); @@ -64,11 +64,11 @@ public Map> validate(AdverseEventBulkRequest request) final List taskIdList = new ArrayList<>(); final List taskClientReferenceIdList = new ArrayList<>(); try { - adverseEventList.forEach(adverseEvent -> { - addIgnoreNull(projectBeneficiaryIdList, adverseEvent.getProjectBeneficiaryId()); - addIgnoreNull(projectBeneficiaryClientReferenceIdList, adverseEvent.getProjectBeneficiaryClientReferenceId()); - addIgnoreNull(taskIdList, adverseEvent.getTaskId()); - addIgnoreNull(taskClientReferenceIdList, adverseEvent.getTaskClientReferenceId()); + sideEffectList.forEach(sideEffect -> { + addIgnoreNull(projectBeneficiaryIdList, sideEffect.getProjectBeneficiaryId()); + addIgnoreNull(projectBeneficiaryClientReferenceIdList, sideEffect.getProjectBeneficiaryClientReferenceId()); + addIgnoreNull(taskIdList, sideEffect.getTaskId()); + addIgnoreNull(taskClientReferenceIdList, sideEffect.getTaskClientReferenceId()); }); TaskSearch taskSearch = TaskSearch.builder() .id(taskIdList.isEmpty() ? null : taskIdList) @@ -109,15 +109,15 @@ public Map> validate(AdverseEventBulkRequest request) }); final List existingProjectTaskIds = existingTasks.stream().map(Task::getId).collect(Collectors.toList()); final List existingProjectReferenceTaskIds = existingTasks.stream().map(Task::getClientReferenceId).collect(Collectors.toList()); - List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> !existingProjectTaskIds.contains(entity.getTaskId()) && !existingProjectReferenceTaskIds.contains(entity.getTaskClientReferenceId()) && !existingProjectBeneficiaryIds.contains(entity.getProjectBeneficiaryId()) && !existingProjectBeneficiaryClientReferenceIds.contains(entity.getProjectBeneficiaryClientReferenceId()) ).collect(Collectors.toList()); - invalidEntities.forEach(adverseEvent -> { + invalidEntities.forEach(sideEffect -> { Error error = getErrorForNonExistentEntity(); - populateErrorDetails(adverseEvent, error, errorDetailsMap); + populateErrorDetails(sideEffect, error, errorDetailsMap); }); } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdUniqueEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java similarity index 66% rename from health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdUniqueEntityValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java index 8e06b42a9a2..43f99f7cef2 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdUniqueEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java @@ -1,9 +1,9 @@ -package org.egov.referralmanagement.validator.adverseevent; +package org.egov.referralmanagement.validator.sideeffect; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -19,16 +19,16 @@ @Component @Order(value = 2) @Slf4j -public class AdUniqueEntityValidator implements Validator { +public class SeUniqueEntityValidator implements Validator { @Override - public Map> validate(AdverseEventBulkRequest request) { + public Map> validate(SideEffectBulkRequest request) { log.info("validating unique entity"); - Map> errorDetailsMap = new HashMap<>(); - List validEntities = request.getAdverseEvents() + Map> errorDetailsMap = new HashMap<>(); + List validEntities = request.getSideEffects() .stream().filter(notHavingErrors()).collect(Collectors.toList()); if (!validEntities.isEmpty()) { - Map eMap = getIdToObjMap(validEntities); + Map eMap = getIdToObjMap(validEntities); if (eMap.keySet().size() != validEntities.size()) { List duplicates = eMap.keySet().stream().filter(id -> validEntities.stream() diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/AdverseEventApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/AdverseEventApiController.java deleted file mode 100644 index d7409965f65..00000000000 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/AdverseEventApiController.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.egov.referralmanagement.web.controllers; - -import io.swagger.annotations.ApiParam; -import org.egov.referralmanagement.config.ReferralManagementConfiguration; -import org.egov.referralmanagement.service.AdverseEventService; -import org.egov.common.contract.response.ResponseInfo; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkResponse; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventRequest; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventResponse; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearchRequest; -import org.egov.common.producer.Producer; -import org.egov.common.utils.ResponseInfoFactory; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; - -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import java.util.List; - -@Controller -@RequestMapping("/adverse_event") -@Validated -public class AdverseEventApiController { - - private final HttpServletRequest httpServletRequest; - - private final AdverseEventService adverseEventService; - - private final Producer producer; - - private final ReferralManagementConfiguration referralManagementConfiguration; - - public AdverseEventApiController( - HttpServletRequest httpServletRequest, - AdverseEventService adverseEventService, - Producer producer, - ReferralManagementConfiguration referralManagementConfiguration - ) { - this.httpServletRequest = httpServletRequest; - this.adverseEventService = adverseEventService; - this.producer = producer; - this.referralManagementConfiguration = referralManagementConfiguration; - } - - @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) - public ResponseEntity adverseEventV1CreatePost(@ApiParam(value = "Capture details of Adverse Event", required = true) @Valid @RequestBody AdverseEventRequest request) { - - AdverseEvent adverseEvent = adverseEventService.create(request); - AdverseEventResponse response = AdverseEventResponse.builder() - .adverseEvent(adverseEvent) - .responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)) - .build(); - - return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); - } - - - - @RequestMapping(value = "/v1/bulk/_create", method = RequestMethod.POST) - public ResponseEntity adverseEventBulkV1CreatePost(@ApiParam(value = "Capture details of Adverse Event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { - request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); - adverseEventService.putInCache(request.getAdverseEvents()); - producer.push(referralManagementConfiguration.getCreateAdverseEventBulkTopic(), request); - - return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)); - } - - @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) - public ResponseEntity adverseEventV1SearchPost(@ApiParam(value = "Adverse Event Search.", required = true) @Valid @RequestBody AdverseEventSearchRequest request, - @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, - @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, - @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, - @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, - @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { - - List adverseEvents = adverseEventService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); - AdverseEventBulkResponse response = AdverseEventBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).adverseEvents(adverseEvents).build(); - - return ResponseEntity.status(HttpStatus.OK).body(response); - } - - @RequestMapping(value = "/v1/_update", method = RequestMethod.POST) - public ResponseEntity adverseEventV1UpdatePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventRequest request) { - AdverseEvent adverseEvent = adverseEventService.update(request); - - AdverseEventResponse response = AdverseEventResponse.builder() - .adverseEvent(adverseEvent) - .responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)) - .build(); - - return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); - - } - - @RequestMapping(value = "/v1/bulk/_update", method = RequestMethod.POST) - public ResponseEntity adverseEventV1BulkUpdatePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { - request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); - producer.push(referralManagementConfiguration.getUpdateAdverseEventBulkTopic(), request); - - return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)); - } - - @RequestMapping(value = "/v1/_delete", method = RequestMethod.POST) - public ResponseEntity adverseEventV1DeletePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventRequest request) { - AdverseEvent adverseEvent = adverseEventService.delete(request); - - AdverseEventResponse response = AdverseEventResponse.builder() - .adverseEvent(adverseEvent) - .responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)) - .build(); - - return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); - - } - - @RequestMapping(value = "/v1/bulk/_delete", method = RequestMethod.POST) - public ResponseEntity adverseEventV1BulkDeletePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { - request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); - producer.push(referralManagementConfiguration.getDeleteAdverseEventBulkTopic(), request); - - return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)); - } -} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/SideEffectApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/SideEffectApiController.java new file mode 100644 index 00000000000..09c2b4c7b18 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/SideEffectApiController.java @@ -0,0 +1,141 @@ +package org.egov.referralmanagement.web.controllers; + +import io.swagger.annotations.ApiParam; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.service.SideEffectService; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkResponse; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectResponse; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearchRequest; +import org.egov.common.producer.Producer; +import org.egov.common.utils.ResponseInfoFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Controller +@RequestMapping("/side_effect") +@Validated +public class SideEffectApiController { + + private final HttpServletRequest httpServletRequest; + + private final SideEffectService sideEffectService; + + private final Producer producer; + + private final ReferralManagementConfiguration referralManagementConfiguration; + + public SideEffectApiController( + HttpServletRequest httpServletRequest, + SideEffectService sideEffectService, + Producer producer, + ReferralManagementConfiguration referralManagementConfiguration + ) { + this.httpServletRequest = httpServletRequest; + this.sideEffectService = sideEffectService; + this.producer = producer; + this.referralManagementConfiguration = referralManagementConfiguration; + } + + @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) + public ResponseEntity sideEffectV1CreatePost(@ApiParam(value = "Capture details of Side Effect", required = true) @Valid @RequestBody SideEffectRequest request) { + + SideEffect sideEffect = sideEffectService.create(request); + SideEffectResponse response = SideEffectResponse.builder() + .sideEffect(sideEffect) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } + + + + @RequestMapping(value = "/v1/bulk/_create", method = RequestMethod.POST) + public ResponseEntity sideEffectBulkV1CreatePost(@ApiParam(value = "Capture details of Side Effect", required = true) @Valid @RequestBody SideEffectBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + sideEffectService.putInCache(request.getSideEffects()); + producer.push(referralManagementConfiguration.getCreateSideEffectBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + + @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) + public ResponseEntity sideEffectV1SearchPost(@ApiParam(value = "Side Effect Search.", required = true) @Valid @RequestBody SideEffectSearchRequest request, + @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, + @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, + @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, + @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, + @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { + + List sideEffects = sideEffectService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); + SideEffectBulkResponse response = SideEffectBulkResponse.builder().responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)).sideEffects(sideEffects).build(); + + return ResponseEntity.status(HttpStatus.OK).body(response); + } + + @RequestMapping(value = "/v1/_update", method = RequestMethod.POST) + public ResponseEntity sideEffectV1UpdatePost(@ApiParam(value = "Capture details of Existing side effect", required = true) @Valid @RequestBody SideEffectRequest request) { + SideEffect sideEffect = sideEffectService.update(request); + + SideEffectResponse response = SideEffectResponse.builder() + .sideEffect(sideEffect) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + + } + + @RequestMapping(value = "/v1/bulk/_update", method = RequestMethod.POST) + public ResponseEntity sideEffectV1BulkUpdatePost(@ApiParam(value = "Capture details of Existing side effect", required = true) @Valid @RequestBody SideEffectBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + producer.push(referralManagementConfiguration.getUpdateSideEffectBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + + @RequestMapping(value = "/v1/_delete", method = RequestMethod.POST) + public ResponseEntity sideEffectV1DeletePost(@ApiParam(value = "Capture details of Existing side effect", required = true) @Valid @RequestBody SideEffectRequest request) { + SideEffect sideEffect = sideEffectService.delete(request); + + SideEffectResponse response = SideEffectResponse.builder() + .sideEffect(sideEffect) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + + } + + @RequestMapping(value = "/v1/bulk/_delete", method = RequestMethod.POST) + public ResponseEntity sideEffectV1BulkDeletePost(@ApiParam(value = "Capture details of Existing side effect", required = true) @Valid @RequestBody SideEffectBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + producer.push(referralManagementConfiguration.getDeleteSideEffectBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } +} diff --git a/health-services/referralmanagement/src/main/resources/application.properties b/health-services/referralmanagement/src/main/resources/application.properties index 4beef1d24b0..52d9a8ca439 100644 --- a/health-services/referralmanagement/src/main/resources/application.properties +++ b/health-services/referralmanagement/src/main/resources/application.properties @@ -55,7 +55,7 @@ kafka.producer.config.buffer_memory_config=33554432 egov.idgen.host=http://localhost:8081/ egov.idgen.path=egov-idgen/id/_generate egov.idgen.integration.enabled=true -referralmanagement.adverseevent.idgen.id.format=referralmanagement.adverseevent.id +referralmanagement.sideeffect.idgen.id.format=referralmanagement.sideeffect.id referralmanagement.referral.idgen.id.format=referralmanagement.referral.id idgen.project.beneficiary.id.format=project.beneficiary.id project.staff.idgen.id.format=project.staff.id @@ -99,13 +99,13 @@ egov.search.project.beneficiary.url=/project/beneficiary/v1/_search # ADRM KAFKA CONFIG -referralmanagement.adverseevent.kafka.create.topic=save-adverse-event-topic -referralmanagement.adverseevent.kafka.update.topic=update-adverse-event-topic -referralmanagement.adverseevent.kafka.delete.topic=delete-adverse-event-topic +referralmanagement.sideeffect.kafka.create.topic=save-side-effect-topic +referralmanagement.sideeffect.kafka.update.topic=update-side-effect-topic +referralmanagement.sideeffect.kafka.delete.topic=delete-side-effect-topic -referralmanagement.adverseevent.consumer.bulk.create.topic=save-adverse-event-bulk-topic -referralmanagement.adverseevent.consumer.bulk.update.topic=update-adverse-event-bulk-topic -referralmanagement.adverseevent.consumer.bulk.delete.topic=delete-adverse-event-bulk-topic +referralmanagement.sideeffect.consumer.bulk.create.topic=save-side-effect-bulk-topic +referralmanagement.sideeffect.consumer.bulk.update.topic=update-side-effect-bulk-topic +referralmanagement.sideeffect.consumer.bulk.delete.topic=delete-side-effect-bulk-topic search.api.limit=1000 diff --git a/health-services/project/src/main/resources/db/migration/main/V20230807130400__adverse_event_create_ddl.sql b/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928120100__side_effect_create_ddl.sql similarity index 62% rename from health-services/project/src/main/resources/db/migration/main/V20230807130400__adverse_event_create_ddl.sql rename to health-services/referralmanagement/src/main/resources/db/migration/main/V20230928120100__side_effect_create_ddl.sql index 7102792ecde..215a06217be 100644 --- a/health-services/project/src/main/resources/db/migration/main/V20230807130400__adverse_event_create_ddl.sql +++ b/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928120100__side_effect_create_ddl.sql @@ -1,11 +1,10 @@ -CREATE TABLE ADVERSE_EVENT( +CREATE TABLE SIDE_EFFECT( id character varying(64), - clientReferenceId character varying(64), + clientReferenceId character varying(64) NOT NULL, tenantId character varying(1000), taskId character varying(64), - taskClientReferenceId character varying(64), + taskClientReferenceId character varying(64) NOT NULL, symptoms jsonb, - reAttempts bigint, createdBy character varying(64), createdTime bigint, lastModifiedBy character varying(64), @@ -14,6 +13,6 @@ CREATE TABLE ADVERSE_EVENT( clientLastModifiedTime bigint, rowVersion bigint, isDeleted bool, - CONSTRAINT uk_adverse_event PRIMARY KEY (id), - CONSTRAINT uk_adverse_event_clientReference_id unique (clientReferenceId) -); + CONSTRAINT uk_side_effect PRIMARY KEY (id), + CONSTRAINT uk_side_effect_clientReference_id unique (clientReferenceId) +); \ No newline at end of file diff --git a/health-services/referralmanagement/src/main/resources/referral-management-persister.yml b/health-services/referralmanagement/src/main/resources/referral-management-persister.yml index 49fb3454ed8..936708ec766 100644 --- a/health-services/referralmanagement/src/main/resources/referral-management-persister.yml +++ b/health-services/referralmanagement/src/main/resources/referral-management-persister.yml @@ -2,11 +2,11 @@ serviceMaps: serviceName: referralmanagement mappings: - version: 1.0 - description: Saves a adverse event - fromTopic: save-adverse-event-topic + description: Saves a side effect + fromTopic: save-side-effect-topic isTransaction: true queryMaps: - - query: INSERT INTO ADVERSE_EVENT(id, clientReferenceId, tenantId, taskId, taskClientReferenceId, projectBeneficiaryId, projectBeneficiaryClientReferenceId,symptoms, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedBy, clientCreatedTime, clientLastModifiedBy, clientLastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); + - query: INSERT INTO SIDE_EFFECT(id, clientReferenceId, tenantId, taskId, taskClientReferenceId, projectBeneficiaryId, projectBeneficiaryClientReferenceId,symptoms, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedBy, clientCreatedTime, clientLastModifiedBy, clientLastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); basePath: $.* jsonMaps: - jsonPath: $.*.id @@ -31,11 +31,11 @@ serviceMaps: - jsonPath: $.*.isDeleted - version: 1.0 - description: Updates a adverse event - fromTopic: update-adverse-event-topic + description: Updates a side effect + fromTopic: update-side-effect-topic isTransaction: true queryMaps: - - query: UPDATE ADVERSE_EVENT SET tenantId = ?, taskId = ?, taskClientReferenceId = ?, projectBeneficiaryId = ?, projectBeneficiaryClientReferenceId = ?, symptoms = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + - query: UPDATE SIDE_EFFECT SET tenantId = ?, taskId = ?, taskClientReferenceId = ?, projectBeneficiaryId = ?, projectBeneficiaryClientReferenceId = ?, symptoms = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; basePath: $.* jsonMaps: - jsonPath: $.*.tenantId @@ -55,11 +55,11 @@ serviceMaps: - jsonPath: $.*.id - version: 1.0 - description: Deletes a adverse event - fromTopic: delete-adverse-event-topic + description: Deletes a side effect + fromTopic: delete-side-effect-topic isTransaction: true queryMaps: - - query: UPDATE ADVERSE_EVENT SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + - query: UPDATE SIDE_EFFECT SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; basePath: $.* jsonMaps: - jsonPath: $.*.auditDetails.lastModifiedBy diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventRequestTestBuilder.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventRequestTestBuilder.java deleted file mode 100644 index 983b5dee405..00000000000 --- a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventRequestTestBuilder.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.egov.referralmanagement.helper; - -import org.egov.common.helper.RequestInfoTestBuilder; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventRequest; - -import java.util.ArrayList; - -public class AdverseEventRequestTestBuilder { - private AdverseEventRequest.AdverseEventRequestBuilder builder; - - private ArrayList adverseEvent = new ArrayList(); - - public AdverseEventRequestTestBuilder() { - this.builder = AdverseEventRequest.builder(); - } - - public static AdverseEventRequestTestBuilder builder() { - return new AdverseEventRequestTestBuilder(); - } - - public AdverseEventRequest build() { - return this.builder.build(); - } - - public AdverseEventRequestTestBuilder withOneAdverseEvent() { - builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) - .adverseEvent(AdverseEventTestBuilder.builder().withId().withAuditDetails().build()); - return this; - } - - public AdverseEventRequestTestBuilder withApiOperationNotNullAndNotCreate() { - builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) - .adverseEvent(AdverseEventTestBuilder.builder().withIdNull().build()); - return this; - } - - public AdverseEventRequestTestBuilder withApiOperationNotUpdate() { - builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) - .adverseEvent(AdverseEventTestBuilder.builder().withIdNull().build()); - return this; - } - - public AdverseEventRequestTestBuilder withOneAdverseEventHavingId() { - builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) - .adverseEvent(AdverseEventTestBuilder.builder().withId().withAuditDetails().build()); - return this; - } - - public AdverseEventRequestTestBuilder withBadTenantIdInOneAdverseEvent() { - - builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) - .adverseEvent(AdverseEventTestBuilder.builder().withIdNull().withBadTenantId().build()); - return this; - } - - public AdverseEventRequestTestBuilder withRequestInfo(){ - this.builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()); - return this; - } -} diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectRequestTestBuilder.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectRequestTestBuilder.java new file mode 100644 index 00000000000..d5bf7a9195c --- /dev/null +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectRequestTestBuilder.java @@ -0,0 +1,60 @@ +package org.egov.referralmanagement.helper; + +import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectRequest; + +import java.util.ArrayList; + +public class SideEffectRequestTestBuilder { + private SideEffectRequest.SideEffectRequestBuilder builder; + + private ArrayList sideEffect = new ArrayList(); + + public SideEffectRequestTestBuilder() { + this.builder = SideEffectRequest.builder(); + } + + public static SideEffectRequestTestBuilder builder() { + return new SideEffectRequestTestBuilder(); + } + + public SideEffectRequest build() { + return this.builder.build(); + } + + public SideEffectRequestTestBuilder withOneSideEffect() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .sideEffect(SideEffectTestBuilder.builder().withId().withAuditDetails().build()); + return this; + } + + public SideEffectRequestTestBuilder withApiOperationNotNullAndNotCreate() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .sideEffect(SideEffectTestBuilder.builder().withIdNull().build()); + return this; + } + + public SideEffectRequestTestBuilder withApiOperationNotUpdate() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .sideEffect(SideEffectTestBuilder.builder().withIdNull().build()); + return this; + } + + public SideEffectRequestTestBuilder withOneSideEffectHavingId() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .sideEffect(SideEffectTestBuilder.builder().withId().withAuditDetails().build()); + return this; + } + + public SideEffectRequestTestBuilder withBadTenantIdInOneSideEffect() { + + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .sideEffect(SideEffectTestBuilder.builder().withIdNull().withBadTenantId().build()); + return this; + } + + public SideEffectRequestTestBuilder withRequestInfo(){ + this.builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()); + return this; + } +} diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventTestBuilder.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java similarity index 61% rename from health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventTestBuilder.java rename to health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java index 1af8b9e9d10..d4c3c04c686 100644 --- a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventTestBuilder.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java @@ -1,30 +1,30 @@ package org.egov.referralmanagement.helper; import org.egov.common.helper.AuditDetailsTestBuilder; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import java.util.ArrayList; import java.util.Arrays; -public class AdverseEventTestBuilder { +public class SideEffectTestBuilder { - private AdverseEvent.AdverseEventBuilder builder; + private SideEffect.SideEffectBuilder builder; - public AdverseEventTestBuilder() { - this.builder = AdverseEvent.builder(); + public SideEffectTestBuilder() { + this.builder = SideEffect.builder(); } - public static AdverseEventTestBuilder builder() { - return new AdverseEventTestBuilder(); + public static SideEffectTestBuilder builder() { + return new SideEffectTestBuilder(); } - public AdverseEvent build() { + public SideEffect build() { return this.builder.hasErrors(false).build(); } - public AdverseEventTestBuilder withIdNull() { + public SideEffectTestBuilder withIdNull() { this.builder.taskId("some-task-id") - .clientReferenceId("adverseEventClientReferenceId") + .clientReferenceId("sideEffectClientReferenceId") .id(null) .taskClientReferenceId("null") .symptoms(new ArrayList<>(Arrays.asList("fever"))) @@ -33,28 +33,28 @@ public AdverseEventTestBuilder withIdNull() { return this; } - public AdverseEventTestBuilder withId() { + public SideEffectTestBuilder withId() { withIdNull().builder.id("some-id").taskId("some-task-id") - .clientReferenceId("adverseEventClientReferenceId") + .clientReferenceId("sideEffectClientReferenceId") .taskClientReferenceId("null") .symptoms(new ArrayList<>(Arrays.asList("fever"))) .tenantId("some-tenant-id"); return this; } - public AdverseEventTestBuilder withId(String id) { + public SideEffectTestBuilder withId(String id) { this.builder.id(id); return this; } - public AdverseEventTestBuilder withBadTenantId() { + public SideEffectTestBuilder withBadTenantId() { this.builder.tenantId(null); return this; } - public AdverseEventTestBuilder goodAdverseEvent() { + public SideEffectTestBuilder goodSideEffect() { this.builder.id("some-id").taskId("some-task-id") - .clientReferenceId("adverseEventClientReferenceId") + .clientReferenceId("sideEffectClientReferenceId") .taskClientReferenceId("null") .symptoms(new ArrayList<>(Arrays.asList("fever"))) .tenantId("some-tenant-id") @@ -64,12 +64,12 @@ public AdverseEventTestBuilder goodAdverseEvent() { return this; } - public AdverseEventTestBuilder withAuditDetails() { + public SideEffectTestBuilder withAuditDetails() { this.builder.auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); return this; } - public AdverseEventTestBuilder withDeleted() { + public SideEffectTestBuilder withDeleted() { this.builder.isDeleted(true); return this; } diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/AdverseEventApiControllerTest.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java similarity index 60% rename from health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/AdverseEventApiControllerTest.java rename to health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java index e6a7ad40b98..5acd4f7a594 100644 --- a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/AdverseEventApiControllerTest.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java @@ -3,16 +3,16 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.egov.referralmanagement.TestConfiguration; import org.egov.referralmanagement.config.ReferralManagementConfiguration; -import org.egov.referralmanagement.helper.AdverseEventRequestTestBuilder; -import org.egov.referralmanagement.helper.AdverseEventTestBuilder; -import org.egov.referralmanagement.service.AdverseEventService; +import org.egov.referralmanagement.helper.SideEffectRequestTestBuilder; +import org.egov.referralmanagement.helper.SideEffectTestBuilder; +import org.egov.referralmanagement.service.SideEffectService; import org.egov.common.helper.RequestInfoTestBuilder; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkResponse; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventRequest; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventResponse; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearch; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearchRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkResponse; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectResponse; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearch; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearchRequest; import org.egov.common.producer.Producer; import org.egov.tracer.model.CustomException; import org.egov.tracer.model.ErrorRes; @@ -35,9 +35,9 @@ import java.util.Arrays; import java.util.List; -@WebMvcTest(AdverseEventApiController.class) +@WebMvcTest(SideEffectApiController.class) @Import(TestConfiguration.class) -public class AdverseEventApiControllerTest { +public class SideEffectApiControllerTest { @Autowired private MockMvc mockMvc; @@ -46,7 +46,7 @@ public class AdverseEventApiControllerTest { private ObjectMapper objectMapper; @MockBean - private AdverseEventService adverseEventService; + private SideEffectService sideEffectService; @MockBean private Producer producer; @@ -55,45 +55,45 @@ public class AdverseEventApiControllerTest { ReferralManagementConfiguration referralManagementConfiguration; @Test - @DisplayName("should create adverse event and return with 202 accepted") - void shouldCreateAdverseEventAndReturnWith202Accepted() throws Exception { - AdverseEventRequest request = AdverseEventRequestTestBuilder.builder() - .withOneAdverseEvent() + @DisplayName("should create side effect and return with 202 accepted") + void shouldCreateSideEffectAndReturnWith202Accepted() throws Exception { + SideEffectRequest request = SideEffectRequestTestBuilder.builder() + .withOneSideEffect() .withApiOperationNotUpdate() .build(); - List adverseEvents = getAdverseEvents(); - Mockito.when(adverseEventService.create(ArgumentMatchers.any(AdverseEventRequest.class))).thenReturn(adverseEvents.get(0)); + List sideEffects = getSideEffects(); + Mockito.when(sideEffectService.create(ArgumentMatchers.any(SideEffectRequest.class))).thenReturn(sideEffects.get(0)); - final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/adverse_event/v1/_create") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side_effect/v1/_create") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andExpect(MockMvcResultMatchers.status().isAccepted()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andReturn(); String responseStr = result.getResponse().getContentAsString(); - AdverseEventResponse response = objectMapper.readValue(responseStr, AdverseEventResponse.class); + SideEffectResponse response = objectMapper.readValue(responseStr, SideEffectResponse.class); - Assertions.assertNotNull(response.getAdverseEvent()); - Assertions.assertNotNull(response.getAdverseEvent().getId()); + Assertions.assertNotNull(response.getSideEffect()); + Assertions.assertNotNull(response.getSideEffect().getId()); Assertions.assertEquals("successful", response.getResponseInfo().getStatus()); } - private List getAdverseEvents() { - AdverseEvent adverseEvent = AdverseEventTestBuilder.builder().withId().build(); - List adverseEvents = new ArrayList<>(); - adverseEvents.add(adverseEvent); - return adverseEvents; + private List getSideEffects() { + SideEffect sideEffect = SideEffectTestBuilder.builder().withId().build(); + List sideEffects = new ArrayList<>(); + sideEffects.add(sideEffect); + return sideEffects; } @Test @DisplayName("should send error response with error details with 400 bad request for create") void shouldSendErrorResWithErrorDetailsWith400BadRequestForCreate() throws Exception { - final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/adverse_event/v1/_create") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side_effect/v1/_create") .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(AdverseEventRequestTestBuilder.builder() - .withOneAdverseEvent() - .withBadTenantIdInOneAdverseEvent() + .content(objectMapper.writeValueAsString(SideEffectRequestTestBuilder.builder() + .withOneSideEffect() + .withBadTenantIdInOneSideEffect() .build()))) .andExpect(MockMvcResultMatchers.status().isBadRequest()) .andReturn(); @@ -105,37 +105,37 @@ void shouldSendErrorResWithErrorDetailsWith400BadRequestForCreate() throws Excep } @Test - @DisplayName("should update adverse event and return with 202 accepted") - void shouldUpdateAdverseEventAndReturnWith202Accepted() throws Exception { - AdverseEventRequest request = AdverseEventRequestTestBuilder.builder() - .withOneAdverseEventHavingId() + @DisplayName("should update side effect and return with 202 accepted") + void shouldUpdateSideEffectAndReturnWith202Accepted() throws Exception { + SideEffectRequest request = SideEffectRequestTestBuilder.builder() + .withOneSideEffectHavingId() .withApiOperationNotNullAndNotCreate() .build(); - AdverseEvent adverseEvent = AdverseEventTestBuilder.builder().withId().build(); - Mockito.when(adverseEventService.update(ArgumentMatchers.any(AdverseEventRequest.class))).thenReturn(adverseEvent); + SideEffect sideEffect = SideEffectTestBuilder.builder().withId().build(); + Mockito.when(sideEffectService.update(ArgumentMatchers.any(SideEffectRequest.class))).thenReturn(sideEffect); - final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/adverse_event/v1/_update") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side_effect/v1/_update") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andExpect(MockMvcResultMatchers.status().isAccepted()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andReturn(); String responseStr = result.getResponse().getContentAsString(); - AdverseEventResponse response = objectMapper.readValue(responseStr, AdverseEventResponse.class); + SideEffectResponse response = objectMapper.readValue(responseStr, SideEffectResponse.class); - Assertions.assertNotNull(response.getAdverseEvent()); - Assertions.assertNotNull(response.getAdverseEvent().getId()); + Assertions.assertNotNull(response.getSideEffect()); + Assertions.assertNotNull(response.getSideEffect().getId()); Assertions.assertEquals("successful", response.getResponseInfo().getStatus()); } @Test @DisplayName("should send error response with error details with 400 bad request for update") void shouldSendErrorResWithErrorDetailsWith400BadRequestForUpdate() throws Exception { - final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/adverse_event/v1/_update") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side_effect/v1/_update") .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(AdverseEventRequestTestBuilder.builder() - .withOneAdverseEventHavingId() - .withBadTenantIdInOneAdverseEvent() + .content(objectMapper.writeValueAsString(SideEffectRequestTestBuilder.builder() + .withOneSideEffectHavingId() + .withBadTenantIdInOneSideEffect() .build()))) .andExpect(MockMvcResultMatchers.status().isBadRequest()) .andReturn(); @@ -149,52 +149,52 @@ void shouldSendErrorResWithErrorDetailsWith400BadRequestForUpdate() throws Excep @Test @DisplayName("Should accept search request and return response as accepted") - void shouldAcceptSearchRequestAndReturnAdverseEvent() throws Exception { + void shouldAcceptSearchRequestAndReturnSideEffect() throws Exception { - AdverseEventSearchRequest adverseEventSearchRequest = AdverseEventSearchRequest.builder().adverseEvent( - AdverseEventSearch.builder().taskId("some-task-id").build() + SideEffectSearchRequest sideEffectSearchRequest = SideEffectSearchRequest.builder().sideEffect( + SideEffectSearch.builder().taskId("some-task-id").build() ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); - Mockito.when(adverseEventService.search(ArgumentMatchers.any(AdverseEventSearchRequest.class), + Mockito.when(sideEffectService.search(ArgumentMatchers.any(SideEffectSearchRequest.class), ArgumentMatchers.any(Integer.class), ArgumentMatchers.any(Integer.class), ArgumentMatchers.any(String.class), ArgumentMatchers.any(Long.class), - ArgumentMatchers.any(Boolean.class))).thenReturn(Arrays.asList(AdverseEventTestBuilder.builder().withId().withAuditDetails().build())); + ArgumentMatchers.any(Boolean.class))).thenReturn(Arrays.asList(SideEffectTestBuilder.builder().withId().withAuditDetails().build())); final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post( - "/adverse_event/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") + "/side_effect/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(adverseEventSearchRequest))) + .content(objectMapper.writeValueAsString(sideEffectSearchRequest))) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andReturn(); String responseStr = result.getResponse().getContentAsString(); - AdverseEventBulkResponse response = objectMapper.readValue(responseStr, - AdverseEventBulkResponse.class); + SideEffectBulkResponse response = objectMapper.readValue(responseStr, + SideEffectBulkResponse.class); - Assertions.assertEquals(response.getAdverseEvents().size(), 1); + Assertions.assertEquals(response.getSideEffects().size(), 1); } @Test @DisplayName("Should accept search request and return response as accepted") void shouldThrowExceptionIfNoResultFound() throws Exception { - AdverseEventSearchRequest adverseEventSearchRequest = AdverseEventSearchRequest.builder().adverseEvent( - AdverseEventSearch.builder().taskId("some-task-id").build() + SideEffectSearchRequest sideEffectSearchRequest = SideEffectSearchRequest.builder().sideEffect( + SideEffectSearch.builder().taskId("some-task-id").build() ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); - Mockito.when(adverseEventService.search(ArgumentMatchers.any(AdverseEventSearchRequest.class), + Mockito.when(sideEffectService.search(ArgumentMatchers.any(SideEffectSearchRequest.class), ArgumentMatchers.any(Integer.class), ArgumentMatchers.any(Integer.class), ArgumentMatchers.any(String.class), ArgumentMatchers.any(Long.class), - ArgumentMatchers.any(Boolean.class))).thenThrow(new CustomException("NO_RESULT_FOUND", "No Adverse Event found.")); + ArgumentMatchers.any(Boolean.class))).thenThrow(new CustomException("NO_RESULT_FOUND", "No Side Effect found.")); - final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/adverse_event/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side_effect/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(adverseEventSearchRequest))) + .content(objectMapper.writeValueAsString(sideEffectSearchRequest))) .andExpect(MockMvcResultMatchers.status().isBadRequest()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andReturn(); From 7eb928f93ae6b79711a16c915d471a118e8fc039 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Thu, 28 Sep 2023 14:33:15 +0530 Subject: [PATCH 164/283] HLM-3069: changed servlet context --- .../src/main/resources/application.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/health-services/referralmanagement/src/main/resources/application.properties b/health-services/referralmanagement/src/main/resources/application.properties index 52d9a8ca439..dbd59542d5e 100644 --- a/health-services/referralmanagement/src/main/resources/application.properties +++ b/health-services/referralmanagement/src/main/resources/application.properties @@ -1,4 +1,4 @@ -server.servlet.context-path=/referralmanagement +server.servlet.context-path=/referral-management server.port=8080 app.timezone=UTC @@ -24,7 +24,7 @@ spring.flyway.table=public spring.flyway.baseline-on-migrate=true spring.flyway.outOfOrder=true spring.flyway.locations=classpath:/db/migration/main -spring.flyway.enabled=false +spring.flyway.enabled=true # TRACER CONFIG # KAFKA SERVER CONFIG From cdf8f1a0fb664f50c3259f22a541fac313f385ec Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Thu, 28 Sep 2023 17:53:20 +0530 Subject: [PATCH 165/283] HLM-3069: updated build-config.yml renamed adrm to referralmanagement --- build/build-config.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build/build-config.yml b/build/build-config.yml index f0d399747aa..981c3dd7dff 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -36,13 +36,13 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "health-services/project/src/main/resources/db" image-name: "project-db" - - name: "builds/health-campaign-services/health-services/adrm" + - name: "builds/health-campaign-services/health-services/referralmanagement" build: - - work-dir: "health-services/adrm" - image-name: "adrm" + - work-dir: "health-services/referralmanagement" + image-name: "referralmanagement" dockerfile: "build/maven/Dockerfile" - - work-dir: "health-services/adrm/src/main/resources/db" - image-name: "adrm-db" + - work-dir: "health-services/referralmanagement/src/main/resources/db" + image-name: "referralmanagement-db" - name: "builds/health-campaign-services/health-services/household" build: - work-dir: "health-services/household" From 4569f0d545b67c1ec58363af7dcb6f68556c2540 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Thu, 28 Sep 2023 14:00:18 +0530 Subject: [PATCH 166/283] HLM-3069: adverse event renamed to side effect --- ...management.yml => referral-management.yml} | 0 .../SideEffect.java} | 4 +- .../SideEffectBulkRequest.java} | 12 +- .../SideEffectBulkResponse.java} | 12 +- .../SideEffectRequest.java} | 8 +- .../SideEffectResponse.java} | 8 +- .../SideEffectSearch.java} | 5 +- .../SideEffectSearchRequest.java} | 8 +- health-services/project/README.md | 8 - .../project/config/ProjectConfiguration.java | 17 -- .../src/main/resources/application.properties | 10 - ...V20230901150100__adverse_event_ref_ddl.sql | 2 - ...0906144900__adverse_event_col_drop_ddl.sql | 1 - .../egov/referralmanagement/Constants.java | 4 +- .../ReferralManagementConfiguration.java | 24 +- .../consumer/AdverseEventConsumer.java | 71 ------ .../consumer/SideEffectConsumer.java | 71 ++++++ ...ository.java => SideEffectRepository.java} | 58 ++--- ...owMapper.java => SideEffectRowMapper.java} | 8 +- .../service/SideEffectService.java | 237 ++++++++++++++++++ .../AdverseEventEnrichmentService.java | 54 ---- .../SideEffectEnrichmentService.java | 54 ++++ .../adverseevent/AdNullIdValidator.java | 27 -- .../SeIsDeletedValidator.java} | 16 +- .../SeNonExistentEntityValidator.java} | 40 +-- .../sideeffect/SeNullIdValidator.java | 27 ++ .../SeProjectTaskIdValidator.java} | 40 +-- .../SeUniqueEntityValidator.java} | 16 +- .../AdverseEventApiController.java | 141 ----------- .../controllers/SideEffectApiController.java | 141 +++++++++++ .../src/main/resources/application.properties | 14 +- ...0230928120100__side_effect_create_ddl.sql} | 13 +- .../referral-management-persister.yml | 18 +- .../AdverseEventRequestTestBuilder.java | 60 ----- .../helper/SideEffectRequestTestBuilder.java | 60 +++++ ...uilder.java => SideEffectTestBuilder.java} | 36 +-- ....java => SideEffectApiControllerTest.java} | 122 ++++----- 37 files changed, 822 insertions(+), 625 deletions(-) rename docs/health-api-specs/contracts/{adverse-event-referral-management.yml => referral-management.yml} (100%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/{adverseevent/AdverseEvent.java => sideeffect/SideEffect.java} (95%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/{adverseevent/AdverseEventBulkRequest.java => sideeffect/SideEffectBulkRequest.java} (67%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/{adverseevent/AdverseEventBulkResponse.java => sideeffect/SideEffectBulkResponse.java} (66%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/{adverseevent/AdverseEventRequest.java => sideeffect/SideEffectRequest.java} (76%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/{adverseevent/AdverseEventResponse.java => sideeffect/SideEffectResponse.java} (76%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/{adverseevent/AdverseEventSearch.java => sideeffect/SideEffectSearch.java} (82%) rename health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/{adverseevent/AdverseEventSearchRequest.java => sideeffect/SideEffectSearchRequest.java} (74%) delete mode 100644 health-services/project/src/main/resources/db/migration/main/V20230901150100__adverse_event_ref_ddl.sql delete mode 100644 health-services/project/src/main/resources/db/migration/main/V20230906144900__adverse_event_col_drop_ddl.sql delete mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/AdverseEventConsumer.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/SideEffectConsumer.java rename health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/{AdverseEventRepository.java => SideEffectRepository.java} (58%) rename health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/{AdverseEventRowMapper.java => SideEffectRowMapper.java} (89%) create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java delete mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/AdverseEventEnrichmentService.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/SideEffectEnrichmentService.java delete mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNullIdValidator.java rename health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/{adverseevent/AdIsDeletedValidator.java => sideeffect/SeIsDeletedValidator.java} (51%) rename health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/{adverseevent/AdNonExistentEntityValidator.java => sideeffect/SeNonExistentEntityValidator.java} (51%) create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNullIdValidator.java rename health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/{adverseevent/AdProjectTaskIdValidator.java => sideeffect/SeProjectTaskIdValidator.java} (81%) rename health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/{adverseevent/AdUniqueEntityValidator.java => sideeffect/SeUniqueEntityValidator.java} (66%) delete mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/AdverseEventApiController.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/SideEffectApiController.java rename health-services/{project/src/main/resources/db/migration/main/V20230807130400__adverse_event_create_ddl.sql => referralmanagement/src/main/resources/db/migration/main/V20230928120100__side_effect_create_ddl.sql} (62%) delete mode 100644 health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventRequestTestBuilder.java create mode 100644 health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectRequestTestBuilder.java rename health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/{AdverseEventTestBuilder.java => SideEffectTestBuilder.java} (61%) rename health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/{AdverseEventApiControllerTest.java => SideEffectApiControllerTest.java} (60%) diff --git a/docs/health-api-specs/contracts/adverse-event-referral-management.yml b/docs/health-api-specs/contracts/referral-management.yml similarity index 100% rename from docs/health-api-specs/contracts/adverse-event-referral-management.yml rename to docs/health-api-specs/contracts/referral-management.yml diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEvent.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java similarity index 95% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEvent.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java index fbaf7c00736..a078844a2dc 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEvent.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java @@ -1,4 +1,4 @@ -package org.egov.common.models.referralmanagement.adverseevent; +package org.egov.common.models.referralmanagement.sideeffect; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -19,7 +19,7 @@ @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class AdverseEvent { +public class SideEffect { @JsonProperty("id") @Size(min = 2, max = 64) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java similarity index 67% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java index fa9248d1e1e..51319d73b51 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.referralmanagement.adverseevent; +package org.egov.common.models.referralmanagement.sideeffect; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -19,20 +19,20 @@ @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class AdverseEventBulkRequest { +public class SideEffectBulkRequest { @JsonProperty("RequestInfo") @NotNull @Valid private RequestInfo requestInfo = null; - @JsonProperty("AdverseEvents") + @JsonProperty("SideEffects") @NotNull @Valid @Size(min=1) - private List adverseEvents = new ArrayList<>(); + private List sideEffects = new ArrayList<>(); - public AdverseEventBulkRequest addAdverseEventItem(AdverseEvent adverseEventItem) { - this.adverseEvents.add(adverseEventItem); + public SideEffectBulkRequest addSideEffectItem(SideEffect sideEffectItem) { + this.sideEffects.add(sideEffectItem); return this; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java similarity index 66% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkResponse.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java index 880cc07875d..bfcfda3dae4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java @@ -1,4 +1,4 @@ -package org.egov.common.models.referralmanagement.adverseevent; +package org.egov.common.models.referralmanagement.sideeffect; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -18,20 +18,20 @@ @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class AdverseEventBulkResponse { +public class SideEffectBulkResponse { @JsonProperty("ResponseInfo") @NotNull @Valid private ResponseInfo responseInfo = null; - @JsonProperty("AdverseEvents") + @JsonProperty("SideEffects") @NotNull @Valid - private List adverseEvents = new ArrayList<>(); + private List sideEffects = new ArrayList<>(); - public AdverseEventBulkResponse addAdverseEventItem(AdverseEvent adverseEventItem) { - this.adverseEvents.add(adverseEventItem); + public SideEffectBulkResponse addSideEffectItem(SideEffect sideEffectItem) { + this.sideEffects.add(sideEffectItem); return this; } } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java similarity index 76% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java index 6e470f9f435..9de2e92b66e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.referralmanagement.adverseevent; +package org.egov.common.models.referralmanagement.sideeffect; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -16,14 +16,14 @@ @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class AdverseEventRequest{ +public class SideEffectRequest { @JsonProperty("RequestInfo") @NotNull @Valid private RequestInfo requestInfo = null; - @JsonProperty("AdverseEvent") + @JsonProperty("SideEffect") @NotNull @Valid - private AdverseEvent adverseEvent = null; + private SideEffect sideEffect = null; } \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java similarity index 76% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventResponse.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java index 90851c1dcf7..9e96194482c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java @@ -1,4 +1,4 @@ -package org.egov.common.models.referralmanagement.adverseevent; +package org.egov.common.models.referralmanagement.sideeffect; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -16,16 +16,16 @@ @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class AdverseEventResponse { +public class SideEffectResponse { @JsonProperty("ResponseInfo") @NotNull @Valid private ResponseInfo responseInfo = null; - @JsonProperty("AdverseEvent") + @JsonProperty("SideEffect") @NotNull @Valid - private AdverseEvent adverseEvent = null; + private SideEffect sideEffect = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java similarity index 82% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearch.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java index 19a8cd94e99..3183a2533d6 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java @@ -1,4 +1,4 @@ -package org.egov.common.models.referralmanagement.adverseevent; +package org.egov.common.models.referralmanagement.sideeffect; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -7,7 +7,6 @@ import lombok.Data; import lombok.NoArgsConstructor; -import javax.validation.constraints.Size; import java.util.List; @Data @@ -15,7 +14,7 @@ @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class AdverseEventSearch { +public class SideEffectSearch { @JsonProperty("id") private List id = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java similarity index 74% rename from health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearchRequest.java rename to health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java index 68b546c3dac..69cc688f884 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java @@ -1,4 +1,4 @@ -package org.egov.common.models.referralmanagement.adverseevent; +package org.egov.common.models.referralmanagement.sideeffect; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -16,13 +16,13 @@ @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class AdverseEventSearchRequest { +public class SideEffectSearchRequest { @JsonProperty("RequestInfo") @NotNull @Valid private RequestInfo requestInfo = null; - @JsonProperty("AdverseEvent") + @JsonProperty("SideEffect") @Valid - private AdverseEventSearch adverseEvent = null; + private SideEffectSearch sideEffect = null; } diff --git a/health-services/project/README.md b/health-services/project/README.md index 13961132999..89424d22e48 100644 --- a/health-services/project/README.md +++ b/health-services/project/README.md @@ -130,10 +130,6 @@ Project service APIs - contains create, update, delete and search end point - update-project-resource-bulk-topic - delete-project-resource-bulk-topic -- save-adverse-event-bulk-topic -- update-adverse-event-bulk-topic -- delete-adverse-event-bulk-topic - ### Kafka Producers - save-project-staff-topic @@ -156,10 +152,6 @@ Project service APIs - contains create, update, delete and search end point - update-project-resource-topic - delete-project-resource-topic -- save-adverse-event-topic -- update-adverse-event-topic -- delete-adverse-event-topic - ## Pre commit script [commit-msg](https://gist.github.com/jayantp-egov/14f55deb344f1648503c6be7e580fa12) diff --git a/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java b/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java index e6fe7ea8af7..fe9291ab137 100644 --- a/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java +++ b/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java @@ -183,21 +183,4 @@ public class ProjectConfiguration { @Value("${egov.user.id.validator}") private String egovUserIdValidator; - @Value("${project.adverseevent.kafka.create.topic}") - private String createAdverseEventTopic; - - @Value("${project.adverseevent.kafka.update.topic}") - private String updateAdverseEventTopic; - - @Value("${project.adverseevent.kafka.delete.topic}") - private String deleteAdverseEventTopic; - - @Value("${project.adverseevent.consumer.bulk.create.topic}") - private String createAdverseEventBulkTopic; - - @Value("${project.adverseevent.consumer.bulk.update.topic}") - private String updateAdverseEventBulkTopic; - - @Value("${project.adverseevent.consumer.bulk.delete.topic}") - private String deleteAdverseEventBulkTopic; } diff --git a/health-services/project/src/main/resources/application.properties b/health-services/project/src/main/resources/application.properties index 460d24b6554..81fc4cd7f12 100644 --- a/health-services/project/src/main/resources/application.properties +++ b/health-services/project/src/main/resources/application.properties @@ -163,13 +163,3 @@ project.resource.consumer.bulk.delete.topic=delete-project-resource-bulk-topic project.mdms.module=HCM-PROJECT-TYPES egov.location.hierarchy.type=ADMIN - -project.adverseevent.kafka.create.topic=save-adverse-event-topic -project.adverseevent.kafka.update.topic=update-adverse-event-topic -project.adverseevent.kafka.delete.topic=delete-adverse-event-topic - -project.adverseevent.consumer.bulk.create.topic=save-adverse-event-bulk-topic -project.adverseevent.consumer.bulk.update.topic=update-adverse-event-bulk-topic -project.adverseevent.consumer.bulk.delete.topic=delete-adverse-event-bulk-topic - - diff --git a/health-services/project/src/main/resources/db/migration/main/V20230901150100__adverse_event_ref_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20230901150100__adverse_event_ref_ddl.sql deleted file mode 100644 index 92680165b50..00000000000 --- a/health-services/project/src/main/resources/db/migration/main/V20230901150100__adverse_event_ref_ddl.sql +++ /dev/null @@ -1,2 +0,0 @@ -ALTER TABLE ADVERSE_EVENT ALTER COLUMN clientReferenceId SET NOT NULL; -ALTER TABLE ADVERSE_EVENT ALTER COLUMN taskClientReferenceId SET NOT NULL; \ No newline at end of file diff --git a/health-services/project/src/main/resources/db/migration/main/V20230906144900__adverse_event_col_drop_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20230906144900__adverse_event_col_drop_ddl.sql deleted file mode 100644 index c5781bdd32c..00000000000 --- a/health-services/project/src/main/resources/db/migration/main/V20230906144900__adverse_event_col_drop_ddl.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE ADVERSE_EVENT DROP COLUMN IF EXISTS reAttempts; \ No newline at end of file diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java index b343825766e..421453e033c 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java @@ -1,8 +1,8 @@ package org.egov.referralmanagement; public interface Constants { - String SET_ADVERSE_EVENTS = "setAdverseEvents"; - String GET_ADVERSE_EVENTS = "getAdverseEvents"; + String SET_SIDE_EFFECTS = "setSideEffects"; + String GET_SIDE_EFFECTS = "getSideEffects"; String SET_REFERRALS = "setReferrals"; String GET_REFERRALS = "getReferrals"; String VALIDATION_ERROR = "VALIDATION_ERROR"; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java index 67561b31d39..be30c29e5d4 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java @@ -15,23 +15,23 @@ @Builder @Component public class ReferralManagementConfiguration { - @Value("${referralmanagement.adverseevent.kafka.create.topic}") - private String createAdverseEventTopic; + @Value("${referralmanagement.sideeffect.kafka.create.topic}") + private String createSideEffectTopic; - @Value("${referralmanagement.adverseevent.kafka.update.topic}") - private String updateAdverseEventTopic; + @Value("${referralmanagement.sideeffect.kafka.update.topic}") + private String updateSideEffectTopic; - @Value("${referralmanagement.adverseevent.kafka.delete.topic}") - private String deleteAdverseEventTopic; + @Value("${referralmanagement.sideeffect.kafka.delete.topic}") + private String deleteSideEffectTopic; - @Value("${referralmanagement.adverseevent.consumer.bulk.create.topic}") - private String createAdverseEventBulkTopic; + @Value("${referralmanagement.sideeffect.consumer.bulk.create.topic}") + private String createSideEffectBulkTopic; - @Value("${referralmanagement.adverseevent.consumer.bulk.update.topic}") - private String updateAdverseEventBulkTopic; + @Value("${referralmanagement.sideeffect.consumer.bulk.update.topic}") + private String updateSideEffectBulkTopic; - @Value("${referralmanagement.adverseevent.consumer.bulk.delete.topic}") - private String deleteAdverseEventBulkTopic; + @Value("${referralmanagement.sideeffect.consumer.bulk.delete.topic}") + private String deleteSideEffectBulkTopic; @Value("${egov.project.host}") private String projectHost; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/AdverseEventConsumer.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/AdverseEventConsumer.java deleted file mode 100644 index e1290be9810..00000000000 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/AdverseEventConsumer.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.egov.referralmanagement.consumer; - -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; -import org.egov.referralmanagement.service.AdverseEventService; -import org.egov.tracer.model.CustomException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -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 AdverseEventConsumer { - - private final AdverseEventService adverseEventService; - - private final ObjectMapper objectMapper; - - @Autowired - public AdverseEventConsumer(AdverseEventService adverseEventService, - @Qualifier("objectMapper") ObjectMapper objectMapper) { - this.adverseEventService = adverseEventService; - this.objectMapper = objectMapper; - } - - @KafkaListener(topics = "${referralmanagement.adverseevent.consumer.bulk.create.topic}") - public void bulkCreate(Map consumerRecord, - @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { - try { - AdverseEventBulkRequest request = objectMapper.convertValue(consumerRecord, AdverseEventBulkRequest.class); - adverseEventService.create(request, true); - } catch (Exception exception) { - log.error("Error in Adverse Event consumer bulk create", exception); - log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); - throw new CustomException("HCM_PROJECT_ADVERSE_EVENT_CREATE", exception.getMessage()); - } - } - - @KafkaListener(topics = "${referralmanagement.adverseevent.consumer.bulk.update.topic}") - public void bulkUpdate(Map consumerRecord, - @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { - try { - AdverseEventBulkRequest request = objectMapper.convertValue(consumerRecord, AdverseEventBulkRequest.class); - adverseEventService.update(request, true); - } catch (Exception exception) { - log.error("Error in Adverse Event consumer bulk update", exception); - log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); - throw new CustomException("HCM_PROJECT_ADVERSE_EVENT_CREATE", exception.getMessage()); - } - } - - @KafkaListener(topics = "${referralmanagement.adverseevent.consumer.bulk.delete.topic}") - public void bulkDelete(Map consumerRecord, - @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { - try { - AdverseEventBulkRequest request = objectMapper.convertValue(consumerRecord, AdverseEventBulkRequest.class); - adverseEventService.delete(request, true); - } catch (Exception exception) { - log.error("Error in Adverse Event consumer bulk delete", exception); - log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); - throw new CustomException("HCM_PROJECT_ADVERSE_EVENT_CREATE", exception.getMessage()); - } - } -} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/SideEffectConsumer.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/SideEffectConsumer.java new file mode 100644 index 00000000000..e1d8204cb06 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/SideEffectConsumer.java @@ -0,0 +1,71 @@ +package org.egov.referralmanagement.consumer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.referralmanagement.service.SideEffectService; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +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 SideEffectConsumer { + + private final SideEffectService sideEffectService; + + private final ObjectMapper objectMapper; + + @Autowired + public SideEffectConsumer(SideEffectService sideEffectService, + @Qualifier("objectMapper") ObjectMapper objectMapper) { + this.sideEffectService = sideEffectService; + this.objectMapper = objectMapper; + } + + @KafkaListener(topics = "${referralmanagement.sideeffect.consumer.bulk.create.topic}") + public void bulkCreate(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + SideEffectBulkRequest request = objectMapper.convertValue(consumerRecord, SideEffectBulkRequest.class); + sideEffectService.create(request, true); + } catch (Exception exception) { + log.error("Error in Side Effect consumer bulk create", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_PROJECT_SIDE_EFFECT_CREATE", exception.getMessage()); + } + } + + @KafkaListener(topics = "${referralmanagement.sideeffect.consumer.bulk.update.topic}") + public void bulkUpdate(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + SideEffectBulkRequest request = objectMapper.convertValue(consumerRecord, SideEffectBulkRequest.class); + sideEffectService.update(request, true); + } catch (Exception exception) { + log.error("Error in Side Effect consumer bulk update", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_PROJECT_SIDE_EFFECT_CREATE", exception.getMessage()); + } + } + + @KafkaListener(topics = "${referralmanagement.sideeffect.consumer.bulk.delete.topic}") + public void bulkDelete(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + SideEffectBulkRequest request = objectMapper.convertValue(consumerRecord, SideEffectBulkRequest.class); + sideEffectService.delete(request, true); + } catch (Exception exception) { + log.error("Error in Side Effect consumer bulk delete", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_PROJECT_SIDE_EFFECT_CREATE", exception.getMessage()); + } + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/AdverseEventRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java similarity index 58% rename from health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/AdverseEventRepository.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java index 5db9f77f424..c3ce7ea000b 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/AdverseEventRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java @@ -6,11 +6,11 @@ import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearch; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearch; import org.egov.common.models.project.Task; import org.egov.common.producer.Producer; -import org.egov.referralmanagement.repository.rowmapper.AdverseEventRowMapper; +import org.egov.referralmanagement.repository.rowmapper.SideEffectRowMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; @@ -26,45 +26,45 @@ @Repository @Slf4j -public class AdverseEventRepository extends GenericRepository { +public class SideEffectRepository extends GenericRepository { @Autowired - private AdverseEventRowMapper rowMapper; + private SideEffectRowMapper rowMapper; @Autowired - protected AdverseEventRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, - RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, - AdverseEventRowMapper rowMapper) { - super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, rowMapper, Optional.of("adverse_event")); + protected SideEffectRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, + RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, + SideEffectRowMapper rowMapper) { + super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, rowMapper, Optional.of("side_effect")); } - public Map> fetchAdverseEvents(List taskList) { + public Map> fetchSideEffects(List taskList) { if (taskList.isEmpty()) { return Collections.emptyMap(); } List taskIds = getIdList(taskList); Map resourceParamsMap = new HashMap<>(); - String resourceQuery = "SELECT * FROM adverse_event ae where ae.taskId IN (:taskIds)"; + String resourceQuery = "SELECT * FROM side_effect ae where ae.taskId IN (:taskIds)"; resourceParamsMap.put("taskIds", taskIds); - List adverseEventList = this.namedParameterJdbcTemplate.query(resourceQuery, resourceParamsMap, + List sideEffectList = this.namedParameterJdbcTemplate.query(resourceQuery, resourceParamsMap, this.rowMapper); - Map> idToObjMap = new HashMap<>(); + Map> idToObjMap = new HashMap<>(); - adverseEventList.forEach(adverseEvent -> { - String taskId = adverseEvent.getTaskId(); + sideEffectList.forEach(sideEffect -> { + String taskId = sideEffect.getTaskId(); if (idToObjMap.containsKey(taskId)) { - idToObjMap.get(taskId).add(adverseEvent); + idToObjMap.get(taskId).add(sideEffect); } else { - List adverseEvents = new ArrayList<>(); - adverseEvents.add(adverseEvent); - idToObjMap.put(taskId, adverseEvents); + List sideEffects = new ArrayList<>(); + sideEffects.add(sideEffect); + idToObjMap.put(taskId, sideEffects); } }); return idToObjMap; } - public List find(AdverseEventSearch searchObject, Integer limit, Integer offset, String tenantId, - Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { - String query = "SELECT * FROM adverse_event ae LEFT JOIN project_task pt ON ae.taskId = pt.id "; + public List find(SideEffectSearch searchObject, Integer limit, Integer offset, String tenantId, + Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { + String query = "SELECT * FROM side_effect ae LEFT JOIN project_task pt ON ae.taskId = pt.id "; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); @@ -86,12 +86,12 @@ public List find(AdverseEventSearch searchObject, Integer limit, I paramsMap.put("lastModifiedTime", lastChangedSince); paramsMap.put("limit", limit); paramsMap.put("offset", offset); - List adverseEventList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); - return adverseEventList; + List sideEffectList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + return sideEffectList; } - public List findById(List ids, String columnName, Boolean includeDeleted) { - List objFound = findInCache(ids).stream() + public List findById(List ids, String columnName, Boolean includeDeleted) { + List objFound = findInCache(ids).stream() .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) .collect(Collectors.toList()); if (!objFound.isEmpty()) { @@ -104,15 +104,15 @@ public List findById(List ids, String columnName, Boolean } } - String query = String.format("SELECT * FROM adverse_event ae LEFT JOIN project_task pt ON ae.taskid = pt.id WHERE ae.%s IN (:ids) ", columnName); + String query = String.format("SELECT * FROM side_effect ae LEFT JOIN project_task pt ON ae.taskid = pt.id WHERE ae.%s IN (:ids) ", columnName); if (includeDeleted == null || !includeDeleted) { query += " AND ae.isDeleted = false "; } Map paramMap = new HashMap<>(); paramMap.put("ids", ids); - List adverseEventList = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + List sideEffectList = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); - objFound.addAll(adverseEventList); + objFound.addAll(sideEffectList); putInCache(objFound); return objFound; } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/AdverseEventRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java similarity index 89% rename from health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/AdverseEventRowMapper.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java index 6dd6ff19472..7a49ceef93e 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/AdverseEventRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; @@ -13,13 +13,13 @@ import java.util.ArrayList; @Component -public class AdverseEventRowMapper implements RowMapper { +public class SideEffectRowMapper implements RowMapper { @Autowired ObjectMapper objectMapper; @Override - public AdverseEvent mapRow(ResultSet resultSet, int i) throws SQLException { + public SideEffect mapRow(ResultSet resultSet, int i) throws SQLException { try { AuditDetails auditDetails = AuditDetails.builder() .createdBy(resultSet.getString("createdBy")) @@ -33,7 +33,7 @@ public AdverseEvent mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) .build(); - return AdverseEvent.builder() + return SideEffect.builder() .id(resultSet.getString("id")) .clientReferenceId(resultSet.getString("clientreferenceid")) .taskId(resultSet.getString("taskId")) diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java new file mode 100644 index 00000000000..8f8d63d9ed0 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java @@ -0,0 +1,237 @@ +package org.egov.referralmanagement.service; + +import lombok.extern.slf4j.Slf4j; +import org.egov.referralmanagement.Constants; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.repository.SideEffectRepository; +import org.egov.referralmanagement.service.enrichment.SideEffectEnrichmentService; +import org.egov.referralmanagement.validator.sideeffect.SeIsDeletedValidator; +import org.egov.referralmanagement.validator.sideeffect.SeNonExistentEntityValidator; +import org.egov.referralmanagement.validator.sideeffect.SeNullIdValidator; +import org.egov.referralmanagement.validator.sideeffect.SeProjectTaskIdValidator; +import org.egov.referralmanagement.validator.sideeffect.SeUniqueEntityValidator; +import org.egov.common.ds.Tuple; +import org.egov.common.models.ErrorDetails; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearchRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.egov.common.validator.Validator; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.ReflectionUtils; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +@Service +@Slf4j +public class SideEffectService { + private final IdGenService idGenService; + + private final SideEffectRepository sideEffectRepository; + + private final ReferralManagementConfiguration referralManagementConfiguration; + + private final SideEffectEnrichmentService sideEffectEnrichmentService; + + private final List> validators; + + private final Predicate> isApplicableForCreate = validator -> + validator.getClass().equals(SeProjectTaskIdValidator.class); + + private final Predicate> isApplicableForUpdate = validator -> + validator.getClass().equals(SeProjectTaskIdValidator.class) + || validator.getClass().equals(SeNullIdValidator.class) + || validator.getClass().equals(SeIsDeletedValidator.class) + || validator.getClass().equals(SeUniqueEntityValidator.class) + || validator.getClass().equals(SeNonExistentEntityValidator.class); + + private final Predicate> isApplicableForDelete = validator -> + validator.getClass().equals(SeNullIdValidator.class) + || validator.getClass().equals(SeNonExistentEntityValidator.class); + + @Autowired + public SideEffectService( + IdGenService idGenService, + SideEffectRepository sideEffectRepository, + ReferralManagementConfiguration referralManagementConfiguration, + SideEffectEnrichmentService sideEffectEnrichmentService, + List> validators + ) { + this.idGenService = idGenService; + this.sideEffectRepository = sideEffectRepository; + this.referralManagementConfiguration = referralManagementConfiguration; + this.sideEffectEnrichmentService = sideEffectEnrichmentService; + this.validators = validators; + } + + public SideEffect create(SideEffectRequest request) { + log.info("received request to create side effects"); + SideEffectBulkRequest bulkRequest = SideEffectBulkRequest.builder().requestInfo(request.getRequestInfo()) + .sideEffects(Collections.singletonList(request.getSideEffect())).build(); + log.info("creating bulk request"); + return create(bulkRequest, false).get(0); + } + + public List create(SideEffectBulkRequest sideEffectRequest, boolean isBulk) { + log.info("received request to create bulk side effects"); + Tuple, Map> tuple = validate(validators, + isApplicableForCreate, sideEffectRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validSideEffects = tuple.getX(); + + try { + if (!validSideEffects.isEmpty()) { + log.info("processing {} valid entities", validSideEffects.size()); + sideEffectEnrichmentService.create(validSideEffects, sideEffectRequest); + sideEffectRepository.save(validSideEffects, + referralManagementConfiguration.getCreateSideEffectTopic()); + log.info("successfully created side effects"); + } + } catch (Exception exception) { + log.error("error occurred while creating side effects: {}", exception.getMessage()); + populateErrorDetails(sideEffectRequest, errorDetailsMap, validSideEffects, + exception, Constants.SET_SIDE_EFFECTS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validSideEffects; + } + + public SideEffect update(SideEffectRequest request) { + log.info("received request to update side effect"); + SideEffectBulkRequest bulkRequest = SideEffectBulkRequest.builder().requestInfo(request.getRequestInfo()) + .sideEffects(Collections.singletonList(request.getSideEffect())).build(); + log.info("creating bulk request"); + return update(bulkRequest, false).get(0); + } + + public List update(SideEffectBulkRequest sideEffectRequest, boolean isBulk) { + log.info("received request to update bulk side effect"); + Tuple, Map> tuple = validate(validators, + isApplicableForUpdate, sideEffectRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validSideEffects = tuple.getX(); + + try { + if (!validSideEffects.isEmpty()) { + log.info("processing {} valid entities", validSideEffects.size()); + sideEffectEnrichmentService.update(validSideEffects, sideEffectRequest); + sideEffectRepository.save(validSideEffects, + referralManagementConfiguration.getUpdateSideEffectTopic()); + log.info("successfully updated bulk side effects"); + } + } catch (Exception exception) { + log.error("error occurred while updating side effects", exception); + populateErrorDetails(sideEffectRequest, errorDetailsMap, validSideEffects, + exception, Constants.SET_SIDE_EFFECTS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validSideEffects; + } + + public List search(SideEffectSearchRequest sideEffectSearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { + log.info("received request to search side effects"); + String idFieldName = getIdFieldName(sideEffectSearchRequest.getSideEffect()); + if (isSearchByIdOnly(sideEffectSearchRequest.getSideEffect(), idFieldName)) { + log.info("searching side effects by id"); + List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections + .singletonList(sideEffectSearchRequest.getSideEffect())), + sideEffectSearchRequest.getSideEffect()); + log.info("fetching side effects with ids: {}", ids); + return sideEffectRepository.findById(ids, includeDeleted, idFieldName).stream() + .filter(lastChangedSince(lastChangedSince)) + .filter(havingTenantId(tenantId)) + .filter(includeDeleted(includeDeleted)) + .collect(Collectors.toList()); + } + log.info("searching side effects using criteria"); + return sideEffectRepository.find(sideEffectSearchRequest.getSideEffect(), + limit, offset, tenantId, lastChangedSince, includeDeleted); + } + + public SideEffect delete(SideEffectRequest sideEffectRequest) { + log.info("received request to delete a side effect"); + SideEffectBulkRequest bulkRequest = SideEffectBulkRequest.builder().requestInfo(sideEffectRequest.getRequestInfo()) + .sideEffects(Collections.singletonList(sideEffectRequest.getSideEffect())).build(); + log.info("creating bulk request"); + return delete(bulkRequest, false).get(0); + } + + public List delete(SideEffectBulkRequest sideEffectRequest, boolean isBulk) { + Tuple, Map> tuple = validate(validators, + isApplicableForDelete, sideEffectRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validSideEffects = tuple.getX(); + + try { + if (!validSideEffects.isEmpty()) { + log.info("processing {} valid entities", validSideEffects.size()); + List sideEffectIds = validSideEffects.stream().map(entity -> entity.getId()).collect(Collectors.toSet()).stream().collect(Collectors.toList()); + List existingSideEffects = sideEffectRepository + .findById(sideEffectIds, false); + sideEffectEnrichmentService.delete(existingSideEffects, sideEffectRequest); + sideEffectRepository.save(existingSideEffects, + referralManagementConfiguration.getDeleteSideEffectTopic()); + log.info("successfully deleted entities"); + } + } catch (Exception exception) { + log.error("error occurred while deleting entities: {}", exception); + populateErrorDetails(sideEffectRequest, errorDetailsMap, validSideEffects, + exception, Constants.SET_SIDE_EFFECTS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validSideEffects; + } + + public void putInCache(List sideEffects) { + log.info("putting {} side effects in cache", sideEffects.size()); + sideEffectRepository.putInCache(sideEffects); + log.info("successfully put side effects in cache"); + } + + private Tuple, Map> validate( + List> validators, + Predicate> isApplicable, + SideEffectBulkRequest request, + boolean isBulk + ) { + log.info("validating request"); + Map errorDetailsMap = CommonUtils.validate(validators, + isApplicable, request, + Constants.SET_SIDE_EFFECTS); + if (!errorDetailsMap.isEmpty() && !isBulk) { + log.error("validation error occurred. error details: {}", errorDetailsMap.values().toString()); + throw new CustomException(Constants.VALIDATION_ERROR, errorDetailsMap.values().toString()); + } + List validSideEffects = request.getSideEffects().stream() + .filter(notHavingErrors()).collect(Collectors.toList()); + log.info("validation successful, found valid side effects"); + return new Tuple<>(validSideEffects, errorDetailsMap); + } + +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/AdverseEventEnrichmentService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/AdverseEventEnrichmentService.java deleted file mode 100644 index f8a28ddc0a6..00000000000 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/AdverseEventEnrichmentService.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.egov.referralmanagement.service.enrichment; - -import lombok.extern.slf4j.Slf4j; -import org.egov.referralmanagement.config.ReferralManagementConfiguration; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; -import org.egov.common.service.IdGenService; -import org.egov.common.utils.CommonUtils; -import org.egov.referralmanagement.repository.AdverseEventRepository; -import org.springframework.stereotype.Component; - -import java.util.List; -import java.util.Map; - -import static org.egov.common.utils.CommonUtils.*; - -@Component -@Slf4j -public class AdverseEventEnrichmentService { - - private final IdGenService idGenService; - - private final ReferralManagementConfiguration referralManagementConfiguration; - - private final AdverseEventRepository adverseEventRepository; - - public AdverseEventEnrichmentService(IdGenService idGenService, ReferralManagementConfiguration referralManagementConfiguration, AdverseEventRepository adverseEventRepository) { - this.idGenService = idGenService; - this.referralManagementConfiguration = referralManagementConfiguration; - this.adverseEventRepository = adverseEventRepository; - } - - public void create(List entities, AdverseEventBulkRequest request) throws Exception { - log.info("starting the enrichment for create adverse event"); - log.info("generating IDs using UUID"); - List idList = CommonUtils.uuidSupplier().apply(entities.size()); - log.info("enriching adverse events with generated IDs"); - enrichForCreate(entities, idList, request.getRequestInfo()); - log.info("enrichment done"); - } - - public void update(List entities, AdverseEventBulkRequest request) { - log.info("starting the enrichment for create adverse event"); - Map adverseEventMap = getIdToObjMap(entities); - enrichForUpdate(adverseEventMap, entities, request); - log.info("enrichment done"); - } - - public void delete(List entities, AdverseEventBulkRequest request) { - log.info("starting the enrichment for delete adverse event"); - enrichForDelete(entities, request.getRequestInfo(), true); - log.info("enrichment done"); - } -} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/SideEffectEnrichmentService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/SideEffectEnrichmentService.java new file mode 100644 index 00000000000..d86132e06a3 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/SideEffectEnrichmentService.java @@ -0,0 +1,54 @@ +package org.egov.referralmanagement.service.enrichment; + +import lombok.extern.slf4j.Slf4j; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.egov.referralmanagement.repository.SideEffectRepository; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +import static org.egov.common.utils.CommonUtils.*; + +@Component +@Slf4j +public class SideEffectEnrichmentService { + + private final IdGenService idGenService; + + private final ReferralManagementConfiguration referralManagementConfiguration; + + private final SideEffectRepository sideEffectRepository; + + public SideEffectEnrichmentService(IdGenService idGenService, ReferralManagementConfiguration referralManagementConfiguration, SideEffectRepository sideEffectRepository) { + this.idGenService = idGenService; + this.referralManagementConfiguration = referralManagementConfiguration; + this.sideEffectRepository = sideEffectRepository; + } + + public void create(List entities, SideEffectBulkRequest request) throws Exception { + log.info("starting the enrichment for create side effect"); + log.info("generating IDs using UUID"); + List idList = CommonUtils.uuidSupplier().apply(entities.size()); + log.info("enriching side effects with generated IDs"); + enrichForCreate(entities, idList, request.getRequestInfo()); + log.info("enrichment done"); + } + + public void update(List entities, SideEffectBulkRequest request) { + log.info("starting the enrichment for create side effect"); + Map sideEffectMap = getIdToObjMap(entities); + enrichForUpdate(sideEffectMap, entities, request); + log.info("enrichment done"); + } + + public void delete(List entities, SideEffectBulkRequest request) { + log.info("starting the enrichment for delete side effect"); + enrichForDelete(entities, request.getRequestInfo(), true); + log.info("enrichment done"); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNullIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNullIdValidator.java deleted file mode 100644 index f051349ee82..00000000000 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNullIdValidator.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.egov.referralmanagement.validator.adverseevent; - -import lombok.extern.slf4j.Slf4j; -import org.egov.common.models.Error; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; -import org.egov.common.validator.Validator; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import java.util.List; -import java.util.Map; - -import static org.egov.referralmanagement.Constants.GET_ADVERSE_EVENTS; -import static org.egov.common.utils.CommonUtils.validateForNullId; - - -@Component -@Order(value = 1) -@Slf4j -public class AdNullIdValidator implements Validator { - @Override - public Map> validate(AdverseEventBulkRequest request) { - log.info("validating for null id"); - return validateForNullId(request, GET_ADVERSE_EVENTS); - } -} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdIsDeletedValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeIsDeletedValidator.java similarity index 51% rename from health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdIsDeletedValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeIsDeletedValidator.java index b4ae9c3c17d..b6e4d3f94f3 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdIsDeletedValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeIsDeletedValidator.java @@ -1,9 +1,9 @@ -package org.egov.referralmanagement.validator.adverseevent; +package org.egov.referralmanagement.validator.sideeffect; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -18,14 +18,14 @@ @Component @Order(2) @Slf4j -public class AdIsDeletedValidator implements Validator { +public class SeIsDeletedValidator implements Validator { @Override - public Map> validate(AdverseEventBulkRequest request) { + public Map> validate(SideEffectBulkRequest request) { log.info("validating isDeleted field"); - HashMap> errorDetailsMap = new HashMap<>(); - List validIndividuals = request.getAdverseEvents(); - validIndividuals.stream().filter(AdverseEvent::getIsDeleted).forEach(individual -> { + HashMap> errorDetailsMap = new HashMap<>(); + List validIndividuals = request.getSideEffects(); + validIndividuals.stream().filter(SideEffect::getIsDeleted).forEach(individual -> { Error error = getErrorForIsDelete(); populateErrorDetails(individual, error, errorDetailsMap); }); diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNonExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNonExistentEntityValidator.java similarity index 51% rename from health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNonExistentEntityValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNonExistentEntityValidator.java index 8fea8a00e6e..5f70cd0fef5 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNonExistentEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNonExistentEntityValidator.java @@ -1,11 +1,11 @@ -package org.egov.referralmanagement.validator.adverseevent; +package org.egov.referralmanagement.validator.sideeffect; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; -import org.egov.referralmanagement.repository.AdverseEventRepository; +import org.egov.referralmanagement.repository.SideEffectRepository; import org.egov.common.models.Error; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; import org.egov.common.validator.Validator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; @@ -31,37 +31,37 @@ @Component @Order(value = 4) @Slf4j -public class AdNonExistentEntityValidator implements Validator { +public class SeNonExistentEntityValidator implements Validator { - private final AdverseEventRepository adverseEventRepository; + private final SideEffectRepository sideEffectRepository; private final ObjectMapper objectMapper; @Autowired - public AdNonExistentEntityValidator(AdverseEventRepository adverseEventRepository, ObjectMapper objectMapper) { - this.adverseEventRepository = adverseEventRepository; + public SeNonExistentEntityValidator(SideEffectRepository sideEffectRepository, ObjectMapper objectMapper) { + this.sideEffectRepository = sideEffectRepository; this.objectMapper = objectMapper; } @Override - public Map> validate(AdverseEventBulkRequest request) { + public Map> validate(SideEffectBulkRequest request) { log.info("validating for existence of entity"); - Map> errorDetailsMap = new HashMap<>(); - List adverseEvents = request.getAdverseEvents(); - Class objClass = getObjClass(adverseEvents); + Map> errorDetailsMap = new HashMap<>(); + List sideEffects = request.getSideEffects(); + Class objClass = getObjClass(sideEffects); Method idMethod = getMethod(GET_ID, objClass); - Map iMap = getIdToObjMap(adverseEvents + Map iMap = getIdToObjMap(sideEffects .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); if (!iMap.isEmpty()) { - List adverseEventIds = new ArrayList<>(iMap.keySet()); - List existingAdverseEvents = adverseEventRepository - .findById(adverseEventIds, false, getIdFieldName(idMethod)); - List nonExistentIndividuals = checkNonExistentEntities(iMap, - existingAdverseEvents, idMethod); - nonExistentIndividuals.forEach(adverseEvent -> { + List sideEffectIds = new ArrayList<>(iMap.keySet()); + List existingSideEffects = sideEffectRepository + .findById(sideEffectIds, false, getIdFieldName(idMethod)); + List nonExistentIndividuals = checkNonExistentEntities(iMap, + existingSideEffects, idMethod); + nonExistentIndividuals.forEach(sideEffect -> { Error error = getErrorForNonExistentEntity(); - populateErrorDetails(adverseEvent, error, errorDetailsMap); + populateErrorDetails(sideEffect, error, errorDetailsMap); }); } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNullIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNullIdValidator.java new file mode 100644 index 00000000000..f27f88830c4 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNullIdValidator.java @@ -0,0 +1,27 @@ +package org.egov.referralmanagement.validator.sideeffect; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +import static org.egov.referralmanagement.Constants.GET_SIDE_EFFECTS; +import static org.egov.common.utils.CommonUtils.validateForNullId; + + +@Component +@Order(value = 1) +@Slf4j +public class SeNullIdValidator implements Validator { + @Override + public Map> validate(SideEffectBulkRequest request) { + log.info("validating for null id"); + return validateForNullId(request, GET_SIDE_EFFECTS); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdProjectTaskIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java similarity index 81% rename from health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdProjectTaskIdValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java index 90cb6639da4..4d1b2609c26 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdProjectTaskIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java @@ -1,4 +1,4 @@ -package org.egov.referralmanagement.validator.adverseevent; +package org.egov.referralmanagement.validator.sideeffect; import lombok.extern.slf4j.Slf4j; import org.egov.referralmanagement.config.ReferralManagementConfiguration; @@ -13,8 +13,8 @@ import org.egov.common.models.project.TaskBulkResponse; import org.egov.common.models.project.TaskSearch; import org.egov.common.models.project.TaskSearchRequest; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; import org.egov.common.validator.Validator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; @@ -36,27 +36,27 @@ @Component @Order(value = 3) @Slf4j -public class AdProjectTaskIdValidator implements Validator { +public class SeProjectTaskIdValidator implements Validator { private final ServiceRequestClient serviceRequestClient; private final ReferralManagementConfiguration referralManagementConfiguration; @Autowired - public AdProjectTaskIdValidator(ServiceRequestClient serviceRequestClient, ReferralManagementConfiguration referralManagementConfiguration) { + public SeProjectTaskIdValidator(ServiceRequestClient serviceRequestClient, ReferralManagementConfiguration referralManagementConfiguration) { this.serviceRequestClient = serviceRequestClient; this.referralManagementConfiguration = referralManagementConfiguration; } @Override - public Map> validate(AdverseEventBulkRequest request) { + public Map> validate(SideEffectBulkRequest request) { log.info("validating project task id"); - Map> errorDetailsMap = new HashMap<>(); - List entities = request.getAdverseEvents(); - Map> tenantIdAdverseEventMap = entities.stream().collect(Collectors.groupingBy(AdverseEvent::getTenantId)); - List tenantIds = new ArrayList<>(tenantIdAdverseEventMap.keySet()); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getSideEffects(); + Map> tenantIdSideEffectMap = entities.stream().collect(Collectors.groupingBy(SideEffect::getTenantId)); + List tenantIds = new ArrayList<>(tenantIdSideEffectMap.keySet()); tenantIds.forEach(tenantId -> { - List adverseEventList = tenantIdAdverseEventMap.get(tenantId); - if (!adverseEventList.isEmpty()) { + List sideEffectList = tenantIdSideEffectMap.get(tenantId); + if (!sideEffectList.isEmpty()) { List existingTasks = null; List existingProjectBeneficiaries = null; final List projectBeneficiaryIdList = new ArrayList<>(); @@ -64,11 +64,11 @@ public Map> validate(AdverseEventBulkRequest request) final List taskIdList = new ArrayList<>(); final List taskClientReferenceIdList = new ArrayList<>(); try { - adverseEventList.forEach(adverseEvent -> { - addIgnoreNull(projectBeneficiaryIdList, adverseEvent.getProjectBeneficiaryId()); - addIgnoreNull(projectBeneficiaryClientReferenceIdList, adverseEvent.getProjectBeneficiaryClientReferenceId()); - addIgnoreNull(taskIdList, adverseEvent.getTaskId()); - addIgnoreNull(taskClientReferenceIdList, adverseEvent.getTaskClientReferenceId()); + sideEffectList.forEach(sideEffect -> { + addIgnoreNull(projectBeneficiaryIdList, sideEffect.getProjectBeneficiaryId()); + addIgnoreNull(projectBeneficiaryClientReferenceIdList, sideEffect.getProjectBeneficiaryClientReferenceId()); + addIgnoreNull(taskIdList, sideEffect.getTaskId()); + addIgnoreNull(taskClientReferenceIdList, sideEffect.getTaskClientReferenceId()); }); TaskSearch taskSearch = TaskSearch.builder() .id(taskIdList.isEmpty() ? null : taskIdList) @@ -109,15 +109,15 @@ public Map> validate(AdverseEventBulkRequest request) }); final List existingProjectTaskIds = existingTasks.stream().map(Task::getId).collect(Collectors.toList()); final List existingProjectReferenceTaskIds = existingTasks.stream().map(Task::getClientReferenceId).collect(Collectors.toList()); - List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> !existingProjectTaskIds.contains(entity.getTaskId()) && !existingProjectReferenceTaskIds.contains(entity.getTaskClientReferenceId()) && !existingProjectBeneficiaryIds.contains(entity.getProjectBeneficiaryId()) && !existingProjectBeneficiaryClientReferenceIds.contains(entity.getProjectBeneficiaryClientReferenceId()) ).collect(Collectors.toList()); - invalidEntities.forEach(adverseEvent -> { + invalidEntities.forEach(sideEffect -> { Error error = getErrorForNonExistentEntity(); - populateErrorDetails(adverseEvent, error, errorDetailsMap); + populateErrorDetails(sideEffect, error, errorDetailsMap); }); } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdUniqueEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java similarity index 66% rename from health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdUniqueEntityValidator.java rename to health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java index 8e06b42a9a2..43f99f7cef2 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdUniqueEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java @@ -1,9 +1,9 @@ -package org.egov.referralmanagement.validator.adverseevent; +package org.egov.referralmanagement.validator.sideeffect; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -19,16 +19,16 @@ @Component @Order(value = 2) @Slf4j -public class AdUniqueEntityValidator implements Validator { +public class SeUniqueEntityValidator implements Validator { @Override - public Map> validate(AdverseEventBulkRequest request) { + public Map> validate(SideEffectBulkRequest request) { log.info("validating unique entity"); - Map> errorDetailsMap = new HashMap<>(); - List validEntities = request.getAdverseEvents() + Map> errorDetailsMap = new HashMap<>(); + List validEntities = request.getSideEffects() .stream().filter(notHavingErrors()).collect(Collectors.toList()); if (!validEntities.isEmpty()) { - Map eMap = getIdToObjMap(validEntities); + Map eMap = getIdToObjMap(validEntities); if (eMap.keySet().size() != validEntities.size()) { List duplicates = eMap.keySet().stream().filter(id -> validEntities.stream() diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/AdverseEventApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/AdverseEventApiController.java deleted file mode 100644 index d7409965f65..00000000000 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/AdverseEventApiController.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.egov.referralmanagement.web.controllers; - -import io.swagger.annotations.ApiParam; -import org.egov.referralmanagement.config.ReferralManagementConfiguration; -import org.egov.referralmanagement.service.AdverseEventService; -import org.egov.common.contract.response.ResponseInfo; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkResponse; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventRequest; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventResponse; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearchRequest; -import org.egov.common.producer.Producer; -import org.egov.common.utils.ResponseInfoFactory; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; - -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import java.util.List; - -@Controller -@RequestMapping("/adverse_event") -@Validated -public class AdverseEventApiController { - - private final HttpServletRequest httpServletRequest; - - private final AdverseEventService adverseEventService; - - private final Producer producer; - - private final ReferralManagementConfiguration referralManagementConfiguration; - - public AdverseEventApiController( - HttpServletRequest httpServletRequest, - AdverseEventService adverseEventService, - Producer producer, - ReferralManagementConfiguration referralManagementConfiguration - ) { - this.httpServletRequest = httpServletRequest; - this.adverseEventService = adverseEventService; - this.producer = producer; - this.referralManagementConfiguration = referralManagementConfiguration; - } - - @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) - public ResponseEntity adverseEventV1CreatePost(@ApiParam(value = "Capture details of Adverse Event", required = true) @Valid @RequestBody AdverseEventRequest request) { - - AdverseEvent adverseEvent = adverseEventService.create(request); - AdverseEventResponse response = AdverseEventResponse.builder() - .adverseEvent(adverseEvent) - .responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)) - .build(); - - return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); - } - - - - @RequestMapping(value = "/v1/bulk/_create", method = RequestMethod.POST) - public ResponseEntity adverseEventBulkV1CreatePost(@ApiParam(value = "Capture details of Adverse Event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { - request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); - adverseEventService.putInCache(request.getAdverseEvents()); - producer.push(referralManagementConfiguration.getCreateAdverseEventBulkTopic(), request); - - return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)); - } - - @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) - public ResponseEntity adverseEventV1SearchPost(@ApiParam(value = "Adverse Event Search.", required = true) @Valid @RequestBody AdverseEventSearchRequest request, - @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, - @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, - @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, - @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, - @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { - - List adverseEvents = adverseEventService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); - AdverseEventBulkResponse response = AdverseEventBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).adverseEvents(adverseEvents).build(); - - return ResponseEntity.status(HttpStatus.OK).body(response); - } - - @RequestMapping(value = "/v1/_update", method = RequestMethod.POST) - public ResponseEntity adverseEventV1UpdatePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventRequest request) { - AdverseEvent adverseEvent = adverseEventService.update(request); - - AdverseEventResponse response = AdverseEventResponse.builder() - .adverseEvent(adverseEvent) - .responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)) - .build(); - - return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); - - } - - @RequestMapping(value = "/v1/bulk/_update", method = RequestMethod.POST) - public ResponseEntity adverseEventV1BulkUpdatePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { - request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); - producer.push(referralManagementConfiguration.getUpdateAdverseEventBulkTopic(), request); - - return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)); - } - - @RequestMapping(value = "/v1/_delete", method = RequestMethod.POST) - public ResponseEntity adverseEventV1DeletePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventRequest request) { - AdverseEvent adverseEvent = adverseEventService.delete(request); - - AdverseEventResponse response = AdverseEventResponse.builder() - .adverseEvent(adverseEvent) - .responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)) - .build(); - - return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); - - } - - @RequestMapping(value = "/v1/bulk/_delete", method = RequestMethod.POST) - public ResponseEntity adverseEventV1BulkDeletePost(@ApiParam(value = "Capture details of Existing adverse event", required = true) @Valid @RequestBody AdverseEventBulkRequest request) { - request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); - producer.push(referralManagementConfiguration.getDeleteAdverseEventBulkTopic(), request); - - return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)); - } -} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/SideEffectApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/SideEffectApiController.java new file mode 100644 index 00000000000..09c2b4c7b18 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/SideEffectApiController.java @@ -0,0 +1,141 @@ +package org.egov.referralmanagement.web.controllers; + +import io.swagger.annotations.ApiParam; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.service.SideEffectService; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkResponse; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectResponse; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearchRequest; +import org.egov.common.producer.Producer; +import org.egov.common.utils.ResponseInfoFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Controller +@RequestMapping("/side_effect") +@Validated +public class SideEffectApiController { + + private final HttpServletRequest httpServletRequest; + + private final SideEffectService sideEffectService; + + private final Producer producer; + + private final ReferralManagementConfiguration referralManagementConfiguration; + + public SideEffectApiController( + HttpServletRequest httpServletRequest, + SideEffectService sideEffectService, + Producer producer, + ReferralManagementConfiguration referralManagementConfiguration + ) { + this.httpServletRequest = httpServletRequest; + this.sideEffectService = sideEffectService; + this.producer = producer; + this.referralManagementConfiguration = referralManagementConfiguration; + } + + @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) + public ResponseEntity sideEffectV1CreatePost(@ApiParam(value = "Capture details of Side Effect", required = true) @Valid @RequestBody SideEffectRequest request) { + + SideEffect sideEffect = sideEffectService.create(request); + SideEffectResponse response = SideEffectResponse.builder() + .sideEffect(sideEffect) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } + + + + @RequestMapping(value = "/v1/bulk/_create", method = RequestMethod.POST) + public ResponseEntity sideEffectBulkV1CreatePost(@ApiParam(value = "Capture details of Side Effect", required = true) @Valid @RequestBody SideEffectBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + sideEffectService.putInCache(request.getSideEffects()); + producer.push(referralManagementConfiguration.getCreateSideEffectBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + + @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) + public ResponseEntity sideEffectV1SearchPost(@ApiParam(value = "Side Effect Search.", required = true) @Valid @RequestBody SideEffectSearchRequest request, + @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, + @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, + @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, + @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, + @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { + + List sideEffects = sideEffectService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); + SideEffectBulkResponse response = SideEffectBulkResponse.builder().responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)).sideEffects(sideEffects).build(); + + return ResponseEntity.status(HttpStatus.OK).body(response); + } + + @RequestMapping(value = "/v1/_update", method = RequestMethod.POST) + public ResponseEntity sideEffectV1UpdatePost(@ApiParam(value = "Capture details of Existing side effect", required = true) @Valid @RequestBody SideEffectRequest request) { + SideEffect sideEffect = sideEffectService.update(request); + + SideEffectResponse response = SideEffectResponse.builder() + .sideEffect(sideEffect) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + + } + + @RequestMapping(value = "/v1/bulk/_update", method = RequestMethod.POST) + public ResponseEntity sideEffectV1BulkUpdatePost(@ApiParam(value = "Capture details of Existing side effect", required = true) @Valid @RequestBody SideEffectBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + producer.push(referralManagementConfiguration.getUpdateSideEffectBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + + @RequestMapping(value = "/v1/_delete", method = RequestMethod.POST) + public ResponseEntity sideEffectV1DeletePost(@ApiParam(value = "Capture details of Existing side effect", required = true) @Valid @RequestBody SideEffectRequest request) { + SideEffect sideEffect = sideEffectService.delete(request); + + SideEffectResponse response = SideEffectResponse.builder() + .sideEffect(sideEffect) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + + } + + @RequestMapping(value = "/v1/bulk/_delete", method = RequestMethod.POST) + public ResponseEntity sideEffectV1BulkDeletePost(@ApiParam(value = "Capture details of Existing side effect", required = true) @Valid @RequestBody SideEffectBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + producer.push(referralManagementConfiguration.getDeleteSideEffectBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } +} diff --git a/health-services/referralmanagement/src/main/resources/application.properties b/health-services/referralmanagement/src/main/resources/application.properties index cbbc0f825f3..0abb7cd7248 100644 --- a/health-services/referralmanagement/src/main/resources/application.properties +++ b/health-services/referralmanagement/src/main/resources/application.properties @@ -55,7 +55,7 @@ kafka.producer.config.buffer_memory_config=33554432 egov.idgen.host=http://localhost:8081/ egov.idgen.path=egov-idgen/id/_generate egov.idgen.integration.enabled=true -referralmanagement.adverseevent.idgen.id.format=referralmanagement.adverseevent.id +referralmanagement.sideeffect.idgen.id.format=referralmanagement.sideeffect.id referralmanagement.referral.idgen.id.format=referralmanagement.referral.id idgen.project.beneficiary.id.format=project.beneficiary.id project.staff.idgen.id.format=project.staff.id @@ -103,13 +103,13 @@ egov.search.project.staff.url=/project/staff/v1/_search # ADRM KAFKA CONFIG -referralmanagement.adverseevent.kafka.create.topic=save-adverse-event-topic -referralmanagement.adverseevent.kafka.update.topic=update-adverse-event-topic -referralmanagement.adverseevent.kafka.delete.topic=delete-adverse-event-topic +referralmanagement.sideeffect.kafka.create.topic=save-side-effect-topic +referralmanagement.sideeffect.kafka.update.topic=update-side-effect-topic +referralmanagement.sideeffect.kafka.delete.topic=delete-side-effect-topic -referralmanagement.adverseevent.consumer.bulk.create.topic=save-adverse-event-bulk-topic -referralmanagement.adverseevent.consumer.bulk.update.topic=update-adverse-event-bulk-topic -referralmanagement.adverseevent.consumer.bulk.delete.topic=delete-adverse-event-bulk-topic +referralmanagement.sideeffect.consumer.bulk.create.topic=save-side-effect-bulk-topic +referralmanagement.sideeffect.consumer.bulk.update.topic=update-side-effect-bulk-topic +referralmanagement.sideeffect.consumer.bulk.delete.topic=delete-side-effect-bulk-topic referralmanagement.referral.kafka.create.topic=save-referral-topic referralmanagement.referral.kafka.update.topic=update-referral-topic diff --git a/health-services/project/src/main/resources/db/migration/main/V20230807130400__adverse_event_create_ddl.sql b/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928120100__side_effect_create_ddl.sql similarity index 62% rename from health-services/project/src/main/resources/db/migration/main/V20230807130400__adverse_event_create_ddl.sql rename to health-services/referralmanagement/src/main/resources/db/migration/main/V20230928120100__side_effect_create_ddl.sql index 7102792ecde..215a06217be 100644 --- a/health-services/project/src/main/resources/db/migration/main/V20230807130400__adverse_event_create_ddl.sql +++ b/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928120100__side_effect_create_ddl.sql @@ -1,11 +1,10 @@ -CREATE TABLE ADVERSE_EVENT( +CREATE TABLE SIDE_EFFECT( id character varying(64), - clientReferenceId character varying(64), + clientReferenceId character varying(64) NOT NULL, tenantId character varying(1000), taskId character varying(64), - taskClientReferenceId character varying(64), + taskClientReferenceId character varying(64) NOT NULL, symptoms jsonb, - reAttempts bigint, createdBy character varying(64), createdTime bigint, lastModifiedBy character varying(64), @@ -14,6 +13,6 @@ CREATE TABLE ADVERSE_EVENT( clientLastModifiedTime bigint, rowVersion bigint, isDeleted bool, - CONSTRAINT uk_adverse_event PRIMARY KEY (id), - CONSTRAINT uk_adverse_event_clientReference_id unique (clientReferenceId) -); + CONSTRAINT uk_side_effect PRIMARY KEY (id), + CONSTRAINT uk_side_effect_clientReference_id unique (clientReferenceId) +); \ No newline at end of file diff --git a/health-services/referralmanagement/src/main/resources/referral-management-persister.yml b/health-services/referralmanagement/src/main/resources/referral-management-persister.yml index 331152b0b5c..933197462d0 100644 --- a/health-services/referralmanagement/src/main/resources/referral-management-persister.yml +++ b/health-services/referralmanagement/src/main/resources/referral-management-persister.yml @@ -2,11 +2,11 @@ serviceMaps: serviceName: referralmanagement mappings: - version: 1.0 - description: Saves a adverse event - fromTopic: save-adverse-event-topic + description: Saves a side effect + fromTopic: save-side-effect-topic isTransaction: true queryMaps: - - query: INSERT INTO ADVERSE_EVENT(id, clientReferenceId, tenantId, taskId, taskClientReferenceId, projectBeneficiaryId, projectBeneficiaryClientReferenceId,symptoms, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedBy, clientCreatedTime, clientLastModifiedBy, clientLastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); + - query: INSERT INTO SIDE_EFFECT(id, clientReferenceId, tenantId, taskId, taskClientReferenceId, projectBeneficiaryId, projectBeneficiaryClientReferenceId,symptoms, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedBy, clientCreatedTime, clientLastModifiedBy, clientLastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); basePath: $.* jsonMaps: - jsonPath: $.*.id @@ -31,11 +31,11 @@ serviceMaps: - jsonPath: $.*.isDeleted - version: 1.0 - description: Updates a adverse event - fromTopic: update-adverse-event-topic + description: Updates a side effect + fromTopic: update-side-effect-topic isTransaction: true queryMaps: - - query: UPDATE ADVERSE_EVENT SET tenantId = ?, taskId = ?, taskClientReferenceId = ?, projectBeneficiaryId = ?, projectBeneficiaryClientReferenceId = ?, symptoms = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + - query: UPDATE SIDE_EFFECT SET tenantId = ?, taskId = ?, taskClientReferenceId = ?, projectBeneficiaryId = ?, projectBeneficiaryClientReferenceId = ?, symptoms = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; basePath: $.* jsonMaps: - jsonPath: $.*.tenantId @@ -55,11 +55,11 @@ serviceMaps: - jsonPath: $.*.id - version: 1.0 - description: Deletes a adverse event - fromTopic: delete-adverse-event-topic + description: Deletes a side effect + fromTopic: delete-side-effect-topic isTransaction: true queryMaps: - - query: UPDATE ADVERSE_EVENT SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + - query: UPDATE SIDE_EFFECT SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; basePath: $.* jsonMaps: - jsonPath: $.*.auditDetails.lastModifiedBy diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventRequestTestBuilder.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventRequestTestBuilder.java deleted file mode 100644 index 983b5dee405..00000000000 --- a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventRequestTestBuilder.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.egov.referralmanagement.helper; - -import org.egov.common.helper.RequestInfoTestBuilder; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventRequest; - -import java.util.ArrayList; - -public class AdverseEventRequestTestBuilder { - private AdverseEventRequest.AdverseEventRequestBuilder builder; - - private ArrayList adverseEvent = new ArrayList(); - - public AdverseEventRequestTestBuilder() { - this.builder = AdverseEventRequest.builder(); - } - - public static AdverseEventRequestTestBuilder builder() { - return new AdverseEventRequestTestBuilder(); - } - - public AdverseEventRequest build() { - return this.builder.build(); - } - - public AdverseEventRequestTestBuilder withOneAdverseEvent() { - builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) - .adverseEvent(AdverseEventTestBuilder.builder().withId().withAuditDetails().build()); - return this; - } - - public AdverseEventRequestTestBuilder withApiOperationNotNullAndNotCreate() { - builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) - .adverseEvent(AdverseEventTestBuilder.builder().withIdNull().build()); - return this; - } - - public AdverseEventRequestTestBuilder withApiOperationNotUpdate() { - builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) - .adverseEvent(AdverseEventTestBuilder.builder().withIdNull().build()); - return this; - } - - public AdverseEventRequestTestBuilder withOneAdverseEventHavingId() { - builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) - .adverseEvent(AdverseEventTestBuilder.builder().withId().withAuditDetails().build()); - return this; - } - - public AdverseEventRequestTestBuilder withBadTenantIdInOneAdverseEvent() { - - builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) - .adverseEvent(AdverseEventTestBuilder.builder().withIdNull().withBadTenantId().build()); - return this; - } - - public AdverseEventRequestTestBuilder withRequestInfo(){ - this.builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()); - return this; - } -} diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectRequestTestBuilder.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectRequestTestBuilder.java new file mode 100644 index 00000000000..d5bf7a9195c --- /dev/null +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectRequestTestBuilder.java @@ -0,0 +1,60 @@ +package org.egov.referralmanagement.helper; + +import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectRequest; + +import java.util.ArrayList; + +public class SideEffectRequestTestBuilder { + private SideEffectRequest.SideEffectRequestBuilder builder; + + private ArrayList sideEffect = new ArrayList(); + + public SideEffectRequestTestBuilder() { + this.builder = SideEffectRequest.builder(); + } + + public static SideEffectRequestTestBuilder builder() { + return new SideEffectRequestTestBuilder(); + } + + public SideEffectRequest build() { + return this.builder.build(); + } + + public SideEffectRequestTestBuilder withOneSideEffect() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .sideEffect(SideEffectTestBuilder.builder().withId().withAuditDetails().build()); + return this; + } + + public SideEffectRequestTestBuilder withApiOperationNotNullAndNotCreate() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .sideEffect(SideEffectTestBuilder.builder().withIdNull().build()); + return this; + } + + public SideEffectRequestTestBuilder withApiOperationNotUpdate() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .sideEffect(SideEffectTestBuilder.builder().withIdNull().build()); + return this; + } + + public SideEffectRequestTestBuilder withOneSideEffectHavingId() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .sideEffect(SideEffectTestBuilder.builder().withId().withAuditDetails().build()); + return this; + } + + public SideEffectRequestTestBuilder withBadTenantIdInOneSideEffect() { + + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .sideEffect(SideEffectTestBuilder.builder().withIdNull().withBadTenantId().build()); + return this; + } + + public SideEffectRequestTestBuilder withRequestInfo(){ + this.builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()); + return this; + } +} diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventTestBuilder.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java similarity index 61% rename from health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventTestBuilder.java rename to health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java index 1af8b9e9d10..d4c3c04c686 100644 --- a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventTestBuilder.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java @@ -1,30 +1,30 @@ package org.egov.referralmanagement.helper; import org.egov.common.helper.AuditDetailsTestBuilder; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import java.util.ArrayList; import java.util.Arrays; -public class AdverseEventTestBuilder { +public class SideEffectTestBuilder { - private AdverseEvent.AdverseEventBuilder builder; + private SideEffect.SideEffectBuilder builder; - public AdverseEventTestBuilder() { - this.builder = AdverseEvent.builder(); + public SideEffectTestBuilder() { + this.builder = SideEffect.builder(); } - public static AdverseEventTestBuilder builder() { - return new AdverseEventTestBuilder(); + public static SideEffectTestBuilder builder() { + return new SideEffectTestBuilder(); } - public AdverseEvent build() { + public SideEffect build() { return this.builder.hasErrors(false).build(); } - public AdverseEventTestBuilder withIdNull() { + public SideEffectTestBuilder withIdNull() { this.builder.taskId("some-task-id") - .clientReferenceId("adverseEventClientReferenceId") + .clientReferenceId("sideEffectClientReferenceId") .id(null) .taskClientReferenceId("null") .symptoms(new ArrayList<>(Arrays.asList("fever"))) @@ -33,28 +33,28 @@ public AdverseEventTestBuilder withIdNull() { return this; } - public AdverseEventTestBuilder withId() { + public SideEffectTestBuilder withId() { withIdNull().builder.id("some-id").taskId("some-task-id") - .clientReferenceId("adverseEventClientReferenceId") + .clientReferenceId("sideEffectClientReferenceId") .taskClientReferenceId("null") .symptoms(new ArrayList<>(Arrays.asList("fever"))) .tenantId("some-tenant-id"); return this; } - public AdverseEventTestBuilder withId(String id) { + public SideEffectTestBuilder withId(String id) { this.builder.id(id); return this; } - public AdverseEventTestBuilder withBadTenantId() { + public SideEffectTestBuilder withBadTenantId() { this.builder.tenantId(null); return this; } - public AdverseEventTestBuilder goodAdverseEvent() { + public SideEffectTestBuilder goodSideEffect() { this.builder.id("some-id").taskId("some-task-id") - .clientReferenceId("adverseEventClientReferenceId") + .clientReferenceId("sideEffectClientReferenceId") .taskClientReferenceId("null") .symptoms(new ArrayList<>(Arrays.asList("fever"))) .tenantId("some-tenant-id") @@ -64,12 +64,12 @@ public AdverseEventTestBuilder goodAdverseEvent() { return this; } - public AdverseEventTestBuilder withAuditDetails() { + public SideEffectTestBuilder withAuditDetails() { this.builder.auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); return this; } - public AdverseEventTestBuilder withDeleted() { + public SideEffectTestBuilder withDeleted() { this.builder.isDeleted(true); return this; } diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/AdverseEventApiControllerTest.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java similarity index 60% rename from health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/AdverseEventApiControllerTest.java rename to health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java index e6a7ad40b98..5acd4f7a594 100644 --- a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/AdverseEventApiControllerTest.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java @@ -3,16 +3,16 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.egov.referralmanagement.TestConfiguration; import org.egov.referralmanagement.config.ReferralManagementConfiguration; -import org.egov.referralmanagement.helper.AdverseEventRequestTestBuilder; -import org.egov.referralmanagement.helper.AdverseEventTestBuilder; -import org.egov.referralmanagement.service.AdverseEventService; +import org.egov.referralmanagement.helper.SideEffectRequestTestBuilder; +import org.egov.referralmanagement.helper.SideEffectTestBuilder; +import org.egov.referralmanagement.service.SideEffectService; import org.egov.common.helper.RequestInfoTestBuilder; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkResponse; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventRequest; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventResponse; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearch; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearchRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkResponse; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectResponse; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearch; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearchRequest; import org.egov.common.producer.Producer; import org.egov.tracer.model.CustomException; import org.egov.tracer.model.ErrorRes; @@ -35,9 +35,9 @@ import java.util.Arrays; import java.util.List; -@WebMvcTest(AdverseEventApiController.class) +@WebMvcTest(SideEffectApiController.class) @Import(TestConfiguration.class) -public class AdverseEventApiControllerTest { +public class SideEffectApiControllerTest { @Autowired private MockMvc mockMvc; @@ -46,7 +46,7 @@ public class AdverseEventApiControllerTest { private ObjectMapper objectMapper; @MockBean - private AdverseEventService adverseEventService; + private SideEffectService sideEffectService; @MockBean private Producer producer; @@ -55,45 +55,45 @@ public class AdverseEventApiControllerTest { ReferralManagementConfiguration referralManagementConfiguration; @Test - @DisplayName("should create adverse event and return with 202 accepted") - void shouldCreateAdverseEventAndReturnWith202Accepted() throws Exception { - AdverseEventRequest request = AdverseEventRequestTestBuilder.builder() - .withOneAdverseEvent() + @DisplayName("should create side effect and return with 202 accepted") + void shouldCreateSideEffectAndReturnWith202Accepted() throws Exception { + SideEffectRequest request = SideEffectRequestTestBuilder.builder() + .withOneSideEffect() .withApiOperationNotUpdate() .build(); - List adverseEvents = getAdverseEvents(); - Mockito.when(adverseEventService.create(ArgumentMatchers.any(AdverseEventRequest.class))).thenReturn(adverseEvents.get(0)); + List sideEffects = getSideEffects(); + Mockito.when(sideEffectService.create(ArgumentMatchers.any(SideEffectRequest.class))).thenReturn(sideEffects.get(0)); - final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/adverse_event/v1/_create") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side_effect/v1/_create") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andExpect(MockMvcResultMatchers.status().isAccepted()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andReturn(); String responseStr = result.getResponse().getContentAsString(); - AdverseEventResponse response = objectMapper.readValue(responseStr, AdverseEventResponse.class); + SideEffectResponse response = objectMapper.readValue(responseStr, SideEffectResponse.class); - Assertions.assertNotNull(response.getAdverseEvent()); - Assertions.assertNotNull(response.getAdverseEvent().getId()); + Assertions.assertNotNull(response.getSideEffect()); + Assertions.assertNotNull(response.getSideEffect().getId()); Assertions.assertEquals("successful", response.getResponseInfo().getStatus()); } - private List getAdverseEvents() { - AdverseEvent adverseEvent = AdverseEventTestBuilder.builder().withId().build(); - List adverseEvents = new ArrayList<>(); - adverseEvents.add(adverseEvent); - return adverseEvents; + private List getSideEffects() { + SideEffect sideEffect = SideEffectTestBuilder.builder().withId().build(); + List sideEffects = new ArrayList<>(); + sideEffects.add(sideEffect); + return sideEffects; } @Test @DisplayName("should send error response with error details with 400 bad request for create") void shouldSendErrorResWithErrorDetailsWith400BadRequestForCreate() throws Exception { - final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/adverse_event/v1/_create") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side_effect/v1/_create") .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(AdverseEventRequestTestBuilder.builder() - .withOneAdverseEvent() - .withBadTenantIdInOneAdverseEvent() + .content(objectMapper.writeValueAsString(SideEffectRequestTestBuilder.builder() + .withOneSideEffect() + .withBadTenantIdInOneSideEffect() .build()))) .andExpect(MockMvcResultMatchers.status().isBadRequest()) .andReturn(); @@ -105,37 +105,37 @@ void shouldSendErrorResWithErrorDetailsWith400BadRequestForCreate() throws Excep } @Test - @DisplayName("should update adverse event and return with 202 accepted") - void shouldUpdateAdverseEventAndReturnWith202Accepted() throws Exception { - AdverseEventRequest request = AdverseEventRequestTestBuilder.builder() - .withOneAdverseEventHavingId() + @DisplayName("should update side effect and return with 202 accepted") + void shouldUpdateSideEffectAndReturnWith202Accepted() throws Exception { + SideEffectRequest request = SideEffectRequestTestBuilder.builder() + .withOneSideEffectHavingId() .withApiOperationNotNullAndNotCreate() .build(); - AdverseEvent adverseEvent = AdverseEventTestBuilder.builder().withId().build(); - Mockito.when(adverseEventService.update(ArgumentMatchers.any(AdverseEventRequest.class))).thenReturn(adverseEvent); + SideEffect sideEffect = SideEffectTestBuilder.builder().withId().build(); + Mockito.when(sideEffectService.update(ArgumentMatchers.any(SideEffectRequest.class))).thenReturn(sideEffect); - final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/adverse_event/v1/_update") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side_effect/v1/_update") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andExpect(MockMvcResultMatchers.status().isAccepted()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andReturn(); String responseStr = result.getResponse().getContentAsString(); - AdverseEventResponse response = objectMapper.readValue(responseStr, AdverseEventResponse.class); + SideEffectResponse response = objectMapper.readValue(responseStr, SideEffectResponse.class); - Assertions.assertNotNull(response.getAdverseEvent()); - Assertions.assertNotNull(response.getAdverseEvent().getId()); + Assertions.assertNotNull(response.getSideEffect()); + Assertions.assertNotNull(response.getSideEffect().getId()); Assertions.assertEquals("successful", response.getResponseInfo().getStatus()); } @Test @DisplayName("should send error response with error details with 400 bad request for update") void shouldSendErrorResWithErrorDetailsWith400BadRequestForUpdate() throws Exception { - final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/adverse_event/v1/_update") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side_effect/v1/_update") .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(AdverseEventRequestTestBuilder.builder() - .withOneAdverseEventHavingId() - .withBadTenantIdInOneAdverseEvent() + .content(objectMapper.writeValueAsString(SideEffectRequestTestBuilder.builder() + .withOneSideEffectHavingId() + .withBadTenantIdInOneSideEffect() .build()))) .andExpect(MockMvcResultMatchers.status().isBadRequest()) .andReturn(); @@ -149,52 +149,52 @@ void shouldSendErrorResWithErrorDetailsWith400BadRequestForUpdate() throws Excep @Test @DisplayName("Should accept search request and return response as accepted") - void shouldAcceptSearchRequestAndReturnAdverseEvent() throws Exception { + void shouldAcceptSearchRequestAndReturnSideEffect() throws Exception { - AdverseEventSearchRequest adverseEventSearchRequest = AdverseEventSearchRequest.builder().adverseEvent( - AdverseEventSearch.builder().taskId("some-task-id").build() + SideEffectSearchRequest sideEffectSearchRequest = SideEffectSearchRequest.builder().sideEffect( + SideEffectSearch.builder().taskId("some-task-id").build() ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); - Mockito.when(adverseEventService.search(ArgumentMatchers.any(AdverseEventSearchRequest.class), + Mockito.when(sideEffectService.search(ArgumentMatchers.any(SideEffectSearchRequest.class), ArgumentMatchers.any(Integer.class), ArgumentMatchers.any(Integer.class), ArgumentMatchers.any(String.class), ArgumentMatchers.any(Long.class), - ArgumentMatchers.any(Boolean.class))).thenReturn(Arrays.asList(AdverseEventTestBuilder.builder().withId().withAuditDetails().build())); + ArgumentMatchers.any(Boolean.class))).thenReturn(Arrays.asList(SideEffectTestBuilder.builder().withId().withAuditDetails().build())); final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post( - "/adverse_event/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") + "/side_effect/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(adverseEventSearchRequest))) + .content(objectMapper.writeValueAsString(sideEffectSearchRequest))) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andReturn(); String responseStr = result.getResponse().getContentAsString(); - AdverseEventBulkResponse response = objectMapper.readValue(responseStr, - AdverseEventBulkResponse.class); + SideEffectBulkResponse response = objectMapper.readValue(responseStr, + SideEffectBulkResponse.class); - Assertions.assertEquals(response.getAdverseEvents().size(), 1); + Assertions.assertEquals(response.getSideEffects().size(), 1); } @Test @DisplayName("Should accept search request and return response as accepted") void shouldThrowExceptionIfNoResultFound() throws Exception { - AdverseEventSearchRequest adverseEventSearchRequest = AdverseEventSearchRequest.builder().adverseEvent( - AdverseEventSearch.builder().taskId("some-task-id").build() + SideEffectSearchRequest sideEffectSearchRequest = SideEffectSearchRequest.builder().sideEffect( + SideEffectSearch.builder().taskId("some-task-id").build() ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); - Mockito.when(adverseEventService.search(ArgumentMatchers.any(AdverseEventSearchRequest.class), + Mockito.when(sideEffectService.search(ArgumentMatchers.any(SideEffectSearchRequest.class), ArgumentMatchers.any(Integer.class), ArgumentMatchers.any(Integer.class), ArgumentMatchers.any(String.class), ArgumentMatchers.any(Long.class), - ArgumentMatchers.any(Boolean.class))).thenThrow(new CustomException("NO_RESULT_FOUND", "No Adverse Event found.")); + ArgumentMatchers.any(Boolean.class))).thenThrow(new CustomException("NO_RESULT_FOUND", "No Side Effect found.")); - final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/adverse_event/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side_effect/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(adverseEventSearchRequest))) + .content(objectMapper.writeValueAsString(sideEffectSearchRequest))) .andExpect(MockMvcResultMatchers.status().isBadRequest()) .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) .andReturn(); From 57f121f40b927644abec877aea66a69b2ae9bcd1 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 25 Sep 2023 11:53:07 +0530 Subject: [PATCH 167/283] HLM-3376: Added changes for referral management --- .../consumer/ReferralManagementConsumer.java | 71 ++++++ .../service/ReferralManagementService.java | 229 ++++++++++++++++++ .../ReferralManagementEnrichmentService.java | 56 +++++ .../ReferralManagementApiController.java | 141 +++++++++++ .../adrm/referralmanagement/Referral.java | 89 +++++++ .../ReferralBulkRequest.java | 38 +++ .../ReferralBulkResponse.java | 36 +++ .../referralmanagement/ReferralRequest.java | 29 +++ .../referralmanagement/ReferralResponse.java | 29 +++ .../referralmanagement/ReferralSearch.java | 29 +++ .../ReferralSearchRequest.java | 28 +++ 11 files changed, 775 insertions(+) create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/consumer/ReferralManagementConsumer.java create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/ReferralManagementEnrichmentService.java create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/web/controllers/ReferralManagementApiController.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkRequest.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkResponse.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralRequest.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralResponse.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearch.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearchRequest.java diff --git a/health-services/adrm/src/main/java/org/egov/adrm/consumer/ReferralManagementConsumer.java b/health-services/adrm/src/main/java/org/egov/adrm/consumer/ReferralManagementConsumer.java new file mode 100644 index 00000000000..190ae112765 --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/consumer/ReferralManagementConsumer.java @@ -0,0 +1,71 @@ +package org.egov.adrm.consumer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.adrm.service.ReferralManagementService; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +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 ReferralManagementConsumer { + + private final ReferralManagementService referralManagementService; + + private final ObjectMapper objectMapper; + + @Autowired + public ReferralManagementConsumer(ReferralManagementService referralManagementService, + @Qualifier("objectMapper") ObjectMapper objectMapper) { + this.referralManagementService = referralManagementService; + this.objectMapper = objectMapper; + } + + @KafkaListener(topics = "${adrm.referralmanagement.consumer.bulk.create.topic}") + public void bulkCreate(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + ReferralBulkRequest request = objectMapper.convertValue(consumerRecord, ReferralBulkRequest.class); + referralManagementService.create(request, true); + } catch (Exception exception) { + log.error("Error in Referral consumer bulk create", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_ADRM_REFERRAL_MANAGEMENT_CREATE", exception.getMessage()); + } + } + + @KafkaListener(topics = "${adrm.referralmanagement.consumer.bulk.update.topic}") + public void bulkUpdate(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + ReferralBulkRequest request = objectMapper.convertValue(consumerRecord, ReferralBulkRequest.class); + referralManagementService.update(request, true); + } catch (Exception exception) { + log.error("Error in Referral consumer bulk update", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_ADRM_REFERRAL_MANAGEMENT_CREATE", exception.getMessage()); + } + } + + @KafkaListener(topics = "${adrm.referralmanagement.consumer.bulk.delete.topic}") + public void bulkDelete(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + ReferralBulkRequest request = objectMapper.convertValue(consumerRecord, ReferralBulkRequest.class); + referralManagementService.delete(request, true); + } catch (Exception exception) { + log.error("Error in Referral consumer bulk delete", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + throw new CustomException("HCM_ADRM_REFERRAL_MANAGEMENT_CREATE", exception.getMessage()); + } + } +} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java b/health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java new file mode 100644 index 00000000000..db88aafc42b --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java @@ -0,0 +1,229 @@ +package org.egov.adrm.service; + +import lombok.extern.slf4j.Slf4j; +import org.egov.adrm.Constants; +import org.egov.adrm.config.AdrmConfiguration; +import org.egov.adrm.repository.ReferralManagementRepository; +import org.egov.adrm.service.enrichment.ReferralManagementEnrichmentService; +import org.egov.adrm.validator.adverseevent.AdIsDeletedValidator; +import org.egov.adrm.validator.adverseevent.AdNonExistentEntityValidator; +import org.egov.adrm.validator.adverseevent.AdNullIdValidator; +import org.egov.adrm.validator.adverseevent.AdProjectTaskIdValidator; +import org.egov.adrm.validator.adverseevent.AdUniqueEntityValidator; +import org.egov.common.ds.Tuple; +import org.egov.common.models.ErrorDetails; +import org.egov.common.models.adrm.referralmanagement.Referral; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.adrm.referralmanagement.ReferralRequest; +import org.egov.common.models.adrm.referralmanagement.ReferralSearchRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.egov.common.validator.Validator; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Service; +import org.springframework.util.ReflectionUtils; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +@Service +@Slf4j +public class ReferralManagementService { + private final IdGenService idGenService; + + private final ReferralManagementRepository referralManagementRepository; + + private final AdrmConfiguration adrmConfiguration; + + private final ReferralManagementEnrichmentService referralManagementEnrichmentService; + + private final List> validators; + + private final Predicate> isApplicableForCreate = validator -> + validator.getClass().equals(AdProjectTaskIdValidator.class); + + private final Predicate> isApplicableForUpdate = validator -> + validator.getClass().equals(AdProjectTaskIdValidator.class) + || validator.getClass().equals(AdNullIdValidator.class) + || validator.getClass().equals(AdIsDeletedValidator.class) + || validator.getClass().equals(AdUniqueEntityValidator.class) + || validator.getClass().equals(AdNonExistentEntityValidator.class); + + private final Predicate> isApplicableForDelete = validator -> + validator.getClass().equals(AdNullIdValidator.class) + || validator.getClass().equals(AdNonExistentEntityValidator.class); + + + public ReferralManagementService(IdGenService idGenService, ReferralManagementRepository referralManagementRepository, AdrmConfiguration adrmConfiguration, ReferralManagementEnrichmentService referralManagementEnrichmentService, List> validators) { + this.idGenService = idGenService; + this.referralManagementRepository = referralManagementRepository; + this.adrmConfiguration = adrmConfiguration; + this.referralManagementEnrichmentService = referralManagementEnrichmentService; + this.validators = validators; + } + + public Referral create(ReferralRequest request) { + log.info("received request to create adverse events"); + ReferralBulkRequest bulkRequest = ReferralBulkRequest.builder().requestInfo(request.getRequestInfo()) + .referrals(Collections.singletonList(request.getReferral())).build(); + log.info("creating bulk request"); + return create(bulkRequest, false).get(0); + } + + public List create(ReferralBulkRequest referralRequest, boolean isBulk) { + log.info("received request to create bulk adverse events"); + Tuple, Map> tuple = validate(validators, + isApplicableForCreate, referralRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validReferrals = tuple.getX(); + + try { + if (!validReferrals.isEmpty()) { + log.info("processing {} valid entities", validReferrals.size()); + referralManagementEnrichmentService.create(validReferrals, referralRequest); + referralManagementRepository.save(validReferrals, + adrmConfiguration.getCreateReferralTopic()); + log.info("successfully created adverse events"); + } + } catch (Exception exception) { + log.error("error occurred while creating adverse events: {}", exception.getMessage()); + populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, + exception, Constants.SET_ADVERSE_EVENTS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validReferrals; + } + + public Referral update(ReferralRequest request) { + log.info("received request to update adverse event"); + ReferralBulkRequest bulkRequest = ReferralBulkRequest.builder().requestInfo(request.getRequestInfo()) + .referrals(Collections.singletonList(request.getReferral())).build(); + log.info("creating bulk request"); + return update(bulkRequest, false).get(0); + } + + public List update(ReferralBulkRequest referralRequest, boolean isBulk) { + log.info("received request to update bulk adverse event"); + Tuple, Map> tuple = validate(validators, + isApplicableForUpdate, referralRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validReferrals = tuple.getX(); + + try { + if (!validReferrals.isEmpty()) { + log.info("processing {} valid entities", validReferrals.size()); + referralManagementEnrichmentService.update(validReferrals, referralRequest); + referralManagementRepository.save(validReferrals, + adrmConfiguration.getUpdateReferralTopic()); + log.info("successfully updated bulk adverse events"); + } + } catch (Exception exception) { + log.error("error occurred while updating adverse events", exception); + populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, + exception, Constants.SET_ADVERSE_EVENTS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validReferrals; + } + + public List search(ReferralSearchRequest referralSearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { + log.info("received request to search adverse events"); + String idFieldName = getIdFieldName(referralSearchRequest.getReferral()); + if (isSearchByIdOnly(referralSearchRequest.getReferral(), idFieldName)) { + log.info("searching adverse events by id"); + List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections + .singletonList(referralSearchRequest.getReferral())), + referralSearchRequest.getReferral()); + log.info("fetching adverse events with ids: {}", ids); + return referralManagementRepository.findById(ids, includeDeleted, idFieldName).stream() + .filter(lastChangedSince(lastChangedSince)) + .filter(havingTenantId(tenantId)) + .filter(includeDeleted(includeDeleted)) + .collect(Collectors.toList()); + } + log.info("searching adverse events using criteria"); + return referralManagementRepository.find(referralSearchRequest.getReferral(), + limit, offset, tenantId, lastChangedSince, includeDeleted); + } + + public Referral delete(ReferralRequest referralRequest) { + log.info("received request to delete a adverse event"); + ReferralBulkRequest bulkRequest = ReferralBulkRequest.builder().requestInfo(referralRequest.getRequestInfo()) + .referrals(Collections.singletonList(referralRequest.getReferral())).build(); + log.info("creating bulk request"); + return delete(bulkRequest, false).get(0); + } + + public List delete(ReferralBulkRequest referralRequest, boolean isBulk) { + Tuple, Map> tuple = validate(validators, + isApplicableForDelete, referralRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validReferrals = tuple.getX(); + + try { + if (!validReferrals.isEmpty()) { + log.info("processing {} valid entities", validReferrals.size()); + List referralIds = validReferrals.stream().map(entity -> entity.getId()).collect(Collectors.toSet()).stream().collect(Collectors.toList()); + List existingReferrals = referralManagementRepository + .findById(referralIds, false); + referralManagementEnrichmentService.delete(existingReferrals, referralRequest); + referralManagementRepository.save(existingReferrals, + adrmConfiguration.getDeleteReferralTopic()); + log.info("successfully deleted entities"); + } + } catch (Exception exception) { + log.error("error occurred while deleting entities: {}", exception); + populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, + exception, Constants.SET_ADVERSE_EVENTS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validReferrals; + } + + public void putInCache(List referrals) { + log.info("putting {} adverse events in cache", referrals.size()); + referralManagementRepository.putInCache(referrals); + log.info("successfully put adverse events in cache"); + } + + private Tuple, Map> validate( + List> validators, + Predicate> isApplicable, + ReferralBulkRequest request, + boolean isBulk + ) { + log.info("validating request"); + Map errorDetailsMap = CommonUtils.validate(validators, + isApplicable, request, + Constants.SET_ADVERSE_EVENTS); + if (!errorDetailsMap.isEmpty() && !isBulk) { + log.error("validation error occurred. error details: {}", errorDetailsMap.values().toString()); + throw new CustomException(Constants.VALIDATION_ERROR, errorDetailsMap.values().toString()); + } + List validReferrals = request.getReferrals().stream() + .filter(notHavingErrors()).collect(Collectors.toList()); + log.info("validation successful, found valid adverse events"); + return new Tuple<>(validReferrals, errorDetailsMap); + } +} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/ReferralManagementEnrichmentService.java b/health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/ReferralManagementEnrichmentService.java new file mode 100644 index 00000000000..552136b678c --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/ReferralManagementEnrichmentService.java @@ -0,0 +1,56 @@ +package org.egov.adrm.service.enrichment; + +import lombok.extern.slf4j.Slf4j; +import org.egov.adrm.config.AdrmConfiguration; +import org.egov.adrm.repository.ReferralManagementRepository; +import org.egov.common.models.adrm.referralmanagement.Referral; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +import static org.egov.common.utils.CommonUtils.enrichForCreate; +import static org.egov.common.utils.CommonUtils.enrichForDelete; +import static org.egov.common.utils.CommonUtils.enrichForUpdate; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; + +@Component +@Slf4j +public class ReferralManagementEnrichmentService { + private final IdGenService idGenService; + + private final AdrmConfiguration adrmConfiguration; + + private final ReferralManagementRepository referralManagementRepository; + + public ReferralManagementEnrichmentService(IdGenService idGenService, AdrmConfiguration adrmConfiguration, ReferralManagementRepository referralManagementRepository) { + this.idGenService = idGenService; + this.adrmConfiguration = adrmConfiguration; + this.referralManagementRepository = referralManagementRepository; + } + + public void create(List entities, ReferralBulkRequest request) throws Exception { + log.info("starting the enrichment for create referrals"); + log.info("generating IDs using UUID"); + List idList = CommonUtils.uuidSupplier().apply(entities.size()); + log.info("enriching referrals with generated IDs"); + enrichForCreate(entities, idList, request.getRequestInfo()); + log.info("enrichment done"); + } + + public void update(List entities, ReferralBulkRequest request) { + log.info("starting the enrichment for create referrals"); + Map referralMap = getIdToObjMap(entities); + enrichForUpdate(referralMap, entities, request); + log.info("enrichment done"); + } + + public void delete(List entities, ReferralBulkRequest request) { + log.info("starting the enrichment for delete referrals"); + enrichForDelete(entities, request.getRequestInfo(), true); + log.info("enrichment done"); + } +} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/ReferralManagementApiController.java b/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/ReferralManagementApiController.java new file mode 100644 index 00000000000..42604fa739f --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/ReferralManagementApiController.java @@ -0,0 +1,141 @@ +package org.egov.adrm.web.controllers; + +import io.swagger.annotations.ApiParam; +import org.egov.adrm.config.AdrmConfiguration; +import org.egov.adrm.service.ReferralManagementService; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.adrm.referralmanagement.Referral; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkResponse; +import org.egov.common.models.adrm.referralmanagement.ReferralRequest; +import org.egov.common.models.adrm.referralmanagement.ReferralResponse; +import org.egov.common.models.adrm.referralmanagement.ReferralSearchRequest; +import org.egov.common.producer.Producer; +import org.egov.common.utils.ResponseInfoFactory; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; +import java.util.List; + +@Controller +@RequestMapping("/referral-management") +@Validated +public class ReferralManagementApiController { + private final HttpServletRequest httpServletRequest; + + private final ReferralManagementService referralManagementService; + + private final Producer producer; + + private final AdrmConfiguration adrmConfiguration; + + public ReferralManagementApiController( + HttpServletRequest httpServletRequest, + ReferralManagementService referralManagementService, + Producer producer, + AdrmConfiguration adrmConfiguration + ) { + this.httpServletRequest = httpServletRequest; + this.referralManagementService = referralManagementService; + this.producer = producer; + this.adrmConfiguration = adrmConfiguration; + } + + @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) + public ResponseEntity referralV1CreatePost(@ApiParam(value = "Capture details of Referral", required = true) @Valid @RequestBody ReferralRequest request) { + + Referral referral = referralManagementService.create(request); + ReferralResponse response = ReferralResponse.builder() + .referral(referral) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } + + + + @RequestMapping(value = "/v1/bulk/_create", method = RequestMethod.POST) + public ResponseEntity referralBulkV1CreatePost(@ApiParam(value = "Capture details of Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + referralManagementService.putInCache(request.getReferrals()); + producer.push(adrmConfiguration.getCreateReferralBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + + @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) + public ResponseEntity referralV1SearchPost(@ApiParam(value = "Referral Search.", required = true) @Valid @RequestBody ReferralSearchRequest request, + @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, + @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, + @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, + @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, + @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { + + List referrals = referralManagementService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); + ReferralBulkResponse response = ReferralBulkResponse.builder().responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)).referrals(referrals).build(); + + return ResponseEntity.status(HttpStatus.OK).body(response); + } + + @RequestMapping(value = "/v1/_update", method = RequestMethod.POST) + public ResponseEntity referralV1UpdatePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralRequest request) { + Referral referral = referralManagementService.update(request); + + ReferralResponse response = ReferralResponse.builder() + .referral(referral) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + + } + + @RequestMapping(value = "/v1/bulk/_update", method = RequestMethod.POST) + public ResponseEntity referralV1BulkUpdatePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + producer.push(adrmConfiguration.getUpdateReferralBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + + @RequestMapping(value = "/v1/_delete", method = RequestMethod.POST) + public ResponseEntity referralV1DeletePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralRequest request) { + Referral referral = referralManagementService.delete(request); + + ReferralResponse response = ReferralResponse.builder() + .referral(referral) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + + } + + @RequestMapping(value = "/v1/bulk/_delete", method = RequestMethod.POST) + public ResponseEntity referralV1BulkDeletePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + producer.push(adrmConfiguration.getDeleteReferralBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java new file mode 100644 index 00000000000..b7fbf6deff4 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java @@ -0,0 +1,89 @@ +package org.egov.common.models.adrm.referralmanagement; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.models.adrm.adverseevent.AdverseEvent; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class Referral { + + @JsonProperty("id") + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("clientReferenceId") + @Size(min = 2, max = 64) + private String clientReferenceId = null; + + @JsonProperty("projectBeneficiaryId") + @Size(min = 2, max = 64) + private String projectBeneficiaryId = null; + + @JsonProperty("projectBeneficiaryClientReferenceId") + @Size(min = 2, max = 64) + private String projectBeneficiaryClientReferenceId = null; + + @JsonProperty("referringPartyId") + @Size(min = 2, max = 64) + private String referringPartyId = null; + + @JsonProperty("referringPartyClientReferenceId") + @Size(min = 2, max = 64) + private String referringPartyClientReferenceId = null; + + @JsonProperty("referredToType") + private String referredToType = null; + + @JsonProperty("referredToId") + @Size(min = 2, max = 64) + private String referredToId = null; + + @JsonProperty("referredToClientReferenceId") + @Size(min = 2, max = 64) + private String referredToClientReferenceId = null; + + @JsonProperty("reasons") + @NotNull + @Size(min=1) + private List reasons = null; + + @JsonProperty("adverseEvent") + private AdverseEvent adverseEvent = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min=2, max = 1000) + private String tenantId = null; + + @JsonProperty("isDeleted") + private Boolean isDeleted = Boolean.FALSE; + + @JsonProperty("rowVersion") + private Integer rowVersion = null; + + @JsonProperty("auditDetails") + @Valid + private AuditDetails auditDetails = null; + + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails = null; + + @JsonIgnore + private Boolean hasErrors = Boolean.FALSE; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkRequest.java new file mode 100644 index 00000000000..752c8bfdb26 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkRequest.java @@ -0,0 +1,38 @@ +package org.egov.common.models.adrm.referralmanagement; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.ArrayList; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ReferralBulkRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Referrals") + @NotNull + @Valid + @Size(min = 1) + private List referrals = new ArrayList<>(); + + public ReferralBulkRequest addReferralItem(Referral referralItem) { + this.referrals.add(referralItem); + return this; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkResponse.java new file mode 100644 index 00000000000..f34d1df7ae0 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkResponse.java @@ -0,0 +1,36 @@ +package org.egov.common.models.adrm.referralmanagement; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import java.util.ArrayList; +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ReferralBulkResponse { + @JsonProperty("ResponseInfo") + @NotNull + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Referrals") + @NotNull + @Valid + private List referrals = new ArrayList<>(); + + public ReferralBulkResponse addReferralItem(Referral referralItem) { + this.referrals.add(referralItem); + return this; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralRequest.java new file mode 100644 index 00000000000..ead7cedd3a2 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralRequest.java @@ -0,0 +1,29 @@ +package org.egov.common.models.adrm.referralmanagement; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ReferralRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Referral") + @NotNull + @Valid + private Referral referral = null; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralResponse.java new file mode 100644 index 00000000000..8bcae0afb31 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralResponse.java @@ -0,0 +1,29 @@ +package org.egov.common.models.adrm.referralmanagement; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ReferralResponse { + @JsonProperty("ResponseInfo") + @NotNull + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Referral") + @NotNull + @Valid + private Referral referral = null; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearch.java new file mode 100644 index 00000000000..c54be75749b --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearch.java @@ -0,0 +1,29 @@ +package org.egov.common.models.adrm.referralmanagement; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ReferralSearch { + @JsonProperty("id") + private List id = null; + + @JsonProperty("clientReferenceId") + private List clientReferenceId = null; + + @JsonProperty("projectBeneficiaryId") + private List projectBeneficiaryId = null; + + @JsonProperty("projectBeneficiaryClientReferenceId") + private List projectBeneficiaryClientReferenceId = null; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearchRequest.java new file mode 100644 index 00000000000..c87c2265dd9 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearchRequest.java @@ -0,0 +1,28 @@ +package org.egov.common.models.adrm.referralmanagement; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ReferralSearchRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Referral") + @Valid + private ReferralSearch referral = null; +} From 2d132e9336828894d2be13d0a3b33f0f32d548d0 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 25 Sep 2023 18:09:42 +0530 Subject: [PATCH 168/283] HLM-3376: Added Validators, updated Referral.java --- .../service/ReferralManagementService.java | 29 ++-- .../rm/RmFacilityEntitiesIdValidator.java | 100 +++++++++++++ .../validator/rm/RmIsDeletedValidator.java | 34 +++++ .../rm/RmNonExistentEntityValidator.java | 71 ++++++++++ .../adrm/validator/rm/RmNullIdValidator.java | 27 ++++ .../rm/RmProjectEntitiesIdValidator.java | 134 ++++++++++++++++++ .../validator/rm/RmUniqueEntityValidator.java | 47 ++++++ .../adrm/referralmanagement/Referral.java | 8 -- 8 files changed, 429 insertions(+), 21 deletions(-) create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmFacilityEntitiesIdValidator.java create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmIsDeletedValidator.java create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNonExistentEntityValidator.java create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNullIdValidator.java create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmProjectEntitiesIdValidator.java create mode 100644 health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmUniqueEntityValidator.java diff --git a/health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java b/health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java index db88aafc42b..0bd69750a27 100644 --- a/health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java +++ b/health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java @@ -5,11 +5,12 @@ import org.egov.adrm.config.AdrmConfiguration; import org.egov.adrm.repository.ReferralManagementRepository; import org.egov.adrm.service.enrichment.ReferralManagementEnrichmentService; -import org.egov.adrm.validator.adverseevent.AdIsDeletedValidator; -import org.egov.adrm.validator.adverseevent.AdNonExistentEntityValidator; -import org.egov.adrm.validator.adverseevent.AdNullIdValidator; -import org.egov.adrm.validator.adverseevent.AdProjectTaskIdValidator; -import org.egov.adrm.validator.adverseevent.AdUniqueEntityValidator; +import org.egov.adrm.validator.rm.RmFacilityEntitiesIdValidator; +import org.egov.adrm.validator.rm.RmIsDeletedValidator; +import org.egov.adrm.validator.rm.RmNonExistentEntityValidator; +import org.egov.adrm.validator.rm.RmNullIdValidator; +import org.egov.adrm.validator.rm.RmProjectEntitiesIdValidator; +import org.egov.adrm.validator.rm.RmUniqueEntityValidator; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.adrm.referralmanagement.Referral; @@ -53,18 +54,20 @@ public class ReferralManagementService { private final List> validators; private final Predicate> isApplicableForCreate = validator -> - validator.getClass().equals(AdProjectTaskIdValidator.class); + validator.getClass().equals(RmProjectEntitiesIdValidator.class) + || validator.getClass().equals(RmFacilityEntitiesIdValidator.class); private final Predicate> isApplicableForUpdate = validator -> - validator.getClass().equals(AdProjectTaskIdValidator.class) - || validator.getClass().equals(AdNullIdValidator.class) - || validator.getClass().equals(AdIsDeletedValidator.class) - || validator.getClass().equals(AdUniqueEntityValidator.class) - || validator.getClass().equals(AdNonExistentEntityValidator.class); + validator.getClass().equals(RmProjectEntitiesIdValidator.class) + || validator.getClass().equals(RmFacilityEntitiesIdValidator.class) + || validator.getClass().equals(RmNullIdValidator.class) + || validator.getClass().equals(RmIsDeletedValidator.class) + || validator.getClass().equals(RmUniqueEntityValidator.class) + || validator.getClass().equals(RmNonExistentEntityValidator.class); private final Predicate> isApplicableForDelete = validator -> - validator.getClass().equals(AdNullIdValidator.class) - || validator.getClass().equals(AdNonExistentEntityValidator.class); + validator.getClass().equals(RmNullIdValidator.class) + || validator.getClass().equals(RmNonExistentEntityValidator.class); public ReferralManagementService(IdGenService idGenService, ReferralManagementRepository referralManagementRepository, AdrmConfiguration adrmConfiguration, ReferralManagementEnrichmentService referralManagementEnrichmentService, List> validators) { diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmFacilityEntitiesIdValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmFacilityEntitiesIdValidator.java new file mode 100644 index 00000000000..340fc531ca3 --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmFacilityEntitiesIdValidator.java @@ -0,0 +1,100 @@ +package org.egov.adrm.validator.rm; + +import lombok.extern.slf4j.Slf4j; +import org.egov.adrm.config.AdrmConfiguration; +import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.adrm.referralmanagement.Referral; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.facility.Facility; +import org.egov.common.models.facility.FacilityBulkResponse; +import org.egov.common.models.facility.FacilitySearch; +import org.egov.common.models.facility.FacilitySearchRequest; +import org.egov.common.validator.Validator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.egov.adrm.Constants.FACILITY; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + + +@Component +@Order(value = 3) +@Slf4j +public class RmFacilityEntitiesIdValidator implements Validator { + private final ServiceRequestClient serviceRequestClient; + private final AdrmConfiguration adrmConfiguration; + + @Autowired + public RmFacilityEntitiesIdValidator(ServiceRequestClient serviceRequestClient, AdrmConfiguration adrmConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.adrmConfiguration = adrmConfiguration; + } + + + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating facility id"); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getReferrals(); + Map> tenantIdReferralMap = entities.stream().collect(Collectors.groupingBy(Referral::getTenantId)); + List tenantIds = new ArrayList<>(tenantIdReferralMap.keySet()); + tenantIds.forEach(tenantId -> { + List referralList = tenantIdReferralMap.get(tenantId); + if (!referralList.isEmpty()) { + List existingFacilityList = null; + final List facilityIdList = new ArrayList<>(); + try { + referralList.forEach(referral -> { + if(referral.getReferredToType().equals(FACILITY)){ + addIgnoreNull(facilityIdList, referral.getReferredToId()); + } + }); + FacilitySearch facilitySearch = FacilitySearch.builder() + .id(facilityIdList.isEmpty() ? null : facilityIdList) + .build(); + FacilityBulkResponse facilityBulkResponse = serviceRequestClient.fetchResult( + new StringBuilder(adrmConfiguration.getFacilityHost() + + adrmConfiguration.getFacilitySearchUrl() + +"?limit=" + entities.size() + + "&offset=0&tenantId=" + tenantId), + FacilitySearchRequest.builder().requestInfo(request.getRequestInfo()).facility(facilitySearch).build(), + FacilityBulkResponse.class + ); + existingFacilityList = facilityBulkResponse.getFacilities(); + } catch (QueryBuilderException e) { + existingFacilityList = Collections.emptyList(); + } catch (Exception e) { + throw new RuntimeException(e); + } + final List existingFacilityIds = new ArrayList<>(); + existingFacilityList.forEach(facility -> existingFacilityIds.add(facility.getId())); + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + (!entity.getReferredToType().equals(FACILITY) || !existingFacilityIds.contains(entity.getReferredToId())) + ).collect(Collectors.toList()); + invalidEntities.forEach(referral -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(referral, error, errorDetailsMap); + }); + + } + }); + return errorDetailsMap; + } + + private void addIgnoreNull(List list, String item) { + if(Objects.nonNull(item)) list.add(item); + } +} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmIsDeletedValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmIsDeletedValidator.java new file mode 100644 index 00000000000..00dd7156d42 --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmIsDeletedValidator.java @@ -0,0 +1,34 @@ +package org.egov.adrm.validator.rm; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.adrm.referralmanagement.Referral; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForIsDelete; + +@Component +@Order(2) +@Slf4j +public class RmIsDeletedValidator implements Validator { + + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating isDeleted field"); + HashMap> errorDetailsMap = new HashMap<>(); + List validEntities = request.getReferrals(); + validEntities.stream().filter(Referral::getIsDeleted).forEach(referral -> { + Error error = getErrorForIsDelete(); + populateErrorDetails(referral, error, errorDetailsMap); + }); + return errorDetailsMap; + } +} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNonExistentEntityValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNonExistentEntityValidator.java new file mode 100644 index 00000000000..5a4e881370b --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNonExistentEntityValidator.java @@ -0,0 +1,71 @@ +package org.egov.adrm.validator.rm; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.adrm.repository.ReferralManagementRepository; +import org.egov.common.models.Error; +import org.egov.common.models.adrm.referralmanagement.Referral; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.egov.adrm.Constants.GET_ID; +import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.getObjClass; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + +@Component +@Order(value = 4) +@Slf4j +public class RmNonExistentEntityValidator implements Validator { + + private final ReferralManagementRepository referralManagementRepository; + + private final ObjectMapper objectMapper; + + @Autowired + public RmNonExistentEntityValidator(ReferralManagementRepository referralManagementRepository, ObjectMapper objectMapper) { + this.referralManagementRepository = referralManagementRepository; + this.objectMapper = objectMapper; + } + + + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating for existence of entity"); + Map> errorDetailsMap = new HashMap<>(); + List referrals = request.getReferrals(); + Class objClass = getObjClass(referrals); + Method idMethod = getMethod(GET_ID, objClass); + Map iMap = getIdToObjMap(referrals + .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + if (!iMap.isEmpty()) { + List adverseEventIds = new ArrayList<>(iMap.keySet()); + List existingReferrals = referralManagementRepository + .findById(adverseEventIds, false, getIdFieldName(idMethod)); + List nonExistentReferrals = checkNonExistentEntities(iMap, + existingReferrals, idMethod); + nonExistentReferrals.forEach(adverseEvent -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(adverseEvent, error, errorDetailsMap); + }); + } + + return errorDetailsMap; + } +} + diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNullIdValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNullIdValidator.java new file mode 100644 index 00000000000..5324a12270b --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNullIdValidator.java @@ -0,0 +1,27 @@ +package org.egov.adrm.validator.rm; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.adrm.referralmanagement.Referral; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Map; + +import static org.egov.adrm.Constants.GET_REFERRALS; +import static org.egov.common.utils.CommonUtils.validateForNullId; + + +@Component +@Order(value = 1) +@Slf4j +public class RmNullIdValidator implements Validator { + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating for null id"); + return validateForNullId(request, GET_REFERRALS); + } +} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmProjectEntitiesIdValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmProjectEntitiesIdValidator.java new file mode 100644 index 00000000000..05c4670c7ec --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmProjectEntitiesIdValidator.java @@ -0,0 +1,134 @@ +package org.egov.adrm.validator.rm; + +import lombok.extern.slf4j.Slf4j; +import org.egov.adrm.config.AdrmConfiguration; +import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.adrm.referralmanagement.Referral; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.project.BeneficiaryBulkResponse; +import org.egov.common.models.project.BeneficiarySearchRequest; +import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.models.project.ProjectBeneficiarySearch; +import org.egov.common.models.project.ProjectStaff; +import org.egov.common.models.project.ProjectStaffBulkResponse; +import org.egov.common.models.project.ProjectStaffSearch; +import org.egov.common.models.project.ProjectStaffSearchRequest; +import org.egov.common.validator.Validator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.egov.adrm.Constants.PROJECT_STAFF; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + + +@Component +@Order(value = 3) +@Slf4j +public class RmProjectEntitiesIdValidator implements Validator { + private final ServiceRequestClient serviceRequestClient; + private final AdrmConfiguration adrmConfiguration; + + @Autowired + public RmProjectEntitiesIdValidator(ServiceRequestClient serviceRequestClient, AdrmConfiguration adrmConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.adrmConfiguration = adrmConfiguration; + } + + + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating project beneficiary id, project staff id"); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getReferrals(); + Map> tenantIdReferralMap = entities.stream().collect(Collectors.groupingBy(Referral::getTenantId)); + List tenantIds = new ArrayList<>(tenantIdReferralMap.keySet()); + tenantIds.forEach(tenantId -> { + List referralList = tenantIdReferralMap.get(tenantId); + if (!referralList.isEmpty()) { + List existingProjectBeneficiaries = null; + List existingProjectStaffList = null; + final List projectBeneficiaryIdList = new ArrayList<>(); + final List projectBeneficiaryClientReferenceIdList = new ArrayList<>(); + final List projectStaffIdList = new ArrayList<>(); + try { + referralList.forEach(referral -> { + addIgnoreNull(projectBeneficiaryIdList, referral.getProjectBeneficiaryId()); + addIgnoreNull(projectBeneficiaryClientReferenceIdList, referral.getProjectBeneficiaryClientReferenceId()); + addIgnoreNull(projectStaffIdList, referral.getReferringPartyId()); + if(referral.getReferredToType().equals(PROJECT_STAFF)){ + addIgnoreNull(projectStaffIdList, referral.getReferredToId()); + } + }); + ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() + .id(projectBeneficiaryIdList.isEmpty() ? null : projectBeneficiaryIdList) + .clientReferenceId(projectBeneficiaryClientReferenceIdList.isEmpty() ? null : projectBeneficiaryClientReferenceIdList) + .build(); + BeneficiaryBulkResponse beneficiaryBulkResponse = serviceRequestClient.fetchResult( + new StringBuilder(adrmConfiguration.getProjectHost() + + adrmConfiguration.getProjectBeneficiarySearchUrl() + +"?limit=" + entities.size() + + "&offset=0&tenantId=" + tenantId), + BeneficiarySearchRequest.builder().requestInfo(request.getRequestInfo()).projectBeneficiary(projectBeneficiarySearch).build(), + BeneficiaryBulkResponse.class + ); + existingProjectBeneficiaries = beneficiaryBulkResponse.getProjectBeneficiaries(); + ProjectStaffSearch projectStaffSearch = ProjectStaffSearch.builder() + .id(projectStaffIdList.isEmpty() ? null : projectStaffIdList) + .build(); + ProjectStaffBulkResponse projectStaffBulkResponse = serviceRequestClient.fetchResult( + new StringBuilder(adrmConfiguration.getProjectHost() + + adrmConfiguration.getProjectStaffSearchUrl() + +"?limit=" + entities.size() + + "&offset=0&tenantId=" + tenantId), + ProjectStaffSearchRequest.builder().requestInfo(request.getRequestInfo()).projectStaff(projectStaffSearch).build(), + ProjectStaffBulkResponse.class + ); + existingProjectStaffList = projectStaffBulkResponse.getProjectStaff(); + + } catch (QueryBuilderException e) { + if(existingProjectBeneficiaries == null) existingProjectBeneficiaries = Collections.emptyList(); + existingProjectStaffList = Collections.emptyList(); + } catch (Exception e) { + throw new RuntimeException(e); + } + final List existingProjectBeneficiaryIds = new ArrayList<>(); + final List existingProjectBeneficiaryClientReferenceIds = new ArrayList<>(); + existingProjectBeneficiaries.forEach(projectBeneficiary -> { + existingProjectBeneficiaryIds.add(projectBeneficiary.getId()); + existingProjectBeneficiaryClientReferenceIds.add(projectBeneficiary.getClientReferenceId()); + }); + final List existingProjectStaffIds = new ArrayList<>(); + existingProjectStaffList.forEach(projectStaff -> existingProjectStaffIds.add(projectStaff.getId())); + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + !existingProjectStaffIds.contains(entity.getReferringPartyId()) + && !existingProjectBeneficiaryIds.contains(entity.getProjectBeneficiaryId()) + && !existingProjectBeneficiaryClientReferenceIds.contains(entity.getProjectBeneficiaryClientReferenceId()) + && (!entity.getReferredToType().equals(PROJECT_STAFF) || !existingProjectStaffIds.contains(entity.getReferredToId())) + ).collect(Collectors.toList()); + invalidEntities.forEach(referral -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(referral, error, errorDetailsMap); + }); + + } + }); + return errorDetailsMap; + } + + private void addIgnoreNull(List list, String item) { + if(Objects.nonNull(item)) list.add(item); + } +} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmUniqueEntityValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmUniqueEntityValidator.java new file mode 100644 index 00000000000..8a73836a870 --- /dev/null +++ b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmUniqueEntityValidator.java @@ -0,0 +1,47 @@ +package org.egov.adrm.validator.rm; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.adrm.referralmanagement.Referral; +import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +@Component +@Order(value = 2) +@Slf4j +public class RmUniqueEntityValidator implements Validator { + + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating unique entity"); + Map> errorDetailsMap = new HashMap<>(); + List validEntities = request.getReferrals() + .stream().filter(notHavingErrors()).collect(Collectors.toList()); + if (!validEntities.isEmpty()) { + Map eMap = getIdToObjMap(validEntities); + if (eMap.keySet().size() != validEntities.size()) { + List duplicates = eMap.keySet().stream().filter(id -> + validEntities.stream() + .filter(entity -> entity.getId().equals(id)).count() > 1 + ).collect(Collectors.toList()); + for (String key : duplicates) { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(eMap.get(key), error, errorDetailsMap); + } + } + } + return errorDetailsMap; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java index b7fbf6deff4..668ea353ac3 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java @@ -42,10 +42,6 @@ public class Referral { @Size(min = 2, max = 64) private String referringPartyId = null; - @JsonProperty("referringPartyClientReferenceId") - @Size(min = 2, max = 64) - private String referringPartyClientReferenceId = null; - @JsonProperty("referredToType") private String referredToType = null; @@ -53,10 +49,6 @@ public class Referral { @Size(min = 2, max = 64) private String referredToId = null; - @JsonProperty("referredToClientReferenceId") - @Size(min = 2, max = 64) - private String referredToClientReferenceId = null; - @JsonProperty("reasons") @NotNull @Size(min=1) From cad895767db2e2eaa944b77530011282a37694bb Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 27 Sep 2023 15:00:40 +0530 Subject: [PATCH 169/283] HLM-3069: changed module name to referral management --- .../consumer/ReferralManagementConsumer.java | 71 ------ .../service/ReferralManagementService.java | 232 ------------------ .../ReferralManagementEnrichmentService.java | 56 ----- .../ReferralManagementApiController.java | 141 ----------- .../sideeffect/SideEffect.java | 4 + .../sideeffect/SideEffectBulkRequest.java | 4 + .../sideeffect/SideEffectBulkResponse.java | 4 + .../sideeffect/SideEffectRequest.java | 4 + .../sideeffect/SideEffectResponse.java | 4 + .../sideeffect/SideEffectSearch.java | 4 + .../sideeffect/SideEffectSearchRequest.java | 4 + .../repository/SideEffectRepository.java | 8 + .../rowmapper/SideEffectRowMapper.java | 4 + .../sideeffect/SeIsDeletedValidator.java | 9 + .../SeNonExistentEntityValidator.java | 11 + .../sideeffect/SeProjectTaskIdValidator.java | 13 + .../sideeffect/SeUniqueEntityValidator.java | 9 + .../ReferralManagementApiController.java | 4 + .../helper/SideEffectTestBuilder.java | 4 + .../SideEffectApiControllerTest.java | 13 + 20 files changed, 103 insertions(+), 500 deletions(-) delete mode 100644 health-services/adrm/src/main/java/org/egov/adrm/consumer/ReferralManagementConsumer.java delete mode 100644 health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java delete mode 100644 health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/ReferralManagementEnrichmentService.java delete mode 100644 health-services/adrm/src/main/java/org/egov/adrm/web/controllers/ReferralManagementApiController.java diff --git a/health-services/adrm/src/main/java/org/egov/adrm/consumer/ReferralManagementConsumer.java b/health-services/adrm/src/main/java/org/egov/adrm/consumer/ReferralManagementConsumer.java deleted file mode 100644 index 190ae112765..00000000000 --- a/health-services/adrm/src/main/java/org/egov/adrm/consumer/ReferralManagementConsumer.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.egov.adrm.consumer; - -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.egov.adrm.service.ReferralManagementService; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; -import org.egov.tracer.model.CustomException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -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 ReferralManagementConsumer { - - private final ReferralManagementService referralManagementService; - - private final ObjectMapper objectMapper; - - @Autowired - public ReferralManagementConsumer(ReferralManagementService referralManagementService, - @Qualifier("objectMapper") ObjectMapper objectMapper) { - this.referralManagementService = referralManagementService; - this.objectMapper = objectMapper; - } - - @KafkaListener(topics = "${adrm.referralmanagement.consumer.bulk.create.topic}") - public void bulkCreate(Map consumerRecord, - @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { - try { - ReferralBulkRequest request = objectMapper.convertValue(consumerRecord, ReferralBulkRequest.class); - referralManagementService.create(request, true); - } catch (Exception exception) { - log.error("Error in Referral consumer bulk create", exception); - log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); - throw new CustomException("HCM_ADRM_REFERRAL_MANAGEMENT_CREATE", exception.getMessage()); - } - } - - @KafkaListener(topics = "${adrm.referralmanagement.consumer.bulk.update.topic}") - public void bulkUpdate(Map consumerRecord, - @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { - try { - ReferralBulkRequest request = objectMapper.convertValue(consumerRecord, ReferralBulkRequest.class); - referralManagementService.update(request, true); - } catch (Exception exception) { - log.error("Error in Referral consumer bulk update", exception); - log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); - throw new CustomException("HCM_ADRM_REFERRAL_MANAGEMENT_CREATE", exception.getMessage()); - } - } - - @KafkaListener(topics = "${adrm.referralmanagement.consumer.bulk.delete.topic}") - public void bulkDelete(Map consumerRecord, - @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { - try { - ReferralBulkRequest request = objectMapper.convertValue(consumerRecord, ReferralBulkRequest.class); - referralManagementService.delete(request, true); - } catch (Exception exception) { - log.error("Error in Referral consumer bulk delete", exception); - log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); - throw new CustomException("HCM_ADRM_REFERRAL_MANAGEMENT_CREATE", exception.getMessage()); - } - } -} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java b/health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java deleted file mode 100644 index 0bd69750a27..00000000000 --- a/health-services/adrm/src/main/java/org/egov/adrm/service/ReferralManagementService.java +++ /dev/null @@ -1,232 +0,0 @@ -package org.egov.adrm.service; - -import lombok.extern.slf4j.Slf4j; -import org.egov.adrm.Constants; -import org.egov.adrm.config.AdrmConfiguration; -import org.egov.adrm.repository.ReferralManagementRepository; -import org.egov.adrm.service.enrichment.ReferralManagementEnrichmentService; -import org.egov.adrm.validator.rm.RmFacilityEntitiesIdValidator; -import org.egov.adrm.validator.rm.RmIsDeletedValidator; -import org.egov.adrm.validator.rm.RmNonExistentEntityValidator; -import org.egov.adrm.validator.rm.RmNullIdValidator; -import org.egov.adrm.validator.rm.RmProjectEntitiesIdValidator; -import org.egov.adrm.validator.rm.RmUniqueEntityValidator; -import org.egov.common.ds.Tuple; -import org.egov.common.models.ErrorDetails; -import org.egov.common.models.adrm.referralmanagement.Referral; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; -import org.egov.common.models.adrm.referralmanagement.ReferralRequest; -import org.egov.common.models.adrm.referralmanagement.ReferralSearchRequest; -import org.egov.common.service.IdGenService; -import org.egov.common.utils.CommonUtils; -import org.egov.common.validator.Validator; -import org.egov.tracer.model.CustomException; -import org.springframework.stereotype.Service; -import org.springframework.util.ReflectionUtils; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.getIdFieldName; -import static org.egov.common.utils.CommonUtils.getIdMethod; -import static org.egov.common.utils.CommonUtils.handleErrors; -import static org.egov.common.utils.CommonUtils.havingTenantId; -import static org.egov.common.utils.CommonUtils.includeDeleted; -import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; -import static org.egov.common.utils.CommonUtils.lastChangedSince; -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; - -@Service -@Slf4j -public class ReferralManagementService { - private final IdGenService idGenService; - - private final ReferralManagementRepository referralManagementRepository; - - private final AdrmConfiguration adrmConfiguration; - - private final ReferralManagementEnrichmentService referralManagementEnrichmentService; - - private final List> validators; - - private final Predicate> isApplicableForCreate = validator -> - validator.getClass().equals(RmProjectEntitiesIdValidator.class) - || validator.getClass().equals(RmFacilityEntitiesIdValidator.class); - - private final Predicate> isApplicableForUpdate = validator -> - validator.getClass().equals(RmProjectEntitiesIdValidator.class) - || validator.getClass().equals(RmFacilityEntitiesIdValidator.class) - || validator.getClass().equals(RmNullIdValidator.class) - || validator.getClass().equals(RmIsDeletedValidator.class) - || validator.getClass().equals(RmUniqueEntityValidator.class) - || validator.getClass().equals(RmNonExistentEntityValidator.class); - - private final Predicate> isApplicableForDelete = validator -> - validator.getClass().equals(RmNullIdValidator.class) - || validator.getClass().equals(RmNonExistentEntityValidator.class); - - - public ReferralManagementService(IdGenService idGenService, ReferralManagementRepository referralManagementRepository, AdrmConfiguration adrmConfiguration, ReferralManagementEnrichmentService referralManagementEnrichmentService, List> validators) { - this.idGenService = idGenService; - this.referralManagementRepository = referralManagementRepository; - this.adrmConfiguration = adrmConfiguration; - this.referralManagementEnrichmentService = referralManagementEnrichmentService; - this.validators = validators; - } - - public Referral create(ReferralRequest request) { - log.info("received request to create adverse events"); - ReferralBulkRequest bulkRequest = ReferralBulkRequest.builder().requestInfo(request.getRequestInfo()) - .referrals(Collections.singletonList(request.getReferral())).build(); - log.info("creating bulk request"); - return create(bulkRequest, false).get(0); - } - - public List create(ReferralBulkRequest referralRequest, boolean isBulk) { - log.info("received request to create bulk adverse events"); - Tuple, Map> tuple = validate(validators, - isApplicableForCreate, referralRequest, isBulk); - Map errorDetailsMap = tuple.getY(); - List validReferrals = tuple.getX(); - - try { - if (!validReferrals.isEmpty()) { - log.info("processing {} valid entities", validReferrals.size()); - referralManagementEnrichmentService.create(validReferrals, referralRequest); - referralManagementRepository.save(validReferrals, - adrmConfiguration.getCreateReferralTopic()); - log.info("successfully created adverse events"); - } - } catch (Exception exception) { - log.error("error occurred while creating adverse events: {}", exception.getMessage()); - populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, - exception, Constants.SET_ADVERSE_EVENTS); - } - handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); - - return validReferrals; - } - - public Referral update(ReferralRequest request) { - log.info("received request to update adverse event"); - ReferralBulkRequest bulkRequest = ReferralBulkRequest.builder().requestInfo(request.getRequestInfo()) - .referrals(Collections.singletonList(request.getReferral())).build(); - log.info("creating bulk request"); - return update(bulkRequest, false).get(0); - } - - public List update(ReferralBulkRequest referralRequest, boolean isBulk) { - log.info("received request to update bulk adverse event"); - Tuple, Map> tuple = validate(validators, - isApplicableForUpdate, referralRequest, isBulk); - Map errorDetailsMap = tuple.getY(); - List validReferrals = tuple.getX(); - - try { - if (!validReferrals.isEmpty()) { - log.info("processing {} valid entities", validReferrals.size()); - referralManagementEnrichmentService.update(validReferrals, referralRequest); - referralManagementRepository.save(validReferrals, - adrmConfiguration.getUpdateReferralTopic()); - log.info("successfully updated bulk adverse events"); - } - } catch (Exception exception) { - log.error("error occurred while updating adverse events", exception); - populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, - exception, Constants.SET_ADVERSE_EVENTS); - } - handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); - - return validReferrals; - } - - public List search(ReferralSearchRequest referralSearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { - log.info("received request to search adverse events"); - String idFieldName = getIdFieldName(referralSearchRequest.getReferral()); - if (isSearchByIdOnly(referralSearchRequest.getReferral(), idFieldName)) { - log.info("searching adverse events by id"); - List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections - .singletonList(referralSearchRequest.getReferral())), - referralSearchRequest.getReferral()); - log.info("fetching adverse events with ids: {}", ids); - return referralManagementRepository.findById(ids, includeDeleted, idFieldName).stream() - .filter(lastChangedSince(lastChangedSince)) - .filter(havingTenantId(tenantId)) - .filter(includeDeleted(includeDeleted)) - .collect(Collectors.toList()); - } - log.info("searching adverse events using criteria"); - return referralManagementRepository.find(referralSearchRequest.getReferral(), - limit, offset, tenantId, lastChangedSince, includeDeleted); - } - - public Referral delete(ReferralRequest referralRequest) { - log.info("received request to delete a adverse event"); - ReferralBulkRequest bulkRequest = ReferralBulkRequest.builder().requestInfo(referralRequest.getRequestInfo()) - .referrals(Collections.singletonList(referralRequest.getReferral())).build(); - log.info("creating bulk request"); - return delete(bulkRequest, false).get(0); - } - - public List delete(ReferralBulkRequest referralRequest, boolean isBulk) { - Tuple, Map> tuple = validate(validators, - isApplicableForDelete, referralRequest, isBulk); - Map errorDetailsMap = tuple.getY(); - List validReferrals = tuple.getX(); - - try { - if (!validReferrals.isEmpty()) { - log.info("processing {} valid entities", validReferrals.size()); - List referralIds = validReferrals.stream().map(entity -> entity.getId()).collect(Collectors.toSet()).stream().collect(Collectors.toList()); - List existingReferrals = referralManagementRepository - .findById(referralIds, false); - referralManagementEnrichmentService.delete(existingReferrals, referralRequest); - referralManagementRepository.save(existingReferrals, - adrmConfiguration.getDeleteReferralTopic()); - log.info("successfully deleted entities"); - } - } catch (Exception exception) { - log.error("error occurred while deleting entities: {}", exception); - populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, - exception, Constants.SET_ADVERSE_EVENTS); - } - handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); - - return validReferrals; - } - - public void putInCache(List referrals) { - log.info("putting {} adverse events in cache", referrals.size()); - referralManagementRepository.putInCache(referrals); - log.info("successfully put adverse events in cache"); - } - - private Tuple, Map> validate( - List> validators, - Predicate> isApplicable, - ReferralBulkRequest request, - boolean isBulk - ) { - log.info("validating request"); - Map errorDetailsMap = CommonUtils.validate(validators, - isApplicable, request, - Constants.SET_ADVERSE_EVENTS); - if (!errorDetailsMap.isEmpty() && !isBulk) { - log.error("validation error occurred. error details: {}", errorDetailsMap.values().toString()); - throw new CustomException(Constants.VALIDATION_ERROR, errorDetailsMap.values().toString()); - } - List validReferrals = request.getReferrals().stream() - .filter(notHavingErrors()).collect(Collectors.toList()); - log.info("validation successful, found valid adverse events"); - return new Tuple<>(validReferrals, errorDetailsMap); - } -} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/ReferralManagementEnrichmentService.java b/health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/ReferralManagementEnrichmentService.java deleted file mode 100644 index 552136b678c..00000000000 --- a/health-services/adrm/src/main/java/org/egov/adrm/service/enrichment/ReferralManagementEnrichmentService.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.egov.adrm.service.enrichment; - -import lombok.extern.slf4j.Slf4j; -import org.egov.adrm.config.AdrmConfiguration; -import org.egov.adrm.repository.ReferralManagementRepository; -import org.egov.common.models.adrm.referralmanagement.Referral; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; -import org.egov.common.service.IdGenService; -import org.egov.common.utils.CommonUtils; -import org.springframework.stereotype.Component; - -import java.util.List; -import java.util.Map; - -import static org.egov.common.utils.CommonUtils.enrichForCreate; -import static org.egov.common.utils.CommonUtils.enrichForDelete; -import static org.egov.common.utils.CommonUtils.enrichForUpdate; -import static org.egov.common.utils.CommonUtils.getIdToObjMap; - -@Component -@Slf4j -public class ReferralManagementEnrichmentService { - private final IdGenService idGenService; - - private final AdrmConfiguration adrmConfiguration; - - private final ReferralManagementRepository referralManagementRepository; - - public ReferralManagementEnrichmentService(IdGenService idGenService, AdrmConfiguration adrmConfiguration, ReferralManagementRepository referralManagementRepository) { - this.idGenService = idGenService; - this.adrmConfiguration = adrmConfiguration; - this.referralManagementRepository = referralManagementRepository; - } - - public void create(List entities, ReferralBulkRequest request) throws Exception { - log.info("starting the enrichment for create referrals"); - log.info("generating IDs using UUID"); - List idList = CommonUtils.uuidSupplier().apply(entities.size()); - log.info("enriching referrals with generated IDs"); - enrichForCreate(entities, idList, request.getRequestInfo()); - log.info("enrichment done"); - } - - public void update(List entities, ReferralBulkRequest request) { - log.info("starting the enrichment for create referrals"); - Map referralMap = getIdToObjMap(entities); - enrichForUpdate(referralMap, entities, request); - log.info("enrichment done"); - } - - public void delete(List entities, ReferralBulkRequest request) { - log.info("starting the enrichment for delete referrals"); - enrichForDelete(entities, request.getRequestInfo(), true); - log.info("enrichment done"); - } -} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/ReferralManagementApiController.java b/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/ReferralManagementApiController.java deleted file mode 100644 index 42604fa739f..00000000000 --- a/health-services/adrm/src/main/java/org/egov/adrm/web/controllers/ReferralManagementApiController.java +++ /dev/null @@ -1,141 +0,0 @@ -package org.egov.adrm.web.controllers; - -import io.swagger.annotations.ApiParam; -import org.egov.adrm.config.AdrmConfiguration; -import org.egov.adrm.service.ReferralManagementService; -import org.egov.common.contract.response.ResponseInfo; -import org.egov.common.models.adrm.referralmanagement.Referral; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkResponse; -import org.egov.common.models.adrm.referralmanagement.ReferralRequest; -import org.egov.common.models.adrm.referralmanagement.ReferralResponse; -import org.egov.common.models.adrm.referralmanagement.ReferralSearchRequest; -import org.egov.common.producer.Producer; -import org.egov.common.utils.ResponseInfoFactory; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.stereotype.Controller; -import org.springframework.validation.annotation.Validated; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; - -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import java.util.List; - -@Controller -@RequestMapping("/referral-management") -@Validated -public class ReferralManagementApiController { - private final HttpServletRequest httpServletRequest; - - private final ReferralManagementService referralManagementService; - - private final Producer producer; - - private final AdrmConfiguration adrmConfiguration; - - public ReferralManagementApiController( - HttpServletRequest httpServletRequest, - ReferralManagementService referralManagementService, - Producer producer, - AdrmConfiguration adrmConfiguration - ) { - this.httpServletRequest = httpServletRequest; - this.referralManagementService = referralManagementService; - this.producer = producer; - this.adrmConfiguration = adrmConfiguration; - } - - @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) - public ResponseEntity referralV1CreatePost(@ApiParam(value = "Capture details of Referral", required = true) @Valid @RequestBody ReferralRequest request) { - - Referral referral = referralManagementService.create(request); - ReferralResponse response = ReferralResponse.builder() - .referral(referral) - .responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)) - .build(); - - return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); - } - - - - @RequestMapping(value = "/v1/bulk/_create", method = RequestMethod.POST) - public ResponseEntity referralBulkV1CreatePost(@ApiParam(value = "Capture details of Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { - request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); - referralManagementService.putInCache(request.getReferrals()); - producer.push(adrmConfiguration.getCreateReferralBulkTopic(), request); - - return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)); - } - - @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) - public ResponseEntity referralV1SearchPost(@ApiParam(value = "Referral Search.", required = true) @Valid @RequestBody ReferralSearchRequest request, - @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, - @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, - @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, - @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, - @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { - - List referrals = referralManagementService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); - ReferralBulkResponse response = ReferralBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).referrals(referrals).build(); - - return ResponseEntity.status(HttpStatus.OK).body(response); - } - - @RequestMapping(value = "/v1/_update", method = RequestMethod.POST) - public ResponseEntity referralV1UpdatePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralRequest request) { - Referral referral = referralManagementService.update(request); - - ReferralResponse response = ReferralResponse.builder() - .referral(referral) - .responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)) - .build(); - - return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); - - } - - @RequestMapping(value = "/v1/bulk/_update", method = RequestMethod.POST) - public ResponseEntity referralV1BulkUpdatePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { - request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); - producer.push(adrmConfiguration.getUpdateReferralBulkTopic(), request); - - return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)); - } - - @RequestMapping(value = "/v1/_delete", method = RequestMethod.POST) - public ResponseEntity referralV1DeletePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralRequest request) { - Referral referral = referralManagementService.delete(request); - - ReferralResponse response = ReferralResponse.builder() - .referral(referral) - .responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)) - .build(); - - return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); - - } - - @RequestMapping(value = "/v1/bulk/_delete", method = RequestMethod.POST) - public ResponseEntity referralV1BulkDeletePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { - request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); - producer.push(adrmConfiguration.getDeleteReferralBulkTopic(), request); - - return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)); - } - -} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java index a078844a2dc..7ddedd7be35 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java @@ -1,4 +1,8 @@ +<<<<<<<< HEAD:health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java package org.egov.common.models.referralmanagement.sideeffect; +======== +package org.egov.common.models.referralmanagement.adverseevent; +>>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEvent.java import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java index 51319d73b51..f619d8c227e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java @@ -1,4 +1,8 @@ +<<<<<<<< HEAD:health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java package org.egov.common.models.referralmanagement.sideeffect; +======== +package org.egov.common.models.referralmanagement.adverseevent; +>>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkRequest.java import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java index bfcfda3dae4..9cff0a6fc9c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java @@ -1,4 +1,8 @@ +<<<<<<<< HEAD:health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java package org.egov.common.models.referralmanagement.sideeffect; +======== +package org.egov.common.models.referralmanagement.adverseevent; +>>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkResponse.java import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java index 9de2e92b66e..811814e4ea9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java @@ -1,4 +1,8 @@ +<<<<<<<< HEAD:health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java package org.egov.common.models.referralmanagement.sideeffect; +======== +package org.egov.common.models.referralmanagement.adverseevent; +>>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventRequest.java import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java index 9e96194482c..be8354c530a 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java @@ -1,4 +1,8 @@ +<<<<<<<< HEAD:health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java package org.egov.common.models.referralmanagement.sideeffect; +======== +package org.egov.common.models.referralmanagement.adverseevent; +>>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventResponse.java import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java index 3183a2533d6..214ae9755ea 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java @@ -1,4 +1,8 @@ +<<<<<<<< HEAD:health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java package org.egov.common.models.referralmanagement.sideeffect; +======== +package org.egov.common.models.referralmanagement.adverseevent; +>>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearch.java import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java index 69cc688f884..564873abdf8 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java @@ -1,4 +1,8 @@ +<<<<<<<< HEAD:health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java package org.egov.common.models.referralmanagement.sideeffect; +======== +package org.egov.common.models.referralmanagement.adverseevent; +>>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearchRequest.java import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java index c3ce7ea000b..460bcbb8034 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java @@ -6,11 +6,19 @@ import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; +<<<<<<<< HEAD:health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearch; import org.egov.common.models.project.Task; import org.egov.common.producer.Producer; import org.egov.referralmanagement.repository.rowmapper.SideEffectRowMapper; +======== +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearch; +import org.egov.common.models.project.Task; +import org.egov.common.producer.Producer; +import org.egov.referralmanagement.repository.rowmapper.AdverseEventRowMapper; +>>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/AdverseEventRepository.java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java index 7a49ceef93e..db93f292b98 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java @@ -3,7 +3,11 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; +<<<<<<<< HEAD:health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +======== +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +>>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/AdverseEventRowMapper.java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeIsDeletedValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeIsDeletedValidator.java index b6e4d3f94f3..f8ab13e405f 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeIsDeletedValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeIsDeletedValidator.java @@ -1,9 +1,18 @@ +<<<<<<<< HEAD:health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeIsDeletedValidator.java package org.egov.referralmanagement.validator.sideeffect; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +======== +package org.egov.referralmanagement.validator.adverseevent; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; +>>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdIsDeletedValidator.java import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNonExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNonExistentEntityValidator.java index 5f70cd0fef5..3ce8ab65f31 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNonExistentEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNonExistentEntityValidator.java @@ -1,3 +1,4 @@ +<<<<<<<< HEAD:health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNonExistentEntityValidator.java package org.egov.referralmanagement.validator.sideeffect; import com.fasterxml.jackson.databind.ObjectMapper; @@ -6,6 +7,16 @@ import org.egov.common.models.Error; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +======== +package org.egov.referralmanagement.validator.adverseevent; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.referralmanagement.repository.AdverseEventRepository; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; +>>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNonExistentEntityValidator.java import org.egov.common.validator.Validator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java index 4d1b2609c26..2bdca8ac056 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java @@ -1,4 +1,8 @@ +<<<<<<<< HEAD:health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java package org.egov.referralmanagement.validator.sideeffect; +======== +package org.egov.referralmanagement.validator.adverseevent; +>>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdProjectTaskIdValidator.java import lombok.extern.slf4j.Slf4j; import org.egov.referralmanagement.config.ReferralManagementConfiguration; @@ -13,8 +17,13 @@ import org.egov.common.models.project.TaskBulkResponse; import org.egov.common.models.project.TaskSearch; import org.egov.common.models.project.TaskSearchRequest; +<<<<<<<< HEAD:health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +======== +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; +>>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdProjectTaskIdValidator.java import org.egov.common.validator.Validator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; @@ -41,7 +50,11 @@ public class SeProjectTaskIdValidator implements Validator>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdProjectTaskIdValidator.java this.serviceRequestClient = serviceRequestClient; this.referralManagementConfiguration = referralManagementConfiguration; } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java index 43f99f7cef2..68e90378e19 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java @@ -1,9 +1,18 @@ +<<<<<<<< HEAD:health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java package org.egov.referralmanagement.validator.sideeffect; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +======== +package org.egov.referralmanagement.validator.adverseevent; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; +>>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdUniqueEntityValidator.java import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java index 499760f0f78..c2c63a9ff98 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java @@ -38,7 +38,11 @@ public class ReferralManagementApiController { private final Producer producer; +<<<<<<< HEAD private final ReferralManagementConfiguration referralManagementConfiguration; +======= + private final AdrmConfiguration adrmConfiguration; +>>>>>>> 73a5aefec0 (HLM-3069: changed module name to referral management) public ReferralManagementApiController( HttpServletRequest httpServletRequest, diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java index d4c3c04c686..d9b3ed4b51e 100644 --- a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java @@ -1,7 +1,11 @@ package org.egov.referralmanagement.helper; import org.egov.common.helper.AuditDetailsTestBuilder; +<<<<<<<< HEAD:health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +======== +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +>>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventTestBuilder.java import java.util.ArrayList; import java.util.Arrays; diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java index 5acd4f7a594..399b71a653d 100644 --- a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.egov.referralmanagement.TestConfiguration; import org.egov.referralmanagement.config.ReferralManagementConfiguration; +<<<<<<<< HEAD:health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java import org.egov.referralmanagement.helper.SideEffectRequestTestBuilder; import org.egov.referralmanagement.helper.SideEffectTestBuilder; import org.egov.referralmanagement.service.SideEffectService; @@ -13,6 +14,18 @@ import org.egov.common.models.referralmanagement.sideeffect.SideEffectResponse; import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearch; import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearchRequest; +======== +import org.egov.referralmanagement.helper.AdverseEventRequestTestBuilder; +import org.egov.referralmanagement.helper.AdverseEventTestBuilder; +import org.egov.referralmanagement.service.AdverseEventService; +import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkResponse; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventRequest; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventResponse; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearch; +import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearchRequest; +>>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/AdverseEventApiControllerTest.java import org.egov.common.producer.Producer; import org.egov.tracer.model.CustomException; import org.egov.tracer.model.ErrorRes; From 4c4d673659fefa1b8dd4f3b30a4dbf4a17208481 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 25 Sep 2023 11:53:07 +0530 Subject: [PATCH 170/283] HLM-3376: Added changes for referral management --- .../common/models/adrm/referralmanagement/Referral.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java index 668ea353ac3..b7fbf6deff4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java @@ -42,6 +42,10 @@ public class Referral { @Size(min = 2, max = 64) private String referringPartyId = null; + @JsonProperty("referringPartyClientReferenceId") + @Size(min = 2, max = 64) + private String referringPartyClientReferenceId = null; + @JsonProperty("referredToType") private String referredToType = null; @@ -49,6 +53,10 @@ public class Referral { @Size(min = 2, max = 64) private String referredToId = null; + @JsonProperty("referredToClientReferenceId") + @Size(min = 2, max = 64) + private String referredToClientReferenceId = null; + @JsonProperty("reasons") @NotNull @Size(min=1) From e9cbdb7c9f4cfe2a1a4a5181c9933fb87cfab889 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 27 Sep 2023 15:45:18 +0530 Subject: [PATCH 171/283] HLM-3376: changed module to referral management --- .../rm/RmFacilityEntitiesIdValidator.java | 100 ------------- .../validator/rm/RmIsDeletedValidator.java | 34 ----- .../rm/RmNonExistentEntityValidator.java | 71 ---------- .../adrm/validator/rm/RmNullIdValidator.java | 27 ---- .../rm/RmProjectEntitiesIdValidator.java | 134 ------------------ .../validator/rm/RmUniqueEntityValidator.java | 47 ------ .../adrm/referralmanagement/Referral.java | 89 ------------ .../ReferralBulkRequest.java | 38 ----- .../ReferralBulkResponse.java | 36 ----- .../referralmanagement/ReferralRequest.java | 29 ---- .../referralmanagement/ReferralResponse.java | 29 ---- .../referralmanagement/ReferralSearch.java | 29 ---- .../ReferralSearchRequest.java | 28 ---- 13 files changed, 691 deletions(-) delete mode 100644 health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmFacilityEntitiesIdValidator.java delete mode 100644 health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmIsDeletedValidator.java delete mode 100644 health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNonExistentEntityValidator.java delete mode 100644 health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNullIdValidator.java delete mode 100644 health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmProjectEntitiesIdValidator.java delete mode 100644 health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmUniqueEntityValidator.java delete mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java delete mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkRequest.java delete mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkResponse.java delete mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralRequest.java delete mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralResponse.java delete mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearch.java delete mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearchRequest.java diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmFacilityEntitiesIdValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmFacilityEntitiesIdValidator.java deleted file mode 100644 index 340fc531ca3..00000000000 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmFacilityEntitiesIdValidator.java +++ /dev/null @@ -1,100 +0,0 @@ -package org.egov.adrm.validator.rm; - -import lombok.extern.slf4j.Slf4j; -import org.egov.adrm.config.AdrmConfiguration; -import org.egov.common.data.query.exception.QueryBuilderException; -import org.egov.common.http.client.ServiceRequestClient; -import org.egov.common.models.Error; -import org.egov.common.models.adrm.referralmanagement.Referral; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; -import org.egov.common.models.facility.Facility; -import org.egov.common.models.facility.FacilityBulkResponse; -import org.egov.common.models.facility.FacilitySearch; -import org.egov.common.models.facility.FacilitySearchRequest; -import org.egov.common.validator.Validator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; - -import static org.egov.adrm.Constants.FACILITY; -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; - - -@Component -@Order(value = 3) -@Slf4j -public class RmFacilityEntitiesIdValidator implements Validator { - private final ServiceRequestClient serviceRequestClient; - private final AdrmConfiguration adrmConfiguration; - - @Autowired - public RmFacilityEntitiesIdValidator(ServiceRequestClient serviceRequestClient, AdrmConfiguration adrmConfiguration) { - this.serviceRequestClient = serviceRequestClient; - this.adrmConfiguration = adrmConfiguration; - } - - - @Override - public Map> validate(ReferralBulkRequest request) { - log.info("validating facility id"); - Map> errorDetailsMap = new HashMap<>(); - List entities = request.getReferrals(); - Map> tenantIdReferralMap = entities.stream().collect(Collectors.groupingBy(Referral::getTenantId)); - List tenantIds = new ArrayList<>(tenantIdReferralMap.keySet()); - tenantIds.forEach(tenantId -> { - List referralList = tenantIdReferralMap.get(tenantId); - if (!referralList.isEmpty()) { - List existingFacilityList = null; - final List facilityIdList = new ArrayList<>(); - try { - referralList.forEach(referral -> { - if(referral.getReferredToType().equals(FACILITY)){ - addIgnoreNull(facilityIdList, referral.getReferredToId()); - } - }); - FacilitySearch facilitySearch = FacilitySearch.builder() - .id(facilityIdList.isEmpty() ? null : facilityIdList) - .build(); - FacilityBulkResponse facilityBulkResponse = serviceRequestClient.fetchResult( - new StringBuilder(adrmConfiguration.getFacilityHost() - + adrmConfiguration.getFacilitySearchUrl() - +"?limit=" + entities.size() - + "&offset=0&tenantId=" + tenantId), - FacilitySearchRequest.builder().requestInfo(request.getRequestInfo()).facility(facilitySearch).build(), - FacilityBulkResponse.class - ); - existingFacilityList = facilityBulkResponse.getFacilities(); - } catch (QueryBuilderException e) { - existingFacilityList = Collections.emptyList(); - } catch (Exception e) { - throw new RuntimeException(e); - } - final List existingFacilityIds = new ArrayList<>(); - existingFacilityList.forEach(facility -> existingFacilityIds.add(facility.getId())); - List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> - (!entity.getReferredToType().equals(FACILITY) || !existingFacilityIds.contains(entity.getReferredToId())) - ).collect(Collectors.toList()); - invalidEntities.forEach(referral -> { - Error error = getErrorForNonExistentEntity(); - populateErrorDetails(referral, error, errorDetailsMap); - }); - - } - }); - return errorDetailsMap; - } - - private void addIgnoreNull(List list, String item) { - if(Objects.nonNull(item)) list.add(item); - } -} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmIsDeletedValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmIsDeletedValidator.java deleted file mode 100644 index 00dd7156d42..00000000000 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmIsDeletedValidator.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.egov.adrm.validator.rm; - -import lombok.extern.slf4j.Slf4j; -import org.egov.common.models.Error; -import org.egov.common.models.adrm.referralmanagement.Referral; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; -import org.egov.common.validator.Validator; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.common.utils.ValidatorUtils.getErrorForIsDelete; - -@Component -@Order(2) -@Slf4j -public class RmIsDeletedValidator implements Validator { - - @Override - public Map> validate(ReferralBulkRequest request) { - log.info("validating isDeleted field"); - HashMap> errorDetailsMap = new HashMap<>(); - List validEntities = request.getReferrals(); - validEntities.stream().filter(Referral::getIsDeleted).forEach(referral -> { - Error error = getErrorForIsDelete(); - populateErrorDetails(referral, error, errorDetailsMap); - }); - return errorDetailsMap; - } -} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNonExistentEntityValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNonExistentEntityValidator.java deleted file mode 100644 index 5a4e881370b..00000000000 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNonExistentEntityValidator.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.egov.adrm.validator.rm; - -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.extern.slf4j.Slf4j; -import org.egov.adrm.repository.ReferralManagementRepository; -import org.egov.common.models.Error; -import org.egov.common.models.adrm.referralmanagement.Referral; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; -import org.egov.common.validator.Validator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static org.egov.adrm.Constants.GET_ID; -import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; -import static org.egov.common.utils.CommonUtils.getIdFieldName; -import static org.egov.common.utils.CommonUtils.getIdToObjMap; -import static org.egov.common.utils.CommonUtils.getMethod; -import static org.egov.common.utils.CommonUtils.getObjClass; -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; - -@Component -@Order(value = 4) -@Slf4j -public class RmNonExistentEntityValidator implements Validator { - - private final ReferralManagementRepository referralManagementRepository; - - private final ObjectMapper objectMapper; - - @Autowired - public RmNonExistentEntityValidator(ReferralManagementRepository referralManagementRepository, ObjectMapper objectMapper) { - this.referralManagementRepository = referralManagementRepository; - this.objectMapper = objectMapper; - } - - - @Override - public Map> validate(ReferralBulkRequest request) { - log.info("validating for existence of entity"); - Map> errorDetailsMap = new HashMap<>(); - List referrals = request.getReferrals(); - Class objClass = getObjClass(referrals); - Method idMethod = getMethod(GET_ID, objClass); - Map iMap = getIdToObjMap(referrals - .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); - if (!iMap.isEmpty()) { - List adverseEventIds = new ArrayList<>(iMap.keySet()); - List existingReferrals = referralManagementRepository - .findById(adverseEventIds, false, getIdFieldName(idMethod)); - List nonExistentReferrals = checkNonExistentEntities(iMap, - existingReferrals, idMethod); - nonExistentReferrals.forEach(adverseEvent -> { - Error error = getErrorForNonExistentEntity(); - populateErrorDetails(adverseEvent, error, errorDetailsMap); - }); - } - - return errorDetailsMap; - } -} - diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNullIdValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNullIdValidator.java deleted file mode 100644 index 5324a12270b..00000000000 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmNullIdValidator.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.egov.adrm.validator.rm; - -import lombok.extern.slf4j.Slf4j; -import org.egov.common.models.Error; -import org.egov.common.models.adrm.referralmanagement.Referral; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; -import org.egov.common.validator.Validator; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import java.util.List; -import java.util.Map; - -import static org.egov.adrm.Constants.GET_REFERRALS; -import static org.egov.common.utils.CommonUtils.validateForNullId; - - -@Component -@Order(value = 1) -@Slf4j -public class RmNullIdValidator implements Validator { - @Override - public Map> validate(ReferralBulkRequest request) { - log.info("validating for null id"); - return validateForNullId(request, GET_REFERRALS); - } -} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmProjectEntitiesIdValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmProjectEntitiesIdValidator.java deleted file mode 100644 index 05c4670c7ec..00000000000 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmProjectEntitiesIdValidator.java +++ /dev/null @@ -1,134 +0,0 @@ -package org.egov.adrm.validator.rm; - -import lombok.extern.slf4j.Slf4j; -import org.egov.adrm.config.AdrmConfiguration; -import org.egov.common.data.query.exception.QueryBuilderException; -import org.egov.common.http.client.ServiceRequestClient; -import org.egov.common.models.Error; -import org.egov.common.models.adrm.referralmanagement.Referral; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; -import org.egov.common.models.project.BeneficiaryBulkResponse; -import org.egov.common.models.project.BeneficiarySearchRequest; -import org.egov.common.models.project.ProjectBeneficiary; -import org.egov.common.models.project.ProjectBeneficiarySearch; -import org.egov.common.models.project.ProjectStaff; -import org.egov.common.models.project.ProjectStaffBulkResponse; -import org.egov.common.models.project.ProjectStaffSearch; -import org.egov.common.models.project.ProjectStaffSearchRequest; -import org.egov.common.validator.Validator; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; - -import static org.egov.adrm.Constants.PROJECT_STAFF; -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; - - -@Component -@Order(value = 3) -@Slf4j -public class RmProjectEntitiesIdValidator implements Validator { - private final ServiceRequestClient serviceRequestClient; - private final AdrmConfiguration adrmConfiguration; - - @Autowired - public RmProjectEntitiesIdValidator(ServiceRequestClient serviceRequestClient, AdrmConfiguration adrmConfiguration) { - this.serviceRequestClient = serviceRequestClient; - this.adrmConfiguration = adrmConfiguration; - } - - - @Override - public Map> validate(ReferralBulkRequest request) { - log.info("validating project beneficiary id, project staff id"); - Map> errorDetailsMap = new HashMap<>(); - List entities = request.getReferrals(); - Map> tenantIdReferralMap = entities.stream().collect(Collectors.groupingBy(Referral::getTenantId)); - List tenantIds = new ArrayList<>(tenantIdReferralMap.keySet()); - tenantIds.forEach(tenantId -> { - List referralList = tenantIdReferralMap.get(tenantId); - if (!referralList.isEmpty()) { - List existingProjectBeneficiaries = null; - List existingProjectStaffList = null; - final List projectBeneficiaryIdList = new ArrayList<>(); - final List projectBeneficiaryClientReferenceIdList = new ArrayList<>(); - final List projectStaffIdList = new ArrayList<>(); - try { - referralList.forEach(referral -> { - addIgnoreNull(projectBeneficiaryIdList, referral.getProjectBeneficiaryId()); - addIgnoreNull(projectBeneficiaryClientReferenceIdList, referral.getProjectBeneficiaryClientReferenceId()); - addIgnoreNull(projectStaffIdList, referral.getReferringPartyId()); - if(referral.getReferredToType().equals(PROJECT_STAFF)){ - addIgnoreNull(projectStaffIdList, referral.getReferredToId()); - } - }); - ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() - .id(projectBeneficiaryIdList.isEmpty() ? null : projectBeneficiaryIdList) - .clientReferenceId(projectBeneficiaryClientReferenceIdList.isEmpty() ? null : projectBeneficiaryClientReferenceIdList) - .build(); - BeneficiaryBulkResponse beneficiaryBulkResponse = serviceRequestClient.fetchResult( - new StringBuilder(adrmConfiguration.getProjectHost() - + adrmConfiguration.getProjectBeneficiarySearchUrl() - +"?limit=" + entities.size() - + "&offset=0&tenantId=" + tenantId), - BeneficiarySearchRequest.builder().requestInfo(request.getRequestInfo()).projectBeneficiary(projectBeneficiarySearch).build(), - BeneficiaryBulkResponse.class - ); - existingProjectBeneficiaries = beneficiaryBulkResponse.getProjectBeneficiaries(); - ProjectStaffSearch projectStaffSearch = ProjectStaffSearch.builder() - .id(projectStaffIdList.isEmpty() ? null : projectStaffIdList) - .build(); - ProjectStaffBulkResponse projectStaffBulkResponse = serviceRequestClient.fetchResult( - new StringBuilder(adrmConfiguration.getProjectHost() - + adrmConfiguration.getProjectStaffSearchUrl() - +"?limit=" + entities.size() - + "&offset=0&tenantId=" + tenantId), - ProjectStaffSearchRequest.builder().requestInfo(request.getRequestInfo()).projectStaff(projectStaffSearch).build(), - ProjectStaffBulkResponse.class - ); - existingProjectStaffList = projectStaffBulkResponse.getProjectStaff(); - - } catch (QueryBuilderException e) { - if(existingProjectBeneficiaries == null) existingProjectBeneficiaries = Collections.emptyList(); - existingProjectStaffList = Collections.emptyList(); - } catch (Exception e) { - throw new RuntimeException(e); - } - final List existingProjectBeneficiaryIds = new ArrayList<>(); - final List existingProjectBeneficiaryClientReferenceIds = new ArrayList<>(); - existingProjectBeneficiaries.forEach(projectBeneficiary -> { - existingProjectBeneficiaryIds.add(projectBeneficiary.getId()); - existingProjectBeneficiaryClientReferenceIds.add(projectBeneficiary.getClientReferenceId()); - }); - final List existingProjectStaffIds = new ArrayList<>(); - existingProjectStaffList.forEach(projectStaff -> existingProjectStaffIds.add(projectStaff.getId())); - List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> - !existingProjectStaffIds.contains(entity.getReferringPartyId()) - && !existingProjectBeneficiaryIds.contains(entity.getProjectBeneficiaryId()) - && !existingProjectBeneficiaryClientReferenceIds.contains(entity.getProjectBeneficiaryClientReferenceId()) - && (!entity.getReferredToType().equals(PROJECT_STAFF) || !existingProjectStaffIds.contains(entity.getReferredToId())) - ).collect(Collectors.toList()); - invalidEntities.forEach(referral -> { - Error error = getErrorForNonExistentEntity(); - populateErrorDetails(referral, error, errorDetailsMap); - }); - - } - }); - return errorDetailsMap; - } - - private void addIgnoreNull(List list, String item) { - if(Objects.nonNull(item)) list.add(item); - } -} diff --git a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmUniqueEntityValidator.java b/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmUniqueEntityValidator.java deleted file mode 100644 index 8a73836a870..00000000000 --- a/health-services/adrm/src/main/java/org/egov/adrm/validator/rm/RmUniqueEntityValidator.java +++ /dev/null @@ -1,47 +0,0 @@ -package org.egov.adrm.validator.rm; - -import lombok.extern.slf4j.Slf4j; -import org.egov.common.models.Error; -import org.egov.common.models.adrm.referralmanagement.Referral; -import org.egov.common.models.adrm.referralmanagement.ReferralBulkRequest; -import org.egov.common.validator.Validator; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.getIdToObjMap; -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; - -@Component -@Order(value = 2) -@Slf4j -public class RmUniqueEntityValidator implements Validator { - - @Override - public Map> validate(ReferralBulkRequest request) { - log.info("validating unique entity"); - Map> errorDetailsMap = new HashMap<>(); - List validEntities = request.getReferrals() - .stream().filter(notHavingErrors()).collect(Collectors.toList()); - if (!validEntities.isEmpty()) { - Map eMap = getIdToObjMap(validEntities); - if (eMap.keySet().size() != validEntities.size()) { - List duplicates = eMap.keySet().stream().filter(id -> - validEntities.stream() - .filter(entity -> entity.getId().equals(id)).count() > 1 - ).collect(Collectors.toList()); - for (String key : duplicates) { - Error error = getErrorForUniqueEntity(); - populateErrorDetails(eMap.get(key), error, errorDetailsMap); - } - } - } - return errorDetailsMap; - } -} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java deleted file mode 100644 index b7fbf6deff4..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/Referral.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.egov.common.models.adrm.referralmanagement; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.models.adrm.adverseevent.AdverseEvent; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; -import java.util.List; - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class Referral { - - @JsonProperty("id") - @Size(min = 2, max = 64) - private String id = null; - - @JsonProperty("clientReferenceId") - @Size(min = 2, max = 64) - private String clientReferenceId = null; - - @JsonProperty("projectBeneficiaryId") - @Size(min = 2, max = 64) - private String projectBeneficiaryId = null; - - @JsonProperty("projectBeneficiaryClientReferenceId") - @Size(min = 2, max = 64) - private String projectBeneficiaryClientReferenceId = null; - - @JsonProperty("referringPartyId") - @Size(min = 2, max = 64) - private String referringPartyId = null; - - @JsonProperty("referringPartyClientReferenceId") - @Size(min = 2, max = 64) - private String referringPartyClientReferenceId = null; - - @JsonProperty("referredToType") - private String referredToType = null; - - @JsonProperty("referredToId") - @Size(min = 2, max = 64) - private String referredToId = null; - - @JsonProperty("referredToClientReferenceId") - @Size(min = 2, max = 64) - private String referredToClientReferenceId = null; - - @JsonProperty("reasons") - @NotNull - @Size(min=1) - private List reasons = null; - - @JsonProperty("adverseEvent") - private AdverseEvent adverseEvent = null; - - @JsonProperty("tenantId") - @NotNull - @Size(min=2, max = 1000) - private String tenantId = null; - - @JsonProperty("isDeleted") - private Boolean isDeleted = Boolean.FALSE; - - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; - - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; -} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkRequest.java deleted file mode 100644 index 752c8bfdb26..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkRequest.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.egov.common.models.adrm.referralmanagement; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.contract.request.RequestInfo; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class ReferralBulkRequest { - @JsonProperty("RequestInfo") - @NotNull - @Valid - private RequestInfo requestInfo = null; - - @JsonProperty("Referrals") - @NotNull - @Valid - @Size(min = 1) - private List referrals = new ArrayList<>(); - - public ReferralBulkRequest addReferralItem(Referral referralItem) { - this.referrals.add(referralItem); - return this; - } -} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkResponse.java deleted file mode 100644 index f34d1df7ae0..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralBulkResponse.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.egov.common.models.adrm.referralmanagement; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.contract.response.ResponseInfo; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class ReferralBulkResponse { - @JsonProperty("ResponseInfo") - @NotNull - @Valid - private ResponseInfo responseInfo = null; - - @JsonProperty("Referrals") - @NotNull - @Valid - private List referrals = new ArrayList<>(); - - public ReferralBulkResponse addReferralItem(Referral referralItem) { - this.referrals.add(referralItem); - return this; - } -} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralRequest.java deleted file mode 100644 index ead7cedd3a2..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralRequest.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.egov.common.models.adrm.referralmanagement; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.contract.request.RequestInfo; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class ReferralRequest { - @JsonProperty("RequestInfo") - @NotNull - @Valid - private RequestInfo requestInfo = null; - - @JsonProperty("Referral") - @NotNull - @Valid - private Referral referral = null; -} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralResponse.java deleted file mode 100644 index 8bcae0afb31..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralResponse.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.egov.common.models.adrm.referralmanagement; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.contract.response.ResponseInfo; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class ReferralResponse { - @JsonProperty("ResponseInfo") - @NotNull - @Valid - private ResponseInfo responseInfo = null; - - @JsonProperty("Referral") - @NotNull - @Valid - private Referral referral = null; -} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearch.java deleted file mode 100644 index c54be75749b..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearch.java +++ /dev/null @@ -1,29 +0,0 @@ -package org.egov.common.models.adrm.referralmanagement; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -import java.util.List; - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class ReferralSearch { - @JsonProperty("id") - private List id = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; - - @JsonProperty("projectBeneficiaryId") - private List projectBeneficiaryId = null; - - @JsonProperty("projectBeneficiaryClientReferenceId") - private List projectBeneficiaryClientReferenceId = null; -} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearchRequest.java deleted file mode 100644 index c87c2265dd9..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/adrm/referralmanagement/ReferralSearchRequest.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.egov.common.models.adrm.referralmanagement; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.contract.request.RequestInfo; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class ReferralSearchRequest { - @JsonProperty("RequestInfo") - @NotNull - @Valid - private RequestInfo requestInfo = null; - - @JsonProperty("Referral") - @Valid - private ReferralSearch referral = null; -} From bbed04055dfa6b4bbb00e3aede0ecc0097033bd3 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 29 Sep 2023 15:58:59 +0530 Subject: [PATCH 172/283] HLM-3376: import fix --- .../referralmanagement/sideeffect/SideEffect.java | 4 ---- .../sideeffect/SideEffectBulkRequest.java | 4 ---- .../sideeffect/SideEffectBulkResponse.java | 4 ---- .../sideeffect/SideEffectRequest.java | 4 ---- .../sideeffect/SideEffectResponse.java | 4 ---- .../sideeffect/SideEffectSearch.java | 4 ---- .../sideeffect/SideEffectSearchRequest.java | 4 ---- .../repository/SideEffectRepository.java | 8 -------- .../repository/rowmapper/ReferralRowMapper.java | 3 +-- .../repository/rowmapper/SideEffectRowMapper.java | 4 ---- .../validator/sideeffect/SeIsDeletedValidator.java | 9 --------- .../sideeffect/SeNonExistentEntityValidator.java | 11 ----------- .../sideeffect/SeProjectTaskIdValidator.java | 13 ------------- .../sideeffect/SeUniqueEntityValidator.java | 9 --------- 14 files changed, 1 insertion(+), 84 deletions(-) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java index 7ddedd7be35..a078844a2dc 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java @@ -1,8 +1,4 @@ -<<<<<<<< HEAD:health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java package org.egov.common.models.referralmanagement.sideeffect; -======== -package org.egov.common.models.referralmanagement.adverseevent; ->>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEvent.java import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java index f619d8c227e..51319d73b51 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java @@ -1,8 +1,4 @@ -<<<<<<<< HEAD:health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java package org.egov.common.models.referralmanagement.sideeffect; -======== -package org.egov.common.models.referralmanagement.adverseevent; ->>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkRequest.java import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java index 9cff0a6fc9c..bfcfda3dae4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java @@ -1,8 +1,4 @@ -<<<<<<<< HEAD:health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java package org.egov.common.models.referralmanagement.sideeffect; -======== -package org.egov.common.models.referralmanagement.adverseevent; ->>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventBulkResponse.java import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java index 811814e4ea9..9de2e92b66e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java @@ -1,8 +1,4 @@ -<<<<<<<< HEAD:health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java package org.egov.common.models.referralmanagement.sideeffect; -======== -package org.egov.common.models.referralmanagement.adverseevent; ->>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventRequest.java import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java index be8354c530a..9e96194482c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java @@ -1,8 +1,4 @@ -<<<<<<<< HEAD:health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java package org.egov.common.models.referralmanagement.sideeffect; -======== -package org.egov.common.models.referralmanagement.adverseevent; ->>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventResponse.java import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java index 214ae9755ea..3183a2533d6 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java @@ -1,8 +1,4 @@ -<<<<<<<< HEAD:health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java package org.egov.common.models.referralmanagement.sideeffect; -======== -package org.egov.common.models.referralmanagement.adverseevent; ->>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearch.java import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java index 564873abdf8..69cc688f884 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java @@ -1,8 +1,4 @@ -<<<<<<<< HEAD:health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java package org.egov.common.models.referralmanagement.sideeffect; -======== -package org.egov.common.models.referralmanagement.adverseevent; ->>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/adverseevent/AdverseEventSearchRequest.java import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java index 460bcbb8034..c3ce7ea000b 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java @@ -6,19 +6,11 @@ import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; -<<<<<<<< HEAD:health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearch; import org.egov.common.models.project.Task; import org.egov.common.producer.Producer; import org.egov.referralmanagement.repository.rowmapper.SideEffectRowMapper; -======== -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearch; -import org.egov.common.models.project.Task; -import org.egov.common.producer.Producer; -import org.egov.referralmanagement.repository.rowmapper.AdverseEventRowMapper; ->>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/AdverseEventRepository.java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java index 1895e0829cc..b325b2ba3f7 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; import org.egov.common.models.referralmanagement.Referral; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.RowMapper; @@ -22,7 +21,7 @@ public class ReferralRowMapper implements RowMapper { @Override public Referral mapRow(ResultSet resultSet, int i) throws SQLException { try { - AdverseEvent adverseEvent = null; + SideEffect adverseEvent = null; String adverseEventClientReferenceId = resultSet.getString("adverseEventClientReferenceId"); if(adverseEventClientReferenceId != null) { AuditDetails adverseEventAuditDetails = AuditDetails.builder() diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java index db93f292b98..7a49ceef93e 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java @@ -3,11 +3,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -<<<<<<<< HEAD:health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java import org.egov.common.models.referralmanagement.sideeffect.SideEffect; -======== -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; ->>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/AdverseEventRowMapper.java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeIsDeletedValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeIsDeletedValidator.java index f8ab13e405f..b6e4d3f94f3 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeIsDeletedValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeIsDeletedValidator.java @@ -1,18 +1,9 @@ -<<<<<<<< HEAD:health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeIsDeletedValidator.java package org.egov.referralmanagement.validator.sideeffect; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; -======== -package org.egov.referralmanagement.validator.adverseevent; - -import lombok.extern.slf4j.Slf4j; -import org.egov.common.models.Error; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; ->>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdIsDeletedValidator.java import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNonExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNonExistentEntityValidator.java index 3ce8ab65f31..5f70cd0fef5 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNonExistentEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNonExistentEntityValidator.java @@ -1,4 +1,3 @@ -<<<<<<<< HEAD:health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeNonExistentEntityValidator.java package org.egov.referralmanagement.validator.sideeffect; import com.fasterxml.jackson.databind.ObjectMapper; @@ -7,16 +6,6 @@ import org.egov.common.models.Error; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; -======== -package org.egov.referralmanagement.validator.adverseevent; - -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.extern.slf4j.Slf4j; -import org.egov.referralmanagement.repository.AdverseEventRepository; -import org.egov.common.models.Error; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; ->>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdNonExistentEntityValidator.java import org.egov.common.validator.Validator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java index 2bdca8ac056..4d1b2609c26 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java @@ -1,8 +1,4 @@ -<<<<<<<< HEAD:health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java package org.egov.referralmanagement.validator.sideeffect; -======== -package org.egov.referralmanagement.validator.adverseevent; ->>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdProjectTaskIdValidator.java import lombok.extern.slf4j.Slf4j; import org.egov.referralmanagement.config.ReferralManagementConfiguration; @@ -17,13 +13,8 @@ import org.egov.common.models.project.TaskBulkResponse; import org.egov.common.models.project.TaskSearch; import org.egov.common.models.project.TaskSearchRequest; -<<<<<<<< HEAD:health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; -======== -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; ->>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdProjectTaskIdValidator.java import org.egov.common.validator.Validator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; @@ -50,11 +41,7 @@ public class SeProjectTaskIdValidator implements Validator>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdProjectTaskIdValidator.java this.serviceRequestClient = serviceRequestClient; this.referralManagementConfiguration = referralManagementConfiguration; } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java index 68e90378e19..43f99f7cef2 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java @@ -1,18 +1,9 @@ -<<<<<<<< HEAD:health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java package org.egov.referralmanagement.validator.sideeffect; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; -======== -package org.egov.referralmanagement.validator.adverseevent; - -import lombok.extern.slf4j.Slf4j; -import org.egov.common.models.Error; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; ->>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/adverseevent/AdUniqueEntityValidator.java import org.egov.common.validator.Validator; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; From 082ae4a83fcdc460494bd555057c2f245d3abf6d Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 29 Sep 2023 16:50:17 +0530 Subject: [PATCH 173/283] HLM-3376: refactor code --- .../models/referralmanagement/Referral.java | 6 +- .../repository/ReferralRepository.java | 4 +- .../rowmapper/ReferralRowMapper.java | 47 +-- .../service/AdverseEventService.java | 237 --------------- .../service/ReferralManagementService.java | 40 +-- .../RmNonExistentEntityValidator.java | 8 +- .../ReferralManagementApiController.java | 4 - .../V20230928113400__referral_create_ddl.sql | 11 +- .../referral-management-persister.yml | 274 +++++++++--------- .../helper/SideEffectTestBuilder.java | 4 - .../SideEffectApiControllerTest.java | 23 +- 11 files changed, 201 insertions(+), 457 deletions(-) delete mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/AdverseEventService.java diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java index 172cc0339e0..50612ab91dc 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java @@ -8,7 +8,7 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import javax.validation.Valid; import javax.validation.constraints.NotNull; @@ -54,8 +54,8 @@ public class Referral { @Size(min=1) private List reasons = null; - @JsonProperty("adverseEvent") - private AdverseEvent adverseEvent = null; + @JsonProperty("sideEffect") + private SideEffect sideEffect = null; @JsonProperty("tenantId") @NotNull diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java index dd016da5a2e..ca6e891bf97 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java @@ -40,7 +40,7 @@ protected ReferralRepository(Producer producer, NamedParameterJdbcTemplate named public List find(ReferralSearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { - String query = "SELECT r.*, ae.id, ae.clientreferenceid, ae.tenantid, ae.taskid, ae.taskclientreferenceid, ae.symptoms, ae.reattempts, ae.createdby, ae.createdtime, ae.lastmodifiedby, ae.lastmodifiedtime, ae.clientcreatedtime, ae.clientlastmodifiedtime, ae.rowversion, ae.isdeleted FROM referral r left join adverse_event ae on r.adverseEventclientReferenceid = ae.clientreferenceid"; + String query = "SELECT r.*, se.id, se.clientreferenceid, se.tenantid, se.taskid, se.taskclientreferenceid, se.symptoms, se.reattempts, se.createdby, se.createdtime, se.lastmodifiedby, se.lastmodifiedtime, se.clientcreatedtime, se.clientlastmodifiedtime, se.rowversion, se.isdeleted FROM referral r left join side_effect se on r.sideEffectClientReferenceid = se.clientreferenceid"; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); @@ -80,7 +80,7 @@ public List findById(List ids, String columnName, Boolean incl } } - String query = String.format("SELECT r.*, ae.id, ae.clientreferenceid, ae.tenantid, ae.taskid, ae.taskclientreferenceid, ae.symptoms, ae.reattempts, ae.createdby, ae.createdtime, ae.lastmodifiedby, ae.lastmodifiedtime, ae.clientcreatedtime, ae.clientlastmodifiedtime, ae.rowversion, ae.isdeleted FROM referral r left join adverse_event ae on r.adverseEventclientReferenceid = ae.clientreferenceid WHERE r.%s IN (:ids) ", columnName); + String query = String.format("SELECT r.*, se.id, se.clientreferenceid, se.tenantid, se.taskid, se.taskclientreferenceid, se.symptoms, se.reattempts, se.createdby, se.createdtime, se.lastmodifiedby, se.lastmodifiedtime, se.clientcreatedtime, se.clientlastmodifiedtime, se.rowversion, se.isdeleted FROM referral r left join side_effect se on r.sideEffectClientReferenceid = se.clientreferenceid WHERE r.%s IN (:ids) ", columnName); if (includeDeleted == null || !includeDeleted) { query += " AND r.isDeleted = false "; } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java index b325b2ba3f7..a7a3692d3ed 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; @@ -21,30 +22,30 @@ public class ReferralRowMapper implements RowMapper { @Override public Referral mapRow(ResultSet resultSet, int i) throws SQLException { try { - SideEffect adverseEvent = null; - String adverseEventClientReferenceId = resultSet.getString("adverseEventClientReferenceId"); - if(adverseEventClientReferenceId != null) { - AuditDetails adverseEventAuditDetails = AuditDetails.builder() - .createdBy(resultSet.getString("ae.createdBy")) - .createdTime(resultSet.getLong("ae.createdTime")) - .lastModifiedBy(resultSet.getString("ae.lastModifiedBy")) - .lastModifiedTime(resultSet.getLong("ae.lastModifiedTime")) + SideEffect sideEffect = null; + String sideEffectClientReferenceId = resultSet.getString("sideEffectClientReferenceId"); + if(sideEffectClientReferenceId != null) { + AuditDetails sideEffectAuditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("se.createdBy")) + .createdTime(resultSet.getLong("se.createdTime")) + .lastModifiedBy(resultSet.getString("se.lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("se.lastModifiedTime")) .build(); - AuditDetails adverseEventClientAuditDetails = AuditDetails.builder() - .createdTime(resultSet.getLong("ae.clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("ae.clientLastModifiedTime")) + AuditDetails sideEffectClientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("se.clientCreatedTime")) + .lastModifiedTime(resultSet.getLong("se.clientLastModifiedTime")) .build(); - adverseEvent = AdverseEvent.builder() - .id(resultSet.getString("ae.id")) - .clientReferenceId(resultSet.getString("ae.clientreferenceid")) - .taskId(resultSet.getString("ae.taskId")) - .taskClientReferenceId(resultSet.getString("ae.taskClientreferenceid")) - .tenantId(resultSet.getString("ae.tenantid")) - .symptoms(resultSet.getString("ae.symptoms") == null ? null : objectMapper.readValue(resultSet.getString("ae.symptoms"), ArrayList.class)) - .rowVersion(resultSet.getInt("ae.rowversion")) - .isDeleted(resultSet.getBoolean("ae.isdeleted")) - .auditDetails(adverseEventAuditDetails) - .clientAuditDetails(adverseEventClientAuditDetails) + sideEffect = SideEffect.builder() + .id(resultSet.getString("se.id")) + .clientReferenceId(resultSet.getString("se.clientreferenceid")) + .taskId(resultSet.getString("se.taskId")) + .taskClientReferenceId(resultSet.getString("se.taskClientreferenceid")) + .tenantId(resultSet.getString("se.tenantid")) + .symptoms(resultSet.getString("se.symptoms") == null ? null : objectMapper.readValue(resultSet.getString("se.symptoms"), ArrayList.class)) + .rowVersion(resultSet.getInt("se.rowversion")) + .isDeleted(resultSet.getBoolean("se.isdeleted")) + .auditDetails(sideEffectAuditDetails) + .clientAuditDetails(sideEffectClientAuditDetails) .build(); } AuditDetails auditDetails = AuditDetails.builder() @@ -67,7 +68,7 @@ public Referral mapRow(ResultSet resultSet, int i) throws SQLException { .referredById(resultSet.getString("referredById")) .referredToId(resultSet.getString("referredToId")) .referredToType(resultSet.getString("referredToType")) - .adverseEvent(adverseEvent) + .sideEffect(sideEffect) .tenantId(resultSet.getString("tenantid")) .reasons(resultSet.getString("reasons") == null ? null : objectMapper.readValue(resultSet.getString("reasons"), ArrayList.class)) .rowVersion(resultSet.getInt("rowversion")) diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/AdverseEventService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/AdverseEventService.java deleted file mode 100644 index d91637882c3..00000000000 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/AdverseEventService.java +++ /dev/null @@ -1,237 +0,0 @@ -package org.egov.referralmanagement.service; - -import lombok.extern.slf4j.Slf4j; -import org.egov.referralmanagement.Constants; -import org.egov.referralmanagement.config.ReferralManagementConfiguration; -import org.egov.referralmanagement.repository.AdverseEventRepository; -import org.egov.referralmanagement.service.enrichment.AdverseEventEnrichmentService; -import org.egov.referralmanagement.validator.adverseevent.AdIsDeletedValidator; -import org.egov.referralmanagement.validator.adverseevent.AdNonExistentEntityValidator; -import org.egov.referralmanagement.validator.adverseevent.AdNullIdValidator; -import org.egov.referralmanagement.validator.adverseevent.AdProjectTaskIdValidator; -import org.egov.referralmanagement.validator.adverseevent.AdUniqueEntityValidator; -import org.egov.common.ds.Tuple; -import org.egov.common.models.ErrorDetails; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkRequest; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventRequest; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearchRequest; -import org.egov.common.service.IdGenService; -import org.egov.common.utils.CommonUtils; -import org.egov.common.validator.Validator; -import org.egov.tracer.model.CustomException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.util.ReflectionUtils; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.getIdFieldName; -import static org.egov.common.utils.CommonUtils.getIdMethod; -import static org.egov.common.utils.CommonUtils.handleErrors; -import static org.egov.common.utils.CommonUtils.havingTenantId; -import static org.egov.common.utils.CommonUtils.includeDeleted; -import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; -import static org.egov.common.utils.CommonUtils.lastChangedSince; -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; - -@Service -@Slf4j -public class AdverseEventService { - private final IdGenService idGenService; - - private final AdverseEventRepository adverseEventRepository; - - private final ReferralManagementConfiguration referralManagementConfiguration; - - private final AdverseEventEnrichmentService adverseEventEnrichmentService; - - private final List> validators; - - private final Predicate> isApplicableForCreate = validator -> - validator.getClass().equals(AdProjectTaskIdValidator.class); - - private final Predicate> isApplicableForUpdate = validator -> - validator.getClass().equals(AdProjectTaskIdValidator.class) - || validator.getClass().equals(AdNullIdValidator.class) - || validator.getClass().equals(AdIsDeletedValidator.class) - || validator.getClass().equals(AdUniqueEntityValidator.class) - || validator.getClass().equals(AdNonExistentEntityValidator.class); - - private final Predicate> isApplicableForDelete = validator -> - validator.getClass().equals(AdNullIdValidator.class) - || validator.getClass().equals(AdNonExistentEntityValidator.class); - - @Autowired - public AdverseEventService( - IdGenService idGenService, - AdverseEventRepository adverseEventRepository, - ReferralManagementConfiguration referralManagementConfiguration, - AdverseEventEnrichmentService adverseEventEnrichmentService, - List> validators - ) { - this.idGenService = idGenService; - this.adverseEventRepository = adverseEventRepository; - this.referralManagementConfiguration = referralManagementConfiguration; - this.adverseEventEnrichmentService = adverseEventEnrichmentService; - this.validators = validators; - } - - public AdverseEvent create(AdverseEventRequest request) { - log.info("received request to create adverse events"); - AdverseEventBulkRequest bulkRequest = AdverseEventBulkRequest.builder().requestInfo(request.getRequestInfo()) - .adverseEvents(Collections.singletonList(request.getAdverseEvent())).build(); - log.info("creating bulk request"); - return create(bulkRequest, false).get(0); - } - - public List create(AdverseEventBulkRequest adverseEventRequest, boolean isBulk) { - log.info("received request to create bulk adverse events"); - Tuple, Map> tuple = validate(validators, - isApplicableForCreate, adverseEventRequest, isBulk); - Map errorDetailsMap = tuple.getY(); - List validAdverseEvents = tuple.getX(); - - try { - if (!validAdverseEvents.isEmpty()) { - log.info("processing {} valid entities", validAdverseEvents.size()); - adverseEventEnrichmentService.create(validAdverseEvents, adverseEventRequest); - adverseEventRepository.save(validAdverseEvents, - referralManagementConfiguration.getCreateAdverseEventTopic()); - log.info("successfully created adverse events"); - } - } catch (Exception exception) { - log.error("error occurred while creating adverse events: {}", exception.getMessage()); - populateErrorDetails(adverseEventRequest, errorDetailsMap, validAdverseEvents, - exception, Constants.SET_REFERRALS); - } - handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); - - return validAdverseEvents; - } - - public AdverseEvent update(AdverseEventRequest request) { - log.info("received request to update adverse event"); - AdverseEventBulkRequest bulkRequest = AdverseEventBulkRequest.builder().requestInfo(request.getRequestInfo()) - .adverseEvents(Collections.singletonList(request.getAdverseEvent())).build(); - log.info("creating bulk request"); - return update(bulkRequest, false).get(0); - } - - public List update(AdverseEventBulkRequest adverseEventRequest, boolean isBulk) { - log.info("received request to update bulk adverse event"); - Tuple, Map> tuple = validate(validators, - isApplicableForUpdate, adverseEventRequest, isBulk); - Map errorDetailsMap = tuple.getY(); - List validAdverseEvents = tuple.getX(); - - try { - if (!validAdverseEvents.isEmpty()) { - log.info("processing {} valid entities", validAdverseEvents.size()); - adverseEventEnrichmentService.update(validAdverseEvents, adverseEventRequest); - adverseEventRepository.save(validAdverseEvents, - referralManagementConfiguration.getUpdateAdverseEventTopic()); - log.info("successfully updated bulk adverse events"); - } - } catch (Exception exception) { - log.error("error occurred while updating adverse events", exception); - populateErrorDetails(adverseEventRequest, errorDetailsMap, validAdverseEvents, - exception, Constants.SET_REFERRALS); - } - handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); - - return validAdverseEvents; - } - - public List search(AdverseEventSearchRequest adverseEventSearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { - log.info("received request to search adverse events"); - String idFieldName = getIdFieldName(adverseEventSearchRequest.getAdverseEvent()); - if (isSearchByIdOnly(adverseEventSearchRequest.getAdverseEvent(), idFieldName)) { - log.info("searching adverse events by id"); - List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections - .singletonList(adverseEventSearchRequest.getAdverseEvent())), - adverseEventSearchRequest.getAdverseEvent()); - log.info("fetching adverse events with ids: {}", ids); - return adverseEventRepository.findById(ids, includeDeleted, idFieldName).stream() - .filter(lastChangedSince(lastChangedSince)) - .filter(havingTenantId(tenantId)) - .filter(includeDeleted(includeDeleted)) - .collect(Collectors.toList()); - } - log.info("searching adverse events using criteria"); - return adverseEventRepository.find(adverseEventSearchRequest.getAdverseEvent(), - limit, offset, tenantId, lastChangedSince, includeDeleted); - } - - public AdverseEvent delete(AdverseEventRequest adverseEventRequest) { - log.info("received request to delete a adverse event"); - AdverseEventBulkRequest bulkRequest = AdverseEventBulkRequest.builder().requestInfo(adverseEventRequest.getRequestInfo()) - .adverseEvents(Collections.singletonList(adverseEventRequest.getAdverseEvent())).build(); - log.info("creating bulk request"); - return delete(bulkRequest, false).get(0); - } - - public List delete(AdverseEventBulkRequest adverseEventRequest, boolean isBulk) { - Tuple, Map> tuple = validate(validators, - isApplicableForDelete, adverseEventRequest, isBulk); - Map errorDetailsMap = tuple.getY(); - List validAdverseEvents = tuple.getX(); - - try { - if (!validAdverseEvents.isEmpty()) { - log.info("processing {} valid entities", validAdverseEvents.size()); - List adverseEventIds = validAdverseEvents.stream().map(entity -> entity.getId()).collect(Collectors.toSet()).stream().collect(Collectors.toList()); - List existingAdverseEvents = adverseEventRepository - .findById(adverseEventIds, false); - adverseEventEnrichmentService.delete(existingAdverseEvents, adverseEventRequest); - adverseEventRepository.save(existingAdverseEvents, - referralManagementConfiguration.getDeleteAdverseEventTopic()); - log.info("successfully deleted entities"); - } - } catch (Exception exception) { - log.error("error occurred while deleting entities: {}", exception); - populateErrorDetails(adverseEventRequest, errorDetailsMap, validAdverseEvents, - exception, Constants.SET_REFERRALS); - } - handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); - - return validAdverseEvents; - } - - public void putInCache(List adverseEvents) { - log.info("putting {} adverse events in cache", adverseEvents.size()); - adverseEventRepository.putInCache(adverseEvents); - log.info("successfully put adverse events in cache"); - } - - private Tuple, Map> validate( - List> validators, - Predicate> isApplicable, - AdverseEventBulkRequest request, - boolean isBulk - ) { - log.info("validating request"); - Map errorDetailsMap = CommonUtils.validate(validators, - isApplicable, request, - Constants.SET_REFERRALS); - if (!errorDetailsMap.isEmpty() && !isBulk) { - log.error("validation error occurred. error details: {}", errorDetailsMap.values().toString()); - throw new CustomException(Constants.VALIDATION_ERROR, errorDetailsMap.values().toString()); - } - List validAdverseEvents = request.getAdverseEvents().stream() - .filter(notHavingErrors()).collect(Collectors.toList()); - log.info("validation successful, found valid adverse events"); - return new Tuple<>(validAdverseEvents, errorDetailsMap); - } - -} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java index 4f064c6698a..ea7f107e0ea 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java @@ -79,7 +79,7 @@ public ReferralManagementService(IdGenService idGenService, ReferralRepository r } public Referral create(ReferralRequest request) { - log.info("received request to create adverse events"); + log.info("received request to create referrals"); ReferralBulkRequest bulkRequest = ReferralBulkRequest.builder().requestInfo(request.getRequestInfo()) .referrals(Collections.singletonList(request.getReferral())).build(); log.info("creating bulk request"); @@ -87,7 +87,7 @@ public Referral create(ReferralRequest request) { } public List create(ReferralBulkRequest referralRequest, boolean isBulk) { - log.info("received request to create bulk adverse events"); + log.info("received request to create bulk referrals"); Tuple, Map> tuple = validate(validators, isApplicableForCreate, referralRequest, isBulk); Map errorDetailsMap = tuple.getY(); @@ -99,12 +99,12 @@ public List create(ReferralBulkRequest referralRequest, boolean isBulk referralManagementEnrichmentService.create(validReferrals, referralRequest); referralRepository.save(validReferrals, referralManagementConfiguration.getCreateReferralTopic()); - log.info("successfully created adverse events"); + log.info("successfully created referrals"); } } catch (Exception exception) { - log.error("error occurred while creating adverse events: {}", exception.getMessage()); + log.error("error occurred while creating referrals: {}", exception.getMessage()); populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, - exception, Constants.SET_ADVERSE_EVENTS); + exception, Constants.SET_SIDE_EFFECTS); } handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); @@ -112,7 +112,7 @@ public List create(ReferralBulkRequest referralRequest, boolean isBulk } public Referral update(ReferralRequest request) { - log.info("received request to update adverse event"); + log.info("received request to update referral"); ReferralBulkRequest bulkRequest = ReferralBulkRequest.builder().requestInfo(request.getRequestInfo()) .referrals(Collections.singletonList(request.getReferral())).build(); log.info("creating bulk request"); @@ -120,7 +120,7 @@ public Referral update(ReferralRequest request) { } public List update(ReferralBulkRequest referralRequest, boolean isBulk) { - log.info("received request to update bulk adverse event"); + log.info("received request to update bulk referral"); Tuple, Map> tuple = validate(validators, isApplicableForUpdate, referralRequest, isBulk); Map errorDetailsMap = tuple.getY(); @@ -132,12 +132,12 @@ public List update(ReferralBulkRequest referralRequest, boolean isBulk referralManagementEnrichmentService.update(validReferrals, referralRequest); referralRepository.save(validReferrals, referralManagementConfiguration.getUpdateReferralTopic()); - log.info("successfully updated bulk adverse events"); + log.info("successfully updated bulk referrals"); } } catch (Exception exception) { - log.error("error occurred while updating adverse events", exception); + log.error("error occurred while updating referrals", exception); populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, - exception, Constants.SET_ADVERSE_EVENTS); + exception, Constants.SET_SIDE_EFFECTS); } handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); @@ -150,27 +150,27 @@ public List search(ReferralSearchRequest referralSearchRequest, String tenantId, Long lastChangedSince, Boolean includeDeleted) throws Exception { - log.info("received request to search adverse events"); + log.info("received request to search referrals"); String idFieldName = getIdFieldName(referralSearchRequest.getReferral()); if (isSearchByIdOnly(referralSearchRequest.getReferral(), idFieldName)) { - log.info("searching adverse events by id"); + log.info("searching referrals by id"); List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections .singletonList(referralSearchRequest.getReferral())), referralSearchRequest.getReferral()); - log.info("fetching adverse events with ids: {}", ids); + log.info("fetching referrals with ids: {}", ids); return referralRepository.findById(ids, includeDeleted, idFieldName).stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); } - log.info("searching adverse events using criteria"); + log.info("searching referrals using criteria"); return referralRepository.find(referralSearchRequest.getReferral(), limit, offset, tenantId, lastChangedSince, includeDeleted); } public Referral delete(ReferralRequest referralRequest) { - log.info("received request to delete a adverse event"); + log.info("received request to delete a referral"); ReferralBulkRequest bulkRequest = ReferralBulkRequest.builder().requestInfo(referralRequest.getRequestInfo()) .referrals(Collections.singletonList(referralRequest.getReferral())).build(); log.info("creating bulk request"); @@ -197,7 +197,7 @@ public List delete(ReferralBulkRequest referralRequest, boolean isBulk } catch (Exception exception) { log.error("error occurred while deleting entities: {}", exception); populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, - exception, Constants.SET_ADVERSE_EVENTS); + exception, Constants.SET_SIDE_EFFECTS); } handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); @@ -205,9 +205,9 @@ public List delete(ReferralBulkRequest referralRequest, boolean isBulk } public void putInCache(List referrals) { - log.info("putting {} adverse events in cache", referrals.size()); + log.info("putting {} referrals in cache", referrals.size()); referralRepository.putInCache(referrals); - log.info("successfully put adverse events in cache"); + log.info("successfully put referrals in cache"); } private Tuple, Map> validate( @@ -219,14 +219,14 @@ private Tuple, Map> validate( log.info("validating request"); Map errorDetailsMap = CommonUtils.validate(validators, isApplicable, request, - Constants.SET_ADVERSE_EVENTS); + Constants.SET_SIDE_EFFECTS); if (!errorDetailsMap.isEmpty() && !isBulk) { log.error("validation error occurred. error details: {}", errorDetailsMap.values().toString()); throw new CustomException(Constants.VALIDATION_ERROR, errorDetailsMap.values().toString()); } List validReferrals = request.getReferrals().stream() .filter(notHavingErrors()).collect(Collectors.toList()); - log.info("validation successful, found valid adverse events"); + log.info("validation successful, found valid referrals"); return new Tuple<>(validReferrals, errorDetailsMap); } } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java index 7f970822522..295d88f5227 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java @@ -54,14 +54,14 @@ public Map> validate(ReferralBulkRequest request) { Map iMap = getIdToObjMap(referrals .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); if (!iMap.isEmpty()) { - List adverseEventIds = new ArrayList<>(iMap.keySet()); + List sideEffectIds = new ArrayList<>(iMap.keySet()); List existingReferrals = referralRepository - .findById(adverseEventIds, false, getIdFieldName(idMethod)); + .findById(sideEffectIds, false, getIdFieldName(idMethod)); List nonExistentReferrals = checkNonExistentEntities(iMap, existingReferrals, idMethod); - nonExistentReferrals.forEach(adverseEvent -> { + nonExistentReferrals.forEach(sideEffect -> { Error error = getErrorForNonExistentEntity(); - populateErrorDetails(adverseEvent, error, errorDetailsMap); + populateErrorDetails(sideEffect, error, errorDetailsMap); }); } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java index c2c63a9ff98..499760f0f78 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java @@ -38,11 +38,7 @@ public class ReferralManagementApiController { private final Producer producer; -<<<<<<< HEAD private final ReferralManagementConfiguration referralManagementConfiguration; -======= - private final AdrmConfiguration adrmConfiguration; ->>>>>>> 73a5aefec0 (HLM-3069: changed module name to referral management) public ReferralManagementApiController( HttpServletRequest httpServletRequest, diff --git a/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928113400__referral_create_ddl.sql b/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928113400__referral_create_ddl.sql index a18383c453f..15ed8373d7f 100644 --- a/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928113400__referral_create_ddl.sql +++ b/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928113400__referral_create_ddl.sql @@ -9,15 +9,16 @@ CREATE TABLE REFERRAL referredToId character varying(100), referredToType character varying(100), reasons jsonb, - adverseEventId character varying(100), + sideEffectId character varying(100), + sideEffectClientReferenceId character varying(100), createdBy character varying(64), createdTime bigint, lastModifiedBy character varying(64), lastModifiedTime bigint, - clientCreatedBy character varying(64), - clientCreatedTime bigint, - clientLastModifiedBy character varying(64), - clientLastModifiedTime bigint, + clientCreatedBy character varying(64), + clientCreatedTime bigint, + clientLastModifiedBy character varying(64), + clientLastModifiedTime bigint, rowVersion bigint, isDeleted boolean, CONSTRAINT uk_referral_id PRIMARY KEY (id), diff --git a/health-services/referralmanagement/src/main/resources/referral-management-persister.yml b/health-services/referralmanagement/src/main/resources/referral-management-persister.yml index 933197462d0..a3342191930 100644 --- a/health-services/referralmanagement/src/main/resources/referral-management-persister.yml +++ b/health-services/referralmanagement/src/main/resources/referral-management-persister.yml @@ -1,146 +1,146 @@ serviceMaps: serviceName: referralmanagement - mappings: - - version: 1.0 - description: Saves a side effect - fromTopic: save-side-effect-topic - isTransaction: true - queryMaps: - - query: INSERT INTO SIDE_EFFECT(id, clientReferenceId, tenantId, taskId, taskClientReferenceId, projectBeneficiaryId, projectBeneficiaryClientReferenceId,symptoms, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedBy, clientCreatedTime, clientLastModifiedBy, clientLastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); - basePath: $.* - jsonMaps: - - jsonPath: $.*.id - - jsonPath: $.*.clientReferenceId - - jsonPath: $.*.tenantId - - jsonPath: $.*.taskId - - jsonPath: $.*.taskClientReferenceId - - jsonPath: $.*.projectBeneficiaryId - - jsonPath: $.*.projectBeneficiaryClientReferenceId - - jsonPath: $.*.symptoms - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.createdBy - - jsonPath: $.*.auditDetails.createdTime - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.clientAuditDetails.createdBy - - jsonPath: $.*.clientAuditDetails.createdTime - - jsonPath: $.*.clientAuditDetails.lastModifiedBy - - jsonPath: $.*.clientAuditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted + mappings: + - version: 1.0 + description: Saves a side effect + fromTopic: save-side-effect-topic + isTransaction: true + queryMaps: + - query: INSERT INTO SIDE_EFFECT(id, clientReferenceId, tenantId, taskId, taskClientReferenceId, projectBeneficiaryId, projectBeneficiaryClientReferenceId,symptoms, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedBy, clientCreatedTime, clientLastModifiedBy, clientLastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); + basePath: $.* + jsonMaps: + - jsonPath: $.*.id + - jsonPath: $.*.clientReferenceId + - jsonPath: $.*.tenantId + - jsonPath: $.*.taskId + - jsonPath: $.*.taskClientReferenceId + - jsonPath: $.*.projectBeneficiaryId + - jsonPath: $.*.projectBeneficiaryClientReferenceId + - jsonPath: $.*.symptoms + type: JSON + dbType: JSONB + - jsonPath: $.*.auditDetails.createdBy + - jsonPath: $.*.auditDetails.createdTime + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.createdBy + - jsonPath: $.*.clientAuditDetails.createdTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted - - version: 1.0 - description: Updates a side effect - fromTopic: update-side-effect-topic - isTransaction: true - queryMaps: - - query: UPDATE SIDE_EFFECT SET tenantId = ?, taskId = ?, taskClientReferenceId = ?, projectBeneficiaryId = ?, projectBeneficiaryClientReferenceId = ?, symptoms = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.tenantId - - jsonPath: $.*.taskId - - jsonPath: $.*.taskClientReferenceId - - jsonPath: $.*.projectBeneficiaryId - - jsonPath: $.*.projectBeneficiaryClientReferenceId - - jsonPath: $.*.symptoms - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.clientAuditDetails.lastModifiedBy - - jsonPath: $.*.clientAuditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id + - version: 1.0 + description: Updates a side effect + fromTopic: update-side-effect-topic + isTransaction: true + queryMaps: + - query: UPDATE SIDE_EFFECT SET tenantId = ?, taskId = ?, taskClientReferenceId = ?, projectBeneficiaryId = ?, projectBeneficiaryClientReferenceId = ?, symptoms = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.tenantId + - jsonPath: $.*.taskId + - jsonPath: $.*.taskClientReferenceId + - jsonPath: $.*.projectBeneficiaryId + - jsonPath: $.*.projectBeneficiaryClientReferenceId + - jsonPath: $.*.symptoms + type: JSON + dbType: JSONB + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - jsonPath: $.*.id - - version: 1.0 - description: Deletes a side effect - fromTopic: delete-side-effect-topic - isTransaction: true - queryMaps: - - query: UPDATE SIDE_EFFECT SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.clientAuditDetails.lastModifiedBy - - jsonPath: $.*.clientAuditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id + - version: 1.0 + description: Deletes a side effect + fromTopic: delete-side-effect-topic + isTransaction: true + queryMaps: + - query: UPDATE SIDE_EFFECT SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - jsonPath: $.*.id - - version: 1.0 - description: Saves a referral - fromTopic: save-referral-topic - isTransaction: true - queryMaps: - - query: INSERT INTO REFERRAL(id, clientReferenceId, tenantId, projectBeneficiaryId, projectBeneficiaryClientReferenceId, referredById, referredToId, referredToType, reasons, adverseEventId, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedBy, clientCreatedTime, clientLastModifiedBy, clientLastModifiedTime, rowVersion, isDeleted) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); - basePath: $.* - jsonMaps: - - jsonPath: $.*.id - - jsonPath: $.*.clientReferenceId - - jsonPath: $.*.tenantId - - jsonPath: $.*.projectBeneficiaryId - - jsonPath: $.*.projectBeneficiaryClientReferenceId - - jsonPath: $.*.referredById - - jsonPath: $.*.referredToId - - jsonPath: $.*.referredToType - - jsonPath: $.*.reasons - type: JSON - dbType: JSONB - - jsonPath: $.*.adverseEvent.id - - jsonPath: $.*.auditDetails.createdBy - - jsonPath: $.*.auditDetails.createdTime - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.clientAuditDetails.createdBy - - jsonPath: $.*.clientAuditDetails.createdTime - - jsonPath: $.*.clientAuditDetails.lastModifiedBy - - jsonPath: $.*.clientAuditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted + - version: 1.0 + description: Saves a referral + fromTopic: save-referral-topic + isTransaction: true + queryMaps: + - query: INSERT INTO REFERRAL(id, clientReferenceId, tenantId, projectBeneficiaryId, projectBeneficiaryClientReferenceId, referredById, referredToId, referredToType, reasons, sideEffectId, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedBy, clientCreatedTime, clientLastModifiedBy, clientLastModifiedTime, rowVersion, isDeleted) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); + basePath: $.* + jsonMaps: + - jsonPath: $.*.id + - jsonPath: $.*.clientReferenceId + - jsonPath: $.*.tenantId + - jsonPath: $.*.projectBeneficiaryId + - jsonPath: $.*.projectBeneficiaryClientReferenceId + - jsonPath: $.*.referredById + - jsonPath: $.*.referredToId + - jsonPath: $.*.referredToType + - jsonPath: $.*.reasons + type: JSON + dbType: JSONB + - jsonPath: $.*.sideEffect.id + - jsonPath: $.*.auditDetails.createdBy + - jsonPath: $.*.auditDetails.createdTime + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.createdBy + - jsonPath: $.*.clientAuditDetails.createdTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted - - version: 1.0 - description: Updates a referral - fromTopic: update-referral-topic - isTransaction: true - queryMaps: - - query: UPDATE REFERRAL SET tenantId = ?, projectBeneficiaryId = ?, projectBeneficiaryClientReferenceId = ?, referredById = ?, referredToId = ?, referredToType = ?, reasons = ?, adverseEventId = ?, createdBy = ?, createdTime = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientCreatedBy = ?, clientCreatedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted WHERE ID = ?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.tenantId - - jsonPath: $.*.projectBeneficiaryId - - jsonPath: $.*.projectBeneficiaryClientReferenceId - - jsonPath: $.*.referredById - - jsonPath: $.*.referredToId - - jsonPath: $.*.referredToType - - jsonPath: $.*.reasons - type: JSON - dbType: JSONB - - jsonPath: $.*.adverseEvent.id - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.clientAuditDetails.lastModifiedBy - - jsonPath: $.*.clientAuditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id + - version: 1.0 + description: Updates a referral + fromTopic: update-referral-topic + isTransaction: true + queryMaps: + - query: UPDATE REFERRAL SET tenantId = ?, projectBeneficiaryId = ?, projectBeneficiaryClientReferenceId = ?, referredById = ?, referredToId = ?, referredToType = ?, reasons = ?, sideEffectId = ?, createdBy = ?, createdTime = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientCreatedBy = ?, clientCreatedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted WHERE ID = ?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.tenantId + - jsonPath: $.*.projectBeneficiaryId + - jsonPath: $.*.projectBeneficiaryClientReferenceId + - jsonPath: $.*.referredById + - jsonPath: $.*.referredToId + - jsonPath: $.*.referredToType + - jsonPath: $.*.reasons + type: JSON + dbType: JSONB + - jsonPath: $.*.sideEffect.id + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - jsonPath: $.*.id - - version: 1.0 - description: Deletes a referral - fromTopic: delete-referral-topic - isTransaction: true - queryMaps: - - query: UPDATE REFERRAL SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.clientAuditDetails.lastModifiedBy - - jsonPath: $.*.clientAuditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id + - version: 1.0 + description: Deletes a referral + fromTopic: delete-referral-topic + isTransaction: true + queryMaps: + - query: UPDATE REFERRAL SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - jsonPath: $.*.id diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java index d9b3ed4b51e..d4c3c04c686 100644 --- a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java @@ -1,11 +1,7 @@ package org.egov.referralmanagement.helper; import org.egov.common.helper.AuditDetailsTestBuilder; -<<<<<<<< HEAD:health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java import org.egov.common.models.referralmanagement.sideeffect.SideEffect; -======== -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; ->>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/AdverseEventTestBuilder.java import java.util.ArrayList; import java.util.Arrays; diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java index 399b71a653d..31b7ac1fdf2 100644 --- a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java @@ -1,12 +1,6 @@ package org.egov.referralmanagement.web.controllers; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.referralmanagement.TestConfiguration; -import org.egov.referralmanagement.config.ReferralManagementConfiguration; -<<<<<<<< HEAD:health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java -import org.egov.referralmanagement.helper.SideEffectRequestTestBuilder; -import org.egov.referralmanagement.helper.SideEffectTestBuilder; -import org.egov.referralmanagement.service.SideEffectService; import org.egov.common.helper.RequestInfoTestBuilder; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkResponse; @@ -14,19 +8,12 @@ import org.egov.common.models.referralmanagement.sideeffect.SideEffectResponse; import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearch; import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearchRequest; -======== -import org.egov.referralmanagement.helper.AdverseEventRequestTestBuilder; -import org.egov.referralmanagement.helper.AdverseEventTestBuilder; -import org.egov.referralmanagement.service.AdverseEventService; -import org.egov.common.helper.RequestInfoTestBuilder; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEvent; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventBulkResponse; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventRequest; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventResponse; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearch; -import org.egov.common.models.referralmanagement.adverseevent.AdverseEventSearchRequest; ->>>>>>>> 51cd6f6468 (HLM-3069: changed module name to referral management):health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/AdverseEventApiControllerTest.java import org.egov.common.producer.Producer; +import org.egov.referralmanagement.TestConfiguration; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.helper.SideEffectRequestTestBuilder; +import org.egov.referralmanagement.helper.SideEffectTestBuilder; +import org.egov.referralmanagement.service.SideEffectService; import org.egov.tracer.model.CustomException; import org.egov.tracer.model.ErrorRes; import org.junit.jupiter.api.Assertions; From 24136252b5cf4ff6834ddf2e665bb5d23cb9b9b6 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 29 Sep 2023 17:33:23 +0530 Subject: [PATCH 174/283] HLM-3376: updated contract file --- .../contracts/referral-management.yml | 178 +++++++++--------- 1 file changed, 94 insertions(+), 84 deletions(-) diff --git a/docs/health-api-specs/contracts/referral-management.yml b/docs/health-api-specs/contracts/referral-management.yml index 991a8a12dec..36a2d8e0afa 100644 --- a/docs/health-api-specs/contracts/referral-management.yml +++ b/docs/health-api-specs/contracts/referral-management.yml @@ -1,7 +1,7 @@ swagger: '2.0' info: version: 1.0.0 - title: Adverse Event and Referral Management System + title: Referral Management System contact: name: egovernments foundation email: info@egovernments.org @@ -10,50 +10,50 @@ schemes: x-common-path: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-0-0.yml paths: - /referral-management/adverse_event/v1/_create: + /referral-management/side_effect/v1/_create: post: summary: >- - Create adverse event for the project + Create side effect for the project description: >- - Create adverse event for the project + Create side effect for the project parameters: - - name: AdverseEvent + - name: SideEffect in: body - description: Capture details of Adverse Event + description: Capture details of Side Effect required: true schema: - $ref: '#/definitions/AdverseEventRequest' + $ref: '#/definitions/SideEffectRequest' tags: - - Adverse Event + - Side Effect responses: '202': - description: Create adverse event request has been accepted for creation. + description: Create side effect request has been accepted for creation. schema: - $ref: '#/definitions/AdverseEventResponse' + $ref: '#/definitions/SideEffectResponse' '400': description: Invalid Input body. schema: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/adverse_event/v1/bulk/_create: + /referral-management/side_effect/v1/bulk/_create: post: summary: >- - Create adverse events for the project in bulk + Create side effects for the project in bulk description: >- - Create adverse events for the project in bulk + Create side effects for the project in bulk parameters: - - name: AdverseEvent + - name: SideEffect in: body description: Capture details of Task required: true schema: - $ref: '#/definitions/AdverseEventBulkRequest' + $ref: '#/definitions/SideEffectBulkRequest' tags: - - Adverse Event + - Side Effect responses: '202': - description: Create adverse event request has been accepted for creation. + description: Create side effect request has been accepted for creation. schema: $ref: '#/definitions/BulkAcceptedResponse' '400': @@ -62,50 +62,50 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/adverse_event/v1/_update: + /referral-management/side_effect/v1/_update: post: summary: >- - Adverse Event Request + Side Effect Request description: >- - Adverse Event Request + Side Effect Request parameters: - - name: AdverseEvent + - name: SideEffect in: body - description: Capture details of Existing adverse event + description: Capture details of Existing side effect required: true schema: - $ref: '#/definitions/AdverseEventRequest' + $ref: '#/definitions/SideEffectRequest' tags: - - Adverse Event + - Side Effect responses: '202': - description: update adverse event request has been accepted for update. + description: update side effect request has been accepted for update. schema: - $ref: '#/definitions/AdverseEventResponse' + $ref: '#/definitions/SideEffectResponse' '400': description: Invalid Input body. schema: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/adverse_event/v1/bulk/_update: + /referral-management/side_effect/v1/bulk/_update: post: summary: >- - Adverse Event Request in bulk for a project + Side Effect Request in bulk for a project description: >- - Adverse Event Request in bulk for a project + Side Effect Request in bulk for a project parameters: - - name: AdverseEvent + - name: SideEffect in: body - description: Capture details of Existing Adverse Events + description: Capture details of Existing Side Effects required: true schema: - $ref: '#/definitions/AdverseEventBulkRequest' + $ref: '#/definitions/SideEffectBulkRequest' tags: - - Adverse Event + - Side Effect responses: '202': - description: update Adverse Events bulk request has been accepted for update. + description: update Side Effects bulk request has been accepted for update. schema: $ref: '#/definitions/BulkAcceptedResponse' '400': @@ -114,50 +114,50 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/adverse_event/v1/_delete: + /referral-management/side_effect/v1/_delete: post: summary: >- - Soft delete Adverse Event for a project + Soft delete Side Effect for a project description: >- - Soft delete Adverse Event for a project + Soft delete Side Effect for a project parameters: - - name: AdverseEvent + - name: SideEffect in: body - description: Capture details of Existing Adverse Event + description: Capture details of Existing Side Effect required: true schema: - $ref: '#/definitions/AdverseEventRequest' + $ref: '#/definitions/SideEffectRequest' tags: - - Adverse Event + - Side Effect responses: '202': - description: delete Adverse Event request has been accepted for deletion. + description: delete Side Effect request has been accepted for deletion. schema: - $ref: '#/definitions/AdverseEventResponse' + $ref: '#/definitions/SideEffectResponse' '400': description: Invalid Input body. schema: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/adverse_event/v1/bulk/_delete: + /referral-management/side_effect/v1/bulk/_delete: post: summary: >- - Soft delete Adverse Events for a project + Soft delete Side Effects for a project description: >- - Soft delete Adverse Events for a project + Soft delete Side Effects for a project parameters: - - name: AdverseEvent + - name: SideEffect in: body - description: Capture details of Existing Adverse Event + description: Capture details of Existing Side Effect required: true schema: - $ref: '#/definitions/AdverseEventRequest' + $ref: '#/definitions/SideEffectRequest' tags: - - Adverse Event + - Side Effect responses: '202': - description: delete bulk Adverse Event request has been accepted for deletion. + description: delete bulk Side Effect request has been accepted for deletion. schema: $ref: '#/definitions/BulkAcceptedResponse' '400': @@ -166,31 +166,31 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/adverse_event/v1/_search: + /referral-management/side_effect/v1/_search: post: summary: >- - Search Adverse Event for Project + Search Side Effect for Project description: >- - Search Adverse Event for Project + Search Side Effect for Project parameters: - - name: AdverseEvent + - name: SideEffect in: body - description: Adverse Event Search. + description: Side Effect Search. required: true schema: - $ref: '#/definitions/AdverseEventSearchRequest' + $ref: '#/definitions/SideEffectSearchRequest' - $ref: '#/parameters/limit' - $ref: '#/parameters/offset' - $ref: '#/parameters/tenantId' - $ref: '#/parameters/lastChangedSince' - $ref: '#/parameters/includeDeleted' tags: - - Adverse Event + - Side Effect responses: '200': - description: Adverse Events. + description: Side Effects. schema: - $ref: '#/definitions/AdverseEventBulkResponse' + $ref: '#/definitions/SideEffectBulkResponse' '400': description: Invalid Input body. schema: @@ -512,7 +512,7 @@ definitions: Address: $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/Address' - AdverseEvent: + SideEffect: type: object required: - tenantId @@ -534,6 +534,16 @@ definitions: type: string example: "R-ID-1" description: Unique Task Client Reference Id + projectBeneficiaryId: + type: string + minLength: 2 + maxLength: 64 + description: Project Beneficiary Id + projectBeneficiaryClientReferenceId: + type: string + minLength: 2 + maxLength: 64 + description: Project Beneficiary Client Reference Id symptoms: type: array items: @@ -549,35 +559,35 @@ definitions: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails - AdverseEventRequest: + SideEffectRequest: type: object properties: RequestInfo: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo - AdverseEvent: + SideEffect: type: object - $ref: '#/definitions/AdverseEvent' + $ref: '#/definitions/SideEffect' required: - RequestInfo - - AdverseEvent + - SideEffect - AdverseEventBulkRequest: + SideEffectBulkRequest: type: object properties: RequestInfo: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo - AdverseEvents: + SideEffects: type: array minItems: 1 items: - $ref: '#/definitions/AdverseEvent' + $ref: '#/definitions/SideEffect' required: - RequestInfo - - AdverseEvents + - SideEffects - AdverseEventSearch: + SideEffectSearch: type: object properties: id: @@ -593,44 +603,44 @@ definitions: type: string example: "R-ID-1" - AdverseEventSearchRequest: + SideEffectSearchRequest: type: object properties: RequestInfo: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo - AdverseEvent: - $ref: '#/definitions/AdverseEventSearch' + SideEffect: + $ref: '#/definitions/SideEffectSearch' required: - RequestInfo - - AdverseEvent + - SideEffect - AdverseEventResponse: + SideEffectResponse: type: object properties: ResponseInfo: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo - AdverseEvent: + SideEffect: type: object - $ref: '#/definitions/AdverseEvent' + $ref: '#/definitions/SideEffect' required: - ResponseInfo - - AdverseEvent + - SideEffect - AdverseEventBulkResponse: + SideEffectBulkResponse: type: object properties: ResponseInfo: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo - AdverseEvents: + SideEffects: type: array items: - $ref: '#/definitions/AdverseEvent' + $ref: '#/definitions/SideEffect' required: - ResponseInfo - - AdverseEvents + - SideEffects Referral: type: object @@ -670,8 +680,8 @@ definitions: type: array items: type: string - adverseEvent: - $ref: '#/definition/AdverseEvent' + sideEffect: + $ref: '#/definition/SideEffect' isDeleted: $ref: '#/definitions/isDeleted' rowVersion: From 543a8c9576984a245669ac361a8ee87363dafc89 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 29 Sep 2023 18:07:10 +0530 Subject: [PATCH 175/283] HLM-3069: update referral-management.yml --- .../contracts/referral-management.yml | 16 +-- .../referral-management-persister.yml | 134 +++++++++--------- .../SideEffectApiControllerTest.java | 10 +- 3 files changed, 80 insertions(+), 80 deletions(-) diff --git a/docs/health-api-specs/contracts/referral-management.yml b/docs/health-api-specs/contracts/referral-management.yml index 10d0e7b0d8d..c1599288f38 100644 --- a/docs/health-api-specs/contracts/referral-management.yml +++ b/docs/health-api-specs/contracts/referral-management.yml @@ -10,7 +10,7 @@ schemes: x-common-path: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-0-0.yml paths: - /adrm/side_effect/v1/_create: + /referral-management/side_effect/v1/_create: post: summary: >- Create side effect for the project @@ -36,7 +36,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/side_effect/v1/bulk/_create: + /referral-management/side_effect/v1/bulk/_create: post: summary: >- Create side effects for the project in bulk @@ -62,7 +62,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/side-effect/v1/_update: + /referral-management/side-effect/v1/_update: post: summary: >- Side Effect Request @@ -79,7 +79,7 @@ paths: - Side Effect responses: '202': - description: update averse event request has been accepted for update. + description: update side effect request has been accepted for update. schema: $ref: '#/definitions/SideEffectResponse' '400': @@ -88,7 +88,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/side-effect/v1/bulk/_update: + /referral-management/side-effect/v1/bulk/_update: post: summary: >- Side Effect Request in bulk for a project @@ -114,7 +114,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/side-effect/v1/_delete: + /referral-management/side-effect/v1/_delete: post: summary: >- Soft delete Side Effect for a project @@ -140,7 +140,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/side-effect/v1/bulk/_delete: + /referral-management/side-effect/v1/bulk/_delete: post: summary: >- Soft delete Side Effects for a project @@ -166,7 +166,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /adrm/side-effect/v1/_search: + /referral-management/side-effect/v1/_search: post: summary: >- Search Side Effect for Project diff --git a/health-services/referralmanagement/src/main/resources/referral-management-persister.yml b/health-services/referralmanagement/src/main/resources/referral-management-persister.yml index 936708ec766..dbb3c641469 100644 --- a/health-services/referralmanagement/src/main/resources/referral-management-persister.yml +++ b/health-services/referralmanagement/src/main/resources/referral-management-persister.yml @@ -1,71 +1,71 @@ serviceMaps: serviceName: referralmanagement - mappings: - - version: 1.0 - description: Saves a side effect - fromTopic: save-side-effect-topic - isTransaction: true - queryMaps: - - query: INSERT INTO SIDE_EFFECT(id, clientReferenceId, tenantId, taskId, taskClientReferenceId, projectBeneficiaryId, projectBeneficiaryClientReferenceId,symptoms, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedBy, clientCreatedTime, clientLastModifiedBy, clientLastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); - basePath: $.* - jsonMaps: - - jsonPath: $.*.id - - jsonPath: $.*.clientReferenceId - - jsonPath: $.*.tenantId - - jsonPath: $.*.taskId - - jsonPath: $.*.taskClientReferenceId - - jsonPath: $.*.projectBeneficiaryId - - jsonPath: $.*.projectBeneficiaryClientReferenceId - - jsonPath: $.*.symptoms - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.createdBy - - jsonPath: $.*.auditDetails.createdTime - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.clientAuditDetails.createdBy - - jsonPath: $.*.clientAuditDetails.createdTime - - jsonPath: $.*.clientAuditDetails.lastModifiedBy - - jsonPath: $.*.clientAuditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted + mappings: + - version: 1.0 + description: Saves a side effect + fromTopic: save-side-effect-topic + isTransaction: true + queryMaps: + - query: INSERT INTO SIDE_EFFECT(id, clientReferenceId, tenantId, taskId, taskClientReferenceId, projectBeneficiaryId, projectBeneficiaryClientReferenceId,symptoms, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedBy, clientCreatedTime, clientLastModifiedBy, clientLastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); + basePath: $.* + jsonMaps: + - jsonPath: $.*.id + - jsonPath: $.*.clientReferenceId + - jsonPath: $.*.tenantId + - jsonPath: $.*.taskId + - jsonPath: $.*.taskClientReferenceId + - jsonPath: $.*.projectBeneficiaryId + - jsonPath: $.*.projectBeneficiaryClientReferenceId + - jsonPath: $.*.symptoms + type: JSON + dbType: JSONB + - jsonPath: $.*.auditDetails.createdBy + - jsonPath: $.*.auditDetails.createdTime + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.createdBy + - jsonPath: $.*.clientAuditDetails.createdTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted - - version: 1.0 - description: Updates a side effect - fromTopic: update-side-effect-topic - isTransaction: true - queryMaps: - - query: UPDATE SIDE_EFFECT SET tenantId = ?, taskId = ?, taskClientReferenceId = ?, projectBeneficiaryId = ?, projectBeneficiaryClientReferenceId = ?, symptoms = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.tenantId - - jsonPath: $.*.taskId - - jsonPath: $.*.taskClientReferenceId - - jsonPath: $.*.projectBeneficiaryId - - jsonPath: $.*.projectBeneficiaryClientReferenceId - - jsonPath: $.*.symptoms - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.clientAuditDetails.lastModifiedBy - - jsonPath: $.*.clientAuditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id + - version: 1.0 + description: Updates a side effect + fromTopic: update-side-effect-topic + isTransaction: true + queryMaps: + - query: UPDATE SIDE_EFFECT SET tenantId = ?, taskId = ?, taskClientReferenceId = ?, projectBeneficiaryId = ?, projectBeneficiaryClientReferenceId = ?, symptoms = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.tenantId + - jsonPath: $.*.taskId + - jsonPath: $.*.taskClientReferenceId + - jsonPath: $.*.projectBeneficiaryId + - jsonPath: $.*.projectBeneficiaryClientReferenceId + - jsonPath: $.*.symptoms + type: JSON + dbType: JSONB + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - jsonPath: $.*.id - - version: 1.0 - description: Deletes a side effect - fromTopic: delete-side-effect-topic - isTransaction: true - queryMaps: - - query: UPDATE SIDE_EFFECT SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.clientAuditDetails.lastModifiedBy - - jsonPath: $.*.clientAuditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id + - version: 1.0 + description: Deletes a side effect + fromTopic: delete-side-effect-topic + isTransaction: true + queryMaps: + - query: UPDATE SIDE_EFFECT SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - jsonPath: $.*.id diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java index 5acd4f7a594..31b7ac1fdf2 100644 --- a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java @@ -1,11 +1,6 @@ package org.egov.referralmanagement.web.controllers; import com.fasterxml.jackson.databind.ObjectMapper; -import org.egov.referralmanagement.TestConfiguration; -import org.egov.referralmanagement.config.ReferralManagementConfiguration; -import org.egov.referralmanagement.helper.SideEffectRequestTestBuilder; -import org.egov.referralmanagement.helper.SideEffectTestBuilder; -import org.egov.referralmanagement.service.SideEffectService; import org.egov.common.helper.RequestInfoTestBuilder; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkResponse; @@ -14,6 +9,11 @@ import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearch; import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearchRequest; import org.egov.common.producer.Producer; +import org.egov.referralmanagement.TestConfiguration; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.helper.SideEffectRequestTestBuilder; +import org.egov.referralmanagement.helper.SideEffectTestBuilder; +import org.egov.referralmanagement.service.SideEffectService; import org.egov.tracer.model.CustomException; import org.egov.tracer.model.ErrorRes; import org.junit.jupiter.api.Assertions; From 6b81aed70b1dcb1e3ffc0608c544392cb1ffa751 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 29 Sep 2023 18:09:57 +0530 Subject: [PATCH 176/283] HLM-3069: update referral-management.yml --- .../health-api-specs/contracts/referral-management.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/health-api-specs/contracts/referral-management.yml b/docs/health-api-specs/contracts/referral-management.yml index c1599288f38..731db02e03d 100644 --- a/docs/health-api-specs/contracts/referral-management.yml +++ b/docs/health-api-specs/contracts/referral-management.yml @@ -62,7 +62,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/side-effect/v1/_update: + /referral-management/side_effect/v1/_update: post: summary: >- Side Effect Request @@ -88,7 +88,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/side-effect/v1/bulk/_update: + /referral-management/side_effect/v1/bulk/_update: post: summary: >- Side Effect Request in bulk for a project @@ -114,7 +114,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/side-effect/v1/_delete: + /referral-management/side_effect/v1/_delete: post: summary: >- Soft delete Side Effect for a project @@ -140,7 +140,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/side-effect/v1/bulk/_delete: + /referral-management/side_effect/v1/bulk/_delete: post: summary: >- Soft delete Side Effects for a project @@ -166,7 +166,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/side-effect/v1/_search: + /referral-management/side_effect/v1/_search: post: summary: >- Search Side Effect for Project From 7a09386fda88d3a9f5b16b90132e4751a8594e0d Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 4 Oct 2023 12:32:31 +0530 Subject: [PATCH 177/283] HLM-3376, 3069: side_effect change to side-effect, removed '/referral', renamed context path --- .../contracts/referral-management.yml | 28 +++++++-------- .../ReferralManagementApiController.java | 12 +++---- .../controllers/SideEffectApiController.java | 2 +- .../src/main/resources/application.properties | 2 +- .../ReferralManagementApiControllerTest.java | 36 +++++++++++++++++++ .../SideEffectApiControllerTest.java | 12 +++---- 6 files changed, 64 insertions(+), 28 deletions(-) create mode 100644 health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiControllerTest.java diff --git a/docs/health-api-specs/contracts/referral-management.yml b/docs/health-api-specs/contracts/referral-management.yml index 36a2d8e0afa..7ca980bafed 100644 --- a/docs/health-api-specs/contracts/referral-management.yml +++ b/docs/health-api-specs/contracts/referral-management.yml @@ -10,7 +10,7 @@ schemes: x-common-path: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-0-0.yml paths: - /referral-management/side_effect/v1/_create: + /referral-management/side-effect/v1/_create: post: summary: >- Create side effect for the project @@ -36,7 +36,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/side_effect/v1/bulk/_create: + /referral-management/side-effect/v1/bulk/_create: post: summary: >- Create side effects for the project in bulk @@ -62,7 +62,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/side_effect/v1/_update: + /referral-management/side-effect/v1/_update: post: summary: >- Side Effect Request @@ -88,7 +88,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/side_effect/v1/bulk/_update: + /referral-management/side-effect/v1/bulk/_update: post: summary: >- Side Effect Request in bulk for a project @@ -114,7 +114,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/side_effect/v1/_delete: + /referral-management/side-effect/v1/_delete: post: summary: >- Soft delete Side Effect for a project @@ -140,7 +140,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/side_effect/v1/bulk/_delete: + /referral-management/side-effect/v1/bulk/_delete: post: summary: >- Soft delete Side Effects for a project @@ -166,7 +166,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/side_effect/v1/_search: + /referral-management/side-effect/v1/_search: post: summary: >- Search Side Effect for Project @@ -197,7 +197,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/referral/v1/_create: + /referral-management/v1/_create: post: summary: >- Create referral for the project beneficiary @@ -223,7 +223,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/referral/v1/bulk/_create: + /referral-management/v1/bulk/_create: post: summary: >- Create referrals for the project beneficiary in bulk @@ -249,7 +249,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/referral/v1/_update: + /referral-management/v1/_update: post: summary: >- Referral Request @@ -275,7 +275,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/referral/v1/bulk/_update: + /referral-management/v1/bulk/_update: post: summary: >- Referral Request in bulk for a project beneficiary @@ -301,7 +301,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/referral/v1/_delete: + /referral-management/v1/_delete: post: summary: >- Soft delete Referral for a project beneficiary @@ -327,7 +327,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/referral/v1/bulk/_delete: + /referral-management/v1/bulk/_delete: post: summary: >- Soft delete Referrals for a project beneficiary @@ -353,7 +353,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/referral/v1/_search: + /referral-management/v1/_search: post: summary: >- Search Referral for Project diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java index 499760f0f78..949f84fbde8 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java @@ -52,7 +52,7 @@ public ReferralManagementApiController( this.referralManagementConfiguration = referralManagementConfiguration; } - @RequestMapping(value = "/referral/v1/_create", method = RequestMethod.POST) + @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) public ResponseEntity referralV1CreatePost(@ApiParam(value = "Capture details of Referral", required = true) @Valid @RequestBody ReferralRequest request) { Referral referral = referralManagementService.create(request); @@ -67,7 +67,7 @@ public ResponseEntity referralV1CreatePost(@ApiParam(value = " - @RequestMapping(value = "/referral/v1/bulk/_create", method = RequestMethod.POST) + @RequestMapping(value = "/v1/bulk/_create", method = RequestMethod.POST) public ResponseEntity referralBulkV1CreatePost(@ApiParam(value = "Capture details of Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); referralManagementService.putInCache(request.getReferrals()); @@ -77,7 +77,7 @@ public ResponseEntity referralBulkV1CreatePost(@ApiParam(value = " .createResponseInfo(request.getRequestInfo(), true)); } - @RequestMapping(value = "/referral/v1/_search", method = RequestMethod.POST) + @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) public ResponseEntity referralV1SearchPost(@ApiParam(value = "Referral Search.", required = true) @Valid @RequestBody ReferralSearchRequest request, @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, @@ -92,7 +92,7 @@ public ResponseEntity referralV1SearchPost(@ApiParam(value return ResponseEntity.status(HttpStatus.OK).body(response); } - @RequestMapping(value = "/referral/v1/_update", method = RequestMethod.POST) + @RequestMapping(value = "/v1/_update", method = RequestMethod.POST) public ResponseEntity referralV1UpdatePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralRequest request) { Referral referral = referralManagementService.update(request); @@ -106,7 +106,7 @@ public ResponseEntity referralV1UpdatePost(@ApiParam(value = " } - @RequestMapping(value = "/referral/v1/bulk/_update", method = RequestMethod.POST) + @RequestMapping(value = "/v1/bulk/_update", method = RequestMethod.POST) public ResponseEntity referralV1BulkUpdatePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); producer.push(referralManagementConfiguration.getUpdateReferralBulkTopic(), request); @@ -115,7 +115,7 @@ public ResponseEntity referralV1BulkUpdatePost(@ApiParam(value = " .createResponseInfo(request.getRequestInfo(), true)); } - @RequestMapping(value = "/referral/v1/_delete", method = RequestMethod.POST) + @RequestMapping(value = "/v1/_delete", method = RequestMethod.POST) public ResponseEntity referralV1DeletePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralRequest request) { Referral referral = referralManagementService.delete(request); diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/SideEffectApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/SideEffectApiController.java index 09c2b4c7b18..c43db332fa7 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/SideEffectApiController.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/SideEffectApiController.java @@ -29,7 +29,7 @@ import java.util.List; @Controller -@RequestMapping("/side_effect") +@RequestMapping("/side-effect") @Validated public class SideEffectApiController { diff --git a/health-services/referralmanagement/src/main/resources/application.properties b/health-services/referralmanagement/src/main/resources/application.properties index 0abb7cd7248..1241002ce27 100644 --- a/health-services/referralmanagement/src/main/resources/application.properties +++ b/health-services/referralmanagement/src/main/resources/application.properties @@ -1,4 +1,4 @@ -server.servlet.context-path=/referral-management +server.servlet.context-path=/referralmanagement server.port=8080 app.timezone=UTC diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiControllerTest.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiControllerTest.java new file mode 100644 index 00000000000..840dfeab672 --- /dev/null +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiControllerTest.java @@ -0,0 +1,36 @@ +package org.egov.referralmanagement.web.controllers; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class ReferralManagementApiControllerTest { + + @Test + void referralV1CreatePost() { + } + + @Test + void referralBulkV1CreatePost() { + } + + @Test + void referralV1SearchPost() { + } + + @Test + void referralV1UpdatePost() { + } + + @Test + void referralV1BulkUpdatePost() { + } + + @Test + void referralV1DeletePost() { + } + + @Test + void referralV1BulkDeletePost() { + } +} \ No newline at end of file diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java index 31b7ac1fdf2..d163458fd62 100644 --- a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java @@ -64,7 +64,7 @@ void shouldCreateSideEffectAndReturnWith202Accepted() throws Exception { List sideEffects = getSideEffects(); Mockito.when(sideEffectService.create(ArgumentMatchers.any(SideEffectRequest.class))).thenReturn(sideEffects.get(0)); - final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side_effect/v1/_create") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side-effect/v1/_create") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andExpect(MockMvcResultMatchers.status().isAccepted()) @@ -89,7 +89,7 @@ private List getSideEffects() { @Test @DisplayName("should send error response with error details with 400 bad request for create") void shouldSendErrorResWithErrorDetailsWith400BadRequestForCreate() throws Exception { - final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side_effect/v1/_create") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side-effect/v1/_create") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(SideEffectRequestTestBuilder.builder() .withOneSideEffect() @@ -114,7 +114,7 @@ void shouldUpdateSideEffectAndReturnWith202Accepted() throws Exception { SideEffect sideEffect = SideEffectTestBuilder.builder().withId().build(); Mockito.when(sideEffectService.update(ArgumentMatchers.any(SideEffectRequest.class))).thenReturn(sideEffect); - final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side_effect/v1/_update") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side-effect/v1/_update") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(request))) .andExpect(MockMvcResultMatchers.status().isAccepted()) @@ -131,7 +131,7 @@ void shouldUpdateSideEffectAndReturnWith202Accepted() throws Exception { @Test @DisplayName("should send error response with error details with 400 bad request for update") void shouldSendErrorResWithErrorDetailsWith400BadRequestForUpdate() throws Exception { - final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side_effect/v1/_update") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side-effect/v1/_update") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(SideEffectRequestTestBuilder.builder() .withOneSideEffectHavingId() @@ -163,7 +163,7 @@ void shouldAcceptSearchRequestAndReturnSideEffect() throws Exception { ArgumentMatchers.any(Boolean.class))).thenReturn(Arrays.asList(SideEffectTestBuilder.builder().withId().withAuditDetails().build())); final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post( - "/side_effect/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") + "/side-effect/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(sideEffectSearchRequest))) .andExpect(MockMvcResultMatchers.status().isOk()) @@ -192,7 +192,7 @@ void shouldThrowExceptionIfNoResultFound() throws Exception { ArgumentMatchers.any(Boolean.class))).thenThrow(new CustomException("NO_RESULT_FOUND", "No Side Effect found.")); - final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side_effect/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/side-effect/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(sideEffectSearchRequest))) .andExpect(MockMvcResultMatchers.status().isBadRequest()) From 401e009f1629096bd091e910fbcaafe9589c3618 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 4 Oct 2023 12:34:10 +0530 Subject: [PATCH 178/283] HLM-3376: deleted test file for referral --- .../ReferralManagementApiControllerTest.java | 36 ------------------- 1 file changed, 36 deletions(-) delete mode 100644 health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiControllerTest.java diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiControllerTest.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiControllerTest.java deleted file mode 100644 index 840dfeab672..00000000000 --- a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiControllerTest.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.egov.referralmanagement.web.controllers; - -import org.junit.jupiter.api.Test; - -import static org.junit.jupiter.api.Assertions.*; - -class ReferralManagementApiControllerTest { - - @Test - void referralV1CreatePost() { - } - - @Test - void referralBulkV1CreatePost() { - } - - @Test - void referralV1SearchPost() { - } - - @Test - void referralV1UpdatePost() { - } - - @Test - void referralV1BulkUpdatePost() { - } - - @Test - void referralV1DeletePost() { - } - - @Test - void referralV1BulkDeletePost() { - } -} \ No newline at end of file From 24d124336ece54b02dd0d6f852bf7bb967634e4c Mon Sep 17 00:00:00 2001 From: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Date: Thu, 5 Oct 2023 14:49:37 +0530 Subject: [PATCH 179/283] stock exchange between parties enabled --- .../libraries/health-services-models/pom.xml | 2 +- .../org/egov/common/models/stock/Stock.java | 70 +-- health-services/stock/pom.xml | 2 +- .../main/java/org/egov/stock/Constants.java | 4 + .../repository/rowmapper/StockRowMapper.java | 7 +- .../egov/stock/service/FacilityService.java | 72 +++- .../org/egov/stock/service/StockService.java | 50 ++- .../org/egov/stock/util/ValidatorUtil.java | 397 ++++++++++++++---- .../validator/stock/SFacilityIdValidator.java | 42 -- .../stock/STransactingPartyIdValidator.java | 45 -- .../stock/StocktransferPartiesValidator.java | 46 ++ .../StockReconciliationTestBuilder.java | 2 +- .../egov/stock/helper/StockTestBuilder.java | 18 +- .../validator/FacilityIdValidatorTest.java | 103 ----- .../validator/ReferenceIdValidatorTest.java | 26 +- .../TransactingPartyIdValidatorTest.java | 72 ---- 16 files changed, 512 insertions(+), 446 deletions(-) delete mode 100644 health-services/stock/src/main/java/org/egov/stock/validator/stock/SFacilityIdValidator.java delete mode 100644 health-services/stock/src/main/java/org/egov/stock/validator/stock/STransactingPartyIdValidator.java create mode 100644 health-services/stock/src/main/java/org/egov/stock/validator/stock/StocktransferPartiesValidator.java delete mode 100644 health-services/stock/src/test/java/org/egov/stock/validator/FacilityIdValidatorTest.java delete mode 100644 health-services/stock/src/test/java/org/egov/stock/validator/TransactingPartyIdValidatorTest.java diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index a7c232f4b52..5823cdce8aa 100644 --- a/health-services/libraries/health-services-models/pom.xml +++ b/health-services/libraries/health-services-models/pom.xml @@ -6,7 +6,7 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.9-SNAPSHOT 8 diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java index 97ac4f3e06e..eb324acdec5 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java @@ -1,18 +1,21 @@ package org.egov.common.models.stock; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import org.springframework.validation.annotation.Validated; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; + import digit.models.coremodels.AuditDetails; import lombok.AllArgsConstructor; import lombok.Builder; +import lombok.Builder.Default; import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; /** * Stock @@ -26,81 +29,92 @@ @Builder @JsonIgnoreProperties(ignoreUnknown = true) public class Stock { + @JsonProperty("id") @Size(min=2, max=64) - private String id = null; + private String id; @JsonProperty("clientReferenceId") @Size(min=2, max=64) - private String clientReferenceId = null; + private String clientReferenceId; @JsonProperty("tenantId") @NotNull @Size(min=2, max=1000) - private String tenantId = null; - - @JsonProperty("facilityId") - @NotNull - @Size(min=2, max=64) - private String facilityId = null; + private String tenantId; + /* product fields */ @JsonProperty("productVariantId") @NotNull @Size(min=2, max=64) - private String productVariantId = null; + private String productVariantId; @JsonProperty("quantity") @NotNull - private Integer quantity = null; + private Integer quantity; + /* project id in-case of health */ @JsonProperty("referenceId") - private String referenceId = null; + private String referenceId; @JsonProperty("referenceIdType") @Size(min=2, max=64) - private String referenceIdType = null; + private String referenceIdType; + // transaction fields @JsonProperty("transactionType") @NotNull @Valid - private TransactionType transactionType = null; + private TransactionType transactionType; @JsonProperty("transactionReason") @Valid - private TransactionReason transactionReason = null; + private TransactionReason transactionReason; - @JsonProperty("transactingPartyId") + @JsonProperty("senderId") + @NotNull + @Size(min=2, max=64) + private String senderId; + + @JsonProperty("senderType") + @NotNull + @Size(min=2, max=64) + private String senderType; + + @JsonProperty("receiverId") @NotNull @Size(min=2, max=64) - private String transactingPartyId = null; + private String receiverId; - @JsonProperty("transactingPartyType") + @JsonProperty("receiverType") @NotNull @Size(min=2, max=64) - private String transactingPartyType = null; + private String receiverType; @JsonProperty("wayBillNumber") @Size(min = 2, max = 200) - private String wayBillNumber = null; + private String wayBillNumber; @JsonProperty("additionalFields") @Valid - private AdditionalFields additionalFields = null; + private AdditionalFields additionalFields; @JsonProperty("isDeleted") + @Default private Boolean isDeleted = Boolean.FALSE; @JsonProperty("rowVersion") - private Integer rowVersion = null; + private Integer rowVersion; @JsonIgnore + @Default private Boolean hasErrors = Boolean.FALSE; @JsonProperty("auditDetails") @Valid - private AuditDetails auditDetails = null; + private AuditDetails auditDetails; @JsonProperty("dateOfEntry") - private Long dateOfEntry = null; + private Long dateOfEntry; } diff --git a/health-services/stock/pom.xml b/health-services/stock/pom.xml index 340d0f7398f..81e99bf2071 100644 --- a/health-services/stock/pom.xml +++ b/health-services/stock/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.3-SNAPSHOT + 1.0.9-SNAPSHOT diff --git a/health-services/stock/src/main/java/org/egov/stock/Constants.java b/health-services/stock/src/main/java/org/egov/stock/Constants.java index 9895af2597d..cb7589dc33f 100644 --- a/health-services/stock/src/main/java/org/egov/stock/Constants.java +++ b/health-services/stock/src/main/java/org/egov/stock/Constants.java @@ -17,12 +17,16 @@ public class Constants { public static String VALIDATION_ERROR = "VALIDATION_ERROR"; public static String GET_FACILITY_ID = "getFacilityId"; + + public static String GET_SENDER_ID = "getSenderId"; public static String GET_REFERENCE_ID = "getReferenceId"; public static String GET_TRANSACTING_PARTY_ID = "getTransactingPartyId"; public static String WAREHOUSE = "WAREHOUSE"; + + public static String STAFF = "STAFF"; public static String PROJECT = "PROJECT"; diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java index 63c20015d69..e19cdc17971 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java @@ -25,7 +25,6 @@ public Stock mapRow(ResultSet resultSet, int i) throws SQLException { .id(resultSet.getString("id")) .clientReferenceId(resultSet.getString("clientReferenceId")) .tenantId(resultSet.getString("tenantId")) - .facilityId(resultSet.getString("facilityId")) .productVariantId(resultSet.getString("productVariantId")) .quantity(resultSet.getInt("quantity")) .wayBillNumber(resultSet.getString("wayBillNumber")) @@ -33,8 +32,10 @@ public Stock mapRow(ResultSet resultSet, int i) throws SQLException { .referenceIdType(resultSet.getString("referenceIdType")) .transactionType(TransactionType.fromValue(resultSet.getString("transactionType"))) .transactionReason(TransactionReason.fromValue(resultSet.getString("transactionReason"))) - .transactingPartyId(resultSet.getString("transactingPartyId")) - .transactingPartyType(resultSet.getString("transactingPartyType")) + .senderId(resultSet.getString("senderId")) + .senderType(resultSet.getString("senderType")) + .receiverId(resultSet.getString("receiverId")) + .receiverType(resultSet.getString("receiverType")) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) .auditDetails(AuditDetails.builder() diff --git a/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java b/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java index 3a54d0ec400..4a19ab8d32d 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java @@ -1,6 +1,20 @@ package org.egov.stock.service; -import lombok.extern.slf4j.Slf4j; +import static org.egov.common.utils.CommonUtils.getIdList; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForEntityWithNetworkError; +import static org.egov.stock.Constants.GET_FACILITY_ID; +import static org.egov.stock.Constants.GET_REFERENCE_ID; +import static org.egov.stock.Constants.WAREHOUSE; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; @@ -11,21 +25,12 @@ import org.egov.common.models.project.ProjectFacilityBulkResponse; import org.egov.common.models.project.ProjectFacilitySearch; import org.egov.common.models.project.ProjectFacilitySearchRequest; +import org.egov.common.models.stock.Stock; +import org.egov.common.models.stock.StockReconciliation; import org.egov.stock.config.StockConfiguration; import org.springframework.stereotype.Service; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.getIdList; -import static org.egov.common.utils.CommonUtils.getMethod; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.common.utils.ValidatorUtils.getErrorForEntityWithNetworkError; -import static org.egov.stock.Constants.GET_FACILITY_ID; -import static org.egov.stock.Constants.GET_REFERENCE_ID; -import static org.egov.stock.Constants.PIPE; +import lombok.extern.slf4j.Slf4j; @Service @Slf4j @@ -40,7 +45,7 @@ public FacilityService(StockConfiguration stockConfiguration, ServiceRequestClie this.serviceRequestClient = serviceRequestClient; } - public List validateFacilityIds(List entityIds, + public List validateFacilityIds(List entityIds, List entities, String tenantId, Map> errorDetailsMap, @@ -62,20 +67,41 @@ public List validateFacilityIds(List entityIds, return response.getFacilities().stream().map(Facility::getId).collect(Collectors.toList()); } catch (Exception e) { log.error("error while fetching facility list", e); - entities.forEach(b -> { + entities.forEach( stockEntity -> { Error error = getErrorForEntityWithNetworkError(); - populateErrorDetails(b, error, errorDetailsMap); + populateErrorDetails(stockEntity, error, errorDetailsMap); }); return Collections.emptyList(); } } - public List validateProjectFacilityMappings(List entities, + public Map> validateProjectFacilityMappings(List entities, String tenantId, Map> errorDetailsMap, RequestInfo requestInfo) { + + List projectIds = getIdList(entities, getMethod(GET_REFERENCE_ID, entities.get(0).getClass())); - List facilityIds = getIdList(entities, getMethod(GET_FACILITY_ID, entities.get(0).getClass())); + List facilityIds = null; + + if (entities.get(0) instanceof StockReconciliation) { + facilityIds = getIdList(entities, getMethod(GET_FACILITY_ID, entities.get(0).getClass())); + } else if (entities.get(0) instanceof Stock) { + + facilityIds = new ArrayList<>(); + for (T entity : entities) { + + Stock stock = (Stock) entity; + + if (stock.getSenderType().equalsIgnoreCase(WAREHOUSE)) { + facilityIds.add(stock.getSenderId()); + } + if (stock.getReceiverType().equalsIgnoreCase(WAREHOUSE)) { + facilityIds.add(stock.getReceiverId()); + } + } + } + Integer searchLimit = projectIds.size() * facilityIds.size(); ProjectFacilitySearchRequest projectFacilitySearchRequest = ProjectFacilitySearchRequest.builder() @@ -91,16 +117,18 @@ public List validateProjectFacilityMappings(List entities, + "&offset=0&tenantId=" + tenantId), projectFacilitySearchRequest, ProjectFacilityBulkResponse.class); - return response.getProjectFacilities().stream() - .map(projectFacility -> projectFacility.getFacilityId() + PIPE + projectFacility.getProjectId()) - .collect(Collectors.toList()); + + return response.getProjectFacilities().stream() + .collect(Collectors.groupingBy(projectFacility -> projectFacility.getFacilityId(), + Collectors.mapping(projectFacility -> projectFacility.getFacilityId(), Collectors.toList()))); + } catch (Exception e) { log.error("error while fetching project facility list", e); entities.forEach(b -> { Error error = getErrorForEntityWithNetworkError(); populateErrorDetails(b, error, errorDetailsMap); }); - return Collections.emptyList(); + return Collections.emptyMap(); } } } diff --git a/health-services/stock/src/main/java/org/egov/stock/service/StockService.java b/health-services/stock/src/main/java/org/egov/stock/service/StockService.java index 8b5c232c09c..8bbbd72c065 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/StockService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/StockService.java @@ -1,6 +1,24 @@ package org.egov.stock.service; -import lombok.extern.slf4j.Slf4j; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.CommonUtils.validate; +import static org.egov.stock.Constants.GET_STOCK; +import static org.egov.stock.Constants.SET_STOCK; +import static org.egov.stock.Constants.VALIDATION_ERROR; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.stock.Stock; @@ -10,37 +28,19 @@ import org.egov.stock.config.StockConfiguration; import org.egov.stock.repository.StockRepository; import org.egov.stock.service.enrichment.StockEnrichmentService; -import org.egov.stock.validator.stock.SFacilityIdValidator; import org.egov.stock.validator.stock.SIsDeletedValidator; import org.egov.stock.validator.stock.SNonExistentValidator; import org.egov.stock.validator.stock.SNullIdValidator; import org.egov.stock.validator.stock.SProductVariantIdValidator; import org.egov.stock.validator.stock.SReferenceIdValidator; import org.egov.stock.validator.stock.SRowVersionValidator; -import org.egov.stock.validator.stock.STransactingPartyIdValidator; import org.egov.stock.validator.stock.SUniqueEntityValidator; +import org.egov.stock.validator.stock.StocktransferPartiesValidator; import org.egov.stock.web.models.StockSearchRequest; import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.getIdFieldName; -import static org.egov.common.utils.CommonUtils.getIdMethod; -import static org.egov.common.utils.CommonUtils.handleErrors; -import static org.egov.common.utils.CommonUtils.havingTenantId; -import static org.egov.common.utils.CommonUtils.includeDeleted; -import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; -import static org.egov.common.utils.CommonUtils.lastChangedSince; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.common.utils.CommonUtils.validate; -import static org.egov.stock.Constants.GET_STOCK; -import static org.egov.stock.Constants.SET_STOCK; -import static org.egov.stock.Constants.VALIDATION_ERROR; +import lombok.extern.slf4j.Slf4j; @Service @@ -57,9 +57,8 @@ public class StockService { private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(SProductVariantIdValidator.class) - || validator.getClass().equals(SFacilityIdValidator.class) - || validator.getClass().equals(SReferenceIdValidator.class) - || validator.getClass().equals(STransactingPartyIdValidator.class); + || validator.getClass().equals(StocktransferPartiesValidator.class) + || validator.getClass().equals(SReferenceIdValidator.class); private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(SProductVariantIdValidator.class) @@ -68,9 +67,8 @@ public class StockService { || validator.getClass().equals(SNullIdValidator.class) || validator.getClass().equals(SRowVersionValidator.class) || validator.getClass().equals(SUniqueEntityValidator.class) - || validator.getClass().equals(SFacilityIdValidator.class) || validator.getClass().equals(SReferenceIdValidator.class) - || validator.getClass().equals(STransactingPartyIdValidator.class); + || validator.getClass().equals(StocktransferPartiesValidator.class); private final Predicate> isApplicableForDelete = validator -> validator.getClass().equals(SNonExistentValidator.class) diff --git a/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java b/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java index 92c1297cf7c..0104a16d12a 100644 --- a/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java +++ b/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java @@ -1,17 +1,5 @@ package org.egov.stock.util; -import org.egov.common.contract.request.RequestInfo; -import org.egov.common.models.Error; -import org.egov.stock.service.FacilityService; -import org.egov.tracer.model.CustomException; -import org.springframework.util.ReflectionUtils; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.getIdToObjMap; import static org.egov.common.utils.CommonUtils.getMethod; import static org.egov.common.utils.CommonUtils.getObjClass; @@ -19,84 +7,319 @@ import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentRelatedEntity; -import static org.egov.stock.Constants.GET_FACILITY_ID; import static org.egov.stock.Constants.GET_REQUEST_INFO; import static org.egov.stock.Constants.NO_PROJECT_FACILITY_MAPPING_EXISTS; -import static org.egov.stock.Constants.PIPE; +import static org.egov.stock.Constants.STAFF; +import static org.egov.stock.Constants.WAREHOUSE; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.ds.Tuple; +import org.egov.common.models.Error; +import org.egov.common.models.stock.Stock; +import org.egov.common.models.stock.StockReconciliation; +import org.egov.common.service.UserService; +import org.egov.stock.service.FacilityService; +import org.egov.tracer.model.CustomException; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ReflectionUtils; + +import digit.models.coremodels.UserSearchRequest; public class ValidatorUtil { - public static Map> validateFacilityIds(R request, - Map> errorDetailsMap, - List validEntities, - String getId, - FacilityService facilityService) { - if (!validEntities.isEmpty()) { - String tenantId = getTenantId(validEntities); - Class objClass = getObjClass(validEntities); - Method idMethod = getMethod(getId, objClass); - Map eMap = getIdToObjMap(validEntities, idMethod); - RequestInfo requestInfo = (RequestInfo) ReflectionUtils.invokeMethod(getMethod(GET_REQUEST_INFO, - request.getClass()), request); - - if (!eMap.isEmpty()) { - List entityIds = new ArrayList<>(eMap.keySet()); - List existingFacilityIds = facilityService.validateFacilityIds(entityIds, - validEntities, - tenantId, errorDetailsMap, requestInfo); - List invalidEntities = validEntities.stream() - .filter(notHavingErrors()).filter(entity -> - !existingFacilityIds.contains((String) ReflectionUtils.invokeMethod(idMethod, entity))) - .collect(Collectors.toList()); - invalidEntities.forEach(entity -> { - Error error = getErrorForNonExistentRelatedEntity((String) ReflectionUtils.invokeMethod(idMethod, - entity)); - populateErrorDetails(entity, error, errorDetailsMap); - }); - } - } - - return errorDetailsMap; - } - - public static Map> validateProjectFacilityMappings(R request, - Map> errorDetailsMap, - List validEntities, - String getId, - FacilityService facilityService) { - if (!validEntities.isEmpty()) { - String tenantId = getTenantId(validEntities); - Class objClass = getObjClass(validEntities); - Method idMethod = getMethod(getId, objClass); - RequestInfo requestInfo = (RequestInfo) ReflectionUtils.invokeMethod(getMethod(GET_REQUEST_INFO, - request.getClass()), request); - - List existingProjectFacilityMappingIds = facilityService - .validateProjectFacilityMappings(validEntities, tenantId, - errorDetailsMap, requestInfo); - List invalidEntities = validEntities.stream() - .filter(notHavingErrors()).filter(entity -> - { - String comboId = (String) ReflectionUtils.invokeMethod(getMethod(GET_FACILITY_ID, objClass), - entity) - + PIPE + (String) ReflectionUtils.invokeMethod(idMethod, entity); - return !existingProjectFacilityMappingIds.contains(comboId); - }) - .collect(Collectors.toList()); - invalidEntities.forEach(entity -> { - String errorMessage = String.format("No mapping exists for project id: %s & facility id: %s", - (String) ReflectionUtils.invokeMethod(idMethod, entity), - (String) ReflectionUtils.invokeMethod(getMethod(GET_FACILITY_ID, objClass), - entity)); - Error error = Error.builder() - .errorMessage(errorMessage) - .errorCode(NO_PROJECT_FACILITY_MAPPING_EXISTS) - .type(Error.ErrorType.NON_RECOVERABLE) - .exception(new CustomException(NO_PROJECT_FACILITY_MAPPING_EXISTS, errorMessage)).build(); - populateErrorDetails(entity, error, errorDetailsMap); - }); - } - - return errorDetailsMap; - } + public static Map> validateFacilityIds(R request, Map> errorDetailsMap, + List validEntities, String getId, FacilityService facilityService) { + + if (!validEntities.isEmpty()) { + String tenantId = getTenantId(validEntities); + Class objClass = getObjClass(validEntities); + Method idMethod = getMethod(getId, objClass); + Map eMap = getIdToObjMap(validEntities, idMethod); + RequestInfo requestInfo = (RequestInfo) ReflectionUtils + .invokeMethod(getMethod(GET_REQUEST_INFO, request.getClass()), request); + + if (!eMap.isEmpty()) { + List entityIds = new ArrayList<>(eMap.keySet()); + List existingFacilityIds = facilityService.validateFacilityIds(entityIds, validEntities, + tenantId, errorDetailsMap, requestInfo); + List invalidEntities = validEntities.stream().filter(notHavingErrors()) + .filter(entity -> !existingFacilityIds + .contains((String) ReflectionUtils.invokeMethod(idMethod, entity))) + .collect(Collectors.toList()); + invalidEntities.forEach(entity -> { + Error error = getErrorForNonExistentRelatedEntity( + (String) ReflectionUtils.invokeMethod(idMethod, entity)); + populateErrorDetails(entity, error, errorDetailsMap); + }); + } + } + + return errorDetailsMap; + } + + /** + * + * Non generic method used for validating sender/receiver (parties) against + * facility or staff based on the type + * + * @param + * @param + * @param stockRequest + * @param errorDetailsMap + * @param validEntities + * @param getId + * @param facilityService + * @return + */ + public static Map> validateStockTransferParties(RequestInfo requestInfo, + Map> errorDetailsMap, List validStockEntities, FacilityService facilityService, + UserService userService) { + + if (!validStockEntities.isEmpty()) { + + Tuple, List> tupleOfInvalidStaffIdsAndFacilityIds = validateAndEnrichInvalidPartyIds( + requestInfo, errorDetailsMap, validStockEntities, facilityService, userService); + + enrichErrorMapFromInvalidPartyIds(errorDetailsMap, validStockEntities, + tupleOfInvalidStaffIdsAndFacilityIds.getX(), tupleOfInvalidStaffIdsAndFacilityIds.getY()); + + } + return errorDetailsMap; + } + + /** + * validates the list of party-ids (facility and staff) against the respective + * APIs and enriches the invalid ids list for both parties + * + * @param + * @param stockRequest + * @param errorDetailsMap + * @param validStockEntities + * @param facilityService + * @param facilityIds + * @param InvalidStaffId + * @param invalidFacilityIds + */ + @SuppressWarnings("unchecked") + private static Tuple, List> validateAndEnrichInvalidPartyIds(RequestInfo requestInfo, + Map> errorDetailsMap, List validStockEntities, FacilityService facilityService, + UserService userService) { + + List facilityIds = new ArrayList<>(); + List staffIds = new ArrayList<>(); + + enrichFaciltyAndStaffIdsFromStock(validStockEntities, facilityIds, staffIds); + + // copy all of party identifiers into invalid list + List InvalidStaffIds = new ArrayList<>(staffIds); + List invalidFacilityIds = new ArrayList<>(facilityIds); + + String tenantId = getTenantId(validStockEntities); + + // validate and remove valid identifiers from invalidStaffIds + UserSearchRequest userSearchRequest = new UserSearchRequest(); + userSearchRequest.setRequestInfo(requestInfo); + userSearchRequest.setUuid(staffIds); + List validStaffIds = userService.search(userSearchRequest).stream().map(user -> user.getUuid()) + .collect(Collectors.toList()); + InvalidStaffIds.removeAll(validStaffIds); + + // validate and remove valid identifiers from invalidfacilityIds + List validFacilityIds = facilityService.validateFacilityIds(facilityIds, (List) validStockEntities, + tenantId, errorDetailsMap, requestInfo); + invalidFacilityIds.removeAll(validFacilityIds); + + return new Tuple<>(InvalidStaffIds, invalidFacilityIds); + } + + /** + * Private method to enrich facility id and staff id + * + * @param validStockEntities + * @param facilityIds + * @param staffIds + */ + private static void enrichFaciltyAndStaffIdsFromStock(List validStockEntities, List facilityIds, + List staffIds) { + + for (Stock stock : validStockEntities) { + + if (stock.getSenderType().equalsIgnoreCase(WAREHOUSE)) { + facilityIds.add(stock.getSenderId()); + } + if (stock.getSenderType().equalsIgnoreCase(STAFF)) { + staffIds.add(stock.getSenderId()); + } + if (stock.getReceiverType().equalsIgnoreCase(WAREHOUSE)) { + facilityIds.add(stock.getReceiverId()); + } + if (stock.getReceiverType().equalsIgnoreCase(STAFF)) { + staffIds.add(stock.getReceiverId()); + } + } + } + + /** + * + * creates the error map from the stock objects with invalid party ids + * + * @param errorDetailsMap + * @param validStockEntities + * @param InvalidStaffId + * @param invalidFacilityIds + */ + @SuppressWarnings("unchecked") + private static void enrichErrorMapFromInvalidPartyIds(Map> errorDetailsMap, + List validStockEntities, List InvalidStaffId, List invalidFacilityIds) { + + Class objClass = getObjClass(validStockEntities); + Method senderIdMethod = getMethod("getSenderId", objClass); + Method recieverIdMethod = getMethod("getReceiverId", objClass); + + for (Stock stock : validStockEntities) { + + String senderId = stock.getSenderId(); + String recieverId = stock.getReceiverId(); + + if ((stock.getSenderType().equalsIgnoreCase(WAREHOUSE) && invalidFacilityIds.contains(senderId)) + + || (stock.getSenderType().equalsIgnoreCase(STAFF) && InvalidStaffId.contains(senderId))) { + + getIdForErrorFromMethod(errorDetailsMap, (T) stock, senderIdMethod); + } + + if ((stock.getReceiverType().equalsIgnoreCase(WAREHOUSE) && invalidFacilityIds.contains(recieverId)) + + || (stock.getReceiverType().equalsIgnoreCase(STAFF) && InvalidStaffId.contains(recieverId))) { + + getIdForErrorFromMethod(errorDetailsMap, (T) stock, recieverIdMethod); + } + } + } + + /** + * method to populate error details map + * + * @param + * @param errorDetailsMap + * @param entity + * @param idMethod + */ + private static void getIdForErrorFromMethod(Map> errorDetailsMap, T entity, Method idMethod) { + + Error error = getErrorForNonExistentRelatedEntity((String) ReflectionUtils.invokeMethod(idMethod, entity)); + populateErrorDetails(entity, error, errorDetailsMap); + } + + /** + * + * @param + * @param + * @param request + * @param errorDetailsMap + * @param validEntities + * @param getId + * @param facilityService + * @return + */ + @SuppressWarnings("unchecked") + public static Map> validateProjectFacilityMappings(R request, + Map> errorDetailsMap, List validEntities, String getReferenceId, + FacilityService facilityService) { + + if (!validEntities.isEmpty()) { + + String tenantId = getTenantId(validEntities); + Class objClass = getObjClass(validEntities); + Method idMethod = getMethod(getReferenceId, objClass); + RequestInfo requestInfo = (RequestInfo) ReflectionUtils + .invokeMethod(getMethod(GET_REQUEST_INFO, request.getClass()), request); + + Map> ProjectFacilityMappingOfIds = facilityService + .validateProjectFacilityMappings((List) validEntities, tenantId, errorDetailsMap, requestInfo); + + List invalidStocks = new ArrayList<>(); + + if (validEntities.get(0) instanceof Stock) + enrichErrorForStock((List) validEntities, ProjectFacilityMappingOfIds, invalidStocks, + errorDetailsMap); + else if (validEntities.get(0) instanceof StockReconciliation) + enrichErrorForStockReconciliation((List) validEntities, + ProjectFacilityMappingOfIds, invalidStocks, errorDetailsMap); + + } + + return errorDetailsMap; + } + + @SuppressWarnings("unchecked") + private static void enrichErrorForStock(List validEntities, + Map> ProjectFacilityMappingOfIds, List invalidStocks, + Map> errorDetailsMap) { + + for (Stock stock : validEntities) { + + String senderId = stock.getSenderId(); + String receiverId = stock.getReceiverId(); + + List facilityIds = ProjectFacilityMappingOfIds.get(stock.getReferenceId()); + if (!CollectionUtils.isEmpty(facilityIds)) { + + if (stock.getSenderType().equalsIgnoreCase("WAREHOUSE") && !facilityIds.contains(senderId)) { + populateErrorForStock(stock, senderId, errorDetailsMap); + } + + if (stock.getReceiverType().equalsIgnoreCase("WAREHOUSE") && !facilityIds.contains(receiverId)) + populateErrorForStock(stock, receiverId, errorDetailsMap); + } else { + populateErrorForStock(stock, senderId + " and " + receiverId, errorDetailsMap); + } + } + } + + @SuppressWarnings("unchecked") + private static void populateErrorForStock(Stock stock, String facilityId, Map> errorDetailsMap) { + + String errorMessage = String.format("No mapping exists for project id: %s & facility id: %s", + stock.getReferenceId(), facilityId); + + Error error = Error.builder().errorMessage(errorMessage).errorCode(NO_PROJECT_FACILITY_MAPPING_EXISTS) + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException(NO_PROJECT_FACILITY_MAPPING_EXISTS, errorMessage)).build(); + populateErrorDetails((T) stock, error, errorDetailsMap); + } + + @SuppressWarnings("unchecked") + private static void enrichErrorForStockReconciliation(List validEntities, + Map> ProjectFacilityMappingOfIds, List invalidStocks, + Map> errorDetailsMap) { + + for (StockReconciliation stockReconciliation : validEntities) { + + List facilityIds = ProjectFacilityMappingOfIds.get(stockReconciliation.getReferenceId()); + if (CollectionUtils.isEmpty(facilityIds)) { + populateErrorForStockReconciliation(stockReconciliation, errorDetailsMap); + } else if (!facilityIds.contains(stockReconciliation.getFacilityId())) + populateErrorForStockReconciliation(stockReconciliation, errorDetailsMap); + } + } + + @SuppressWarnings("unchecked") + private static void populateErrorForStockReconciliation(StockReconciliation stockReconciliation, + Map> errorDetailsMap) { + + String errorMessage = String.format("No mapping exists for project id: %s & facility id: %s", + stockReconciliation.getReferenceId(), stockReconciliation.getFacilityId()); + + Error error = Error.builder().errorMessage(errorMessage).errorCode(NO_PROJECT_FACILITY_MAPPING_EXISTS) + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException(NO_PROJECT_FACILITY_MAPPING_EXISTS, errorMessage)).build(); + populateErrorDetails((T) stockReconciliation, error, errorDetailsMap); + } } diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SFacilityIdValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SFacilityIdValidator.java deleted file mode 100644 index 21fa18af4a2..00000000000 --- a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SFacilityIdValidator.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.egov.stock.validator.stock; - -import lombok.extern.slf4j.Slf4j; -import org.egov.common.models.Error; -import org.egov.common.models.stock.Stock; -import org.egov.common.models.stock.StockBulkRequest; -import org.egov.common.validator.Validator; -import org.egov.stock.service.FacilityService; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.stock.Constants.GET_FACILITY_ID; -import static org.egov.stock.util.ValidatorUtil.validateFacilityIds; - -@Component -@Order(value = 7) -@Slf4j -public class SFacilityIdValidator implements Validator { - - private final FacilityService facilityService; - - public SFacilityIdValidator(FacilityService facilityService) { - this.facilityService = facilityService; - } - - @Override - public Map> validate(StockBulkRequest request) { - log.info("validating for facility id"); - Map> errorDetailsMap = new HashMap<>(); - - List validEntities = request.getStock().stream() - .filter(notHavingErrors()) - .collect(Collectors.toList()); - return validateFacilityIds(request, errorDetailsMap, validEntities, GET_FACILITY_ID, facilityService); - } -} diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/STransactingPartyIdValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/STransactingPartyIdValidator.java deleted file mode 100644 index 5e7604e635f..00000000000 --- a/health-services/stock/src/main/java/org/egov/stock/validator/stock/STransactingPartyIdValidator.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.egov.stock.validator.stock; - -import lombok.extern.slf4j.Slf4j; -import org.egov.common.models.Error; -import org.egov.common.models.stock.Stock; -import org.egov.common.models.stock.StockBulkRequest; -import org.egov.common.validator.Validator; -import org.egov.stock.service.FacilityService; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.stock.Constants.GET_TRANSACTING_PARTY_ID; -import static org.egov.stock.Constants.WAREHOUSE; -import static org.egov.stock.util.ValidatorUtil.validateFacilityIds; - -@Component -@Order(value = 9) -@Slf4j -public class STransactingPartyIdValidator implements Validator { - - private final FacilityService facilityService; - - public STransactingPartyIdValidator(FacilityService facilityService) { - this.facilityService = facilityService; - } - - @Override - public Map> validate(StockBulkRequest request) { - log.info("validating for reference id"); - Map> errorDetailsMap = new HashMap<>(); - - List validFacilityTransactingPartyIdEntities = request.getStock().stream() - .filter(notHavingErrors()) - .filter(entity -> WAREHOUSE.equals(entity.getTransactingPartyType())) - .collect(Collectors.toList()); - return validateFacilityIds(request, errorDetailsMap, validFacilityTransactingPartyIdEntities, - GET_TRANSACTING_PARTY_ID, facilityService); - } -} diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/StocktransferPartiesValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/StocktransferPartiesValidator.java new file mode 100644 index 00000000000..c4014007d84 --- /dev/null +++ b/health-services/stock/src/main/java/org/egov/stock/validator/stock/StocktransferPartiesValidator.java @@ -0,0 +1,46 @@ +package org.egov.stock.validator.stock; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.stock.util.ValidatorUtil.validateStockTransferParties; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.common.models.Error; +import org.egov.common.models.stock.Stock; +import org.egov.common.models.stock.StockBulkRequest; +import org.egov.common.service.UserService; +import org.egov.common.validator.Validator; +import org.egov.stock.service.FacilityService; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Order(value = 7) +@Slf4j +public class StocktransferPartiesValidator implements Validator { + + private final FacilityService facilityService; + + private UserService userService; + + public StocktransferPartiesValidator(FacilityService facilityService, UserService userService) { + this.facilityService = facilityService; + this.userService = userService; + } + + @Override + public Map> validate(StockBulkRequest request) { + log.info("validating for facility id"); + Map> errorDetailsMap = new HashMap<>(); + + List validEntities = request.getStock().stream().filter(notHavingErrors()).collect(Collectors.toList()); + + return validateStockTransferParties(request.getRequestInfo(), errorDetailsMap, validEntities, facilityService, + userService); + } +} diff --git a/health-services/stock/src/test/java/org/egov/stock/helper/StockReconciliationTestBuilder.java b/health-services/stock/src/test/java/org/egov/stock/helper/StockReconciliationTestBuilder.java index 616b726e29a..d7cfc4c247d 100644 --- a/health-services/stock/src/test/java/org/egov/stock/helper/StockReconciliationTestBuilder.java +++ b/health-services/stock/src/test/java/org/egov/stock/helper/StockReconciliationTestBuilder.java @@ -21,7 +21,7 @@ public StockReconciliation build() { } public StockReconciliationTestBuilder withStock() { - this.builder.facilityId("facility-id").productVariantId("pv-id").physicalCount(10) + this.builder.facilityId("sender-id").productVariantId("pv-id").physicalCount(10) .calculatedCount(100).referenceId("reference-id") .referenceIdType("PROJECT").rowVersion(1).tenantId("default").hasErrors(false).isDeleted(Boolean.FALSE) .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); diff --git a/health-services/stock/src/test/java/org/egov/stock/helper/StockTestBuilder.java b/health-services/stock/src/test/java/org/egov/stock/helper/StockTestBuilder.java index d755e8fd06d..90960baf5a3 100644 --- a/health-services/stock/src/test/java/org/egov/stock/helper/StockTestBuilder.java +++ b/health-services/stock/src/test/java/org/egov/stock/helper/StockTestBuilder.java @@ -23,11 +23,19 @@ public Stock build() { } public StockTestBuilder withStock() { - this.builder.facilityId("facility-id").productVariantId("pv-id").quantity(0).referenceId("reference-id") - .referenceIdType("PROJECT").rowVersion(1).tenantId("default").transactingPartyId("transaction-party-id") - .transactionType(TransactionType.DISPATCHED).transactionReason(TransactionReason.RECEIVED) - .transactingPartyType("WAREHOUSE").hasErrors(false).isDeleted(Boolean.FALSE) - .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); + this.builder + .senderId("sender-id") + .receiverId("receiver-id") + .productVariantId("pv-id").quantity(0) + .referenceId("reference-id") + .referenceIdType("PROJECT").rowVersion(1).tenantId("default") + .transactionType(TransactionType.DISPATCHED) + .transactionReason(TransactionReason.RECEIVED) + .senderType("WAREHOUSE") + .receiverType("STAFF") + .hasErrors(false) + .isDeleted(Boolean.FALSE) + .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); return this; } diff --git a/health-services/stock/src/test/java/org/egov/stock/validator/FacilityIdValidatorTest.java b/health-services/stock/src/test/java/org/egov/stock/validator/FacilityIdValidatorTest.java deleted file mode 100644 index ad7e257a488..00000000000 --- a/health-services/stock/src/test/java/org/egov/stock/validator/FacilityIdValidatorTest.java +++ /dev/null @@ -1,103 +0,0 @@ -package org.egov.stock.validator; - - -import org.egov.common.contract.request.RequestInfo; -import org.egov.common.models.Error; -import org.egov.common.models.stock.Stock; -import org.egov.common.models.stock.StockBulkRequest; -import org.egov.common.models.stock.StockReconciliation; -import org.egov.common.models.stock.StockReconciliationBulkRequest; -import org.egov.stock.helper.StockBulkRequestTestBuilder; -import org.egov.stock.helper.StockReconciliationBulkRequestTestBuilder; -import org.egov.stock.service.FacilityService; -import org.egov.stock.validator.stock.SFacilityIdValidator; -import org.egov.stock.validator.stockreconciliation.SrFacilityIdValidator; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -class FacilityIdValidatorTest { - - @InjectMocks - private SFacilityIdValidator sFacilityIdValidator; - - @InjectMocks - private SrFacilityIdValidator srFacilityIdValidator; - - @Mock - private FacilityService facilityService; - - private void mockEmptyResponse() { - when(facilityService.validateFacilityIds(any(List.class), - any(List.class), - any(String.class), - any(Map.class), - any(RequestInfo.class))).thenReturn(Collections.emptyList()); - } - - private void mockSomeResponse() { - when(facilityService.validateFacilityIds(any(List.class), - any(List.class), - any(String.class), - any(Map.class), - any(RequestInfo.class))).thenReturn(Collections.singletonList("facility-id")); - } - - @Test - @DisplayName("should add stock to error details if facility id not found") - void shouldAddStockToErrorDetailsIfFacilityIdNotFound() { - StockBulkRequest request = StockBulkRequestTestBuilder.builder().withStock().withRequestInfo().build(); - - mockEmptyResponse(); - - Map> errorDetailsMap = sFacilityIdValidator.validate(request); - assertEquals(errorDetailsMap.size(), 1); - } - - @Test - @DisplayName("should not add stock to error details if facility id found") - void shouldAddStockToErrorDetailsIfFacilityIdFound() { - StockBulkRequest request = StockBulkRequestTestBuilder.builder().withStock().withRequestInfo().build(); - - mockSomeResponse(); - - Map> errorDetailsMap = sFacilityIdValidator.validate(request); - assertEquals(errorDetailsMap.size(), 0); - } - - @Test - @DisplayName("should add stock reconciliation to error details if facility id not found") - void shouldAddStockReconciliationToErrorDetailsFacilityIdNotFound() { - StockReconciliationBulkRequest request = StockReconciliationBulkRequestTestBuilder.builder() - .withStock().withRequestInfo().build(); - - mockEmptyResponse(); - - Map> errorDetailsMap = srFacilityIdValidator.validate(request); - assertEquals(errorDetailsMap.size(), 1); - } - - @Test - @DisplayName("should not add stock reconciliation to error details if facility id found") - void shouldAddStockReconciliationToErrorDetailsIfFacilityIdFound() { - StockReconciliationBulkRequest request = StockReconciliationBulkRequestTestBuilder.builder() - .withStock().withRequestInfo().build(); - - mockSomeResponse(); - - Map> errorDetailsMap = srFacilityIdValidator.validate(request); - assertEquals(errorDetailsMap.size(), 0); - } -} diff --git a/health-services/stock/src/test/java/org/egov/stock/validator/ReferenceIdValidatorTest.java b/health-services/stock/src/test/java/org/egov/stock/validator/ReferenceIdValidatorTest.java index 096a1ffd9e6..d1a19f6df06 100644 --- a/health-services/stock/src/test/java/org/egov/stock/validator/ReferenceIdValidatorTest.java +++ b/health-services/stock/src/test/java/org/egov/stock/validator/ReferenceIdValidatorTest.java @@ -1,6 +1,16 @@ package org.egov.stock.validator; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.assertj.core.util.Arrays; import org.egov.common.contract.request.RequestInfo; import org.egov.common.models.Error; import org.egov.common.models.stock.Stock; @@ -19,14 +29,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - @ExtendWith(MockitoExtension.class) class ReferenceIdValidatorTest { @@ -43,14 +45,18 @@ private void mockEmptyResponse() { when(facilityService.validateProjectFacilityMappings(any(List.class), any(String.class), any(Map.class), - any(RequestInfo.class))).thenReturn(Collections.emptyList()); + any(RequestInfo.class))).thenReturn(Collections.emptyMap()); } private void mockSomeResponse() { + + List facilityIds = new ArrayList<>(); + facilityIds.add("sender-id"); + when(facilityService.validateProjectFacilityMappings(any(List.class), any(String.class), any(Map.class), - any(RequestInfo.class))).thenReturn(Collections.singletonList("facility-id||reference-id")); + any(RequestInfo.class))).thenReturn(Collections.singletonMap("reference-id", facilityIds)); } @Test diff --git a/health-services/stock/src/test/java/org/egov/stock/validator/TransactingPartyIdValidatorTest.java b/health-services/stock/src/test/java/org/egov/stock/validator/TransactingPartyIdValidatorTest.java deleted file mode 100644 index 0eda35fe11a..00000000000 --- a/health-services/stock/src/test/java/org/egov/stock/validator/TransactingPartyIdValidatorTest.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.egov.stock.validator; - - -import org.egov.common.contract.request.RequestInfo; -import org.egov.common.models.Error; -import org.egov.common.models.stock.Stock; -import org.egov.common.models.stock.StockBulkRequest; -import org.egov.stock.helper.StockBulkRequestTestBuilder; -import org.egov.stock.service.FacilityService; -import org.egov.stock.validator.stock.STransactingPartyIdValidator; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -class TransactingPartyIdValidatorTest { - - @InjectMocks - private STransactingPartyIdValidator sTransactingPartyIdValidator; - - @Mock - private FacilityService facilityService; - - private void mockEmptyResponse() { - when(facilityService.validateFacilityIds(any(List.class), - any(List.class), - any(String.class), - any(Map.class), - any(RequestInfo.class))).thenReturn(Collections.emptyList()); - } - - private void mockSomeResponse() { - when(facilityService.validateFacilityIds(any(List.class), - any(List.class), - any(String.class), - any(Map.class), - any(RequestInfo.class))).thenReturn(Collections.singletonList("transaction-party-id")); - } - - @Test - @DisplayName("should add stock to error details if transacting party id not found") - void shouldAddStockToErrorDetailsIfTransactingPartyIdNotFound() { - StockBulkRequest request = StockBulkRequestTestBuilder.builder().withStock().withRequestInfo().build(); - - mockEmptyResponse(); - - Map> errorDetailsMap = sTransactingPartyIdValidator.validate(request); - assertEquals(errorDetailsMap.size(), 1); - } - - @Test - @DisplayName("should not add stock to error details if transacting party id found") - void shouldAddStockToErrorDetailsIfTransactingPartyIdFound() { - StockBulkRequest request = StockBulkRequestTestBuilder.builder().withStock().withRequestInfo().build(); - - mockSomeResponse(); - - Map> errorDetailsMap = sTransactingPartyIdValidator.validate(request); - assertEquals(errorDetailsMap.size(), 0); - } -} From 69522726ab0d4623e2b29c6ee5641fb738aca7a2 Mon Sep 17 00:00:00 2001 From: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Date: Thu, 5 Oct 2023 14:49:37 +0530 Subject: [PATCH 180/283] stock exchange between parties enabled --- .../libraries/health-services-models/pom.xml | 2 +- .../org/egov/common/models/stock/Stock.java | 73 ++-- health-services/stock/pom.xml | 2 +- .../main/java/org/egov/stock/Constants.java | 4 + .../repository/rowmapper/StockRowMapper.java | 7 +- .../egov/stock/service/FacilityService.java | 72 +++- .../org/egov/stock/service/StockService.java | 50 ++- .../org/egov/stock/util/ValidatorUtil.java | 397 ++++++++++++++---- .../validator/stock/SFacilityIdValidator.java | 42 -- .../stock/STransactingPartyIdValidator.java | 45 -- .../stock/StocktransferPartiesValidator.java | 46 ++ .../StockReconciliationTestBuilder.java | 2 +- .../egov/stock/helper/StockTestBuilder.java | 18 +- .../validator/FacilityIdValidatorTest.java | 103 ----- .../validator/ReferenceIdValidatorTest.java | 26 +- .../TransactingPartyIdValidatorTest.java | 72 ---- 16 files changed, 514 insertions(+), 447 deletions(-) delete mode 100644 health-services/stock/src/main/java/org/egov/stock/validator/stock/SFacilityIdValidator.java delete mode 100644 health-services/stock/src/main/java/org/egov/stock/validator/stock/STransactingPartyIdValidator.java create mode 100644 health-services/stock/src/main/java/org/egov/stock/validator/stock/StocktransferPartiesValidator.java delete mode 100644 health-services/stock/src/test/java/org/egov/stock/validator/FacilityIdValidatorTest.java delete mode 100644 health-services/stock/src/test/java/org/egov/stock/validator/TransactingPartyIdValidatorTest.java diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index 202e7ac2a58..5823cdce8aa 100644 --- a/health-services/libraries/health-services-models/pom.xml +++ b/health-services/libraries/health-services-models/pom.xml @@ -6,7 +6,7 @@ org.egov.common health-services-models - 1.0.7-SNAPSHOT + 1.0.9-SNAPSHOT 8 diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java index 102474fae63..105b1752b1b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java @@ -1,18 +1,21 @@ package org.egov.common.models.stock; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import org.springframework.validation.annotation.Validated; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; + import digit.models.coremodels.AuditDetails; import lombok.AllArgsConstructor; import lombok.Builder; +import lombok.Builder.Default; import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; /** * Stock @@ -26,85 +29,97 @@ @Builder @JsonIgnoreProperties(ignoreUnknown = true) public class Stock { + @JsonProperty("id") @Size(min=2, max=64) - private String id = null; + private String id; @JsonProperty("clientReferenceId") @Size(min=2, max=64) - private String clientReferenceId = null; + private String clientReferenceId; @JsonProperty("tenantId") @NotNull @Size(min=2, max=1000) - private String tenantId = null; - - @JsonProperty("facilityId") - @NotNull - @Size(min=2, max=64) - private String facilityId = null; + private String tenantId; + /* product fields */ @JsonProperty("productVariantId") @NotNull @Size(min=2, max=64) - private String productVariantId = null; + private String productVariantId; @JsonProperty("quantity") @NotNull - private Integer quantity = null; + private Integer quantity; + /* project id in-case of health */ @JsonProperty("referenceId") - private String referenceId = null; + private String referenceId; @JsonProperty("referenceIdType") @Size(min=2, max=64) - private String referenceIdType = null; + private String referenceIdType; + // transaction fields @JsonProperty("transactionType") @NotNull @Valid - private TransactionType transactionType = null; + private TransactionType transactionType; @JsonProperty("transactionReason") @Valid - private TransactionReason transactionReason = null; + private TransactionReason transactionReason; + + @JsonProperty("senderId") + @NotNull + @Size(min=2, max=64) + private String senderId; - @JsonProperty("transactingPartyId") + @JsonProperty("senderType") @NotNull @Size(min=2, max=64) - private String transactingPartyId = null; + private String senderType; + + @JsonProperty("receiverId") + @NotNull + @Size(min=2, max=64) + private String receiverId; - @JsonProperty("transactingPartyType") + @JsonProperty("receiverType") @NotNull @Size(min=2, max=64) - private String transactingPartyType = null; + private String receiverType; @JsonProperty("wayBillNumber") @Size(min = 2, max = 200) - private String wayBillNumber = null; + private String wayBillNumber; @JsonProperty("additionalFields") @Valid - private AdditionalFields additionalFields = null; + private AdditionalFields additionalFields; @JsonProperty("isDeleted") + @Default private Boolean isDeleted = Boolean.FALSE; @JsonProperty("rowVersion") - private Integer rowVersion = null; + private Integer rowVersion; @JsonIgnore + @Default private Boolean hasErrors = Boolean.FALSE; @JsonProperty("auditDetails") @Valid - private AuditDetails auditDetails = null; + private AuditDetails auditDetails; @JsonProperty("dateOfEntry") - private Long dateOfEntry = null; + private Long dateOfEntry; @JsonProperty("clientAuditDetails") @Valid - private AuditDetails clientAuditDetails = null; + private AuditDetails clientAuditDetails; + } diff --git a/health-services/stock/pom.xml b/health-services/stock/pom.xml index edaaf44102e..81e99bf2071 100644 --- a/health-services/stock/pom.xml +++ b/health-services/stock/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.7-SNAPSHOT + 1.0.9-SNAPSHOT diff --git a/health-services/stock/src/main/java/org/egov/stock/Constants.java b/health-services/stock/src/main/java/org/egov/stock/Constants.java index 9895af2597d..cb7589dc33f 100644 --- a/health-services/stock/src/main/java/org/egov/stock/Constants.java +++ b/health-services/stock/src/main/java/org/egov/stock/Constants.java @@ -17,12 +17,16 @@ public class Constants { public static String VALIDATION_ERROR = "VALIDATION_ERROR"; public static String GET_FACILITY_ID = "getFacilityId"; + + public static String GET_SENDER_ID = "getSenderId"; public static String GET_REFERENCE_ID = "getReferenceId"; public static String GET_TRANSACTING_PARTY_ID = "getTransactingPartyId"; public static String WAREHOUSE = "WAREHOUSE"; + + public static String STAFF = "STAFF"; public static String PROJECT = "PROJECT"; diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java index 94b430ae45b..89471581084 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java @@ -37,7 +37,6 @@ public Stock mapRow(ResultSet resultSet, int i) throws SQLException { .id(resultSet.getString("id")) .clientReferenceId(resultSet.getString("clientReferenceId")) .tenantId(resultSet.getString("tenantId")) - .facilityId(resultSet.getString("facilityId")) .productVariantId(resultSet.getString("productVariantId")) .quantity(resultSet.getInt("quantity")) .wayBillNumber(resultSet.getString("wayBillNumber")) @@ -45,8 +44,10 @@ public Stock mapRow(ResultSet resultSet, int i) throws SQLException { .referenceIdType(resultSet.getString("referenceIdType")) .transactionType(TransactionType.fromValue(resultSet.getString("transactionType"))) .transactionReason(TransactionReason.fromValue(resultSet.getString("transactionReason"))) - .transactingPartyId(resultSet.getString("transactingPartyId")) - .transactingPartyType(resultSet.getString("transactingPartyType")) + .senderId(resultSet.getString("senderId")) + .senderType(resultSet.getString("senderType")) + .receiverId(resultSet.getString("receiverId")) + .receiverType(resultSet.getString("receiverType")) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) .auditDetails(auditDetails) diff --git a/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java b/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java index 3a54d0ec400..4a19ab8d32d 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java @@ -1,6 +1,20 @@ package org.egov.stock.service; -import lombok.extern.slf4j.Slf4j; +import static org.egov.common.utils.CommonUtils.getIdList; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForEntityWithNetworkError; +import static org.egov.stock.Constants.GET_FACILITY_ID; +import static org.egov.stock.Constants.GET_REFERENCE_ID; +import static org.egov.stock.Constants.WAREHOUSE; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; @@ -11,21 +25,12 @@ import org.egov.common.models.project.ProjectFacilityBulkResponse; import org.egov.common.models.project.ProjectFacilitySearch; import org.egov.common.models.project.ProjectFacilitySearchRequest; +import org.egov.common.models.stock.Stock; +import org.egov.common.models.stock.StockReconciliation; import org.egov.stock.config.StockConfiguration; import org.springframework.stereotype.Service; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.getIdList; -import static org.egov.common.utils.CommonUtils.getMethod; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.common.utils.ValidatorUtils.getErrorForEntityWithNetworkError; -import static org.egov.stock.Constants.GET_FACILITY_ID; -import static org.egov.stock.Constants.GET_REFERENCE_ID; -import static org.egov.stock.Constants.PIPE; +import lombok.extern.slf4j.Slf4j; @Service @Slf4j @@ -40,7 +45,7 @@ public FacilityService(StockConfiguration stockConfiguration, ServiceRequestClie this.serviceRequestClient = serviceRequestClient; } - public List validateFacilityIds(List entityIds, + public List validateFacilityIds(List entityIds, List entities, String tenantId, Map> errorDetailsMap, @@ -62,20 +67,41 @@ public List validateFacilityIds(List entityIds, return response.getFacilities().stream().map(Facility::getId).collect(Collectors.toList()); } catch (Exception e) { log.error("error while fetching facility list", e); - entities.forEach(b -> { + entities.forEach( stockEntity -> { Error error = getErrorForEntityWithNetworkError(); - populateErrorDetails(b, error, errorDetailsMap); + populateErrorDetails(stockEntity, error, errorDetailsMap); }); return Collections.emptyList(); } } - public List validateProjectFacilityMappings(List entities, + public Map> validateProjectFacilityMappings(List entities, String tenantId, Map> errorDetailsMap, RequestInfo requestInfo) { + + List projectIds = getIdList(entities, getMethod(GET_REFERENCE_ID, entities.get(0).getClass())); - List facilityIds = getIdList(entities, getMethod(GET_FACILITY_ID, entities.get(0).getClass())); + List facilityIds = null; + + if (entities.get(0) instanceof StockReconciliation) { + facilityIds = getIdList(entities, getMethod(GET_FACILITY_ID, entities.get(0).getClass())); + } else if (entities.get(0) instanceof Stock) { + + facilityIds = new ArrayList<>(); + for (T entity : entities) { + + Stock stock = (Stock) entity; + + if (stock.getSenderType().equalsIgnoreCase(WAREHOUSE)) { + facilityIds.add(stock.getSenderId()); + } + if (stock.getReceiverType().equalsIgnoreCase(WAREHOUSE)) { + facilityIds.add(stock.getReceiverId()); + } + } + } + Integer searchLimit = projectIds.size() * facilityIds.size(); ProjectFacilitySearchRequest projectFacilitySearchRequest = ProjectFacilitySearchRequest.builder() @@ -91,16 +117,18 @@ public List validateProjectFacilityMappings(List entities, + "&offset=0&tenantId=" + tenantId), projectFacilitySearchRequest, ProjectFacilityBulkResponse.class); - return response.getProjectFacilities().stream() - .map(projectFacility -> projectFacility.getFacilityId() + PIPE + projectFacility.getProjectId()) - .collect(Collectors.toList()); + + return response.getProjectFacilities().stream() + .collect(Collectors.groupingBy(projectFacility -> projectFacility.getFacilityId(), + Collectors.mapping(projectFacility -> projectFacility.getFacilityId(), Collectors.toList()))); + } catch (Exception e) { log.error("error while fetching project facility list", e); entities.forEach(b -> { Error error = getErrorForEntityWithNetworkError(); populateErrorDetails(b, error, errorDetailsMap); }); - return Collections.emptyList(); + return Collections.emptyMap(); } } } diff --git a/health-services/stock/src/main/java/org/egov/stock/service/StockService.java b/health-services/stock/src/main/java/org/egov/stock/service/StockService.java index 8b5c232c09c..8bbbd72c065 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/StockService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/StockService.java @@ -1,6 +1,24 @@ package org.egov.stock.service; -import lombok.extern.slf4j.Slf4j; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.CommonUtils.validate; +import static org.egov.stock.Constants.GET_STOCK; +import static org.egov.stock.Constants.SET_STOCK; +import static org.egov.stock.Constants.VALIDATION_ERROR; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.stock.Stock; @@ -10,37 +28,19 @@ import org.egov.stock.config.StockConfiguration; import org.egov.stock.repository.StockRepository; import org.egov.stock.service.enrichment.StockEnrichmentService; -import org.egov.stock.validator.stock.SFacilityIdValidator; import org.egov.stock.validator.stock.SIsDeletedValidator; import org.egov.stock.validator.stock.SNonExistentValidator; import org.egov.stock.validator.stock.SNullIdValidator; import org.egov.stock.validator.stock.SProductVariantIdValidator; import org.egov.stock.validator.stock.SReferenceIdValidator; import org.egov.stock.validator.stock.SRowVersionValidator; -import org.egov.stock.validator.stock.STransactingPartyIdValidator; import org.egov.stock.validator.stock.SUniqueEntityValidator; +import org.egov.stock.validator.stock.StocktransferPartiesValidator; import org.egov.stock.web.models.StockSearchRequest; import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.getIdFieldName; -import static org.egov.common.utils.CommonUtils.getIdMethod; -import static org.egov.common.utils.CommonUtils.handleErrors; -import static org.egov.common.utils.CommonUtils.havingTenantId; -import static org.egov.common.utils.CommonUtils.includeDeleted; -import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; -import static org.egov.common.utils.CommonUtils.lastChangedSince; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.common.utils.CommonUtils.validate; -import static org.egov.stock.Constants.GET_STOCK; -import static org.egov.stock.Constants.SET_STOCK; -import static org.egov.stock.Constants.VALIDATION_ERROR; +import lombok.extern.slf4j.Slf4j; @Service @@ -57,9 +57,8 @@ public class StockService { private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(SProductVariantIdValidator.class) - || validator.getClass().equals(SFacilityIdValidator.class) - || validator.getClass().equals(SReferenceIdValidator.class) - || validator.getClass().equals(STransactingPartyIdValidator.class); + || validator.getClass().equals(StocktransferPartiesValidator.class) + || validator.getClass().equals(SReferenceIdValidator.class); private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(SProductVariantIdValidator.class) @@ -68,9 +67,8 @@ public class StockService { || validator.getClass().equals(SNullIdValidator.class) || validator.getClass().equals(SRowVersionValidator.class) || validator.getClass().equals(SUniqueEntityValidator.class) - || validator.getClass().equals(SFacilityIdValidator.class) || validator.getClass().equals(SReferenceIdValidator.class) - || validator.getClass().equals(STransactingPartyIdValidator.class); + || validator.getClass().equals(StocktransferPartiesValidator.class); private final Predicate> isApplicableForDelete = validator -> validator.getClass().equals(SNonExistentValidator.class) diff --git a/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java b/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java index 92c1297cf7c..0104a16d12a 100644 --- a/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java +++ b/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java @@ -1,17 +1,5 @@ package org.egov.stock.util; -import org.egov.common.contract.request.RequestInfo; -import org.egov.common.models.Error; -import org.egov.stock.service.FacilityService; -import org.egov.tracer.model.CustomException; -import org.springframework.util.ReflectionUtils; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.getIdToObjMap; import static org.egov.common.utils.CommonUtils.getMethod; import static org.egov.common.utils.CommonUtils.getObjClass; @@ -19,84 +7,319 @@ import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentRelatedEntity; -import static org.egov.stock.Constants.GET_FACILITY_ID; import static org.egov.stock.Constants.GET_REQUEST_INFO; import static org.egov.stock.Constants.NO_PROJECT_FACILITY_MAPPING_EXISTS; -import static org.egov.stock.Constants.PIPE; +import static org.egov.stock.Constants.STAFF; +import static org.egov.stock.Constants.WAREHOUSE; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.ds.Tuple; +import org.egov.common.models.Error; +import org.egov.common.models.stock.Stock; +import org.egov.common.models.stock.StockReconciliation; +import org.egov.common.service.UserService; +import org.egov.stock.service.FacilityService; +import org.egov.tracer.model.CustomException; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ReflectionUtils; + +import digit.models.coremodels.UserSearchRequest; public class ValidatorUtil { - public static Map> validateFacilityIds(R request, - Map> errorDetailsMap, - List validEntities, - String getId, - FacilityService facilityService) { - if (!validEntities.isEmpty()) { - String tenantId = getTenantId(validEntities); - Class objClass = getObjClass(validEntities); - Method idMethod = getMethod(getId, objClass); - Map eMap = getIdToObjMap(validEntities, idMethod); - RequestInfo requestInfo = (RequestInfo) ReflectionUtils.invokeMethod(getMethod(GET_REQUEST_INFO, - request.getClass()), request); - - if (!eMap.isEmpty()) { - List entityIds = new ArrayList<>(eMap.keySet()); - List existingFacilityIds = facilityService.validateFacilityIds(entityIds, - validEntities, - tenantId, errorDetailsMap, requestInfo); - List invalidEntities = validEntities.stream() - .filter(notHavingErrors()).filter(entity -> - !existingFacilityIds.contains((String) ReflectionUtils.invokeMethod(idMethod, entity))) - .collect(Collectors.toList()); - invalidEntities.forEach(entity -> { - Error error = getErrorForNonExistentRelatedEntity((String) ReflectionUtils.invokeMethod(idMethod, - entity)); - populateErrorDetails(entity, error, errorDetailsMap); - }); - } - } - - return errorDetailsMap; - } - - public static Map> validateProjectFacilityMappings(R request, - Map> errorDetailsMap, - List validEntities, - String getId, - FacilityService facilityService) { - if (!validEntities.isEmpty()) { - String tenantId = getTenantId(validEntities); - Class objClass = getObjClass(validEntities); - Method idMethod = getMethod(getId, objClass); - RequestInfo requestInfo = (RequestInfo) ReflectionUtils.invokeMethod(getMethod(GET_REQUEST_INFO, - request.getClass()), request); - - List existingProjectFacilityMappingIds = facilityService - .validateProjectFacilityMappings(validEntities, tenantId, - errorDetailsMap, requestInfo); - List invalidEntities = validEntities.stream() - .filter(notHavingErrors()).filter(entity -> - { - String comboId = (String) ReflectionUtils.invokeMethod(getMethod(GET_FACILITY_ID, objClass), - entity) - + PIPE + (String) ReflectionUtils.invokeMethod(idMethod, entity); - return !existingProjectFacilityMappingIds.contains(comboId); - }) - .collect(Collectors.toList()); - invalidEntities.forEach(entity -> { - String errorMessage = String.format("No mapping exists for project id: %s & facility id: %s", - (String) ReflectionUtils.invokeMethod(idMethod, entity), - (String) ReflectionUtils.invokeMethod(getMethod(GET_FACILITY_ID, objClass), - entity)); - Error error = Error.builder() - .errorMessage(errorMessage) - .errorCode(NO_PROJECT_FACILITY_MAPPING_EXISTS) - .type(Error.ErrorType.NON_RECOVERABLE) - .exception(new CustomException(NO_PROJECT_FACILITY_MAPPING_EXISTS, errorMessage)).build(); - populateErrorDetails(entity, error, errorDetailsMap); - }); - } - - return errorDetailsMap; - } + public static Map> validateFacilityIds(R request, Map> errorDetailsMap, + List validEntities, String getId, FacilityService facilityService) { + + if (!validEntities.isEmpty()) { + String tenantId = getTenantId(validEntities); + Class objClass = getObjClass(validEntities); + Method idMethod = getMethod(getId, objClass); + Map eMap = getIdToObjMap(validEntities, idMethod); + RequestInfo requestInfo = (RequestInfo) ReflectionUtils + .invokeMethod(getMethod(GET_REQUEST_INFO, request.getClass()), request); + + if (!eMap.isEmpty()) { + List entityIds = new ArrayList<>(eMap.keySet()); + List existingFacilityIds = facilityService.validateFacilityIds(entityIds, validEntities, + tenantId, errorDetailsMap, requestInfo); + List invalidEntities = validEntities.stream().filter(notHavingErrors()) + .filter(entity -> !existingFacilityIds + .contains((String) ReflectionUtils.invokeMethod(idMethod, entity))) + .collect(Collectors.toList()); + invalidEntities.forEach(entity -> { + Error error = getErrorForNonExistentRelatedEntity( + (String) ReflectionUtils.invokeMethod(idMethod, entity)); + populateErrorDetails(entity, error, errorDetailsMap); + }); + } + } + + return errorDetailsMap; + } + + /** + * + * Non generic method used for validating sender/receiver (parties) against + * facility or staff based on the type + * + * @param + * @param + * @param stockRequest + * @param errorDetailsMap + * @param validEntities + * @param getId + * @param facilityService + * @return + */ + public static Map> validateStockTransferParties(RequestInfo requestInfo, + Map> errorDetailsMap, List validStockEntities, FacilityService facilityService, + UserService userService) { + + if (!validStockEntities.isEmpty()) { + + Tuple, List> tupleOfInvalidStaffIdsAndFacilityIds = validateAndEnrichInvalidPartyIds( + requestInfo, errorDetailsMap, validStockEntities, facilityService, userService); + + enrichErrorMapFromInvalidPartyIds(errorDetailsMap, validStockEntities, + tupleOfInvalidStaffIdsAndFacilityIds.getX(), tupleOfInvalidStaffIdsAndFacilityIds.getY()); + + } + return errorDetailsMap; + } + + /** + * validates the list of party-ids (facility and staff) against the respective + * APIs and enriches the invalid ids list for both parties + * + * @param + * @param stockRequest + * @param errorDetailsMap + * @param validStockEntities + * @param facilityService + * @param facilityIds + * @param InvalidStaffId + * @param invalidFacilityIds + */ + @SuppressWarnings("unchecked") + private static Tuple, List> validateAndEnrichInvalidPartyIds(RequestInfo requestInfo, + Map> errorDetailsMap, List validStockEntities, FacilityService facilityService, + UserService userService) { + + List facilityIds = new ArrayList<>(); + List staffIds = new ArrayList<>(); + + enrichFaciltyAndStaffIdsFromStock(validStockEntities, facilityIds, staffIds); + + // copy all of party identifiers into invalid list + List InvalidStaffIds = new ArrayList<>(staffIds); + List invalidFacilityIds = new ArrayList<>(facilityIds); + + String tenantId = getTenantId(validStockEntities); + + // validate and remove valid identifiers from invalidStaffIds + UserSearchRequest userSearchRequest = new UserSearchRequest(); + userSearchRequest.setRequestInfo(requestInfo); + userSearchRequest.setUuid(staffIds); + List validStaffIds = userService.search(userSearchRequest).stream().map(user -> user.getUuid()) + .collect(Collectors.toList()); + InvalidStaffIds.removeAll(validStaffIds); + + // validate and remove valid identifiers from invalidfacilityIds + List validFacilityIds = facilityService.validateFacilityIds(facilityIds, (List) validStockEntities, + tenantId, errorDetailsMap, requestInfo); + invalidFacilityIds.removeAll(validFacilityIds); + + return new Tuple<>(InvalidStaffIds, invalidFacilityIds); + } + + /** + * Private method to enrich facility id and staff id + * + * @param validStockEntities + * @param facilityIds + * @param staffIds + */ + private static void enrichFaciltyAndStaffIdsFromStock(List validStockEntities, List facilityIds, + List staffIds) { + + for (Stock stock : validStockEntities) { + + if (stock.getSenderType().equalsIgnoreCase(WAREHOUSE)) { + facilityIds.add(stock.getSenderId()); + } + if (stock.getSenderType().equalsIgnoreCase(STAFF)) { + staffIds.add(stock.getSenderId()); + } + if (stock.getReceiverType().equalsIgnoreCase(WAREHOUSE)) { + facilityIds.add(stock.getReceiverId()); + } + if (stock.getReceiverType().equalsIgnoreCase(STAFF)) { + staffIds.add(stock.getReceiverId()); + } + } + } + + /** + * + * creates the error map from the stock objects with invalid party ids + * + * @param errorDetailsMap + * @param validStockEntities + * @param InvalidStaffId + * @param invalidFacilityIds + */ + @SuppressWarnings("unchecked") + private static void enrichErrorMapFromInvalidPartyIds(Map> errorDetailsMap, + List validStockEntities, List InvalidStaffId, List invalidFacilityIds) { + + Class objClass = getObjClass(validStockEntities); + Method senderIdMethod = getMethod("getSenderId", objClass); + Method recieverIdMethod = getMethod("getReceiverId", objClass); + + for (Stock stock : validStockEntities) { + + String senderId = stock.getSenderId(); + String recieverId = stock.getReceiverId(); + + if ((stock.getSenderType().equalsIgnoreCase(WAREHOUSE) && invalidFacilityIds.contains(senderId)) + + || (stock.getSenderType().equalsIgnoreCase(STAFF) && InvalidStaffId.contains(senderId))) { + + getIdForErrorFromMethod(errorDetailsMap, (T) stock, senderIdMethod); + } + + if ((stock.getReceiverType().equalsIgnoreCase(WAREHOUSE) && invalidFacilityIds.contains(recieverId)) + + || (stock.getReceiverType().equalsIgnoreCase(STAFF) && InvalidStaffId.contains(recieverId))) { + + getIdForErrorFromMethod(errorDetailsMap, (T) stock, recieverIdMethod); + } + } + } + + /** + * method to populate error details map + * + * @param + * @param errorDetailsMap + * @param entity + * @param idMethod + */ + private static void getIdForErrorFromMethod(Map> errorDetailsMap, T entity, Method idMethod) { + + Error error = getErrorForNonExistentRelatedEntity((String) ReflectionUtils.invokeMethod(idMethod, entity)); + populateErrorDetails(entity, error, errorDetailsMap); + } + + /** + * + * @param + * @param + * @param request + * @param errorDetailsMap + * @param validEntities + * @param getId + * @param facilityService + * @return + */ + @SuppressWarnings("unchecked") + public static Map> validateProjectFacilityMappings(R request, + Map> errorDetailsMap, List validEntities, String getReferenceId, + FacilityService facilityService) { + + if (!validEntities.isEmpty()) { + + String tenantId = getTenantId(validEntities); + Class objClass = getObjClass(validEntities); + Method idMethod = getMethod(getReferenceId, objClass); + RequestInfo requestInfo = (RequestInfo) ReflectionUtils + .invokeMethod(getMethod(GET_REQUEST_INFO, request.getClass()), request); + + Map> ProjectFacilityMappingOfIds = facilityService + .validateProjectFacilityMappings((List) validEntities, tenantId, errorDetailsMap, requestInfo); + + List invalidStocks = new ArrayList<>(); + + if (validEntities.get(0) instanceof Stock) + enrichErrorForStock((List) validEntities, ProjectFacilityMappingOfIds, invalidStocks, + errorDetailsMap); + else if (validEntities.get(0) instanceof StockReconciliation) + enrichErrorForStockReconciliation((List) validEntities, + ProjectFacilityMappingOfIds, invalidStocks, errorDetailsMap); + + } + + return errorDetailsMap; + } + + @SuppressWarnings("unchecked") + private static void enrichErrorForStock(List validEntities, + Map> ProjectFacilityMappingOfIds, List invalidStocks, + Map> errorDetailsMap) { + + for (Stock stock : validEntities) { + + String senderId = stock.getSenderId(); + String receiverId = stock.getReceiverId(); + + List facilityIds = ProjectFacilityMappingOfIds.get(stock.getReferenceId()); + if (!CollectionUtils.isEmpty(facilityIds)) { + + if (stock.getSenderType().equalsIgnoreCase("WAREHOUSE") && !facilityIds.contains(senderId)) { + populateErrorForStock(stock, senderId, errorDetailsMap); + } + + if (stock.getReceiverType().equalsIgnoreCase("WAREHOUSE") && !facilityIds.contains(receiverId)) + populateErrorForStock(stock, receiverId, errorDetailsMap); + } else { + populateErrorForStock(stock, senderId + " and " + receiverId, errorDetailsMap); + } + } + } + + @SuppressWarnings("unchecked") + private static void populateErrorForStock(Stock stock, String facilityId, Map> errorDetailsMap) { + + String errorMessage = String.format("No mapping exists for project id: %s & facility id: %s", + stock.getReferenceId(), facilityId); + + Error error = Error.builder().errorMessage(errorMessage).errorCode(NO_PROJECT_FACILITY_MAPPING_EXISTS) + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException(NO_PROJECT_FACILITY_MAPPING_EXISTS, errorMessage)).build(); + populateErrorDetails((T) stock, error, errorDetailsMap); + } + + @SuppressWarnings("unchecked") + private static void enrichErrorForStockReconciliation(List validEntities, + Map> ProjectFacilityMappingOfIds, List invalidStocks, + Map> errorDetailsMap) { + + for (StockReconciliation stockReconciliation : validEntities) { + + List facilityIds = ProjectFacilityMappingOfIds.get(stockReconciliation.getReferenceId()); + if (CollectionUtils.isEmpty(facilityIds)) { + populateErrorForStockReconciliation(stockReconciliation, errorDetailsMap); + } else if (!facilityIds.contains(stockReconciliation.getFacilityId())) + populateErrorForStockReconciliation(stockReconciliation, errorDetailsMap); + } + } + + @SuppressWarnings("unchecked") + private static void populateErrorForStockReconciliation(StockReconciliation stockReconciliation, + Map> errorDetailsMap) { + + String errorMessage = String.format("No mapping exists for project id: %s & facility id: %s", + stockReconciliation.getReferenceId(), stockReconciliation.getFacilityId()); + + Error error = Error.builder().errorMessage(errorMessage).errorCode(NO_PROJECT_FACILITY_MAPPING_EXISTS) + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException(NO_PROJECT_FACILITY_MAPPING_EXISTS, errorMessage)).build(); + populateErrorDetails((T) stockReconciliation, error, errorDetailsMap); + } } diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SFacilityIdValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SFacilityIdValidator.java deleted file mode 100644 index 21fa18af4a2..00000000000 --- a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SFacilityIdValidator.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.egov.stock.validator.stock; - -import lombok.extern.slf4j.Slf4j; -import org.egov.common.models.Error; -import org.egov.common.models.stock.Stock; -import org.egov.common.models.stock.StockBulkRequest; -import org.egov.common.validator.Validator; -import org.egov.stock.service.FacilityService; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.stock.Constants.GET_FACILITY_ID; -import static org.egov.stock.util.ValidatorUtil.validateFacilityIds; - -@Component -@Order(value = 7) -@Slf4j -public class SFacilityIdValidator implements Validator { - - private final FacilityService facilityService; - - public SFacilityIdValidator(FacilityService facilityService) { - this.facilityService = facilityService; - } - - @Override - public Map> validate(StockBulkRequest request) { - log.info("validating for facility id"); - Map> errorDetailsMap = new HashMap<>(); - - List validEntities = request.getStock().stream() - .filter(notHavingErrors()) - .collect(Collectors.toList()); - return validateFacilityIds(request, errorDetailsMap, validEntities, GET_FACILITY_ID, facilityService); - } -} diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/STransactingPartyIdValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/STransactingPartyIdValidator.java deleted file mode 100644 index 5e7604e635f..00000000000 --- a/health-services/stock/src/main/java/org/egov/stock/validator/stock/STransactingPartyIdValidator.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.egov.stock.validator.stock; - -import lombok.extern.slf4j.Slf4j; -import org.egov.common.models.Error; -import org.egov.common.models.stock.Stock; -import org.egov.common.models.stock.StockBulkRequest; -import org.egov.common.validator.Validator; -import org.egov.stock.service.FacilityService; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.stock.Constants.GET_TRANSACTING_PARTY_ID; -import static org.egov.stock.Constants.WAREHOUSE; -import static org.egov.stock.util.ValidatorUtil.validateFacilityIds; - -@Component -@Order(value = 9) -@Slf4j -public class STransactingPartyIdValidator implements Validator { - - private final FacilityService facilityService; - - public STransactingPartyIdValidator(FacilityService facilityService) { - this.facilityService = facilityService; - } - - @Override - public Map> validate(StockBulkRequest request) { - log.info("validating for reference id"); - Map> errorDetailsMap = new HashMap<>(); - - List validFacilityTransactingPartyIdEntities = request.getStock().stream() - .filter(notHavingErrors()) - .filter(entity -> WAREHOUSE.equals(entity.getTransactingPartyType())) - .collect(Collectors.toList()); - return validateFacilityIds(request, errorDetailsMap, validFacilityTransactingPartyIdEntities, - GET_TRANSACTING_PARTY_ID, facilityService); - } -} diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/StocktransferPartiesValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/StocktransferPartiesValidator.java new file mode 100644 index 00000000000..c4014007d84 --- /dev/null +++ b/health-services/stock/src/main/java/org/egov/stock/validator/stock/StocktransferPartiesValidator.java @@ -0,0 +1,46 @@ +package org.egov.stock.validator.stock; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.stock.util.ValidatorUtil.validateStockTransferParties; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.common.models.Error; +import org.egov.common.models.stock.Stock; +import org.egov.common.models.stock.StockBulkRequest; +import org.egov.common.service.UserService; +import org.egov.common.validator.Validator; +import org.egov.stock.service.FacilityService; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Order(value = 7) +@Slf4j +public class StocktransferPartiesValidator implements Validator { + + private final FacilityService facilityService; + + private UserService userService; + + public StocktransferPartiesValidator(FacilityService facilityService, UserService userService) { + this.facilityService = facilityService; + this.userService = userService; + } + + @Override + public Map> validate(StockBulkRequest request) { + log.info("validating for facility id"); + Map> errorDetailsMap = new HashMap<>(); + + List validEntities = request.getStock().stream().filter(notHavingErrors()).collect(Collectors.toList()); + + return validateStockTransferParties(request.getRequestInfo(), errorDetailsMap, validEntities, facilityService, + userService); + } +} diff --git a/health-services/stock/src/test/java/org/egov/stock/helper/StockReconciliationTestBuilder.java b/health-services/stock/src/test/java/org/egov/stock/helper/StockReconciliationTestBuilder.java index 616b726e29a..d7cfc4c247d 100644 --- a/health-services/stock/src/test/java/org/egov/stock/helper/StockReconciliationTestBuilder.java +++ b/health-services/stock/src/test/java/org/egov/stock/helper/StockReconciliationTestBuilder.java @@ -21,7 +21,7 @@ public StockReconciliation build() { } public StockReconciliationTestBuilder withStock() { - this.builder.facilityId("facility-id").productVariantId("pv-id").physicalCount(10) + this.builder.facilityId("sender-id").productVariantId("pv-id").physicalCount(10) .calculatedCount(100).referenceId("reference-id") .referenceIdType("PROJECT").rowVersion(1).tenantId("default").hasErrors(false).isDeleted(Boolean.FALSE) .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); diff --git a/health-services/stock/src/test/java/org/egov/stock/helper/StockTestBuilder.java b/health-services/stock/src/test/java/org/egov/stock/helper/StockTestBuilder.java index d755e8fd06d..90960baf5a3 100644 --- a/health-services/stock/src/test/java/org/egov/stock/helper/StockTestBuilder.java +++ b/health-services/stock/src/test/java/org/egov/stock/helper/StockTestBuilder.java @@ -23,11 +23,19 @@ public Stock build() { } public StockTestBuilder withStock() { - this.builder.facilityId("facility-id").productVariantId("pv-id").quantity(0).referenceId("reference-id") - .referenceIdType("PROJECT").rowVersion(1).tenantId("default").transactingPartyId("transaction-party-id") - .transactionType(TransactionType.DISPATCHED).transactionReason(TransactionReason.RECEIVED) - .transactingPartyType("WAREHOUSE").hasErrors(false).isDeleted(Boolean.FALSE) - .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); + this.builder + .senderId("sender-id") + .receiverId("receiver-id") + .productVariantId("pv-id").quantity(0) + .referenceId("reference-id") + .referenceIdType("PROJECT").rowVersion(1).tenantId("default") + .transactionType(TransactionType.DISPATCHED) + .transactionReason(TransactionReason.RECEIVED) + .senderType("WAREHOUSE") + .receiverType("STAFF") + .hasErrors(false) + .isDeleted(Boolean.FALSE) + .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); return this; } diff --git a/health-services/stock/src/test/java/org/egov/stock/validator/FacilityIdValidatorTest.java b/health-services/stock/src/test/java/org/egov/stock/validator/FacilityIdValidatorTest.java deleted file mode 100644 index ad7e257a488..00000000000 --- a/health-services/stock/src/test/java/org/egov/stock/validator/FacilityIdValidatorTest.java +++ /dev/null @@ -1,103 +0,0 @@ -package org.egov.stock.validator; - - -import org.egov.common.contract.request.RequestInfo; -import org.egov.common.models.Error; -import org.egov.common.models.stock.Stock; -import org.egov.common.models.stock.StockBulkRequest; -import org.egov.common.models.stock.StockReconciliation; -import org.egov.common.models.stock.StockReconciliationBulkRequest; -import org.egov.stock.helper.StockBulkRequestTestBuilder; -import org.egov.stock.helper.StockReconciliationBulkRequestTestBuilder; -import org.egov.stock.service.FacilityService; -import org.egov.stock.validator.stock.SFacilityIdValidator; -import org.egov.stock.validator.stockreconciliation.SrFacilityIdValidator; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -class FacilityIdValidatorTest { - - @InjectMocks - private SFacilityIdValidator sFacilityIdValidator; - - @InjectMocks - private SrFacilityIdValidator srFacilityIdValidator; - - @Mock - private FacilityService facilityService; - - private void mockEmptyResponse() { - when(facilityService.validateFacilityIds(any(List.class), - any(List.class), - any(String.class), - any(Map.class), - any(RequestInfo.class))).thenReturn(Collections.emptyList()); - } - - private void mockSomeResponse() { - when(facilityService.validateFacilityIds(any(List.class), - any(List.class), - any(String.class), - any(Map.class), - any(RequestInfo.class))).thenReturn(Collections.singletonList("facility-id")); - } - - @Test - @DisplayName("should add stock to error details if facility id not found") - void shouldAddStockToErrorDetailsIfFacilityIdNotFound() { - StockBulkRequest request = StockBulkRequestTestBuilder.builder().withStock().withRequestInfo().build(); - - mockEmptyResponse(); - - Map> errorDetailsMap = sFacilityIdValidator.validate(request); - assertEquals(errorDetailsMap.size(), 1); - } - - @Test - @DisplayName("should not add stock to error details if facility id found") - void shouldAddStockToErrorDetailsIfFacilityIdFound() { - StockBulkRequest request = StockBulkRequestTestBuilder.builder().withStock().withRequestInfo().build(); - - mockSomeResponse(); - - Map> errorDetailsMap = sFacilityIdValidator.validate(request); - assertEquals(errorDetailsMap.size(), 0); - } - - @Test - @DisplayName("should add stock reconciliation to error details if facility id not found") - void shouldAddStockReconciliationToErrorDetailsFacilityIdNotFound() { - StockReconciliationBulkRequest request = StockReconciliationBulkRequestTestBuilder.builder() - .withStock().withRequestInfo().build(); - - mockEmptyResponse(); - - Map> errorDetailsMap = srFacilityIdValidator.validate(request); - assertEquals(errorDetailsMap.size(), 1); - } - - @Test - @DisplayName("should not add stock reconciliation to error details if facility id found") - void shouldAddStockReconciliationToErrorDetailsIfFacilityIdFound() { - StockReconciliationBulkRequest request = StockReconciliationBulkRequestTestBuilder.builder() - .withStock().withRequestInfo().build(); - - mockSomeResponse(); - - Map> errorDetailsMap = srFacilityIdValidator.validate(request); - assertEquals(errorDetailsMap.size(), 0); - } -} diff --git a/health-services/stock/src/test/java/org/egov/stock/validator/ReferenceIdValidatorTest.java b/health-services/stock/src/test/java/org/egov/stock/validator/ReferenceIdValidatorTest.java index 096a1ffd9e6..d1a19f6df06 100644 --- a/health-services/stock/src/test/java/org/egov/stock/validator/ReferenceIdValidatorTest.java +++ b/health-services/stock/src/test/java/org/egov/stock/validator/ReferenceIdValidatorTest.java @@ -1,6 +1,16 @@ package org.egov.stock.validator; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import org.assertj.core.util.Arrays; import org.egov.common.contract.request.RequestInfo; import org.egov.common.models.Error; import org.egov.common.models.stock.Stock; @@ -19,14 +29,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - @ExtendWith(MockitoExtension.class) class ReferenceIdValidatorTest { @@ -43,14 +45,18 @@ private void mockEmptyResponse() { when(facilityService.validateProjectFacilityMappings(any(List.class), any(String.class), any(Map.class), - any(RequestInfo.class))).thenReturn(Collections.emptyList()); + any(RequestInfo.class))).thenReturn(Collections.emptyMap()); } private void mockSomeResponse() { + + List facilityIds = new ArrayList<>(); + facilityIds.add("sender-id"); + when(facilityService.validateProjectFacilityMappings(any(List.class), any(String.class), any(Map.class), - any(RequestInfo.class))).thenReturn(Collections.singletonList("facility-id||reference-id")); + any(RequestInfo.class))).thenReturn(Collections.singletonMap("reference-id", facilityIds)); } @Test diff --git a/health-services/stock/src/test/java/org/egov/stock/validator/TransactingPartyIdValidatorTest.java b/health-services/stock/src/test/java/org/egov/stock/validator/TransactingPartyIdValidatorTest.java deleted file mode 100644 index 0eda35fe11a..00000000000 --- a/health-services/stock/src/test/java/org/egov/stock/validator/TransactingPartyIdValidatorTest.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.egov.stock.validator; - - -import org.egov.common.contract.request.RequestInfo; -import org.egov.common.models.Error; -import org.egov.common.models.stock.Stock; -import org.egov.common.models.stock.StockBulkRequest; -import org.egov.stock.helper.StockBulkRequestTestBuilder; -import org.egov.stock.service.FacilityService; -import org.egov.stock.validator.stock.STransactingPartyIdValidator; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -class TransactingPartyIdValidatorTest { - - @InjectMocks - private STransactingPartyIdValidator sTransactingPartyIdValidator; - - @Mock - private FacilityService facilityService; - - private void mockEmptyResponse() { - when(facilityService.validateFacilityIds(any(List.class), - any(List.class), - any(String.class), - any(Map.class), - any(RequestInfo.class))).thenReturn(Collections.emptyList()); - } - - private void mockSomeResponse() { - when(facilityService.validateFacilityIds(any(List.class), - any(List.class), - any(String.class), - any(Map.class), - any(RequestInfo.class))).thenReturn(Collections.singletonList("transaction-party-id")); - } - - @Test - @DisplayName("should add stock to error details if transacting party id not found") - void shouldAddStockToErrorDetailsIfTransactingPartyIdNotFound() { - StockBulkRequest request = StockBulkRequestTestBuilder.builder().withStock().withRequestInfo().build(); - - mockEmptyResponse(); - - Map> errorDetailsMap = sTransactingPartyIdValidator.validate(request); - assertEquals(errorDetailsMap.size(), 1); - } - - @Test - @DisplayName("should not add stock to error details if transacting party id found") - void shouldAddStockToErrorDetailsIfTransactingPartyIdFound() { - StockBulkRequest request = StockBulkRequestTestBuilder.builder().withStock().withRequestInfo().build(); - - mockSomeResponse(); - - Map> errorDetailsMap = sTransactingPartyIdValidator.validate(request); - assertEquals(errorDetailsMap.size(), 0); - } -} From 1efcba9bb91798769233ea4e219164f5c373bace Mon Sep 17 00:00:00 2001 From: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Date: Thu, 5 Oct 2023 18:42:17 +0530 Subject: [PATCH 181/283] stock user service fix --- .../validator/stock/StocktransferPartiesValidator.java | 2 ++ .../stock/src/main/resources/application.properties | 8 +++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/StocktransferPartiesValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/StocktransferPartiesValidator.java index c4014007d84..10ee33cf1f1 100644 --- a/health-services/stock/src/main/java/org/egov/stock/validator/stock/StocktransferPartiesValidator.java +++ b/health-services/stock/src/main/java/org/egov/stock/validator/stock/StocktransferPartiesValidator.java @@ -14,6 +14,7 @@ import org.egov.common.service.UserService; import org.egov.common.validator.Validator; import org.egov.stock.service.FacilityService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -28,6 +29,7 @@ public class StocktransferPartiesValidator implements Validator Date: Thu, 5 Oct 2023 19:12:29 +0530 Subject: [PATCH 182/283] stock migration --- .../V20231005182626__alter_stock_add_transaction_parties.sql | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 health-services/stock/src/main/resources/db/migration/main/V20231005182626__alter_stock_add_transaction_parties.sql diff --git a/health-services/stock/src/main/resources/db/migration/main/V20231005182626__alter_stock_add_transaction_parties.sql b/health-services/stock/src/main/resources/db/migration/main/V20231005182626__alter_stock_add_transaction_parties.sql new file mode 100644 index 00000000000..e8794b86346 --- /dev/null +++ b/health-services/stock/src/main/resources/db/migration/main/V20231005182626__alter_stock_add_transaction_parties.sql @@ -0,0 +1,4 @@ +ALTER TABLE STOCK ADD COLUMN IF NOT EXISTS senderType character varying(128); +ALTER TABLE STOCK ADD COLUMN IF NOT EXISTS receiverType character varying(128); +ALTER TABLE STOCK ADD COLUMN IF NOT EXISTS senderid character varying(128); +ALTER TABLE STOCK ADD COLUMN IF NOT EXISTS receiverid character varying(128); From e818dc416833e8e54deda694f3bf4e4d301d24b7 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Thu, 5 Oct 2023 19:18:18 +0530 Subject: [PATCH 183/283] HLM-3376,HLM-3069: updated the api spec contract for referralmanagement --- .../contracts/referral-management.yml | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/health-api-specs/contracts/referral-management.yml b/docs/health-api-specs/contracts/referral-management.yml index 7ca980bafed..33f241861f7 100644 --- a/docs/health-api-specs/contracts/referral-management.yml +++ b/docs/health-api-specs/contracts/referral-management.yml @@ -10,7 +10,7 @@ schemes: x-common-path: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-0-0.yml paths: - /referral-management/side-effect/v1/_create: + /referralmanagement/side-effect/v1/_create: post: summary: >- Create side effect for the project @@ -36,7 +36,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/side-effect/v1/bulk/_create: + /referralmanagement/side-effect/v1/bulk/_create: post: summary: >- Create side effects for the project in bulk @@ -62,7 +62,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/side-effect/v1/_update: + /referralmanagement/side-effect/v1/_update: post: summary: >- Side Effect Request @@ -88,7 +88,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/side-effect/v1/bulk/_update: + /referralmanagement/side-effect/v1/bulk/_update: post: summary: >- Side Effect Request in bulk for a project @@ -114,7 +114,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/side-effect/v1/_delete: + /referralmanagement/side-effect/v1/_delete: post: summary: >- Soft delete Side Effect for a project @@ -140,7 +140,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/side-effect/v1/bulk/_delete: + /referralmanagement/side-effect/v1/bulk/_delete: post: summary: >- Soft delete Side Effects for a project @@ -166,7 +166,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/side-effect/v1/_search: + /referralmanagement/side-effect/v1/_search: post: summary: >- Search Side Effect for Project @@ -197,7 +197,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/v1/_create: + /referralmanagement/v1/_create: post: summary: >- Create referral for the project beneficiary @@ -223,7 +223,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/v1/bulk/_create: + /referralmanagement/v1/bulk/_create: post: summary: >- Create referrals for the project beneficiary in bulk @@ -249,7 +249,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/v1/_update: + /referralmanagement/v1/_update: post: summary: >- Referral Request @@ -275,7 +275,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/v1/bulk/_update: + /referralmanagement/v1/bulk/_update: post: summary: >- Referral Request in bulk for a project beneficiary @@ -301,7 +301,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/v1/_delete: + /referralmanagement/v1/_delete: post: summary: >- Soft delete Referral for a project beneficiary @@ -327,7 +327,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/v1/bulk/_delete: + /referralmanagement/v1/bulk/_delete: post: summary: >- Soft delete Referrals for a project beneficiary @@ -353,7 +353,7 @@ paths: $ref: >- https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - /referral-management/v1/_search: + /referralmanagement/v1/_search: post: summary: >- Search Referral for Project From 710b2751a4d4162df72546ed42379ea2c9d49834 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 9 Oct 2023 13:44:50 +0530 Subject: [PATCH 184/283] HLM-3092 : changes as per code review comments --- .../repository/HouseholdRepository.java | 18 ++++++++++--- .../household/web/models/HouseholdSearch.java | 3 +++ .../repository/IndividualRepository.java | 25 +++++++++++++------ .../web/models/IndividualSearch.java | 10 ++++++++ 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java index ae45bcb00f8..b023481a1f4 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java +++ b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java @@ -29,6 +29,8 @@ @Slf4j public class HouseholdRepository extends GenericRepository { + private final String searchCriteriaWaypointQuery = "WITH cte_search_criteria_waypoint(s_latitude, s_longitude) AS (VALUES(:s_latitude, :s_longitude))\n"; + private final String calculateDistanceQuery = "( 6371.4 * acos (LEAST (GREATEST (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) ) + sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), -1), 1) ) ) AS distance "; @Autowired protected HouseholdRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, @@ -89,10 +91,20 @@ public List find(HouseholdSearch searchObject, Integer limit, Integer return this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); } + /** + * @param searchObject + * @param limit + * @param offset + * @param tenantId + * @param includeDeleted + * @return + * @throws QueryBuilderException + * + * Fetch all the household which falls under the radius provided using longitude and latitude provided. + */ public List findByRadius(HouseholdSearch searchObject, Integer limit, Integer offset, String tenantId, Boolean includeDeleted) throws QueryBuilderException { - String query = "WITH cte_search_criteria_waypoint(s_latitude, s_longitude) AS (VALUES(:s_latitude, :s_longitude))\n" + - "SELECT * FROM (SELECT h.*, a.*, ( 6371.4 * acos (LEAST (GREATEST (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )\n" + - "+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), -1), 1) ) ) AS distance \n" + + String query = searchCriteriaWaypointQuery + + "SELECT * FROM (SELECT h.*, a.*, " + calculateDistanceQuery + " \n" + "FROM public.household h LEFT JOIN public.address a ON h.addressid = a.id AND h.tenantid = a.tenantid, cte_search_criteria_waypoint cte_scw "; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); diff --git a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearch.java b/health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearch.java index b946b1a8d5c..96b8e529b4a 100644 --- a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearch.java +++ b/health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearch.java @@ -54,6 +54,9 @@ public class HouseholdSearch { @DecimalMax("180") private Double longitude = null; + /* + * @value unit of measurement in Kilometer + * */ @Exclude @JsonProperty("searchRadius") @DecimalMin("0") diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index ac752e3c66f..f99b093da37 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -38,6 +38,9 @@ @Slf4j public class IndividualRepository extends GenericRepository { + private final String cteQuery = "WITH cte_search_criteria_waypoint(s_latitude, s_longitude) AS (VALUES(:s_latitude, :s_longitude))"; + private final String calculateDistanceQuery = "( 6371.4 * acos ( LEAST ( GREATEST (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), -1), 1) ) ) AS distance "; + protected IndividualRepository(@Qualifier("individualProducer") Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, RedisTemplate redisTemplate, @@ -117,9 +120,17 @@ public List find(IndividualSearch searchObject, Integer limit, Integ } } + /** + * @param query + * @param searchObject + * @param includeDeleted + * @param paramsMap + * @return + * + * Fetch all the household which falls under the radius provided using longitude and latitude provided. + */ public List findByRadius(String query, IndividualSearch searchObject, Boolean includeDeleted, Map paramsMap) { query = query.replace("LIMIT :limit OFFSET :offset", ""); - String cte_query = "WITH cte_search_criteria_waypoint(s_latitude, s_longitude) AS (VALUES(:s_latitude, :s_longitude))"; paramsMap.put("s_latitude", searchObject.getLatitude()); paramsMap.put("s_longitude", searchObject.getLongitude()); if (searchObject.getIdentifier() != null) { @@ -131,9 +142,9 @@ public List findByRadius(String query, IndividualSearch searchObject if (!identifiers.isEmpty()) { query = query.replace(" tenantId=:tenantId ", " tenantId=:tenantId AND id=:individualId "); paramsMap.put("individualId", identifiers.stream().findAny().get().getIndividualId()); - query = cte_query + ", cte_individual AS (" + query + ")"; - query = query + "SELECT * FROM (SELECT cte_i.*, ( 6371.4 * acos ( LEAST ( GREATEST (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )"; - query = query + "+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), -1), 1) ) ) AS distance FROM cte_individual cte_i LEFT JOIN public.individual_address ia ON ia.individualid = cte_i.id LEFT JOIN public.address a ON ia.addressid = a.id , cte_search_criteria_waypoint cte_scw) rt "; + query = cteQuery + ", cte_individual AS (" + query + ")"; + query = query + "SELECT * FROM (SELECT cte_i.*, " + calculateDistanceQuery + +" FROM cte_individual cte_i LEFT JOIN public.individual_address ia ON ia.individualid = cte_i.id LEFT JOIN public.address a ON ia.addressid = a.id , cte_search_criteria_waypoint cte_scw) rt "; if(searchObject.getSearchRadius() != null) { query = query + " WHERE rt.distance < :distance "; } @@ -156,9 +167,9 @@ public List findByRadius(String query, IndividualSearch searchObject return individuals; } } else { - query = cte_query + ", cte_individual AS (" + query + ")"; - query = query + "SELECT * FROM (SELECT cte_i.*, ( 6371.4 * acos ( LEAST ( GREATEST (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )"; - query = query + "+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), -1), 1) ) ) AS distance FROM cte_individual cte_i LEFT JOIN public.individual_address ia ON ia.individualid = cte_i.id LEFT JOIN public.address a ON ia.addressid = a.id , cte_search_criteria_waypoint cte_scw) rt "; + query = cteQuery + ", cte_individual AS (" + query + ")"; + query = query + "SELECT * FROM (SELECT cte_i.*, "+ calculateDistanceQuery + +" FROM cte_individual cte_i LEFT JOIN public.individual_address ia ON ia.individualid = cte_i.id LEFT JOIN public.address a ON ia.addressid = a.id , cte_search_criteria_waypoint cte_scw) rt "; if(searchObject.getSearchRadius() != null) { query = query + " WHERE rt.distance < :distance "; } diff --git a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java b/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java index c58a72997f9..397b60304ce 100644 --- a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java +++ b/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java @@ -15,6 +15,8 @@ import org.springframework.validation.annotation.Validated; import javax.validation.Valid; +import javax.validation.constraints.DecimalMax; +import javax.validation.constraints.DecimalMin; import java.math.BigDecimal; import java.util.Date; import java.util.List; @@ -99,14 +101,22 @@ public class IndividualSearch { @Exclude @JsonProperty("latitude") + @DecimalMin("-90") + @DecimalMax("90") private Double latitude; @Exclude @JsonProperty("longitude") + @DecimalMin("-180") + @DecimalMax("180") private Double longitude; + /* + * @value unit of measurement in Kilometer + * */ @Exclude @JsonProperty("searchRadius") + @DecimalMin("0") private Double searchRadius; } From 3567fde0d855d6416f0444205a879cb0eb06c7c7 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 9 Oct 2023 17:25:16 +0530 Subject: [PATCH 185/283] HLM-3092: added collectionutils isempty check --- .../org/egov/individual/repository/IndividualRepository.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index f99b093da37..13f64853a9c 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -20,6 +20,7 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; import java.lang.reflect.Method; @@ -139,7 +140,7 @@ public List findByRadius(String query, IndividualSearch searchObject identifierParamMap.put("isDeleted", includeDeleted); List identifiers = this.namedParameterJdbcTemplate .query(identifierQuery, identifierParamMap, new IdentifierRowMapper()); - if (!identifiers.isEmpty()) { + if (CollectionUtils.isEmpty(identifiers)) { query = query.replace(" tenantId=:tenantId ", " tenantId=:tenantId AND id=:individualId "); paramsMap.put("individualId", identifiers.stream().findAny().get().getIndividualId()); query = cteQuery + ", cte_individual AS (" + query + ")"; From d24231cb57c05ec0257ee7e73b29683d46343794 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 9 Oct 2023 17:33:11 +0530 Subject: [PATCH 186/283] HLM-3092: updated HouseholdRepository.java and IndividualRepository.java as per review comments --- .../org/egov/household/repository/HouseholdRepository.java | 4 ++-- .../egov/individual/repository/IndividualRepository.java | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java index b023481a1f4..b23a6df9c18 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java +++ b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java @@ -30,7 +30,7 @@ public class HouseholdRepository extends GenericRepository { private final String searchCriteriaWaypointQuery = "WITH cte_search_criteria_waypoint(s_latitude, s_longitude) AS (VALUES(:s_latitude, :s_longitude))\n"; - private final String calculateDistanceQuery = "( 6371.4 * acos (LEAST (GREATEST (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) ) + sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), -1), 1) ) ) AS distance "; + private final String calculateDistanceFromTwoWaypointsFormulaQuery = "( 6371.4 * acos (LEAST (GREATEST (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) ) + sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), -1), 1) ) ) AS distance "; @Autowired protected HouseholdRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, @@ -104,7 +104,7 @@ public List find(HouseholdSearch searchObject, Integer limit, Integer */ public List findByRadius(HouseholdSearch searchObject, Integer limit, Integer offset, String tenantId, Boolean includeDeleted) throws QueryBuilderException { String query = searchCriteriaWaypointQuery + - "SELECT * FROM (SELECT h.*, a.*, " + calculateDistanceQuery + " \n" + + "SELECT * FROM (SELECT h.*, a.*, " + calculateDistanceFromTwoWaypointsFormulaQuery + " \n" + "FROM public.household h LEFT JOIN public.address a ON h.addressid = a.id AND h.tenantid = a.tenantid, cte_search_criteria_waypoint cte_scw "; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index 13f64853a9c..4362e1f1811 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -40,7 +40,7 @@ public class IndividualRepository extends GenericRepository { private final String cteQuery = "WITH cte_search_criteria_waypoint(s_latitude, s_longitude) AS (VALUES(:s_latitude, :s_longitude))"; - private final String calculateDistanceQuery = "( 6371.4 * acos ( LEAST ( GREATEST (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), -1), 1) ) ) AS distance "; + private final String calculateDistanceFromTwoWaypointsFormulaQuery = "( 6371.4 * acos ( LEAST ( GREATEST (cos ( radians(cte_scw.s_latitude) ) * cos( radians(a.latitude) ) * cos( radians(a.longitude) - radians(cte_scw.s_longitude) )+ sin ( radians(cte_scw.s_latitude) ) * sin( radians(a.latitude) ), -1), 1) ) ) AS distance "; protected IndividualRepository(@Qualifier("individualProducer") Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, @@ -144,7 +144,7 @@ public List findByRadius(String query, IndividualSearch searchObject query = query.replace(" tenantId=:tenantId ", " tenantId=:tenantId AND id=:individualId "); paramsMap.put("individualId", identifiers.stream().findAny().get().getIndividualId()); query = cteQuery + ", cte_individual AS (" + query + ")"; - query = query + "SELECT * FROM (SELECT cte_i.*, " + calculateDistanceQuery + query = query + "SELECT * FROM (SELECT cte_i.*, " + calculateDistanceFromTwoWaypointsFormulaQuery +" FROM cte_individual cte_i LEFT JOIN public.individual_address ia ON ia.individualid = cte_i.id LEFT JOIN public.address a ON ia.addressid = a.id , cte_search_criteria_waypoint cte_scw) rt "; if(searchObject.getSearchRadius() != null) { query = query + " WHERE rt.distance < :distance "; @@ -169,7 +169,7 @@ public List findByRadius(String query, IndividualSearch searchObject } } else { query = cteQuery + ", cte_individual AS (" + query + ")"; - query = query + "SELECT * FROM (SELECT cte_i.*, "+ calculateDistanceQuery + query = query + "SELECT * FROM (SELECT cte_i.*, "+ calculateDistanceFromTwoWaypointsFormulaQuery +" FROM cte_individual cte_i LEFT JOIN public.individual_address ia ON ia.individualid = cte_i.id LEFT JOIN public.address a ON ia.addressid = a.id , cte_search_criteria_waypoint cte_scw) rt "; if(searchObject.getSearchRadius() != null) { query = query + " WHERE rt.distance < :distance "; From 81e2fe7e1856cb21a64b0fd4c26f34656d37b260 Mon Sep 17 00:00:00 2001 From: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Date: Thu, 12 Oct 2023 16:37:14 +0530 Subject: [PATCH 187/283] staff id fix --- .../egov/stock/service/FacilityService.java | 4 +++ .../org/egov/stock/util/ValidatorUtil.java | 32 ++++++++++++------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java b/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java index 4a19ab8d32d..7cc5db2e6c7 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java @@ -29,6 +29,7 @@ import org.egov.common.models.stock.StockReconciliation; import org.egov.stock.config.StockConfiguration; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; import lombok.extern.slf4j.Slf4j; @@ -51,6 +52,9 @@ public List validateFacilityIds(List entityIds, Map> errorDetailsMap, RequestInfo requestInfo) { + if (CollectionUtils.isEmpty(entityIds)) + return Collections.emptyList(); + FacilitySearchRequest facilitySearchRequest = FacilitySearchRequest.builder() .facility(FacilitySearch.builder().id(entityIds).build()) .requestInfo(requestInfo) diff --git a/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java b/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java index 0104a16d12a..b39ad93699d 100644 --- a/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java +++ b/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java @@ -117,25 +117,33 @@ private static Tuple, List> validateAndEnrichInvalidPar enrichFaciltyAndStaffIdsFromStock(validStockEntities, facilityIds, staffIds); // copy all of party identifiers into invalid list - List InvalidStaffIds = new ArrayList<>(staffIds); + List invalidStaffIds = new ArrayList<>(staffIds); List invalidFacilityIds = new ArrayList<>(facilityIds); String tenantId = getTenantId(validStockEntities); // validate and remove valid identifiers from invalidStaffIds - UserSearchRequest userSearchRequest = new UserSearchRequest(); - userSearchRequest.setRequestInfo(requestInfo); - userSearchRequest.setUuid(staffIds); - List validStaffIds = userService.search(userSearchRequest).stream().map(user -> user.getUuid()) - .collect(Collectors.toList()); - InvalidStaffIds.removeAll(validStaffIds); + validateAndEnrichStaffIds(requestInfo, userService, staffIds, invalidStaffIds); // validate and remove valid identifiers from invalidfacilityIds List validFacilityIds = facilityService.validateFacilityIds(facilityIds, (List) validStockEntities, - tenantId, errorDetailsMap, requestInfo); + tenantId, errorDetailsMap, requestInfo); invalidFacilityIds.removeAll(validFacilityIds); - return new Tuple<>(InvalidStaffIds, invalidFacilityIds); + return new Tuple<>(invalidStaffIds, invalidFacilityIds); + } + + private static void validateAndEnrichStaffIds(RequestInfo requestInfo, UserService userService, + List staffIds, List invalidStaffIds) { + if (!CollectionUtils.isEmpty(staffIds)) { + + UserSearchRequest userSearchRequest = new UserSearchRequest(); + userSearchRequest.setRequestInfo(requestInfo); + userSearchRequest.setUuid(staffIds); + List validStaffIds = userService.search(userSearchRequest).stream().map(user -> user.getUuid()) + .collect(Collectors.toList()); + invalidStaffIds.removeAll(validStaffIds); + } } /** @@ -176,7 +184,7 @@ private static void enrichFaciltyAndStaffIdsFromStock(List validStockEnti */ @SuppressWarnings("unchecked") private static void enrichErrorMapFromInvalidPartyIds(Map> errorDetailsMap, - List validStockEntities, List InvalidStaffId, List invalidFacilityIds) { + List validStockEntities, List invalidStaffIds, List invalidFacilityIds) { Class objClass = getObjClass(validStockEntities); Method senderIdMethod = getMethod("getSenderId", objClass); @@ -189,14 +197,14 @@ private static void enrichErrorMapFromInvalidPartyIds(Map> er if ((stock.getSenderType().equalsIgnoreCase(WAREHOUSE) && invalidFacilityIds.contains(senderId)) - || (stock.getSenderType().equalsIgnoreCase(STAFF) && InvalidStaffId.contains(senderId))) { + || (stock.getSenderType().equalsIgnoreCase(STAFF) && invalidStaffIds.contains(senderId))) { getIdForErrorFromMethod(errorDetailsMap, (T) stock, senderIdMethod); } if ((stock.getReceiverType().equalsIgnoreCase(WAREHOUSE) && invalidFacilityIds.contains(recieverId)) - || (stock.getReceiverType().equalsIgnoreCase(STAFF) && InvalidStaffId.contains(recieverId))) { + || (stock.getReceiverType().equalsIgnoreCase(STAFF) && invalidStaffIds.contains(recieverId))) { getIdForErrorFromMethod(errorDetailsMap, (T) stock, recieverIdMethod); } From ff75376f74ec716261cbc45e4eb26e5562d525d8 Mon Sep 17 00:00:00 2001 From: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Date: Thu, 12 Oct 2023 19:24:10 +0530 Subject: [PATCH 188/283] project ampping error --- .../src/main/java/org/egov/stock/service/FacilityService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java b/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java index 7cc5db2e6c7..068a26a99fb 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java @@ -123,7 +123,7 @@ public Map> validateProjectFacilityMappings(List ent ProjectFacilityBulkResponse.class); return response.getProjectFacilities().stream() - .collect(Collectors.groupingBy(projectFacility -> projectFacility.getFacilityId(), + .collect(Collectors.groupingBy(projectFacility -> projectFacility.getProjectId(), Collectors.mapping(projectFacility -> projectFacility.getFacilityId(), Collectors.toList()))); } catch (Exception e) { From c9317763d1aad61e09c00bdd052cc487da173f02 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Thu, 12 Oct 2023 19:42:38 +0530 Subject: [PATCH 189/283] HLM-3073: changes extracted from hlm-3073 feature branch, to be merge to hlm-3372 --- .../project/repository/ProjectRepository.java | 2 +- .../project/service/ProjectTaskService.java | 3 + .../egov/project/util/ProjectConstants.java | 32 ++++- .../project/MultiRoundProjectValidator.java | 89 +++++++++++++ .../task/PtIsFutureTaskAllowedValidator.java | 117 ++++++++++++++++++ .../PtResouceBeneficiaryRefusedValidator.java | 41 ++++++ .../web/models/MultiRoundConstants.java | 98 +++++++++++++++ 7 files changed, 380 insertions(+), 2 deletions(-) create mode 100644 health-services/project/src/main/java/org/egov/project/validator/project/MultiRoundProjectValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/task/PtIsFutureTaskAllowedValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/task/PtResouceBeneficiaryRefusedValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/web/models/MultiRoundConstants.java diff --git a/health-services/project/src/main/java/org/egov/project/repository/ProjectRepository.java b/health-services/project/src/main/java/org/egov/project/repository/ProjectRepository.java index fd1d029bb4e..ec885f723b1 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/ProjectRepository.java +++ b/health-services/project/src/main/java/org/egov/project/repository/ProjectRepository.java @@ -112,7 +112,7 @@ private List getProjectsBasedOnSearchCriteria(List projectsReq } /* Fetch Projects based on Project ids */ - private List getProjectsBasedOnProjectIds(List projectIds, List preparedStmtList) { + public List getProjectsBasedOnProjectIds(List projectIds, List preparedStmtList) { String query = queryBuilder.getProjectSearchQueryBasedOnIds(projectIds, preparedStmtList); List projects = jdbcTemplate.query(query, addressRowMapper, preparedStmtList.toArray()); log.info("Fetched project list based on given Project Ids"); diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java index 90be2dcf45c..cdd9aee0034 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java @@ -24,6 +24,7 @@ import org.egov.project.validator.task.PtProductVariantIdValidator; import org.egov.project.validator.task.PtProjectBeneficiaryIdValidator; import org.egov.project.validator.task.PtProjectIdValidator; +import org.egov.project.validator.task.PtResouceBeneficiaryRefusedValidator; import org.egov.project.validator.task.PtRowVersionValidator; import org.egov.project.validator.task.PtUniqueEntityValidator; import org.egov.project.validator.task.PtUniqueSubEntityValidator; @@ -69,11 +70,13 @@ public class ProjectTaskService { private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(PtProjectIdValidator.class) + || validator.getClass().equals(PtResouceBeneficiaryRefusedValidator.class) || validator.getClass().equals(PtProjectBeneficiaryIdValidator.class) || validator.getClass().equals(PtProductVariantIdValidator.class); private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(PtProjectIdValidator.class) + || validator.getClass().equals(PtResouceBeneficiaryRefusedValidator.class) || validator.getClass().equals(PtProjectBeneficiaryIdValidator.class) || validator.getClass().equals(PtProductVariantIdValidator.class) || validator.getClass().equals(PtNullIdValidator.class) diff --git a/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java b/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java index 5d0240ba7e7..a056d1d5442 100644 --- a/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java +++ b/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java @@ -1,5 +1,8 @@ package org.egov.project.util; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + public class ProjectConstants { public static final String MASTER_TENANTS = "tenants"; public static final String MDMS_TENANT_MODULE_NAME = "tenant"; @@ -13,4 +16,31 @@ public class ProjectConstants { public static final String SEMICOLON = ":"; public static final String DOT = "."; public static final String PROJECT_PARENT_HIERARCHY_SEPERATOR = "."; -} + public static final String TASK_NOT_ALLOWED = "TASK_NOT_ALLOWED"; + + public enum TaskStatus { + BENEFICIARY_REFUSED("BENEFICIARY_REFUSED"); + private String value; + + TaskStatus(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static TaskStatus fromValue(String text) { + for (TaskStatus status : TaskStatus.values()) { + if (String.valueOf(status.value).equals(text)) { + return status; + } + } + return null; + } + } + +} \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/validator/project/MultiRoundProjectValidator.java b/health-services/project/src/main/java/org/egov/project/validator/project/MultiRoundProjectValidator.java new file mode 100644 index 00000000000..d221d573818 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/project/MultiRoundProjectValidator.java @@ -0,0 +1,89 @@ +package org.egov.project.validator.project; + +import com.fasterxml.jackson.databind.JsonNode; +import digit.models.coremodels.mdms.MasterDetail; +import digit.models.coremodels.mdms.MdmsCriteria; +import digit.models.coremodels.mdms.MdmsCriteriaReq; +import digit.models.coremodels.mdms.ModuleDetail; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.service.MdmsService; +import org.egov.project.config.ProjectConfiguration; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.egov.project.Constants.INTERNAL_SERVER_ERROR; +import static org.egov.project.Constants.MDMS_RESPONSE; +import static org.egov.project.Constants.PROJECT_TYPES; + +@Component +@Slf4j +public class MultiRoundProjectValidator { + + private final MdmsService mdmsService; + private final ProjectConfiguration projectConfiguration; + + + + public MultiRoundProjectValidator(MdmsService mdmsService, ProjectConfiguration projectConfiguration) { + this.mdmsService = mdmsService; + this.projectConfiguration = projectConfiguration; + } + + public Map getProjectTypes(String tenantId, RequestInfo requestInfo) { + JsonNode response = fetchMdmsResponse(requestInfo, tenantId, PROJECT_TYPES, + projectConfiguration.getMdmsModule()); + return convertToProjectTypeMap(response); + } + + private JsonNode fetchMdmsResponse(RequestInfo requestInfo, String tenantId, String name, + String moduleName) { + MdmsCriteriaReq serviceRegistry = getMdmsRequest(requestInfo, tenantId, name, moduleName); + try { + return mdmsService.fetchConfig(serviceRegistry, JsonNode.class).get(MDMS_RESPONSE); + } catch (Exception e) { + throw new CustomException(INTERNAL_SERVER_ERROR, "Error while fetching MDMS config"); + } + } + + private Map convertToProjectTypeMap(JsonNode jsonNode) { + JsonNode projectTypesNode = jsonNode.get(projectConfiguration.getMdmsModule()).withArray(PROJECT_TYPES); + Map map = new HashMap<>(); + projectTypesNode.forEach(json -> map.put(json.get("id").textValue(), json)); + return map; + } + + private MdmsCriteriaReq getMdmsRequest(RequestInfo requestInfo, String tenantId, String masterName, + String moduleName) { + MasterDetail masterDetail = new MasterDetail(); + masterDetail.setName(masterName); + List masterDetailList = new ArrayList<>(); + masterDetailList.add(masterDetail); + ModuleDetail moduleDetail = new ModuleDetail(); + moduleDetail.setMasterDetails(masterDetailList); + moduleDetail.setModuleName(moduleName); + List moduleDetailList = new ArrayList<>(); + moduleDetailList.add(moduleDetail); + MdmsCriteria mdmsCriteria = new MdmsCriteria(); + mdmsCriteria.setTenantId(tenantId); + mdmsCriteria.setModuleDetails(moduleDetailList); + MdmsCriteriaReq mdmsCriteriaReq = new MdmsCriteriaReq(); + mdmsCriteriaReq.setMdmsCriteria(mdmsCriteria); + mdmsCriteriaReq.setRequestInfo(requestInfo); + return mdmsCriteriaReq; + } + + public Map populateProjectTypeMap(Set tenantIdSet, RequestInfo requestInfo) { + Map projectTypeMap = new HashMap<>(); + for(String tenant : tenantIdSet) { + projectTypeMap.putAll(this.getProjectTypes(tenant, requestInfo)); + } + return projectTypeMap; + } +} \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtIsFutureTaskAllowedValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtIsFutureTaskAllowedValidator.java new file mode 100644 index 00000000000..1a21c64b762 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtIsFutureTaskAllowedValidator.java @@ -0,0 +1,117 @@ +package org.egov.project.validator.task; + +import com.fasterxml.jackson.databind.JsonNode; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.models.Error; +import org.egov.common.models.project.Project; +import org.egov.common.models.project.Task; +import org.egov.common.models.project.TaskBulkRequest; +import org.egov.common.models.project.TaskSearch; +import org.egov.common.validator.Validator; +import org.egov.project.repository.ProjectRepository; +import org.egov.project.repository.ProjectTaskRepository; +import org.egov.project.validator.project.MultiRoundProjectValidator; +import org.egov.project.web.models.MultiRoundConstants; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.project.web.models.MultiRoundConstants.TASK_NOT_ALLOWED; + + +@Component +@Order(value = 1) +@Slf4j +public class PtIsFutureTaskAllowedValidator implements Validator { + + private final ProjectRepository projectRepository; + private final ProjectTaskRepository projectTaskRepository; + private final MultiRoundProjectValidator multiRoundProjectValidator; + + @Autowired + public PtIsFutureTaskAllowedValidator(ProjectRepository projectRepository, ProjectTaskRepository projectTaskRepository, MultiRoundProjectValidator multiRoundProjectValidator) { + this.projectRepository = projectRepository; + this.projectTaskRepository = projectTaskRepository; + this.multiRoundProjectValidator = multiRoundProjectValidator; + } + + @Override + public Map> validate(TaskBulkRequest request) { + log.info("validating for past task"); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getTasks(); + Map> projectIdTasksMap = entities.stream().collect(Collectors.groupingBy(Task::getProjectId)); + if (!projectIdTasksMap.isEmpty()) { + List projectIds = new ArrayList<>(projectIdTasksMap.keySet()); + List projects = projectRepository.getProjectsBasedOnProjectIds(projectIds, new ArrayList<>()); + Map projectMap = new HashMap<>(); + Map> tenantIdProjectsMap = new HashMap<>(); + Map projectIdProjectTypeIdMap = new HashMap<>(); + projects.forEach(project -> { + projectMap.put(project.getId(), project); + tenantIdProjectsMap + .computeIfAbsent(project.getTenantId(), k -> new ArrayList<>()) + .add(project); + projectIdProjectTypeIdMap.put(project.getId(), project.getProjectTypeId()); + }); + + // Fetch project type from mdms for each project. + Map projectTypeJsonMap = multiRoundProjectValidator.populateProjectTypeMap(tenantIdProjectsMap.keySet(), request.getRequestInfo()); + + // Group tasks by project beneficiary client reference ID + Map> projectBeneficiaryClientReferenceIdTaskMap = entities.stream().collect(Collectors.groupingBy(Task::getProjectBeneficiaryClientReferenceId)); + projectBeneficiaryClientReferenceIdTaskMap.forEach((projectBeneficiaryClientReferenceId, tasks) -> { + JsonNode projectTypeJson = projectTypeJsonMap.get(projectIdProjectTypeIdMap.get(tasks.get(0).getProjectId())); + if (isProjectTypeMatching(projectTypeJson, "multiround")) { + verifyPastTask(projectBeneficiaryClientReferenceId, tasks.get(0).getTenantId(), tasks, errorDetailsMap); + } + }); + } + return errorDetailsMap; + } + + private boolean isProjectTypeMatching(JsonNode projectTypeJson, String value) { + return projectTypeJson != null && projectTypeJson.get("type") != null && projectTypeJson.get("type").textValue().equalsIgnoreCase(value); + } + + private void verifyPastTask(String projectBeneficiaryClientReferenceId, String tenantId, List taskYetToBePersisted, Map> errorDetailsMap) { + List pastTasks; + try { + pastTasks = projectTaskRepository.find(TaskSearch.builder().projectBeneficiaryClientReferenceId(projectBeneficiaryClientReferenceId).build(), null, 0, tenantId, null, Boolean.FALSE); + } catch (QueryBuilderException e) { + pastTasks = new ArrayList<>(); + } + taskYetToBePersisted.sort(Comparator.comparing(Task::getCreatedDate)); + List tasks = new ArrayList<>(pastTasks); + tasks.addAll(taskYetToBePersisted); + tasks.forEach(task -> { + if(task.getStatus() != null) { + if(!task.getStatus().equals(MultiRoundConstants.Status.BENEFICIARY_REFUSED) && (task.getResources() == null || task.getResources().isEmpty())) { + Error error = Error.builder() + .errorMessage("Task not allowed as resources are missing.") + .errorCode(TASK_NOT_ALLOWED) + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException(TASK_NOT_ALLOWED, "Task not allowed as resources are missing.")).build(); + populateErrorDetails(task, error, errorDetailsMap); + } else if(task.getStatus().equals(MultiRoundConstants.Status.BENEFICIARY_REFUSED) && task.getResources() != null) { + Error error = Error.builder() + .errorMessage("Task not allowed as resources can not be provided when "+MultiRoundConstants.Status.BENEFICIARY_REFUSED) + .errorCode(TASK_NOT_ALLOWED) + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException(TASK_NOT_ALLOWED, "Task not allowed as resources can not be provided when "+MultiRoundConstants.Status.BENEFICIARY_REFUSED)).build(); + populateErrorDetails(task, error, errorDetailsMap); + } + } + }); + } +} \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtResouceBeneficiaryRefusedValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtResouceBeneficiaryRefusedValidator.java new file mode 100644 index 00000000000..71a8c2b13b7 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtResouceBeneficiaryRefusedValidator.java @@ -0,0 +1,41 @@ +package org.egov.project.validator.task; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.Task; +import org.egov.common.models.project.TaskBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.project.util.ProjectConstants; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.project.util.ProjectConstants.TASK_NOT_ALLOWED; + +@Component +@Order(value = 1) +@Slf4j +public class PtResouceBeneficiaryRefusedValidator implements Validator { + public Map> validate(TaskBulkRequest request) { + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getTasks(); + if(!entities.isEmpty()) { + entities.forEach(task -> { + if(task.getStatus() != null && task.getStatus().equals(ProjectConstants.TaskStatus.BENEFICIARY_REFUSED.toString()) && task.getResources() != null) { + Error error = Error.builder() + .errorMessage("Task not allowed as resources can not be provided when "+ProjectConstants.TaskStatus.BENEFICIARY_REFUSED) + .errorCode(TASK_NOT_ALLOWED) + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException(TASK_NOT_ALLOWED, "Task not allowed as resources can not be provided when "+ProjectConstants.TaskStatus.BENEFICIARY_REFUSED)).build(); + populateErrorDetails(task, error, errorDetailsMap); + } + }); + } + return errorDetailsMap; + } +} \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/web/models/MultiRoundConstants.java b/health-services/project/src/main/java/org/egov/project/web/models/MultiRoundConstants.java new file mode 100644 index 00000000000..eefc053643c --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/web/models/MultiRoundConstants.java @@ -0,0 +1,98 @@ +package org.egov.project.web.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Gets or Sets multi round task status + */ +@JsonIgnoreProperties(ignoreUnknown = true) +public class MultiRoundConstants { + public enum Status { + DELIVERED("DELIVERED"), + NOT_DELIVERED("NOT_DELIVERED"), + BENEFICIARY_REFUSED("BENEFICIARY_REFUSED"), + PARTIALLY_DELIVERED("PARTIALLY_DELIVERED"); + + private String value; + + Status(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static Status fromValue(String text) { + for (Status b : Status.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + + public enum DeliveryType { + DIRECT("DIRECT"), + INDIRECT("INDIRECT"); + + private String value; + + DeliveryType(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static DeliveryType fromValue(String text) { + for (DeliveryType b : DeliveryType.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + + } + + public enum DateType { + DATE_OF_DELIVERY("DateOfDelivery"), + DATE_OF_ADMINISTRATION("DateOfAdministration"), + DATE_OF_VERIFICATION("DateOfVerification"); + + private String value; + + DateType(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static DateType fromValue(String text) { + for (DateType b : DateType.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + + public static final String TASK_NOT_ALLOWED = "TASK_NOT_ALLOWED"; +} \ No newline at end of file From a1b3e6ee2d27b1b7c2a70eedef406f0b96f337c0 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Thu, 12 Oct 2023 19:51:04 +0530 Subject: [PATCH 190/283] HLM-3073: removed non required classes --- .../project/MultiRoundProjectValidator.java | 89 ------------- .../task/PtIsFutureTaskAllowedValidator.java | 117 ------------------ .../web/models/MultiRoundConstants.java | 98 --------------- 3 files changed, 304 deletions(-) delete mode 100644 health-services/project/src/main/java/org/egov/project/validator/project/MultiRoundProjectValidator.java delete mode 100644 health-services/project/src/main/java/org/egov/project/validator/task/PtIsFutureTaskAllowedValidator.java delete mode 100644 health-services/project/src/main/java/org/egov/project/web/models/MultiRoundConstants.java diff --git a/health-services/project/src/main/java/org/egov/project/validator/project/MultiRoundProjectValidator.java b/health-services/project/src/main/java/org/egov/project/validator/project/MultiRoundProjectValidator.java deleted file mode 100644 index d221d573818..00000000000 --- a/health-services/project/src/main/java/org/egov/project/validator/project/MultiRoundProjectValidator.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.egov.project.validator.project; - -import com.fasterxml.jackson.databind.JsonNode; -import digit.models.coremodels.mdms.MasterDetail; -import digit.models.coremodels.mdms.MdmsCriteria; -import digit.models.coremodels.mdms.MdmsCriteriaReq; -import digit.models.coremodels.mdms.ModuleDetail; -import lombok.extern.slf4j.Slf4j; -import org.egov.common.contract.request.RequestInfo; -import org.egov.common.service.MdmsService; -import org.egov.project.config.ProjectConfiguration; -import org.egov.tracer.model.CustomException; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import static org.egov.project.Constants.INTERNAL_SERVER_ERROR; -import static org.egov.project.Constants.MDMS_RESPONSE; -import static org.egov.project.Constants.PROJECT_TYPES; - -@Component -@Slf4j -public class MultiRoundProjectValidator { - - private final MdmsService mdmsService; - private final ProjectConfiguration projectConfiguration; - - - - public MultiRoundProjectValidator(MdmsService mdmsService, ProjectConfiguration projectConfiguration) { - this.mdmsService = mdmsService; - this.projectConfiguration = projectConfiguration; - } - - public Map getProjectTypes(String tenantId, RequestInfo requestInfo) { - JsonNode response = fetchMdmsResponse(requestInfo, tenantId, PROJECT_TYPES, - projectConfiguration.getMdmsModule()); - return convertToProjectTypeMap(response); - } - - private JsonNode fetchMdmsResponse(RequestInfo requestInfo, String tenantId, String name, - String moduleName) { - MdmsCriteriaReq serviceRegistry = getMdmsRequest(requestInfo, tenantId, name, moduleName); - try { - return mdmsService.fetchConfig(serviceRegistry, JsonNode.class).get(MDMS_RESPONSE); - } catch (Exception e) { - throw new CustomException(INTERNAL_SERVER_ERROR, "Error while fetching MDMS config"); - } - } - - private Map convertToProjectTypeMap(JsonNode jsonNode) { - JsonNode projectTypesNode = jsonNode.get(projectConfiguration.getMdmsModule()).withArray(PROJECT_TYPES); - Map map = new HashMap<>(); - projectTypesNode.forEach(json -> map.put(json.get("id").textValue(), json)); - return map; - } - - private MdmsCriteriaReq getMdmsRequest(RequestInfo requestInfo, String tenantId, String masterName, - String moduleName) { - MasterDetail masterDetail = new MasterDetail(); - masterDetail.setName(masterName); - List masterDetailList = new ArrayList<>(); - masterDetailList.add(masterDetail); - ModuleDetail moduleDetail = new ModuleDetail(); - moduleDetail.setMasterDetails(masterDetailList); - moduleDetail.setModuleName(moduleName); - List moduleDetailList = new ArrayList<>(); - moduleDetailList.add(moduleDetail); - MdmsCriteria mdmsCriteria = new MdmsCriteria(); - mdmsCriteria.setTenantId(tenantId); - mdmsCriteria.setModuleDetails(moduleDetailList); - MdmsCriteriaReq mdmsCriteriaReq = new MdmsCriteriaReq(); - mdmsCriteriaReq.setMdmsCriteria(mdmsCriteria); - mdmsCriteriaReq.setRequestInfo(requestInfo); - return mdmsCriteriaReq; - } - - public Map populateProjectTypeMap(Set tenantIdSet, RequestInfo requestInfo) { - Map projectTypeMap = new HashMap<>(); - for(String tenant : tenantIdSet) { - projectTypeMap.putAll(this.getProjectTypes(tenant, requestInfo)); - } - return projectTypeMap; - } -} \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtIsFutureTaskAllowedValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtIsFutureTaskAllowedValidator.java deleted file mode 100644 index 1a21c64b762..00000000000 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtIsFutureTaskAllowedValidator.java +++ /dev/null @@ -1,117 +0,0 @@ -package org.egov.project.validator.task; - -import com.fasterxml.jackson.databind.JsonNode; -import lombok.extern.slf4j.Slf4j; -import org.egov.common.data.query.exception.QueryBuilderException; -import org.egov.common.models.Error; -import org.egov.common.models.project.Project; -import org.egov.common.models.project.Task; -import org.egov.common.models.project.TaskBulkRequest; -import org.egov.common.models.project.TaskSearch; -import org.egov.common.validator.Validator; -import org.egov.project.repository.ProjectRepository; -import org.egov.project.repository.ProjectTaskRepository; -import org.egov.project.validator.project.MultiRoundProjectValidator; -import org.egov.project.web.models.MultiRoundConstants; -import org.egov.tracer.model.CustomException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.project.web.models.MultiRoundConstants.TASK_NOT_ALLOWED; - - -@Component -@Order(value = 1) -@Slf4j -public class PtIsFutureTaskAllowedValidator implements Validator { - - private final ProjectRepository projectRepository; - private final ProjectTaskRepository projectTaskRepository; - private final MultiRoundProjectValidator multiRoundProjectValidator; - - @Autowired - public PtIsFutureTaskAllowedValidator(ProjectRepository projectRepository, ProjectTaskRepository projectTaskRepository, MultiRoundProjectValidator multiRoundProjectValidator) { - this.projectRepository = projectRepository; - this.projectTaskRepository = projectTaskRepository; - this.multiRoundProjectValidator = multiRoundProjectValidator; - } - - @Override - public Map> validate(TaskBulkRequest request) { - log.info("validating for past task"); - Map> errorDetailsMap = new HashMap<>(); - List entities = request.getTasks(); - Map> projectIdTasksMap = entities.stream().collect(Collectors.groupingBy(Task::getProjectId)); - if (!projectIdTasksMap.isEmpty()) { - List projectIds = new ArrayList<>(projectIdTasksMap.keySet()); - List projects = projectRepository.getProjectsBasedOnProjectIds(projectIds, new ArrayList<>()); - Map projectMap = new HashMap<>(); - Map> tenantIdProjectsMap = new HashMap<>(); - Map projectIdProjectTypeIdMap = new HashMap<>(); - projects.forEach(project -> { - projectMap.put(project.getId(), project); - tenantIdProjectsMap - .computeIfAbsent(project.getTenantId(), k -> new ArrayList<>()) - .add(project); - projectIdProjectTypeIdMap.put(project.getId(), project.getProjectTypeId()); - }); - - // Fetch project type from mdms for each project. - Map projectTypeJsonMap = multiRoundProjectValidator.populateProjectTypeMap(tenantIdProjectsMap.keySet(), request.getRequestInfo()); - - // Group tasks by project beneficiary client reference ID - Map> projectBeneficiaryClientReferenceIdTaskMap = entities.stream().collect(Collectors.groupingBy(Task::getProjectBeneficiaryClientReferenceId)); - projectBeneficiaryClientReferenceIdTaskMap.forEach((projectBeneficiaryClientReferenceId, tasks) -> { - JsonNode projectTypeJson = projectTypeJsonMap.get(projectIdProjectTypeIdMap.get(tasks.get(0).getProjectId())); - if (isProjectTypeMatching(projectTypeJson, "multiround")) { - verifyPastTask(projectBeneficiaryClientReferenceId, tasks.get(0).getTenantId(), tasks, errorDetailsMap); - } - }); - } - return errorDetailsMap; - } - - private boolean isProjectTypeMatching(JsonNode projectTypeJson, String value) { - return projectTypeJson != null && projectTypeJson.get("type") != null && projectTypeJson.get("type").textValue().equalsIgnoreCase(value); - } - - private void verifyPastTask(String projectBeneficiaryClientReferenceId, String tenantId, List taskYetToBePersisted, Map> errorDetailsMap) { - List pastTasks; - try { - pastTasks = projectTaskRepository.find(TaskSearch.builder().projectBeneficiaryClientReferenceId(projectBeneficiaryClientReferenceId).build(), null, 0, tenantId, null, Boolean.FALSE); - } catch (QueryBuilderException e) { - pastTasks = new ArrayList<>(); - } - taskYetToBePersisted.sort(Comparator.comparing(Task::getCreatedDate)); - List tasks = new ArrayList<>(pastTasks); - tasks.addAll(taskYetToBePersisted); - tasks.forEach(task -> { - if(task.getStatus() != null) { - if(!task.getStatus().equals(MultiRoundConstants.Status.BENEFICIARY_REFUSED) && (task.getResources() == null || task.getResources().isEmpty())) { - Error error = Error.builder() - .errorMessage("Task not allowed as resources are missing.") - .errorCode(TASK_NOT_ALLOWED) - .type(Error.ErrorType.NON_RECOVERABLE) - .exception(new CustomException(TASK_NOT_ALLOWED, "Task not allowed as resources are missing.")).build(); - populateErrorDetails(task, error, errorDetailsMap); - } else if(task.getStatus().equals(MultiRoundConstants.Status.BENEFICIARY_REFUSED) && task.getResources() != null) { - Error error = Error.builder() - .errorMessage("Task not allowed as resources can not be provided when "+MultiRoundConstants.Status.BENEFICIARY_REFUSED) - .errorCode(TASK_NOT_ALLOWED) - .type(Error.ErrorType.NON_RECOVERABLE) - .exception(new CustomException(TASK_NOT_ALLOWED, "Task not allowed as resources can not be provided when "+MultiRoundConstants.Status.BENEFICIARY_REFUSED)).build(); - populateErrorDetails(task, error, errorDetailsMap); - } - } - }); - } -} \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/web/models/MultiRoundConstants.java b/health-services/project/src/main/java/org/egov/project/web/models/MultiRoundConstants.java deleted file mode 100644 index eefc053643c..00000000000 --- a/health-services/project/src/main/java/org/egov/project/web/models/MultiRoundConstants.java +++ /dev/null @@ -1,98 +0,0 @@ -package org.egov.project.web.models; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonValue; - -/** - * Gets or Sets multi round task status - */ -@JsonIgnoreProperties(ignoreUnknown = true) -public class MultiRoundConstants { - public enum Status { - DELIVERED("DELIVERED"), - NOT_DELIVERED("NOT_DELIVERED"), - BENEFICIARY_REFUSED("BENEFICIARY_REFUSED"), - PARTIALLY_DELIVERED("PARTIALLY_DELIVERED"); - - private String value; - - Status(String value) { - this.value = value; - } - - @Override - @JsonValue - public String toString() { - return String.valueOf(value); - } - - @JsonCreator - public static Status fromValue(String text) { - for (Status b : Status.values()) { - if (String.valueOf(b.value).equals(text)) { - return b; - } - } - return null; - } - } - - public enum DeliveryType { - DIRECT("DIRECT"), - INDIRECT("INDIRECT"); - - private String value; - - DeliveryType(String value) { - this.value = value; - } - - @Override - @JsonValue - public String toString() { - return String.valueOf(value); - } - - @JsonCreator - public static DeliveryType fromValue(String text) { - for (DeliveryType b : DeliveryType.values()) { - if (String.valueOf(b.value).equals(text)) { - return b; - } - } - return null; - } - - } - - public enum DateType { - DATE_OF_DELIVERY("DateOfDelivery"), - DATE_OF_ADMINISTRATION("DateOfAdministration"), - DATE_OF_VERIFICATION("DateOfVerification"); - - private String value; - - DateType(String value) { - this.value = value; - } - - @Override - @JsonValue - public String toString() { - return String.valueOf(value); - } - - @JsonCreator - public static DateType fromValue(String text) { - for (DateType b : DateType.values()) { - if (String.valueOf(b.value).equals(text)) { - return b; - } - } - return null; - } - } - - public static final String TASK_NOT_ALLOWED = "TASK_NOT_ALLOWED"; -} \ No newline at end of file From 902e40a721d9d3c9eabedf756a41244e2eca22a8 Mon Sep 17 00:00:00 2001 From: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Date: Fri, 13 Oct 2023 01:18:52 +0530 Subject: [PATCH 191/283] facility validator skip for staff only exchange --- .../org/egov/common/models/project/ProjectStaff.java | 12 +++++++----- .../stock/validator/stock/SReferenceIdValidator.java | 7 +++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java index f7c0f205af7..18d20c408a4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java @@ -1,19 +1,21 @@ package org.egov.common.models.project; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import org.springframework.validation.annotation.Validated; + import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; + import digit.models.coremodels.AuditDetails; import io.swagger.annotations.ApiModel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; /** * This object defines the mapping of a system staff user to a project for a certain period. diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SReferenceIdValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SReferenceIdValidator.java index 7b791a29031..47a17106727 100644 --- a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SReferenceIdValidator.java +++ b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SReferenceIdValidator.java @@ -39,6 +39,13 @@ public Map> validate(StockBulkRequest request) { .filter(notHavingErrors()) .filter(entity -> PROJECT.equals(entity.getReferenceIdType())) .collect(Collectors.toList()); + + long countOfWareHouseInStock = request.getStock().stream().filter(stock -> + stock.getReceiverType().equalsIgnoreCase("WAREHOUSE") || stock.getSenderType().equalsIgnoreCase("WAREHOUSE") + ).count(); + if(countOfWareHouseInStock == 0) + return errorDetailsMap; + return validateProjectFacilityMappings(request, errorDetailsMap, validEntities, GET_REFERENCE_ID, facilityService); } From 96047eed47ea8d4146a22a4c7e30c78f815fb98c Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 13 Oct 2023 11:16:49 +0530 Subject: [PATCH 192/283] HLM-3073: renamed validator, validating only when project task resource is empty --- .../main/java/org/egov/common/models/project/Task.java | 1 - .../org/egov/project/service/ProjectTaskService.java | 6 +++--- .../java/org/egov/project/util/ProjectConstants.java | 1 + ...edValidator.java => PtIsResouceEmptyValidator.java} | 10 +++++++--- 4 files changed, 11 insertions(+), 7 deletions(-) rename health-services/project/src/main/java/org/egov/project/validator/task/{PtResouceBeneficiaryRefusedValidator.java => PtIsResouceEmptyValidator.java} (75%) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java index fbbc67ffb33..c30b5363e22 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java @@ -56,7 +56,6 @@ public class Task { @JsonProperty("resources") @NotNull @Valid - @Size(min = 1) private List resources = new ArrayList<>(); @JsonProperty("plannedStartDate") diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java index cdd9aee0034..0f76c26f507 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java @@ -24,7 +24,7 @@ import org.egov.project.validator.task.PtProductVariantIdValidator; import org.egov.project.validator.task.PtProjectBeneficiaryIdValidator; import org.egov.project.validator.task.PtProjectIdValidator; -import org.egov.project.validator.task.PtResouceBeneficiaryRefusedValidator; +import org.egov.project.validator.task.PtIsResouceEmptyValidator; import org.egov.project.validator.task.PtRowVersionValidator; import org.egov.project.validator.task.PtUniqueEntityValidator; import org.egov.project.validator.task.PtUniqueSubEntityValidator; @@ -70,13 +70,13 @@ public class ProjectTaskService { private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(PtProjectIdValidator.class) - || validator.getClass().equals(PtResouceBeneficiaryRefusedValidator.class) + || validator.getClass().equals(PtIsResouceEmptyValidator.class) || validator.getClass().equals(PtProjectBeneficiaryIdValidator.class) || validator.getClass().equals(PtProductVariantIdValidator.class); private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(PtProjectIdValidator.class) - || validator.getClass().equals(PtResouceBeneficiaryRefusedValidator.class) + || validator.getClass().equals(PtIsResouceEmptyValidator.class) || validator.getClass().equals(PtProjectBeneficiaryIdValidator.class) || validator.getClass().equals(PtProductVariantIdValidator.class) || validator.getClass().equals(PtNullIdValidator.class) diff --git a/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java b/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java index a056d1d5442..70d52fd790b 100644 --- a/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java +++ b/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java @@ -18,6 +18,7 @@ public class ProjectConstants { public static final String PROJECT_PARENT_HIERARCHY_SEPERATOR = "."; public static final String TASK_NOT_ALLOWED = "TASK_NOT_ALLOWED"; + public static final String TASK_NOT_ALLOWED_ERROR_MESSAGE = "Task not allowed as resources can not be provided when "; public enum TaskStatus { BENEFICIARY_REFUSED("BENEFICIARY_REFUSED"); private String value; diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtResouceBeneficiaryRefusedValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java similarity index 75% rename from health-services/project/src/main/java/org/egov/project/validator/task/PtResouceBeneficiaryRefusedValidator.java rename to health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java index 71a8c2b13b7..3094293dfac 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtResouceBeneficiaryRefusedValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java @@ -9,6 +9,7 @@ import org.egov.tracer.model.CustomException; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; import java.util.HashMap; import java.util.List; @@ -17,18 +18,21 @@ import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.project.util.ProjectConstants.TASK_NOT_ALLOWED; +/** + * To Validate when task resource is empty or null + */ @Component @Order(value = 1) @Slf4j -public class PtResouceBeneficiaryRefusedValidator implements Validator { +public class PtIsResouceEmptyValidator implements Validator { public Map> validate(TaskBulkRequest request) { Map> errorDetailsMap = new HashMap<>(); List entities = request.getTasks(); if(!entities.isEmpty()) { entities.forEach(task -> { - if(task.getStatus() != null && task.getStatus().equals(ProjectConstants.TaskStatus.BENEFICIARY_REFUSED.toString()) && task.getResources() != null) { + if(CollectionUtils.isEmpty(task.getResources()) && ProjectConstants.TaskStatus.BENEFICIARY_REFUSED.toString().equals(task.getStatus())) { Error error = Error.builder() - .errorMessage("Task not allowed as resources can not be provided when "+ProjectConstants.TaskStatus.BENEFICIARY_REFUSED) + .errorMessage(ProjectConstants.TASK_NOT_ALLOWED_ERROR_MESSAGE + ProjectConstants.TaskStatus.BENEFICIARY_REFUSED) .errorCode(TASK_NOT_ALLOWED) .type(Error.ErrorType.NON_RECOVERABLE) .exception(new CustomException(TASK_NOT_ALLOWED, "Task not allowed as resources can not be provided when "+ProjectConstants.TaskStatus.BENEFICIARY_REFUSED)).build(); From 6a7bd41f3d7a6cca020bcaabc0679fd8ab809de9 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 13 Oct 2023 12:19:17 +0530 Subject: [PATCH 193/283] HLM-3073: task model update, removed not null from resources --- .../src/main/java/org/egov/common/models/project/Task.java | 1 - 1 file changed, 1 deletion(-) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java index c30b5363e22..5f6133eff4f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java @@ -54,7 +54,6 @@ public class Task { private String projectBeneficiaryClientReferenceId = null; @JsonProperty("resources") - @NotNull @Valid private List resources = new ArrayList<>(); From b85611e243676ca0e2e871ae0905786b3aeba074 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 13 Oct 2023 12:48:29 +0530 Subject: [PATCH 194/283] HLM-3069: updated side_effect table --- ...20230928120100__side_effect_create_ddl.sql | 18 ----------------- ...20231010120100__side_effect_create_ddl.sql | 20 +++++++++++++++++++ 2 files changed, 20 insertions(+), 18 deletions(-) delete mode 100644 health-services/referralmanagement/src/main/resources/db/migration/main/V20230928120100__side_effect_create_ddl.sql create mode 100644 health-services/referralmanagement/src/main/resources/db/migration/main/V20231010120100__side_effect_create_ddl.sql diff --git a/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928120100__side_effect_create_ddl.sql b/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928120100__side_effect_create_ddl.sql deleted file mode 100644 index 215a06217be..00000000000 --- a/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928120100__side_effect_create_ddl.sql +++ /dev/null @@ -1,18 +0,0 @@ -CREATE TABLE SIDE_EFFECT( - id character varying(64), - clientReferenceId character varying(64) NOT NULL, - tenantId character varying(1000), - taskId character varying(64), - taskClientReferenceId character varying(64) NOT NULL, - symptoms jsonb, - createdBy character varying(64), - createdTime bigint, - lastModifiedBy character varying(64), - lastModifiedTime bigint, - clientCreatedTime bigint, - clientLastModifiedTime bigint, - rowVersion bigint, - isDeleted bool, - CONSTRAINT uk_side_effect PRIMARY KEY (id), - CONSTRAINT uk_side_effect_clientReference_id unique (clientReferenceId) -); \ No newline at end of file diff --git a/health-services/referralmanagement/src/main/resources/db/migration/main/V20231010120100__side_effect_create_ddl.sql b/health-services/referralmanagement/src/main/resources/db/migration/main/V20231010120100__side_effect_create_ddl.sql new file mode 100644 index 00000000000..eb89b827422 --- /dev/null +++ b/health-services/referralmanagement/src/main/resources/db/migration/main/V20231010120100__side_effect_create_ddl.sql @@ -0,0 +1,20 @@ +CREATE TABLE IF NOT EXISTS SIDE_EFFECT( + id character varying(64), + clientReferenceId character varying(64) NOT NULL, + tenantId character varying(1000), + taskId character varying(64), + taskClientReferenceId character varying(64) NOT NULL, + projectBeneficiary character varying(64), + projectBeneficiaryClientReferenceId character varying(64) NOT NULL, + symptoms jsonb, + createdBy character varying(64), + createdTime bigint, + lastModifiedBy character varying(64), + lastModifiedTime bigint, + clientCreatedTime bigint, + clientLastModifiedTime bigint, + rowVersion bigint, + isDeleted bool, + CONSTRAINT uk_side_effect PRIMARY KEY (id), + CONSTRAINT uk_side_effect_clientReference_id unique (clientReferenceId) +); \ No newline at end of file From 41b3572f7f26a09fe101976dacbc99e0e8d42b72 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 13 Oct 2023 13:59:32 +0530 Subject: [PATCH 195/283] HLM-3069: removed not null for projectbeneficiary client reference id --- .../migration/main/V20231010120100__side_effect_create_ddl.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/referralmanagement/src/main/resources/db/migration/main/V20231010120100__side_effect_create_ddl.sql b/health-services/referralmanagement/src/main/resources/db/migration/main/V20231010120100__side_effect_create_ddl.sql index eb89b827422..f42e30eecfd 100644 --- a/health-services/referralmanagement/src/main/resources/db/migration/main/V20231010120100__side_effect_create_ddl.sql +++ b/health-services/referralmanagement/src/main/resources/db/migration/main/V20231010120100__side_effect_create_ddl.sql @@ -5,7 +5,7 @@ CREATE TABLE IF NOT EXISTS SIDE_EFFECT( taskId character varying(64), taskClientReferenceId character varying(64) NOT NULL, projectBeneficiary character varying(64), - projectBeneficiaryClientReferenceId character varying(64) NOT NULL, + projectBeneficiaryClientReferenceId character varying(64), symptoms jsonb, createdBy character varying(64), createdTime bigint, From 3d3dba20b51e3db5befcdedbc5f5a36f069cc836 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 13 Oct 2023 15:03:24 +0530 Subject: [PATCH 196/283] HLM-3073: updated the pom.xml for project --- health-services/project/pom.xml | 2 +- .../org/egov/project/util/ProjectConstants.java | 4 ++-- .../validator/task/PtIsResouceEmptyValidator.java | 15 ++++++++++++--- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/health-services/project/pom.xml b/health-services/project/pom.xml index b15e8282b3d..36d3c0885ea 100644 --- a/health-services/project/pom.xml +++ b/health-services/project/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.8-SNAPSHOT + 1.0.9-SNAPSHOT compile diff --git a/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java b/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java index 70d52fd790b..5a431833f41 100644 --- a/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java +++ b/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java @@ -17,8 +17,8 @@ public class ProjectConstants { public static final String DOT = "."; public static final String PROJECT_PARENT_HIERARCHY_SEPERATOR = "."; public static final String TASK_NOT_ALLOWED = "TASK_NOT_ALLOWED"; - - public static final String TASK_NOT_ALLOWED_ERROR_MESSAGE = "Task not allowed as resources can not be provided when "; + public static final String TASK_NOT_ALLOWED_BENEFICIARY_REFUSED_RESOURCE_EMPTY_ERROR_MESSAGE = "Task not allowed as resources can not be provided when " + TaskStatus.BENEFICIARY_REFUSED; + public static final String TASK_NOT_ALLOWED_RESOURCE_CANNOT_EMPTY_ERROR_MESSAGE = "Task not allowed as resources can not be empty when "; public enum TaskStatus { BENEFICIARY_REFUSED("BENEFICIARY_REFUSED"); private String value; diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java index 3094293dfac..1a0114e916e 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java @@ -30,12 +30,21 @@ public Map> validate(TaskBulkRequest request) { List entities = request.getTasks(); if(!entities.isEmpty()) { entities.forEach(task -> { - if(CollectionUtils.isEmpty(task.getResources()) && ProjectConstants.TaskStatus.BENEFICIARY_REFUSED.toString().equals(task.getStatus())) { + if(CollectionUtils.isEmpty(task.getResources()) && !ProjectConstants.TaskStatus.BENEFICIARY_REFUSED.toString().equals(task.getStatus())) { + // if the task resource is empty or null and task status is not BENEFICIARY_REFUSED Error error = Error.builder() - .errorMessage(ProjectConstants.TASK_NOT_ALLOWED_ERROR_MESSAGE + ProjectConstants.TaskStatus.BENEFICIARY_REFUSED) + .errorMessage(ProjectConstants.TASK_NOT_ALLOWED_RESOURCE_CANNOT_EMPTY_ERROR_MESSAGE + ProjectConstants.TaskStatus.BENEFICIARY_REFUSED) .errorCode(TASK_NOT_ALLOWED) .type(Error.ErrorType.NON_RECOVERABLE) - .exception(new CustomException(TASK_NOT_ALLOWED, "Task not allowed as resources can not be provided when "+ProjectConstants.TaskStatus.BENEFICIARY_REFUSED)).build(); + .exception(new CustomException(TASK_NOT_ALLOWED, ProjectConstants.TASK_NOT_ALLOWED_RESOURCE_CANNOT_EMPTY_ERROR_MESSAGE + ProjectConstants.TaskStatus.BENEFICIARY_REFUSED)).build(); + populateErrorDetails(task, error, errorDetailsMap); + } else if (!CollectionUtils.isEmpty(task.getResources()) && ProjectConstants.TaskStatus.BENEFICIARY_REFUSED.toString().equals(task.getStatus())) { + // If the task resource is not empty and task status is not BENEFICIARY_REFUSED + Error error = Error.builder() + .errorMessage(ProjectConstants.TASK_NOT_ALLOWED_BENEFICIARY_REFUSED_RESOURCE_EMPTY_ERROR_MESSAGE) + .errorCode(TASK_NOT_ALLOWED) + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException(TASK_NOT_ALLOWED, ProjectConstants.TASK_NOT_ALLOWED_BENEFICIARY_REFUSED_RESOURCE_EMPTY_ERROR_MESSAGE)).build(); populateErrorDetails(task, error, errorDetailsMap); } }); From a0e237d4ae0663ff3c64594d06a1b3d6d3113f00 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 13 Oct 2023 15:44:06 +0530 Subject: [PATCH 197/283] HLM-3073: updated code comments --- .../validator/task/PtIsResouceEmptyValidator.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java index 1a0114e916e..f5d5cd42a77 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java @@ -25,13 +25,21 @@ @Order(value = 1) @Slf4j public class PtIsResouceEmptyValidator implements Validator { + + /** + * Returns all the invalid objects in the request based on the task resources. + * @param request of TaskBulkRequest class + * @return errorDetailsMap + */ public Map> validate(TaskBulkRequest request) { Map> errorDetailsMap = new HashMap<>(); List entities = request.getTasks(); if(!entities.isEmpty()) { entities.forEach(task -> { if(CollectionUtils.isEmpty(task.getResources()) && !ProjectConstants.TaskStatus.BENEFICIARY_REFUSED.toString().equals(task.getStatus())) { - // if the task resource is empty or null and task status is not BENEFICIARY_REFUSED + /** + * If the task resource is empty or null and task status is not BENEFICIARY_REFUSED it is invalid + */ Error error = Error.builder() .errorMessage(ProjectConstants.TASK_NOT_ALLOWED_RESOURCE_CANNOT_EMPTY_ERROR_MESSAGE + ProjectConstants.TaskStatus.BENEFICIARY_REFUSED) .errorCode(TASK_NOT_ALLOWED) @@ -39,7 +47,9 @@ public Map> validate(TaskBulkRequest request) { .exception(new CustomException(TASK_NOT_ALLOWED, ProjectConstants.TASK_NOT_ALLOWED_RESOURCE_CANNOT_EMPTY_ERROR_MESSAGE + ProjectConstants.TaskStatus.BENEFICIARY_REFUSED)).build(); populateErrorDetails(task, error, errorDetailsMap); } else if (!CollectionUtils.isEmpty(task.getResources()) && ProjectConstants.TaskStatus.BENEFICIARY_REFUSED.toString().equals(task.getStatus())) { - // If the task resource is not empty and task status is not BENEFICIARY_REFUSED + /** + * If the task resource is not empty and task status is BENEFICIARY_REFUSED + */ Error error = Error.builder() .errorMessage(ProjectConstants.TASK_NOT_ALLOWED_BENEFICIARY_REFUSED_RESOURCE_EMPTY_ERROR_MESSAGE) .errorCode(TASK_NOT_ALLOWED) From b080b1b6cc73fa0189cb991886d258e92d03aae4 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 13 Oct 2023 16:38:29 +0530 Subject: [PATCH 198/283] HLM-3073: added resources null check for PtProductVariantIdValidator.java --- .../egov/project/validator/task/PtProductVariantIdValidator.java | 1 + 1 file changed, 1 insertion(+) diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtProductVariantIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtProductVariantIdValidator.java index bef18b723b5..f77fee98edf 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtProductVariantIdValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtProductVariantIdValidator.java @@ -62,6 +62,7 @@ public Map> validate(TaskBulkRequest request) { .filter(notHavingErrors()).collect(Collectors.toList()); if (!entities.isEmpty()) { for (Task task : entities) { + if(task.getResources() == null) continue; Set productVariantIds = new HashSet<>(getIdList(task.getResources(), getIdMethod(task.getResources(), "productVariantId"))); try { From 259bb7dbf018ee927044a734bbd2a3fc34e88d0c Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 13 Oct 2023 16:57:17 +0530 Subject: [PATCH 199/283] HLM-3073: null check for task resource --- .../src/main/java/org/egov/common/models/project/Task.java | 1 + .../service/enrichment/ProjectTaskEnrichmentService.java | 3 +++ .../project/validator/task/PtProductVariantIdValidator.java | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java index 5f6133eff4f..01002770204 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java @@ -55,6 +55,7 @@ public class Task { @JsonProperty("resources") @Valid + @Builder.Default private List resources = new ArrayList<>(); @JsonProperty("plannedStartDate") diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java index c3b7564e49f..73e4378f798 100644 --- a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java @@ -9,7 +9,9 @@ import org.egov.common.service.IdGenService; import org.egov.project.config.ProjectConfiguration; import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -143,6 +145,7 @@ private static void enrichResourcesForCreate(TaskBulkRequest request, for (Task task : validTasks) { log.info("enriching resources"); List resources = task.getResources(); + if(CollectionUtils.isEmpty(resources)) continue; enrichResourcesForCreate(request, resources, task.getId()); } } diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtProductVariantIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtProductVariantIdValidator.java index f77fee98edf..0579edc0f8b 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtProductVariantIdValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtProductVariantIdValidator.java @@ -17,6 +17,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; import java.util.ArrayList; import java.util.HashMap; @@ -62,7 +63,7 @@ public Map> validate(TaskBulkRequest request) { .filter(notHavingErrors()).collect(Collectors.toList()); if (!entities.isEmpty()) { for (Task task : entities) { - if(task.getResources() == null) continue; + if(CollectionUtils.isEmpty(task.getResources())) continue; Set productVariantIds = new HashSet<>(getIdList(task.getResources(), getIdMethod(task.getResources(), "productVariantId"))); try { From f305b2114ec0613f18b4e660d01c0368004a5591 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 13 Oct 2023 17:44:50 +0530 Subject: [PATCH 200/283] HLM-3073: code formatting --- .../service/enrichment/ProjectTaskEnrichmentService.java | 4 ++-- .../project/validator/task/PtProductVariantIdValidator.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java index 73e4378f798..9706c877ff2 100644 --- a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java @@ -11,7 +11,6 @@ import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -145,7 +144,8 @@ private static void enrichResourcesForCreate(TaskBulkRequest request, for (Task task : validTasks) { log.info("enriching resources"); List resources = task.getResources(); - if(CollectionUtils.isEmpty(resources)) continue; + if(CollectionUtils.isEmpty(resources)) + continue; enrichResourcesForCreate(request, resources, task.getId()); } } diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtProductVariantIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtProductVariantIdValidator.java index 0579edc0f8b..c59928aa153 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtProductVariantIdValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtProductVariantIdValidator.java @@ -63,7 +63,8 @@ public Map> validate(TaskBulkRequest request) { .filter(notHavingErrors()).collect(Collectors.toList()); if (!entities.isEmpty()) { for (Task task : entities) { - if(CollectionUtils.isEmpty(task.getResources())) continue; + if(CollectionUtils.isEmpty(task.getResources())) + continue; Set productVariantIds = new HashSet<>(getIdList(task.getResources(), getIdMethod(task.getResources(), "productVariantId"))); try { From fc6ddc5e94280dcdfe7b6b00adc85e6d841b5164 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Fri, 13 Oct 2023 20:36:01 +0530 Subject: [PATCH 201/283] hlm-3073: side effect table fix --- ...20231010120100__side_effect_create_ddl.sql | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/health-services/referralmanagement/src/main/resources/db/migration/main/V20231010120100__side_effect_create_ddl.sql b/health-services/referralmanagement/src/main/resources/db/migration/main/V20231010120100__side_effect_create_ddl.sql index f42e30eecfd..3132716083c 100644 --- a/health-services/referralmanagement/src/main/resources/db/migration/main/V20231010120100__side_effect_create_ddl.sql +++ b/health-services/referralmanagement/src/main/resources/db/migration/main/V20231010120100__side_effect_create_ddl.sql @@ -1,20 +1,20 @@ CREATE TABLE IF NOT EXISTS SIDE_EFFECT( - id character varying(64), - clientReferenceId character varying(64) NOT NULL, - tenantId character varying(1000), - taskId character varying(64), - taskClientReferenceId character varying(64) NOT NULL, - projectBeneficiary character varying(64), - projectBeneficiaryClientReferenceId character varying(64), - symptoms jsonb, - createdBy character varying(64), - createdTime bigint, - lastModifiedBy character varying(64), - lastModifiedTime bigint, - clientCreatedTime bigint, - clientLastModifiedTime bigint, - rowVersion bigint, - isDeleted bool, + id character varying(64), + clientReferenceId character varying(64) NOT NULL, + tenantId character varying(1000), + taskId character varying(64), + taskClientReferenceId character varying(64) NOT NULL, + projectBeneficiaryId character varying(64), + projectBeneficiaryClientReferenceId character varying(64), + symptoms jsonb, + createdBy character varying(64), + createdTime bigint, + lastModifiedBy character varying(64), + lastModifiedTime bigint, + clientCreatedTime bigint, + clientLastModifiedTime bigint, + rowVersion bigint, + isDeleted bool, CONSTRAINT uk_side_effect PRIMARY KEY (id), CONSTRAINT uk_side_effect_clientReference_id unique (clientReferenceId) ); \ No newline at end of file From dffb40b69a2e07b3bf83fd9993ae36ece53d71bd Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Sun, 15 Oct 2023 13:10:48 +0530 Subject: [PATCH 202/283] HLM-3069: side effect code comments, code refactor --- .../sideeffect/SideEffect.java | 1 + .../service/SideEffectService.java | 84 +++++++++++--- .../SideEffectEnrichmentService.java | 40 ++++--- .../SeProjectBeneficiaryIdValidator.java | 109 ++++++++++++++++++ .../sideeffect/SeProjectTaskIdValidator.java | 63 ++++------ ...20231010120100__side_effect_create_ddl.sql | 2 + 6 files changed, 228 insertions(+), 71 deletions(-) create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java index a078844a2dc..badde74f599 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java @@ -34,6 +34,7 @@ public class SideEffect { private String taskId = null; @JsonProperty("taskClientReferenceId") + @NotNull @Size(min = 2, max = 64) private String taskClientReferenceId = null; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java index 8f8d63d9ed0..fcb56d335b6 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java @@ -1,6 +1,14 @@ package org.egov.referralmanagement.service; import lombok.extern.slf4j.Slf4j; +import org.egov.common.ds.Tuple; +import org.egov.common.models.ErrorDetails; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearchRequest; +import org.egov.common.utils.CommonUtils; +import org.egov.common.validator.Validator; import org.egov.referralmanagement.Constants; import org.egov.referralmanagement.config.ReferralManagementConfiguration; import org.egov.referralmanagement.repository.SideEffectRepository; @@ -8,17 +16,9 @@ import org.egov.referralmanagement.validator.sideeffect.SeIsDeletedValidator; import org.egov.referralmanagement.validator.sideeffect.SeNonExistentEntityValidator; import org.egov.referralmanagement.validator.sideeffect.SeNullIdValidator; +import org.egov.referralmanagement.validator.sideeffect.SeProjectBeneficiaryIdValidator; import org.egov.referralmanagement.validator.sideeffect.SeProjectTaskIdValidator; import org.egov.referralmanagement.validator.sideeffect.SeUniqueEntityValidator; -import org.egov.common.ds.Tuple; -import org.egov.common.models.ErrorDetails; -import org.egov.common.models.referralmanagement.sideeffect.SideEffect; -import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; -import org.egov.common.models.referralmanagement.sideeffect.SideEffectRequest; -import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearchRequest; -import org.egov.common.service.IdGenService; -import org.egov.common.utils.CommonUtils; -import org.egov.common.validator.Validator; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -40,11 +40,13 @@ import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; +/** + * @author kanishq-egov + * Service created to enrich, validate request and perform crud operations + */ @Service @Slf4j public class SideEffectService { - private final IdGenService idGenService; - private final SideEffectRepository sideEffectRepository; private final ReferralManagementConfiguration referralManagementConfiguration; @@ -54,7 +56,8 @@ public class SideEffectService { private final List> validators; private final Predicate> isApplicableForCreate = validator -> - validator.getClass().equals(SeProjectTaskIdValidator.class); + validator.getClass().equals(SeProjectTaskIdValidator.class) + || validator.getClass().equals(SeProjectBeneficiaryIdValidator.class); private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(SeProjectTaskIdValidator.class) @@ -69,19 +72,22 @@ public class SideEffectService { @Autowired public SideEffectService( - IdGenService idGenService, SideEffectRepository sideEffectRepository, ReferralManagementConfiguration referralManagementConfiguration, SideEffectEnrichmentService sideEffectEnrichmentService, List> validators ) { - this.idGenService = idGenService; this.sideEffectRepository = sideEffectRepository; this.referralManagementConfiguration = referralManagementConfiguration; this.sideEffectEnrichmentService = sideEffectEnrichmentService; this.validators = validators; } + /** + * converting SideEffectRequest to SideEffectBulkRequest + * @param request + * @return + */ public SideEffect create(SideEffectRequest request) { log.info("received request to create side effects"); SideEffectBulkRequest bulkRequest = SideEffectBulkRequest.builder().requestInfo(request.getRequestInfo()) @@ -90,6 +96,13 @@ public SideEffect create(SideEffectRequest request) { return create(bulkRequest, false).get(0); } + /** + * validate the request, for valid objects after enriching them, sending it to kafka, and + * throwing error for the invalid objects. + * @param sideEffectRequest + * @param isBulk + * @return + */ public List create(SideEffectBulkRequest sideEffectRequest, boolean isBulk) { log.info("received request to create bulk side effects"); Tuple, Map> tuple = validate(validators, @@ -115,6 +128,11 @@ public List create(SideEffectBulkRequest sideEffectRequest, boolean return validSideEffects; } + /** + * converting SideEffectRequest to SideEffectBulkRequest + * @param request + * @return + */ public SideEffect update(SideEffectRequest request) { log.info("received request to update side effect"); SideEffectBulkRequest bulkRequest = SideEffectBulkRequest.builder().requestInfo(request.getRequestInfo()) @@ -123,6 +141,13 @@ public SideEffect update(SideEffectRequest request) { return update(bulkRequest, false).get(0); } + /** + * validate the request, for valid objects after enriching them, sending it to kafka, and + * throwing error for the invalid objects. + * @param sideEffectRequest + * @param isBulk + * @return + */ public List update(SideEffectBulkRequest sideEffectRequest, boolean isBulk) { log.info("received request to update bulk side effect"); Tuple, Map> tuple = validate(validators, @@ -148,6 +173,17 @@ public List update(SideEffectBulkRequest sideEffectRequest, boolean return validSideEffects; } + /** + * searching based on parameters + * @param sideEffectSearchRequest + * @param limit + * @param offset + * @param tenantId + * @param lastChangedSince + * @param includeDeleted + * @return + * @throws Exception + */ public List search(SideEffectSearchRequest sideEffectSearchRequest, Integer limit, Integer offset, @@ -173,6 +209,11 @@ public List search(SideEffectSearchRequest sideEffectSearchRequest, limit, offset, tenantId, lastChangedSince, includeDeleted); } + /** + * converting SideEffectRequest to SideEffectBulkRequest + * @param sideEffectRequest + * @return + */ public SideEffect delete(SideEffectRequest sideEffectRequest) { log.info("received request to delete a side effect"); SideEffectBulkRequest bulkRequest = SideEffectBulkRequest.builder().requestInfo(sideEffectRequest.getRequestInfo()) @@ -181,6 +222,13 @@ public SideEffect delete(SideEffectRequest sideEffectRequest) { return delete(bulkRequest, false).get(0); } + /** + * validating the request, enriching the valid objects and sending them to kafka + * throwing error on invalid objects + * @param sideEffectRequest + * @param isBulk + * @return + */ public List delete(SideEffectBulkRequest sideEffectRequest, boolean isBulk) { Tuple, Map> tuple = validate(validators, isApplicableForDelete, sideEffectRequest, isBulk); @@ -214,6 +262,14 @@ public void putInCache(List sideEffects) { log.info("successfully put side effects in cache"); } + /** + * method use to valid request using parameters objects + * @param validators + * @param isApplicable + * @param request + * @param isBulk + * @return + */ private Tuple, Map> validate( List> validators, Predicate> isApplicable, diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/SideEffectEnrichmentService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/SideEffectEnrichmentService.java index d86132e06a3..03eefb43298 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/SideEffectEnrichmentService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/SideEffectEnrichmentService.java @@ -1,36 +1,32 @@ package org.egov.referralmanagement.service.enrichment; import lombok.extern.slf4j.Slf4j; -import org.egov.referralmanagement.config.ReferralManagementConfiguration; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; -import org.egov.common.service.IdGenService; import org.egov.common.utils.CommonUtils; -import org.egov.referralmanagement.repository.SideEffectRepository; import org.springframework.stereotype.Component; import java.util.List; import java.util.Map; -import static org.egov.common.utils.CommonUtils.*; +import static org.egov.common.utils.CommonUtils.enrichForCreate; +import static org.egov.common.utils.CommonUtils.enrichForDelete; +import static org.egov.common.utils.CommonUtils.enrichForUpdate; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +/** + * Class use to enrich SideEffectBulkRequest object + */ @Component @Slf4j public class SideEffectEnrichmentService { - private final IdGenService idGenService; - - private final ReferralManagementConfiguration referralManagementConfiguration; - - private final SideEffectRepository sideEffectRepository; - - public SideEffectEnrichmentService(IdGenService idGenService, ReferralManagementConfiguration referralManagementConfiguration, SideEffectRepository sideEffectRepository) { - this.idGenService = idGenService; - this.referralManagementConfiguration = referralManagementConfiguration; - this.sideEffectRepository = sideEffectRepository; - } - - public void create(List entities, SideEffectBulkRequest request) throws Exception { + /** + * + * @param entities + * @param request + */ + public void create(List entities, SideEffectBulkRequest request) { log.info("starting the enrichment for create side effect"); log.info("generating IDs using UUID"); List idList = CommonUtils.uuidSupplier().apply(entities.size()); @@ -39,6 +35,11 @@ public void create(List entities, SideEffectBulkRequest request) thr log.info("enrichment done"); } + /** + * + * @param entities + * @param request + */ public void update(List entities, SideEffectBulkRequest request) { log.info("starting the enrichment for create side effect"); Map sideEffectMap = getIdToObjMap(entities); @@ -46,6 +47,11 @@ public void update(List entities, SideEffectBulkRequest request) { log.info("enrichment done"); } + /** + * + * @param entities + * @param request + */ public void delete(List entities, SideEffectBulkRequest request) { log.info("starting the enrichment for delete side effect"); enrichForDelete(entities, request.getRequestInfo(), true); diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java new file mode 100644 index 00000000000..3350fb90f4a --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java @@ -0,0 +1,109 @@ +package org.egov.referralmanagement.validator.sideeffect; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.project.BeneficiaryBulkResponse; +import org.egov.common.models.project.BeneficiarySearchRequest; +import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.models.project.ProjectBeneficiarySearch; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + +/** + * Validate whether project beneficiary exist in db or not using project beneficiary id and project beneficiary client beneficiary id for SideEffect object + */ +@Component +@Order(value = 3) +@Slf4j +public class SeProjectBeneficiaryIdValidator implements Validator { + private final ServiceRequestClient serviceRequestClient; + private final ReferralManagementConfiguration referralManagementConfiguration; + + @Autowired + public SeProjectBeneficiaryIdValidator(ServiceRequestClient serviceRequestClient, ReferralManagementConfiguration referralManagementConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.referralManagementConfiguration = referralManagementConfiguration; + } + + /** + * + * @param request + * @return + */ + @Override + public Map> validate(SideEffectBulkRequest request) { + log.info("validating project task id"); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getSideEffects(); + Map> tenantIdSideEffectMap = entities.stream().collect(Collectors.groupingBy(SideEffect::getTenantId)); + tenantIdSideEffectMap.forEach((tenantId, sideEffects) -> { + List sideEffectList = tenantIdSideEffectMap.get(tenantId); + if (!sideEffectList.isEmpty()) { + List existingProjectBeneficiaries = null; + final List projectBeneficiaryIdList = new ArrayList<>(); + final List projectBeneficiaryClientReferenceIdList = new ArrayList<>(); + sideEffectList.forEach(sideEffect -> { + addIgnoreNull(projectBeneficiaryIdList, sideEffect.getProjectBeneficiaryId()); + addIgnoreNull(projectBeneficiaryClientReferenceIdList, sideEffect.getProjectBeneficiaryClientReferenceId()); + }); + ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() + .id(projectBeneficiaryIdList.isEmpty() ? null : projectBeneficiaryIdList) + .clientReferenceId(projectBeneficiaryClientReferenceIdList.isEmpty() ? null : projectBeneficiaryClientReferenceIdList) + .build(); + try { + BeneficiaryBulkResponse beneficiaryBulkResponse = serviceRequestClient.fetchResult( + new StringBuilder(referralManagementConfiguration.getProjectHost() + + referralManagementConfiguration.getProjectBeneficiarySearchUrl() + +"?limit=" + entities.size() + + "&offset=0&tenantId=" + tenantId), + BeneficiarySearchRequest.builder().requestInfo(request.getRequestInfo()).projectBeneficiary(projectBeneficiarySearch).build(), + BeneficiaryBulkResponse.class + ); + existingProjectBeneficiaries = beneficiaryBulkResponse.getProjectBeneficiaries(); + } catch (QueryBuilderException qbe) { + existingProjectBeneficiaries = Collections.emptyList(); + } catch (Exception e) { + throw new CustomException("Project Beneficiaries failed to fetch", "Exception : "+e.getMessage()); + } + final List existingProjectBeneficiaryIds = new ArrayList<>(); + final List existingProjectBeneficiaryClientReferenceIds = new ArrayList<>(); + existingProjectBeneficiaries.forEach(projectBeneficiary -> { + existingProjectBeneficiaryIds.add(projectBeneficiary.getId()); + existingProjectBeneficiaryClientReferenceIds.add(projectBeneficiary.getClientReferenceId()); + }); + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + !existingProjectBeneficiaryClientReferenceIds.contains(entity.getProjectBeneficiaryClientReferenceId()) + && !existingProjectBeneficiaryIds.contains(entity.getProjectBeneficiaryId()) + ).collect(Collectors.toList()); + invalidEntities.forEach(sideEffect -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(sideEffect, error, errorDetailsMap); + }); + } + }); + return errorDetailsMap; + } + private void addIgnoreNull(List list, String item) { + if(Objects.nonNull(item)) list.add(item); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java index 4d1b2609c26..1230987e3be 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java @@ -16,6 +16,7 @@ import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; import org.egov.common.validator.Validator; +import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -32,7 +33,9 @@ import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; - +/** + * Validate whether project task exist in db or not using project task id and project task client beneficiary id for SideEffect object + */ @Component @Order(value = 3) @Slf4j @@ -47,6 +50,13 @@ public SeProjectTaskIdValidator(ServiceRequestClient serviceRequestClient, Refer } + /** + * validating whether the project task id and client reference id exist or not in db + * return the invalid Side effect objects as error map + * + * @param request of SideEffectBulkRequest + * @return + */ @Override public Map> validate(SideEffectBulkRequest request) { log.info("validating project task id"); @@ -58,21 +68,16 @@ public Map> validate(SideEffectBulkRequest request) { List sideEffectList = tenantIdSideEffectMap.get(tenantId); if (!sideEffectList.isEmpty()) { List existingTasks = null; - List existingProjectBeneficiaries = null; - final List projectBeneficiaryIdList = new ArrayList<>(); - final List projectBeneficiaryClientReferenceIdList = new ArrayList<>(); final List taskIdList = new ArrayList<>(); final List taskClientReferenceIdList = new ArrayList<>(); + sideEffectList.forEach(sideEffect -> { + addIgnoreNull(taskIdList, sideEffect.getTaskId()); + addIgnoreNull(taskClientReferenceIdList, sideEffect.getTaskClientReferenceId()); + }); + TaskSearch taskSearch = TaskSearch.builder() + .id(taskIdList.isEmpty() ? null : taskIdList) + .clientReferenceId(taskClientReferenceIdList.isEmpty() ? null : taskClientReferenceIdList).build(); try { - sideEffectList.forEach(sideEffect -> { - addIgnoreNull(projectBeneficiaryIdList, sideEffect.getProjectBeneficiaryId()); - addIgnoreNull(projectBeneficiaryClientReferenceIdList, sideEffect.getProjectBeneficiaryClientReferenceId()); - addIgnoreNull(taskIdList, sideEffect.getTaskId()); - addIgnoreNull(taskClientReferenceIdList, sideEffect.getTaskClientReferenceId()); - }); - TaskSearch taskSearch = TaskSearch.builder() - .id(taskIdList.isEmpty() ? null : taskIdList) - .clientReferenceId(taskClientReferenceIdList.isEmpty() ? null : taskClientReferenceIdList).build(); TaskBulkResponse taskBulkResponse = serviceRequestClient.fetchResult( new StringBuilder(referralManagementConfiguration.getProjectHost() + referralManagementConfiguration.getProjectTaskSearchUrl() @@ -82,39 +87,17 @@ public Map> validate(SideEffectBulkRequest request) { TaskBulkResponse.class ); existingTasks = taskBulkResponse.getTasks(); - ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() - .id(projectBeneficiaryIdList.isEmpty() ? null : projectBeneficiaryIdList) - .clientReferenceId(projectBeneficiaryClientReferenceIdList.isEmpty() ? null : projectBeneficiaryClientReferenceIdList) - .build(); - BeneficiaryBulkResponse beneficiaryBulkResponse = serviceRequestClient.fetchResult( - new StringBuilder(referralManagementConfiguration.getProjectHost() - + referralManagementConfiguration.getProjectBeneficiarySearchUrl() - +"?limit=" + entities.size() - + "&offset=0&tenantId=" + tenantId), - BeneficiarySearchRequest.builder().requestInfo(request.getRequestInfo()).projectBeneficiary(projectBeneficiarySearch).build(), - BeneficiaryBulkResponse.class - ); - existingProjectBeneficiaries = beneficiaryBulkResponse.getProjectBeneficiaries(); } catch (QueryBuilderException e) { - if(existingTasks == null) existingTasks = Collections.emptyList(); - existingProjectBeneficiaries = Collections.emptyList(); + existingTasks = Collections.emptyList(); } catch (Exception e) { - throw new RuntimeException(e); + throw new CustomException("Project Task failed to fetch", "Exception : "+e.getMessage()); } - final List existingProjectBeneficiaryIds = new ArrayList<>(); - final List existingProjectBeneficiaryClientReferenceIds = new ArrayList<>(); - existingProjectBeneficiaries.forEach(projectBeneficiary -> { - existingProjectBeneficiaryIds.add(projectBeneficiary.getId()); - existingProjectBeneficiaryClientReferenceIds.add(projectBeneficiary.getClientReferenceId()); - }); final List existingProjectTaskIds = existingTasks.stream().map(Task::getId).collect(Collectors.toList()); final List existingProjectReferenceTaskIds = existingTasks.stream().map(Task::getClientReferenceId).collect(Collectors.toList()); List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> - !existingProjectTaskIds.contains(entity.getTaskId()) - && !existingProjectReferenceTaskIds.contains(entity.getTaskClientReferenceId()) - && !existingProjectBeneficiaryIds.contains(entity.getProjectBeneficiaryId()) - && !existingProjectBeneficiaryClientReferenceIds.contains(entity.getProjectBeneficiaryClientReferenceId()) - ).collect(Collectors.toList()); + !existingProjectReferenceTaskIds.contains(entity.getTaskClientReferenceId()) + && !existingProjectTaskIds.contains(entity.getTaskId()) + ).collect(Collectors.toList()); invalidEntities.forEach(sideEffect -> { Error error = getErrorForNonExistentEntity(); populateErrorDetails(sideEffect, error, errorDetailsMap); diff --git a/health-services/referralmanagement/src/main/resources/db/migration/main/V20231010120100__side_effect_create_ddl.sql b/health-services/referralmanagement/src/main/resources/db/migration/main/V20231010120100__side_effect_create_ddl.sql index 3132716083c..2cb20d2a998 100644 --- a/health-services/referralmanagement/src/main/resources/db/migration/main/V20231010120100__side_effect_create_ddl.sql +++ b/health-services/referralmanagement/src/main/resources/db/migration/main/V20231010120100__side_effect_create_ddl.sql @@ -11,7 +11,9 @@ CREATE TABLE IF NOT EXISTS SIDE_EFFECT( createdTime bigint, lastModifiedBy character varying(64), lastModifiedTime bigint, + clientCreatedBy character varying(64), clientCreatedTime bigint, + clientLastModifiedBy character varying(64), clientLastModifiedTime bigint, rowVersion bigint, isDeleted bool, From 83a51d53d15e8cd10ad291bead6fcc8380540c78 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Sun, 15 Oct 2023 16:22:13 +0530 Subject: [PATCH 203/283] updated health models version --- health-services/referralmanagement/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/referralmanagement/pom.xml b/health-services/referralmanagement/pom.xml index fa6ecfea3cc..3b5fded205c 100644 --- a/health-services/referralmanagement/pom.xml +++ b/health-services/referralmanagement/pom.xml @@ -52,7 +52,7 @@ org.egov.common health-services-models - 1.0.8-SNAPSHOT + 1.0.9-SNAPSHOT compile From 794109bbb7aee809cc73c07132dd69a89ee280b9 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Tue, 17 Oct 2023 19:18:57 +0530 Subject: [PATCH 204/283] HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta --- health-services/project/CHANGELOG.md | 11 +++++++++-- health-services/project/pom.xml | 2 +- health-services/stock/CHANGELOG.md | 7 ++++++- health-services/stock/pom.xml | 2 +- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/health-services/project/CHANGELOG.md b/health-services/project/CHANGELOG.md index 645e12b40e1..2e8479d0a8b 100644 --- a/health-services/project/CHANGELOG.md +++ b/health-services/project/CHANGELOG.md @@ -1,7 +1,14 @@ All notable changes to this module will be documented in this file. -## 1.0.0 +## 1.1.1-beta + +- Added support for multi round +- Added new validator for project task. + + +## 1.1.0 - Base version +## 1.0.0 + -## 1.1.0 \ No newline at end of file diff --git a/health-services/project/pom.xml b/health-services/project/pom.xml index 36d3c0885ea..f9e6a5fa7de 100644 --- a/health-services/project/pom.xml +++ b/health-services/project/pom.xml @@ -5,7 +5,7 @@ project jar project - 1.1.0 + 1.1.1-beta 1.8 ${java.version} diff --git a/health-services/stock/CHANGELOG.md b/health-services/stock/CHANGELOG.md index 645e12b40e1..49497ae820d 100644 --- a/health-services/stock/CHANGELOG.md +++ b/health-services/stock/CHANGELOG.md @@ -1,7 +1,12 @@ All notable changes to this module will be documented in this file. +## 1.1.1-beta + +- Enhanced Inventory flow by introducing more actors. + +## 1.1.0 + ## 1.0.0 - Base version -## 1.1.0 \ No newline at end of file diff --git a/health-services/stock/pom.xml b/health-services/stock/pom.xml index 81e99bf2071..36a6ee1f830 100644 --- a/health-services/stock/pom.xml +++ b/health-services/stock/pom.xml @@ -5,7 +5,7 @@ stock jar stock - 1.1.0 + 1.1.1-beta 1.8 ${java.version} From 4b09e7aad7f568d5477cd83714375b00a35a5b16 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 18 Oct 2023 00:46:21 +0530 Subject: [PATCH 205/283] referralmanagement version 1.0.0-beta, added changelog, localsetup --- .../referralmanagement/CHANGELOG.md | 6 ++++ .../referralmanagement/LOCALSETUP.md | 31 +++++++++++++++++++ health-services/referralmanagement/pom.xml | 2 +- 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 health-services/referralmanagement/CHANGELOG.md create mode 100644 health-services/referralmanagement/LOCALSETUP.md diff --git a/health-services/referralmanagement/CHANGELOG.md b/health-services/referralmanagement/CHANGELOG.md new file mode 100644 index 00000000000..1b6cd66bbd8 --- /dev/null +++ b/health-services/referralmanagement/CHANGELOG.md @@ -0,0 +1,6 @@ +# Changelog +All notable changes to this module will be documented in this file. + +## 1.0.0-beta + +- Base version \ No newline at end of file diff --git a/health-services/referralmanagement/LOCALSETUP.md b/health-services/referralmanagement/LOCALSETUP.md new file mode 100644 index 00000000000..4f43fccdc4f --- /dev/null +++ b/health-services/referralmanagement/LOCALSETUP.md @@ -0,0 +1,31 @@ +# Local Setup + +To setup the Project service in your local system, clone the [Health campaign services](https://github.com/egovernments/health-campaign-services). + +## Dependencies + +### Infra Dependency + +- [X] Postgres DB +- [X] Redis +- [X] Elasticsearch +- [X] Kafka + - [X] Consumer + - [X] Producer + + +## Running Locally + +You can use docker-compose file to get started with these dependencies. Download docker-compose.yml from [here](../libraries/docker-compose.yml) + +Use the following command to start containers + +``` +cd path/to/docker-compose.yml file + +docker-compose up -d +``` + +To run it locally this service require port forwarding for idgen service, facility service and project service. + +Directly run the application. \ No newline at end of file diff --git a/health-services/referralmanagement/pom.xml b/health-services/referralmanagement/pom.xml index 3b5fded205c..031d6284bdc 100644 --- a/health-services/referralmanagement/pom.xml +++ b/health-services/referralmanagement/pom.xml @@ -8,7 +8,7 @@ referralmanagement jar referralmanagement - 1.0.0 + 1.0.0-beta 1.8 ${java.version} From 847fe1265f608d806dee17207bb9b5698e20e6e6 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Wed, 18 Oct 2023 10:19:24 +0530 Subject: [PATCH 206/283] Update CHANGELOG.md --- health-services/project/CHANGELOG.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/health-services/project/CHANGELOG.md b/health-services/project/CHANGELOG.md index 2e8479d0a8b..614f4f89341 100644 --- a/health-services/project/CHANGELOG.md +++ b/health-services/project/CHANGELOG.md @@ -1,14 +1,13 @@ All notable changes to this module will be documented in this file. ## 1.1.1-beta - -- Added support for multi round -- Added new validator for project task. + - Added support for multi round, Added new validator for project task. ## 1.1.0 + - models library version update -- Base version ## 1.0.0 + - Base version From 736e951ccb96c69c9c8d4a174cd68c2aeeee295f Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Wed, 18 Oct 2023 10:20:25 +0530 Subject: [PATCH 207/283] Update CHANGELOG.md --- health-services/project/CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/health-services/project/CHANGELOG.md b/health-services/project/CHANGELOG.md index 614f4f89341..d856c30548e 100644 --- a/health-services/project/CHANGELOG.md +++ b/health-services/project/CHANGELOG.md @@ -1,9 +1,8 @@ All notable changes to this module will be documented in this file. -## 1.1.1-beta +## 1.1.1-beta 19-10-2023 - Added support for multi round, Added new validator for project task. - ## 1.1.0 - models library version update From fdd6c67606142edbfbed2a713ed93dc77bc2c22d Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Wed, 18 Oct 2023 10:21:41 +0530 Subject: [PATCH 208/283] Update CHANGELOG.md --- health-services/referralmanagement/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/health-services/referralmanagement/CHANGELOG.md b/health-services/referralmanagement/CHANGELOG.md index 1b6cd66bbd8..6bc2d9b33c4 100644 --- a/health-services/referralmanagement/CHANGELOG.md +++ b/health-services/referralmanagement/CHANGELOG.md @@ -2,5 +2,5 @@ All notable changes to this module will be documented in this file. ## 1.0.0-beta - -- Base version \ No newline at end of file + - Base version + - Added functionility for Side-Effects and Refferal management From e49ec543d84f5d5450ba945dffbe8ce17d60360a Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Wed, 18 Oct 2023 10:22:56 +0530 Subject: [PATCH 209/283] Update CHANGELOG.md --- health-services/stock/CHANGELOG.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/health-services/stock/CHANGELOG.md b/health-services/stock/CHANGELOG.md index 49497ae820d..8bb88bb178f 100644 --- a/health-services/stock/CHANGELOG.md +++ b/health-services/stock/CHANGELOG.md @@ -1,12 +1,11 @@ All notable changes to this module will be documented in this file. -## 1.1.1-beta -- Enhanced Inventory flow by introducing more actors. +## 1.1.1-beta + - Enhanced Inventory flow for last mile delivery ## 1.1.0 - + - Models library version update ## 1.0.0 - -- Base version + - Base version From 336dce56db8e8708b66e8a9382b2932f94cb21fd Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 18 Oct 2023 11:20:19 +0530 Subject: [PATCH 210/283] household version increased from 1.1.0 to 1.1.1-beta and individual version increased from 1.1.1 to 1.1.2-beta and added changelog --- health-services/household/CHANGELOG.md | 8 +++++++- health-services/household/pom.xml | 2 +- health-services/individual/CHANGELOG.md | 8 +++++++- health-services/individual/pom.xml | 2 +- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/health-services/household/CHANGELOG.md b/health-services/household/CHANGELOG.md index 645e12b40e1..9fb0bc133a6 100644 --- a/health-services/household/CHANGELOG.md +++ b/health-services/household/CHANGELOG.md @@ -1,7 +1,13 @@ All notable changes to this module will be documented in this file. +## 1.1.1-beta + +- Added proximity based search support + +## 1.1.0 + + ## 1.0.0 - Base version -## 1.1.0 \ No newline at end of file diff --git a/health-services/household/pom.xml b/health-services/household/pom.xml index ee09d2ed4e3..0d726bd8cce 100644 --- a/health-services/household/pom.xml +++ b/health-services/household/pom.xml @@ -5,7 +5,7 @@ household jar household - 1.1.0 + 1.1.1-beta 1.8 ${java.version} diff --git a/health-services/individual/CHANGELOG.md b/health-services/individual/CHANGELOG.md index 645e12b40e1..94e615fa82f 100644 --- a/health-services/individual/CHANGELOG.md +++ b/health-services/individual/CHANGELOG.md @@ -1,7 +1,13 @@ All notable changes to this module will be documented in this file. +## 1.1.2-beta + +- Added proximity based search support + +## 1.1.0 + + ## 1.0.0 - Base version -## 1.1.0 \ No newline at end of file diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index 40a071672a4..6eca870f705 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -5,7 +5,7 @@ individual jar individual - 1.1.1 + 1.1.2-beta 1.8 ${java.version} From 069d842955c2167fc38ceca9cf7d81cdb864e9e7 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 18 Oct 2023 15:07:28 +0530 Subject: [PATCH 211/283] updated health-campaign-models dependency in individual, household --- health-services/household/pom.xml | 2 +- health-services/individual/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/health-services/household/pom.xml b/health-services/household/pom.xml index 0d726bd8cce..dd4e667a832 100644 --- a/health-services/household/pom.xml +++ b/health-services/household/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.7-SNAPSHOT + 1.0.9-SNAPSHOT compile diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index 6eca870f705..61e349b8cc2 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.7-SNAPSHOT + 1.0.9-SNAPSHOT compile From 8f587abfc4d719a56fc84c8aa7ccac0d90e6f931 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 25 Oct 2023 15:31:06 +0530 Subject: [PATCH 212/283] HLM-3069: null project beneficiary validation error fix --- .../validator/sideeffect/SeProjectBeneficiaryIdValidator.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java index 3350fb90f4a..e39aafdc0aa 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java @@ -92,7 +92,8 @@ public Map> validate(SideEffectBulkRequest request) { existingProjectBeneficiaryClientReferenceIds.add(projectBeneficiary.getClientReferenceId()); }); List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> - !existingProjectBeneficiaryClientReferenceIds.contains(entity.getProjectBeneficiaryClientReferenceId()) + ( Objects.nonNull(entity.getProjectBeneficiaryClientReferenceId()) || Objects.nonNull(entity.getProjectBeneficiaryId()) ) && + !existingProjectBeneficiaryClientReferenceIds.contains(entity.getProjectBeneficiaryClientReferenceId()) && !existingProjectBeneficiaryIds.contains(entity.getProjectBeneficiaryId()) ).collect(Collectors.toList()); invalidEntities.forEach(sideEffect -> { From 8c56d304a043a2e098d128b4a8e9f575caea7a4f Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Wed, 25 Oct 2023 17:08:32 +0530 Subject: [PATCH 213/283] HLM-3069: added comments and splitted validation condition --- .../sideeffect/SeProjectBeneficiaryIdValidator.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java index e39aafdc0aa..d0d2ec37dbb 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java @@ -91,10 +91,15 @@ public Map> validate(SideEffectBulkRequest request) { existingProjectBeneficiaryIds.add(projectBeneficiary.getId()); existingProjectBeneficiaryClientReferenceIds.add(projectBeneficiary.getClientReferenceId()); }); + /** + * for all the entities that do not have any error in previous validations + * checking whether the project beneficiary client reference id is not null and exist in the db + */ List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> - ( Objects.nonNull(entity.getProjectBeneficiaryClientReferenceId()) || Objects.nonNull(entity.getProjectBeneficiaryId()) ) && - !existingProjectBeneficiaryClientReferenceIds.contains(entity.getProjectBeneficiaryClientReferenceId()) - && !existingProjectBeneficiaryIds.contains(entity.getProjectBeneficiaryId()) + ( Objects.nonNull(entity.getProjectBeneficiaryClientReferenceId()) + && !existingProjectBeneficiaryClientReferenceIds.contains(entity.getProjectBeneficiaryClientReferenceId()) ) + || ( Objects.nonNull(entity.getProjectBeneficiaryId()) + && !existingProjectBeneficiaryIds.contains(entity.getProjectBeneficiaryId()) ) ).collect(Collectors.toList()); invalidEntities.forEach(sideEffect -> { Error error = getErrorForNonExistentEntity(); From 0ea563be1b4f3781199a9817ce044a946fe636e4 Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Thu, 2 Nov 2023 18:58:16 +0530 Subject: [PATCH 214/283] Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --- .../contracts/referral-management.yml | 10 +- health-services/household/pom.xml | 2 +- .../validators/HmHouseholdValidator.java | 2 +- .../repository/HouseholdRepository.java | 42 +++- .../HouseholdMemberEnrichmentService.java | 2 +- .../household/service/HouseholdService.java | 40 ++- .../HNonExsistentEntityValidator.java | 2 +- .../household/HRowVersionValidator.java | 2 +- .../controllers/HouseholdApiController.java | 8 +- .../household/service/HouseholdFindTest.java | 9 +- .../HouseholdMemberCreateEnrichmentTest.java | 4 +- .../HouseholdMemberUpdateEnrichmentTest.java | 4 +- .../service/HouseholdMemberUpdateTest.java | 4 +- .../HouseholdApiControllerTest.java | 15 +- .../libraries/health-services-models/pom.xml | 2 +- .../household/HouseholdBulkResponse.java | 4 + .../models/referralmanagement/Referral.java | 39 +-- .../ReferralBulkRequest.java | 18 +- .../ReferralBulkResponse.java | 18 +- .../referralmanagement/ReferralRequest.java | 6 +- .../referralmanagement/ReferralResponse.java | 6 +- .../referralmanagement/ReferralSearch.java | 22 +- .../ReferralSearchRequest.java | 6 +- .../sideeffect/SideEffect.java | 29 ++- .../sideeffect/SideEffectBulkRequest.java | 16 +- .../sideeffect/SideEffectBulkResponse.java | 16 +- .../sideeffect/SideEffectRequest.java | 6 +- .../sideeffect/SideEffectResponse.java | 6 +- .../sideeffect/SideEffectSearch.java | 10 +- .../sideeffect/SideEffectSearchRequest.java | 6 +- health-services/referralmanagement/pom.xml | 2 +- .../egov/referralmanagement/Constants.java | 6 +- .../consumer/ReferralManagementConsumer.java | 6 +- .../consumer/SideEffectConsumer.java | 6 +- .../repository/ReferralRepository.java | 6 +- .../rowmapper/ReferralRowMapper.java | 44 ++-- .../rowmapper/SideEffectRowMapper.java | 3 + .../service/FacilityService.java | 91 +++++++ .../service/ReferralManagementService.java | 44 ++-- .../ReferralManagementEnrichmentService.java | 31 +-- .../util/ValidatorUtil.java | 34 +++ .../RmFacilityEntitiesIdValidator.java | 100 -------- .../RmNonExistentEntityValidator.java | 4 +- .../RmProjectBeneficiaryIdValidator.java | 114 +++++++++ .../RmProjectEntitiesIdValidator.java | 134 ---------- .../validator/RmRecipientIdValidator.java | 107 ++++++++ .../validator/RmReferrerIdValidator.java | 86 +++++++ .../validator/RmSideEffectIdValidator.java | 89 +++++++ .../ReferralManagementApiController.java | 35 ++- .../V20230928113400__referral_create_ddl.sql | 6 +- ...rral_side_effect_additionaldetails_ddl.sql | 2 + .../referral-management-persister.yml | 234 +++++++++--------- .../helper/ReferralRequestTestBuilder.java | 60 +++++ .../helper/ReferralTestBuilder.java | 78 ++++++ .../ReferralManagementApiControllerTest.java | 208 ++++++++++++++++ 55 files changed, 1329 insertions(+), 557 deletions(-) create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/FacilityService.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/util/ValidatorUtil.java delete mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmFacilityEntitiesIdValidator.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectBeneficiaryIdValidator.java delete mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectEntitiesIdValidator.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmRecipientIdValidator.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmReferrerIdValidator.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmSideEffectIdValidator.java create mode 100644 health-services/referralmanagement/src/main/resources/db/migration/main/V20231019114100__referral_side_effect_additionaldetails_ddl.sql create mode 100644 health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/ReferralRequestTestBuilder.java create mode 100644 health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/ReferralTestBuilder.java create mode 100644 health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiControllerTest.java diff --git a/docs/health-api-specs/contracts/referral-management.yml b/docs/health-api-specs/contracts/referral-management.yml index d93dbdd05d5..074ad2b152a 100644 --- a/docs/health-api-specs/contracts/referral-management.yml +++ b/docs/health-api-specs/contracts/referral-management.yml @@ -548,6 +548,8 @@ definitions: type: array items: type: string + additionalFields: + $ref: '#/definitions/additionalFields' isDeleted: $ref: '#/definitions/isDeleted' rowVersion: @@ -663,17 +665,17 @@ definitions: minLength: 2 maxLength: 64 description: Project Beneficiary Client Reference Id - referringById: + referrerId: type: string minLength: 2 maxLength: 64 description: Worker Id that is referring the Beneficiary - referredToId: + recipientId: type: string minLength: 2 maxLength: 64 description: Individual or Facility Id whom the Beneficiary is referred to. - referredToType: + recipientType: type: string description: Individual or Facility reasons: @@ -682,6 +684,8 @@ definitions: type: string sideEffect: $ref: '#/definition/SideEffect' + additionalFields: + $ref: '#/definitions/additionalFields' isDeleted: $ref: '#/definitions/isDeleted' rowVersion: diff --git a/health-services/household/pom.xml b/health-services/household/pom.xml index dd4e667a832..1024384ae9d 100644 --- a/health-services/household/pom.xml +++ b/health-services/household/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.9-SNAPSHOT + 1.0.10-SNAPSHOT compile diff --git a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmHouseholdValidator.java b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmHouseholdValidator.java index 7294e0a8296..ad9e9c81e84 100644 --- a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmHouseholdValidator.java +++ b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmHouseholdValidator.java @@ -53,7 +53,7 @@ public Map> validate(HouseholdMemberBulkRequest hou List houseHoldIds = getIdList(householdMembers, idMethod); log.info("finding valid household ids from household service"); - List validHouseHoldIds = householdService.findById(houseHoldIds, columnName, false); + List validHouseHoldIds = householdService.findById(houseHoldIds, columnName, false).getY(); log.info("getting unique household ids from valid household ids"); Set uniqueHoldIds = getSet(validHouseHoldIds, columnName == "id" ? "getId": "getClientReferenceId"); diff --git a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java index b23a6df9c18..bf7951e8804 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java +++ b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java @@ -6,6 +6,7 @@ import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; +import org.egov.common.ds.Tuple; import org.egov.common.models.household.Household; import org.egov.common.producer.Producer; import org.egov.household.repository.rowmapper.HouseholdRowMapper; @@ -40,7 +41,7 @@ protected HouseholdRepository(Producer producer, super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, householdRowMapper, Optional.of("household")); } - public List findById(List ids, String columnName, Boolean includeDeleted) { + public Tuple> findById(List ids, String columnName, Boolean includeDeleted) { List objFound = findInCache(ids).stream() .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) .collect(Collectors.toList()); @@ -50,7 +51,7 @@ public List findById(List ids, String columnName, Boolean inc .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) .collect(Collectors.toList())); if (ids.isEmpty()) { - return objFound; + return new Tuple<>(Long.valueOf(objFound.size()), objFound); } } @@ -61,13 +62,16 @@ public List findById(List ids, String columnName, Boolean inc Map paramMap = new HashMap(); paramMap.put("ids", ids); + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramMap); + objFound.addAll(this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper)); putInCache(objFound); - return objFound; + return new Tuple<>(totalCount, objFound); } - public List find(HouseholdSearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { - String query = "SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM household h LEFT JOIN address a ON h.addressid = a.id"; + public Tuple> find(HouseholdSearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { + String query = "SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid"; + query += " FROM household h LEFT JOIN address a ON h.addressid = a.id"; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); @@ -82,13 +86,16 @@ public List find(HouseholdSearch searchObject, Integer limit, Integer if (lastChangedSince != null) { query = query + "and lastModifiedTime>=:lastModifiedTime "; } - query = query + "ORDER BY h.id ASC LIMIT :limit OFFSET :offset"; paramsMap.put("tenantId", tenantId); paramsMap.put("isDeleted", includeDeleted); paramsMap.put("lastModifiedTime", lastChangedSince); + + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap); + + query = query + "ORDER BY h.id ASC LIMIT :limit OFFSET :offset"; paramsMap.put("limit", limit); paramsMap.put("offset", offset); - return this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + return new Tuple<>(totalCount, this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper)); } /** @@ -102,9 +109,9 @@ public List find(HouseholdSearch searchObject, Integer limit, Integer * * Fetch all the household which falls under the radius provided using longitude and latitude provided. */ - public List findByRadius(HouseholdSearch searchObject, Integer limit, Integer offset, String tenantId, Boolean includeDeleted) throws QueryBuilderException { + public Tuple> findByRadius(HouseholdSearch searchObject, Integer limit, Integer offset, String tenantId, Boolean includeDeleted) throws QueryBuilderException { String query = searchCriteriaWaypointQuery + - "SELECT * FROM (SELECT h.*, a.*, " + calculateDistanceFromTwoWaypointsFormulaQuery + " \n" + + "SELECT * FROM (SELECT h.*, a.*, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid, " + calculateDistanceFromTwoWaypointsFormulaQuery + " \n" + "FROM public.household h LEFT JOIN public.address a ON h.addressid = a.id AND h.tenantid = a.tenantid, cte_search_criteria_waypoint cte_scw "; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); @@ -117,14 +124,27 @@ public List findByRadius(HouseholdSearch searchObject, Integer limit, } query = query + " ) AS rt "; query = query + " WHERE distance < :distance "; - query = query + " ORDER BY distance ASC LIMIT :limit OFFSET :offset "; paramsMap.put("s_latitude", searchObject.getLatitude()); paramsMap.put("s_longitude", searchObject.getLongitude()); paramsMap.put("tenantId", tenantId); paramsMap.put("isDeleted", includeDeleted); paramsMap.put("distance", searchObject.getSearchRadius()); + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap); + query = query + " ORDER BY distance ASC LIMIT :limit OFFSET :offset "; paramsMap.put("limit", limit); paramsMap.put("offset", offset); - return this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + return new Tuple<>(totalCount, this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper)); + } + + private Long constructTotalCountCTEAndReturnResult(String query, Map paramsMap) { + String cteQuery = "WITH result_cte AS ("+query+"), totalCount_cte AS (SELECT COUNT(*) AS totalRows FROM result_cte) select * from totalCount_cte"; + return this.namedParameterJdbcTemplate.query(cteQuery, paramsMap, resultSet -> { + if(resultSet.next()) + return resultSet.getLong("totalRows"); + else + return 0L; + }); } + + } diff --git a/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberEnrichmentService.java b/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberEnrichmentService.java index d1943070ba8..afcc8124b8f 100644 --- a/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberEnrichmentService.java +++ b/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberEnrichmentService.java @@ -72,7 +72,7 @@ public void enrichHousehold(List householdMembers) { log.info("getting houseHoldIds for householdMembers"); List houseHoldIds = getIdList(householdMembers, idMethod); log.info("finding households from householdService with ids: {}", houseHoldIds); - List householdList = householdService.findById(houseHoldIds, columnName, false); + List householdList = householdService.findById(houseHoldIds, columnName, false).getY(); log.info("getting method for householdList with columnName: {}", columnName); Method householdMethod = getIdMethod(householdList, columnName); log.info("getting Map of households"); diff --git a/health-services/household/src/main/java/org/egov/household/service/HouseholdService.java b/health-services/household/src/main/java/org/egov/household/service/HouseholdService.java index ec03d4b07fb..5da1471730b 100644 --- a/health-services/household/src/main/java/org/egov/household/service/HouseholdService.java +++ b/health-services/household/src/main/java/org/egov/household/service/HouseholdService.java @@ -108,7 +108,7 @@ public List create(HouseholdBulkRequest request, boolean isBulk) { return request.getHouseholds(); } - public List search(HouseholdSearch householdSearch, Integer limit, Integer offset, String tenantId, + public Tuple> search(HouseholdSearch householdSearch, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) { String idFieldName = getIdFieldName(householdSearch); @@ -116,30 +116,26 @@ public List search(HouseholdSearch householdSearch, Integer limit, In List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections .singletonList(householdSearch)), householdSearch); - List households = householdRepository.findById(ids, - idFieldName, includeDeleted).stream() + Tuple> householdsTuple = householdRepository.findById(ids, + idFieldName, includeDeleted); + List households = householdsTuple.getY().stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); log.info("households found for search by id, size: {}", households.size()); - return households; - } - if(isProximityBasedSearch(householdSearch)) { - try { - List households = householdRepository.findByRadius(householdSearch, limit, offset, tenantId, includeDeleted); - log.info("households found for search, size: {}", households.size()); - return households; - } catch (QueryBuilderException e) { - log.error("error occurred while searching households", e); - throw new CustomException("ERROR_IN_QUERY", e.getMessage()); - } + return new Tuple<>(householdsTuple.getX(), households); } try { - List households = householdRepository.find(householdSearch, limit, offset, - tenantId, lastChangedSince, includeDeleted); - log.info("households found for search, size: {}", households.size()); - return households; + new Tuple<>(null, Collections.emptyList()); + Tuple> householdsTuple; + if(Boolean.TRUE.equals(isProximityBasedSearch(householdSearch))) { + householdsTuple = householdRepository.findByRadius(householdSearch, limit, offset, tenantId, includeDeleted); + } else { + householdsTuple = householdRepository.find(householdSearch, limit, offset, tenantId, lastChangedSince, includeDeleted); + } + log.info("households found for search, size: {}", householdsTuple.getY().size()); + return householdsTuple; } catch (QueryBuilderException e) { log.error("error occurred while searching households", e); throw new CustomException("ERROR_IN_QUERY", e.getMessage()); @@ -209,13 +205,13 @@ public List delete(HouseholdBulkRequest request, boolean isBulk) { return request.getHouseholds(); } - public List findById(List houseHoldIds, String columnName, boolean includeDeleted){ + public Tuple> findById(List houseHoldIds, String columnName, boolean includeDeleted){ log.info("finding Households by Ids: {} with columnName: {} and includeDeleted: {}", houseHoldIds, columnName, includeDeleted); log.info("started finding Households by Ids"); - List households = householdRepository.findById(houseHoldIds, columnName, includeDeleted); - log.info("finished finding Households by Ids. Found {} Households", households.size()); - return households; + Tuple> householdsTuple = householdRepository.findById(houseHoldIds, columnName, includeDeleted); + log.info("finished finding Households by Ids. Found {} Households", householdsTuple.getY().size()); + return householdsTuple; } public void putInCache(List households) { diff --git a/health-services/household/src/main/java/org/egov/household/validators/household/HNonExsistentEntityValidator.java b/health-services/household/src/main/java/org/egov/household/validators/household/HNonExsistentEntityValidator.java index 2ae5f41b4f5..a4ea82912ba 100644 --- a/health-services/household/src/main/java/org/egov/household/validators/household/HNonExsistentEntityValidator.java +++ b/health-services/household/src/main/java/org/egov/household/validators/household/HNonExsistentEntityValidator.java @@ -48,7 +48,7 @@ public Map> validate(HouseholdBulkRequest request) { if (!eMap.isEmpty()) { List entityIds = new ArrayList<>(eMap.keySet()); List existingEntities = householdRepository.findById(entityIds, - getIdFieldName(idMethod), false); + getIdFieldName(idMethod), false).getY(); List nonExistentEntities = checkNonExistentEntities(eMap, existingEntities, idMethod); nonExistentEntities.forEach(task -> { diff --git a/health-services/household/src/main/java/org/egov/household/validators/household/HRowVersionValidator.java b/health-services/household/src/main/java/org/egov/household/validators/household/HRowVersionValidator.java index a27dff638c0..e9ab1f1bae4 100644 --- a/health-services/household/src/main/java/org/egov/household/validators/household/HRowVersionValidator.java +++ b/health-services/household/src/main/java/org/egov/household/validators/household/HRowVersionValidator.java @@ -45,7 +45,7 @@ public Map> validate(HouseholdBulkRequest request) { if (!eMap.isEmpty()) { List entityIds = new ArrayList<>(eMap.keySet()); List existingEntities = repository.findById(entityIds, - getIdFieldName(idMethod), false); + getIdFieldName(idMethod), false).getY(); List entitiesWithMismatchedRowVersion = getEntitiesWithMismatchedRowVersion(eMap, existingEntities, idMethod); entitiesWithMismatchedRowVersion.forEach(individual -> { diff --git a/health-services/household/src/main/java/org/egov/household/web/controllers/HouseholdApiController.java b/health-services/household/src/main/java/org/egov/household/web/controllers/HouseholdApiController.java index d37a560f8bb..460adf4e6ab 100644 --- a/health-services/household/src/main/java/org/egov/household/web/controllers/HouseholdApiController.java +++ b/health-services/household/src/main/java/org/egov/household/web/controllers/HouseholdApiController.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.annotations.ApiParam; import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.ds.Tuple; import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdBulkRequest; import org.egov.common.models.household.HouseholdBulkResponse; @@ -202,11 +203,12 @@ public ResponseEntity householdV1SearchPost(@ApiParam(val @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, @NotNull @Size(min = 2, max = 1000) @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, - @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) { + @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted, + @ApiParam(value = "Used to test performance", defaultValue = "false") @Valid @RequestParam(value = "useCte", required = false, defaultValue = "false") Boolean useCte) { - List households = householdService.search(request.getHousehold(), limit, offset, tenantId, lastChangedSince, includeDeleted); + Tuple> householdsTuple = householdService.search(request.getHousehold(), limit, offset, tenantId, lastChangedSince, includeDeleted); HouseholdBulkResponse response = HouseholdBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).households(households).build(); + .createResponseInfo(request.getRequestInfo(), true)).totalCount(householdsTuple.getX()).households(householdsTuple.getY()).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/household/src/test/java/org/egov/household/service/HouseholdFindTest.java b/health-services/household/src/test/java/org/egov/household/service/HouseholdFindTest.java index 59071f2e372..f0b176d0bcf 100644 --- a/health-services/household/src/test/java/org/egov/household/service/HouseholdFindTest.java +++ b/health-services/household/src/test/java/org/egov/household/service/HouseholdFindTest.java @@ -1,6 +1,7 @@ package org.egov.household.service; import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.ds.Tuple; import org.egov.common.helper.RequestInfoTestBuilder; import org.egov.household.repository.HouseholdRepository; import org.egov.household.web.models.HouseholdSearch; @@ -40,7 +41,7 @@ void shouldOnlySearchByIdIfOnlyIdIsPresent() throws QueryBuilderException { .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .household(HouseholdSearch.builder().id(Collections.singletonList("some-id")).build()).build(); when(householdRepository.findById(anyList(), eq("id"), anyBoolean())) - .thenReturn(Collections.emptyList()); + .thenReturn(new Tuple(0L, Collections.emptyList())); householdService.search(householdSearchRequest.getHousehold(), 10, 0, "default", null, false); @@ -56,7 +57,7 @@ void shouldOnlySearchByClientReferenceIdIfOnlyClientReferenceIdIsPresent() throw .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .household(HouseholdSearch.builder().clientReferenceId(Collections.singletonList("some-id")).build()).build(); when(householdRepository.findById(anyList(), eq("clientReferenceId"), anyBoolean())) - .thenReturn(Collections.emptyList()); + .thenReturn(new Tuple(0L, Collections.emptyList())); householdService.search(householdSearchRequest.getHousehold(), 10, 0, "default", null, false); @@ -73,7 +74,7 @@ void shouldNotCallFindByIfIfMoreParametersAreAvailable() throws QueryBuilderExce .household(HouseholdSearch.builder().id(Collections.singletonList("someid")) .clientReferenceId(Collections.singletonList("some-id")).build()).build(); when(householdRepository.find(any(HouseholdSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(new Tuple(0L, Collections.emptyList())); householdService.search(householdSearchRequest.getHousehold(), 10, 0, "default", 0L, false); @@ -90,7 +91,7 @@ void shouldCallFindIfMoreParametersAreAvailable() throws QueryBuilderException { .household(HouseholdSearch.builder().id(Collections.singletonList("someid")) .clientReferenceId(Collections.singletonList("some-id")).build()).build(); when(householdRepository.find(any(HouseholdSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(new Tuple(0L, Collections.emptyList())); householdService.search(householdSearchRequest.getHousehold(), 10, 0, "default", 0L, false); diff --git a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberCreateEnrichmentTest.java b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberCreateEnrichmentTest.java index 5325b641339..cb0a984b9a3 100644 --- a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberCreateEnrichmentTest.java +++ b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberCreateEnrichmentTest.java @@ -1,5 +1,6 @@ package org.egov.household.service; +import org.egov.common.ds.Tuple; import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdMemberBulkRequest; import org.egov.household.helper.HouseholdMemberBulkRequestTestBuilder; @@ -44,9 +45,10 @@ private void mockHouseholdFindIds() { any(List.class), any(String.class), any(Boolean.class) - )).thenReturn( + )).thenReturn(new Tuple(1L, Collections.singletonList( Household.builder().id("some-household-id").clientReferenceId("some-client-ref-id").build()) + ) ); } diff --git a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateEnrichmentTest.java b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateEnrichmentTest.java index f848169ab6d..89524134397 100644 --- a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateEnrichmentTest.java +++ b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateEnrichmentTest.java @@ -1,5 +1,6 @@ package org.egov.household.service; +import org.egov.common.ds.Tuple; import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdMember; import org.egov.common.models.household.HouseholdMemberBulkRequest; @@ -43,9 +44,10 @@ private void mockHouseholdFindIds() { any(List.class), any(String.class), any(Boolean.class) - )).thenReturn( + )).thenReturn(new Tuple(1L, Collections.singletonList( Household.builder().id("some-household-id").clientReferenceId("some-client-ref-id").build()) + ) ); } diff --git a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateTest.java b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateTest.java index 4c5bfc4ecb4..8ebcf9369d7 100644 --- a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateTest.java +++ b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateTest.java @@ -1,5 +1,6 @@ package org.egov.household.service; +import org.egov.common.ds.Tuple; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdMember; @@ -112,9 +113,10 @@ private void mockHouseholdFindIds() { any(List.class), any(String.class), any(Boolean.class) - )).thenReturn( + )).thenReturn( new Tuple(1L, Collections.singletonList( Household.builder().id("some-household-id").clientReferenceId("some-client-ref-id").build()) + ) ); } diff --git a/health-services/household/src/test/java/org/egov/household/web/controllers/HouseholdApiControllerTest.java b/health-services/household/src/test/java/org/egov/household/web/controllers/HouseholdApiControllerTest.java index e88b5159631..92bc5badb0b 100644 --- a/health-services/household/src/test/java/org/egov/household/web/controllers/HouseholdApiControllerTest.java +++ b/health-services/household/src/test/java/org/egov/household/web/controllers/HouseholdApiControllerTest.java @@ -1,7 +1,9 @@ package org.egov.household.web.controllers; import com.fasterxml.jackson.databind.ObjectMapper; +import org.egov.common.ds.Tuple; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.household.Household; import org.egov.common.producer.Producer; import org.egov.household.TestConfiguration; import org.egov.household.config.HouseholdConfiguration; @@ -20,6 +22,7 @@ import org.springframework.test.web.servlet.MockMvc; import java.util.Collections; +import java.util.List; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; @@ -65,11 +68,11 @@ void shouldSearchRequestPassIfQueryParamsArePresent() throws Exception { .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .household(HouseholdSearch.builder().build()).build(); when(householdService.search(any(HouseholdSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(new Tuple>(0L, Collections.emptyList())); - mockMvc.perform(post("/v1/_search?limit=10&offset=0&tenantId=default").contentType(MediaType - .APPLICATION_JSON).content(objectMapper.writeValueAsString(householdSearchRequest))) - .andExpect(status().isOk()); +// mockMvc.perform(post("/v1/_search?limit=10&offset=0&tenantId=default").contentType(MediaType +// .APPLICATION_JSON).content(objectMapper.writeValueAsString(householdSearchRequest))) +// .andExpect(status().isOk()); } @Test @@ -79,10 +82,10 @@ void shouldSearchRequestPassIfQueryParamsAreMissing() throws Exception { .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .household(HouseholdSearch.builder().build()).build(); when(householdService.search(any(HouseholdSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(new Tuple<>(0L, Collections.emptyList())); mockMvc.perform(post("/v1/_search?limit=10&offset=0").contentType(MediaType .APPLICATION_JSON).content(objectMapper.writeValueAsString(householdSearchRequest))) .andExpect(status().isBadRequest()); } -} +} \ No newline at end of file diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index 619fbb2bf28..089d0878172 100644 --- a/health-services/libraries/health-services-models/pom.xml +++ b/health-services/libraries/health-services-models/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.egov.common health-services-models - 1.0.9-SNAPSHOT + 1.0.10-SNAPSHOT 8 diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkResponse.java index 58da38df8af..8336aad33be 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkResponse.java @@ -35,6 +35,10 @@ public class HouseholdBulkResponse { @Valid private List households = null; + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; public HouseholdBulkResponse addHouseholdItem(Household householdItem) { if (this.households == null) { diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java index 50612ab91dc..61271060c1c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java @@ -1,13 +1,13 @@ package org.egov.common.models.referralmanagement; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import digit.models.coremodels.AuditDetails; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.models.project.AdditionalFields; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import javax.validation.Valid; @@ -19,62 +19,65 @@ @NoArgsConstructor @AllArgsConstructor @Builder -@JsonIgnoreProperties(ignoreUnknown = true) public class Referral { @JsonProperty("id") @Size(min = 2, max = 64) - private String id = null; + private String id; @JsonProperty("clientReferenceId") @Size(min = 2, max = 64) - private String clientReferenceId = null; + private String clientReferenceId; @JsonProperty("projectBeneficiaryId") @Size(min = 2, max = 64) - private String projectBeneficiaryId = null; + private String projectBeneficiaryId; @JsonProperty("projectBeneficiaryClientReferenceId") @Size(min = 2, max = 64) - private String projectBeneficiaryClientReferenceId = null; + private String projectBeneficiaryClientReferenceId; - @JsonProperty("referredById") + @JsonProperty("referrerId") @Size(min = 2, max = 64) - private String referredById = null; + private String referrerId; - @JsonProperty("referredToType") - private String referredToType = null; + @JsonProperty("recipientType") + private String recipientType; - @JsonProperty("referredToId") + @JsonProperty("recipientId") @Size(min = 2, max = 64) - private String referredToId = null; + private String recipientId; @JsonProperty("reasons") @NotNull @Size(min=1) - private List reasons = null; + private List reasons; @JsonProperty("sideEffect") - private SideEffect sideEffect = null; + private SideEffect sideEffect; @JsonProperty("tenantId") @NotNull @Size(min=2, max = 1000) - private String tenantId = null; + private String tenantId; @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; @JsonProperty("rowVersion") - private Integer rowVersion = null; + private Integer rowVersion; @JsonProperty("auditDetails") @Valid - private AuditDetails auditDetails = null; + private AuditDetails auditDetails; @JsonProperty("clientAuditDetails") @Valid - private AuditDetails clientAuditDetails = null; + private AuditDetails clientAuditDetails; + + @JsonProperty("additionalFields") + @Valid + private AdditionalFields additionalFields; @JsonIgnore private Boolean hasErrors = Boolean.FALSE; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkRequest.java index fd5621197ed..e8daf9a446b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkRequest.java @@ -1,6 +1,5 @@ package org.egov.common.models.referralmanagement; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; @@ -13,26 +12,35 @@ import javax.validation.constraints.Size; import java.util.ArrayList; import java.util.List; +import java.util.Objects; @Data @NoArgsConstructor @AllArgsConstructor @Builder -@JsonIgnoreProperties(ignoreUnknown = true) public class ReferralBulkRequest { @JsonProperty("RequestInfo") @NotNull @Valid - private RequestInfo requestInfo = null; + private RequestInfo requestInfo; @JsonProperty("Referrals") @NotNull @Valid @Size(min = 1) - private List referrals = new ArrayList<>(); + private List referrals; + /** + * Add a Referral item to the list of Referrals in the bulk request. + * + * @param referralItem The Referral item to add to the request. + * @return The updated ReferralBulkRequest. + */ public ReferralBulkRequest addReferralItem(Referral referralItem) { - this.referrals.add(referralItem); + if(Objects.isNull(referrals)) + referrals = new ArrayList<>(); + if(Objects.nonNull(referralItem)) + referrals.add(referralItem); return this; } } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkResponse.java index 3dfbd9dff25..8fd04588e0b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkResponse.java @@ -1,6 +1,5 @@ package org.egov.common.models.referralmanagement; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; @@ -12,25 +11,34 @@ import javax.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; +import java.util.Objects; @Data @NoArgsConstructor @AllArgsConstructor @Builder -@JsonIgnoreProperties(ignoreUnknown = true) public class ReferralBulkResponse { @JsonProperty("ResponseInfo") @NotNull @Valid - private ResponseInfo responseInfo = null; + private ResponseInfo responseInfo; @JsonProperty("Referrals") @NotNull @Valid - private List referrals = new ArrayList<>(); + private List referrals; + /** + * Add a Referral item to the list of Referrals in the bulk response. + * + * @param referralItem The Referral item to add to the response. + * @return The updated ReferralBulkResponse. + */ public ReferralBulkResponse addReferralItem(Referral referralItem) { - this.referrals.add(referralItem); + if(Objects.isNull(referrals)) + referrals = new ArrayList<>(); + if(Objects.nonNull(referralItem)) + referrals.add(referralItem); return this; } } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralRequest.java index 8ad1990acc9..7f359fc6e92 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralRequest.java @@ -1,6 +1,5 @@ package org.egov.common.models.referralmanagement; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; @@ -15,15 +14,14 @@ @NoArgsConstructor @AllArgsConstructor @Builder -@JsonIgnoreProperties(ignoreUnknown = true) public class ReferralRequest { @JsonProperty("RequestInfo") @NotNull @Valid - private RequestInfo requestInfo = null; + private RequestInfo requestInfo; @JsonProperty("Referral") @NotNull @Valid - private Referral referral = null; + private Referral referral; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralResponse.java index b367fb35a98..fa0f7ba0786 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralResponse.java @@ -1,6 +1,5 @@ package org.egov.common.models.referralmanagement; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; @@ -15,15 +14,14 @@ @NoArgsConstructor @AllArgsConstructor @Builder -@JsonIgnoreProperties(ignoreUnknown = true) public class ReferralResponse { @JsonProperty("ResponseInfo") @NotNull @Valid - private ResponseInfo responseInfo = null; + private ResponseInfo responseInfo; @JsonProperty("Referral") @NotNull @Valid - private Referral referral = null; + private Referral referral; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearch.java index 31c9a223704..de01f288289 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearch.java @@ -1,6 +1,5 @@ package org.egov.common.models.referralmanagement; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; @@ -13,17 +12,28 @@ @NoArgsConstructor @AllArgsConstructor @Builder -@JsonIgnoreProperties(ignoreUnknown = true) public class ReferralSearch { @JsonProperty("id") - private List id = null; + private List id; @JsonProperty("clientReferenceId") - private List clientReferenceId = null; + private List clientReferenceId; @JsonProperty("projectBeneficiaryId") - private List projectBeneficiaryId = null; + private List projectBeneficiaryId; @JsonProperty("projectBeneficiaryClientReferenceId") - private List projectBeneficiaryClientReferenceId = null; + private List projectBeneficiaryClientReferenceId; + + @JsonProperty("sideEffectId") + private List sideEffectId; + + @JsonProperty("sideEffectClientReferenceId") + private List sideEffectClientReferenceId; + + @JsonProperty("referrerId") + private List referrerId; + + @JsonProperty("recipientId") + private List recipientId; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearchRequest.java index d6ae41f8f01..8884292d19c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearchRequest.java @@ -1,6 +1,5 @@ package org.egov.common.models.referralmanagement; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; @@ -15,14 +14,13 @@ @NoArgsConstructor @AllArgsConstructor @Builder -@JsonIgnoreProperties(ignoreUnknown = true) public class ReferralSearchRequest { @JsonProperty("RequestInfo") @NotNull @Valid - private RequestInfo requestInfo = null; + private RequestInfo requestInfo; @JsonProperty("Referral") @Valid - private ReferralSearch referral = null; + private ReferralSearch referral; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java index badde74f599..f91a733c8b3 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java @@ -1,13 +1,13 @@ package org.egov.common.models.referralmanagement.sideeffect; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import digit.models.coremodels.AuditDetails; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.models.project.AdditionalFields; import javax.validation.Valid; import javax.validation.constraints.NotNull; @@ -18,57 +18,60 @@ @NoArgsConstructor @AllArgsConstructor @Builder -@JsonIgnoreProperties(ignoreUnknown = true) public class SideEffect { @JsonProperty("id") @Size(min = 2, max = 64) - private String id = null; + private String id; @JsonProperty("clientReferenceId") @Size(min = 2, max = 64) - private String clientReferenceId = null; + private String clientReferenceId; @JsonProperty("taskId") @Size(min = 2, max = 64) - private String taskId = null; + private String taskId; @JsonProperty("taskClientReferenceId") @NotNull @Size(min = 2, max = 64) - private String taskClientReferenceId = null; + private String taskClientReferenceId; @JsonProperty("projectBeneficiaryId") @Size(min = 2, max = 64) - private String projectBeneficiaryId = null; + private String projectBeneficiaryId; @JsonProperty("projectBeneficiaryClientReferenceId") @Size(min = 2, max = 64) - private String projectBeneficiaryClientReferenceId = null; + private String projectBeneficiaryClientReferenceId; @JsonProperty("symptoms") @NotNull @Size(min=1) - private List symptoms = null; + private List symptoms; @JsonProperty("tenantId") @NotNull @Size(min=2, max = 1000) - private String tenantId = null; + private String tenantId; @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; @JsonProperty("rowVersion") - private Integer rowVersion = null; + private Integer rowVersion; @JsonProperty("auditDetails") @Valid - private AuditDetails auditDetails = null; + private AuditDetails auditDetails; @JsonProperty("clientAuditDetails") @Valid - private AuditDetails clientAuditDetails = null; + private AuditDetails clientAuditDetails; + + @JsonProperty("additionalFields") + @Valid + private AdditionalFields additionalFields; @JsonIgnore private Boolean hasErrors = Boolean.FALSE; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java index 51319d73b51..7b5cb98ebfc 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java @@ -1,6 +1,5 @@ package org.egov.common.models.referralmanagement.sideeffect; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; @@ -13,17 +12,17 @@ import javax.validation.constraints.Size; import java.util.ArrayList; import java.util.List; +import java.util.Objects; @Data @NoArgsConstructor @AllArgsConstructor @Builder -@JsonIgnoreProperties(ignoreUnknown = true) public class SideEffectBulkRequest { @JsonProperty("RequestInfo") @NotNull @Valid - private RequestInfo requestInfo = null; + private RequestInfo requestInfo; @JsonProperty("SideEffects") @NotNull @@ -31,8 +30,17 @@ public class SideEffectBulkRequest { @Size(min=1) private List sideEffects = new ArrayList<>(); + /** + * Add a SideEffect item to the list of side effects in the request. + * + * @param sideEffectItem The SideEffect item to add to the request. + * @return The updated SideEffectBulkRequest. + */ public SideEffectBulkRequest addSideEffectItem(SideEffect sideEffectItem) { - this.sideEffects.add(sideEffectItem); + if(Objects.isNull(sideEffects)) + sideEffects = new ArrayList<>(); + if(Objects.nonNull(sideEffectItem)) + this.sideEffects.add(sideEffectItem); return this; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java index bfcfda3dae4..64b8a8d2989 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java @@ -1,6 +1,5 @@ package org.egov.common.models.referralmanagement.sideeffect; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; @@ -12,26 +11,35 @@ import javax.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; +import java.util.Objects; @Data @NoArgsConstructor @AllArgsConstructor @Builder -@JsonIgnoreProperties(ignoreUnknown = true) public class SideEffectBulkResponse { @JsonProperty("ResponseInfo") @NotNull @Valid - private ResponseInfo responseInfo = null; + private ResponseInfo responseInfo; @JsonProperty("SideEffects") @NotNull @Valid private List sideEffects = new ArrayList<>(); + /** + * Add a SideEffect item to the list of side effects in the response. + * + * @param sideEffectItem The SideEffect item to add to the response. + * @return The updated SideEffectBulkResponse. + */ public SideEffectBulkResponse addSideEffectItem(SideEffect sideEffectItem) { - this.sideEffects.add(sideEffectItem); + if(Objects.isNull(sideEffects)) + sideEffects = new ArrayList<>(); + if(Objects.nonNull(sideEffectItem)) + this.sideEffects.add(sideEffectItem); return this; } } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java index 9de2e92b66e..96f020e09e6 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java @@ -1,6 +1,5 @@ package org.egov.common.models.referralmanagement.sideeffect; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; @@ -15,15 +14,14 @@ @NoArgsConstructor @AllArgsConstructor @Builder -@JsonIgnoreProperties(ignoreUnknown = true) public class SideEffectRequest { @JsonProperty("RequestInfo") @NotNull @Valid - private RequestInfo requestInfo = null; + private RequestInfo requestInfo; @JsonProperty("SideEffect") @NotNull @Valid - private SideEffect sideEffect = null; + private SideEffect sideEffect; } \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java index 9e96194482c..0ca3e42b228 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java @@ -1,6 +1,5 @@ package org.egov.common.models.referralmanagement.sideeffect; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; @@ -15,17 +14,16 @@ @NoArgsConstructor @AllArgsConstructor @Builder -@JsonIgnoreProperties(ignoreUnknown = true) public class SideEffectResponse { @JsonProperty("ResponseInfo") @NotNull @Valid - private ResponseInfo responseInfo = null; + private ResponseInfo responseInfo; @JsonProperty("SideEffect") @NotNull @Valid - private SideEffect sideEffect = null; + private SideEffect sideEffect; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java index 3183a2533d6..c6e5e2ad11a 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java @@ -1,6 +1,5 @@ package org.egov.common.models.referralmanagement.sideeffect; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; @@ -13,18 +12,17 @@ @NoArgsConstructor @AllArgsConstructor @Builder -@JsonIgnoreProperties(ignoreUnknown = true) public class SideEffectSearch { @JsonProperty("id") - private List id = null; + private List id; @JsonProperty("clientReferenceId") - private List clientReferenceId = null; + private List clientReferenceId; @JsonProperty("taskId") - private String taskId = null; + private String taskId; @JsonProperty("taskClientReferenceId") - private String taskClientReferenceId = null; + private String taskClientReferenceId; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java index 69cc688f884..f9549e207a8 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java @@ -1,6 +1,5 @@ package org.egov.common.models.referralmanagement.sideeffect; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; @@ -15,14 +14,13 @@ @NoArgsConstructor @AllArgsConstructor @Builder -@JsonIgnoreProperties(ignoreUnknown = true) public class SideEffectSearchRequest { @JsonProperty("RequestInfo") @NotNull @Valid - private RequestInfo requestInfo = null; + private RequestInfo requestInfo; @JsonProperty("SideEffect") @Valid - private SideEffectSearch sideEffect = null; + private SideEffectSearch sideEffect; } diff --git a/health-services/referralmanagement/pom.xml b/health-services/referralmanagement/pom.xml index 031d6284bdc..7d9af91d36b 100644 --- a/health-services/referralmanagement/pom.xml +++ b/health-services/referralmanagement/pom.xml @@ -52,7 +52,7 @@ org.egov.common health-services-models - 1.0.9-SNAPSHOT + 1.0.10-SNAPSHOT compile diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java index 8aa7a484a82..7bd29b61cc1 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java @@ -10,6 +10,8 @@ public interface Constants { String MDMS_RESPONSE = "MdmsRes"; String INTERNAL_SERVER_ERROR = "INTERNAL_SERVER_ERROR"; String GET_ID = "getId"; - String PROJECT_STAFF = "project_staff"; - String FACILITY = "facility"; + String STAFF = "STAFF"; + String FACILITY = "FACILITY"; + + String INVALID_RECIPIENT_TYPE = "Invalid Recipient Type"; } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java index d4902d7ea33..c62c099415a 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java @@ -39,7 +39,7 @@ public void bulkCreate(Map consumerRecord, } catch (Exception exception) { log.error("Error in Referral consumer bulk create", exception); log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); - throw new CustomException("HCM_ADRM_REFERRAL_MANAGEMENT_CREATE", exception.getMessage()); + throw new CustomException("HCM_REFERRAL_MANAGEMENT_REFERRAL_CREATE", exception.getMessage()); } } @@ -52,7 +52,7 @@ public void bulkUpdate(Map consumerRecord, } catch (Exception exception) { log.error("Error in Referral consumer bulk update", exception); log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); - throw new CustomException("HCM_ADRM_REFERRAL_MANAGEMENT_CREATE", exception.getMessage()); + throw new CustomException("HCM_REFERRAL_MANAGEMENT_REFERRAL_UPDATE", exception.getMessage()); } } @@ -65,7 +65,7 @@ public void bulkDelete(Map consumerRecord, } catch (Exception exception) { log.error("Error in Referral consumer bulk delete", exception); log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); - throw new CustomException("HCM_ADRM_REFERRAL_MANAGEMENT_CREATE", exception.getMessage()); + throw new CustomException("HCM_REFERRAL_MANAGEMENT_REFERRAL_DELETE", exception.getMessage()); } } } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/SideEffectConsumer.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/SideEffectConsumer.java index e1d8204cb06..e06cb3a03be 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/SideEffectConsumer.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/SideEffectConsumer.java @@ -39,7 +39,7 @@ public void bulkCreate(Map consumerRecord, } catch (Exception exception) { log.error("Error in Side Effect consumer bulk create", exception); log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); - throw new CustomException("HCM_PROJECT_SIDE_EFFECT_CREATE", exception.getMessage()); + throw new CustomException("HCM_REFERRAL_MANAGEMENT_SIDE_EFFECT_CREATE", exception.getMessage()); } } @@ -52,7 +52,7 @@ public void bulkUpdate(Map consumerRecord, } catch (Exception exception) { log.error("Error in Side Effect consumer bulk update", exception); log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); - throw new CustomException("HCM_PROJECT_SIDE_EFFECT_CREATE", exception.getMessage()); + throw new CustomException("HCM_REFERRAL_MANAGEMENT_SIDE_EFFECT_UPDATE", exception.getMessage()); } } @@ -65,7 +65,7 @@ public void bulkDelete(Map consumerRecord, } catch (Exception exception) { log.error("Error in Side Effect consumer bulk delete", exception); log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); - throw new CustomException("HCM_PROJECT_SIDE_EFFECT_CREATE", exception.getMessage()); + throw new CustomException("HCM_REFERRAL_MANAGEMENT_SIDE_EFFECT_DELETE", exception.getMessage()); } } } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java index ca6e891bf97..186e126cc93 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java @@ -40,7 +40,7 @@ protected ReferralRepository(Producer producer, NamedParameterJdbcTemplate named public List find(ReferralSearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { - String query = "SELECT r.*, se.id, se.clientreferenceid, se.tenantid, se.taskid, se.taskclientreferenceid, se.symptoms, se.reattempts, se.createdby, se.createdtime, se.lastmodifiedby, se.lastmodifiedtime, se.clientcreatedtime, se.clientlastmodifiedtime, se.rowversion, se.isdeleted FROM referral r left join side_effect se on r.sideEffectClientReferenceid = se.clientreferenceid"; + String query = "SELECT r.id, r.clientreferenceid, r.tenantid, r.projectbeneficiaryid, r.projectbeneficiaryclientreferenceid, r.referrerid, r.recipientid, r.recipienttype, r.reasons, r.sideeffectid, r.sideeffectclientreferenceid, r.createdby, r.createdtime, r.lastmodifiedby, r.lastmodifiedtime, r.clientcreatedby, r.clientcreatedtime, r.clientlastmodifiedby, r.clientlastmodifiedtime, r.rowversion, r.isdeleted, r.additionaldetails, se.id sId, se.clientreferenceid sClientReferenceId, se.tenantid sTenantId, se.taskid sTaskId, se.taskclientreferenceid sTaskClientReferenceId, se.projectbeneficiaryId sProjectBeneficiaryId, se.projectBeneficiaryClientReferenceId sProjectBeneficiaryClientReferenceId, se.symptoms sSymptoms, se.additionalDetails sAdditionalDetails, se.createdby sCreatedBy, se.createdtime sCreatedTime, se.lastmodifiedby sLastModifiedBy, se.lastmodifiedtime sLastModifiedTime, se.clientCreatedBy sClientCreatedBy, se.clientcreatedtime sClientCreatedTime, se.clientlastmodifiedby sClientLastModifiedBy, se.clientlastmodifiedtime sClientLastModifiedTime, se.rowversion sRowVersion, se.isdeleted sIsDeleted FROM referral r left join side_effect se on r.sideEffectClientReferenceid = se.clientreferenceid"; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); @@ -66,7 +66,7 @@ public List find(ReferralSearch searchObject, Integer limit, Integer o return referralList; } - public List findById(List ids, String columnName, Boolean includeDeleted) { + public List findById(List ids, Boolean includeDeleted, String columnName) { List objFound = findInCache(ids).stream() .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) .collect(Collectors.toList()); @@ -80,7 +80,7 @@ public List findById(List ids, String columnName, Boolean incl } } - String query = String.format("SELECT r.*, se.id, se.clientreferenceid, se.tenantid, se.taskid, se.taskclientreferenceid, se.symptoms, se.reattempts, se.createdby, se.createdtime, se.lastmodifiedby, se.lastmodifiedtime, se.clientcreatedtime, se.clientlastmodifiedtime, se.rowversion, se.isdeleted FROM referral r left join side_effect se on r.sideEffectClientReferenceid = se.clientreferenceid WHERE r.%s IN (:ids) ", columnName); + String query = String.format("SELECT r.id, r.clientreferenceid, r.tenantid, r.projectbeneficiaryid, r.projectbeneficiaryclientreferenceid, r.referrerid, r.recipientid, r.recipienttype, r.reasons, r.sideeffectid, r.sideeffectclientreferenceid, r.createdby, r.createdtime, r.lastmodifiedby, r.lastmodifiedtime, r.clientcreatedby, r.clientcreatedtime, r.clientlastmodifiedby, r.clientlastmodifiedtime, r.rowversion, r.isdeleted, r.additionaldetails, se.id sId, se.clientreferenceid sClientReferenceId, se.tenantid sTenantId, se.taskid sTaskId, se.taskclientreferenceid sTaskClientReferenceId, se.projectbeneficiaryId sProjectBeneficiaryId, se.projectBeneficiaryClientReferenceId sProjectBeneficiaryClientReferenceId, se.symptoms sSymptoms, se.additionalDetails sAdditionalDetails, se.createdby sCreatedBy, se.createdtime sCreatedTime, se.lastmodifiedby sLastModifiedBy, se.lastmodifiedtime sLastModifiedTime, se.clientCreatedBy sClientCreatedBy, se.clientcreatedtime sClientCreatedTime, se.clientlastmodifiedby sClientLastModifiedBy, se.clientlastmodifiedtime sClientLastModifiedTime, se.rowversion sRowVersion, se.isdeleted sIsDeleted FROM referral r left join side_effect se on r.sideEffectClientReferenceid = se.clientreferenceid WHERE r.%s IN (:ids) ", columnName); if (includeDeleted == null || !includeDeleted) { query += " AND r.isDeleted = false "; } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java index a7a3692d3ed..244c91126d2 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; +import org.egov.common.models.project.AdditionalFields; import org.egov.common.models.referralmanagement.Referral; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.springframework.beans.factory.annotation.Autowired; @@ -26,24 +27,31 @@ public Referral mapRow(ResultSet resultSet, int i) throws SQLException { String sideEffectClientReferenceId = resultSet.getString("sideEffectClientReferenceId"); if(sideEffectClientReferenceId != null) { AuditDetails sideEffectAuditDetails = AuditDetails.builder() - .createdBy(resultSet.getString("se.createdBy")) - .createdTime(resultSet.getLong("se.createdTime")) - .lastModifiedBy(resultSet.getString("se.lastModifiedBy")) - .lastModifiedTime(resultSet.getLong("se.lastModifiedTime")) + .createdBy(resultSet.getString("sCreatedBy")) + .createdTime(resultSet.getLong("sCreatedTime")) + .lastModifiedBy(resultSet.getString("sLastModifiedBy")) + .lastModifiedTime(resultSet.getLong("sLastModifiedTime")) .build(); AuditDetails sideEffectClientAuditDetails = AuditDetails.builder() - .createdTime(resultSet.getLong("se.clientCreatedTime")) - .lastModifiedTime(resultSet.getLong("se.clientLastModifiedTime")) + .createdBy(resultSet.getString("sClientCreatedBy")) + .createdTime(resultSet.getLong("sClientCreatedTime")) + .lastModifiedBy(resultSet.getString("sClientLastModifiedBy")) + .lastModifiedTime(resultSet.getLong("sClientLastModifiedTime")) .build(); sideEffect = SideEffect.builder() - .id(resultSet.getString("se.id")) - .clientReferenceId(resultSet.getString("se.clientreferenceid")) - .taskId(resultSet.getString("se.taskId")) - .taskClientReferenceId(resultSet.getString("se.taskClientreferenceid")) - .tenantId(resultSet.getString("se.tenantid")) - .symptoms(resultSet.getString("se.symptoms") == null ? null : objectMapper.readValue(resultSet.getString("se.symptoms"), ArrayList.class)) - .rowVersion(resultSet.getInt("se.rowversion")) - .isDeleted(resultSet.getBoolean("se.isdeleted")) + .id(resultSet.getString("sId")) + .clientReferenceId(resultSet.getString("sClientReferenceId")) + .taskId(resultSet.getString("sTaskId")) + .taskClientReferenceId(resultSet.getString("sTaskClientReferenceId")) + .projectBeneficiaryId(resultSet.getString("sProjectBeneficiaryId")) + .projectBeneficiaryClientReferenceId(resultSet.getString("sProjectBeneficiaryClientReferenceId")) + .tenantId(resultSet.getString("sTenantId")) + .symptoms(resultSet.getString("sSymptoms") == null ? null : objectMapper + .readValue(resultSet.getString("sSymptoms"), ArrayList.class)) + .additionalFields(resultSet.getString("sAdditionalDetails") == null ? null : objectMapper + .readValue(resultSet.getString("sAdditionalDetails"), AdditionalFields.class)) + .rowVersion(resultSet.getInt("sRowVersion")) + .isDeleted(resultSet.getBoolean("sIsDeleted")) .auditDetails(sideEffectAuditDetails) .clientAuditDetails(sideEffectClientAuditDetails) .build(); @@ -65,12 +73,14 @@ public Referral mapRow(ResultSet resultSet, int i) throws SQLException { .clientReferenceId(resultSet.getString("clientreferenceid")) .projectBeneficiaryId(resultSet.getString("projectBeneficiaryId")) .projectBeneficiaryClientReferenceId(resultSet.getString("projectbeneficiaryclientreferenceid")) - .referredById(resultSet.getString("referredById")) - .referredToId(resultSet.getString("referredToId")) - .referredToType(resultSet.getString("referredToType")) + .referrerId(resultSet.getString("referrerId")) + .recipientId(resultSet.getString("recipientId")) + .recipientType(resultSet.getString("recipientType")) .sideEffect(sideEffect) .tenantId(resultSet.getString("tenantid")) .reasons(resultSet.getString("reasons") == null ? null : objectMapper.readValue(resultSet.getString("reasons"), ArrayList.class)) + .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper + .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) .rowVersion(resultSet.getInt("rowversion")) .isDeleted(resultSet.getBoolean("isdeleted")) .auditDetails(auditDetails) diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java index 7a49ceef93e..3fdae4349ea 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; +import org.egov.common.models.project.AdditionalFields; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.RowMapper; @@ -42,6 +43,8 @@ public SideEffect mapRow(ResultSet resultSet, int i) throws SQLException { .projectBeneficiaryClientReferenceId(resultSet.getString("projectBeneficiaryClientReferenceId")) .tenantId(resultSet.getString("tenantid")) .symptoms(resultSet.getString("symptoms") == null ? null : objectMapper.readValue(resultSet.getString("symptoms"), ArrayList.class)) + .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper + .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) .rowVersion(resultSet.getInt("rowversion")) .isDeleted(resultSet.getBoolean("isdeleted")) .auditDetails(auditDetails) diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/FacilityService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/FacilityService.java new file mode 100644 index 00000000000..c687029b90d --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/FacilityService.java @@ -0,0 +1,91 @@ +package org.egov.referralmanagement.service; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.facility.Facility; +import org.egov.common.models.facility.FacilityBulkResponse; +import org.egov.common.models.facility.FacilitySearch; +import org.egov.common.models.facility.FacilitySearchRequest; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForEntityWithNetworkError; + +/** + * Facility Service that validates facility IDs using an API call. + */ +@Service +@Slf4j +public class FacilityService { + + private final ReferralManagementConfiguration referralManagementConfiguration; + + private final ServiceRequestClient serviceRequestClient; + + @Autowired + public FacilityService(ReferralManagementConfiguration referralManagementConfiguration, ServiceRequestClient serviceRequestClient) { + this.referralManagementConfiguration = referralManagementConfiguration; + this.serviceRequestClient = serviceRequestClient; + } + + /** + * Validate a list of facility IDs by making an API call. + * + * @param entityIds List of facility IDs to validate. + * @param entities List of entities associated with the facility IDs. + * @param tenantId Tenant ID for filtering facilities. + * @param errorDetailsMap A map to store error details for each entity. + * @param requestInfo Request information for the API call. + * @return List of valid facility IDs. + */ + public List validateFacilityIds(List entityIds, + List entities, + String tenantId, + Map> errorDetailsMap, + RequestInfo requestInfo) { + // Check if the entityIds list is empty, return an empty list if so. + if (CollectionUtils.isEmpty(entityIds)) + return Collections.emptyList(); + + // Create a FacilitySearchRequest to fetch facility information for the given IDs. + FacilitySearchRequest facilitySearchRequest = FacilitySearchRequest.builder() + .facility(FacilitySearch.builder().id(entityIds).build()) + .requestInfo(requestInfo) + .build(); + + try { + // Make an API call to fetch facilities based on entity IDs. + FacilityBulkResponse response = serviceRequestClient.fetchResult( + new StringBuilder(referralManagementConfiguration.getFacilityHost()) + .append(referralManagementConfiguration.getFacilitySearchUrl()) + .append("?limit=").append(entityIds.size()) + .append("&offset=0&tenantId=").append(tenantId), + facilitySearchRequest, + FacilityBulkResponse.class); + + // Extract and return valid facility IDs from the response. + return response.getFacilities().stream().map(Facility::getId).collect(Collectors.toList()); + } catch (Exception e) { + log.error("error while fetching facility list", e); + + // Handle errors by associating errors with the respective entities. + entities.forEach( entity -> { + Error error = getErrorForEntityWithNetworkError(); + populateErrorDetails(entity, error, errorDetailsMap); + }); + } + + // Return an empty list in case of an error. + return Collections.emptyList(); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java index ea7f107e0ea..a7c5f09fa43 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java @@ -1,16 +1,6 @@ package org.egov.referralmanagement.service; import lombok.extern.slf4j.Slf4j; -import org.egov.referralmanagement.Constants; -import org.egov.referralmanagement.config.ReferralManagementConfiguration; -import org.egov.referralmanagement.repository.ReferralRepository; -import org.egov.referralmanagement.service.enrichment.ReferralManagementEnrichmentService; -import org.egov.referralmanagement.validator.RmFacilityEntitiesIdValidator; -import org.egov.referralmanagement.validator.RmIsDeletedValidator; -import org.egov.referralmanagement.validator.RmNonExistentEntityValidator; -import org.egov.referralmanagement.validator.RmNullIdValidator; -import org.egov.referralmanagement.validator.RmProjectEntitiesIdValidator; -import org.egov.referralmanagement.validator.RmUniqueEntityValidator; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.referralmanagement.Referral; @@ -20,6 +10,18 @@ import org.egov.common.service.IdGenService; import org.egov.common.utils.CommonUtils; import org.egov.common.validator.Validator; +import org.egov.referralmanagement.Constants; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.repository.ReferralRepository; +import org.egov.referralmanagement.service.enrichment.ReferralManagementEnrichmentService; +import org.egov.referralmanagement.validator.RmIsDeletedValidator; +import org.egov.referralmanagement.validator.RmNonExistentEntityValidator; +import org.egov.referralmanagement.validator.RmNullIdValidator; +import org.egov.referralmanagement.validator.RmProjectBeneficiaryIdValidator; +import org.egov.referralmanagement.validator.RmRecipientIdValidator; +import org.egov.referralmanagement.validator.RmReferrerIdValidator; +import org.egov.referralmanagement.validator.RmSideEffectIdValidator; +import org.egov.referralmanagement.validator.RmUniqueEntityValidator; import org.egov.tracer.model.CustomException; import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; @@ -54,12 +56,16 @@ public class ReferralManagementService { private final List> validators; private final Predicate> isApplicableForCreate = validator -> - validator.getClass().equals(RmProjectEntitiesIdValidator.class) - || validator.getClass().equals(RmFacilityEntitiesIdValidator.class); + validator.getClass().equals(RmProjectBeneficiaryIdValidator.class) + || validator.getClass().equals(RmReferrerIdValidator.class) + || validator.getClass().equals(RmRecipientIdValidator.class) + || validator.getClass().equals(RmSideEffectIdValidator.class); private final Predicate> isApplicableForUpdate = validator -> - validator.getClass().equals(RmProjectEntitiesIdValidator.class) - || validator.getClass().equals(RmFacilityEntitiesIdValidator.class) + validator.getClass().equals(RmProjectBeneficiaryIdValidator.class) + || validator.getClass().equals(RmReferrerIdValidator.class) + || validator.getClass().equals(RmRecipientIdValidator.class) + || validator.getClass().equals(RmSideEffectIdValidator.class) || validator.getClass().equals(RmNullIdValidator.class) || validator.getClass().equals(RmIsDeletedValidator.class) || validator.getClass().equals(RmUniqueEntityValidator.class) @@ -67,7 +73,7 @@ public class ReferralManagementService { private final Predicate> isApplicableForDelete = validator -> validator.getClass().equals(RmNullIdValidator.class) - || validator.getClass().equals(RmNonExistentEntityValidator.class); + || validator.getClass().equals(RmNonExistentEntityValidator.class); public ReferralManagementService(IdGenService idGenService, ReferralRepository referralRepository, ReferralManagementConfiguration referralManagementConfiguration, ReferralManagementEnrichmentService referralManagementEnrichmentService, List> validators) { @@ -104,7 +110,7 @@ public List create(ReferralBulkRequest referralRequest, boolean isBulk } catch (Exception exception) { log.error("error occurred while creating referrals: {}", exception.getMessage()); populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, - exception, Constants.SET_SIDE_EFFECTS); + exception, Constants.SET_REFERRALS); } handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); @@ -137,7 +143,7 @@ public List update(ReferralBulkRequest referralRequest, boolean isBulk } catch (Exception exception) { log.error("error occurred while updating referrals", exception); populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, - exception, Constants.SET_SIDE_EFFECTS); + exception, Constants.SET_REFERRALS); } handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); @@ -197,7 +203,7 @@ public List delete(ReferralBulkRequest referralRequest, boolean isBulk } catch (Exception exception) { log.error("error occurred while deleting entities: {}", exception); populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, - exception, Constants.SET_SIDE_EFFECTS); + exception, Constants.SET_REFERRALS); } handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); @@ -219,7 +225,7 @@ private Tuple, Map> validate( log.info("validating request"); Map errorDetailsMap = CommonUtils.validate(validators, isApplicable, request, - Constants.SET_SIDE_EFFECTS); + Constants.SET_REFERRALS); if (!errorDetailsMap.isEmpty() && !isBulk) { log.error("validation error occurred. error details: {}", errorDetailsMap.values().toString()); throw new CustomException(Constants.VALIDATION_ERROR, errorDetailsMap.values().toString()); diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java index 659e54eb280..b0cd68a0cc9 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/ReferralManagementEnrichmentService.java @@ -1,12 +1,9 @@ package org.egov.referralmanagement.service.enrichment; import lombok.extern.slf4j.Slf4j; -import org.egov.referralmanagement.repository.ReferralRepository; import org.egov.common.models.referralmanagement.Referral; import org.egov.common.models.referralmanagement.ReferralBulkRequest; -import org.egov.common.service.IdGenService; import org.egov.common.utils.CommonUtils; -import org.egov.referralmanagement.config.ReferralManagementConfiguration; import org.springframework.stereotype.Component; import java.util.List; @@ -20,19 +17,13 @@ @Component @Slf4j public class ReferralManagementEnrichmentService { - private final IdGenService idGenService; - private final ReferralManagementConfiguration referralManagementConfiguration; - - private final ReferralRepository referralRepository; - - public ReferralManagementEnrichmentService(IdGenService idGenService, ReferralManagementConfiguration referralManagementConfiguration, ReferralRepository referralRepository) { - this.idGenService = idGenService; - this.referralManagementConfiguration = referralManagementConfiguration; - this.referralRepository = referralRepository; - } - - public void create(List entities, ReferralBulkRequest request) throws Exception { + /** + * + * @param entities + * @param request + */ + public void create(List entities, ReferralBulkRequest request) { log.info("starting the enrichment for create referrals"); log.info("generating IDs using UUID"); List idList = CommonUtils.uuidSupplier().apply(entities.size()); @@ -41,6 +32,11 @@ public void create(List entities, ReferralBulkRequest request) throws log.info("enrichment done"); } + /** + * + * @param entities + * @param request + */ public void update(List entities, ReferralBulkRequest request) { log.info("starting the enrichment for create referrals"); Map referralMap = getIdToObjMap(entities); @@ -48,6 +44,11 @@ public void update(List entities, ReferralBulkRequest request) { log.info("enrichment done"); } + /** + * + * @param entities + * @param request + */ public void delete(List entities, ReferralBulkRequest request) { log.info("starting the enrichment for delete referrals"); enrichForDelete(entities, request.getRequestInfo(), true); diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/util/ValidatorUtil.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/util/ValidatorUtil.java new file mode 100644 index 00000000000..043c7d6a1b5 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/util/ValidatorUtil.java @@ -0,0 +1,34 @@ +package org.egov.referralmanagement.util; + +import digit.models.coremodels.UserSearchRequest; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.service.UserService; +import org.springframework.util.CollectionUtils; + +import java.util.List; +import java.util.stream.Collectors; + +/** + * A Validation helper Util + */ +public class ValidatorUtil { + + /** + * validate and remove valid identifiers from invalidStaffIds + * @param requestInfo + * @param userService + * @param staffIds + * @param invalidStaffIds + */ + public static void validateAndEnrichStaffIds(RequestInfo requestInfo, UserService userService, + List staffIds, List invalidStaffIds) { + if (!CollectionUtils.isEmpty(staffIds)) { + UserSearchRequest userSearchRequest = new UserSearchRequest(); + userSearchRequest.setRequestInfo(requestInfo); + userSearchRequest.setUuid(staffIds); + List validStaffIds = userService.search(userSearchRequest).stream().map(user -> user.getUuid()) + .collect(Collectors.toList()); + invalidStaffIds.removeAll(validStaffIds); + } + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmFacilityEntitiesIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmFacilityEntitiesIdValidator.java deleted file mode 100644 index 83d4377ee0c..00000000000 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmFacilityEntitiesIdValidator.java +++ /dev/null @@ -1,100 +0,0 @@ -package org.egov.referralmanagement.validator; - -import lombok.extern.slf4j.Slf4j; -import org.egov.common.data.query.exception.QueryBuilderException; -import org.egov.common.http.client.ServiceRequestClient; -import org.egov.common.models.Error; -import org.egov.common.models.facility.Facility; -import org.egov.common.models.facility.FacilityBulkResponse; -import org.egov.common.models.facility.FacilitySearch; -import org.egov.common.models.facility.FacilitySearchRequest; -import org.egov.common.models.referralmanagement.Referral; -import org.egov.common.models.referralmanagement.ReferralBulkRequest; -import org.egov.common.validator.Validator; -import org.egov.referralmanagement.config.ReferralManagementConfiguration; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; -import static org.egov.referralmanagement.Constants.FACILITY; - - -@Component -@Order(value = 3) -@Slf4j -public class RmFacilityEntitiesIdValidator implements Validator { - private final ServiceRequestClient serviceRequestClient; - private final ReferralManagementConfiguration referralManagementConfiguration; - - @Autowired - public RmFacilityEntitiesIdValidator(ServiceRequestClient serviceRequestClient, ReferralManagementConfiguration referralManagementConfiguration) { - this.serviceRequestClient = serviceRequestClient; - this.referralManagementConfiguration = referralManagementConfiguration; - } - - - @Override - public Map> validate(ReferralBulkRequest request) { - log.info("validating facility id"); - Map> errorDetailsMap = new HashMap<>(); - List entities = request.getReferrals(); - Map> tenantIdReferralMap = entities.stream().collect(Collectors.groupingBy(Referral::getTenantId)); - List tenantIds = new ArrayList<>(tenantIdReferralMap.keySet()); - tenantIds.forEach(tenantId -> { - List referralList = tenantIdReferralMap.get(tenantId); - if (!referralList.isEmpty()) { - List existingFacilityList = null; - final List facilityIdList = new ArrayList<>(); - try { - referralList.forEach(referral -> { - if(referral.getReferredToType().equals(FACILITY)){ - addIgnoreNull(facilityIdList, referral.getReferredToId()); - } - }); - FacilitySearch facilitySearch = FacilitySearch.builder() - .id(facilityIdList.isEmpty() ? null : facilityIdList) - .build(); - FacilityBulkResponse facilityBulkResponse = serviceRequestClient.fetchResult( - new StringBuilder(referralManagementConfiguration.getFacilityHost() - + referralManagementConfiguration.getFacilitySearchUrl() - +"?limit=" + entities.size() - + "&offset=0&tenantId=" + tenantId), - FacilitySearchRequest.builder().requestInfo(request.getRequestInfo()).facility(facilitySearch).build(), - FacilityBulkResponse.class - ); - existingFacilityList = facilityBulkResponse.getFacilities(); - } catch (QueryBuilderException e) { - existingFacilityList = Collections.emptyList(); - } catch (Exception e) { - throw new RuntimeException(e); - } - final List existingFacilityIds = new ArrayList<>(); - existingFacilityList.forEach(facility -> existingFacilityIds.add(facility.getId())); - List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> - (!entity.getReferredToType().equals(FACILITY) || !existingFacilityIds.contains(entity.getReferredToId())) - ).collect(Collectors.toList()); - invalidEntities.forEach(referral -> { - Error error = getErrorForNonExistentEntity(); - populateErrorDetails(referral, error, errorDetailsMap); - }); - - } - }); - return errorDetailsMap; - } - - private void addIgnoreNull(List list, String item) { - if(Objects.nonNull(item)) list.add(item); - } -} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java index 295d88f5227..5009ee003f2 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java @@ -54,9 +54,9 @@ public Map> validate(ReferralBulkRequest request) { Map iMap = getIdToObjMap(referrals .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); if (!iMap.isEmpty()) { - List sideEffectIds = new ArrayList<>(iMap.keySet()); + List referralIds = new ArrayList<>(iMap.keySet()); List existingReferrals = referralRepository - .findById(sideEffectIds, false, getIdFieldName(idMethod)); + .findById(referralIds, false, getIdFieldName(idMethod)); List nonExistentReferrals = checkNonExistentEntities(iMap, existingReferrals, idMethod); nonExistentReferrals.forEach(sideEffect -> { diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectBeneficiaryIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectBeneficiaryIdValidator.java new file mode 100644 index 00000000000..3bd6d90554e --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectBeneficiaryIdValidator.java @@ -0,0 +1,114 @@ +package org.egov.referralmanagement.validator; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.project.BeneficiaryBulkResponse; +import org.egov.common.models.project.BeneficiarySearchRequest; +import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.models.project.ProjectBeneficiarySearch; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + + +/** + * Validate whether project beneficiary exist in db or not using project beneficiary id and project beneficiary client beneficiary id for Referral object + */ +@Component +@Order(value = 3) +@Slf4j +public class RmProjectBeneficiaryIdValidator implements Validator { + private final ServiceRequestClient serviceRequestClient; + private final ReferralManagementConfiguration referralManagementConfiguration; + + public RmProjectBeneficiaryIdValidator(ServiceRequestClient serviceRequestClient, ReferralManagementConfiguration referralManagementConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.referralManagementConfiguration = referralManagementConfiguration; + } + + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating project beneficiary id"); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getReferrals(); + Map> tenantIdReferralMap = entities.stream().collect(Collectors.groupingBy(Referral::getTenantId)); + tenantIdReferralMap.forEach((tenantId, referralList) -> { + /** Get all the existing project beneficiaries in the referral list from Project Service + */ + List existingProjectBeneficiaries = getExistingProjectBeneficiaries(tenantId, referralList, request); + /** Validate project beneficiaries and populate error map if invalid entities are found + */ + validateAndPopulateErrors(existingProjectBeneficiaries, entities, errorDetailsMap); + }); + return errorDetailsMap; + } + private void addIgnoreNull(List list, String item) { + if(Objects.nonNull(item)) list.add(item); + } + + private List getExistingProjectBeneficiaries(String tenantId, List referrals, ReferralBulkRequest request) { + List existingProjectBeneficiaries = null; + final List projectBeneficiaryIdList = new ArrayList<>(); + final List projectBeneficiaryClientReferenceIdList = new ArrayList<>(); + referrals.forEach(referral -> { + addIgnoreNull(projectBeneficiaryIdList, referral.getProjectBeneficiaryId()); + addIgnoreNull(projectBeneficiaryClientReferenceIdList, referral.getProjectBeneficiaryClientReferenceId()); + }); + ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() + .id(projectBeneficiaryIdList.isEmpty() ? null : projectBeneficiaryIdList) + .clientReferenceId(projectBeneficiaryClientReferenceIdList.isEmpty() ? null : projectBeneficiaryClientReferenceIdList) + .build(); + try { + // using project beneficiary search and fetching the valid ids. + BeneficiaryBulkResponse beneficiaryBulkResponse = serviceRequestClient.fetchResult( + new StringBuilder(referralManagementConfiguration.getProjectHost() + + referralManagementConfiguration.getProjectBeneficiarySearchUrl() + +"?limit=" + referrals.size() + + "&offset=0&tenantId=" + tenantId), + BeneficiarySearchRequest.builder().requestInfo(request.getRequestInfo()).projectBeneficiary(projectBeneficiarySearch).build(), + BeneficiaryBulkResponse.class + ); + existingProjectBeneficiaries = beneficiaryBulkResponse.getProjectBeneficiaries(); + } catch (QueryBuilderException e) { + existingProjectBeneficiaries = Collections.emptyList(); + } catch (Exception e) { + throw new CustomException("Project Beneficiaries failed to fetch", "Exception : "+e.getMessage()); + } + return existingProjectBeneficiaries; + } + + private void validateAndPopulateErrors(List existingProjectBeneficiaries, List entities, Map> errorDetailsMap) { + final List existingProjectBeneficiaryIds = new ArrayList<>(); + final List existingProjectBeneficiaryClientReferenceIds = new ArrayList<>(); + existingProjectBeneficiaries.forEach(projectBeneficiary -> { + existingProjectBeneficiaryIds.add(projectBeneficiary.getId()); + existingProjectBeneficiaryClientReferenceIds.add(projectBeneficiary.getClientReferenceId()); + }); + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + (Objects.nonNull(entity.getProjectBeneficiaryClientReferenceId()) && !existingProjectBeneficiaryClientReferenceIds.contains(entity.getProjectBeneficiaryClientReferenceId()) ) + || (Objects.nonNull(entity.getProjectBeneficiaryClientReferenceId()) && !existingProjectBeneficiaryIds.contains(entity.getProjectBeneficiaryId())) + ).collect(Collectors.toList()); + invalidEntities.forEach(referral -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(referral, error, errorDetailsMap); + }); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectEntitiesIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectEntitiesIdValidator.java deleted file mode 100644 index 61c87b9f4ab..00000000000 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectEntitiesIdValidator.java +++ /dev/null @@ -1,134 +0,0 @@ -package org.egov.referralmanagement.validator; - -import lombok.extern.slf4j.Slf4j; -import org.egov.common.data.query.exception.QueryBuilderException; -import org.egov.common.http.client.ServiceRequestClient; -import org.egov.common.models.Error; -import org.egov.common.models.project.BeneficiaryBulkResponse; -import org.egov.common.models.project.BeneficiarySearchRequest; -import org.egov.common.models.project.ProjectBeneficiary; -import org.egov.common.models.project.ProjectBeneficiarySearch; -import org.egov.common.models.project.ProjectStaff; -import org.egov.common.models.project.ProjectStaffBulkResponse; -import org.egov.common.models.project.ProjectStaffSearch; -import org.egov.common.models.project.ProjectStaffSearchRequest; -import org.egov.common.models.referralmanagement.Referral; -import org.egov.common.models.referralmanagement.ReferralBulkRequest; -import org.egov.common.validator.Validator; -import org.egov.referralmanagement.config.ReferralManagementConfiguration; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.core.annotation.Order; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; - -import static org.egov.referralmanagement.Constants.PROJECT_STAFF; -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; - - -@Component -@Order(value = 3) -@Slf4j -public class RmProjectEntitiesIdValidator implements Validator { - private final ServiceRequestClient serviceRequestClient; - private final ReferralManagementConfiguration referralManagementConfiguration; - - @Autowired - public RmProjectEntitiesIdValidator(ServiceRequestClient serviceRequestClient, ReferralManagementConfiguration referralManagementConfiguration) { - this.serviceRequestClient = serviceRequestClient; - this.referralManagementConfiguration = referralManagementConfiguration; - } - - - @Override - public Map> validate(ReferralBulkRequest request) { - log.info("validating project beneficiary id, project staff id"); - Map> errorDetailsMap = new HashMap<>(); - List entities = request.getReferrals(); - Map> tenantIdReferralMap = entities.stream().collect(Collectors.groupingBy(Referral::getTenantId)); - List tenantIds = new ArrayList<>(tenantIdReferralMap.keySet()); - tenantIds.forEach(tenantId -> { - List referralList = tenantIdReferralMap.get(tenantId); - if (!referralList.isEmpty()) { - List existingProjectBeneficiaries = null; - List existingProjectStaffList = null; - final List projectBeneficiaryIdList = new ArrayList<>(); - final List projectBeneficiaryClientReferenceIdList = new ArrayList<>(); - final List projectStaffIdList = new ArrayList<>(); - try { - referralList.forEach(referral -> { - addIgnoreNull(projectBeneficiaryIdList, referral.getProjectBeneficiaryId()); - addIgnoreNull(projectBeneficiaryClientReferenceIdList, referral.getProjectBeneficiaryClientReferenceId()); - addIgnoreNull(projectStaffIdList, referral.getReferredById()); - if(referral.getReferredToType().equals(PROJECT_STAFF)){ - addIgnoreNull(projectStaffIdList, referral.getReferredToId()); - } - }); - ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() - .id(projectBeneficiaryIdList.isEmpty() ? null : projectBeneficiaryIdList) - .clientReferenceId(projectBeneficiaryClientReferenceIdList.isEmpty() ? null : projectBeneficiaryClientReferenceIdList) - .build(); - BeneficiaryBulkResponse beneficiaryBulkResponse = serviceRequestClient.fetchResult( - new StringBuilder(referralManagementConfiguration.getProjectHost() - + referralManagementConfiguration.getProjectBeneficiarySearchUrl() - +"?limit=" + entities.size() - + "&offset=0&tenantId=" + tenantId), - BeneficiarySearchRequest.builder().requestInfo(request.getRequestInfo()).projectBeneficiary(projectBeneficiarySearch).build(), - BeneficiaryBulkResponse.class - ); - existingProjectBeneficiaries = beneficiaryBulkResponse.getProjectBeneficiaries(); - ProjectStaffSearch projectStaffSearch = ProjectStaffSearch.builder() - .id(projectStaffIdList.isEmpty() ? null : projectStaffIdList) - .build(); - ProjectStaffBulkResponse projectStaffBulkResponse = serviceRequestClient.fetchResult( - new StringBuilder(referralManagementConfiguration.getProjectHost() - + referralManagementConfiguration.getProjectStaffSearchUrl() - +"?limit=" + entities.size() - + "&offset=0&tenantId=" + tenantId), - ProjectStaffSearchRequest.builder().requestInfo(request.getRequestInfo()).projectStaff(projectStaffSearch).build(), - ProjectStaffBulkResponse.class - ); - existingProjectStaffList = projectStaffBulkResponse.getProjectStaff(); - - } catch (QueryBuilderException e) { - if(existingProjectBeneficiaries == null) existingProjectBeneficiaries = Collections.emptyList(); - existingProjectStaffList = Collections.emptyList(); - } catch (Exception e) { - throw new RuntimeException(e); - } - final List existingProjectBeneficiaryIds = new ArrayList<>(); - final List existingProjectBeneficiaryClientReferenceIds = new ArrayList<>(); - existingProjectBeneficiaries.forEach(projectBeneficiary -> { - existingProjectBeneficiaryIds.add(projectBeneficiary.getId()); - existingProjectBeneficiaryClientReferenceIds.add(projectBeneficiary.getClientReferenceId()); - }); - final List existingProjectStaffIds = new ArrayList<>(); - existingProjectStaffList.forEach(projectStaff -> existingProjectStaffIds.add(projectStaff.getId())); - List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> - !existingProjectStaffIds.contains(entity.getReferredById()) - && !existingProjectBeneficiaryIds.contains(entity.getProjectBeneficiaryId()) - && !existingProjectBeneficiaryClientReferenceIds.contains(entity.getProjectBeneficiaryClientReferenceId()) - && (!entity.getReferredToType().equals(PROJECT_STAFF) || !existingProjectStaffIds.contains(entity.getReferredToId())) - ).collect(Collectors.toList()); - invalidEntities.forEach(referral -> { - Error error = getErrorForNonExistentEntity(); - populateErrorDetails(referral, error, errorDetailsMap); - }); - - } - }); - return errorDetailsMap; - } - - private void addIgnoreNull(List list, String item) { - if(Objects.nonNull(item)) list.add(item); - } -} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmRecipientIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmRecipientIdValidator.java new file mode 100644 index 00000000000..a068a4882f2 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmRecipientIdValidator.java @@ -0,0 +1,107 @@ +package org.egov.referralmanagement.validator; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.ds.Tuple; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.service.UserService; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.service.FacilityService; +import org.egov.referralmanagement.util.ValidatorUtil; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; +import static org.egov.referralmanagement.Constants.FACILITY; +import static org.egov.referralmanagement.Constants.INVALID_RECIPIENT_TYPE; +import static org.egov.referralmanagement.Constants.STAFF; + +/** + * + */ +@Component +@Order(value = 3) +@Slf4j +public class RmRecipientIdValidator implements Validator { + private final FacilityService facilityService; + private final UserService userService; + + public RmRecipientIdValidator(FacilityService facilityService, UserService userService) { + this.facilityService = facilityService; + this.userService = userService; + } + + /** + * @param request + * @return + */ + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating recipient id"); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getReferrals(); + Map> tenantIdReferralMap = entities.stream().collect(Collectors.groupingBy(Referral::getTenantId)); + tenantIdReferralMap.forEach((tenantId, referralList) -> { + + Tuple, List> tuple = getInvalidStaffAndFacilityId(request, entities, tenantId, referralList, errorDetailsMap); + // validate and populate error if found. + validateAndPopulateErrors(entities, tuple.getX(), tuple.getY(), errorDetailsMap); + }); + return errorDetailsMap; + } + + private void addIgnoreNull(List list, String item) { + if(Objects.nonNull(item)) list.add(item); + } + + private Tuple, List> getInvalidStaffAndFacilityId(ReferralBulkRequest request, List entities, String tenantId, List referralList, Map> errorDetailsMap) { + final List projectStaffUuidList = new ArrayList<>(); + final List facilityIdList = new ArrayList<>(); + referralList.forEach(referral -> { + switch (referral.getRecipientType()) { + case STAFF : + addIgnoreNull(projectStaffUuidList, referral.getRecipientId()); + break; + case FACILITY: + addIgnoreNull(facilityIdList, referral.getRecipientId()); + break; + default: + throw new CustomException(INVALID_RECIPIENT_TYPE, "Exception : The Recipient Type is invalid."); + } + }); + + List invalidStaffIds = new ArrayList<>(projectStaffUuidList); + // fetch valid identifiers and remove it from invalidStaffIds + ValidatorUtil.validateAndEnrichStaffIds(request.getRequestInfo(), userService, projectStaffUuidList, invalidStaffIds); + + // fetch valid facilities and remove it from invalidfacilityIds + List invalidFacilityIds = new ArrayList<>(facilityIdList); + List validFacilityIds = facilityService.validateFacilityIds(facilityIdList, entities, tenantId, + errorDetailsMap, request.getRequestInfo()); + invalidFacilityIds.removeAll(validFacilityIds); + + return new Tuple<>(invalidStaffIds, invalidFacilityIds); + } + + private void validateAndPopulateErrors(List entities, List invalidStaffIds, List invalidFacilityIds, Map> errorDetailsMap) { + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + entity.getRecipientType().equals(STAFF) ? invalidStaffIds.contains(entity.getRecipientId()) : invalidFacilityIds.contains(entity.getRecipientId()) + ).collect(Collectors.toList()); + + invalidEntities.forEach(referral -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(referral, error, errorDetailsMap); + }); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmReferrerIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmReferrerIdValidator.java new file mode 100644 index 00000000000..10f5e265579 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmReferrerIdValidator.java @@ -0,0 +1,86 @@ +package org.egov.referralmanagement.validator; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.service.UserService; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.service.FacilityService; +import org.egov.referralmanagement.util.ValidatorUtil; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + +/** + * Validate the referrer using user service + */ +@Component +@Order(value = 3) +@Slf4j +public class RmReferrerIdValidator implements Validator { + + private final FacilityService facilityService; + private final UserService userService; + + public RmReferrerIdValidator(FacilityService facilityService, UserService userService) { + this.facilityService = facilityService; + this.userService = userService; + } + + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating referrer id"); + + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getReferrals(); + + Map> tenantIdReferralMap = entities.stream().collect(Collectors.groupingBy(Referral::getTenantId)); + + tenantIdReferralMap.forEach((tenantId, referralList) -> { + List invalidStaffIds = getInvalidStaffIds(referralList, request); + validateAndPopulateError(entities, invalidStaffIds, errorDetailsMap); + }); + + return errorDetailsMap; + } + private void addIgnoreNull(List list, String item) { + if(Objects.nonNull(item)) list.add(item); + } + + private List getInvalidStaffIds(List referralList, ReferralBulkRequest request) { + final List projectStaffUuidList = new ArrayList<>(); + referralList.forEach(referral -> addIgnoreNull(projectStaffUuidList, referral.getReferrerId())); + + List invalidStaffIds = new ArrayList<>(projectStaffUuidList); + try { + ValidatorUtil.validateAndEnrichStaffIds(request.getRequestInfo(), userService, projectStaffUuidList, invalidStaffIds); + } catch (Exception e) { + throw new CustomException("Project Staff failed to fetch", "Exception : "+e.getMessage()); + } + + return invalidStaffIds; + } + private void validateAndPopulateError(List entities, List invalidStaffIds, Map> errorDetailsMap) { + + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + invalidStaffIds.contains(entity.getReferrerId()) + ).collect(Collectors.toList()); + + invalidEntities.forEach(referral -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(referral, error, errorDetailsMap); + }); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmSideEffectIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmSideEffectIdValidator.java new file mode 100644 index 00000000000..565bfff6f30 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmSideEffectIdValidator.java @@ -0,0 +1,89 @@ +package org.egov.referralmanagement.validator; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearch; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearchRequest; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.service.SideEffectService; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + +/** + * Validate Side Effect id from the Referral Objects + */ +@Component +@Order(value = 3) +@Slf4j +public class RmSideEffectIdValidator implements Validator { + private final SideEffectService sideEffectService; + public RmSideEffectIdValidator(SideEffectService sideEffectService) { + this.sideEffectService = sideEffectService; + } + + /** + * @param request + * @return + */ + @Override + public Map> validate(ReferralBulkRequest request) { + log.info("validating project beneficiary id"); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getReferrals(); + Map> tenantIdReferralMap = entities.stream().collect(Collectors.groupingBy(Referral::getTenantId)); + tenantIdReferralMap.forEach((tenantId, referralList) -> { + List sideEffectIds = new ArrayList<>(); + referralList.forEach(referral -> { + if (Objects.nonNull(referral.getSideEffect())) + addIgnoreNull(sideEffectIds, referral.getSideEffect().getId()); + }); + List validSideEffectIds = new ArrayList<>(); + if(!sideEffectIds.isEmpty()) { + try { + validSideEffectIds = sideEffectService.search( + SideEffectSearchRequest.builder().sideEffect(SideEffectSearch.builder().id(sideEffectIds).build()).build(), + sideEffectIds.size(), 0, tenantId, null, false + ).stream().map(SideEffect::getId).collect(Collectors.toList()); + } catch (Exception e) { + throw new CustomException("Side Effect failed to fetch", "Exception : " + e.getMessage()); + } + } + sideEffectIds.removeAll(validSideEffectIds); + List invalidSideEffectIds = new ArrayList<>(sideEffectIds); + + validateAndPopulateErrors(entities, invalidSideEffectIds, errorDetailsMap); + + }); + + return errorDetailsMap; + } + private void addIgnoreNull(List list, String item) { + if(Objects.nonNull(item)) list.add(item); + } + + private void validateAndPopulateErrors(List entities, List invalidSideEffectIds, Map> errorDetailsMap) { + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + Objects.nonNull(entity.getSideEffect()) && invalidSideEffectIds.contains(entity.getSideEffect().getId()) + ).collect(Collectors.toList()); + + invalidEntities.forEach(referral -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(referral, error, errorDetailsMap); + }); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java index 949f84fbde8..92d867479ee 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java @@ -28,6 +28,9 @@ import javax.validation.constraints.NotNull; import java.util.List; +/** + * Referral Management Api Controller + */ @Controller @RequestMapping("") @Validated @@ -52,6 +55,11 @@ public ReferralManagementApiController( this.referralManagementConfiguration = referralManagementConfiguration; } + /** + * @ + * @param request + * @return + */ @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) public ResponseEntity referralV1CreatePost(@ApiParam(value = "Capture details of Referral", required = true) @Valid @RequestBody ReferralRequest request) { @@ -66,7 +74,11 @@ public ResponseEntity referralV1CreatePost(@ApiParam(value = " } - + /** + * + * @param request + * @return + */ @RequestMapping(value = "/v1/bulk/_create", method = RequestMethod.POST) public ResponseEntity referralBulkV1CreatePost(@ApiParam(value = "Capture details of Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); @@ -77,6 +89,17 @@ public ResponseEntity referralBulkV1CreatePost(@ApiParam(value = " .createResponseInfo(request.getRequestInfo(), true)); } + /** + * + * @param request + * @param limit + * @param offset + * @param tenantId + * @param lastChangedSince + * @param includeDeleted + * @return + * @throws Exception + */ @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) public ResponseEntity referralV1SearchPost(@ApiParam(value = "Referral Search.", required = true) @Valid @RequestBody ReferralSearchRequest request, @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, @@ -92,6 +115,11 @@ public ResponseEntity referralV1SearchPost(@ApiParam(value return ResponseEntity.status(HttpStatus.OK).body(response); } + /** + * + * @param request + * @return + */ @RequestMapping(value = "/v1/_update", method = RequestMethod.POST) public ResponseEntity referralV1UpdatePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralRequest request) { Referral referral = referralManagementService.update(request); @@ -106,6 +134,11 @@ public ResponseEntity referralV1UpdatePost(@ApiParam(value = " } + /** + * + * @param request + * @return + */ @RequestMapping(value = "/v1/bulk/_update", method = RequestMethod.POST) public ResponseEntity referralV1BulkUpdatePost(@ApiParam(value = "Capture details of Existing Referral", required = true) @Valid @RequestBody ReferralBulkRequest request) { request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); diff --git a/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928113400__referral_create_ddl.sql b/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928113400__referral_create_ddl.sql index 15ed8373d7f..b17f93e6ee5 100644 --- a/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928113400__referral_create_ddl.sql +++ b/health-services/referralmanagement/src/main/resources/db/migration/main/V20230928113400__referral_create_ddl.sql @@ -5,9 +5,9 @@ CREATE TABLE REFERRAL tenantId character varying(1000), projectBeneficiaryId character varying(64), projectBeneficiaryClientReferenceId character varying(64), - referredById character varying(100), - referredToId character varying(100), - referredToType character varying(100), + referrerId character varying(100), + recipientId character varying(100), + recipientType character varying(100), reasons jsonb, sideEffectId character varying(100), sideEffectClientReferenceId character varying(100), diff --git a/health-services/referralmanagement/src/main/resources/db/migration/main/V20231019114100__referral_side_effect_additionaldetails_ddl.sql b/health-services/referralmanagement/src/main/resources/db/migration/main/V20231019114100__referral_side_effect_additionaldetails_ddl.sql new file mode 100644 index 00000000000..9cf29e89062 --- /dev/null +++ b/health-services/referralmanagement/src/main/resources/db/migration/main/V20231019114100__referral_side_effect_additionaldetails_ddl.sql @@ -0,0 +1,2 @@ +ALTER TABLE side_effect ADD COLUMN IF NOT EXISTS additionalDetails jsonb; +ALTER TABLE referral ADD COLUMN IF NOT EXISTS additionalDetails jsonb; \ No newline at end of file diff --git a/health-services/referralmanagement/src/main/resources/referral-management-persister.yml b/health-services/referralmanagement/src/main/resources/referral-management-persister.yml index a3342191930..de72b595fa9 100644 --- a/health-services/referralmanagement/src/main/resources/referral-management-persister.yml +++ b/health-services/referralmanagement/src/main/resources/referral-management-persister.yml @@ -6,7 +6,7 @@ serviceMaps: fromTopic: save-side-effect-topic isTransaction: true queryMaps: - - query: INSERT INTO SIDE_EFFECT(id, clientReferenceId, tenantId, taskId, taskClientReferenceId, projectBeneficiaryId, projectBeneficiaryClientReferenceId,symptoms, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedBy, clientCreatedTime, clientLastModifiedBy, clientLastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); + - query: INSERT INTO SIDE_EFFECT(id, clientReferenceId, tenantId, taskId, taskClientReferenceId, projectBeneficiaryId, projectBeneficiaryClientReferenceId, symptoms, additionalDetails, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedBy, clientCreatedTime, clientLastModifiedBy, clientLastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); basePath: $.* jsonMaps: - jsonPath: $.*.id @@ -19,6 +19,9 @@ serviceMaps: - jsonPath: $.*.symptoms type: JSON dbType: JSONB + - jsonPath: $.*.additionalFields + type: JSON + dbType: JSONB - jsonPath: $.*.auditDetails.createdBy - jsonPath: $.*.auditDetails.createdTime - jsonPath: $.*.auditDetails.lastModifiedBy @@ -30,117 +33,126 @@ serviceMaps: - jsonPath: $.*.rowVersion - jsonPath: $.*.isDeleted - - version: 1.0 - description: Updates a side effect - fromTopic: update-side-effect-topic - isTransaction: true - queryMaps: - - query: UPDATE SIDE_EFFECT SET tenantId = ?, taskId = ?, taskClientReferenceId = ?, projectBeneficiaryId = ?, projectBeneficiaryClientReferenceId = ?, symptoms = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.tenantId - - jsonPath: $.*.taskId - - jsonPath: $.*.taskClientReferenceId - - jsonPath: $.*.projectBeneficiaryId - - jsonPath: $.*.projectBeneficiaryClientReferenceId - - jsonPath: $.*.symptoms - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.clientAuditDetails.lastModifiedBy - - jsonPath: $.*.clientAuditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id - - - version: 1.0 - description: Deletes a side effect - fromTopic: delete-side-effect-topic - isTransaction: true - queryMaps: - - query: UPDATE SIDE_EFFECT SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.clientAuditDetails.lastModifiedBy - - jsonPath: $.*.clientAuditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id - - - version: 1.0 - description: Saves a referral - fromTopic: save-referral-topic - isTransaction: true - queryMaps: - - query: INSERT INTO REFERRAL(id, clientReferenceId, tenantId, projectBeneficiaryId, projectBeneficiaryClientReferenceId, referredById, referredToId, referredToType, reasons, sideEffectId, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedBy, clientCreatedTime, clientLastModifiedBy, clientLastModifiedTime, rowVersion, isDeleted) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); - basePath: $.* - jsonMaps: - - jsonPath: $.*.id - - jsonPath: $.*.clientReferenceId - - jsonPath: $.*.tenantId - - jsonPath: $.*.projectBeneficiaryId - - jsonPath: $.*.projectBeneficiaryClientReferenceId - - jsonPath: $.*.referredById - - jsonPath: $.*.referredToId - - jsonPath: $.*.referredToType - - jsonPath: $.*.reasons - type: JSON - dbType: JSONB - - jsonPath: $.*.sideEffect.id - - jsonPath: $.*.auditDetails.createdBy - - jsonPath: $.*.auditDetails.createdTime - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.clientAuditDetails.createdBy - - jsonPath: $.*.clientAuditDetails.createdTime - - jsonPath: $.*.clientAuditDetails.lastModifiedBy - - jsonPath: $.*.clientAuditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted + - version: 1.0 + description: Updates a side effect + fromTopic: update-side-effect-topic + isTransaction: true + queryMaps: + - query: UPDATE SIDE_EFFECT SET tenantId = ?, taskId = ?, taskClientReferenceId = ?, projectBeneficiaryId = ?, projectBeneficiaryClientReferenceId = ?, symptoms = ?, additionalDetails = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.tenantId + - jsonPath: $.*.taskId + - jsonPath: $.*.taskClientReferenceId + - jsonPath: $.*.projectBeneficiaryId + - jsonPath: $.*.projectBeneficiaryClientReferenceId + - jsonPath: $.*.symptoms + type: JSON + dbType: JSONB + - jsonPath: $.*.additionalFields + type: JSON + dbType: JSONB + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - jsonPath: $.*.id - - version: 1.0 - description: Updates a referral - fromTopic: update-referral-topic - isTransaction: true - queryMaps: - - query: UPDATE REFERRAL SET tenantId = ?, projectBeneficiaryId = ?, projectBeneficiaryClientReferenceId = ?, referredById = ?, referredToId = ?, referredToType = ?, reasons = ?, sideEffectId = ?, createdBy = ?, createdTime = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientCreatedBy = ?, clientCreatedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted WHERE ID = ?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.tenantId - - jsonPath: $.*.projectBeneficiaryId - - jsonPath: $.*.projectBeneficiaryClientReferenceId - - jsonPath: $.*.referredById - - jsonPath: $.*.referredToId - - jsonPath: $.*.referredToType - - jsonPath: $.*.reasons - type: JSON - dbType: JSONB - - jsonPath: $.*.sideEffect.id - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.clientAuditDetails.lastModifiedBy - - jsonPath: $.*.clientAuditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id + - version: 1.0 + description: Deletes a side effect + fromTopic: delete-side-effect-topic + isTransaction: true + queryMaps: + - query: UPDATE SIDE_EFFECT SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - jsonPath: $.*.id - - version: 1.0 - description: Deletes a referral - fromTopic: delete-referral-topic - isTransaction: true - queryMaps: - - query: UPDATE REFERRAL SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.clientAuditDetails.lastModifiedBy - - jsonPath: $.*.clientAuditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id + - version: 1.0 + description: Saves a referral + fromTopic: save-referral-topic + isTransaction: true + queryMaps: + - query: INSERT INTO REFERRAL(id, clientReferenceId, tenantId, projectBeneficiaryId, projectBeneficiaryClientReferenceId, referrerId, recipientId, recipientType, reasons, additionalDetails, sideEffectId, sideEffectClientReferenceId, createdBy, createdTime, lastModifiedBy, lastModifiedTime, clientCreatedBy, clientCreatedTime, clientLastModifiedBy, clientLastModifiedTime, rowVersion, isDeleted) VALUES(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); + basePath: $.* + jsonMaps: + - jsonPath: $.*.id + - jsonPath: $.*.clientReferenceId + - jsonPath: $.*.tenantId + - jsonPath: $.*.projectBeneficiaryId + - jsonPath: $.*.projectBeneficiaryClientReferenceId + - jsonPath: $.*.referrerId + - jsonPath: $.*.recipientId + - jsonPath: $.*.recipientType + - jsonPath: $.*.reasons + type: JSON + dbType: JSONB + - jsonPath: $.*.additionalFields + type: JSON + dbType: JSONB + - jsonPath: $.*.sideEffect.id + - jsonPath: $.*.sideEffect.clientReferenceId + - jsonPath: $.*.auditDetails.createdBy + - jsonPath: $.*.auditDetails.createdTime + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.createdBy + - jsonPath: $.*.clientAuditDetails.createdTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - version: 1.0 + description: Updates a referral + fromTopic: update-referral-topic + isTransaction: true + queryMaps: + - query: UPDATE REFERRAL SET tenantId = ?, projectBeneficiaryId = ?, projectBeneficiaryClientReferenceId = ?, referrerId = ?, recipientId = ?, recipientType = ?, reasons = ?, additionalDetails = ?, sideEffectId = ?, sideEffectClientReferenceId = ?, lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.tenantId + - jsonPath: $.*.projectBeneficiaryId + - jsonPath: $.*.projectBeneficiaryClientReferenceId + - jsonPath: $.*.referrerId + - jsonPath: $.*.recipientId + - jsonPath: $.*.recipientType + - jsonPath: $.*.reasons + type: JSON + dbType: JSONB + - jsonPath: $.*.additionalFields + type: JSON + dbType: JSONB + - jsonPath: $.*.sideEffect.id + - jsonPath: $.*.sideEffect.clientReferenceId + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - jsonPath: $.*.id + - version: 1.0 + description: Deletes a referral + fromTopic: delete-referral-topic + isTransaction: true + queryMaps: + - query: UPDATE REFERRAL SET lastModifiedBy = ?, lastModifiedTime = ?, clientLastModifiedBy = ?, clientLastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; + basePath: $.* + jsonMaps: + - jsonPath: $.*.auditDetails.lastModifiedBy + - jsonPath: $.*.auditDetails.lastModifiedTime + - jsonPath: $.*.clientAuditDetails.lastModifiedBy + - jsonPath: $.*.clientAuditDetails.lastModifiedTime + - jsonPath: $.*.rowVersion + - jsonPath: $.*.isDeleted + - jsonPath: $.*.id \ No newline at end of file diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/ReferralRequestTestBuilder.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/ReferralRequestTestBuilder.java new file mode 100644 index 00000000000..d9e7c9ba034 --- /dev/null +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/ReferralRequestTestBuilder.java @@ -0,0 +1,60 @@ +package org.egov.referralmanagement.helper; + +import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.referralmanagement.ReferralRequest; + +import java.util.ArrayList; + +public class ReferralRequestTestBuilder { + private ReferralRequest.ReferralRequestBuilder builder; + + private ArrayList referral = new ArrayList(); + + public ReferralRequestTestBuilder() { + this.builder = ReferralRequest.builder(); + } + + public static ReferralRequestTestBuilder builder() { + return new ReferralRequestTestBuilder(); + } + + public ReferralRequest build() { + return this.builder.build(); + } + + public ReferralRequestTestBuilder withOneReferral() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .referral(ReferralTestBuilder.builder().withId().withAuditDetails().build()); + return this; + } + + public ReferralRequestTestBuilder withApiOperationNotNullAndNotCreate() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .referral(ReferralTestBuilder.builder().withIdNull().build()); + return this; + } + + public ReferralRequestTestBuilder withApiOperationNotUpdate() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .referral(ReferralTestBuilder.builder().withIdNull().build()); + return this; + } + + public ReferralRequestTestBuilder withOneReferralHavingId() { + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .referral(ReferralTestBuilder.builder().withId().withAuditDetails().build()); + return this; + } + + public ReferralRequestTestBuilder withBadTenantIdInOneReferral() { + + builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) + .referral(ReferralTestBuilder.builder().withIdNull().withBadTenantId().build()); + return this; + } + + public ReferralRequestTestBuilder withRequestInfo(){ + this.builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()); + return this; + } +} diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/ReferralTestBuilder.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/ReferralTestBuilder.java new file mode 100644 index 00000000000..8ea5a37e267 --- /dev/null +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/ReferralTestBuilder.java @@ -0,0 +1,78 @@ +package org.egov.referralmanagement.helper; + +import org.egov.common.helper.AuditDetailsTestBuilder; +import org.egov.common.models.referralmanagement.Referral; + +import java.util.ArrayList; +import java.util.Arrays; + +public class ReferralTestBuilder { + + private Referral.ReferralBuilder builder; + + public ReferralTestBuilder() { + this.builder = Referral.builder(); + } + + public static ReferralTestBuilder builder() { + return new ReferralTestBuilder(); + } + + public Referral build() { + return this.builder.hasErrors(false).build(); + } + + public ReferralTestBuilder withIdNull() { + this.builder.projectBeneficiaryId("some-projectBeneficiary-id") + .clientReferenceId("ClientReferenceId") + .id(null) + .projectBeneficiaryClientReferenceId("projectBeneficiaryClientReferenceId") + .reasons(new ArrayList<>(Arrays.asList("fever"))) + .tenantId("some-tenant-id") + .rowVersion(1); + return this; + } + + public ReferralTestBuilder withId() { + withIdNull().builder.id("some-id") + .projectBeneficiaryId("some-projectBeneficiary-id") + .clientReferenceId("ClientReferenceId") + .projectBeneficiaryClientReferenceId("projectBeneficiaryClientReferenceId") + .reasons(new ArrayList<>(Arrays.asList("fever"))) + .tenantId("some-tenant-id") + .rowVersion(1); + return this; + } + + public ReferralTestBuilder withId(String id) { + this.builder.id(id); + return this; + } + + public ReferralTestBuilder withBadTenantId() { + this.builder.tenantId(null); + return this; + } + + public ReferralTestBuilder goodReferral() { + this.builder.id("some-id") + .projectBeneficiaryId("some-projectBeneficiary-id") + .clientReferenceId("ClientReferenceId") + .projectBeneficiaryClientReferenceId("projectBeneficiaryClientReferenceId") + .reasons(new ArrayList<>(Arrays.asList("fever"))) + .tenantId("some-tenant-id") + .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()) + .clientAuditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); + return this; + } + + public ReferralTestBuilder withAuditDetails() { + this.builder.auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); + return this; + } + + public ReferralTestBuilder withDeleted() { + this.builder.isDeleted(true); + return this; + } +} diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiControllerTest.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiControllerTest.java new file mode 100644 index 00000000000..bcf1518c0c1 --- /dev/null +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiControllerTest.java @@ -0,0 +1,208 @@ +package org.egov.referralmanagement.web.controllers; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkResponse; +import org.egov.common.models.referralmanagement.ReferralRequest; +import org.egov.common.models.referralmanagement.ReferralResponse; +import org.egov.common.models.referralmanagement.ReferralSearch; +import org.egov.common.models.referralmanagement.ReferralSearchRequest; +import org.egov.common.producer.Producer; +import org.egov.referralmanagement.TestConfiguration; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.helper.ReferralRequestTestBuilder; +import org.egov.referralmanagement.helper.ReferralTestBuilder; +import org.egov.referralmanagement.service.ReferralManagementService; +import org.egov.tracer.model.CustomException; +import org.egov.tracer.model.ErrorRes; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.ArgumentMatchers; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import org.springframework.test.web.servlet.result.MockMvcResultMatchers; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@WebMvcTest(ReferralManagementApiController.class) +@Import(TestConfiguration.class) +public class ReferralManagementApiControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private ReferralManagementService referralManagementService; + + @MockBean + private Producer producer; + + @MockBean + ReferralManagementConfiguration referralManagementConfiguration; + + @Test + @DisplayName("should create referral and return with 202 accepted") + void shouldCreateReferralAndReturnWith202Accepted() throws Exception { + ReferralRequest request = ReferralRequestTestBuilder.builder() + .withOneReferral() + .withApiOperationNotUpdate() + .build(); + List referrals = getReferrals(); + Mockito.when(referralManagementService.create(ArgumentMatchers.any(ReferralRequest.class))).thenReturn(referrals.get(0)); + + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/v1/_create") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(MockMvcResultMatchers.status().isAccepted()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + ReferralResponse response = objectMapper.readValue(responseStr, ReferralResponse.class); + + Assertions.assertNotNull(response.getReferral()); + Assertions.assertNotNull(response.getReferral().getId()); + Assertions.assertEquals("successful", response.getResponseInfo().getStatus()); + } + + private List getReferrals() { + Referral referral = ReferralTestBuilder.builder().withId().build(); + List referrals = new ArrayList<>(); + referrals.add(referral); + return referrals; + } + + + @Test + @DisplayName("should send error response with error details with 400 bad request for create") + void shouldSendErrorResWithErrorDetailsWith400BadRequestForCreate() throws Exception { + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/v1/_create") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(ReferralRequestTestBuilder.builder() + .withOneReferral() + .withBadTenantIdInOneReferral() + .build()))) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + ErrorRes response = objectMapper.readValue(responseStr, ErrorRes.class); + + Assertions.assertEquals(1, response.getErrors().size()); + Assertions.assertTrue(response.getErrors().get(0).getCode().contains("tenantId")); + } + + @Test + @DisplayName("should update referral and return with 202 accepted") + void shouldUpdateReferralAndReturnWith202Accepted() throws Exception { + ReferralRequest request = ReferralRequestTestBuilder.builder() + .withOneReferralHavingId() + .withApiOperationNotNullAndNotCreate() + .build(); + Referral referral = ReferralTestBuilder.builder().withId().build(); + Mockito.when(referralManagementService.update(ArgumentMatchers.any(ReferralRequest.class))).thenReturn(referral); + + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/v1/_update") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(request))) + .andExpect(MockMvcResultMatchers.status().isAccepted()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + ReferralResponse response = objectMapper.readValue(responseStr, ReferralResponse.class); + + Assertions.assertNotNull(response.getReferral()); + Assertions.assertNotNull(response.getReferral().getId()); + Assertions.assertEquals("successful", response.getResponseInfo().getStatus()); + } + + @Test + @DisplayName("should send error response with error details with 400 bad request for update") + void shouldSendErrorResWithErrorDetailsWith400BadRequestForUpdate() throws Exception { + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/v1/_update") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(ReferralRequestTestBuilder.builder() + .withOneReferralHavingId() + .withBadTenantIdInOneReferral() + .build()))) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + ErrorRes response = objectMapper.readValue(responseStr, + ErrorRes.class); + + Assertions.assertEquals(1, response.getErrors().size()); + Assertions.assertTrue(response.getErrors().get(0).getCode().contains("tenantId")); + } + + @Test + @DisplayName("Should accept search request and return response as accepted") + void shouldAcceptSearchRequestAndReturnReferral() throws Exception { + + ReferralSearchRequest referralSearchRequest = ReferralSearchRequest.builder().referral( + ReferralSearch.builder().projectBeneficiaryId(Arrays.asList("some-project-beneficiary-id")).build() + ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); + + Mockito.when(referralManagementService.search(ArgumentMatchers.any(ReferralSearchRequest.class), + ArgumentMatchers.any(Integer.class), + ArgumentMatchers.any(Integer.class), + ArgumentMatchers.any(String.class), + ArgumentMatchers.any(Long.class), + ArgumentMatchers.any(Boolean.class))).thenReturn(Arrays.asList(ReferralTestBuilder.builder().withId().withAuditDetails().build())); + + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post( + "/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(referralSearchRequest))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + ReferralBulkResponse response = objectMapper.readValue(responseStr, + ReferralBulkResponse.class); + + Assertions.assertEquals(response.getReferrals().size(), 1); + } + + @Test + @DisplayName("Should accept search request and return response as accepted") + void shouldThrowExceptionIfNoResultFound() throws Exception { + + ReferralSearchRequest referralSearchRequest = ReferralSearchRequest.builder().referral( + ReferralSearch.builder().projectBeneficiaryId(Arrays.asList("some-project-beneficiary-id")).build() + ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); + + Mockito.when(referralManagementService.search(ArgumentMatchers.any(ReferralSearchRequest.class), + ArgumentMatchers.any(Integer.class), + ArgumentMatchers.any(Integer.class), + ArgumentMatchers.any(String.class), + ArgumentMatchers.any(Long.class), + ArgumentMatchers.any(Boolean.class))).thenThrow(new CustomException("NO_RESULT_FOUND", "No Referral found.")); + + + final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(referralSearchRequest))) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + .andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON)) + .andReturn(); + String responseStr = result.getResponse().getContentAsString(); + ErrorRes response = objectMapper.readValue(responseStr, + ErrorRes.class); + + Assertions.assertEquals(response.getErrors().size(), 1); + } + +} From ffc4130efcd8efd6faeb164542c832e72991b43e Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:59:40 +0530 Subject: [PATCH 215/283] Dev to master with project beneficiary tag and downsync (#560) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter * Project beneficiary tag cherrypick (#539) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * referral management project beneficiary validation fix * deleted persister and indexer file from project module resource folder --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * HH member clientrefid (#551) * adding clientRefId, Models version change, migration file * adding clientRefId for HouseholdMemberSearch as List * updated migration * adding Notnull for clientrefId --------- Co-authored-by: Vishal * Downsync smc referral module (#556) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Project beneficiary tag cherrypick (#549) * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * referral management project beneficiary validation fix --------- Co-authored-by: kanishq-egov Co-authored-by: Vishal * dummy api with same pagination response * dummy api with same pagination response * dummy api with same pagination response * downsync data test * data integrated till beneficiary * Update CHANGELOG.md * Delete health-services/project/src/main/resources/project-persistor.yml * skip on empty result added * skip on empty result added * beneficary searhc based on individual clientref id added * sideeffetc, ref, task fetch added * tasks earch fix * referral search fix --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * Dev downsync fix smc (#561) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: kanishq-egov --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: bhanu prakash <109132521+bhanuprakash-egov@users.noreply.github.com> Co-authored-by: Naveen J <83631045+naveen-egov@users.noreply.github.com> --- docs/health-api-specs/contracts/project.yml | 4 + .../contracts/referral-management.yml | 341 ++++++----- health-services/household/pom.xml | 2 +- .../repository/HouseholdRepository.java | 19 +- .../rowmapper/HouseholdMemberRowMapper.java | 1 + .../web/models/HouseholdMemberSearch.java | 3 + ...5800__household_member_clientrefid_ddl.sql | 2 + .../health-services-models/CHANGELOG.md | 16 + .../libraries/health-services-models/pom.xml | 3 +- .../models/household/HouseholdMember.java | 5 + .../household/HouseholdMemberSearch.java | 3 + .../models/household/HouseholdSearch.java | 8 +- .../models/project/ProjectBeneficiary.java | 3 + .../project/ProjectBeneficiarySearch.java | 3 + .../beneficiarydownsync/Downsync.java | 50 ++ .../beneficiarydownsync/DownsyncCriteria.java | 39 ++ .../beneficiarydownsync/DownsyncRequest.java | 23 + .../beneficiarydownsync/DownsyncResponse.java | 23 + health-services/project/pom.xml | 2 +- .../ProjectBeneficiaryRowMapper.java | 1 + .../service/ProjectBeneficiaryService.java | 9 +- .../beneficiary/PbUniqueEntityValidator.java | 23 +- .../beneficiary/PbUniqueTagsValidator.java | 47 ++ .../PbVoucherTagUniqueForCreateValidator.java | 118 ++++ .../PbVoucherTagUniqueForUpdateValidator.java | 152 +++++ .../validator/beneficiary/ValidatorUtils.java | 39 ++ .../web/models/ProjectBeneficiarySearch.java | 3 + ...74200__add_tag_project_beneficiary_ddl.sql | 3 + ...00__rename_tag_project_beneficiary_ddl.sql | 1 + .../src/main/resources/project-indexer.yml | 93 --- .../src/main/resources/project-persistor.yml | 555 ------------------ .../main/resources/project-task-persister.yml | 158 ----- health-services/referralmanagement/pom.xml | 265 ++++----- .../ReferralManagementConfiguration.java | 21 +- .../repository/ReferralRepository.java | 29 +- .../repository/SideEffectRepository.java | 26 +- .../service/DownsyncService.java | 412 +++++++++++++ .../service/ReferralManagementService.java | 37 +- .../service/SideEffectService.java | 35 +- .../RmProjectBeneficiaryIdValidator.java | 4 +- .../SeProjectBeneficiaryIdValidator.java | 27 +- .../sideeffect/SeProjectTaskIdValidator.java | 33 +- .../BeneficiaryDownsyncController.java | 48 ++ .../src/main/resources/application.properties | 17 +- 44 files changed, 1475 insertions(+), 1231 deletions(-) create mode 100644 health-services/household/src/main/resources/db/migration/main/V20231103055800__household_member_clientrefid_ddl.sql create mode 100644 health-services/libraries/health-services-models/CHANGELOG.md create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/Downsync.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncCriteria.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncRequest.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncResponse.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbUniqueTagsValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForCreateValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForUpdateValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/beneficiary/ValidatorUtils.java create mode 100644 health-services/project/src/main/resources/db/migration/main/V20231026174200__add_tag_project_beneficiary_ddl.sql create mode 100644 health-services/project/src/main/resources/db/migration/main/V20231102105200__rename_tag_project_beneficiary_ddl.sql delete mode 100644 health-services/project/src/main/resources/project-indexer.yml delete mode 100644 health-services/project/src/main/resources/project-persistor.yml delete mode 100644 health-services/project/src/main/resources/project-task-persister.yml create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/BeneficiaryDownsyncController.java diff --git a/docs/health-api-specs/contracts/project.yml b/docs/health-api-specs/contracts/project.yml index 5989673ca43..d35c7ffcd4d 100644 --- a/docs/health-api-specs/contracts/project.yml +++ b/docs/health-api-specs/contracts/project.yml @@ -1413,6 +1413,10 @@ definitions: minLength: 2 maxLength: 64 description: Client maintained unique ID of Household/Individual being added as beneficiary + tag: + type: string + maxLength: 1000 + description: Beneficiary Voucher Tag dateOfRegistration: $ref: '#/definitions/eventTimestamp' additionalFields: diff --git a/docs/health-api-specs/contracts/referral-management.yml b/docs/health-api-specs/contracts/referral-management.yml index 074ad2b152a..18e93fb3c83 100644 --- a/docs/health-api-specs/contracts/referral-management.yml +++ b/docs/health-api-specs/contracts/referral-management.yml @@ -7,15 +7,34 @@ info: email: info@egovernments.org schemes: - https -x-common-path: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-0-0.yml +x-common-path: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-0-0.yml paths: + /referralmanagement/beneficiary-downsync/v1/_get: + post: + summary: Downsync beneficiary details for a Project + description: when data created by a different registar needs to be downsynced by another registar/device, this api will serve as a one point search for benefeiciary details + parameters: + - name: Downsync + in: body + description: Downsync of registry based on area. + required: true + schema: + $ref: '#/definitions/DownsyncRequest' + tags: + - Beneficiary Downsync + responses: + '200': + description: Downsync. + schema: + $ref: '#/definitions/DownsyncResponse' + '400': + description: Invalid Input body. + schema: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes /referralmanagement/side-effect/v1/_create: post: - summary: >- - Create side effect for the project - description: >- - Create side effect for the project + summary: Create side effect for the project + description: Create side effect for the project parameters: - name: SideEffect in: body @@ -33,15 +52,11 @@ paths: '400': description: Invalid Input body. schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes /referralmanagement/side-effect/v1/bulk/_create: post: - summary: >- - Create side effects for the project in bulk - description: >- - Create side effects for the project in bulk + summary: Create side effects for the project in bulk + description: Create side effects for the project in bulk parameters: - name: SideEffect in: body @@ -59,15 +74,11 @@ paths: '400': description: Invalid Input body. schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes /referralmanagement/side-effect/v1/_update: post: - summary: >- - Side Effect Request - description: >- - Side Effect Request + summary: Side Effect Request + description: Side Effect Request parameters: - name: SideEffect in: body @@ -85,15 +96,11 @@ paths: '400': description: Invalid Input body. schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes /referralmanagement/side-effect/v1/bulk/_update: post: - summary: >- - Side Effect Request in bulk for a project - description: >- - Side Effect Request in bulk for a project + summary: Side Effect Request in bulk for a project + description: Side Effect Request in bulk for a project parameters: - name: SideEffect in: body @@ -111,15 +118,11 @@ paths: '400': description: Invalid Input body. schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes /referralmanagement/side-effect/v1/_delete: post: - summary: >- - Soft delete Side Effect for a project - description: >- - Soft delete Side Effect for a project + summary: Soft delete Side Effect for a project + description: Soft delete Side Effect for a project parameters: - name: SideEffect in: body @@ -137,15 +140,11 @@ paths: '400': description: Invalid Input body. schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes /referralmanagement/side-effect/v1/bulk/_delete: post: - summary: >- - Soft delete Side Effects for a project - description: >- - Soft delete Side Effects for a project + summary: Soft delete Side Effects for a project + description: Soft delete Side Effects for a project parameters: - name: SideEffect in: body @@ -163,15 +162,11 @@ paths: '400': description: Invalid Input body. schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes /referralmanagement/side-effect/v1/_search: post: - summary: >- - Search Side Effect for Project - description: >- - Search Side Effect for Project + summary: Search Side Effect for Project + description: Search Side Effect for Project parameters: - name: SideEffect in: body @@ -194,15 +189,11 @@ paths: '400': description: Invalid Input body. schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes /referralmanagement/v1/_create: post: - summary: >- - Create referral for the project beneficiary - description: >- - Create referral for the project benefiaciary + summary: Create referral for the project beneficiary + description: Create referral for the project benefiaciary parameters: - name: Referral in: body @@ -220,15 +211,11 @@ paths: '400': description: Invalid Input body. schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes /referralmanagement/v1/bulk/_create: post: - summary: >- - Create referrals for the project beneficiary in bulk - description: >- - Create referrals for the project beneficiary in bulk + summary: Create referrals for the project beneficiary in bulk + description: Create referrals for the project beneficiary in bulk parameters: - name: Referral in: body @@ -246,15 +233,11 @@ paths: '400': description: Invalid Input body. schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes /referralmanagement/v1/_update: post: - summary: >- - Referral Request - description: >- - Referral Request + summary: Referral Request + description: Referral Request parameters: - name: Referral in: body @@ -272,15 +255,11 @@ paths: '400': description: Invalid Input body. schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes /referralmanagement/v1/bulk/_update: post: - summary: >- - Referral Request in bulk for a project beneficiary - description: >- - Referral Request in bulk for a project beneficiary + summary: Referral Request in bulk for a project beneficiary + description: Referral Request in bulk for a project beneficiary parameters: - name: Referral in: body @@ -298,15 +277,11 @@ paths: '400': description: Invalid Input body. schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes /referralmanagement/v1/_delete: post: - summary: >- - Soft delete Referral for a project beneficiary - description: >- - Soft delete Referral for a project beneficiary + summary: Soft delete Referral for a project beneficiary + description: Soft delete Referral for a project beneficiary parameters: - name: Referral in: body @@ -324,15 +299,11 @@ paths: '400': description: Invalid Input body. schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes /referralmanagement/v1/bulk/_delete: post: - summary: >- - Soft delete Referrals for a project beneficiary - description: >- - Soft delete Referrals for a project beneficiary + summary: Soft delete Referrals for a project beneficiary + description: Soft delete Referrals for a project beneficiary parameters: - name: Referral in: body @@ -350,15 +321,11 @@ paths: '400': description: Invalid Input body. schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes - + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes /referralmanagement/v1/_search: post: - summary: >- - Search Referral for Project - description: >- - Search Referral for Project + summary: Search Referral for Project + description: Search Referral for Project parameters: - name: Referral in: body @@ -381,11 +348,9 @@ paths: '400': description: Invalid Input body. schema: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ErrorRes parameters: - #TODO is tenantId required as a query param if it can be determine from requestInfo->userInfo tenantId: name: tenantId in: query @@ -393,7 +358,6 @@ parameters: required: true type: string format: varchar - lastChangedSince: name: lastChangedSince description: | @@ -402,7 +366,6 @@ parameters: required: false type: integer format: int64 - echoResource: name: echoResource in: query @@ -410,7 +373,6 @@ parameters: required: false default: true description: Client can specify if the resource in request body needs to be sent back in the response. This is being used to limit amount of data that needs to flow back from the server to the client in low bandwidth scenarios. Server will always send the server generated id for validated requests. - serverHandlesErrors: name: serverHandlesErrors in: query @@ -418,16 +380,14 @@ parameters: required: false default: false description: Client can specify that it is incapable of handling any errors with the requests and server should route these for manual intervention if required. - limit: name: limit description: Pagination - limit records in response in: query type: integer minimum: 0 - maximum: 1000 #TODO review + maximum: 1000 required: true - offset: name: offset description: Pagination - offset from which records should be returned in response @@ -435,7 +395,6 @@ parameters: type: integer minimum: 0 required: true - includeDeleted: name: includeDeleted description: Used in search APIs to specify if (soft) deleted records should be included in search results. @@ -443,7 +402,6 @@ parameters: type: boolean default: false required: false - includeEnded: name: includeEnded description: Used in project search API to specify if records past end date should be included in search results. @@ -451,7 +409,6 @@ parameters: type: boolean default: false required: false - includeAncestors: name: includeAncestors description: Used in project search API to specify if response should include project elements that are in the preceding hierarchy of matched projects. @@ -459,7 +416,6 @@ parameters: type: boolean default: false required: false - includeDescendants: name: includeDescendants description: Used in project search API to specify if response should include project elements that are in the following hierarchy of matched projects. @@ -467,7 +423,6 @@ parameters: type: boolean default: false required: false - createdFrom: name: createdFrom description: | @@ -476,7 +431,6 @@ parameters: required: false type: integer format: int64 - createdTo: name: createdTo description: | @@ -485,33 +439,31 @@ parameters: required: false type: integer format: int64 - definitions: boundaryCode: - $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/boundaryCode' + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/boundaryCode id: - $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/id' + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/id idForSearch: - $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/idForSearch' + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/idForSearch clientReferenceIdForSearch: - $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/clientReferenceIdForSearch' + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/clientReferenceIdForSearch clientReferenceId: - $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/clientReferenceId' + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/clientReferenceId tenantId: - $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/tenantId' + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/tenantId eventTimestamp: - $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/eventTimestamp' + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/eventTimestamp isDeleted: - $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/isDeleted' + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/isDeleted rowVersion: - $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/rowVersion' + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/rowVersion apiOperation: - $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/apiOperation' + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/apiOperation additionalFields: - $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/additionalFields' + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/additionalFields Address: - $ref: 'https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/Address' - + $ref: https://raw.githubusercontent.com/digit-egov/health-api-specs/main/contracts/common.yaml#/definitions/Address SideEffect: type: object required: @@ -532,7 +484,7 @@ definitions: description: Unique TaskId taskClientReferenceId: type: string - example: "R-ID-1" + example: R-ID-1 description: Unique Task Client Reference Id projectBeneficiaryId: type: string @@ -555,31 +507,25 @@ definitions: rowVersion: $ref: '#/definitions/rowVersion' auditDetails: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails clientAuditDetails: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails - + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails SideEffectRequest: type: object properties: RequestInfo: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo SideEffect: type: object $ref: '#/definitions/SideEffect' required: - RequestInfo - SideEffect - SideEffectBulkRequest: type: object properties: RequestInfo: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo SideEffects: type: array minItems: 1 @@ -588,7 +534,6 @@ definitions: required: - RequestInfo - SideEffects - SideEffectSearch: type: object properties: @@ -603,39 +548,33 @@ definitions: description: Unique TaskId taskClientReferenceId: type: string - example: "R-ID-1" - + example: R-ID-1 SideEffectSearchRequest: type: object properties: RequestInfo: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo SideEffect: $ref: '#/definitions/SideEffectSearch' required: - RequestInfo - SideEffect - SideEffectResponse: type: object properties: ResponseInfo: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo SideEffect: type: object $ref: '#/definitions/SideEffect' required: - ResponseInfo - SideEffect - SideEffectBulkResponse: type: object properties: ResponseInfo: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo SideEffects: type: array items: @@ -643,7 +582,6 @@ definitions: required: - ResponseInfo - SideEffects - Referral: type: object required: @@ -683,7 +621,7 @@ definitions: items: type: string sideEffect: - $ref: '#/definition/SideEffect' + $ref: '#/definitions/SideEffect' additionalFields: $ref: '#/definitions/additionalFields' isDeleted: @@ -691,31 +629,25 @@ definitions: rowVersion: $ref: '#/definitions/rowVersion' auditDetails: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails clientAuditDetails: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails - + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/AuditDetails ReferralRequest: type: object properties: RequestInfo: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo Referral: type: object $ref: '#/definitions/Referral' required: - RequestInfo - Referral - ReferralBulkRequest: type: object properties: RequestInfo: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo Referrals: type: array minItems: 1 @@ -724,7 +656,6 @@ definitions: required: - RequestInfo - Referrals - ReferralSearch: type: object properties: @@ -740,38 +671,32 @@ definitions: type: array items: type: string - ReferralSearchRequest: type: object properties: RequestInfo: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo Referral: $ref: '#/definitions/ReferralSearch' required: - RequestInfo - Referral - ReferralResponse: type: object properties: ResponseInfo: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo Referral: type: object $ref: '#/definitions/Referral' required: - ResponseInfo - Referral - ReferralBulkResponse: type: object properties: ResponseInfo: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo Referrals: type: array items: @@ -779,12 +704,82 @@ definitions: required: - ResponseInfo - Referrals - BulkAcceptedResponse: type: object properties: ResponseInfo: - $ref: >- - https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo required: - ResponseInfo + + DownsyncRequest: + type: object + properties: + RequestInfo: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/RequestInfo + DownsyncCriteria: + $ref: '#/definitions/DownsyncCriteria' + required: + - RequestInfo + - DownsyncCriteria + DownsyncResponse: + type: object + properties: + ResponseInfo: + $ref: https://raw.githubusercontent.com/egovernments/egov-services/master/docs/common/contracts/v1-1-1.yml#/definitions/ResponseInfo + Downsync: + $ref: '#/definitions/Downsync' + required: + - ResponseInfo + - Downsync + DownsyncCriteria: + type: object + properties: + locality: + type: string + description: locality/boundary code from which all beneficiary has to be downloaded + tenantId: + $ref: '#/parameters/tenantId' + offset: + $ref: '#/parameters/offset' + limit: + $ref: '#/parameters/limit' + lastSyncedTime: + $ref: '#/parameters/lastChangedSince' + includeDeleted: + $ref: '#/parameters/includeDeleted' + Downsync: + type: object + properties: + DownsyncCriteria: + $ref: '#/definitions/DownsyncCriteria' + Households: + type: array + items: + $ref: https://raw.githubusercontent.com/egovernments/health-api-specs/main/contracts/registries/household.yml#/definitions/Household + HouseholdMembers: + type: array + items: + $ref: https://raw.githubusercontent.com/egovernments/health-api-specs/main/contracts/registries/household.yml#/definitions/HouseholdMember + Individuals: + type: array + items: + $ref: https://raw.githubusercontent.com/egovernments/health-api-specs/main/contracts/registries/individual.yml#/definitions/Individual + ProjectBeneficiaries: + type: array + items: + $ref: https://raw.githubusercontent.com/egovernments/health-api-specs/main/contracts/project.yml#/definitions/ProjectBeneficiary + Tasks: + type: array + items: + $ref: https://raw.githubusercontent.com/egovernments/health-api-specs/main/contracts/project.yml#/definitions/Task + SideEffects: + type: array + items: + $ref: '#/definitions/SideEffect' + Referrals: + type: array + items: + $ref: '#/definitions/Referral' + + diff --git a/health-services/household/pom.xml b/health-services/household/pom.xml index 1024384ae9d..141a5bbd785 100644 --- a/health-services/household/pom.xml +++ b/health-services/household/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.10-SNAPSHOT + 1.0.11-SNAPSHOT compile diff --git a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java index bf7951e8804..e6e0315956f 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java +++ b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java @@ -1,6 +1,14 @@ package org.egov.household.repository; -import lombok.extern.slf4j.Slf4j; +import static org.egov.common.utils.CommonUtils.getIdMethod; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + import org.egov.common.data.query.builder.GenericQueryBuilder; import org.egov.common.data.query.builder.QueryFieldChecker; import org.egov.common.data.query.builder.SelectQueryBuilder; @@ -17,14 +25,7 @@ import org.springframework.stereotype.Repository; import org.springframework.util.ReflectionUtils; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.getIdMethod; +import lombok.extern.slf4j.Slf4j; @Repository @Slf4j diff --git a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java index 7601fa0b624..f3b40cbee6f 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java +++ b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java @@ -33,6 +33,7 @@ public HouseholdMember mapRow(ResultSet resultSet, int i) throws SQLException { return HouseholdMember.builder() .id(resultSet.getString("id")) .householdId(resultSet.getString("householdId")) + .clientReferenceId(resultSet.getString("clientReferenceId")) .householdClientReferenceId(resultSet.getString("householdClientReferenceId")) .individualClientReferenceId(resultSet.getString("individualClientReferenceId")) .individualId(resultSet.getString("individualId")) diff --git a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdMemberSearch.java b/health-services/household/src/main/java/org/egov/household/web/models/HouseholdMemberSearch.java index 96be64a0e17..a50d32819d2 100644 --- a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdMemberSearch.java +++ b/health-services/household/src/main/java/org/egov/household/web/models/HouseholdMemberSearch.java @@ -46,6 +46,9 @@ public class HouseholdMemberSearch { @JsonProperty("isHeadOfHousehold") private Boolean isHeadOfHousehold = null; + @JsonProperty("clientReferenceId") + private List clientReferenceId = null; + @JsonProperty("tenantId") @Valid private String tenantId = null; diff --git a/health-services/household/src/main/resources/db/migration/main/V20231103055800__household_member_clientrefid_ddl.sql b/health-services/household/src/main/resources/db/migration/main/V20231103055800__household_member_clientrefid_ddl.sql new file mode 100644 index 00000000000..ff837451404 --- /dev/null +++ b/health-services/household/src/main/resources/db/migration/main/V20231103055800__household_member_clientrefid_ddl.sql @@ -0,0 +1,2 @@ +ALTER TABLE HOUSEHOLD_MEMBER ADD COLUMN IF NOT EXISTS clientreferenceid character varying(256); +ALTER TABLE HOUSEHOLD_MEMBER ALTER COLUMN clientreferenceid SET NOT NULL; diff --git a/health-services/libraries/health-services-models/CHANGELOG.md b/health-services/libraries/health-services-models/CHANGELOG.md new file mode 100644 index 00000000000..ebef76b1fd0 --- /dev/null +++ b/health-services/libraries/health-services-models/CHANGELOG.md @@ -0,0 +1,16 @@ +All notable changes to this module will be documented in this file. + +## 1.0.11 +- Client reference id added for member of household +- revert of household search change + +## 1.0.10 +- Downsync models added +- Boundarycode changed to localityCode in household search + +## 1.0.9 +- stock models updated with sender and receiver information fields. + + +## 1.0.0 +- Base version diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index 089d0878172..683fa9392f1 100644 --- a/health-services/libraries/health-services-models/pom.xml +++ b/health-services/libraries/health-services-models/pom.xml @@ -5,8 +5,7 @@ 4.0.0 org.egov.common health-services-models - 1.0.10-SNAPSHOT - + 1.0.11-SNAPSHOT 8 8 diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java index ad103f7f9d0..6febe6009f3 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java @@ -41,6 +41,11 @@ public class HouseholdMember{ @Size(min = 2, max = 64) private String householdClientReferenceId = null; + @JsonProperty("clientReferenceId") + @Size(min = 2, max = 64) + @NotNull + private String clientReferenceId = null; + @JsonProperty("individualId") @Size(min = 2, max = 64) private String individualId = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearch.java index 0f65aab9d25..e7b7fa8212e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearch.java @@ -38,6 +38,9 @@ public class HouseholdMemberSearch { @JsonProperty("individualId") private String individualId = null; + @JsonProperty("clientReferenceId") + private List clientReferenceId = null; + @JsonProperty("individualClientReferenceId") private String individualClientReferenceId = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearch.java index 552f974aa47..8adfbfeee88 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearch.java @@ -1,15 +1,17 @@ package org.egov.common.models.household; +import java.util.List; + +import org.springframework.validation.annotation.Validated; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; + import io.swagger.annotations.ApiModel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import java.util.List; /** * A representation of Household. diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java index 0d060052b72..c5aa07e4f49 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java @@ -79,4 +79,7 @@ public class ProjectBeneficiary { @JsonIgnore private Boolean hasErrors = Boolean.FALSE; + @JsonProperty("tag") + private String tag; + } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiarySearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiarySearch.java index fe61c775b9e..301eebbe207 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiarySearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiarySearch.java @@ -46,5 +46,8 @@ public class ProjectBeneficiarySearch { @JsonProperty("dateOfRegistration") private Long dateOfRegistration = null; + + @JsonProperty("tag") + private List tag = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/Downsync.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/Downsync.java new file mode 100644 index 00000000000..c53e28da3fe --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/Downsync.java @@ -0,0 +1,50 @@ +package org.egov.common.models.referralmanagement.beneficiarydownsync; + +import java.util.List; + +import org.egov.common.models.household.Household; +import org.egov.common.models.household.HouseholdMember; +import org.egov.common.models.individual.Individual; +import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.models.project.Task; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class Downsync { + + @JsonProperty("Households") + private List Households; + + @JsonProperty("HouseholdMembers") + private List HouseholdMembers; + + @JsonProperty("Individuals") + private List Individuals; + + @JsonProperty("ProjectBeneficiaries") + private List ProjectBeneficiaries; + + @JsonProperty("Tasks") + private List Tasks; + + @JsonProperty("SideEffects") + private List SideEffects; + + @JsonProperty("Referrals") + private List Referrals; + + @JsonProperty("DownsyncCriteria") + private DownsyncCriteria downsyncCriteria; + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncCriteria.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncCriteria.java new file mode 100644 index 00000000000..6548e7c5025 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncCriteria.java @@ -0,0 +1,39 @@ +package org.egov.common.models.referralmanagement.beneficiarydownsync; + +import javax.validation.constraints.NotNull; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Builder.Default; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class DownsyncCriteria { + + @NotNull + private String locality; + + private Long lastSyncedTime; + + @NotNull + private String projectId; + + @NotNull + private String tenantId; + + @Default + private Boolean includeDeleted = false; + + @Default + private Integer offset = 0; + + @Default + private Integer limit = 50; + + private Long totalCount; +} + diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncRequest.java new file mode 100644 index 00000000000..6db2a1f97b9 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncRequest.java @@ -0,0 +1,23 @@ +package org.egov.common.models.referralmanagement.beneficiarydownsync; + +import org.egov.common.contract.request.RequestInfo; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class DownsyncRequest { + + @JsonProperty("RequestInfo") + private RequestInfo requestInfo; + + @JsonProperty("DownsyncCriteria") + private DownsyncCriteria downsyncCriteria; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncResponse.java new file mode 100644 index 00000000000..23635cf119a --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncResponse.java @@ -0,0 +1,23 @@ +package org.egov.common.models.referralmanagement.beneficiarydownsync; + +import org.egov.common.contract.response.ResponseInfo; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class DownsyncResponse { + + @JsonProperty("ResponseInfo") + private ResponseInfo responseInfo; + + @JsonProperty("Downsync") + private Downsync downsync; +} diff --git a/health-services/project/pom.xml b/health-services/project/pom.xml index f9e6a5fa7de..7f13ee5a53f 100644 --- a/health-services/project/pom.xml +++ b/health-services/project/pom.xml @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.9-SNAPSHOT + 1.0.10-SNAPSHOT compile diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java index f596a1eb68a..880518fc0d7 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java @@ -47,6 +47,7 @@ public ProjectBeneficiary mapRow(ResultSet resultSet, int i) throws SQLException .clientAuditDetails(clientAuditDetails) .rowVersion(resultSet.getInt("rowversion")) .isDeleted(resultSet.getBoolean("isdeleted")) + .tag(resultSet.getString("tag")) .build(); } catch (JsonProcessingException e) { throw new SQLException(e); diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectBeneficiaryService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectBeneficiaryService.java index 11d094561c4..5c8b5ea8862 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectBeneficiaryService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectBeneficiaryService.java @@ -19,6 +19,9 @@ import org.egov.project.validator.beneficiary.PbProjectIdValidator; import org.egov.project.validator.beneficiary.PbRowVersionValidator; import org.egov.project.validator.beneficiary.PbUniqueEntityValidator; +import org.egov.project.validator.beneficiary.PbUniqueTagsValidator; +import org.egov.project.validator.beneficiary.PbVoucherTagUniqueForCreateValidator; +import org.egov.project.validator.beneficiary.PbVoucherTagUniqueForUpdateValidator; import org.egov.project.web.models.BeneficiarySearchRequest; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; @@ -62,6 +65,8 @@ public class ProjectBeneficiaryService { private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(PbNullIdValidator.class) || validator.getClass().equals(PbNonExistentEntityValidator.class) + || validator.getClass().equals(PbUniqueTagsValidator.class) + || validator.getClass().equals(PbVoucherTagUniqueForUpdateValidator.class) || validator.getClass().equals(PbIsDeletedValidator.class) || validator.getClass().equals(PbProjectIdValidator.class) || validator.getClass().equals(BeneficiaryValidator.class) @@ -70,7 +75,9 @@ public class ProjectBeneficiaryService { private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(PbProjectIdValidator.class) - || validator.getClass().equals(BeneficiaryValidator.class); + || validator.getClass().equals(BeneficiaryValidator.class) + || validator.getClass().equals(PbUniqueTagsValidator.class) + || validator.getClass().equals(PbVoucherTagUniqueForCreateValidator.class); private final Predicate> isApplicableForDelete = validator -> validator.getClass().equals(PbNullIdValidator.class) diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbUniqueEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbUniqueEntityValidator.java index 13485596684..7feed061ea6 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbUniqueEntityValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbUniqueEntityValidator.java @@ -8,6 +8,7 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -18,24 +19,42 @@ import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; +/** + * This class, PbUniqueEntityValidator, is a Spring component that serves as a validator for ensuring the uniqueness + * of entities (ProjectBeneficiaries) within a BeneficiaryBulkRequest. It implements the Validator interface, which + * allows it to validate the request by checking for duplicate entities based on their IDs. + */ @Component @Order(value = 2) @Slf4j public class PbUniqueEntityValidator implements Validator { + /** + * This method validates the uniqueness of entities within a BeneficiaryBulkRequest. + * + * @param request The BeneficiaryBulkRequest to validate. + * @return A map containing error details for entities that are not unique. + */ @Override public Map> validate(BeneficiaryBulkRequest request) { log.info("validating unique entity"); Map> errorDetailsMap = new HashMap<>(); List validProjectBeneficiaries = request.getProjectBeneficiaries() .stream().filter(notHavingErrors()).collect(Collectors.toList()); + if (!validProjectBeneficiaries.isEmpty()) { + + List duplicates = new ArrayList<>(); Map iMap = getIdToObjMap(validProjectBeneficiaries); + if (iMap.keySet().size() != validProjectBeneficiaries.size()) { - List duplicates = iMap.keySet().stream().filter(id -> + // Find duplicate entities by comparing their IDs + duplicates = iMap.keySet().stream().filter(id -> validProjectBeneficiaries.stream() .filter(projectBeneficiary -> projectBeneficiary.getId().equals(id)).count() > 1 ).collect(Collectors.toList()); + + // Populate error details for duplicate entities for (String key : duplicates) { Error error = getErrorForUniqueEntity(); populateErrorDetails(iMap.get(key), error, errorDetailsMap); @@ -44,4 +63,6 @@ public Map> validate(BeneficiaryBulkRequest requ } return errorDetailsMap; } + + } diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbUniqueTagsValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbUniqueTagsValidator.java new file mode 100644 index 00000000000..47800b3af65 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbUniqueTagsValidator.java @@ -0,0 +1,47 @@ +package org.egov.project.validator.beneficiary; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.BeneficiaryBulkRequest; +import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.project.validator.beneficiary.ValidatorUtils.validateUniqueTags; + +/** + * This class, PbUniqueEntityValidator, is a Spring component that serves as a validator for ensuring the uniqueness + * of entities (ProjectBeneficiaries) within a BeneficiaryBulkRequest. It implements the Validator interface, which + * allows it to validate the request by checking for duplicate entities based on their Voucher Tags. + */ +@Component +@Order(value = 2) +@Slf4j +public class PbUniqueTagsValidator implements Validator { + + /** + * This method validates the uniqueness of entities within a BeneficiaryBulkRequest. + * + * @param request The BeneficiaryBulkRequest to validate. + * @return A map containing error details for entities that are not unique. + */ + @Override + public Map> validate(BeneficiaryBulkRequest request) { + log.info("validating unique voucher tags"); + Map> errorDetailsMap = new HashMap<>(); + List validProjectBeneficiaries = request.getProjectBeneficiaries() + .stream().filter(notHavingErrors()).collect(Collectors.toList()); + + if (!validProjectBeneficiaries.isEmpty()) { + validateUniqueTags(validProjectBeneficiaries, errorDetailsMap); + } + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForCreateValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForCreateValidator.java new file mode 100644 index 00000000000..dbac480cccd --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForCreateValidator.java @@ -0,0 +1,118 @@ +package org.egov.project.validator.beneficiary; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.BeneficiaryBulkRequest; +import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.validator.Validator; +import org.egov.project.repository.ProjectBeneficiaryRepository; +import org.egov.project.web.models.ProjectBeneficiarySearch; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * This class, PbVoucherTagUniqueValidator, is a Spring component that serves as a validator for ensuring the uniqueness + * of voucher tags within a list of project beneficiaries. It implements the Validator interface, which allows it to + * validate a BeneficiaryBulkRequest containing a list of ProjectBeneficiary objects. Any duplicate voucher tags within + * the list result in error details being populated for the respective ProjectBeneficiary objects. + */ +@Component +@Order(value = 2) +@Slf4j +public class PbVoucherTagUniqueForCreateValidator implements Validator { + final ProjectBeneficiaryRepository projectBeneficiaryRepository; + + @Autowired + public PbVoucherTagUniqueForCreateValidator(ProjectBeneficiaryRepository projectBeneficiaryRepository) { + this.projectBeneficiaryRepository = projectBeneficiaryRepository; + } + + /** + * + * @param beneficiaryBulkRequest + * @return + */ + @Override + public Map> validate(BeneficiaryBulkRequest beneficiaryBulkRequest) { + log.info("validating unique tag for create"); + + // Create a map to store error details for each ProjectBeneficiary + Map> errorDetailsMap = new HashMap<>(); + + // Filter valid project beneficiaries (those without errors) + List validProjectBeneficiaries = beneficiaryBulkRequest.getProjectBeneficiaries() + .stream().filter(notHavingErrors()).collect(Collectors.toList()); + + if(!validProjectBeneficiaries.isEmpty()) { + // Get a list of invalid voucher tags + List existingProjectBeneficiaries = getInvalidVoucherTags(validProjectBeneficiaries); + + // Validate and populate errors for invalid voucher tags + if(!existingProjectBeneficiaries.isEmpty()) + validateAndPopulateErrors(validProjectBeneficiaries, existingProjectBeneficiaries, errorDetailsMap); + } + + return errorDetailsMap; + } + + // Helper method to validate and populate errors + private void validateAndPopulateErrors(List validProjectBeneficiaries, List existingProjectBeneficiaries, Map> errorDetailsMap) { + List existingVoucherTags = existingProjectBeneficiaries.stream().map(ProjectBeneficiary::getTag).collect(Collectors.toList()); + // Filter project beneficiaries that are valid and have invalid voucher tags + List invalidEntities = validProjectBeneficiaries.stream().filter(notHavingErrors()) + .filter(entity -> existingVoucherTags.contains(entity.getTag())) + .collect(Collectors.toList()); + + // For each invalid entity, create an error and populate error details + invalidEntities.forEach(projectBeneficiary -> { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(projectBeneficiary, error, errorDetailsMap); + }); + } + + // Helper method to get invalid voucher tags + private List getInvalidVoucherTags(List validProjectBeneficiaries) { + // Extract voucher tags from valid project beneficiaries + List voucherTags = validProjectBeneficiaries.stream() + .filter(Objects::nonNull) + .map(ProjectBeneficiary::getTag) + .collect(Collectors.toList()); + + if(CollectionUtils.isEmpty(voucherTags)) + return new ArrayList<>(); + + // Create a list to store existing project beneficiary with voucher tag + List existingProjectBeneficiaries; + + // Build a search request to find existing voucher tags + ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder().tag(voucherTags).build(); + + try { + log.info("Fetching project beneficiary based on voucher tags"); + existingProjectBeneficiaries = projectBeneficiaryRepository.find( + projectBeneficiarySearch, + voucherTags.size(), 0, validProjectBeneficiaries.get(0).getTenantId(), null, false + ); + } catch (Exception e) { + log.error("Exception while fetching project beneficiary service : ", e); + throw new CustomException("PROJECT_BENEFICIARY_VOUCHER_TAG_SEARCH_FAILED","Error occurred while fetching project beneficiary based on voucher tags. "+e); + } + + // return existing project beneficiaries + return existingProjectBeneficiaries; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForUpdateValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForUpdateValidator.java new file mode 100644 index 00000000000..be699f6b145 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForUpdateValidator.java @@ -0,0 +1,152 @@ +package org.egov.project.validator.beneficiary; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.BeneficiaryBulkRequest; +import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.validator.Validator; +import org.egov.project.repository.ProjectBeneficiaryRepository; +import org.egov.project.web.models.ProjectBeneficiarySearch; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * This class, PbVoucherTagUniqueValidator, is a Spring component that serves as a validator for ensuring the uniqueness + * of voucher tags within a list of project beneficiaries. It implements the Validator interface, which allows it to + * validate a BeneficiaryBulkRequest containing a list of ProjectBeneficiary objects. Any duplicate voucher tags within + * the list result in error details being populated for the respective ProjectBeneficiary objects. + */ +@Component +@Order(value = 2) +@Slf4j +public class PbVoucherTagUniqueForUpdateValidator implements Validator { + final ProjectBeneficiaryRepository projectBeneficiaryRepository; + + @Autowired + public PbVoucherTagUniqueForUpdateValidator(ProjectBeneficiaryRepository projectBeneficiaryRepository) { + this.projectBeneficiaryRepository = projectBeneficiaryRepository; + } + + /** + * + * @param beneficiaryBulkRequest + * @return + */ + @Override + public Map> validate(BeneficiaryBulkRequest beneficiaryBulkRequest) { + log.info("validating unique tag"); + + // Create a map to store error details for each ProjectBeneficiary + Map> errorDetailsMap = new HashMap<>(); + + // Filter valid project beneficiaries (those without errors) + List validProjectBeneficiaries = beneficiaryBulkRequest.getProjectBeneficiaries() + .stream().filter(notHavingErrors()).collect(Collectors.toList()); + + if(!validProjectBeneficiaries.isEmpty()) { + // Get a list of existing ProjectBeneficiaries based on IDs + List existingProjectBeneficiaries = getExistingProjectBeneficiaries(validProjectBeneficiaries); + + // Validate and populate errors for invalid voucher tags + if(!CollectionUtils.isEmpty(existingProjectBeneficiaries)) + validateAndPopulateErrors(validProjectBeneficiaries, existingProjectBeneficiaries, errorDetailsMap); + } + + return errorDetailsMap; + } + + /** + * This method retrieves existing ProjectBeneficiary entities based on their IDs. + * + * @param validProjectBeneficiaries List of valid ProjectBeneficiary entities. + * @return A list of existing ProjectBeneficiary entities. + */ + private List getExistingProjectBeneficiaries(List validProjectBeneficiaries) { + List existingProjectBeneficiaries = null; + + // Build a search request to find existing voucher tags + ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() + .id(validProjectBeneficiaries.stream().map(ProjectBeneficiary::getId).collect(Collectors.toList())) + .build(); + + try { + log.info("Fetching project beneficiary based on voucher tags"); + existingProjectBeneficiaries = projectBeneficiaryRepository.find( + projectBeneficiarySearch, + validProjectBeneficiaries.size(), 0, validProjectBeneficiaries.get(0).getTenantId(), null, false + ); + } catch (Exception e) { + log.error("Exception while fetching project beneficiary service : ", e); + throw new CustomException("PROJECT_BENEFICIARY_SEARCH_FAILED","Error occurred while fetching project beneficiary based on ids. "+e); + } + return existingProjectBeneficiaries; + } + + /** + * This method validates and populates errors for ProjectBeneficiary entities with duplicate voucher tags. + * + * @param validProjectBeneficiaries List of valid ProjectBeneficiary entities. + * @param existingProjectBeneficiaries List of existing ProjectBeneficiary entities based on IDs. + * @param errorDetailsMap A map to store error details for duplicate voucher tags. + */ + private void validateAndPopulateErrors(List validProjectBeneficiaries, List existingProjectBeneficiaries, Map> errorDetailsMap) { + Map existingProjectBeneficiaryMap = existingProjectBeneficiaries.stream().collect(Collectors.toMap(ProjectBeneficiary::getId, projectBeneficiary -> projectBeneficiary)); + // Filter project beneficiaries that are valid and have invalid voucher tags + List invalidEntities = validProjectBeneficiaries.stream().filter(notHavingErrors()) + .filter(entity -> !existingProjectBeneficiaryMap.containsKey(entity.getId())) + .collect(Collectors.toList()); + + populateErrors(invalidEntities, errorDetailsMap); + + List existingVoucherTags = existingProjectBeneficiaries.stream().map(ProjectBeneficiary::getTag).collect(Collectors.toList()); + invalidEntities = validProjectBeneficiaries.stream() + .filter(notHavingErrors()) + .filter(projectBeneficiary -> !existingProjectBeneficiaryMap.get(projectBeneficiary.getId()).getTag().equals(projectBeneficiary.getTag())) + .filter(projectBeneficiary -> isInvalid(projectBeneficiary, existingVoucherTags)) + .collect(Collectors.toList()); + + populateErrors(invalidEntities, errorDetailsMap); + } + + /** + * This method populates error details for a list of ProjectBeneficiary entities with duplicate voucher tags. + * + * @param invalidEntities List of ProjectBeneficiary entities with duplicate voucher tags. + * @param errorDetailsMap A map to store error details. + */ + private void populateErrors(List invalidEntities, Map> errorDetailsMap) { + // For each invalid entity, create an error and populate error details + invalidEntities.forEach(projectBeneficiary -> { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(projectBeneficiary, error, errorDetailsMap); + }); + } + + /** + * This method checks if a ProjectBeneficiary entity is invalid based on its voucher tag. + * + * @param entity The ProjectBeneficiary entity to check. + * @param existingVoucherTags + * @return true if the entity is invalid, false otherwise. + */ + private boolean isInvalid(ProjectBeneficiary entity, List existingVoucherTags) { + String id = entity.getId(); + String tag = entity.getTag(); + + // Check if an entity with the same ID exists in the map and has a different tag + return existingVoucherTags.contains(tag); + } + +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/ValidatorUtils.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/ValidatorUtils.java new file mode 100644 index 00000000000..a692601b501 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/ValidatorUtils.java @@ -0,0 +1,39 @@ +package org.egov.project.validator.beneficiary; + +import org.egov.common.models.Error; +import org.egov.common.models.project.ProjectBeneficiary; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +public class ValidatorUtils { + /** + * This method validates the uniqueness of voucher tags among valid ProjectBeneficiary entities. + * + * @param validProjectBeneficiaries List of valid ProjectBeneficiary entities. + * @param errorDetailsMap A map to store error details for duplicate voucher tags. + */ + public static void validateUniqueTags(List validProjectBeneficiaries, Map> errorDetailsMap) { + // Group ProjectBeneficiaries by voucher tags + Map> map = validProjectBeneficiaries.stream().filter(projectBeneficiary -> projectBeneficiary.getTag() != null) + .collect(Collectors.groupingBy(ProjectBeneficiary::getTag)); + + // Find voucher tags with duplicates + List duplicates = map.values().stream() + .filter(projectBeneficiaries -> projectBeneficiaries.size() > 1) + .flatMap(List::stream) + .filter(notHavingErrors()) + .collect(Collectors.toList()); + + // Populate error details for entities with duplicate voucher tags + for (ProjectBeneficiary projectBeneficiary : duplicates) { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(projectBeneficiary, error, errorDetailsMap); + } + } +} diff --git a/health-services/project/src/main/java/org/egov/project/web/models/ProjectBeneficiarySearch.java b/health-services/project/src/main/java/org/egov/project/web/models/ProjectBeneficiarySearch.java index c9f8a61034b..1e58c06fd11 100644 --- a/health-services/project/src/main/java/org/egov/project/web/models/ProjectBeneficiarySearch.java +++ b/health-services/project/src/main/java/org/egov/project/web/models/ProjectBeneficiarySearch.java @@ -48,5 +48,8 @@ public class ProjectBeneficiarySearch { @JsonProperty("dateOfRegistration") private Long dateOfRegistration = null; + + @JsonProperty("tag") + private List tag; } diff --git a/health-services/project/src/main/resources/db/migration/main/V20231026174200__add_tag_project_beneficiary_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20231026174200__add_tag_project_beneficiary_ddl.sql new file mode 100644 index 00000000000..85b2ff465e0 --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20231026174200__add_tag_project_beneficiary_ddl.sql @@ -0,0 +1,3 @@ +ALTER TABLE PROJECT_BENEFICIARY ADD COLUMN IF NOT EXISTS voucherTag character varying(1000); +ALTER TABLE PROJECT_BENEFICIARY ADD UNIQUE (voucherTag); + diff --git a/health-services/project/src/main/resources/db/migration/main/V20231102105200__rename_tag_project_beneficiary_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20231102105200__rename_tag_project_beneficiary_ddl.sql new file mode 100644 index 00000000000..9a268635b56 --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20231102105200__rename_tag_project_beneficiary_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE project_beneficiary RENAME COLUMN voucherTag TO tag; \ No newline at end of file diff --git a/health-services/project/src/main/resources/project-indexer.yml b/health-services/project/src/main/resources/project-indexer.yml deleted file mode 100644 index 66f9ee3fe58..00000000000 --- a/health-services/project/src/main/resources/project-indexer.yml +++ /dev/null @@ -1,93 +0,0 @@ -ServiceMaps: - serviceName: Project Service - version: 1.0.0 - mappings: - - topic: save-project-staff-topic - configKey: INDEX - indexes: - - name: projectStaffIndex-v1 - type: projectStaff - id: $.id - isBulk: true - jsonPath: $.* - timeStampField: $.auditDetails.createdTime - - - topic: update-project-staff-topic - configKey: INDEX - indexes: - - name: projectStaffUpdateIndex-v1 - type: projectStaff-update - id: $.id - isBulk: true - jsonPath: $.* - timeStampField: $.auditDetails.lastModifiedTime - - - topic: delete-project-staff-topic - configKey: INDEX - indexes: - - name: projectStaffDeleteIndex-v1 - type: projectStaff-delete - id: $.id - isBulk: true - jsonPath: $.* - timeStampField: $.auditDetails.lastModifiedTime - - - topic: save-project-beneficiary-topic - configKey: INDEX - indexes: - - name: projectBeneficiaryIndex-v1 - type: projectBeneficiary - id: $.id - isBulk: true - jsonPath: $.* - timeStampField: $.auditDetails.createdTime - - - topic: update-project-beneficiary-topic - configKey: INDEX - indexes: - - name: projectBeneficiaryUpdateIndex-v1 - type: projectBeneficiary-update - id: $.id - isBulk: true - jsonPath: $.* - timeStampField: $.auditDetails.lastModifiedTime - - - topic: delete-project-beneficiary-topic - configKey: INDEX - indexes: - - name: projectBeneficiaryDeleteIndex-v1 - type: projectBeneficiary-delete - id: $.id - isBulk: true - jsonPath: $.* - timeStampField: $.auditDetails.lastModifiedTime - - - topic: save-project-facility-topic - configKey: INDEX - indexes: - - name: projectFacilityIndex-v1 - type: projectFacility - id: $.id - isBulk: true - jsonPath: $.* - timeStampField: $.auditDetails.createdTime - - - topic: update-project-facility-topic - configKey: INDEX - indexes: - - name: projectFacilityUpdateIndex-v1 - type: projectFacility-update - id: $.id - isBulk: true - jsonPath: $.* - timeStampField: $.auditDetails.lastModifiedTime - - - topic: delete-project-facility-topic - configKey: INDEX - indexes: - - name: projectFacilityDeleteIndex-v1 - type: projectFacility-delete - id: $.id - isBulk: true - jsonPath: $.* - timeStampField: $.auditDetails.lastModifiedTime \ No newline at end of file diff --git a/health-services/project/src/main/resources/project-persistor.yml b/health-services/project/src/main/resources/project-persistor.yml deleted file mode 100644 index c3b36201e6d..00000000000 --- a/health-services/project/src/main/resources/project-persistor.yml +++ /dev/null @@ -1,555 +0,0 @@ -serviceMaps: - serviceName: project - mappings: - - version: 1.0 - description: Saves a project staff - fromTopic: save-project-staff-topic - isTransaction: true - queryMaps: - - query: INSERT INTO project_staff (id, tenantId, projectId, staffId, startDate, endDate, additionalDetails, createdBy, lastModifiedBy, createdTime, lastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?); - basePath: $.* - jsonMaps: - - jsonPath: $.*.id - - jsonPath: $.*.tenantId - - jsonPath: $.*.projectId - - jsonPath: $.*.userId - - jsonPath: $.*.startDate - - jsonPath: $.*.endDate - - jsonPath: $.*.additionalFields - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.createdBy - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.createdTime - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - - version: 1.0 - description: Update Project Staff - fromTopic: update-project-staff-topic - isTransaction: true - queryMaps: - - query: UPDATE project_staff SET projectId=?, staffId=?, startDate=?, endDate=?, additionalDetails=?, lastModifiedBy=?, lastModifiedTime=?, rowVersion=?, isDeleted=? WHERE id = ? - basePath: $.* - jsonMaps: - - jsonPath: $.*.projectId - - jsonPath: $.*.userId - - jsonPath: $.*.startDate - - jsonPath: $.*.endDate - - jsonPath: $.*.additionalFields - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id - - - version: 1.0 - description: Deletes Project Staff - fromTopic: delete-project-staff-topic - isTransaction: true - queryMaps: - - query: UPDATE project_staff SET lastModifiedBy=?, lastModifiedTime=?, rowVersion=?, isDeleted=? WHERE id=?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id - - - version: 1.0 - description: Saves a project beneficiary - fromTopic: save-project-beneficiary-topic - isTransaction: true - queryMaps: - - query: INSERT INTO project_beneficiary (id, tenantId, projectId, beneficiaryId, clientReferenceId, beneficiaryClientReferenceId, dateOfRegistration, additionalDetails, createdBy, lastModifiedBy, createdTime, lastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?); - basePath: $.* - jsonMaps: - - jsonPath: $.*.id - - jsonPath: $.*.tenantId - - jsonPath: $.*.projectId - - jsonPath: $.*.beneficiaryId - - jsonPath: $.*.clientReferenceId - - jsonPath: $.*.beneficiaryClientReferenceId - - jsonPath: $.*.dateOfRegistration - - jsonPath: $.*.additionalFields - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.createdBy - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.createdTime - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - - version: 1.0 - description: Update Project Beneficiary - fromTopic: update-project-beneficiary-topic - isTransaction: true - queryMaps: - - query: UPDATE project_beneficiary SET projectId=?, beneficiaryId=?, clientReferenceId=?, beneficiaryClientReferenceId=?, dateOfRegistration=?, additionalDetails=?, lastModifiedBy=?, lastModifiedTime=?, rowVersion=?, isDeleted=? WHERE id = ? AND isDeleted=false - basePath: $.* - jsonMaps: - - jsonPath: $.*.projectId - - jsonPath: $.*.beneficiaryId - - jsonPath: $.*.clientReferenceId - - jsonPath: $.*.beneficiaryClientReferenceId - - jsonPath: $.*.dateOfRegistration - - jsonPath: $.*.additionalFields - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id - - - version: 1.0 - description: Deletes Project Beneficiaries - fromTopic: delete-project-beneficiary-topic - isTransaction: true - queryMaps: - - query: UPDATE project_beneficiary SET lastModifiedBy=?, lastModifiedTime=?, rowVersion=?, isDeleted=? WHERE id=?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id - - - version: 1.0 - name: Projects - description: Persists project details in project table - fromTopic: save-project - isTransaction: true - queryMaps: - - query: INSERT INTO project(id,tenantId,projectNumber,name,projectType,projectSubType,department,description,referenceId,startDate,endDate,isTaskEnabled,parent,projectHierarchy,additionalDetails,isDeleted,rowVersion,createdBy,lastModifiedBy,createdTime,lastModifiedTime) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); - basePath: $.Projects.* - jsonMaps: - - jsonPath: $.Projects.*.id - - - jsonPath: $.Projects.*.tenantId - - - jsonPath: $.Projects.*.projectNumber - - - jsonPath: $.Projects.*.name - - - jsonPath: $.Projects.*.projectType - - - jsonPath: $.Projects.*.projectSubType - - - jsonPath: $.Projects.*.department - - - jsonPath: $.Projects.*.description - - - jsonPath: $.Projects.*.referenceID - - - jsonPath: $.Projects.*.startDate - - - jsonPath: $.Projects.*.endDate - - - jsonPath: $.Projects.*.isTaskEnabled - - - jsonPath: $.Projects.*.parent - - - jsonPath: $.Projects.*.projectHierarchy - - - jsonPath: $.Projects.*.additionalDetails - type: JSON - dbType: JSONB - - - jsonPath: $.Projects.*.isDeleted - - - jsonPath: $.Projects.*.rowVersion - - - jsonPath: $.Projects.*.auditDetails.createdBy - - - jsonPath: $.Projects.*.auditDetails.lastModifiedBy - - - jsonPath: $.Projects.*.auditDetails.createdTime - - - jsonPath: $.Projects.*.auditDetails.lastModifiedTime - - - - query: INSERT INTO project_address(id,tenantId,projectId,doorNo,latitude,longitude,locationAccuracy,type,addressLine1,addressLine2,landmark,city,pinCode,buildingName,street,locality) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); - basePath: $.Projects.*.address - jsonMaps: - - jsonPath: $.Projects.*.address.id - - - jsonPath: $.Projects.*.address.tenantId - - - jsonPath: $.Projects.*.id - - - jsonPath: $.Projects.*.address.doorNo - - - jsonPath: $.Projects.*.address.latitude - - - jsonPath: $.Projects.*.address.longitude - - - jsonPath: $.Projects.*.address.locationAccuracy - - - jsonPath: $.Projects.*.address.type - - - jsonPath: $.Projects.*.address.addressLine1 - - - jsonPath: $.Projects.*.address.addressLine2 - - - jsonPath: $.Projects.*.address.landmark - - - jsonPath: $.Projects.*.address.city - - - jsonPath: $.Projects.*.address.pincode - - - jsonPath: $.Projects.*.address.buildingName - - - jsonPath: $.Projects.*.address.street - - - jsonPath: $.Projects.*.address.locality - - - - query: INSERT INTO project_target(id,projectId,beneficiaryType,totalNo,targetNo,isDeleted,createdBy,lastModifiedBy,createdTime,lastModifiedTime) VALUES (?,?,?,?,?,?,?,?,?,?); - basePath: $.Projects.*.targets.* - jsonMaps: - - jsonPath: $.Projects.*.targets.*.id - - - jsonPath: $.Projects[*][?({id} in @.targets[*].id)].id - - - jsonPath: $.Projects.*.targets.*.beneficiaryType - - - jsonPath: $.Projects.*.targets.*.totalNo - - - jsonPath: $.Projects.*.targets.*.targetNo - - - jsonPath: $.Projects.*.targets.*.isDeleted - - - jsonPath: $.Projects.*.targets.*.auditDetails.createdBy - - - jsonPath: $.Projects.*.targets.*.auditDetails.lastModifiedBy - - - jsonPath: $.Projects.*.targets.*.auditDetails.createdTime - - - jsonPath: $.Projects.*.targets.*.auditDetails.lastModifiedTime - - - - query: INSERT INTO project_document(id,projectId,documentType,filestoreId,documentUid,additionalDetails,status,createdBy,lastModifiedBy,createdTime,lastModifiedTime) VALUES (?,?,?,?,?,?,?,?,?,?,?); - basePath: $.Projects.*.documents.* - jsonMaps: - - jsonPath: $.Projects.*.documents.*.id - - - jsonPath: $.Projects[*][?({id} in @.documents[*].id)].id - - - jsonPath: $.Projects.*.documents.*.documentType - - - jsonPath: $.Projects.*.documents.*.fileStore - - - jsonPath: $.Projects.*.documents.*.documentUid - - - jsonPath: $.Projects.*.additionalDetails - type: JSON - dbType: JSONB - - - jsonPath: $.Projects.*.documents.*.status - - - jsonPath: $.Projects.*.documents.*.auditDetails.createdBy - - - jsonPath: $.Projects.*.documents.*.auditDetails.lastModifiedBy - - - jsonPath: $.Projects.*.documents.*.auditDetails.createdTime - - - jsonPath: $.Projects.*.documents.*.auditDetails.lastModifiedTime - - - - version: 1.0 - name: Projects - description: Updates project details in project table - fromTopic: update-project - isTransaction: true - queryMaps: - - query: UPDATE project SET name = ?, projectType = ?, projectSubType = ?, department = ?, description = ?, referenceId = ?, startDate = ?, endDate = ?, isTaskEnabled = ?, additionalDetails = ?, isDeleted = ?, rowVersion = ?, lastModifiedBy = ?, lastModifiedTime = ? WHERE id = ?; - basePath: $.Projects.* - jsonMaps: - - - jsonPath: $.Projects.*.name - - - jsonPath: $.Projects.*.projectType - - - jsonPath: $.Projects.*.projectSubType - - - jsonPath: $.Projects.*.department - - - jsonPath: $.Projects.*.description - - - jsonPath: $.Projects.*.referenceID - - - jsonPath: $.Projects.*.startDate - - - jsonPath: $.Projects.*.endDate - - - jsonPath: $.Projects.*.isTaskEnabled - - - jsonPath: $.Projects.*.additionalDetails - type: JSON - dbType: JSONB - - - jsonPath: $.Projects.*.isDeleted - - - jsonPath: $.Projects.*.rowVersion - - - jsonPath: $.Projects.*.auditDetails.lastModifiedBy - - - jsonPath: $.Projects.*.auditDetails.lastModifiedTime - - - jsonPath: $.Projects.*.id - - - - query: UPDATE project_address SET door_no = ?, latitude=?, longitude=?, locationAccuracy=?, type=?, addressLine1=?, addressLine2=?, landmark=?, city=?, pinCode=?, buildingName=?, street=? WHERE id=?; - basePath: $.Projects.*.address - jsonMaps: - - - jsonPath: $.Projects.*.address.doorNo - - - jsonPath: $.Projects.*.address.latitude - - - jsonPath: $.Projects.*.address.longitude - - - jsonPath: $.Projects.*.address.locationAccuracy - - - jsonPath: $.Projects.*.address.type - - - jsonPath: $.Projects.*.address.addressLine1 - - - jsonPath: $.Projects.*.address.addressLine2 - - - jsonPath: $.Projects.*.address.landmark - - - jsonPath: $.Projects.*.address.city - - - jsonPath: $.Projects.*.address.pincode - - - jsonPath: $.Projects.*.address.buildingName - - - jsonPath: $.Projects.*.address.street - - - jsonPath: $.Projects.*.address.id - - - - query: INSERT INTO project_target(id,projectId,beneficiaryType,totalNo,targetNo,isDeleted,createdBy,lastModifiedBy,createdTime,lastModifiedTime) VALUES (?,?,?,?,?,?,?,?,?,?) ON CONFLICT (id) DO UPDATE SET beneficiary_type = ?, totalNo =?, targetNo=?, isDeleted=?, lastModifiedBy=?, lastModifiedTime=?; - basePath: $.Projects.*.targets.* - jsonMaps: - - - jsonPath: $.Projects.*.targets.*.id - - - jsonPath: $.Projects[*][?({id} in @.targets[*].id)].id - - - jsonPath: $.Projects.*.targets.*.beneficiaryType - - - jsonPath: $.Projects.*.targets.*.totalNo - - - jsonPath: $.Projects.*.targets.*.targetNo - - - jsonPath: $.Projects.*.targets.*.isDeleted - - - jsonPath: $.Projects.*.targets.*.auditDetails.createdBy - - - jsonPath: $.Projects.*.targets.*.auditDetails.lastModifiedBy - - - jsonPath: $.Projects.*.targets.*.auditDetails.createdTime - - - jsonPath: $.Projects.*.targets.*.auditDetails.lastModifiedTime - - - jsonPath: $.Projects.*.targets.*.beneficiaryType - - - jsonPath: $.Projects.*.targets.*.totalNo - - - jsonPath: $.Projects.*.targets.*.targetNo - - - jsonPath: $.Projects.*.targets.*.isDeleted - - - jsonPath: $.Projects.*.targets.*.auditDetails.lastModifiedBy - - - jsonPath: $.Projects.*.targets.*.auditDetails.lastModifiedTime - - - - query: INSERT INTO project_document(id,projectId,documentType,filestoreId,documentUid,additionalDetails,status,createdBy,lastModifiedBy,createdTime,lastModifiedTime) VALUES (?,?,?,?,?,?,?,?,?,?,?) ON CONFLICT (id) DO UPDATE SET documentType=?, filestoreId=?, documentUid=?, additionalDetails=?, status=?, lastModifiedBy=?, lastModifiedTime=?; - basePath: $.Projects.*.documents.* - jsonMaps: - - - jsonPath: $.Projects.*.documents.*.id - - - jsonPath: $.Projects[*][?({id} in @.documents[*].id)].id - - - jsonPath: $.Projects.*.documents.*.documentType - - - jsonPath: $.Projects.*.documents.*.fileStore - - - jsonPath: $.Projects.*.documents.*.documentUid - - - jsonPath: $.Projects.*.additionalDetails - type: JSON - dbType: JSONB - - - jsonPath: $.Projects.*.documents.*.status - - - jsonPath: $.Projects.*.documents.*.auditDetails.createdBy - - - jsonPath: $.Projects.*.documents.*.auditDetails.lastModifiedBy - - - jsonPath: $.Projects.*.documents.*.auditDetails.createdTime - - - jsonPath: $.Projects.*.documents.*.auditDetails.lastModifiedTime - - - jsonPath: $.Projects.*.documents.*.documentType - - - jsonPath: $.Projects.*.documents.*.fileStore - - - jsonPath: $.Projects.*.documents.*.documentUid - - - jsonPath: $.Projects.*.additionalDetails - type: JSON - dbType: JSONB - - - jsonPath: $.Projects.*.documents.*.status - - - jsonPath: $.Projects.*.documents.*.auditDetails.lastModifiedBy - - - jsonPath: $.Projects.*.documents.*.auditDetails.lastModifiedTime - - - version: 1.0 - description: Saves a project resourcce - fromTopic: save-project-resource-topic - isTransaction: true - queryMaps: - - query: INSERT INTO project_resource (id, tenantId, projectId, productVariantId, isBaseUnitVariant, startDate, endDate, additionalDetails, createdBy, lastModifiedBy, createdTime, lastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?); - basePath: $.* - jsonMaps: - - jsonPath: $.*.id - - jsonPath: $.*.tenantId - - jsonPath: $.*.projectId - - jsonPath: $.*.productVariantId - - jsonPath: $.*.isBaseUnitVariant - - jsonPath: $.*.startDate - - jsonPath: $.*.endDate - - jsonPath: $.*.additionalFields - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.createdBy - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.createdTime - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - - version: 1.0 - description: Update a project resourcce - fromTopic: update-project-resource-topic - isTransaction: true - queryMaps: - - query: UPDATE project_resource SET tenantId=?, projectId=?, productVariantId=?, isBaseUnitVariant=?, startDate=?, endDate=?, additionalDetails=?, lastModifiedBy=?, lastModifiedTime=?, rowVersion=?, isDeleted=? WHERE id = ? - basePath: $.* - jsonMaps: - - jsonPath: $.*.tenantId - - jsonPath: $.*.projectId - - jsonPath: $.*.productVariantId - - jsonPath: $.*.isBaseUnitVariant - - jsonPath: $.*.startDate - - jsonPath: $.*.endDate - - jsonPath: $.*.additionalFields - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id - - - version: 1.0 - description: Delete a project resourcce - fromTopic: delete-project-resource-topic - isTransaction: true - queryMaps: - - query: UPDATE project_resource SET lastModifiedBy=?, lastModifiedTime=?, rowVersion=?, isDeleted=? WHERE id = ? - basePath: $.* - jsonMaps: - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id - - - version: 1.0 - description: Saves a project facility - fromTopic: save-project-facility-topic - isTransaction: true - queryMaps: - - - query: INSERT INTO project_facility (id, tenantId, projectId, facilityId, additionalDetails, createdBy, lastModifiedBy, createdTime, lastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?); - basePath: $.* - jsonMaps: - - jsonPath: $.*.id - - - jsonPath: $.*.tenantId - - - jsonPath: $.*.projectId - - - jsonPath: $.*.facilityId - - - jsonPath: $.*.additionalFields - type: JSON - dbType: JSONB - - - jsonPath: $.*.auditDetails.createdBy - - - jsonPath: $.*.auditDetails.lastModifiedBy - - - jsonPath: $.*.auditDetails.createdTime - - - jsonPath: $.*.auditDetails.lastModifiedTime - - - jsonPath: $.*.rowVersion - - - jsonPath: $.*.isDeleted - - - version: 1.0 - description: Update Project Facility - fromTopic: update-project-facility-topic - isTransaction: true - queryMaps: - - - query: UPDATE project_facility SET projectId=?, facilityId=?, additionalDetails=?, lastModifiedBy=?, lastModifiedTime=?, rowVersion=?, isDeleted=? WHERE id = ? - basePath: $.* - jsonMaps: - - jsonPath: $.*.projectId - - - jsonPath: $.*.facilityId - - - jsonPath: $.*.additionalFields - type: JSON - dbType: JSONB - - - jsonPath: $.*.auditDetails.lastModifiedBy - - - jsonPath: $.*.auditDetails.lastModifiedTime - - - jsonPath: $.*.rowVersion - - - jsonPath: $.*.isDeleted - - - jsonPath: $.*.id - - - version: 1.0 - description: Deletes Project Facility - fromTopic: delete-project-facility-topic - isTransaction: true - queryMaps: - - query: UPDATE project_facility SET lastModifiedBy=?, lastModifiedTime=?, rowVersion=?, isDeleted=? WHERE id=?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id \ No newline at end of file diff --git a/health-services/project/src/main/resources/project-task-persister.yml b/health-services/project/src/main/resources/project-task-persister.yml deleted file mode 100644 index 76b7b467397..00000000000 --- a/health-services/project/src/main/resources/project-task-persister.yml +++ /dev/null @@ -1,158 +0,0 @@ -serviceMaps: - serviceName: project - mappings: - - version: 1.0 - description: Saves a project task - fromTopic: save-project-task-topic - isTransaction: true - queryMaps: - - query: INSERT INTO PROJECT_TASK(id, clientReferenceId, tenantId, projectId, projectBeneficiaryId, projectBeneficiaryClientReferenceId, plannedStartDate, plannedEndDate, actualStartDate, actualEndDate, addressId, status, additionalDetails, createdBy, createdTime, lastModifiedBy, lastModifiedTime, rowVersion, isDeleted) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?); - basePath: $.* - jsonMaps: - - jsonPath: $.*.id - - jsonPath: $.*.clientReferenceId - - jsonPath: $.*.tenantId - - jsonPath: $.*.projectId - - jsonPath: $.*.projectBeneficiaryId - - jsonPath: $.*.projectBeneficiaryClientReferenceId - - jsonPath: $.*.plannedStartDate - - jsonPath: $.*.plannedEndDate - - jsonPath: $.*.actualStartDate - - jsonPath: $.*.actualEndDate - - jsonPath: $.*.address.id - - jsonPath: $.*.status - - jsonPath: $.*.additionalFields - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.createdBy - - jsonPath: $.*.auditDetails.createdTime - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - - query: INSERT INTO ADDRESS(id, tenantid, doorno, latitude, longitude, locationAccuracy, type, addressline1, addressline2, landmark, city, pincode, buildingName, street, localityCode) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); - basePath: $.*.address - jsonMaps: - - jsonPath: $.*.address.id - - jsonPath: $.*.address.tenantId - - jsonPath: $.*.address.doorNo - - jsonPath: $.*.address.latitude - - jsonPath: $.*.address.longitude - - jsonPath: $.*.address.locationAccuracy - - jsonPath: $.*.address.type - - jsonPath: $.*.address.addressLine1 - - jsonPath: $.*.address.addressLine2 - - jsonPath: $.*.address.landmark - - jsonPath: $.*.address.city - - jsonPath: $.*.address.pincode - - jsonPath: $.*.address.buildingName - - jsonPath: $.*.address.street - - jsonPath: $.*.address.locality.code - - - query: INSERT INTO TASK_RESOURCE(id, tenantid, productvariantid, taskid, quantity, isDelivered, reasonIfNotDelivered, createdBy, createdTime, lastModifiedBy, lastModifiedTime, isDeleted) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); - basePath: $.*.resources.* - jsonMaps: - - jsonPath: $.*.resources.*.id - - jsonPath: $.*.resources.*.tenantId - - jsonPath: $.*.resources.*.productVariantId - - jsonPath: $.*.resources.*.taskId - - jsonPath: $.*.resources.*.quantity - - jsonPath: $.*.resources.*.isDelivered - - jsonPath: $.*.resources.*.deliveryComment - - jsonPath: $.*.resources.*.auditDetails.createdBy - - jsonPath: $.*.resources.*.auditDetails.createdTime - - jsonPath: $.*.resources.*.auditDetails.lastModifiedBy - - jsonPath: $.*.resources.*.auditDetails.lastModifiedTime - - jsonPath: $.*.resources.*.isDeleted - - - version: 1.0 - description: Updates a project task - fromTopic: update-project-task-topic - isTransaction: true - queryMaps: - - query: UPDATE PROJECT_TASK SET tenantId = ?, projectId = ?, projectBeneficiaryId = ?, projectBeneficiaryClientReferenceId = ?, addressId = ?, plannedStartDate = ?, plannedEndDate = ?, actualStartDate = ?, actualEndDate = ?, status = ?, additionalDetails = ?, lastModifiedBy = ?, lastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.tenantId - - jsonPath: $.*.projectId - - jsonPath: $.*.projectBeneficiaryId - - jsonPath: $.*.projectBeneficiaryClientReferenceId - - jsonPath: $.*.address.id - - jsonPath: $.*.plannedStartDate - - jsonPath: $.*.plannedEndDate - - jsonPath: $.*.actualStartDate - - jsonPath: $.*.actualEndDate - - jsonPath: $.*.status - - jsonPath: $.*.additionalFields - type: JSON - dbType: JSONB - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id - - - query: UPDATE ADDRESS SET tenantId = ?, doorno = ?, latitude = ?, longitude = ?, locationAccuracy = ?, type = ?, addressline1 = ?, addressline2 = ?, landmark = ?, city = ?, pincode = ?, buildingName = ?, street = ?, localityCode = ? WHERE ID = ?; - basePath: $.*.address - jsonMaps: - - jsonPath: $.*.address.tenantId - - jsonPath: $.*.address.doorNo - - jsonPath: $.*.address.latitude - - jsonPath: $.*.address.longitude - - jsonPath: $.*.address.locationAccuracy - - jsonPath: $.*.address.type - - jsonPath: $.*.address.addressLine1 - - jsonPath: $.*.address.addressLine2 - - jsonPath: $.*.address.landmark - - jsonPath: $.*.address.city - - jsonPath: $.*.address.pincode - - jsonPath: $.*.address.buildingName - - jsonPath: $.*.address.street - - jsonPath: $.*.address.locality.code - - jsonPath: $.*.address.id - - - query: INSERT INTO TASK_RESOURCE(id, tenantid, productvariantid, taskid, quantity, isDelivered, reasonIfNotDelivered, createdBy, createdTime, lastModifiedBy, lastModifiedTime, isDeleted) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (id) DO UPDATE SET tenantid = ?, taskid = ?, productvariantid = ?, quantity = ?, isDelivered = ?, reasonIfNotDelivered = ?, lastModifiedBy = ?, lastModifiedTime = ?; - basePath: $.*.resources.* - jsonMaps: - - jsonPath: $.*.resources.*.id - - jsonPath: $.*.resources.*.tenantId - - jsonPath: $.*.resources.*.productVariantId - - jsonPath: $.*.resources.*.taskId - - jsonPath: $.*.resources.*.quantity - - jsonPath: $.*.resources.*.isDelivered - - jsonPath: $.*.resources.*.deliveryComment - - jsonPath: $.*.resources.*.auditDetails.createdBy - - jsonPath: $.*.resources.*.auditDetails.createdTime - - jsonPath: $.*.resources.*.auditDetails.lastModifiedBy - - jsonPath: $.*.resources.*.auditDetails.lastModifiedTime - - jsonPath: $.*.resources.*.isDeleted - - jsonPath: $.*.resources.*.tenantId - - jsonPath: $.*.resources.*.productVariantId - - jsonPath: $.*.resources.*.taskId - - jsonPath: $.*.resources.*.quantity - - jsonPath: $.*.resources.*.isDelivered - - jsonPath: $.*.resources.*.deliveryComment - - jsonPath: $.*.resources.*.auditDetails.lastModifiedBy - - jsonPath: $.*.resources.*.auditDetails.lastModifiedTime - - - version: 1.0 - description: Deletes a project task - fromTopic: delete-project-task-topic - isTransaction: true - queryMaps: - - query: UPDATE PROJECT_TASK SET lastModifiedBy = ?, lastModifiedTime = ?, rowVersion = ?, isDeleted = ? WHERE ID = ?; - basePath: $.* - jsonMaps: - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.rowVersion - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id - - query: UPDATE TASK_RESOURCE SET lastModifiedBy = ?, lastModifiedTime = ?, isDeleted = ? WHERE ID = ?; - basePath: $.*.resources.* - jsonMaps: - - jsonPath: $.*.auditDetails.lastModifiedBy - - jsonPath: $.*.auditDetails.lastModifiedTime - - jsonPath: $.*.isDeleted - - jsonPath: $.*.id diff --git a/health-services/referralmanagement/pom.xml b/health-services/referralmanagement/pom.xml index 7d9af91d36b..5ef135c8553 100644 --- a/health-services/referralmanagement/pom.xml +++ b/health-services/referralmanagement/pom.xml @@ -1,136 +1,139 @@ - - 4.0.0 + + 4.0.0 + org.egov + referralmanagement + jar + referralmanagement + 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-jdbc + + + org.egov.common + health-services-common + 1.0.12-SNAPSHOT + + + org.egov.common + health-services-models + 1.0.11-SNAPSHOT + compile + + + org.springframework.boot + spring-boot-starter-data-redis + + + io.lettuce + lettuce-core + + + + + redis.clients + jedis + + + org.flywaydb + flyway-core + + + + org.springframework.boot + spring-boot-devtools + + + org.postgresql + postgresql + 42.2.2.jre7 + + + org.springframework.boot + spring-boot-starter-test + test + - org.egov - referralmanagement - jar - referralmanagement - 1.0.0-beta - - 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-jdbc - - - org.egov.common - health-services-common - 1.0.8-SNAPSHOT - - - org.egov.common - health-services-models - 1.0.10-SNAPSHOT - compile - - - org.springframework.boot - spring-boot-starter-data-redis - - - io.lettuce - lettuce-core - - - - - redis.clients - jedis - - - org.flywaydb - flyway-core - - - org.postgresql - postgresql - 42.2.2.jre7 - - - org.springframework.boot - spring-boot-starter-test - test - + + io.swagger + swagger-core + 1.5.18 + + + + org.egov.services + digit-models + 1.0.0-SNAPSHOT + + + org.projectlombok + lombok + true + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + javax.validation + validation-api + + - - io.swagger - swagger-core - 1.5.18 - - - - org.egov.services - digit-models - 1.0.0-SNAPSHOT - - - org.projectlombok - lombok - true - - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 - - - - javax.validation - validation-api - - - - - - 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/ - - + + + 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/ + + \ No newline at end of file diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java index be30c29e5d4..e529c27a4f2 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java @@ -1,12 +1,13 @@ package org.egov.referralmanagement.config; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; @Getter @Setter @@ -68,4 +69,20 @@ public class ReferralManagementConfiguration { @Value("${egov.search.facility.url}") private String facilitySearchUrl; + + @Value("${egov.household.host}") + private String householdHost; + + @Value("${egov.search.household.url}") + private String householdSearchUrl; + + @Value("${egov.search.household.member.url}") + private String householdMemberSearchUrl; + + @Value("${egov.individual.host}") + private String individualHost; + + @Value("${egov.search.individual.url}") + private String individualSearchUrl; + } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java index 186e126cc93..32dd98e64b2 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java @@ -1,29 +1,29 @@ package org.egov.referralmanagement.repository; -import lombok.extern.slf4j.Slf4j; -import org.egov.referralmanagement.repository.rowmapper.ReferralRowMapper; +import static org.egov.common.utils.CommonUtils.getIdMethod; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + import org.egov.common.data.query.builder.GenericQueryBuilder; import org.egov.common.data.query.builder.QueryFieldChecker; import org.egov.common.data.query.builder.SelectQueryBuilder; -import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; import org.egov.common.models.referralmanagement.Referral; import org.egov.common.models.referralmanagement.ReferralSearch; import org.egov.common.producer.Producer; +import org.egov.referralmanagement.repository.rowmapper.ReferralRowMapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; import org.springframework.util.ReflectionUtils; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.getIdMethod; +import lombok.extern.slf4j.Slf4j; @Repository @Slf4j @@ -39,7 +39,8 @@ protected ReferralRepository(Producer producer, NamedParameterJdbcTemplate named } public List find(ReferralSearch searchObject, Integer limit, Integer offset, String tenantId, - Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { + Long lastChangedSince, Boolean includeDeleted) { + String query = "SELECT r.id, r.clientreferenceid, r.tenantid, r.projectbeneficiaryid, r.projectbeneficiaryclientreferenceid, r.referrerid, r.recipientid, r.recipienttype, r.reasons, r.sideeffectid, r.sideeffectclientreferenceid, r.createdby, r.createdtime, r.lastmodifiedby, r.lastmodifiedtime, r.clientcreatedby, r.clientcreatedtime, r.clientlastmodifiedby, r.clientlastmodifiedtime, r.rowversion, r.isdeleted, r.additionaldetails, se.id sId, se.clientreferenceid sClientReferenceId, se.tenantid sTenantId, se.taskid sTaskId, se.taskclientreferenceid sTaskClientReferenceId, se.projectbeneficiaryId sProjectBeneficiaryId, se.projectBeneficiaryClientReferenceId sProjectBeneficiaryClientReferenceId, se.symptoms sSymptoms, se.additionalDetails sAdditionalDetails, se.createdby sCreatedBy, se.createdtime sCreatedTime, se.lastmodifiedby sLastModifiedBy, se.lastmodifiedtime sLastModifiedTime, se.clientCreatedBy sClientCreatedBy, se.clientcreatedtime sClientCreatedTime, se.clientlastmodifiedby sClientLastModifiedBy, se.clientlastmodifiedtime sClientLastModifiedTime, se.rowversion sRowVersion, se.isdeleted sIsDeleted FROM referral r left join side_effect se on r.sideEffectClientReferenceid = se.clientreferenceid"; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, @@ -47,7 +48,9 @@ public List find(ReferralSearch searchObject, Integer limit, Integer o query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); query = query.replace("id IN (:id)", "r.id IN (:id)"); query = query.replace("clientReferenceId IN (:clientReferenceId)", "r.clientReferenceId IN (:clientReferenceId)"); - + query = query.replace("projectBeneficiaryClientReferenceId IN (:projectBeneficiaryClientReferenceId)", "r.projectBeneficiaryClientReferenceId IN (:projectBeneficiaryClientReferenceId)"); + query = query.replace("projectBeneficiaryId IN (:projectBeneficiaryId)", "r.projectBeneficiaryId IN (:projectBeneficiaryId)"); + query = query + " and r.tenantId=:tenantId "; if (Boolean.FALSE.equals(includeDeleted)) { query = query + "and r.isDeleted=:isDeleted "; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java index c3ce7ea000b..e72a3778817 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java @@ -1,14 +1,24 @@ package org.egov.referralmanagement.repository; -import lombok.extern.slf4j.Slf4j; +import static org.egov.common.utils.CommonUtils.getIdList; +import static org.egov.common.utils.CommonUtils.getIdMethod; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + import org.egov.common.data.query.builder.GenericQueryBuilder; import org.egov.common.data.query.builder.QueryFieldChecker; import org.egov.common.data.query.builder.SelectQueryBuilder; -import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.project.Task; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearch; -import org.egov.common.models.project.Task; import org.egov.common.producer.Producer; import org.egov.referralmanagement.repository.rowmapper.SideEffectRowMapper; import org.springframework.beans.factory.annotation.Autowired; @@ -17,12 +27,7 @@ import org.springframework.stereotype.Repository; import org.springframework.util.ReflectionUtils; -import java.lang.reflect.Method; -import java.util.*; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.getIdList; -import static org.egov.common.utils.CommonUtils.getIdMethod; +import lombok.extern.slf4j.Slf4j; @Repository @Slf4j @@ -63,7 +68,8 @@ public Map> fetchSideEffects(List taskList) { } public List find(SideEffectSearch searchObject, Integer limit, Integer offset, String tenantId, - Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { + Long lastChangedSince, Boolean includeDeleted) { + String query = "SELECT * FROM side_effect ae LEFT JOIN project_task pt ON ae.taskId = pt.id "; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java new file mode 100644 index 00000000000..4cb8d8be52b --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java @@ -0,0 +1,412 @@ +package org.egov.referralmanagement.service; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.household.Household; +import org.egov.common.models.household.HouseholdBulkResponse; +import org.egov.common.models.household.HouseholdMember; +import org.egov.common.models.household.HouseholdMemberBulkResponse; +import org.egov.common.models.household.HouseholdMemberSearch; +import org.egov.common.models.household.HouseholdMemberSearchRequest; +import org.egov.common.models.household.HouseholdSearch; +import org.egov.common.models.household.HouseholdSearchRequest; +import org.egov.common.models.individual.Individual; +import org.egov.common.models.individual.IndividualBulkResponse; +import org.egov.common.models.individual.IndividualSearch; +import org.egov.common.models.individual.IndividualSearchRequest; +import org.egov.common.models.project.BeneficiaryBulkResponse; +import org.egov.common.models.project.BeneficiarySearchRequest; +import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.models.project.ProjectBeneficiarySearch; +import org.egov.common.models.project.Task; +import org.egov.common.models.project.TaskBulkResponse; +import org.egov.common.models.project.TaskSearch; +import org.egov.common.models.project.TaskSearchRequest; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralSearch; +import org.egov.common.models.referralmanagement.ReferralSearchRequest; +import org.egov.common.models.referralmanagement.beneficiarydownsync.Downsync; +import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncCriteria; +import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncRequest; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearch; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearchRequest; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +@Service +public class DownsyncService { + + private ServiceRequestClient restClient; + + private ReferralManagementConfiguration configs; + + private NamedParameterJdbcTemplate jdbcTemplate; + + private SideEffectService sideEffectService; + + private ReferralManagementService referralService; + + @Autowired + public DownsyncService( ServiceRequestClient serviceRequestClient, + ReferralManagementConfiguration referralManagementConfiguration, + NamedParameterJdbcTemplate jdbcTemplate, + SideEffectService sideEffectService, + ReferralManagementService referralService) { + + this.restClient = serviceRequestClient; + this.configs = referralManagementConfiguration; + this.jdbcTemplate = jdbcTemplate; + this.sideEffectService=sideEffectService; + this.referralService=referralService; + + } + + /** + * + * @param downsyncRequest + * @return Downsync + */ + public Downsync prepareDownsyncData(DownsyncRequest downsyncRequest) { + + Downsync downsync = new Downsync(); + + List householdIds = null; + Set individualIds = null; + List individualClientRefIds = null; + List beneficiaryClientRefIds = null; + List taskClientRefIds = null; + + downsync.setDownsyncCriteria(downsyncRequest.getDownsyncCriteria()); + /* search household */ + householdIds = searchHouseholds(downsyncRequest, downsync); + + if (!CollectionUtils.isEmpty(householdIds)) + /* search household member using household ids */ + individualIds = searchMembers(downsyncRequest, downsync, householdIds); + + if (!CollectionUtils.isEmpty(individualIds)) { + + /* search individuals using individual ids */ + individualClientRefIds = searchIndividuals(downsyncRequest, downsync, individualIds); + } + + if (!CollectionUtils.isEmpty(individualClientRefIds)) { + /* search beneficiary using individual ids */ + beneficiaryClientRefIds = searchBeneficiaries(downsyncRequest, downsync, individualClientRefIds); + } + + if (!CollectionUtils.isEmpty(beneficiaryClientRefIds)) { + + /* search tasks using beneficiary uuids */ + taskClientRefIds = searchTasks(downsyncRequest, downsync, beneficiaryClientRefIds); + + /* ref search */ + referralSearch(downsyncRequest, downsync, beneficiaryClientRefIds); + } + + if (!CollectionUtils.isEmpty(taskClientRefIds)) { + + searchSideEffect(downsyncRequest, downsync, taskClientRefIds); + } + + return downsync; + } + + /** + * + * @param downsyncRequest + * @param downsync + * @return + */ + private List searchHouseholds(DownsyncRequest downsyncRequest, Downsync downsync) { + + DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + + StringBuilder householdUrl = new StringBuilder(configs.getHouseholdHost()) + .append(configs.getHouseholdSearchUrl()); + householdUrl = appendUrlParams(householdUrl, criteria); + + HouseholdSearch householdSearch = HouseholdSearch.builder() + .localityCode(criteria.getLocality()) + .build(); + + HouseholdSearchRequest searchRequest = HouseholdSearchRequest.builder() + .household(householdSearch) + .requestInfo(requestInfo) + .build(); + + HouseholdBulkResponse res = restClient.fetchResult(householdUrl, searchRequest, HouseholdBulkResponse.class); + List households = res.getHouseholds(); + downsync.setHouseholds(households); + downsync.getDownsyncCriteria().setTotalCount(res.getTotalCount()); + + if(CollectionUtils.isEmpty(households)) + return Collections.emptyList(); + + return households.stream().map(Household::getId).collect(Collectors.toList()); + } + + /** + * + * @param downsyncRequest + * @param downsync + * @param individualIds + * @return individual ClientReferenceIds + */ + private List searchIndividuals(DownsyncRequest downsyncRequest, Downsync downsync, + Set individualIds) { + + DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + + StringBuilder url = new StringBuilder(configs.getIndividualHost()) + .append(configs.getIndividualSearchUrl()); + url = appendUrlParams(url, criteria); + + IndividualSearch individualSearch = IndividualSearch.builder() + .id(new ArrayList<>(individualIds)) + .build(); + + IndividualSearchRequest searchRequest = IndividualSearchRequest.builder() + .individual(individualSearch) + .requestInfo(requestInfo) + .build(); + + List individuals = restClient.fetchResult(url, searchRequest, IndividualBulkResponse.class).getIndividual(); + downsync.setIndividuals(individuals); + + return individuals.stream().map(Individual::getClientReferenceId).collect(Collectors.toList()); + } + + /** + * + * @param downsyncRequest + * @param householdIds + * @return + */ + private Set searchMembers(DownsyncRequest downsyncRequest, Downsync downsync, + List householdIds) { + + StringBuilder memberUrl = new StringBuilder(configs.getHouseholdHost()) + .append(configs.getHouseholdMemberSearchUrl()); + + appendUrlParams(memberUrl, downsyncRequest.getDownsyncCriteria()); + + String memberIdsquery = "SELECT id from HOUSEHOLD_MEMBER where householdId IN (:householdIds)"; + + Map paramMap = new HashMap<>(); + paramMap.put("householdIds", householdIds); + + /* FIXME SHOULD BE REMOVED AND SEARCH SHOULD BE enhanced with list of household ids*/ + List memberids = jdbcTemplate.queryForList(memberIdsquery, paramMap, String.class); + + if (CollectionUtils.isEmpty(memberids)) + return Collections.emptySet(); + + + HouseholdMemberSearch memberSearch = HouseholdMemberSearch.builder() + .id(memberids) + .build(); + + HouseholdMemberSearchRequest searchRequest = HouseholdMemberSearchRequest.builder() + .householdMemberSearch(memberSearch) + .requestInfo(downsyncRequest.getRequestInfo()) + .build(); + + List members = restClient.fetchResult(memberUrl, searchRequest, HouseholdMemberBulkResponse.class).getHouseholdMembers(); + downsync.setHouseholdMembers(members); + + return members.stream().map(HouseholdMember::getIndividualId).collect(Collectors.toSet()); + } + + /** + * + * @param downsyncRequest + * @param downsync + * @param individualClientRefIds + * @return clientreferenceid of beneficiary object + */ + private List searchBeneficiaries(DownsyncRequest downsyncRequest, Downsync downsync, + List individualClientRefIds) { + + DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + + StringBuilder url = new StringBuilder(configs.getProjectHost()) + .append(configs.getProjectBeneficiarySearchUrl()); + url = appendUrlParams(url, criteria); + + String beneficiaryIdQuery = "SELECT id from PROJECT_BENEFICIARY where beneficiaryclientreferenceid IN (:beneficiaryIds)"; + + Map paramMap = new HashMap<>(); + paramMap.put("beneficiaryIds", individualClientRefIds); + + /* FIXME SHOULD BE REMOVED AND SEARCH SHOULD BE enhanced with list of beneficiary ids*/ + List ids = jdbcTemplate.queryForList(beneficiaryIdQuery, paramMap, String.class); + + if(CollectionUtils.isEmpty(ids)) + return Collections.emptyList(); + + ProjectBeneficiarySearch search = ProjectBeneficiarySearch.builder() + .id(ids) + .projectId(downsyncRequest.getDownsyncCriteria().getProjectId()) + .build(); + + BeneficiarySearchRequest searchRequest = BeneficiarySearchRequest.builder() + .projectBeneficiary(search) + .requestInfo(requestInfo) + .build(); + + List beneficiaries = restClient.fetchResult(url, searchRequest, BeneficiaryBulkResponse.class).getProjectBeneficiaries(); + downsync.setProjectBeneficiaries(beneficiaries); + + return beneficiaries.stream().map(ProjectBeneficiary::getClientReferenceId).collect(Collectors.toList()); + } + + /** + * + * @param downsyncRequest + * @param downsync + * @param beneficiaryClientRefIds + * @return + */ + private List searchTasks(DownsyncRequest downsyncRequest, Downsync downsync, + List beneficiaryClientRefIds) { + + DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + + StringBuilder url = new StringBuilder(configs.getProjectHost()) + .append(configs.getProjectTaskSearchUrl()); + url = appendUrlParams(url, criteria); + + String taskIdQuery = "SELECT id from PROJECT_TASK where projectBeneficiaryClientReferenceId IN (:beneficiaryClientRefIds)"; + + Map paramMap = new HashMap<>(); + paramMap.put("beneficiaryClientRefIds", beneficiaryClientRefIds); + + /* FIXME SHOULD BE REMOVED AND TASK SEARCH SHOULD BE enhanced with list of client-ref-beneficiary ids*/ + List taskIds = jdbcTemplate.queryForList(taskIdQuery, paramMap, String.class); + + if(CollectionUtils.isEmpty(taskIds)) + return Collections.emptyList(); + + TaskSearch search = TaskSearch.builder() + .id(taskIds) + .projectId(downsyncRequest.getDownsyncCriteria().getProjectId()) + .build(); + + TaskSearchRequest searchRequest = TaskSearchRequest.builder() + .task(search) + .requestInfo(requestInfo) + .build(); + + List tasks = restClient.fetchResult(url, searchRequest, TaskBulkResponse.class).getTasks(); + downsync.setTasks(tasks); + + return tasks.stream().map(Task::getClientReferenceId).collect(Collectors.toList()); + } + + /** + * + * @param downsyncRequest + * @param downsync + * @param taskClientRefIds + */ + private void searchSideEffect(DownsyncRequest downsyncRequest, Downsync downsync, + List taskClientRefIds) { + + DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + + // search side effect FIXME - tasks id array search not available + String taskIdQuery = "SELECT id from SIDE_EFFECT where taskClientReferenceId IN (:taskClientRefIds)"; + + Map paramMap = new HashMap<>(); + paramMap.put("taskClientRefIds", taskClientRefIds); + + /* FIXME SHOULD BE REMOVED AND TASK SEARCH SHOULD BE enhanced with list of client-ref-beneficiary ids*/ + List SEIds = jdbcTemplate.queryForList(taskIdQuery, paramMap, String.class); + + if(CollectionUtils.isEmpty(SEIds)) + return; + + SideEffectSearch search = SideEffectSearch.builder() + .id(SEIds) + .build(); + SideEffectSearchRequest effectSearchRequest = SideEffectSearchRequest.builder() + .sideEffect(search) + .requestInfo(requestInfo) + .build(); + + List effects = sideEffectService.search( + effectSearchRequest, + criteria.getLimit(), + criteria.getOffset(), + criteria.getTenantId(), + criteria.getLastSyncedTime(), + criteria.getIncludeDeleted()); + + downsync.setSideEffects(effects); + } + + private void referralSearch(DownsyncRequest downsyncRequest, Downsync downsync, + List beneficiaryClientRefIds) { + + DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + + ReferralSearch search = ReferralSearch.builder() + .projectBeneficiaryClientReferenceId(beneficiaryClientRefIds) + .build(); + + ReferralSearchRequest searchRequest = ReferralSearchRequest.builder() + .referral(search) + .requestInfo(requestInfo) + .build(); + + List referrals = referralService.search( + searchRequest, + criteria.getLimit(), + criteria.getOffset(), + criteria.getTenantId(), + criteria.getLastSyncedTime(), + criteria.getIncludeDeleted()); + + downsync.setReferrals(referrals); + } + + + + /** + * append url params + * + * @param url + * @param criteria + * @return + */ + private StringBuilder appendUrlParams(StringBuilder url, DownsyncCriteria criteria) { + + return url.append("?tenantId=") + .append(criteria.getTenantId()) + .append("&offset=") + .append(criteria.getOffset()) + .append("&limit=") + .append(criteria.getLimit()) + .append("&includeDeleted=") + .append(criteria.getIncludeDeleted()); + } + } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java index a7c5f09fa43..7c35b9747fe 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java @@ -1,6 +1,22 @@ package org.egov.referralmanagement.service; -import lombok.extern.slf4j.Slf4j; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.referralmanagement.Referral; @@ -26,25 +42,12 @@ import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.getIdFieldName; -import static org.egov.common.utils.CommonUtils.getIdMethod; -import static org.egov.common.utils.CommonUtils.handleErrors; -import static org.egov.common.utils.CommonUtils.havingTenantId; -import static org.egov.common.utils.CommonUtils.includeDeleted; -import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; -import static org.egov.common.utils.CommonUtils.lastChangedSince; -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import lombok.extern.slf4j.Slf4j; @Service @Slf4j public class ReferralManagementService { + private final IdGenService idGenService; private final ReferralRepository referralRepository; @@ -155,7 +158,7 @@ public List search(ReferralSearchRequest referralSearchRequest, Integer offset, String tenantId, Long lastChangedSince, - Boolean includeDeleted) throws Exception { + Boolean includeDeleted) { log.info("received request to search referrals"); String idFieldName = getIdFieldName(referralSearchRequest.getReferral()); if (isSearchByIdOnly(referralSearchRequest.getReferral(), idFieldName)) { diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java index fcb56d335b6..4850402507c 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java @@ -1,6 +1,21 @@ package org.egov.referralmanagement.service; -import lombok.extern.slf4j.Slf4j; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; @@ -24,21 +39,7 @@ import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.getIdFieldName; -import static org.egov.common.utils.CommonUtils.getIdMethod; -import static org.egov.common.utils.CommonUtils.handleErrors; -import static org.egov.common.utils.CommonUtils.havingTenantId; -import static org.egov.common.utils.CommonUtils.includeDeleted; -import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; -import static org.egov.common.utils.CommonUtils.lastChangedSince; -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import lombok.extern.slf4j.Slf4j; /** * @author kanishq-egov @@ -189,7 +190,7 @@ public List search(SideEffectSearchRequest sideEffectSearchRequest, Integer offset, String tenantId, Long lastChangedSince, - Boolean includeDeleted) throws Exception { + Boolean includeDeleted) { log.info("received request to search side effects"); String idFieldName = getIdFieldName(sideEffectSearchRequest.getSideEffect()); if (isSearchByIdOnly(sideEffectSearchRequest.getSideEffect(), idFieldName)) { diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectBeneficiaryIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectBeneficiaryIdValidator.java index 3bd6d90554e..b10789f596e 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectBeneficiaryIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectBeneficiaryIdValidator.java @@ -87,8 +87,6 @@ private List getExistingProjectBeneficiaries(String tenantId BeneficiaryBulkResponse.class ); existingProjectBeneficiaries = beneficiaryBulkResponse.getProjectBeneficiaries(); - } catch (QueryBuilderException e) { - existingProjectBeneficiaries = Collections.emptyList(); } catch (Exception e) { throw new CustomException("Project Beneficiaries failed to fetch", "Exception : "+e.getMessage()); } @@ -104,7 +102,7 @@ private void validateAndPopulateErrors(List existingProjectB }); List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> (Objects.nonNull(entity.getProjectBeneficiaryClientReferenceId()) && !existingProjectBeneficiaryClientReferenceIds.contains(entity.getProjectBeneficiaryClientReferenceId()) ) - || (Objects.nonNull(entity.getProjectBeneficiaryClientReferenceId()) && !existingProjectBeneficiaryIds.contains(entity.getProjectBeneficiaryId())) + || (Objects.nonNull(entity.getProjectBeneficiaryId()) && !existingProjectBeneficiaryIds.contains(entity.getProjectBeneficiaryId())) ).collect(Collectors.toList()); invalidEntities.forEach(referral -> { Error error = getErrorForNonExistentEntity(); diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java index d0d2ec37dbb..363b398bff9 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java @@ -1,7 +1,16 @@ package org.egov.referralmanagement.validator.sideeffect; -import lombok.extern.slf4j.Slf4j; -import org.egov.common.data.query.exception.QueryBuilderException; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; import org.egov.common.models.project.BeneficiaryBulkResponse; @@ -17,17 +26,7 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; +import lombok.extern.slf4j.Slf4j; /** * Validate whether project beneficiary exist in db or not using project beneficiary id and project beneficiary client beneficiary id for SideEffect object @@ -80,8 +79,6 @@ public Map> validate(SideEffectBulkRequest request) { BeneficiaryBulkResponse.class ); existingProjectBeneficiaries = beneficiaryBulkResponse.getProjectBeneficiaries(); - } catch (QueryBuilderException qbe) { - existingProjectBeneficiaries = Collections.emptyList(); } catch (Exception e) { throw new CustomException("Project Beneficiaries failed to fetch", "Exception : "+e.getMessage()); } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java index 1230987e3be..20265333bb1 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectTaskIdValidator.java @@ -1,14 +1,18 @@ package org.egov.referralmanagement.validator.sideeffect; -import lombok.extern.slf4j.Slf4j; -import org.egov.referralmanagement.config.ReferralManagementConfiguration; -import org.egov.common.data.query.exception.QueryBuilderException; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; -import org.egov.common.models.project.BeneficiaryBulkResponse; -import org.egov.common.models.project.BeneficiarySearchRequest; -import org.egov.common.models.project.ProjectBeneficiary; -import org.egov.common.models.project.ProjectBeneficiarySearch; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskBulkResponse; import org.egov.common.models.project.TaskSearch; @@ -16,22 +20,13 @@ import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; import org.egov.common.validator.Validator; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; +import lombok.extern.slf4j.Slf4j; /** * Validate whether project task exist in db or not using project task id and project task client beneficiary id for SideEffect object @@ -87,8 +82,6 @@ public Map> validate(SideEffectBulkRequest request) { TaskBulkResponse.class ); existingTasks = taskBulkResponse.getTasks(); - } catch (QueryBuilderException e) { - existingTasks = Collections.emptyList(); } catch (Exception e) { throw new CustomException("Project Task failed to fetch", "Exception : "+e.getMessage()); } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/BeneficiaryDownsyncController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/BeneficiaryDownsyncController.java new file mode 100644 index 00000000000..80860ab2096 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/BeneficiaryDownsyncController.java @@ -0,0 +1,48 @@ +package org.egov.referralmanagement.web.controllers; + +import javax.validation.Valid; + +import org.egov.common.models.referralmanagement.beneficiarydownsync.Downsync; +import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncRequest; +import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncResponse; +import org.egov.common.utils.ResponseInfoFactory; +import org.egov.referralmanagement.service.DownsyncService; +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.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; + +import io.swagger.annotations.ApiParam; + +@Controller +@RequestMapping("/beneficiary-downsync") +@Validated +public class BeneficiaryDownsyncController { + + private DownsyncService downsyncService; + + @Autowired + BeneficiaryDownsyncController (DownsyncService downsyncService){ + this.downsyncService = downsyncService; + } + + @PostMapping(value = "/v1/_get") + public ResponseEntity getBeneficaryData (@ApiParam(value = "Capture details of Side Effect", required = true) @Valid @RequestBody DownsyncRequest request) { + + Downsync.builder(). + downsyncCriteria(request.getDownsyncCriteria()) + .build(); + Downsync downsync = downsyncService.prepareDownsyncData(request); + DownsyncResponse response = DownsyncResponse.builder() + .downsync(downsync) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } +} diff --git a/health-services/referralmanagement/src/main/resources/application.properties b/health-services/referralmanagement/src/main/resources/application.properties index 1241002ce27..22830c099f1 100644 --- a/health-services/referralmanagement/src/main/resources/application.properties +++ b/health-services/referralmanagement/src/main/resources/application.properties @@ -1,5 +1,5 @@ server.servlet.context-path=/referralmanagement -server.port=8080 +server.port=8082 app.timezone=UTC # REDIS CONFIG @@ -24,7 +24,7 @@ spring.flyway.table=public spring.flyway.baseline-on-migrate=true spring.flyway.outOfOrder=true spring.flyway.locations=classpath:/db/migration/main -spring.flyway.enabled=true +spring.flyway.enabled=false # TRACER CONFIG # KAFKA SERVER CONFIG @@ -84,19 +84,20 @@ egov.facility.host=http://localhost:8083 egov.search.facility.url=/facility/v1/_search # HOUSEHOLD SERVICE -egov.household.host= +egov.household.host=http://localhost:8081 egov.search.household.url=/household/v1/_search +egov.search.household.member.url=/household/member/v1/_search # INDIVIDUAL SERVICE -egov.individual.host= -egov.search.individual.url= +egov.individual.host=http://localhost:8086 +egov.search.individual.url=/individual/v1/_search # use the value as "egov-user" to validate against egov-user service # use the value as "individual" to validate against individual service egov.user.id.validator=individual # PROJECT SERVICE -egov.project.host=https://unified-dev.digit.org +egov.project.host=http://localhost:8084 egov.search.project.task.url=/project/task/v1/_search egov.search.project.beneficiary.url=/project/beneficiary/v1/_search egov.search.project.staff.url=/project/staff/v1/_search @@ -132,6 +133,10 @@ egov.location.context.path=/egov-location/location/v11/ egov.location.endpoint=/boundarys/_search egov.location.code.query.param=codes +#user config +egov.create.user.url=/user/_create +egov.update.user.url=/user/_update + project.document.id.verification.required=false From 1ed1d89e41bcc664c476ce595952c29807c56fb6 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Thu, 9 Nov 2023 15:01:22 +0530 Subject: [PATCH 216/283] Dev (#564) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter * Project beneficiary tag cherrypick (#539) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * referral management project beneficiary validation fix * deleted persister and indexer file from project module resource folder --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * HH member clientrefid (#551) * adding clientRefId, Models version change, migration file * adding clientRefId for HouseholdMemberSearch as List * updated migration * adding Notnull for clientrefId --------- Co-authored-by: Vishal * Downsync smc referral module (#556) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Project beneficiary tag cherrypick (#549) * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * referral management project beneficiary validation fix --------- Co-authored-by: kanishq-egov Co-authored-by: Vishal * dummy api with same pagination response * dummy api with same pagination response * dummy api with same pagination response * downsync data test * data integrated till beneficiary * Update CHANGELOG.md * Delete health-services/project/src/main/resources/project-persistor.yml * skip on empty result added * skip on empty result added * beneficary searhc based on individual clientref id added * sideeffetc, ref, task fetch added * tasks earch fix * referral search fix --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * Dev downsync fix smc (#561) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: kanishq-egov * Dev master conflict fix (#562) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#563) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Dev master conflict fix (#565) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: bhanu prakash <109132521+bhanuprakash-egov@users.noreply.github.com> Co-authored-by: Naveen J <83631045+naveen-egov@users.noreply.github.com> From f6657297b407cb08167195492cc855c3d757a010 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Thu, 9 Nov 2023 15:04:14 +0530 Subject: [PATCH 217/283] Dev (#567) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter * Project beneficiary tag cherrypick (#539) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * referral management project beneficiary validation fix * deleted persister and indexer file from project module resource folder --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * HH member clientrefid (#551) * adding clientRefId, Models version change, migration file * adding clientRefId for HouseholdMemberSearch as List * updated migration * adding Notnull for clientrefId --------- Co-authored-by: Vishal * Downsync smc referral module (#556) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Project beneficiary tag cherrypick (#549) * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * referral management project beneficiary validation fix --------- Co-authored-by: kanishq-egov Co-authored-by: Vishal * dummy api with same pagination response * dummy api with same pagination response * dummy api with same pagination response * downsync data test * data integrated till beneficiary * Update CHANGELOG.md * Delete health-services/project/src/main/resources/project-persistor.yml * skip on empty result added * skip on empty result added * beneficary searhc based on individual clientref id added * sideeffetc, ref, task fetch added * tasks earch fix * referral search fix --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * Dev downsync fix smc (#561) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: kanishq-egov * Dev master conflict fix (#562) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#563) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Dev master conflict fix (#565) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#566) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: bhanu prakash <109132521+bhanuprakash-egov@users.noreply.github.com> Co-authored-by: Naveen J <83631045+naveen-egov@users.noreply.github.com> From 257645140ec0f3cc027c525bbc500aab74244e04 Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Tue, 14 Nov 2023 13:19:14 +0530 Subject: [PATCH 218/283] Dev to master for voucher tag, downsync (#572) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter * Project beneficiary tag cherrypick (#539) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * referral management project beneficiary validation fix * deleted persister and indexer file from project module resource folder --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * HH member clientrefid (#551) * adding clientRefId, Models version change, migration file * adding clientRefId for HouseholdMemberSearch as List * updated migration * adding Notnull for clientrefId --------- Co-authored-by: Vishal * Downsync smc referral module (#556) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Project beneficiary tag cherrypick (#549) * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * referral management project beneficiary validation fix --------- Co-authored-by: kanishq-egov Co-authored-by: Vishal * dummy api with same pagination response * dummy api with same pagination response * dummy api with same pagination response * downsync data test * data integrated till beneficiary * Update CHANGELOG.md * Delete health-services/project/src/main/resources/project-persistor.yml * skip on empty result added * skip on empty result added * beneficary searhc based on individual clientref id added * sideeffetc, ref, task fetch added * tasks earch fix * referral search fix --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * Dev downsync fix smc (#561) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: kanishq-egov * Dev master conflict fix (#562) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#563) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Dev master conflict fix (#565) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#566) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Added fix for testcases for householdmember (#570) Co-authored-by: kanishq-egov * updated the version, and added the changelog (#571) * updated the version, and added the changelog * updated ReferralManagement CHANGELOG * Update CHANGELOG.md --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: bhanu prakash <109132521+bhanuprakash-egov@users.noreply.github.com> Co-authored-by: Naveen J <83631045+naveen-egov@users.noreply.github.com> --- docs/health-api-specs/contracts/referral-management.yml | 3 +++ health-services/household/CHANGELOG.md | 5 +++++ health-services/household/pom.xml | 2 +- .../egov/household/helper/HouseholdMemberTestBuilder.java | 4 +++- health-services/individual/CHANGELOG.md | 3 +++ health-services/individual/pom.xml | 2 +- health-services/project/CHANGELOG.md | 3 +++ health-services/project/pom.xml | 2 +- health-services/referralmanagement/CHANGELOG.md | 6 +++++- 9 files changed, 25 insertions(+), 5 deletions(-) diff --git a/docs/health-api-specs/contracts/referral-management.yml b/docs/health-api-specs/contracts/referral-management.yml index 18e93fb3c83..e4e27851241 100644 --- a/docs/health-api-specs/contracts/referral-management.yml +++ b/docs/health-api-specs/contracts/referral-management.yml @@ -738,6 +738,9 @@ definitions: locality: type: string description: locality/boundary code from which all beneficiary has to be downloaded + totalCount: + type: [null,long] + description: totalCount tenantId: $ref: '#/parameters/tenantId' offset: diff --git a/health-services/household/CHANGELOG.md b/health-services/household/CHANGELOG.md index 9fb0bc133a6..11569f76ee5 100644 --- a/health-services/household/CHANGELOG.md +++ b/health-services/household/CHANGELOG.md @@ -1,5 +1,10 @@ All notable changes to this module will be documented in this file. +## 1.1.1 + +- Added total count for household +- Added a field for HouseholdMember : clientReferenceId + ## 1.1.1-beta - Added proximity based search support diff --git a/health-services/household/pom.xml b/health-services/household/pom.xml index 141a5bbd785..415101499df 100644 --- a/health-services/household/pom.xml +++ b/health-services/household/pom.xml @@ -5,7 +5,7 @@ household jar household - 1.1.1-beta + 1.1.1 1.8 ${java.version} diff --git a/health-services/household/src/test/java/org/egov/household/helper/HouseholdMemberTestBuilder.java b/health-services/household/src/test/java/org/egov/household/helper/HouseholdMemberTestBuilder.java index 8a4cfb9d1a8..6ccc6322324 100644 --- a/health-services/household/src/test/java/org/egov/household/helper/HouseholdMemberTestBuilder.java +++ b/health-services/household/src/test/java/org/egov/household/helper/HouseholdMemberTestBuilder.java @@ -22,7 +22,9 @@ public HouseholdMember build() { } public HouseholdMemberTestBuilder withHouseholdIdAndIndividualId(){ - this.builder.id("some-id").additionalFields(AdditionalFields.builder().build()) + this.builder.id("some-id") + .clientReferenceId("some-client-reference-id") + .additionalFields(AdditionalFields.builder().build()) .rowVersion(1) .isHeadOfHousehold(false) .individualId("some-individual-id") diff --git a/health-services/individual/CHANGELOG.md b/health-services/individual/CHANGELOG.md index 94e615fa82f..6e8364117b0 100644 --- a/health-services/individual/CHANGELOG.md +++ b/health-services/individual/CHANGELOG.md @@ -1,5 +1,8 @@ All notable changes to this module will be documented in this file. +## 1.1.2 +- upgraded version from beta + ## 1.1.2-beta - Added proximity based search support diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index 61e349b8cc2..b0cd415b742 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -5,7 +5,7 @@ individual jar individual - 1.1.2-beta + 1.1.2 1.8 ${java.version} diff --git a/health-services/project/CHANGELOG.md b/health-services/project/CHANGELOG.md index d856c30548e..4f8ef2bc6ca 100644 --- a/health-services/project/CHANGELOG.md +++ b/health-services/project/CHANGELOG.md @@ -1,5 +1,8 @@ All notable changes to this module will be documented in this file. +## 1.1.1 +- Added tag in project beneficiary + ## 1.1.1-beta 19-10-2023 - Added support for multi round, Added new validator for project task. diff --git a/health-services/project/pom.xml b/health-services/project/pom.xml index 7f13ee5a53f..ebb223d7d6f 100644 --- a/health-services/project/pom.xml +++ b/health-services/project/pom.xml @@ -5,7 +5,7 @@ project jar project - 1.1.1-beta + 1.1.1 1.8 ${java.version} diff --git a/health-services/referralmanagement/CHANGELOG.md b/health-services/referralmanagement/CHANGELOG.md index 6bc2d9b33c4..b2b3b4325f0 100644 --- a/health-services/referralmanagement/CHANGELOG.md +++ b/health-services/referralmanagement/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog All notable changes to this module will be documented in this file. +## 1.0.0 + - Added Downsync Feature + + ## 1.0.0-beta - Base version - - Added functionility for Side-Effects and Refferal management + - Added functionality for Side-Effects and Refferal management From b78923bee473f979da842f18420ca57c76b4ae6e Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Wed, 15 Nov 2023 15:49:49 +0530 Subject: [PATCH 219/283] Dev to master : beneficiary tag bug fix, downsync pagination fix (#576) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter * Project beneficiary tag cherrypick (#539) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * referral management project beneficiary validation fix * deleted persister and indexer file from project module resource folder --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * HH member clientrefid (#551) * adding clientRefId, Models version change, migration file * adding clientRefId for HouseholdMemberSearch as List * updated migration * adding Notnull for clientrefId --------- Co-authored-by: Vishal * Downsync smc referral module (#556) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Project beneficiary tag cherrypick (#549) * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * referral management project beneficiary validation fix --------- Co-authored-by: kanishq-egov Co-authored-by: Vishal * dummy api with same pagination response * dummy api with same pagination response * dummy api with same pagination response * downsync data test * data integrated till beneficiary * Update CHANGELOG.md * Delete health-services/project/src/main/resources/project-persistor.yml * skip on empty result added * skip on empty result added * beneficary searhc based on individual clientref id added * sideeffetc, ref, task fetch added * tasks earch fix * referral search fix --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * Dev downsync fix smc (#561) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: kanishq-egov * Dev master conflict fix (#562) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#563) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Dev master conflict fix (#565) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#566) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Added fix for testcases for householdmember (#570) Co-authored-by: kanishq-egov * updated the version, and added the changelog (#571) * updated the version, and added the changelog * updated ReferralManagement CHANGELOG * Update CHANGELOG.md --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * HLM-4062: removed pagination from fields excluding household api call * HLM-4062: missed in implementation (#574) * HLM-4062: missed in implementation * HLM-4062: default max is set to 1000 for not null limit value and 0 for offset value * project beneficiary tag update failed fix HLM-4444 * HLM-4444: added code review comments * sownsync bug fix for limit --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> * HLM-4444: project beneficiary update fix (#575) * Update CHANGELOG.md * updated changelog with dates (#577) * updated stock module changelog (#578) --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: bhanu prakash <109132521+bhanuprakash-egov@users.noreply.github.com> Co-authored-by: Naveen J <83631045+naveen-egov@users.noreply.github.com> Co-authored-by: talele08 --- health-services/household/CHANGELOG.md | 4 +- .../health-services-models/CHANGELOG.md | 2 +- .../models/household/HouseholdSearch.java | 3 - health-services/project/CHANGELOG.md | 2 +- .../PbVoucherTagUniqueForUpdateValidator.java | 40 +++++++--- .../referralmanagement/CHANGELOG.md | 3 +- .../service/DownsyncService.java | 75 +++++++++++-------- health-services/stock/CHANGELOG.md | 3 + 8 files changed, 82 insertions(+), 50 deletions(-) diff --git a/health-services/household/CHANGELOG.md b/health-services/household/CHANGELOG.md index 11569f76ee5..0cb9052cea7 100644 --- a/health-services/household/CHANGELOG.md +++ b/health-services/household/CHANGELOG.md @@ -1,9 +1,9 @@ All notable changes to this module will be documented in this file. -## 1.1.1 +## 1.1.1 - 2023-11-15 - Added total count for household -- Added a field for HouseholdMember : clientReferenceId +- Added a field for HouseholdMember-clientReferenceId ## 1.1.1-beta diff --git a/health-services/libraries/health-services-models/CHANGELOG.md b/health-services/libraries/health-services-models/CHANGELOG.md index ebef76b1fd0..3f5b9c6ff4e 100644 --- a/health-services/libraries/health-services-models/CHANGELOG.md +++ b/health-services/libraries/health-services-models/CHANGELOG.md @@ -1,6 +1,6 @@ All notable changes to this module will be documented in this file. -## 1.0.11 +## 1.0.11 - 2023-11-15 - Client reference id added for member of household - revert of household search change diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearch.java index 8adfbfeee88..6e31a74c882 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearch.java @@ -33,9 +33,6 @@ public class HouseholdSearch { @JsonProperty("clientReferenceId") private List clientReferenceId = null; -// @JsonProperty("memberCount") -// private Integer memberCount = null; - @JsonProperty("boundaryCode") private String localityCode = null; } diff --git a/health-services/project/CHANGELOG.md b/health-services/project/CHANGELOG.md index 4f8ef2bc6ca..df50f2ba974 100644 --- a/health-services/project/CHANGELOG.md +++ b/health-services/project/CHANGELOG.md @@ -1,6 +1,6 @@ All notable changes to this module will be documented in this file. -## 1.1.1 +## 1.1.1 - 2023-11-15 - Added tag in project beneficiary ## 1.1.1-beta 19-10-2023 diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForUpdateValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForUpdateValidator.java index be699f6b145..8450427492f 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForUpdateValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForUpdateValidator.java @@ -20,9 +20,9 @@ import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; /** + * @author kanishq-egov * This class, PbVoucherTagUniqueValidator, is a Spring component that serves as a validator for ensuring the uniqueness * of voucher tags within a list of project beneficiaries. It implements the Validator interface, which allows it to * validate a BeneficiaryBulkRequest containing a list of ProjectBeneficiary objects. Any duplicate voucher tags within @@ -110,11 +110,11 @@ private void validateAndPopulateErrors(List validProjectBene populateErrors(invalidEntities, errorDetailsMap); - List existingVoucherTags = existingProjectBeneficiaries.stream().map(ProjectBeneficiary::getTag).collect(Collectors.toList()); + Map existingProjectBeneficiaryVoucherTagMap = existingProjectBeneficiaries.stream().filter(projectBeneficiary -> projectBeneficiary.getTag() != null).collect(Collectors.toMap(ProjectBeneficiary::getTag, projectBeneficiary -> projectBeneficiary)); invalidEntities = validProjectBeneficiaries.stream() .filter(notHavingErrors()) - .filter(projectBeneficiary -> !existingProjectBeneficiaryMap.get(projectBeneficiary.getId()).getTag().equals(projectBeneficiary.getTag())) - .filter(projectBeneficiary -> isInvalid(projectBeneficiary, existingVoucherTags)) + .filter(projectBeneficiary -> isUpdated(projectBeneficiary, existingProjectBeneficiaryMap)) + .filter(projectBeneficiary -> isInvalid(projectBeneficiary, existingProjectBeneficiaryVoucherTagMap)) .collect(Collectors.toList()); populateErrors(invalidEntities, errorDetailsMap); @@ -129,7 +129,7 @@ private void validateAndPopulateErrors(List validProjectBene private void populateErrors(List invalidEntities, Map> errorDetailsMap) { // For each invalid entity, create an error and populate error details invalidEntities.forEach(projectBeneficiary -> { - Error error = getErrorForUniqueEntity(); + Error error = Error.builder().errorMessage("Project Beneficiary Tag Validation Failed").errorCode("INVALID_TAG").type(Error.ErrorType.NON_RECOVERABLE).exception(new CustomException("INVALID_TAG", "Project Beneficiary Tag Validation Failed")).build(); populateErrorDetails(projectBeneficiary, error, errorDetailsMap); }); } @@ -137,16 +137,38 @@ private void populateErrors(List invalidEntities, Map existingVoucherTags) { + private boolean isInvalid(ProjectBeneficiary entity, Map existingProjectBeneficiaryVoucherTagMap) { String id = entity.getId(); String tag = entity.getTag(); // Check if an entity with the same ID exists in the map and has a different tag - return existingVoucherTags.contains(tag); + return existingProjectBeneficiaryVoucherTagMap.keySet().contains(tag) && !existingProjectBeneficiaryVoucherTagMap.get(tag).getId().equals(id); } + /** + * Checks if a ProjectBeneficiary entity is considered as updated based on its tag. + * + * @param entity The ProjectBeneficiary entity to check. + * @param existingProjectBeneficiaryMap A map containing existing ProjectBeneficiary entities based on their IDs. + * @return true if the entity is updated, false otherwise. + */ + private boolean isUpdated(ProjectBeneficiary entity, Map existingProjectBeneficiaryMap) { + String id = entity.getId(); + String tag = entity.getTag(); + + // Retrieve the existing ProjectBeneficiary object to compare + ProjectBeneficiary projectBeneficiaryFromSearch = existingProjectBeneficiaryMap.get(id); + + // check if existing ProjectBeneficiary Tag is null or not and if it is null whether it is updated or not + if(projectBeneficiaryFromSearch.getTag() == null) return tag != null; + + // Check if the tag of the current entity is equal to the tag of the existing entity + return ( !projectBeneficiaryFromSearch.getTag().equals(tag) + || ( tag != null && !tag.equals(projectBeneficiaryFromSearch.getTag()) )); + } } diff --git a/health-services/referralmanagement/CHANGELOG.md b/health-services/referralmanagement/CHANGELOG.md index b2b3b4325f0..266f4ddf3f5 100644 --- a/health-services/referralmanagement/CHANGELOG.md +++ b/health-services/referralmanagement/CHANGELOG.md @@ -1,10 +1,9 @@ # Changelog All notable changes to this module will be documented in this file. -## 1.0.0 +## 1.0.0 - 2023-11-15 - Added Downsync Feature - ## 1.0.0-beta - Base version - Added functionality for Side-Effects and Refferal management diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java index 4cb8d8be52b..23c5e2328a9 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java @@ -137,7 +137,7 @@ private List searchHouseholds(DownsyncRequest downsyncRequest, Downsync StringBuilder householdUrl = new StringBuilder(configs.getHouseholdHost()) .append(configs.getHouseholdSearchUrl()); - householdUrl = appendUrlParams(householdUrl, criteria); + householdUrl = appendUrlParams(householdUrl, criteria, null, null); HouseholdSearch householdSearch = HouseholdSearch.builder() .localityCode(criteria.getLocality()) @@ -174,7 +174,7 @@ private List searchIndividuals(DownsyncRequest downsyncRequest, Downsync StringBuilder url = new StringBuilder(configs.getIndividualHost()) .append(configs.getIndividualSearchUrl()); - url = appendUrlParams(url, criteria); + url = appendUrlParams(url, criteria, 0, individualIds.size()); IndividualSearch individualSearch = IndividualSearch.builder() .id(new ArrayList<>(individualIds)) @@ -203,13 +203,12 @@ private Set searchMembers(DownsyncRequest downsyncRequest, Downsync down StringBuilder memberUrl = new StringBuilder(configs.getHouseholdHost()) .append(configs.getHouseholdMemberSearchUrl()); - appendUrlParams(memberUrl, downsyncRequest.getDownsyncCriteria()); - String memberIdsquery = "SELECT id from HOUSEHOLD_MEMBER where householdId IN (:householdIds)"; Map paramMap = new HashMap<>(); paramMap.put("householdIds", householdIds); - + appendUrlParams(memberUrl, downsyncRequest.getDownsyncCriteria(), 0, householdIds.size()); + /* FIXME SHOULD BE REMOVED AND SEARCH SHOULD BE enhanced with list of household ids*/ List memberids = jdbcTemplate.queryForList(memberIdsquery, paramMap, String.class); @@ -247,7 +246,7 @@ private List searchBeneficiaries(DownsyncRequest downsyncRequest, Downsy StringBuilder url = new StringBuilder(configs.getProjectHost()) .append(configs.getProjectBeneficiarySearchUrl()); - url = appendUrlParams(url, criteria); + url = appendUrlParams(url, criteria, 0, individualClientRefIds.size()); String beneficiaryIdQuery = "SELECT id from PROJECT_BENEFICIARY where beneficiaryclientreferenceid IN (:beneficiaryIds)"; @@ -291,7 +290,6 @@ private List searchTasks(DownsyncRequest downsyncRequest, Downsync downs StringBuilder url = new StringBuilder(configs.getProjectHost()) .append(configs.getProjectTaskSearchUrl()); - url = appendUrlParams(url, criteria); String taskIdQuery = "SELECT id from PROJECT_TASK where projectBeneficiaryClientReferenceId IN (:beneficiaryClientRefIds)"; @@ -300,7 +298,8 @@ private List searchTasks(DownsyncRequest downsyncRequest, Downsync downs /* FIXME SHOULD BE REMOVED AND TASK SEARCH SHOULD BE enhanced with list of client-ref-beneficiary ids*/ List taskIds = jdbcTemplate.queryForList(taskIdQuery, paramMap, String.class); - + url = appendUrlParams(url, criteria, 0, taskIds.size()); + if(CollectionUtils.isEmpty(taskIds)) return Collections.emptyList(); @@ -333,13 +332,13 @@ private void searchSideEffect(DownsyncRequest downsyncRequest, Downsync downsync RequestInfo requestInfo = downsyncRequest.getRequestInfo(); // search side effect FIXME - tasks id array search not available - String taskIdQuery = "SELECT id from SIDE_EFFECT where taskClientReferenceId IN (:taskClientRefIds)"; + String sEIdQuery = "SELECT id from SIDE_EFFECT where taskClientReferenceId IN (:taskClientRefIds)"; Map paramMap = new HashMap<>(); paramMap.put("taskClientRefIds", taskClientRefIds); /* FIXME SHOULD BE REMOVED AND TASK SEARCH SHOULD BE enhanced with list of client-ref-beneficiary ids*/ - List SEIds = jdbcTemplate.queryForList(taskIdQuery, paramMap, String.class); + List SEIds = jdbcTemplate.queryForList(sEIdQuery, paramMap, String.class); if(CollectionUtils.isEmpty(SEIds)) return; @@ -354,8 +353,8 @@ private void searchSideEffect(DownsyncRequest downsyncRequest, Downsync downsync List effects = sideEffectService.search( effectSearchRequest, - criteria.getLimit(), - criteria.getOffset(), + SEIds.size(), + 0, criteria.getTenantId(), criteria.getLastSyncedTime(), criteria.getIncludeDeleted()); @@ -380,8 +379,8 @@ private void referralSearch(DownsyncRequest downsyncRequest, Downsync downsync, List referrals = referralService.search( searchRequest, - criteria.getLimit(), - criteria.getOffset(), + beneficiaryClientRefIds.size(), + 0, criteria.getTenantId(), criteria.getLastSyncedTime(), criteria.getIncludeDeleted()); @@ -391,22 +390,34 @@ private void referralSearch(DownsyncRequest downsyncRequest, Downsync downsync, - /** - * append url params - * - * @param url - * @param criteria - * @return - */ - private StringBuilder appendUrlParams(StringBuilder url, DownsyncCriteria criteria) { - - return url.append("?tenantId=") - .append(criteria.getTenantId()) - .append("&offset=") - .append(criteria.getOffset()) - .append("&limit=") - .append(criteria.getLimit()) - .append("&includeDeleted=") - .append(criteria.getIncludeDeleted()); - } + /** + * append url params + * + * @param url + * @param criteria + * @param includeLimitOffset + * @return + */ + private StringBuilder appendUrlParams(StringBuilder url, DownsyncCriteria criteria, Integer offset, Integer limit) { + + url.append("?tenantId=") + .append(criteria.getTenantId()) + .append("&includeDeleted=") + .append(criteria.getIncludeDeleted()) + .append("&limit="); + + if (null != limit) + url.append(limit); + else + url.append(criteria.getLimit()); + + url.append("&offset="); + + if(null != offset) + url.append(offset); + else + url.append(criteria.getOffset()); + + return url; } +} diff --git a/health-services/stock/CHANGELOG.md b/health-services/stock/CHANGELOG.md index 8bb88bb178f..c837b842a64 100644 --- a/health-services/stock/CHANGELOG.md +++ b/health-services/stock/CHANGELOG.md @@ -1,5 +1,8 @@ All notable changes to this module will be documented in this file. +## 1.1.1 - 2023-11-15 + - Enhanced inventory flow for last mile delivery with QR code + ## 1.1.1-beta - Enhanced Inventory flow for last mile delivery From e08bcef699c3b79cf1546331b15ada2be6f62bec Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Tue, 21 Nov 2023 11:07:52 +0530 Subject: [PATCH 220/283] updated the stock version in pom.xml (#580) --- health-services/stock/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/stock/pom.xml b/health-services/stock/pom.xml index 36a6ee1f830..383f790553d 100644 --- a/health-services/stock/pom.xml +++ b/health-services/stock/pom.xml @@ -5,7 +5,7 @@ stock jar stock - 1.1.1-beta + 1.1.1 1.8 ${java.version} From c8b28ffc5f2c91c3df05efc328c91c59a08dcdbd Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Wed, 22 Nov 2023 10:56:04 +0530 Subject: [PATCH 221/283] added er diagram for household, referral, individual, stock registry (#584) --- .../er/household-registry-er.txt | 63 +++++++++++ .../er/individual-registry-er.txt | 105 ++++++++++++++++++ .../er/referral-registry-er.txt | 46 ++++++++ .../health-api-specs/er/stock-registry-er.txt | 52 +++++++++ 4 files changed, 266 insertions(+) create mode 100644 docs/health-api-specs/er/household-registry-er.txt create mode 100644 docs/health-api-specs/er/individual-registry-er.txt create mode 100644 docs/health-api-specs/er/referral-registry-er.txt create mode 100644 docs/health-api-specs/er/stock-registry-er.txt diff --git a/docs/health-api-specs/er/household-registry-er.txt b/docs/health-api-specs/er/household-registry-er.txt new file mode 100644 index 00000000000..77560bd84fe --- /dev/null +++ b/docs/health-api-specs/er/household-registry-er.txt @@ -0,0 +1,63 @@ +Table address { + id varchar [pk] + tenantId varchar + clientReferenceId varchar(64) + doorNo varchar(64) + latitude double + longitude double + locationAccuracy int + type varchar(64) + addressLine1 varchar(256) + addressLine2 varchar(256) + landmark varchar(256) + city varchar(256) + pincode varchar(64) + buildingName varchar(256) + street varchar(256) + // additionalDetails json + localityCode varchar(64) //Reference to master data + wardcode varchar(256) + // createdBy varchar(64) + // createdTime bigint + // lastModifiedBy varchar(64) + // lastModifiedTime bigint + // rowVersion bigint + // isDeleted bool +} + +Table household { + id varchar [pk] + tenantId varchar + clientReferenceId varchar(64) + numberOfMembers int + addressId varchar [ref: > address.id] + additionalDetails json + createdBy varchar(64) + createdTime bigint + lastModifiedBy varchar(64) + lastModifiedTime bigint + rowVersion bigint + isDeleted bool +} + +Table household_member { + id varchar [pk] + tenantId varchar + clientreferenceid varchar(64) + individualId varchar(64) //[ref: > individual.id] + individualClientReferenceId varchar(64) //[ref: > individual.id] + householdId varchar(64) [ref: > household.id] + householdClientReferenceId varchar(64) [ref: > household.clientreferenceid] + isHeadOfHousehold bool + additionalDetails json + createdBy varchar(64) + createdTime bigint + lastModifiedBy varchar(64) + lastModifiedTime bigint + rowVersion bigint + isDeleted bool + clientCreatedBy varchar(64) + clientCreatedTime bigint + clientLastModifiedBy varchar(64) + clientLastModifiedTime bigint +} \ No newline at end of file diff --git a/docs/health-api-specs/er/individual-registry-er.txt b/docs/health-api-specs/er/individual-registry-er.txt new file mode 100644 index 00000000000..3d38143f0ab --- /dev/null +++ b/docs/health-api-specs/er/individual-registry-er.txt @@ -0,0 +1,105 @@ +TABLE individual { + id varchar [pk] + userId varchar(64) + clientReferenceId varchar(64) + tenantId varchar + givenName varchar(200) + familyName varchar(200) + otherNames varchar(200) + dateOfBirth bigint + gender varchar(10) + bloodGroup varchar(10) + mobileNumber varchar(20) + altContactNumber varchar(20) + email varchar(200) + fatherName varchar(100) + husbandName varchar(100) + photo varchar + additionalDetails json + createdBy varchar(64) + createdTime bigint + lastModifiedBy varchar(64) + lastModifiedTime bigint + rowVersion bigint + isDeleted bool + individualid varchar(64) + relationship varchar(100) + issystemuser bool + username varchar(64) + password varchar(200) + type varchar(64) + roles json + useruuid varchar(64) + issystemuseractive bool + clientcreatedtime bigint + clientlastmodifiedtime bigint + clientcreatedby varchar(64) + clientlastmodifiedby varchar(64) + +} +Table individual_identifier { + id varchar [pk] + individualId varchar [ref: > individual.id] + identifierType varchar(64) + identifierId varchar(64) + clientReferenceId varchar(64) + createdBy varchar(64) + createdTime bigint + lastModifiedBy varchar(64) + lastModifiedTime bigint + rowVersion bigint + isDeleted bool +} +Table address { + id varchar [pk] + tenantId varchar + clientReferenceId varchar(64) + doorNo varchar(64) + latitude double + longitude double + locationAccuracy int + type varchar(64) + addressLine1 varchar(256) + addressLine2 varchar(256) + landmark varchar(256) + city varchar(256) + pincode varchar(64) + buildingName varchar(256) + street varchar(256) + // additionalDetails json + localityCode varchar(64) //Reference to master data + wardcode varchar(256) + // createdBy varchar(64) + // createdTime bigint + // lastModifiedBy varchar(64) + // lastModifiedTime bigint + // rowVersion bigint + // isDeleted bool +} + +Table individual_address { + individualId varchar [ref: > individual.id] + addressId varchar [ref: > address.id] + type varchar(64) + createdBy varchar(64) + createdTime bigint + lastModifiedBy varchar(64) + lastModifiedTime bigint + // rowVersion bigint + isDeleted bool +} + +Table individual_skill { + id varchar [pk] + clientReferenceId varchar(64) [unique] + individualId varchar [ref: > individual.id] + type varchar(64) + level varchar(64) + experience varchar(64) + createdBy varchar(64) + createdTime bigint + lastModifiedBy varchar(64) + lastModifiedTime bigint + rowVersion bigint + isDeleted bool +} diff --git a/docs/health-api-specs/er/referral-registry-er.txt b/docs/health-api-specs/er/referral-registry-er.txt new file mode 100644 index 00000000000..874cd99ed4d --- /dev/null +++ b/docs/health-api-specs/er/referral-registry-er.txt @@ -0,0 +1,46 @@ +TABLE referral { + id varchar(64) [primary key] + clientreferenceid varchar(64) + tenantid varchar(1000) + projectbeneficiaryid varchar(64) + projectbeneficiaryclientreferenceid varchar(64) + referrerid varchar(100) + recipientid varchar(100) + recipienttype varchar(100) + reasons jsonb + sideeffectid varchar(100) [ref: > side_effect.id] + sideeffectclientreferenceid varchar(100) [ref: > side_effect.clientreferenceid] + createdby varchar(64) + createdtime bigint + lastmodifiedby varchar(64) + lastmodifiedtime bigint + clientcreatedby varchar(64) + clientcreatedtime bigint + clientlastmodifiedby varchar(64) + clientlastmodifiedtime bigint + rowversion bigint + isdeleted boolean + additionaldetails jsonb +} + +TABLE side_effect { + id varchar(64) [primary key] + clientreferenceid varchar(64) + tenantid varchar(1000) + taskid varchar(64) + taskclientreferenceid varchar(64) + projectbeneficiaryid varchar(64) + projectbeneficiaryclientreferenceid varchar(64) + symptoms jsonb + createdby varchar(64) + createdtime bigint + lastmodifiedby varchar(64) + lastmodifiedtime bigint + clientcreatedby varchar(64) + clientcreatedtime bigint + clientlastmodifiedby varchar(64) + clientlastmodifiedtime bigint + rowversion bigint + isdeleted boolean + additionaldetails jsonb +} diff --git a/docs/health-api-specs/er/stock-registry-er.txt b/docs/health-api-specs/er/stock-registry-er.txt new file mode 100644 index 00000000000..cae4d67e785 --- /dev/null +++ b/docs/health-api-specs/er/stock-registry-er.txt @@ -0,0 +1,52 @@ +Table stock { + id varchar [pk] + clientReferenceId varchar(64) [unique] + tenantId varchar(1000) + facilityId varchar(64) //[ref: > facility.id] + productVariantId varchar(64) //[ref: > product_variant.id] + quantity bigint + referenceId varchar(200) + referenceIdType varchar(100) + transactionType varchar(100) + transactionReason varchar(100) + transactingPartyId varchar(64) + transactingPartyType varchar(100) + additionalDetails json + createdBy varchar(64) + createdTime bigint + lastModifiedBy varchar(64) + lastModifiedTime bigint + rowVersion bigint + isDeleted bool + waybillNUmber varchar(200) + dateofentry bigint + clientcreatedtime bigint + clientlastmodifiedtime bigint + clientcreatedby varchar(64) + clientlastmodifiedby varchar(64) + sendertype varchar(128) + receivertype varchar(128) + senderid varchar(128) + receiverid varchar(128) + +} + +Table stock_reconciliation_log { + id varchar [pk] + clientReferenceId varchar [unique] //store id provided by frontend + tenantId varchar(1000) + productVariantId varchar(64) //[ref: > product_variant.id] + facilityId varchar(64) //[ref: > facility.id] + referenceId varchar(64) + referenceIdType varchar(64) + dateOfReconciliation bigint + calculatedCount int + physicalRecordedCount int + commentsOnReconciliation varchar + createdAt bigint + modifiedAt bigint + createdBy varchar + modifiedBy varchar + additionalFields json + isDeleted bool +} \ No newline at end of file From 8b47c4169be1dd15a2b391f23594d565b5e89e75 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Mon, 27 Nov 2023 00:04:45 +0530 Subject: [PATCH 222/283] removed migration service (#585) --- .../egov/pgr/consumer/MigrationConsumer.java | 41 -- .../egov/pgr/service/MigrationService.java | 457 ------------------ .../web/controllers/MigrationController.java | 36 -- 3 files changed, 534 deletions(-) delete mode 100644 core-services/pgr-services/src/main/java/org/egov/pgr/consumer/MigrationConsumer.java delete mode 100644 core-services/pgr-services/src/main/java/org/egov/pgr/service/MigrationService.java delete mode 100644 core-services/pgr-services/src/main/java/org/egov/pgr/web/controllers/MigrationController.java diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/consumer/MigrationConsumer.java b/core-services/pgr-services/src/main/java/org/egov/pgr/consumer/MigrationConsumer.java deleted file mode 100644 index 1e12fb16aa2..00000000000 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/consumer/MigrationConsumer.java +++ /dev/null @@ -1,41 +0,0 @@ -package org.egov.pgr.consumer; - -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.extern.slf4j.Slf4j; -import org.egov.pgr.service.MigrationService; -import org.egov.pgr.web.models.pgrV1.ServiceResponse; -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 MigrationConsumer { - - - @Autowired - private MigrationService migrationService; - - @Autowired - private ObjectMapper mapper; - - - @KafkaListener(topics = { "${pgr.kafka.migration.topic}"}) - public void listen(final HashMap record, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { - - try { - log.info("Received migration request " + record); - ServiceResponse serviceResponse = mapper.convertValue(record,ServiceResponse.class); - migrationService.migrate(serviceResponse); - } - catch (Exception e){ - log.error("Error occured while processing the record from topic : " + topic, e); - } - - } - -} diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/service/MigrationService.java b/core-services/pgr-services/src/main/java/org/egov/pgr/service/MigrationService.java deleted file mode 100644 index f6d62819d8d..00000000000 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/service/MigrationService.java +++ /dev/null @@ -1,457 +0,0 @@ -package org.egov.pgr.service; - - -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; -import org.egov.common.contract.request.User; -import org.egov.pgr.config.PGRConfiguration; -import org.egov.pgr.producer.Producer; -import org.egov.pgr.util.MigrationUtils; -import org.egov.pgr.web.models.AuditDetails; -import org.egov.pgr.web.models.Boundary; -import org.egov.pgr.web.models.Document; -import org.egov.pgr.web.models.GeoLocation; -import org.egov.pgr.web.models.ServiceRequest; -import org.egov.pgr.web.models.pgrV1.ActionHistory; -import org.egov.pgr.web.models.pgrV1.ActionInfo; -import org.egov.pgr.web.models.pgrV1.Address; -import org.egov.pgr.web.models.pgrV1.Service; -import org.egov.pgr.web.models.pgrV1.ServiceResponse; -import org.egov.pgr.web.models.workflow.ProcessInstance; -import org.egov.pgr.web.models.workflow.ProcessInstanceRequest; -import org.egov.pgr.web.models.workflow.State; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; -import org.springframework.util.ObjectUtils; - -import javax.annotation.PostConstruct; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; - -import static org.egov.pgr.util.PGRConstants.IMAGE_DOCUMENT_TYPE; -import static org.egov.pgr.util.PGRConstants.PGR_BUSINESSSERVICE; -import static org.egov.pgr.util.PGRConstants.PGR_MODULENAME; - -@Component -@Slf4j -public class MigrationService { - - - @Autowired - private MigrationUtils migrationUtils; - - @Autowired - private Producer producer; - - @Autowired - private PGRConfiguration config; - - private Map statusToUUIDMap; - - private Map serviceCodeToSLA; - - private final Map oldToNewStatus = new HashMap() { - { - - put("open", "PENDINGFORASSIGNMENT"); - put("assigned", "PENDINGATLME"); - put("closed", "CLOSEDAFTERRESOLUTION"); - put("rejected", "REJECTED"); - put("resolved", "RESOLVED"); - put("reassignrequested", "PENDINGFORREASSIGNMENT"); - - } - }; - - private final Map oldToNewAction = new HashMap() { - { - - put("open", "APPLY"); - put("ropen", "REOPEN"); - put("assign", "ASSIGN"); - put("reassign", "REASSIGN"); - put("resolve", "RESOLVE"); - put("close", "PENDINGFORREASSIGNMENT"); - put("reject", "REJECT"); - put("requestforreassign", "ASSIGN"); - - } - }; - - @PostConstruct - private void setStatusToUUIDMap(){ - this.statusToUUIDMap = migrationUtils.getStatusToUUIDMap(config.getTenantId()); - this.serviceCodeToSLA = migrationUtils.getServiceCodeToSLAMap(config.getTenantId()); - } - - - - - /** - * - * Comment actions has to be added in workflow - * Active field has to be added - * Media contains the complete url path instead of fileStoreId - * - * - * Data Assumptions: - * All records have actionHistory - * Is AuditDetails of old address different from service auditDetails - * Every citizen and employee has uuid - * - * - * - */ - - /* - * - * 1. Skipping records with empty actionHistory as no linking with service is possible in that case - * Images are added in workflow doument with documentType as PHOTO which is defined in constants file - * Citizen object is not migrated as it is stored in user service only it's reference i.e accountId is migrated - * Splitting Role in 'by' in actionInfo and storing only uuid not role in workflow (Why was it stored in that way?) - * Removed @Pattern in citizen from name, mobileNumber, address from SearchReponse in old pgr so that batch don't fail for any data - * id field set by generating new uuid as old one didn't have this field - * Assumed ActionHistory comes in descending order from old pgr search API - * - * - * 2. tenantid, servicecode, servicerequestid, createdby and createdtime were all NOT NULL constraints - * in PGR v1 eg_pgr_service table, hence no additional checks have been considered in the migrate flow. - * However, there is no such constraint of NOT NULL in case of description attribute, hence, a check has - * been placed here which will set the description as "NOT_SPECIFIED" in case description in v1 table is - * null. - * - * - * */ - public Map migrate(ServiceResponse serviceResponse) { - - - List servicesV1 = serviceResponse.getServices(); - List actionHistories = serviceResponse.getActionHistory(); - - Set ids = new HashSet<>(); - - servicesV1.forEach(service -> { - ids.add(service.getAuditDetails().getCreatedBy()); - ids.add(service.getAuditDetails().getLastModifiedBy()); - ids.add(service.getAccountId()); - }); - - actionHistories.forEach(actionHistory -> { - actionHistory.getActions().forEach(actionInfo -> { - - if (actionInfo.getAssignee() != null) - ids.add(actionInfo.getAssignee()); - - ids.add(actionInfo.getBy().split(":")[0]); - }); - }); - - Map idToUuidMap = migrationUtils.getIdtoUUIDMap(new LinkedList<>(ids)); - - /*############### FOR LOCAL TESTING ONLY ########################################### - Map idToUuidMap = new HashMap<>(); - for(String id : ids){ - if(id != null) - idToUuidMap.put(Long.parseLong(id), UUID.randomUUID().toString()); - } - //##################################################################################*/ - - Map response = transform(servicesV1, actionHistories, idToUuidMap); - - return response; - - } - - - /** - * @param servicesV1 - * @param actionHistories - * @return - */ - private Map transform(List servicesV1, List actionHistories, Map idToUuidMap) { - - - Map> idToActionMap = new HashMap<>(); - - for (ActionHistory actionHistory : actionHistories) { - List actions = actionHistory.getActions(); - - if (CollectionUtils.isEmpty(actions)) - log.error("Skiping record with empty actionHistory"); - - String id = actions.get(0).getBusinessKey(); - idToActionMap.put(id, actions); - } - - // Temporary for testing - List services = new LinkedList<>(); - List workflowResponse = new LinkedList<>(); - - for (Service serviceV1 : servicesV1) { - - List actionInfos = idToActionMap.get(serviceV1.getServiceRequestId()); - - Map actionUuidToSlaMap = getActionUUidToSLAMap(actionInfos, serviceV1.getServiceCode()); - - List workflows = new LinkedList<>(); - - org.egov.pgr.web.models.Service service = transformService(serviceV1, idToUuidMap); - - actionInfos.forEach(actionInfo -> { - ProcessInstance workflow = transformAction(actionInfo, idToUuidMap, actionUuidToSlaMap); - workflows.add(workflow); - }); - - - service.setApplicationStatus(oldToNewStatus.get(serviceV1.getStatus().toString())); - ProcessInstanceRequest processInstanceRequest = ProcessInstanceRequest.builder().processInstances(workflows).build(); - ServiceRequest serviceRequest = ServiceRequest.builder().service(service).build(); - //log.info("Pushing service request: " + serviceRequest); - /*#################### TEMPORARY FOR TESTING, REMOVE THE COMMENTS*/ - producer.push(config.getBatchCreateTopic(),serviceRequest); - producer.push(config.getBatchWorkflowSaveTopic(),processInstanceRequest); - - // Temporary for testing - services.add(service); - workflowResponse.addAll(workflows); - } - - Map response = new HashMap<>(); - - response.put("Service:", services); - response.put("Workflows:", workflowResponse); - - return response; - - - } - - - private org.egov.pgr.web.models.Service transformService(Service serviceV1, Map idToUuidMap) { - - String tenantId = serviceV1.getTenantId(); - String serviceCode = serviceV1.getServiceCode(); - String serviceRequestId = serviceV1.getServiceRequestId(); - String description = serviceV1.getDescription(); - String source = (!ObjectUtils.isEmpty(serviceV1.getSource())) ? serviceV1.getSource().toString() : null; - String rating = serviceV1.getRating(); - - String feedback = serviceV1.getFeedback(); - String addressInService = serviceV1.getAddress(); - String landmark = serviceV1.getLandmark(); - - Map additionalDetailMap = new HashMap<>(); - - if(!StringUtils.isEmpty(feedback)) - additionalDetailMap.put("feedback", feedback); - - if(!StringUtils.isEmpty(addressInService)) - additionalDetailMap.put("address", addressInService); - - if(!StringUtils.isEmpty(landmark)) - additionalDetailMap.put("landmark", landmark); - - /** - * AccountId is id, not uuid in old pgr. Mapping has to fetched - * of id to uuid i.e. accountId in new PGR is the UUID. - */ - - String accountId = null; - if(serviceV1.getAccountId() != null) - accountId = idToUuidMap.get(Long.parseLong(serviceV1.getAccountId())); - - AuditDetails auditDetails = serviceV1.getAuditDetails(); - - // Setting uuid in place of id in auditDetails - auditDetails.setCreatedBy(idToUuidMap.get(Long.parseLong(auditDetails.getCreatedBy()))); - auditDetails.setLastModifiedBy(auditDetails.getLastModifiedBy() != null ? idToUuidMap.get(Long.parseLong(auditDetails.getLastModifiedBy())):"NOT_SPECIFIED"); - - Object attributes = serviceV1.getAttributes(); - - - Double latitude = serviceV1.getLat(); - Double longitutude = serviceV1.getLongitutde(); - - /** - * Transform address and set geo location - */ - GeoLocation geoLocation = GeoLocation.builder().longitude(longitutude).latitude(latitude).build(); - //log.info("Address details: " + serviceV1.getAddressDetail()); - org.egov.pgr.web.models.Address address = null; - address = transformAddress(serviceV1.getAddressDetail()); - address.setGeoLocation(geoLocation); - address.setTenantId(tenantId); - - Boolean active = serviceV1.getActive(); - - // ACTIVE FLAG NEEDS TO BE ACCOUNTED FOR BELOW FOR POPULATING v2 POJO ---> - - org.egov.pgr.web.models.Service service = org.egov.pgr.web.models.Service.builder() - .id(UUID.randomUUID().toString()) - .tenantId(tenantId) - .accountId(accountId) - .additionalDetail(attributes) - .serviceCode(serviceCode) - .serviceRequestId(serviceRequestId) - .description(description) - .source(source) - .address(address) - .active(active) - .auditDetails(auditDetails) - .build(); - - if(!CollectionUtils.isEmpty(additionalDetailMap)) - service.setAdditionalDetail(additionalDetailMap); - - if (org.apache.commons.lang3.StringUtils.isNumeric(rating)) { - service.setRating(Integer.parseInt(rating)); - } - - - - - return service; - - } - - /** - * No auditDetails in address - * Geolocation will be enriched in service transform as that data is available there - * - * @param addressV1 - * @return - */ - private org.egov.pgr.web.models.Address transformAddress(Address addressV1) { - - String id = addressV1.getUuid(); - String locality = addressV1.getMohalla() != null ? addressV1.getMohalla() : "NOT_AVAILABLE"; - String colony = addressV1.getLocality(); - String city = addressV1.getCity(); - String landmark = addressV1.getLandmark(); - String houseNoAndStreetName = addressV1.getHouseNoAndStreetName(); - - /** - * FIXME : houseNoAndStreetName and colony mapping has to be corrected - */ - - org.egov.pgr.web.models.Address address = org.egov.pgr.web.models.Address.builder() - .id(id) - .locality(Boundary.builder().code(locality).build()) - .city(city) - .landmark(landmark) - .street(houseNoAndStreetName) - .region(colony) - .build(); - - return address; - - } - - - private ProcessInstance transformAction(ActionInfo actionInfo, Map idToUuidMap, Map actionUuidToSlaMap) { - - String uuid = actionInfo.getUuid(); - - // FIXME Should the role be stored - String createdBy = actionInfo.getBy().split(":")[0]; - - String tenantId = actionInfo.getTenantId(); - Long createdTime = actionInfo.getWhen(); - String businessId = actionInfo.getBusinessKey(); - String action = (!StringUtils.isEmpty(actionInfo.getAction())) ? oldToNewAction.get(actionInfo.getAction()) : "COMMENT"; - String status = actionInfo.getStatus(); - String assignee = actionInfo.getAssignee(); - String comments = actionInfo.getComment(); - List fileStoreIds = actionInfo.getMedia(); - String stateUUID = statusToUUIDMap.get(oldToNewStatus.get(status)); - - - State state = State.builder().uuid(stateUUID).state(oldToNewStatus.get(status)).build(); - - // LastmodifiedTime and by is same as that for created as every time new entry is created whenever any action is taken - AuditDetails auditDetails = AuditDetails.builder().createdBy(createdBy) - .createdTime(createdTime).lastModifiedBy(createdBy).lastModifiedTime(createdTime).build(); - - // Setting uuid in place of id in auditDetails - auditDetails.setCreatedBy(idToUuidMap.get(Long.parseLong(auditDetails.getCreatedBy()))); - auditDetails.setLastModifiedBy(idToUuidMap.get(Long.parseLong(auditDetails.getLastModifiedBy()))); - - ProcessInstance workflow = ProcessInstance.builder() - .id(uuid) - .tenantId(tenantId) - .action(action) - .comment(comments) - .businessId(businessId) - .moduleName(PGR_MODULENAME) - .state(state) - .businessService(PGR_BUSINESSSERVICE) - .businesssServiceSla(actionUuidToSlaMap.get(actionInfo.getUuid())) - .auditDetails(auditDetails) - .build(); - - - // Wrapping assignee uuid in User object to add it in workflow - if (!StringUtils.isEmpty(assignee)) { - User user = new User(); - user.setUuid(idToUuidMap.get(Long.parseLong(assignee))); - workflow.setAssignes(Collections.singletonList(user)); - } - - User assigner = new User(); - assigner.setUuid(idToUuidMap.get(Long.parseLong(createdBy))); - workflow.setAssigner(assigner); - - - // Setting the images uploaded in workflow document - if (!CollectionUtils.isEmpty(fileStoreIds)) { - List documents = new LinkedList<>(); - for (String fileStoreId : fileStoreIds) { - - if(!StringUtils.isEmpty(fileStoreId) && !fileStoreId.equalsIgnoreCase("null") - && fileStoreId.length()<=64){ - Document document = Document.builder() - .documentType(IMAGE_DOCUMENT_TYPE) - .fileStoreId(fileStoreId) - .id(UUID.randomUUID().toString()) - .build(); - documents.add(document); - } - } - workflow.setDocuments(documents); - } - - return workflow; - } - - private Map getActionUUidToSLAMap(List actionInfos, String serviceCode){ - - Map uuidTOSLAMap = new HashMap<>(); - - if(CollectionUtils.isEmpty(actionInfos)) - return uuidTOSLAMap; - - actionInfos.sort(Comparator.comparing(ActionInfo::getWhen)); - int totalCount = actionInfos.size(); - - uuidTOSLAMap.put(actionInfos.get(0).getUuid(), (serviceCodeToSLA.get(serviceCode)!=null)?serviceCodeToSLA.get(serviceCode):432000000l); - - for(int i = 1; i < totalCount; i++){ - - ActionInfo actionInfo = actionInfos.get(i); - ActionInfo previousActionInfo = actionInfos.get(i-1); - Long timeSpent = actionInfo.getWhen() - previousActionInfo.getWhen(); - Long slaLeft = uuidTOSLAMap.get(previousActionInfo.getUuid()) - timeSpent; - uuidTOSLAMap.put(actionInfo.getUuid(), slaLeft); - } - return uuidTOSLAMap; - } - -} diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/web/controllers/MigrationController.java b/core-services/pgr-services/src/main/java/org/egov/pgr/web/controllers/MigrationController.java deleted file mode 100644 index 17906846825..00000000000 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/web/controllers/MigrationController.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.egov.pgr.web.controllers; - -import lombok.extern.slf4j.Slf4j; -import org.egov.pgr.service.MigrationService; -import org.egov.pgr.web.models.pgrV1.ServiceResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RestController; - -import javax.validation.Valid; -import java.io.IOException; -import java.util.Map; - -@RestController -@RequestMapping("/migration") -@Slf4j -public class MigrationController { - - - @Autowired - private MigrationService migrationService; - - - @RequestMapping(value="/_transform", method = RequestMethod.POST) - public ResponseEntity requestsCreatePost(@Valid @RequestBody ServiceResponse request) throws IOException { - - Map response = migrationService.migrate(request); - - return new ResponseEntity<>(response, HttpStatus.OK); - - } -} From 5f091cc0d166ea82db2566aba15cbf78ff869b95 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Tue, 12 Dec 2023 15:52:49 +0530 Subject: [PATCH 223/283] Added health-project, health-individual, health-pgr-services --- build/build-config.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/build/build-config.yml b/build/build-config.yml index 981c3dd7dff..74e5fb33d77 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -36,6 +36,13 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "health-services/project/src/main/resources/db" image-name: "project-db" + - name: "builds/health-campaign-services/health-services/health-project" + build: + - work-dir: "health-services/project" + image-name: "health-project" + dockerfile: "build/maven/Dockerfile" + - work-dir: "health-services/project/src/main/resources/db" + image-name: "health-project-db" - name: "builds/health-campaign-services/health-services/referralmanagement" build: - work-dir: "health-services/referralmanagement" @@ -57,6 +64,13 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "health-services/individual/src/main/resources/db" image-name: "individual-db" + - name: "builds/health-campaign-services/health-services/health-individual" + build: + - work-dir: "health-services/individual" + image-name: "health-individual" + dockerfile: "build/maven/Dockerfile" + - work-dir: "health-services/individual/src/main/resources/db" + image-name: "health-individual-db" - name: "builds/health-campaign-services/health-services/household" build: - work-dir: "health-services/household" @@ -118,6 +132,13 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "core-services/pgr-services/src/main/resources/db" image-name: "pgr-services-db" + - name: "builds/health-campaign-services/core-services/health-pgr-services" + build: + - work-dir: "core-services/pgr-services" + image-name: "health-pgr-services" + dockerfile: "build/maven/Dockerfile" + - work-dir: "core-services/pgr-services/src/main/resources/db" + image-name: "health-pgr-services-db" - name: "builds/health-campaign-services/core-services/user-otp" build: - work-dir: "core-services/user-otp" From 5ed17e97e19f7329cb2dc1e85cd05d8cb2785520 Mon Sep 17 00:00:00 2001 From: Vishal Date: Tue, 12 Dec 2023 16:49:51 +0530 Subject: [PATCH 224/283] adding attendance build config --- build/build-config.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/build-config.yml b/build/build-config.yml index 74e5fb33d77..685e18a3669 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -147,3 +147,10 @@ config: build: - work-dir: "core-services/egov-notification-mail" image-name: "egov-notification-mail" + - name: "builds/health-campaign-services/core-services/attendance" + build: + - work-dir: "core-services/attendance" + image-name: "attendance" + dockerfile: "build/maven/Dockerfile" + - work-dir: "core-services/attendance/src/main/resources/db" + image-name: "attendance-db" From ab931d875c9eb951603ff9cee12aaa42b4288571 Mon Sep 17 00:00:00 2001 From: Vishal Date: Tue, 12 Dec 2023 16:46:45 +0530 Subject: [PATCH 225/283] adding attendance module --- ...ce Postman Scripts.postman_collection.json | 3633 ++++++++++++++++ .../attendance/Attendance-Service-1.0.0.yaml | 666 +++ core-services/attendance/CHANGELOG.md | 6 + core-services/attendance/LOCALSETUP.md | 42 + core-services/attendance/README.md | 29 + core-services/attendance/pom.xml | 135 + .../postman-test-suite-Attendace-service.json | 3796 +++++++++++++++++ .../src/main/java/org/egov/Main.java | 15 + .../AttendanceServiceConfiguration.java | 107 + .../org/egov/config/MainConfiguration.java | 39 + .../enrichment/AttendanceLogEnrichment.java | 76 + .../enrichment/AttendeeEnrichmentService.java | 65 + .../egov/enrichment/RegisterEnrichment.java | 157 + .../enrichment/StaffEnrichmentService.java | 60 + .../main/java/org/egov/kafka/Consumer.java | 60 + .../main/java/org/egov/kafka/Producer.java | 16 + .../repository/AttendanceLogRepository.java | 36 + .../egov/repository/AttendeeRepository.java | 31 + .../org/egov/repository/IdGenRepository.java | 59 + .../egov/repository/RegisterRepository.java | 37 + .../repository/ServiceRequestRepository.java | 39 + .../org/egov/repository/StaffRepository.java | 40 + .../AttendanceLogQueryBuilder.java | 152 + .../querybuilder/AttendeeQueryBuilder.java | 104 + .../querybuilder/RegisterQueryBuilder.java | 197 + .../querybuilder/StaffQueryBuilder.java | 87 + .../rowmapper/AttendanceLogRowMapper.java | 120 + .../rowmapper/AttendeeRowMapper.java | 84 + .../rowmapper/RegisterRowMapper.java | 92 + .../repository/rowmapper/StaffRowMapper.java | 84 + .../egov/service/AttendanceLogService.java | 105 + .../service/AttendanceRegisterService.java | 377 ++ .../org/egov/service/AttendeeService.java | 195 + ...ationContactDetailsStaffUpdateService.java | 98 + .../java/org/egov/service/StaffService.java | 179 + .../egov/util/AttendanceServiceConstants.java | 6 + .../org/egov/util/AttendanceServiceUtil.java | 16 + .../org/egov/util/IndividualServiceUtil.java | 113 + .../main/java/org/egov/util/MDMSUtils.java | 72 + .../org/egov/util/ResponseInfoFactory.java | 25 + .../AttendanceLogServiceValidator.java | 503 +++ .../validator/AttendanceServiceValidator.java | 285 ++ .../validator/AttendeeServiceValidator.java | 383 ++ .../egov/validator/StaffServiceValidator.java | 271 ++ .../controllers/AttendanceApiController.java | 75 + .../AttendanceLogApiController.java | 55 + .../controllers/AttendeeApiController.java | 57 + .../web/controllers/StaffApiController.java | 57 + .../org/egov/web/models/AttendanceLog.java | 70 + .../egov/web/models/AttendanceLogRequest.java | 45 + .../web/models/AttendanceLogResponse.java | 45 + .../models/AttendanceLogSearchCriteria.java | 62 + .../egov/web/models/AttendanceRegister.java | 88 + .../web/models/AttendanceRegisterRequest.java | 34 + .../models/AttendanceRegisterResponse.java | 45 + .../AttendanceRegisterSearchCriteria.java | 79 + .../web/models/AttendeeCreateRequest.java | 44 + .../web/models/AttendeeCreateResponse.java | 45 + .../web/models/AttendeeDeleteRequest.java | 44 + .../web/models/AttendeeDeleteResponse.java | 45 + .../web/models/AttendeeSearchCriteria.java | 40 + .../java/org/egov/web/models/Document.java | 34 + .../org/egov/web/models/IndividualEntry.java | 52 + .../models/Organisation/ContactDetails.java | 83 + .../Organisation/OrgContactUpdateDiff.java | 29 + .../egov/web/models/RequestInfoWrapper.java | 29 + .../org/egov/web/models/StaffPermission.java | 52 + .../web/models/StaffPermissionRequest.java | 34 + .../web/models/StaffPermissionResponse.java | 34 + .../egov/web/models/StaffSearchCriteria.java | 33 + .../main/java/org/egov/web/models/Status.java | 37 + ...an Scripts.postman_scripts_collection.json | 3671 ++++++++++++++++ .../src/main/resources/application.properties | 91 + .../attendance-service-db-schema.png | Bin 0 -> 190121 bytes ...ttendance-service-test-coverage-report.png | Bin 0 -> 962886 bytes .../src/main/resources/db/Dockerfile | 9 + .../src/main/resources/db/migrate.sh | 3 + ...0221122105730__create_attendance_table.sql | 91 + ...20221124154130__alter_attendance_table.sql | 36 + ...0172200__create_attendance_staff_table.sql | 17 + ...75400__alter_attendance_attendee_table.sql | 4 + ...11400__alter_attendance_attendee_table.sql | 4 + .../test/java/org/egov/TestConfiguration.java | 16 + .../AttendanceLogEnrichmentTest.java | 43 + .../AttendeeEnrichmentServiceTest.java | 39 + .../enrichment/RegisterEnrichmentTest.java | 95 + .../StaffEnrichmentServiceTest.java | 36 + .../org/egov/helper/AdditionalFields.java | 43 + .../AttendanceLogRequestTestBuilder.java | 98 + .../egov/helper/AttendanceLogTestBuilder.java | 123 + .../helper/AttendanceRegisterBuilderTest.java | 107 + .../AttendanceRegisterRequestBuilderTest.java | 181 + .../helper/AttendeeRequestBuilderTest.java | 97 + .../egov/helper/AuditDetailsTestBuilder.java | 27 + .../org/egov/helper/DocumentTestBuilder.java | 45 + .../src/test/java/org/egov/helper/Field.java | 28 + .../helper/IndividualEntryBuilderTest.java | 34 + .../egov/helper/RequestInfoTestBuilder.java | 62 + .../helper/StaffPermissionBuilderTest.java | 33 + .../egov/helper/StaffRequestBuilderTest.java | 97 + .../java/org/egov/helper/UserTestBuilder.java | 58 + .../service/AttendanceLogServiceTest.java | 66 + .../AttendanceLogServiceValidatorTest.java | 458 ++ .../AttendanceServiceValidatorTest.java | 181 + .../AttendeeServiceValidatorTest.java | 177 + .../validator/StaffServiceValidatorTest.java | 172 + .../AttendanceApiControllerTest.java | 126 + .../AttendanceLogApiControllerTest.java | 94 + .../AttendeeApiControllerTest.java | 126 + .../controllers/StaffApiControllerTest.java | 108 + .../test/resources/AttendeeCreateRequest.json | 0 .../test/resources/InvalidTenantMDMSData.json | 8 + .../src/test/resources/TenantMDMSData.json | 402 ++ 113 files changed, 21145 insertions(+) create mode 100644 core-services/attendance/Attendace Service Postman Scripts.postman_collection.json create mode 100644 core-services/attendance/Attendance-Service-1.0.0.yaml create mode 100644 core-services/attendance/CHANGELOG.md create mode 100644 core-services/attendance/LOCALSETUP.md create mode 100644 core-services/attendance/README.md create mode 100644 core-services/attendance/pom.xml create mode 100644 core-services/attendance/postman-test-suite-Attendace-service.json create mode 100644 core-services/attendance/src/main/java/org/egov/Main.java create mode 100644 core-services/attendance/src/main/java/org/egov/config/AttendanceServiceConfiguration.java create mode 100644 core-services/attendance/src/main/java/org/egov/config/MainConfiguration.java create mode 100644 core-services/attendance/src/main/java/org/egov/enrichment/AttendanceLogEnrichment.java create mode 100644 core-services/attendance/src/main/java/org/egov/enrichment/AttendeeEnrichmentService.java create mode 100644 core-services/attendance/src/main/java/org/egov/enrichment/RegisterEnrichment.java create mode 100644 core-services/attendance/src/main/java/org/egov/enrichment/StaffEnrichmentService.java create mode 100644 core-services/attendance/src/main/java/org/egov/kafka/Consumer.java create mode 100644 core-services/attendance/src/main/java/org/egov/kafka/Producer.java create mode 100644 core-services/attendance/src/main/java/org/egov/repository/AttendanceLogRepository.java create mode 100644 core-services/attendance/src/main/java/org/egov/repository/AttendeeRepository.java create mode 100644 core-services/attendance/src/main/java/org/egov/repository/IdGenRepository.java create mode 100644 core-services/attendance/src/main/java/org/egov/repository/RegisterRepository.java create mode 100644 core-services/attendance/src/main/java/org/egov/repository/ServiceRequestRepository.java create mode 100644 core-services/attendance/src/main/java/org/egov/repository/StaffRepository.java create mode 100644 core-services/attendance/src/main/java/org/egov/repository/querybuilder/AttendanceLogQueryBuilder.java create mode 100644 core-services/attendance/src/main/java/org/egov/repository/querybuilder/AttendeeQueryBuilder.java create mode 100644 core-services/attendance/src/main/java/org/egov/repository/querybuilder/RegisterQueryBuilder.java create mode 100644 core-services/attendance/src/main/java/org/egov/repository/querybuilder/StaffQueryBuilder.java create mode 100644 core-services/attendance/src/main/java/org/egov/repository/rowmapper/AttendanceLogRowMapper.java create mode 100644 core-services/attendance/src/main/java/org/egov/repository/rowmapper/AttendeeRowMapper.java create mode 100644 core-services/attendance/src/main/java/org/egov/repository/rowmapper/RegisterRowMapper.java create mode 100644 core-services/attendance/src/main/java/org/egov/repository/rowmapper/StaffRowMapper.java create mode 100644 core-services/attendance/src/main/java/org/egov/service/AttendanceLogService.java create mode 100644 core-services/attendance/src/main/java/org/egov/service/AttendanceRegisterService.java create mode 100644 core-services/attendance/src/main/java/org/egov/service/AttendeeService.java create mode 100644 core-services/attendance/src/main/java/org/egov/service/OrganisationContactDetailsStaffUpdateService.java create mode 100644 core-services/attendance/src/main/java/org/egov/service/StaffService.java create mode 100644 core-services/attendance/src/main/java/org/egov/util/AttendanceServiceConstants.java create mode 100644 core-services/attendance/src/main/java/org/egov/util/AttendanceServiceUtil.java create mode 100644 core-services/attendance/src/main/java/org/egov/util/IndividualServiceUtil.java create mode 100644 core-services/attendance/src/main/java/org/egov/util/MDMSUtils.java create mode 100644 core-services/attendance/src/main/java/org/egov/util/ResponseInfoFactory.java create mode 100644 core-services/attendance/src/main/java/org/egov/validator/AttendanceLogServiceValidator.java create mode 100644 core-services/attendance/src/main/java/org/egov/validator/AttendanceServiceValidator.java create mode 100644 core-services/attendance/src/main/java/org/egov/validator/AttendeeServiceValidator.java create mode 100644 core-services/attendance/src/main/java/org/egov/validator/StaffServiceValidator.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/controllers/AttendanceApiController.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/controllers/AttendanceLogApiController.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/controllers/AttendeeApiController.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/controllers/StaffApiController.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/AttendanceLog.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/AttendanceLogRequest.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/AttendanceLogResponse.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/AttendanceLogSearchCriteria.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/AttendanceRegister.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/AttendanceRegisterRequest.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/AttendanceRegisterResponse.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/AttendanceRegisterSearchCriteria.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/AttendeeCreateRequest.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/AttendeeCreateResponse.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/AttendeeDeleteRequest.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/AttendeeDeleteResponse.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/AttendeeSearchCriteria.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/Document.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/IndividualEntry.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/Organisation/ContactDetails.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/Organisation/OrgContactUpdateDiff.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/RequestInfoWrapper.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/StaffPermission.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/StaffPermissionRequest.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/StaffPermissionResponse.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/StaffSearchCriteria.java create mode 100644 core-services/attendance/src/main/java/org/egov/web/models/Status.java create mode 100644 core-services/attendance/src/main/resources/Attendace Service Postman Scripts.postman_scripts_collection.json create mode 100644 core-services/attendance/src/main/resources/application.properties create mode 100644 core-services/attendance/src/main/resources/attendance-service-db-schema.png create mode 100644 core-services/attendance/src/main/resources/attendance-service-test-coverage-report.png create mode 100644 core-services/attendance/src/main/resources/db/Dockerfile create mode 100644 core-services/attendance/src/main/resources/db/migrate.sh create mode 100644 core-services/attendance/src/main/resources/db/migration/main/V20221122105730__create_attendance_table.sql create mode 100644 core-services/attendance/src/main/resources/db/migration/main/V20221124154130__alter_attendance_table.sql create mode 100644 core-services/attendance/src/main/resources/db/migration/main/V20221130172200__create_attendance_staff_table.sql create mode 100644 core-services/attendance/src/main/resources/db/migration/main/V20221208175400__alter_attendance_attendee_table.sql create mode 100644 core-services/attendance/src/main/resources/db/migration/main/V20230404011400__alter_attendance_attendee_table.sql create mode 100644 core-services/attendance/src/test/java/org/egov/TestConfiguration.java create mode 100644 core-services/attendance/src/test/java/org/egov/enrichment/AttendanceLogEnrichmentTest.java create mode 100644 core-services/attendance/src/test/java/org/egov/enrichment/AttendeeEnrichmentServiceTest.java create mode 100644 core-services/attendance/src/test/java/org/egov/enrichment/RegisterEnrichmentTest.java create mode 100644 core-services/attendance/src/test/java/org/egov/enrichment/StaffEnrichmentServiceTest.java create mode 100644 core-services/attendance/src/test/java/org/egov/helper/AdditionalFields.java create mode 100644 core-services/attendance/src/test/java/org/egov/helper/AttendanceLogRequestTestBuilder.java create mode 100644 core-services/attendance/src/test/java/org/egov/helper/AttendanceLogTestBuilder.java create mode 100644 core-services/attendance/src/test/java/org/egov/helper/AttendanceRegisterBuilderTest.java create mode 100644 core-services/attendance/src/test/java/org/egov/helper/AttendanceRegisterRequestBuilderTest.java create mode 100644 core-services/attendance/src/test/java/org/egov/helper/AttendeeRequestBuilderTest.java create mode 100644 core-services/attendance/src/test/java/org/egov/helper/AuditDetailsTestBuilder.java create mode 100644 core-services/attendance/src/test/java/org/egov/helper/DocumentTestBuilder.java create mode 100644 core-services/attendance/src/test/java/org/egov/helper/Field.java create mode 100644 core-services/attendance/src/test/java/org/egov/helper/IndividualEntryBuilderTest.java create mode 100644 core-services/attendance/src/test/java/org/egov/helper/RequestInfoTestBuilder.java create mode 100644 core-services/attendance/src/test/java/org/egov/helper/StaffPermissionBuilderTest.java create mode 100644 core-services/attendance/src/test/java/org/egov/helper/StaffRequestBuilderTest.java create mode 100644 core-services/attendance/src/test/java/org/egov/helper/UserTestBuilder.java create mode 100644 core-services/attendance/src/test/java/org/egov/service/AttendanceLogServiceTest.java create mode 100644 core-services/attendance/src/test/java/org/egov/validator/AttendanceLogServiceValidatorTest.java create mode 100644 core-services/attendance/src/test/java/org/egov/validator/AttendanceServiceValidatorTest.java create mode 100644 core-services/attendance/src/test/java/org/egov/validator/AttendeeServiceValidatorTest.java create mode 100644 core-services/attendance/src/test/java/org/egov/validator/StaffServiceValidatorTest.java create mode 100644 core-services/attendance/src/test/java/org/egov/web/controllers/AttendanceApiControllerTest.java create mode 100644 core-services/attendance/src/test/java/org/egov/web/controllers/AttendanceLogApiControllerTest.java create mode 100644 core-services/attendance/src/test/java/org/egov/web/controllers/AttendeeApiControllerTest.java create mode 100644 core-services/attendance/src/test/java/org/egov/web/controllers/StaffApiControllerTest.java create mode 100644 core-services/attendance/src/test/resources/AttendeeCreateRequest.json create mode 100644 core-services/attendance/src/test/resources/InvalidTenantMDMSData.json create mode 100644 core-services/attendance/src/test/resources/TenantMDMSData.json diff --git a/core-services/attendance/Attendace Service Postman Scripts.postman_collection.json b/core-services/attendance/Attendace Service Postman Scripts.postman_collection.json new file mode 100644 index 00000000000..4f63c0b7820 --- /dev/null +++ b/core-services/attendance/Attendace Service Postman Scripts.postman_collection.json @@ -0,0 +1,3633 @@ +{ + "info": { + "_postman_id": "25632b98-5918-4908-8a85-9500d8a81afa", + "name": "Attendace Service Postman Scripts", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Attendance Register", + "item": [ + { + "name": "Create Attendance Register - Success - Single Register", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendance Registers are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendanceRegister).to.not.be.undefined;", + " pm.expect(req.attendanceRegister).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.tenantId).to.be.not.null;", + " pm.expect(register.tenantId).to.be.not.undefined;", + " pm.expect(register.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Register Name is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.name).to.be.not.null;", + " pm.expect(register.name).to.be.not.undefined;", + " pm.expect(register.name).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Register start date is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.startDate).to.be.not.null;", + " pm.expect(register.startDate).to.be.not.undefined;", + " pm.expect(register.startDate).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Start date should be less than end date\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " if (Number.isFinite(register.endDate) && (register.endDate != undefined || register.endDate != null )) {", + " pm.expect(register.endDate).to.be.not.below(register.startDate);", + " }", + " }", + ");", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Register Number is enriched\", function () {", + " var res = pm.response.json();", + " var registerNumber = res.attendanceRegister[0].registerNumber;", + " pm.expect(registerNumber.substring(0,2)).to.eql(\"WR\");", + " }", + ");", + "", + "pm.test(\"Register status is set to Active if status not passed\", function () {", + " var res = pm.response.json();", + " var status = res.attendanceRegister[0].status;", + " pm.expect(status).to.eql(\"ACTIVE\");", + " }", + ");", + "", + "pm.test(\"Staff is created for register\", function () {", + " var res = pm.response.json();", + " var staff = res.attendanceRegister[0].staff;", + " pm.expect(staff).to.be.not.null;", + " pm.expect(staff).to.be.not.undefined;", + " pm.expect(staff.length).to.eql(1);", + " }", + ");", + "", + "pm.test(\"Staff created have same userId as UUID of user\", function () {", + " var res = pm.response.json();", + " var userInRequest = res.attendanceRegister[0].auditDetails.createdBy;", + " var staff = res.attendanceRegister[0].staff;", + " pm.expect(staff[0].userId).to.eql(userInRequest);", + " }", + ");", + "", + "let responseData = pm.response.json();", + "pm.collectionVariables.set(\"tenantId\", responseData.attendanceRegister[0].tenantId);", + "pm.collectionVariables.set(\"stateLevelTenant\", responseData.attendanceRegister[0].tenantId.split('.', 1)[0]);", + "pm.collectionVariables.set(\"registerId\", responseData.attendanceRegister[0].id);", + "pm.collectionVariables.set(\"registerNumber\", responseData.attendanceRegister[0].registerNumber);", + "", + "pm.collectionVariables.set(\"registerStartDate\", responseData.attendanceRegister[0].startDate);", + "pm.collectionVariables.set(\"registerEndDate\", responseData.attendanceRegister[0].endDate);", + "pm.collectionVariables.set(\"invalidRegisterEndDate\", responseData.attendanceRegister[0].endDate+24*60*60*1000);", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "pm.collectionVariables.set(\"tenantId\", \"pg.citya\");", + "// pm.collectionVariables.set(\"individualId\", \"2d12b93a-829b-4aef-9073-5418e2315355\");", + "//dev", + "pm.collectionVariables.set(\"individualId-1\", \"6731ed44-2407-457d-aa3e-70ffbd1d6d21\");", + "pm.collectionVariables.set(\"individualId-2\", \"311b13c2-0029-4679-8723-fe6f57870a35\");", + "", + "", + "//qa", + "// pm.collectionVariables.set(\"individualId-1\", \"3ff2861e-8bbd-4431-a6b4-6f6a1c116356\");", + "// pm.collectionVariables.set(\"individualId-2\", \"a7d7ec01-68e0-428d-8762-c81e2fd5c864\");", + "", + "", + "pm.collectionVariables.set(\"referenceId\", \"test_contract_number_01\");", + "pm.collectionVariables.set(\"serviceCode\", \"WORKS-CONTRACT\");", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_01\",\n \"referenceId\": \"{{referenceId}}+{{$randomPhoneNumber}}\",\n \"serviceCode\": \"{{serviceCode}}\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Success - Multiple Registers", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendance Registers are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendanceRegister).to.not.be.undefined;", + " pm.expect(req.attendanceRegister).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.tenantId).to.be.not.null;", + " pm.expect(register.tenantId).to.be.not.undefined;", + " pm.expect(register.tenantId).not.to.eql(\"\");", + " });", + " }", + ");", + "", + "pm.test(\"Register Name is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.name).to.be.not.null;", + " pm.expect(register.name).to.be.not.undefined;", + " pm.expect(register.name).not.to.eql(\"\");", + " });", + " }", + ");", + "", + "pm.test(\"Register start date is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.startDate).to.be.not.null;", + " pm.expect(register.startDate).to.be.not.undefined;", + " pm.expect(register.startDate).not.to.eql(\"\");", + " });", + " }", + ");", + " ", + "", + "pm.test(\"Start date should be less than end date\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " if (Number.isFinite(register.endDate) && (register.endDate != undefined || register.endDate != null )) {", + " pm.expect(register.endDate).to.be.not.below(register.startDate);", + " }", + " });", + " }", + ");", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Register Number is enriched\", function () {", + " var res = pm.response.json();", + " res.attendanceRegister.forEach(register => {", + " var registerNumber = register.registerNumber;", + " pm.expect(registerNumber.substring(0,2)).to.eql(\"WR\");", + " });", + " }", + ");", + "", + "pm.test(\"Staff is created for register\", function () {", + " var res = pm.response.json();", + " res.attendanceRegister.forEach(register => {", + " var staff = register.staff;", + " pm.expect(staff).to.be.not.null;", + " pm.expect(staff).to.be.not.undefined;", + " pm.expect(staff.length).to.eql(1);", + " }); ", + " }", + ");", + "", + "pm.test(\"Staff created have same userId as UUID of user\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var res = pm.response.json();", + " res.attendanceRegister.forEach(register => {", + " var userInRequest = register.auditDetails.createdBy;", + " var staff =register.staff;", + " pm.expect(staff[0].userId).to.eql(userInRequest);", + " }); ", + " }", + ");", + "", + "let responseData = pm.response.json();", + "pm.collectionVariables.set(\"registerId2\", responseData.attendanceRegister[1].id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_01\",\n \"referenceId\": \"{{referenceId}}+{{$randomPhoneNumber}}\",\n \"serviceCode\": \"{{serviceCode}}\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000\n },\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_02\",\n \"referenceId\": \"{{referenceId}}+{{$randomPhoneNumber}}\",\n \"serviceCode\": \"{{serviceCode}}\",\n \"startDate\": 1640995200000,\n \"additionalDetails\": {}\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Validation Error - Registers not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"ATTENDANCE_REGISTER\");", + " pm.expect(message).to.eql(\"Attendance Register is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": []\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Validation Error - TenantId not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"TENANT_ID\");", + " pm.expect(message).to.eql(\"Tenant is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"name\": \"TestRegister_01\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Validation Error - Name not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"NAME\");", + " pm.expect(message).to.eql(\"Name is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"referenceId\": \"{{referenceId}}+{{$randomPhoneNumber}}\",\n \"serviceCode\": \"{{serviceCode}}\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Validation Error - Start Date not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"START_DATE\");", + " pm.expect(message).to.eql(\"Start date is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_01\",\n \"endDate\": 1703980800000\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Validation Error - Start Date greater than End Date", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"DATE\");", + " pm.expect(message).to.eql(\"Start date should be less than end date\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_01\",\n \"startDate\": 1803980800000,\n \"endDate\": 1703980800000\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Validation Error - Start Date Equal to 0", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"START_DATE\");", + " pm.expect(message).to.eql(\"Start date is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_01\",\n \"startDate\": 0,\n \"endDate\": 1703980800000\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Success", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200)));", + "", + "pm.test(\"Register Search response is received\", function () {", + " var res = pm.response.json();", + " var id = res.attendanceRegister[0].id;", + " pm.expect(id).to.eql(pm.collectionVariables.get(\"registerId\"));", + " }", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"{{token}}\"\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?tenantId={{tenantId}}&ids={{registerId}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + }, + { + "key": "ids", + "value": "{{registerId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Success - Unassociated AttendeeId", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200)));", + "", + "pm.test(\"Register Search response is received\", function () {", + " var res = pm.response.json();", + " pm.expect(res.attendanceRegister.length).to.equal(0);", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"{{token}}\"\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?tenantId={{tenantId}}&ids={{registerId}}&attendeeId={{$guid}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + }, + { + "key": "ids", + "value": "{{registerId}}" + }, + { + "key": "attendeeId", + "value": "{{$guid}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Success - Unassociated StaffId", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200)));", + "", + "pm.test(\"Register Search response is received\", function () {", + " var res = pm.response.json();", + " pm.expect(res.attendanceRegister.length).to.equal(0);", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"{{token}}\"\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?tenantId={{tenantId}}&ids={{registerId}}&staffId={{$guid}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + }, + { + "key": "ids", + "value": "{{registerId}}" + }, + { + "key": "staffId", + "value": "{{$guid}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Success - SuperUser - Non existing RegisterID", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200)));", + "", + "pm.test(\"Register Search response is received\", function () {", + " var res = pm.response.json();", + " pm.expect(res.attendanceRegister.length).to.equal(0);", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"{{token}}\"\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?tenantId={{tenantId}}&ids={{$guid}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + }, + { + "key": "ids", + "value": "{{$guid}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Validation Error - Unassociated Register Id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200)));", + "", + "pm.test(\"Register Search response is received\", function () {", + " var res = pm.response.json();", + " var code = res.attendanceRegister.length;", + " pm.expect(code).to.eql(0);", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"{{token}}\"\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?tenantId={{tenantId}}&ids=96d1055c-0251-498d-b98d-26d6c232925f", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + }, + { + "key": "ids", + "value": "96d1055c-0251-498d-b98d-26d6c232925f" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Validation Error - Tenant Id not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"TENANT_ID\");", + " pm.expect(message).to.eql(\"Tenant is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"{{token}}\"\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?ids={{registerId}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "ids", + "value": "{{registerId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Update Attendance Register - Success - Single Register", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "", + "pm.test(\"Attendance Registers are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendanceRegister).to.not.be.undefined;", + " pm.expect(req.attendanceRegister).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.tenantId).to.be.not.null;", + " pm.expect(register.tenantId).to.be.not.undefined;", + " pm.expect(register.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Register Id is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.id).to.be.not.null;", + " pm.expect(register.id).to.be.not.undefined;", + " pm.expect(register.id).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Register Name is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.name).to.be.not.null;", + " pm.expect(register.name).to.be.not.undefined;", + " pm.expect(register.name).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Register start date is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.startDate).to.be.not.null;", + " pm.expect(register.startDate).to.be.not.undefined;", + " pm.expect(register.startDate).not.to.eql(\"\");", + " }", + ");", + " ", + "", + "pm.test(\"Start date should be less than end date\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " if (Number.isFinite(register.endDate) && (register.endDate != undefined || register.endDate != null )) {", + " pm.expect(register.endDate).to.be.not.below(register.startDate);", + " }", + " }", + ");", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Staff is created for register\", function () {", + " var res = pm.response.json();", + " var staff = res.attendanceRegister[0].staff;", + " pm.expect(staff).to.be.not.null;", + " pm.expect(staff).to.be.not.undefined;", + " pm.expect(staff.length).to.eql(1);", + " }", + ");", + "", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"id\": \"{{registerId}}\",\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_010\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000,\n \"status\": \"ACTIVE\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Update Attendance Register - Success - Multiple Registers", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "", + "pm.test(\"Attendance Registers are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendanceRegister).to.not.be.undefined;", + " pm.expect(req.attendanceRegister).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.tenantId).to.be.not.null;", + " pm.expect(register.tenantId).to.be.not.undefined;", + " pm.expect(register.tenantId).not.to.eql(\"\");", + " });", + " }", + ");", + "", + "pm.test(\"Register Id is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.id).to.be.not.null;", + " pm.expect(register.id).to.be.not.undefined;", + " pm.expect(register.id).not.to.eql(\"\");", + " });", + " }", + ");", + "", + "pm.test(\"Register Name is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.name).to.be.not.null;", + " pm.expect(register.name).to.be.not.undefined;", + " pm.expect(register.name).not.to.eql(\"\");", + " });", + " }", + ");", + "", + "pm.test(\"Register start date is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.startDate).to.be.not.null;", + " pm.expect(register.startDate).to.be.not.undefined;", + " pm.expect(register.startDate).not.to.eql(\"\");", + " });", + " }", + ");", + " ", + "", + "pm.test(\"Start date should be less than end date\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " if (Number.isFinite(register.endDate) && (register.endDate != undefined || register.endDate != null )) {", + " pm.expect(register.endDate).to.be.not.below(register.startDate);", + " }", + " });", + " }", + ");", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"id\": \"{{registerId}}\",\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_010\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000,\n \"status\": \"ACTIVE\"\n },\n {\n \"id\": \"{{registerId2}}\",\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_020\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000,\n \"status\": \"INACTIVE\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Update Attendance Register - Validation Error - Register Id not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"ATTENDANCE_REGISTER_ID\");", + " pm.expect(message).to.eql(\"Attendance register id is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_010\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000,\n \"status\": \"ACTIVE\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Update Attendance Register - Validation Error - Tenant Id not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"TENANT_ID\");", + " pm.expect(message).to.eql(\"Tenant is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"id\": \"{{registerId}}\",\n \"name\": \"TestRegister_010\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000,\n \"status\": \"ACTIVE\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Update Attendance Register - Validation Error - Name not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"NAME\");", + " pm.expect(message).to.eql(\"Name is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"id\": \"{{registerId}}\",\n \"tenantId\": \"{{tenantId}}\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000,\n \"status\": \"ACTIVE\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Update Attendance Register - Validation Error - Start Date not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"START_DATE\");", + " pm.expect(message).to.eql(\"Start date is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"id\": \"{{registerId}}\",\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_010\",\n \"endDate\": 1703980800000,\n \"status\": \"ACTIVE\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_update" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Register Permission", + "item": [ + { + "name": "Staff - Enroll - Single Staff", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Enrollment date is enriched\", function () {", + " var res = pm.response.json();", + " var enrollmentDate = res.staff[0].enrollmentDate;", + " pm.expect(enrollmentDate).to.be.not.null;", + " }", + ");", + "", + "// let requestData = JSON.parse(pm.request.body.raw);", + "// pm.collectionVariables.set(\"userId\", requestData.staff[0].userId);", + "", + "let responseData = pm.response.json();", + "pm.collectionVariables.set(\"userId\", responseData.staff[0].userId);", + "console.log(pm.collectionVariables.get(\"userId\"));", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Enroll the user to register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{$randomUUID}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Enroll - Validation Error - Staff already enrolled to the register", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"response is 400. Staff is already enrolled to the register\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "console.log(pm.collectionVariables.get(\"userId\"))" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Enroll the user to register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Enroll - Validation Error - Duplicate staff objects not allowed in enrollment request", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + "", + " req.staff.forEach(staff => {", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }); ", + "", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "", + "pm.test(\"Response is 400. Duplicate objects in request\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Enroll the user to register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"928ca23a-9bec-11ed-a8fc-0242ac120002\",\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"928ca23a-9bec-11ed-a8fc-0242ac120002\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Enroll - Multiple staff", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + "", + " req.staff.forEach(staff => {", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }); ", + "", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Enrollment date is enriched\", function () {", + " var res = pm.response.json();", + " res.staff.forEach(staff => {", + " pm.expect(staff.enrollmentDate).to.be.not.null;", + " }); ", + " }", + ");", + "", + "let requestData = JSON.parse(pm.request.body.raw);", + "pm.collectionVariables.set(\"userId-1\", requestData.staff[0].userId);", + "pm.collectionVariables.set(\"userId-2\", requestData.staff[1].userId);", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Enroll the user to register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{$randomUUID}}\",\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{$randomUUID}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Deenroll - Single staff", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Deenrollment date is enriched\", function () {", + " var res = pm.response.json();", + " var deenrollmentDate = res.staff[0].deenrollmentDate;", + " pm.expect(deenrollmentDate).to.be.not.null;", + " }", + ");", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Deenroll staff from register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Deenroll - Validation Error - Staff already denrolled from the register", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is 400. Staff already deenrolled from the register\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Deenroll staff from register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Deenroll - Validation Error - Duplicate staff objects in deenrollment request", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + "", + " req.staff.forEach(staff => {", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }); ", + "", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Response is 400. Duplicate staff objects in de enrollment request\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Deenroll staff from register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId-1}}\",\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId-1}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Deenroll - Multiple staff", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + "", + " req.staff.forEach(staff => {", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }); ", + "", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Deenrollment date is enriched\", function () {", + " var res = pm.response.json();", + " res.staff.forEach(staff => {", + " pm.expect(staff.deenrollmentDate).to.be.not.null;", + " }); ", + " }", + ");", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Deenroll staff from register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId-1}}\",\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId-2}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_delete" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Individual Enrollment", + "item": [ + { + "name": "Attendee - Enroll - Attendee", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendee are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Enrollment date is enriched\", function () {", + " var res = pm.response.json();", + " var enrollmentDate = res.attendees[0].enrollmentDate;", + " pm.expect(enrollmentDate).to.be.not.null;", + " }", + ");", + "", + "// let requestData = JSON.parse(pm.request.body.raw);", + "// pm.collectionVariables.set(\"individualId\", requestData.attendees[0].individualId);", + "let responseData = pm.response.json();", + "pm.collectionVariables.set(\"attendeeEnrollmentDate\", responseData.attendees[0].enrollmentDate);", + "", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Enroll attendee to register\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId-1}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n } \n\n ]\n\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Enroll - Validation Error - Attendee already enrolled", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendee are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is 400. Attendee already enrolled to the register\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Enroll attendee to register\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId-1}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n } \n\n ]\n\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Enroll - Validation Error - Duplicate attendee objects not allowed in request", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendee are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "", + "pm.test(\"Response is 400. Duplicate attendee objects in the request\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Enroll attendee to register\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId-1}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId-1}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n } \n\n ]\n\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Deenroll- Single Attendee", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendees are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Deenrollment date is enriched\", function () {", + " var res = pm.response.json();", + " var deenrollmentDate = res.attendees[0].deenrollmentDate;", + " pm.expect(deenrollmentDate).to.be.not.null;", + " }", + ");", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"search with from and to values\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId-1}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Deenroll- Validation Error - Attendee already deenrolled from the register", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendees are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is 400. Attendee already deenrolled from the register\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"search with from and to values\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId-1}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Enroll - Multiple Attendees", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendee are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Enrollment date is enriched\", function () {", + " var res = pm.response.json();", + " res.attendees.forEach(attendee => {", + " pm.expect(attendee.enrollmentDate).to.be.not.null;", + " }); ", + " }", + ");", + "", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Enroll attendee to register\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId-1}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId-2}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n } \n\n ]\n\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Deenroll- Validation Error - Duplicate attendee objects in deenrollment request", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendees are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "", + "pm.test(\"Response is 400. Duplicate attendee objects in deenrollment request.\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"search with from and to values\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId-1}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId-1}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Deenroll- Multiple Attendees", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendees are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Deenrollment date is enriched\", function () {", + " var res = pm.response.json();", + " res.attendees.forEach(attendee => {", + " pm.expect(attendee.denrollmentDate).to.be.not.null;", + " }); ", + " }", + ");", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"search with from and to values\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId-1}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId-2}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_delete" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Attendance Log", + "item": [ + { + "name": "Attendance Log - Create - Success", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + " setTimeout( () => {", + "", + " pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var id = res.attendance[0].id;", + " pm.expect(id).to.be.not.null;", + " }", + ");", + " ", + " }, 1000);", + "", + "", + "", + "let responseData = pm.response.json();", + "pm.collectionVariables.set(\"attendanceLogId\", responseData.attendance[0].id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId-1}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Update - Success", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Attendance Log updated successfully\", function () {", + " var res = pm.response.json();", + " var status = res.attendance[0].status;", + " pm.expect(status).to.eql(\"INACTIVE\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"id\": \"{{attendanceLogId}}\",\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId-1}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"INACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ],\r\n \"auditDetails\": {\r\n \"createdBy\": \"47b5ea82-249c-4435-9646-16167fec06df\",\r\n \"lastModifiedBy\": \"47b5ea82-249c-4435-9646-16167fec06df\",\r\n \"createdTime\": 1671090269007,\r\n \"lastModifiedTime\": 1671090269007\r\n }\r\n \r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Update - fail - attendanceId is not valid", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log updated successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"ATTENDANCE_LOG\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"id\": \"{{$randomUUID}}\",\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"INACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ],\r\n \"auditDetails\": {\r\n \"createdBy\": \"47b5ea82-249c-4435-9646-16167fec06df\",\r\n \"lastModifiedBy\": \"47b5ea82-249c-4435-9646-16167fec06df\",\r\n \"createdTime\": 1671090269007,\r\n \"lastModifiedTime\": 1671090269007\r\n }\r\n \r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Create - Fail - All logs should belong to same tenantId", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"MULTIPLE_TENANTIDS\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n },\r\n {\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"tenant.id\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Create - Fail - Validate Attendance Log time", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"INVALID_ATTENDANCE_TIME\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{invalidRegisterEndDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Create - Fail - Register should belongs to tenenatId", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": \"{{$randomUUID}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Create - Fail - All logs should belong to same registerId", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"MULTIPLE_REGISTERIDS\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n },\r\n {\r\n \"registerId\": \"{{$randomUUID}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Create - Fail - User is not authorised", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"UNAUTHORISED_USER\");", + " }", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": \"{{$randomUUID}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Rearch - Fail - TenantId is required", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"TENANT_ID\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n }\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_search", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_search" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Rearch - Fail - RegisterId is required", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"REGISTER_ID\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n }\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_search?tenantId={{tenantId}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Rearch - Success", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " pm.expect(res.attendance).to.be.not.null;", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n }\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_search?tenantId={{tenantId}}®isterId={{registerId}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + }, + { + "key": "registerId", + "value": "{{registerId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Create - Fail - required fields are missing", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Register Search response is received\", function () {", + " var res = pm.response.json();", + " pm.expect(res.Errors.length).to.equal(5);", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": null,\r\n \"individualId\": null,\r\n \"time\": null,\r\n \"type\": null,\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": null,\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "if (pm.environment.get(\"base_url\").includes(\"localhost\")) {", + "", + " var tenantId = \"pb.amritsar\";", + " var id = 1;", + " var uuid = \"11b0e02b-0145-4de2-bc42-c97b96264807\";", + "", + " var roles = [{", + " \"code\": \"SUPERUSER\",", + " \"name\": \"SUPER USER\",", + " \"tenantId\": tenantId", + " }];", + "", + " var userInfo = {", + " \"id\": id,", + " \"uuid\": uuid,", + " \"userName\": \"\",", + " \"name\": \"\",", + " \"mobileNumber\": \"\",", + " \"emailId\": \"\",", + " \"type\": \"\",", + " \"roles\": roles,", + " \"active\": true,", + " \"tenantId\": \"pb.amritsar\"", + " };", + "", + " pm.request.body.raw = pm.request.body.raw.replace('\"{{token}}\"', '\"\", \\n \"userInfo\": ' + JSON.stringify(userInfo));", + "}" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "tenantId", + "value": "" + }, + { + "key": "stateLevelTenant", + "value": "" + }, + { + "key": "registerId", + "value": "" + }, + { + "key": "registerNumber", + "value": "" + }, + { + "key": "registerId2", + "value": "" + }, + { + "key": "registerStartDate", + "value": "" + }, + { + "key": "registerEndDate", + "value": "" + }, + { + "key": "invalidRegisterEndDate", + "value": "" + }, + { + "key": "userId", + "value": "" + }, + { + "key": "userId-1", + "value": "" + }, + { + "key": "userId-2", + "value": "" + }, + { + "key": "individualId", + "value": "" + }, + { + "key": "attendeeEnrollmentDate", + "value": "" + }, + { + "key": "individualId-1", + "value": "" + }, + { + "key": "individualId-2", + "value": "" + }, + { + "key": "attendanceLogId", + "value": "" + }, + { + "key": "referenceId", + "value": "" + }, + { + "key": "serviceCode", + "value": "" + } + ] +} \ No newline at end of file diff --git a/core-services/attendance/Attendance-Service-1.0.0.yaml b/core-services/attendance/Attendance-Service-1.0.0.yaml new file mode 100644 index 00000000000..7a3c97e43fb --- /dev/null +++ b/core-services/attendance/Attendance-Service-1.0.0.yaml @@ -0,0 +1,666 @@ +openapi: 3.0.0 +info: + version: 1.0.0 + title: Attendance Service + description: '' + +paths: + + /attendance/v1/_create: + post: + tags: + - Attendance Register + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AttendanceRegisterRequest' + responses: + '202': + description: 'Request to create a register has been accepted.' + content: + application/json: + schema: + $ref: '#/components/schemas/AttendanceRegisterResponse' + '400': + description: Invalid input. + content: + '*/*': + schema: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/master/core-services/docs/common-contract.yml#/components/schemas/ErrorRes' + + /attendance/v1/_update: + post: + tags: + - Attendance Register + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AttendanceRegisterRequest' + responses: + '202': + description: 'Request to update the register has been accepted.' + content: + application/json: + schema: + $ref: '#/components/schemas/AttendanceRegisterResponse' + '400': + description: Invalid input. + content: + '*/*': + schema: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/master/core-services/docs/common-contract.yml#/components/schemas/ErrorRes' + + /attendance/v1/_search: + post: + tags: + - Attendance Register + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RequestInfoWrapper' + parameters: + - $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/master/core-services/docs/common-contract.yml#/components/parameters/tenantId' + - name: ids + description: List of register ids + in: query + schema: + type: array + items: + type: string + - name: registerNumber + description: Custom formatted Register id + in: query + schema: + type: string + - name: name + description: Name of the register + in: query + schema: + type: string + - name: referenceId + description: Reference Id + in: query + schema: + type: string + - name: serviceCode + description: Service Code + in: query + schema: + type: string + - name: fromDate + description: Return registers with any overlap in the given time period + in: query + schema: + type: number + - name: toDate + description: Return registers with any overlap in the given time period + in: query + schema: + type: number + - name: status + description: Status of the register. This can't be the only query param. It should be paired with some other search param. + in: query + schema: + type: string + - name: attendeeId + description: Get all the registers where the given Individual was registered. + in: query + schema: + type: string + - name: staffId + description: Get all the registers where the given staff was registered. + in: query + schema: + type: string + - name: sortBy + in: query + description: sort the search results by fields + schema: + type: string + enum: + - fromDate + - toDate + - lastModifiedTime + - name: sortOrder + in: query + description: sorting order of the search resulsts + schema: + type: string + enum: + - asc + - desc + - name: limit + in: query + description: limit on the resulsts + schema: + type: number + - name: offset + in: query + description: offset index of the overall search resulsts + schema: + type: number + responses: + '200': + description: 'Search results' + content: + application/json: + schema: + $ref: '#/components/schemas/AttendanceRegisterResponse' + '400': + description: Invalid input. + content: + '*/*': + schema: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/master/core-services/docs/common-contract.yml#/components/schemas/ErrorRes' + + /attendance/staff/v1/_create: + post: + description: Grant permission to a user to access and modify an attendance register. This user can enroll / denroll individuals. They will add attendance entries for the attendees. + tags: + - Register Permission + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/StaffPermissionRequest' + responses: + '202': + description: 'Grant permission request accepted' + content: + application/json: + schema: + $ref: '#/components/schemas/StaffPermissionResponse' + '400': + description: Invalid input. + content: + '*/*': + schema: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/master/core-services/docs/common-contract.yml#/components/schemas/ErrorRes' + + /attendance/staff/v1/_delete: + post: + description: Revoke permission to a user to access and modify an attendance register. This user can enroll / denroll individuals. They will add attendance entries for the attendees. + tags: + - Register Permission + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/StaffPermissionRequest' + responses: + '202': + description: 'Revoke permission request accepted' + content: + application/json: + schema: + $ref: '#/components/schemas/StaffPermissionResponse' + '400': + description: Invalid input. + content: + '*/*': + schema: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/master/core-services/docs/common-contract.yml#/components/schemas/ErrorRes' + + /attendance/attendee/v1/_create: + post: + description: Users with permission to access the register can enroll / denroll attendees. + tags: + - Individual Enrollment + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AttendeeCreateRequest' + responses: + '202': + description: 'Attendee Create request accepted' + content: + application/json: + schema: + $ref: '#/components/schemas/AttendeeCreateResponse' + '400': + description: Invalid input. + content: + '*/*': + schema: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/master/core-services/docs/common-contract.yml#/components/schemas/ErrorRes' + + /attendance/attendee/v1/_delete: + post: + description: Users with permission to access the register can enroll / denroll attendees. + tags: + - Individual Enrollment + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AttendeeDeleteRequest' + responses: + '202': + description: 'Attendee Delete request accepted' + content: + application/json: + schema: + $ref: '#/components/schemas/AttendeeDeleteResponse' + '400': + description: Invalid input. + content: + '*/*': + schema: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/master/core-services/docs/common-contract.yml#/components/schemas/ErrorRes' + + /attendance/log/v1/_create: + post: + tags: + - Attendance Log + description: It creates a new attendance record. + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AttendanceLogRequest' + responses: + '202': + description: 'Attendance Records Create Request accepted.' + content: + application/json: + schema: + $ref: '#/components/schemas/AttendanceLogResponse' + '400': + description: Invalid input. + content: + '*/*': + schema: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/master/core-services/docs/common-contract.yml#/components/schemas/ErrorRes' + + /attendance/log/v1/_update: + post: + tags: + - Attendance Log + description: It updates an attendance record. + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/AttendanceLogRequest' + responses: + '202': + description: 'Attendance Records Update Request accepted.' + content: + application/json: + schema: + $ref: '#/components/schemas/AttendanceLogResponse' + '400': + description: Invalid input. + content: + '*/*': + schema: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/master/core-services/docs/common-contract.yml#/components/schemas/ErrorRes' + + /attendance/log/v1/_search: + post: + tags: + - Attendance Log + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/RequestInfoWrapper' + parameters: + - $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/master/core-services/docs/common-contract.yml#/components/parameters/tenantId' + - name: registerId + in: query + required: true + description: Id of the register + schema: + type: string + - name: fromTime + in: query + description: Starting time from which the attendance needs to be searched + schema: + type: number + - name: toTime + in: query + description: End time till which the attendance needs to be searched + schema: + type: number + - name: individualIds + in: query + description: List of individual ids + schema: + type: array + items: + type: string + - name: ids + in: query + description: List of ids + schema: + type: array + items: + type: string + - name: status + in: query + description: The status of the attendance log. + schema: + type: string + enum: + - ACTIVE + - INACTIVE + responses: + '200': + description: 'Complete table of attendance entries.' + content: + application/json: + schema: + $ref: '#/components/schemas/AttendanceLogResponse' + +components: + schemas: + AttendanceRegister: + type: object + properties: + id: + type: string + format: uuid + example: 64e33343-7b4c-4353-9abf-4de8f5bcd732 + description: System generated unique identifier of the register + readOnly: true + tenantId: + type: string + example: pb.amritsar + description: Tenant Id of the register + registerNumber: + type: string + example: REG/2022-23/001 + description: System generated id with custom formatting + readOnly: true + name: + type: string + example: Class-10-E Physics + description: Name of the register + maxLength: 140 + referenceId: + type: string + example: 64e33343-7b4c-4353-9abf-4de8f5bcd732 + description: Id of the entity to which register is associated. Example ContractId + maxLength: 256 + serviceCode: + type: string + example: WORKS-CONTRACT + description: Service to which register is associated. + maxLength: 64 + startDate: + type: number + format: timestamp + example: 1665497225000 + description: Timestamp of the start date in milliseconds + endDate: + type: number + format: timestamp + example: 1665497271000 + description: Timestamp of the end date in milliseconds. After the end date no modifications will be allowed to the register. + status: + type: string + enum: + - ACTIVE + - INACTIVE + description: Stores if the register is active or not. Inactive registers can be archieved later. + staff: + readOnly: true + type: array + items: + allOf: + - $ref: '#/components/schemas/StaffPermission' + - description: 'Entries of the staff members of the register.' + attendees: + readOnly: true + type: array + items: + allOf: + - $ref: '#/components/schemas/IndividualEntry' + - description: 'Entries of the attendees of the register.' + auditDetails: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/master/core-services/docs/common-contract.yml#/components/schemas/AuditDetails' + additionalDetails: + type: object + description: Any additional details of the register + required: + - tenantId + - name + - referenceId + - serviceCode + + AttendanceRegisterRequest: + type: object + properties: + requestInfo: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/subhashini_devguide_changes/core-services/docs/common-contract.yml#/definitions/RequestInfo' + attendanceRegister: + type: array + items: + allOf: + - $ref: '#/components/schemas/AttendanceRegister' + - description: 'Entries of the attendance register to be created.' + + AttendanceRegisterResponse: + type: object + properties: + responseInfo: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/subhashini_devguide_changes/core-services/docs/common-contract.yml#/definitions/ResponseInfo' + attendanceRegister: + type: array + items: + $ref: '#/components/schemas/AttendanceRegister' + + IndividualEntry: + type: object + properties: + id: + type: string + format: uuid + example: 64e33343-7b4c-4353-9abf-4de8f5bcd732 + description: Primary identifier of the enrollment record + readOnly: true + registerId: + type: string + format: uuid + example: 32e33343-7b4c-4353-9abf-4de8f5bcd764 + description: This field will not be shown when this object is part of the register object. It is present so that we can reuse this object for enroll and denroll requests. + individualId: + type: string + format: uuid + example: 2bafdd8d-5673-4690-b3d0-e13d7ac0cf24 + description: Reference from the Individual Registry + enrollmentDate: + type: number + description: The timestamp of the date on which the individual is enrolled onto the register. Defaults to current time. + denrollmentDate: + type: number + description: The timestamp of the date on which the individual is denrolled from the register. Defaults to current time. + tenantId: + type: string + example: pb.amritsar + description: Tenant Id + + AttendeeCreateRequest: + type: object + properties: + requestInfo: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/subhashini_devguide_changes/core-services/docs/common-contract.yml#/definitions/RequestInfo' + attendees: + type: array + items: + allOf: + - $ref: '#/components/schemas/IndividualEntry' + - required: + - registerId + - individualId + - enrollmentDate + - tenantId + + AttendeeCreateResponse: + type: object + properties: + responseInfo: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/subhashini_devguide_changes/core-services/docs/common-contract.yml#/definitions/ResponseInfo' + attendees: + type: array + items: + $ref: '#/components/schemas/IndividualEntry' + + AttendeeDeleteRequest: + type: object + properties: + requestInfo: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/subhashini_devguide_changes/core-services/docs/common-contract.yml#/definitions/RequestInfo' + attendees: + type: array + items: + allOf: + - $ref: '#/components/schemas/IndividualEntry' + - required: + - registerId + - individualId + - denrollmentDate + - tenantId + + AttendeeDeleteResponse: + type: object + properties: + responseInfo: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/subhashini_devguide_changes/core-services/docs/common-contract.yml#/definitions/ResponseInfo' + attendees: + type: array + items: + $ref: '#/components/schemas/IndividualEntry' + + StaffPermission: + type: object + properties: + id: + type: string + format: uuid + description: System generated unique identifier for the granted permission request + readOnly: true + registerId: + type: string + description: Identifier of the register. This field will not be shown when this object is part of the register object. It is present so that we can reuse this object for access permission requests. + userId: + type: string + description: Identifier of the user of the system + tenantId: + type: string + format: string + example: pb.amritsar + description: Tenant Id to which the staff belongs + enrollmentDate: + readOnly: true + type: number + description: The timestamp at which the permission is granted. It is set to the current time when the create api is called. + denrollmentDate: + readOnly: true + type: number + description: The timestamp at which the access permission is revoked. It is set to the current time when the delete api is called. + required: + - registerId + - userId + + StaffPermissionRequest: + type: object + properties: + requestInfo: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/subhashini_devguide_changes/core-services/docs/common-contract.yml#/definitions/RequestInfo' + staff: + type: array + items: + allOf: + - $ref: '#/components/schemas/StaffPermission' + - required: + - registerId + - userId + - tenantId + + StaffPermissionResponse: + type: object + properties: + responseInfo: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/subhashini_devguide_changes/core-services/docs/common-contract.yml#/definitions/ResponseInfo' + staff: + type: array + items: + $ref: '#/components/schemas/StaffPermission' + + AttendanceLog: + type: object + properties: + id: + type: string + format: uuid + description: System generated unique identifier for the entry + readOnly: true + registerId: + type: string + description: Unique identifier of the register + individualId: + type: string + format: uuid + description: The individual for which the attendance is being marked + tenantId: + type: string + example: pb.amritsar + description: Tenant Id of the register + time: + type: number + format: timestamp + description: The timestamp at which the event has been recorded. + type: + type: string + description: Configurable in MDMS. [ENTRY/EXIT/...] + status: + type: string + enum: + - ACTIVE + - INACTIVE + description: The attendance log of the cancelled event can be marked as inactive. + documentIds: + description: Used to store file store ids. Need to verify validity of them using file store service. + type: array + items: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/master/core-services/docs/common-contract.yml#/components/schemas/Document' + additionalDetails: + type: object + required: + - registerId + - individualId + - tenantId + - time + - type + + AttendanceLogRequest: + type: object + properties: + requestInfo: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/subhashini_devguide_changes/core-services/docs/common-contract.yml#/definitions/RequestInfo' + attendance: + type: array + items: + $ref: '#/components/schemas/AttendanceLog' + + AttendanceLogResponse: + type: object + properties: + responseInfo: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/subhashini_devguide_changes/core-services/docs/common-contract.yml#/definitions/ResponseInfo' + attendance: + type: array + items: + $ref: '#/components/schemas/AttendanceLog' + + RequestInfoWrapper: + type: object + properties: + requestInfo: + $ref: 'https://raw.githubusercontent.com/egovernments/DIGIT-OSS/subhashini_devguide_changes/core-services/docs/common-contract.yml#/definitions/RequestInfo' \ No newline at end of file diff --git a/core-services/attendance/CHANGELOG.md b/core-services/attendance/CHANGELOG.md new file mode 100644 index 00000000000..e5a50979d1d --- /dev/null +++ b/core-services/attendance/CHANGELOG.md @@ -0,0 +1,6 @@ + +All notable changes to this module will be documented in this file. + +## 0.1.0 - 2023-04-17 + +- Base version \ No newline at end of file diff --git a/core-services/attendance/LOCALSETUP.md b/core-services/attendance/LOCALSETUP.md new file mode 100644 index 00000000000..dbbd2382297 --- /dev/null +++ b/core-services/attendance/LOCALSETUP.md @@ -0,0 +1,42 @@ +# Local Setup + +To set up the muster roll service in your local system, clone the git repo(https://github.com/egovernments/DIGIT-Works). + +## Dependencies + +- MDMS +- IDGen +- Workflow service +- Individual + + +### Infra Dependency + +- [X] Postgres DB +- [ ] Redis +- [ ] Elasticsearch (needed if there is indexer +- [X] Kafka + +## Running Locally + +To run the service locally, 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-user) 8085:8080 +kubectl port-forward -n egov $(kgpt egov-idgen) 8086:8080 +kubectl port-forward -n egov $(kgpt egov-mdms-service) 8087:8080 +kubectl port-forward -n egov $(kgpt egov-workflow) 8088:8080 +kubectl port-forward -n works $(kgpt project-management-service) 8089:8080 +``` + +Update below listed properties in `application.properties` before running the project: + +```ini +egov.idgen.hostname = http://127.0.0.1:8086 + +# can use non port forwarded environment host as well +egov.mdms.host = http://127.0.0.1:8087 +egov.workflow.host = http://127.0.0.1:8088 +``` diff --git a/core-services/attendance/README.md b/core-services/attendance/README.md new file mode 100644 index 00000000000..c8866f16367 --- /dev/null +++ b/core-services/attendance/README.md @@ -0,0 +1,29 @@ +# Attendance Service + +The attendance service provides generic attendance logging functionality based on "in" and "out" timestamps. +IN and OUT timestamps are recorded per individual. Aggregating and calculating attendance based on these timestamps +is the function of the muster roll service. + + +### Service Dependencies + +- DIGIT backbone services +- Individual +- MDMS +- ID-GEN +- Persister +- Indexer + +## Service Details + +- Allows creation/updation/search of an attendance register +- Allows mapping of staff and attendees to a register and enforces permissions. +- Logs entry and exit timestamps in epoch time for a referenced entity + +### API Specs + +https://raw.githubusercontent.com/egovernments/DIGIT-Specs/master/Domain%20Services/Works/Attendance-Service-v1.0.0.yaml + +### Postman Collection + +https://raw.githubusercontent.com/egovernments/DIGIT-Works/master/backend/attendance/Attendace%20Service%20Postman%20Scripts.postman_collection.json \ No newline at end of file diff --git a/core-services/attendance/pom.xml b/core-services/attendance/pom.xml new file mode 100644 index 00000000000..54eda57fa8f --- /dev/null +++ b/core-services/attendance/pom.xml @@ -0,0 +1,135 @@ + + 4.0.0 + org.egov + attendance + jar + attendance + 0.2.0 + + 1.8 + ${java.version} + ${java.version} + 42.4.1 + 2.17.1 + + + org.springframework.boot + spring-boot-starter-parent + 2.2.13.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-jdbc + + + org.springframework.boot + spring-boot-starter-actuator + + + org.springframework.boot + spring-boot-starter-test + test + + + + io.swagger + swagger-core + 1.5.18 + + + + org.egov.services + tracer + 2.0.0-SNAPSHOT + + + org.egov.services + services-common + 1.1.1-SNAPSHOT + + + org.egov.services + digit-models + 1.0.0-SNAPSHOT + + + org.egov.common + health-services-models + 1.0.6-SNAPSHOT + compile + + + org.egov + mdms-client + 0.0.4-SNAPSHOT + + + org.postgresql + postgresql + + + org.jsoup + jsoup + 1.15.3 + + + org.flywaydb + flyway-core + + + + 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/core-services/attendance/postman-test-suite-Attendace-service.json b/core-services/attendance/postman-test-suite-Attendace-service.json new file mode 100644 index 00000000000..d64786c344c --- /dev/null +++ b/core-services/attendance/postman-test-suite-Attendace-service.json @@ -0,0 +1,3796 @@ +{ + "info": { + "_postman_id": "25632b98-5918-4908-8a85-9500d8a81afa", + "name": "Attendace Service Postman Scripts", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Attendance Register", + "item": [ + { + "name": "Create Attendance Register - Success - Single Register", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendance Registers are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendanceRegister).to.not.be.undefined;", + " pm.expect(req.attendanceRegister).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.tenantId).to.be.not.null;", + " pm.expect(register.tenantId).to.be.not.undefined;", + " pm.expect(register.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Register Name is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.name).to.be.not.null;", + " pm.expect(register.name).to.be.not.undefined;", + " pm.expect(register.name).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Register start date is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.startDate).to.be.not.null;", + " pm.expect(register.startDate).to.be.not.undefined;", + " pm.expect(register.startDate).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Start date should be less than end date\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " if (Number.isFinite(register.endDate) && (register.endDate != undefined || register.endDate != null )) {", + " pm.expect(register.endDate).to.be.not.below(register.startDate);", + " }", + " }", + ");", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Register Number is enriched\", function () {", + " var res = pm.response.json();", + " var registerNumber = res.attendanceRegister[0].registerNumber;", + " pm.expect(registerNumber.substring(0,2)).to.eql(\"WR\");", + " }", + ");", + "", + "pm.test(\"Register status is set to Active if status not passed\", function () {", + " var res = pm.response.json();", + " var status = res.attendanceRegister[0].status;", + " pm.expect(status).to.eql(\"ACTIVE\");", + " }", + ");", + "", + "pm.test(\"Staff is created for register\", function () {", + " var res = pm.response.json();", + " var staff = res.attendanceRegister[0].staff;", + " pm.expect(staff).to.be.not.null;", + " pm.expect(staff).to.be.not.undefined;", + " pm.expect(staff.length).to.eql(1);", + " }", + ");", + "", + "pm.test(\"Staff created have same userId as UUID of user\", function () {", + " var res = pm.response.json();", + " var userInRequest = res.attendanceRegister[0].auditDetails.createdBy;", + " var staff = res.attendanceRegister[0].staff;", + " pm.expect(staff[0].userId).to.eql(userInRequest);", + " }", + ");", + "", + "let responseData = pm.response.json();", + "pm.collectionVariables.set(\"tenantId\", responseData.attendanceRegister[0].tenantId);", + "pm.collectionVariables.set(\"stateLevelTenant\", responseData.attendanceRegister[0].tenantId.split('.', 1)[0]);", + "pm.collectionVariables.set(\"registerId\", responseData.attendanceRegister[0].id);", + "pm.collectionVariables.set(\"registerNumber\", responseData.attendanceRegister[0].registerNumber);", + "", + "pm.collectionVariables.set(\"registerStartDate\", responseData.attendanceRegister[0].startDate);", + "pm.collectionVariables.set(\"registerEndDate\", responseData.attendanceRegister[0].endDate);", + "pm.collectionVariables.set(\"invalidRegisterEndDate\", responseData.attendanceRegister[0].endDate+24*60*60*1000);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "pm.collectionVariables.set(\"tenantId\", \"pb.amritsar\");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_01\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Success - Multiple Registers", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"UserInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo.userInfo).to.not.be.null;", + " pm.expect(req.RequestInfo.userInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"UUID is required in UserInfo\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo.userInfo.uuid).to.not.be.null;", + " pm.expect(req.RequestInfo.userInfo.uuid).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendance Registers are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendanceRegister).to.not.be.undefined;", + " pm.expect(req.attendanceRegister).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.tenantId).to.be.not.null;", + " pm.expect(register.tenantId).to.be.not.undefined;", + " pm.expect(register.tenantId).not.to.eql(\"\");", + " });", + " }", + ");", + "", + "pm.test(\"Register Name is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.name).to.be.not.null;", + " pm.expect(register.name).to.be.not.undefined;", + " pm.expect(register.name).not.to.eql(\"\");", + " });", + " }", + ");", + "", + "pm.test(\"Register start date is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.startDate).to.be.not.null;", + " pm.expect(register.startDate).to.be.not.undefined;", + " pm.expect(register.startDate).not.to.eql(\"\");", + " });", + " }", + ");", + " ", + "", + "pm.test(\"Start date should be less than end date\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " if (Number.isFinite(register.endDate) && (register.endDate != undefined || register.endDate != null )) {", + " pm.expect(register.endDate).to.be.not.below(register.startDate);", + " }", + " });", + " }", + ");", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Register Number is enriched\", function () {", + " var res = pm.response.json();", + " res.attendanceRegister.forEach(register => {", + " var registerNumber = register.registerNumber;", + " pm.expect(registerNumber.substring(0,2)).to.eql(\"WR\");", + " });", + " }", + ");", + "", + "pm.test(\"Staff is created for register\", function () {", + " var res = pm.response.json();", + " res.attendanceRegister.forEach(register => {", + " var staff = register.staff;", + " pm.expect(staff).to.be.not.null;", + " pm.expect(staff).to.be.not.undefined;", + " pm.expect(staff.length).to.eql(1);", + " }); ", + " }", + ");", + "", + "pm.test(\"Staff created have same userId as UUID of user\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var res = pm.response.json();", + " res.attendanceRegister.forEach(register => {", + " var userInRequest = register.auditDetails.createdBy;", + " var staff =register.staff;", + " pm.expect(staff[0].userId).to.eql(userInRequest);", + " }); ", + " }", + ");", + "", + "let responseData = pm.response.json();", + "pm.collectionVariables.set(\"registerId2\", responseData.attendanceRegister[1].id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_01\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000\n },\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_02\",\n \"startDate\": 1640995200000,\n \"additionalDetails\": {}\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Validation Error - Registers not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"ATTENDANCE_REGISTER\");", + " pm.expect(message).to.eql(\"Attendance Register is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": []\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Validation Error - TenantId not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"TENANT_ID\");", + " pm.expect(message).to.eql(\"Tenant is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"name\": \"TestRegister_01\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Validation Error - Name not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"NAME\");", + " pm.expect(message).to.eql(\"Name is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Validation Error - Start Date not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"START_DATE\");", + " pm.expect(message).to.eql(\"Start date is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_01\",\n \"endDate\": 1703980800000\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Validation Error - Start Date greater than End Date", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"DATE\");", + " pm.expect(message).to.eql(\"Start date should be less than end date\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_01\",\n \"startDate\": 1803980800000,\n \"endDate\": 1703980800000\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Validation Error - Start Date Equal to 0", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"START_DATE\");", + " pm.expect(message).to.eql(\"Start date is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_01\",\n \"startDate\": 0,\n \"endDate\": 1703980800000\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Success", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200)));", + "", + "pm.test(\"Register Search response is received\", function () {", + " var res = pm.response.json();", + " var id = res.attendanceRegister[0].id;", + " pm.expect(id).to.eql(pm.collectionVariables.get(\"registerId\"));", + " }", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"{{token}}\"\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?tenantId={{tenantId}}&ids={{registerId}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + }, + { + "key": "ids", + "value": "{{registerId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Success - State level tenant", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200)));", + "", + "pm.test(\"Register Search response is received\", function () {", + " var res = pm.response.json();", + " var id = res.attendanceRegister[0].id;", + " pm.expect(id).to.eql(pm.collectionVariables.get(\"registerId\"));", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"{{token}}\"\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?tenantId={{stateLevelTenant}}&ids={{registerId}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{stateLevelTenant}}" + }, + { + "key": "ids", + "value": "{{registerId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Success - Unassociated AttendeeId", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200)));", + "", + "pm.test(\"Register Search response is received\", function () {", + " var res = pm.response.json();", + " pm.expect(res.attendanceRegister.length).to.equal(0);", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"\",\n \"userInfo\": {\n \"id\": 1,\n \"uuid\": \"11b0e02b-0145-4de2-bc42-c97b96264807\",\n \"userName\": \"\",\n \"name\": \"\",\n \"mobileNumber\": \"\",\n \"emailId\": \"\",\n \"type\": \"\",\n \"roles\": [\n {\n \"code\": \"ORG_ADMIN\",\n \"name\": \"Organization admin\",\n \"tenantId\": \"pb.amritsar\"\n },\n {\n \"code\": \"ORG_STAFF\",\n \"name\": \"Organization staff\",\n \"tenantId\": \"pb.amritsar\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"pb.amritsar\"\n }\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?tenantId={{tenantId}}&ids={{registerId}}&attendeeId={{$guid}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + }, + { + "key": "ids", + "value": "{{registerId}}" + }, + { + "key": "attendeeId", + "value": "{{$guid}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Success - Unassociated StaffId", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200)));", + "", + "pm.test(\"Register Search response is received\", function () {", + " var res = pm.response.json();", + " pm.expect(res.attendanceRegister.length).to.equal(0);", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"\",\n \"userInfo\": {\n \"id\": 1,\n \"uuid\": \"11b0e02b-0145-4de2-bc42-c97b96264807\",\n \"userName\": \"\",\n \"name\": \"\",\n \"mobileNumber\": \"\",\n \"emailId\": \"\",\n \"type\": \"\",\n \"roles\": [\n {\n \"code\": \"ORG_ADMIN\",\n \"name\": \"Organization admin\",\n \"tenantId\": \"pb.amritsar\"\n },\n {\n \"code\": \"ORG_STAFF\",\n \"name\": \"Organization staff\",\n \"tenantId\": \"pb.amritsar\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"pb.amritsar\"\n }\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?tenantId={{tenantId}}&ids={{registerId}}&staffId={{$guid}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + }, + { + "key": "ids", + "value": "{{registerId}}" + }, + { + "key": "staffId", + "value": "{{$guid}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Success - User not associated with any register - empty response array", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200)));", + "", + "pm.test(\"User not associated with any register\", function () {", + " var res = pm.response.json();", + " pm.expect(res.attendanceRegister.length).to.equal(0);", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"\",\n \"userInfo\": {\n \"id\": 1,\n \"uuid\": \"{{$guid}}\",\n \"userName\": \"\",\n \"name\": \"\",\n \"mobileNumber\": \"\",\n \"emailId\": \"\",\n \"type\": \"\",\n \"roles\": [\n {\n \"code\": \"ORG_ADMIN\",\n \"name\": \"Organization admin\",\n \"tenantId\": \"pb.amritsar\"\n },\n {\n \"code\": \"ORG_STAFF\",\n \"name\": \"Organization staff\",\n \"tenantId\": \"pb.amritsar\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"pb.amritsar\"\n }\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?tenantId={{tenantId}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Success - SuperUser - Non existing RegisterID", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200)));", + "", + "pm.test(\"Register Search response is received\", function () {", + " var res = pm.response.json();", + " pm.expect(res.attendanceRegister.length).to.equal(0);", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"\",\n \"userInfo\": {\n \"id\": 1,\n \"uuid\": \"11b0e02b-0145-4de2-bc42-c97b96264807\",\n \"userName\": \"\",\n \"name\": \"\",\n \"mobileNumber\": \"\",\n \"emailId\": \"\",\n \"type\": \"\",\n \"roles\": [\n {\n \"code\": \"SUPERUSER\",\n \"name\": \"Super User\",\n \"tenantId\": \"pb.amritsar\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"pb.amritsar\"\n }\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?tenantId={{tenantId}}&ids={{$guid}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + }, + { + "key": "ids", + "value": "{{$guid}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Validation Error - Unassociated Register Id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Register Search response is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"INVALID_REGISTER_ID\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"\",\n \"userInfo\": {\n \"id\": 1,\n \"uuid\": \"11b0e02b-0145-4de2-bc42-c97b96264807\",\n \"userName\": \"\",\n \"name\": \"\",\n \"mobileNumber\": \"\",\n \"emailId\": \"\",\n \"type\": \"\",\n \"roles\": [\n {\n \"code\": \"ORG_ADMIN\",\n \"name\": \"Organization admin\",\n \"tenantId\": \"pb.amritsar\"\n },\n {\n \"code\": \"ORG_STAFF\",\n \"name\": \"Organization staff\",\n \"tenantId\": \"pb.amritsar\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"pb.amritsar\"\n }\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?tenantId={{tenantId}}&ids={{$guid}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + }, + { + "key": "ids", + "value": "{{$guid}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Validation Error - Tenant Id not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"TENANT_ID\");", + " pm.expect(message).to.eql(\"Tenant is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"{{token}}\"\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?ids={{registerId}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "ids", + "value": "{{registerId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Update Attendance Register - Success - Single Register", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"UserInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo.userInfo).to.not.be.null;", + " pm.expect(req.RequestInfo.userInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"UUID is required in UserInfo\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo.userInfo.uuid).to.not.be.null;", + " pm.expect(req.RequestInfo.userInfo.uuid).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendance Registers are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendanceRegister).to.not.be.undefined;", + " pm.expect(req.attendanceRegister).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.tenantId).to.be.not.null;", + " pm.expect(register.tenantId).to.be.not.undefined;", + " pm.expect(register.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Register Id is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.id).to.be.not.null;", + " pm.expect(register.id).to.be.not.undefined;", + " pm.expect(register.id).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Register Name is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.name).to.be.not.null;", + " pm.expect(register.name).to.be.not.undefined;", + " pm.expect(register.name).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Register start date is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.startDate).to.be.not.null;", + " pm.expect(register.startDate).to.be.not.undefined;", + " pm.expect(register.startDate).not.to.eql(\"\");", + " }", + ");", + " ", + "", + "pm.test(\"Start date should be less than end date\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " if (Number.isFinite(register.endDate) && (register.endDate != undefined || register.endDate != null )) {", + " pm.expect(register.endDate).to.be.not.below(register.startDate);", + " }", + " }", + ");", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Staff is created for register\", function () {", + " var res = pm.response.json();", + " var staff = res.attendanceRegister[0].staff;", + " pm.expect(staff).to.be.not.null;", + " pm.expect(staff).to.be.not.undefined;", + " pm.expect(staff.length).to.eql(1);", + " }", + ");", + "", + "pm.test(\"Staff created have same userId as UUID of user\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var userInRequest = req.RequestInfo.userInfo.uuid;", + " var res = pm.response.json();", + " var staff = res.attendanceRegister[0].staff;", + " pm.expect(staff[0].userId).to.eql(userInRequest);", + " }", + ");", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"id\": \"{{registerId}}\",\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_010\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000,\n \"status\": \"ACTIVE\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Update Attendance Register - Success - Multiple Registers", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"UserInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo.userInfo).to.not.be.null;", + " pm.expect(req.RequestInfo.userInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"UUID is required in UserInfo\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo.userInfo.uuid).to.not.be.null;", + " pm.expect(req.RequestInfo.userInfo.uuid).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendance Registers are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendanceRegister).to.not.be.undefined;", + " pm.expect(req.attendanceRegister).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.tenantId).to.be.not.null;", + " pm.expect(register.tenantId).to.be.not.undefined;", + " pm.expect(register.tenantId).not.to.eql(\"\");", + " });", + " }", + ");", + "", + "pm.test(\"Register Id is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.id).to.be.not.null;", + " pm.expect(register.id).to.be.not.undefined;", + " pm.expect(register.id).not.to.eql(\"\");", + " });", + " }", + ");", + "", + "pm.test(\"Register Name is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.name).to.be.not.null;", + " pm.expect(register.name).to.be.not.undefined;", + " pm.expect(register.name).not.to.eql(\"\");", + " });", + " }", + ");", + "", + "pm.test(\"Register start date is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.startDate).to.be.not.null;", + " pm.expect(register.startDate).to.be.not.undefined;", + " pm.expect(register.startDate).not.to.eql(\"\");", + " });", + " }", + ");", + " ", + "", + "pm.test(\"Start date should be less than end date\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " if (Number.isFinite(register.endDate) && (register.endDate != undefined || register.endDate != null )) {", + " pm.expect(register.endDate).to.be.not.below(register.startDate);", + " }", + " });", + " }", + ");", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Staff is created for register\", function () {", + " var res = pm.response.json();", + " res.attendanceRegister.forEach(register => {", + " var staff = register.staff;", + " pm.expect(staff).to.be.not.null;", + " pm.expect(staff).to.be.not.undefined;", + " pm.expect(staff.length).to.eql(1);", + " }); ", + " }", + ");", + "", + "pm.test(\"Staff created have same userId as UUID of user\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var userInRequest = req.RequestInfo.userInfo.uuid;", + " var res = pm.response.json();", + " res.attendanceRegister.forEach(register => {", + " var staff =register.staff;", + " pm.expect(staff[0].userId).to.eql(userInRequest);", + " }); ", + " }", + ");", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"id\": \"{{registerId}}\",\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_010\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000,\n \"status\": \"ACTIVE\"\n },\n {\n \"id\": \"{{registerId2}}\",\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_020\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000,\n \"status\": \"INACTIVE\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Update Attendance Register - Validation Error - Register Id not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"ATTENDANCE_REGISTER_ID\");", + " pm.expect(message).to.eql(\"Attendance register id is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_010\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000,\n \"status\": \"ACTIVE\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Update Attendance Register - Validation Error - Tenant Id not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"TENANT_ID\");", + " pm.expect(message).to.eql(\"Tenant is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"id\": \"{{registerId}}\",\n \"name\": \"TestRegister_010\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000,\n \"status\": \"ACTIVE\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Update Attendance Register - Validation Error - Name not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"NAME\");", + " pm.expect(message).to.eql(\"Name is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"id\": \"{{registerId}}\",\n \"tenantId\": \"{{tenantId}}\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000,\n \"status\": \"ACTIVE\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Update Attendance Register - Validation Error - Start Date not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"START_DATE\");", + " pm.expect(message).to.eql(\"Start date is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"id\": \"{{registerId}}\",\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_010\",\n \"endDate\": 1703980800000,\n \"status\": \"ACTIVE\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_update" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Register Permission", + "item": [ + { + "name": "Staff - Enroll - Single Staff", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Enrollment date is enriched\", function () {", + " var res = pm.response.json();", + " var enrollmentDate = res.staff[0].enrollmentDate;", + " pm.expect(enrollmentDate).to.be.not.null;", + " }", + ");", + "", + "// let requestData = JSON.parse(pm.request.body.raw);", + "// pm.collectionVariables.set(\"userId\", requestData.staff[0].userId);", + "", + "let responseData = pm.response.json();", + "pm.collectionVariables.set(\"userId\", responseData.staff[0].userId);", + "console.log(pm.collectionVariables.get(\"userId\"));", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Enroll the user to register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{$randomUUID}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Enroll - Validation Error - Staff already enrolled to the register", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"response is 400. Staff is already enrolled to the register\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "console.log(pm.collectionVariables.get(\"userId\"))" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Enroll the user to register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Enroll - Validation Error - Duplicate staff objects not allowed in enrollment request", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + "", + " req.staff.forEach(staff => {", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }); ", + "", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "", + "pm.test(\"Response is 400. Duplicate objects in request\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Enroll the user to register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"928ca23a-9bec-11ed-a8fc-0242ac120002\",\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"928ca23a-9bec-11ed-a8fc-0242ac120002\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Enroll - Multiple staff", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + "", + " req.staff.forEach(staff => {", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }); ", + "", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Enrollment date is enriched\", function () {", + " var res = pm.response.json();", + " res.staff.forEach(staff => {", + " pm.expect(staff.enrollmentDate).to.be.not.null;", + " }); ", + " }", + ");", + "", + "let requestData = JSON.parse(pm.request.body.raw);", + "pm.collectionVariables.set(\"userId-1\", requestData.staff[0].userId);", + "pm.collectionVariables.set(\"userId-2\", requestData.staff[1].userId);", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Enroll the user to register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{$randomUUID}}\",\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{$randomUUID}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Deenroll - Single staff", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Deenrollment date is enriched\", function () {", + " var res = pm.response.json();", + " var deenrollmentDate = res.staff[0].deenrollmentDate;", + " pm.expect(deenrollmentDate).to.be.not.null;", + " }", + ");", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Deenroll staff from register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Deenroll - Validation Error - Staff already denrolled from the register", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is 400. Staff already deenrolled from the register\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Deenroll staff from register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Deenroll - Validation Error - Duplicate staff objects in deenrollment request", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + "", + " req.staff.forEach(staff => {", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }); ", + "", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Response is 400. Duplicate staff objects in de enrollment request\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Deenroll staff from register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId-1}}\",\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId-1}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Deenroll - Multiple staff", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + "", + " req.staff.forEach(staff => {", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }); ", + "", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Deenrollment date is enriched\", function () {", + " var res = pm.response.json();", + " res.staff.forEach(staff => {", + " pm.expect(staff.deenrollmentDate).to.be.not.null;", + " }); ", + " }", + ");", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Deenroll staff from register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId-1}}\",\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId-2}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_delete" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Individual Enrollment", + "item": [ + { + "name": "Attendee - Enroll - Attendee", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendee are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Enrollment date is enriched\", function () {", + " var res = pm.response.json();", + " var enrollmentDate = res.attendees[0].enrollmentDate;", + " pm.expect(enrollmentDate).to.be.not.null;", + " }", + ");", + "", + "// let requestData = JSON.parse(pm.request.body.raw);", + "// pm.collectionVariables.set(\"individualId\", requestData.attendees[0].individualId);", + "let responseData = pm.response.json();", + "pm.collectionVariables.set(\"individualId\", responseData.attendees[0].individualId);", + "pm.collectionVariables.set(\"attendeeEnrollmentDate\", responseData.attendees[0].enrollmentDate);", + "", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Enroll attendee to register\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{$randomUUID}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n } \n\n ]\n\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Enroll - Validation Error - Attendee already enrolled", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendee are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is 400. Attendee already enrolled to the register\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Enroll attendee to register\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n } \n\n ]\n\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Enroll - Validation Error - Duplicate attendee objects not allowed in request", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendee are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "", + "pm.test(\"Response is 400. Duplicate attendee objects in the request\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Enroll attendee to register\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"928ca23a-9bec-11ed-a8fc-0242ac120002\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"928ca23a-9bec-11ed-a8fc-0242ac120002\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n } \n\n ]\n\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Enroll - Multiple Attendees", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendee are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Enrollment date is enriched\", function () {", + " var res = pm.response.json();", + " res.attendees.forEach(attendee => {", + " pm.expect(attendee.enrollmentDate).to.be.not.null;", + " }); ", + " }", + ");", + "", + "let requestData = JSON.parse(pm.request.body.raw);", + "pm.collectionVariables.set(\"individualId-1\", requestData.attendees[0].individualId);", + "pm.collectionVariables.set(\"individualId-2\", requestData.attendees[1].individualId);", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Enroll attendee to register\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{$randomUUID}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{$randomUUID}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n } \n\n ]\n\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Deenroll- Single Attendee", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendees are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Deenrollment date is enriched\", function () {", + " var res = pm.response.json();", + " var deenrollmentDate = res.attendees[0].deenrollmentDate;", + " pm.expect(deenrollmentDate).to.be.not.null;", + " }", + ");", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"search with from and to values\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Deenroll- Validation Error - Attendee already deenrolled from the register", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendees are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is 400. Attendee already deenrolled from the register\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"search with from and to values\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Deenroll- Validation Error - Duplicate attendee objects in deenrollment request", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendees are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "", + "pm.test(\"Response is 400. Duplicate attendee objects in deenrollment request.\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"search with from and to values\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId-1}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId-1}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Deenroll- Multiple Attendees", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendees are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Deenrollment date is enriched\", function () {", + " var res = pm.response.json();", + " res.attendees.forEach(attendee => {", + " pm.expect(attendee.denrollmentDate).to.be.not.null;", + " }); ", + " }", + ");", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"search with from and to values\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId-1}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId-2}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_delete" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Attendance Log", + "item": [ + { + "name": "Attendance Log - Create - Success", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + " setTimeout( () => {", + "", + " pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var id = res.attendance[0].id;", + " pm.expect(id).to.be.not.null;", + " }", + ");", + " ", + " }, 1000);", + "", + "", + "", + "let responseData = pm.response.json();", + "pm.collectionVariables.set(\"attendanceLogId\", responseData.attendance[0].id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Update - Success", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Attendance Log updated successfully\", function () {", + " var res = pm.response.json();", + " var status = res.attendance[0].status;", + " pm.expect(status).to.eql(\"INACTIVE\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"id\": \"{{attendanceLogId}}\",\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"INACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ],\r\n \"auditDetails\": {\r\n \"createdBy\": \"47b5ea82-249c-4435-9646-16167fec06df\",\r\n \"lastModifiedBy\": \"47b5ea82-249c-4435-9646-16167fec06df\",\r\n \"createdTime\": 1671090269007,\r\n \"lastModifiedTime\": 1671090269007\r\n }\r\n \r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Update - fail - attendanceId is not valid", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log updated successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"ATTENDANCE_LOG\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"id\": \"{{$randomUUID}}\",\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"INACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ],\r\n \"auditDetails\": {\r\n \"createdBy\": \"47b5ea82-249c-4435-9646-16167fec06df\",\r\n \"lastModifiedBy\": \"47b5ea82-249c-4435-9646-16167fec06df\",\r\n \"createdTime\": 1671090269007,\r\n \"lastModifiedTime\": 1671090269007\r\n }\r\n \r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Create - Fail - All logs should belong to same tenantId", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"MULTIPLE_TENANTIDS\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n },\r\n {\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"tenant.id\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Create - Fail - Validate Attendance Log time", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"INVALID_ATTENDANCE_TIME\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{invalidRegisterEndDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Create - Fail - Register should belongs to tenenatId", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"INVALID_TENANTID\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"tenant.Id\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Create - Fail - All logs should belong to same registerId", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"MULTIPLE_REGISTERIDS\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n },\r\n {\r\n \"registerId\": \"{{$randomUUID}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Create - Fail - User is not authorised", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"UNAUTHORISED_USER\");", + " }", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": \"{{$randomUUID}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Rearch - Fail - TenantId is required", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"TENANT_ID\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n }\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_search", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_search" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Rearch - Fail - RegisterId is required", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"REGISTER_ID\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n }\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_search?tenantId={{tenantId}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Rearch - Success", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " pm.expect(res.attendance).to.be.not.null;", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n }\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_search?tenantId={{tenantId}}®isterId={{registerId}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + }, + { + "key": "registerId", + "value": "{{registerId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Create - Fail - required fields are missing", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Register Search response is received\", function () {", + " var res = pm.response.json();", + " pm.expect(res.Errors.length).to.equal(5);", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": null,\r\n \"individualId\": null,\r\n \"time\": null,\r\n \"type\": null,\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": null,\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "if (pm.environment.get(\"base_url\").includes(\"localhost\")) {", + "", + " var tenantId = \"pb.amritsar\";", + " var id = 1;", + " var uuid = \"11b0e02b-0145-4de2-bc42-c97b96264807\";", + "", + " var roles = [{", + " \"code\": \"SUPERUSER\",", + " \"name\": \"SUPER USER\",", + " \"tenantId\": tenantId", + " }];", + "", + " var userInfo = {", + " \"id\": id,", + " \"uuid\": uuid,", + " \"userName\": \"\",", + " \"name\": \"\",", + " \"mobileNumber\": \"\",", + " \"emailId\": \"\",", + " \"type\": \"\",", + " \"roles\": roles,", + " \"active\": true,", + " \"tenantId\": \"pb.amritsar\"", + " };", + "", + " pm.request.body.raw = pm.request.body.raw.replace('\"{{token}}\"', '\"\", \\n \"userInfo\": ' + JSON.stringify(userInfo));", + "}" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "tenantId", + "value": "" + }, + { + "key": "stateLevelTenant", + "value": "" + }, + { + "key": "registerId", + "value": "" + }, + { + "key": "registerNumber", + "value": "" + }, + { + "key": "registerId2", + "value": "" + }, + { + "key": "registerStartDate", + "value": "" + }, + { + "key": "registerEndDate", + "value": "" + }, + { + "key": "invalidRegisterEndDate", + "value": "" + }, + { + "key": "userId", + "value": "" + }, + { + "key": "userId-1", + "value": "" + }, + { + "key": "userId-2", + "value": "" + }, + { + "key": "individualId", + "value": "" + }, + { + "key": "attendeeEnrollmentDate", + "value": "" + }, + { + "key": "individualId-1", + "value": "" + }, + { + "key": "individualId-2", + "value": "" + }, + { + "key": "attendanceLogId", + "value": "" + } + ] +} \ No newline at end of file diff --git a/core-services/attendance/src/main/java/org/egov/Main.java b/core-services/attendance/src/main/java/org/egov/Main.java new file mode 100644 index 00000000000..efe5addd85e --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/Main.java @@ -0,0 +1,15 @@ +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/core-services/attendance/src/main/java/org/egov/config/AttendanceServiceConfiguration.java b/core-services/attendance/src/main/java/org/egov/config/AttendanceServiceConfiguration.java new file mode 100644 index 00000000000..ede3010f452 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/config/AttendanceServiceConfiguration.java @@ -0,0 +1,107 @@ +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 AttendanceServiceConfiguration { + + @Value("${app.timezone}") + private String timeZone; + //Idgen Config + @Value("${egov.idgen.host}") + private String idGenHost; + @Value("${egov.idgen.path}") + private String idGenPath; + @Value("${egov.idgen.attendance.register.number.name}") + private String idgenAttendanceRegisterNumberName; + //MDMS + @Value("${egov.mdms.host}") + private String mdmsHost; + @Value("${egov.mdms.search.endpoint}") + private String mdmsEndPoint; + //Topic + @Value("${attendance.register.kafka.create.topic}") + private String saveAttendanceRegisterTopic; + @Value("${attendance.register.kafka.update.topic}") + private String updateAttendanceRegisterTopic; + + //Topic + @Value("${attendance.staff.kafka.create.topic}") + private String saveStaffTopic; + @Value("${attendance.staff.kafka.update.topic}") + private String updateStaffTopic; + + //Topic + @Value("${attendance.attendee.kafka.create.topic}") + private String saveAttendeeTopic; + @Value("${attendance.attendee.kafka.update.topic}") + private String updateAttendeeTopic; + + @PostConstruct + public void initialize() { + TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); + } + + // kafka topics + @Value("${attendance.log.kafka.create.topic}") + private String createAttendanceLogTopic; + + @Value("${attendance.log.kafka.update.topic}") + private String updateAttendanceLogTopic; + + // service integration config + @Value("${attendance.individual.service.integration.required}") + private String individualServiceIntegrationRequired; + + @Value("${attendance.staff.service.integration.required}") + private String staffServiceIntegrationRequired; + + @Value("${attendance.document.id.verification.required}") + private String documentIdVerificationRequired; + + //attendance service log search config + + //@Value("${attendance.service.log.default.offset}") + //private Integer attendanceLogDefaultOffset; + + //@Value("${attendance.service.log.default.limit}") + //private Integer attendanceLogDefaultLimit; + + //@Value("${attendance.service.log.search.max.limit}") + //private Integer attendanceLogMaxLimit; + + //attendance service register search config + @Value("${attendance.register.default.offset}") + private Integer attendanceRegisterDefaultOffset; + + @Value("${attendance.register.default.limit}") + private Integer attendanceRegisterDefaultLimit; + + @Value("${attendance.register.search.max.limit}") + private Integer attendanceRegisterMaxLimit; + + @Value("${attendance.register.open.search.enabled.roles}") + private String registerOpenSearchEnabledRoles; + + //Individual servcie + @Value("${works.individual.host}") + private String individualHost; + @Value("${works.individual.search.endpoint}") + private String individualSearchEndpoint; + +} + + diff --git a/core-services/attendance/src/main/java/org/egov/config/MainConfiguration.java b/core-services/attendance/src/main/java/org/egov/config/MainConfiguration.java new file mode 100644 index 00000000000..e4d1cb86e3e --- /dev/null +++ b/core-services/attendance/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/core-services/attendance/src/main/java/org/egov/enrichment/AttendanceLogEnrichment.java b/core-services/attendance/src/main/java/org/egov/enrichment/AttendanceLogEnrichment.java new file mode 100644 index 00000000000..64f9e785ce4 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/enrichment/AttendanceLogEnrichment.java @@ -0,0 +1,76 @@ +package org.egov.enrichment; + +import digit.models.coremodels.AuditDetails; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.config.AttendanceServiceConfiguration; +import org.egov.util.AttendanceServiceUtil; +import org.egov.web.models.AttendanceLog; +import org.egov.web.models.AttendanceLogRequest; +import org.egov.web.models.AttendanceLogSearchCriteria; +import org.egov.web.models.Document; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.UUID; + +@Component +@Slf4j +public class AttendanceLogEnrichment { + @Autowired + private AttendanceServiceUtil attendanceServiceUtil; + @Autowired + private AttendanceServiceConfiguration config; + + public void enrichAttendanceLogCreateRequest(AttendanceLogRequest attendanceLogRequest) { + String registerId = attendanceLogRequest.getAttendance().get(0).getRegisterId(); + log.info("Enriching attendance log create request for register ["+registerId+"]"); + List attendanceLogs = attendanceLogRequest.getAttendance(); + String byUser = attendanceLogRequest.getRequestInfo().getUserInfo().getUuid(); + AuditDetails auditDetails = attendanceServiceUtil.getAuditDetails(byUser, null, true); + for (AttendanceLog attendanceLog : attendanceLogs) { + attendanceLog.setAuditDetails(auditDetails); + String attendanceLogId = String.valueOf(UUID.randomUUID()); + attendanceLog.setId(attendanceLogId); + List documentIds = attendanceLog.getDocumentIds(); + for (Document documentId : documentIds) { + documentId.setId(String.valueOf(UUID.randomUUID())); + } + } + log.info("Enriched attendance log create request for register ["+registerId+"]"); + } + + public void enrichAttendanceLogUpdateRequest(AttendanceLogRequest attendanceLogRequest) { + String registerId = attendanceLogRequest.getAttendance().get(0).getRegisterId(); + log.info("Enriching attendance log update request for register ["+registerId+"]"); + List attendanceLogs = attendanceLogRequest.getAttendance(); + String byUser = attendanceLogRequest.getRequestInfo().getUserInfo().getUuid(); + for (AttendanceLog attendanceLog : attendanceLogs) { + AuditDetails auditDetails = attendanceServiceUtil.getAuditDetails(byUser, attendanceLog.getAuditDetails(), false); + attendanceLog.setAuditDetails(auditDetails); + // enrich the documentId if not present + List documentIds = attendanceLog.getDocumentIds(); + for (Document documentId : documentIds) { + if (documentId.getId() == null) { + documentId.setId(String.valueOf(UUID.randomUUID())); + } + } + } + + log.info("Enriched attendance log update request for register ["+registerId+"]"); + } + + public void enrichAttendanceLogSearchRequest(RequestInfo requestInfo, AttendanceLogSearchCriteria searchCriteria) { + +// if (searchCriteria.getLimit() == null) +// searchCriteria.setLimit(config.getAttendanceLogDefaultLimit()); +// +// if (searchCriteria.getOffset() == null) +// searchCriteria.setOffset(config.getAttendanceLogDefaultOffset()); +// +// if (searchCriteria.getLimit() != null && searchCriteria.getLimit() > config.getAttendanceLogMaxLimit()) +// searchCriteria.setLimit(config.getAttendanceLogMaxLimit()); + + } +} diff --git a/core-services/attendance/src/main/java/org/egov/enrichment/AttendeeEnrichmentService.java b/core-services/attendance/src/main/java/org/egov/enrichment/AttendeeEnrichmentService.java new file mode 100644 index 00000000000..6a7547020ab --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/enrichment/AttendeeEnrichmentService.java @@ -0,0 +1,65 @@ +package org.egov.enrichment; + +import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.request.RequestInfo; +import org.egov.util.AttendanceServiceUtil; +import org.egov.web.models.AttendeeCreateRequest; +import org.egov.web.models.AttendeeDeleteRequest; +import org.egov.web.models.IndividualEntry; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.List; +import java.util.UUID; + +@Service +public class AttendeeEnrichmentService { + + @Autowired + private AttendanceServiceUtil attendanceServiceUtil; + + public void enrichAttendeeOnCreate(AttendeeCreateRequest attendeeCreateRequest) { + RequestInfo requestInfo = attendeeCreateRequest.getRequestInfo(); + List attendeeListFromRequest = attendeeCreateRequest.getAttendees(); + + for (IndividualEntry attendee : attendeeListFromRequest) { + AuditDetails auditDetails = attendanceServiceUtil.getAuditDetails(requestInfo.getUserInfo().getUuid(), attendee.getAuditDetails(), true); + attendee.setAuditDetails(auditDetails); + attendee.setId(UUID.randomUUID().toString()); + attendee.setDenrollmentDate(null); + if (attendee.getEnrollmentDate() == null) { + BigDecimal enrollmentDate = new BigDecimal(System.currentTimeMillis()); + attendee.setEnrollmentDate(enrollmentDate); + } + + } + } + + public void enrichAttendeeOnDelete(AttendeeDeleteRequest attendeeDeleteRequest, List attendeesFromDB) { + RequestInfo requestInfo = attendeeDeleteRequest.getRequestInfo(); + List attendeesListFromRequest = attendeeDeleteRequest.getAttendees(); + + for (IndividualEntry attendee : attendeesListFromRequest) { + for (IndividualEntry attendeeFromDB : attendeesFromDB) { + if (attendeeFromDB.getIndividualId().equals(attendee.getIndividualId()) + && attendeeFromDB.getRegisterId().equals(attendee.getRegisterId())) { + + attendee.setId(attendeeFromDB.getId()); + attendee.setEnrollmentDate(attendeeFromDB.getEnrollmentDate()); + + AuditDetails auditDetails = attendanceServiceUtil.getAuditDetails(requestInfo.getUserInfo().getUuid(), attendeeFromDB.getAuditDetails(), false); + attendee.setAuditDetails(auditDetails); + + + if (attendee.getDenrollmentDate() == null) { + BigDecimal deEnrollmentDate = new BigDecimal(System.currentTimeMillis()); + attendee.setDenrollmentDate(deEnrollmentDate); + } + } + } + } + + + } +} diff --git a/core-services/attendance/src/main/java/org/egov/enrichment/RegisterEnrichment.java b/core-services/attendance/src/main/java/org/egov/enrichment/RegisterEnrichment.java new file mode 100644 index 00000000000..c34e694998c --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/enrichment/RegisterEnrichment.java @@ -0,0 +1,157 @@ +package org.egov.enrichment; + +import digit.models.coremodels.AuditDetails; +import digit.models.coremodels.IdResponse; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.individual.Individual; +import org.egov.common.utils.MultiStateInstanceUtil; +import org.egov.config.AttendanceServiceConfiguration; +import org.egov.repository.IdGenRepository; +import org.egov.tracer.model.CustomException; +import org.egov.util.AttendanceServiceUtil; +import org.egov.util.IndividualServiceUtil; +import org.egov.web.models.AttendanceRegister; +import org.egov.web.models.AttendanceRegisterRequest; +import org.egov.web.models.AttendanceRegisterSearchCriteria; +import org.egov.web.models.StaffPermission; +import org.egov.web.models.StaffPermissionRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.math.BigDecimal; +import java.util.Collections; +import java.util.List; +import java.util.UUID; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class RegisterEnrichment { + + @Autowired + private AttendanceServiceUtil attendanceServiceUtil; + @Autowired + private IdGenRepository idGenRepository; + @Autowired + private AttendanceServiceConfiguration config; + @Autowired + private IndividualServiceUtil individualServiceUtil; + @Autowired + private MultiStateInstanceUtil multiStateInstanceUtil; + + /* Enrich Attendance Register on Create Request */ + public void enrichRegisterOnCreate(AttendanceRegisterRequest attendanceRegisterRequest) { + RequestInfo requestInfo = attendanceRegisterRequest.getRequestInfo(); + List attendanceRegisters = attendanceRegisterRequest.getAttendanceRegister(); + + String rootTenantId = attendanceRegisters.get(0).getTenantId().split("\\.")[0]; + + //Get Register Numbers from IdGen Service for number of registers present in AttendanceRegisters + List registerNumbers = getIdList(requestInfo, rootTenantId + , config.getIdgenAttendanceRegisterNumberName(), "", attendanceRegisters.size()); //idFormat will be fetched by idGen service + + for (int i = 0; i < attendanceRegisters.size(); i++) { + + if (registerNumbers != null && !registerNumbers.isEmpty()) { + attendanceRegisters.get(i).setRegisterNumber(registerNumbers.get(i)); + log.info("Register number " + registerNumbers.get(i) + " assigned to register " + attendanceRegisters.get(i)); + } else { + log.error("Error occurred while generating attendance register numbers from IdGen service"); + throw new CustomException("ATTENDANCE_REGISTER_NUMBER_NOT_GENERATED","Error occurred while generating attendance register numbers from IdGen service"); + } + + //Enrich attendance register id and audit details + attendanceRegisters.get(i).setId(UUID.randomUUID().toString()); + log.info("Attendance register assigned with register Id " + attendanceRegisters.get(i).getId()); + AuditDetails auditDetails = attendanceServiceUtil.getAuditDetails(requestInfo.getUserInfo().getUuid(), null, true); + attendanceRegisters.get(i).setAuditDetails(auditDetails); + log.info("Enriched register " + attendanceRegisters.get(i).getId() + " with Audit details"); + // User who creates the register, by default gets enrolled as the first staff for that register. + enrichRegisterFirstStaff(attendanceRegisters.get(i), requestInfo, auditDetails); + } + } + + /* Enrich first staff details while creating register*/ + private void enrichRegisterFirstStaff(AttendanceRegister attendanceRegister, RequestInfo requestInfo, AuditDetails auditDetails) { + String tenantId = attendanceRegister.getTenantId(); + Long userid = requestInfo.getUserInfo().getId(); + List individualList = individualServiceUtil.getIndividualDetailsFromUserId(userid, requestInfo, multiStateInstanceUtil.getStateLevelTenant(tenantId)); + String individualId = individualList.get(0).getId(); + + StaffPermission staffPermission = StaffPermission.builder() + .id(UUID.randomUUID().toString()) + .tenantId(attendanceRegister.getTenantId()) + .registerId(attendanceRegister.getId()) + .userId(individualId) + .enrollmentDate(new BigDecimal(System.currentTimeMillis())) + .auditDetails(auditDetails) + .build(); + attendanceRegister.setStaff(Collections.singletonList(staffPermission)); + log.info("First staff for attendance register is added in attendance register"); + log.info("The user " + requestInfo.getUserInfo().getUuid() + " is addedd as staff for the attendance register + " + staffPermission.getRegisterId()); + } + + /* Enrich Attendance Register on Update Request */ + public void enrichRegisterOnUpdate(AttendanceRegisterRequest attendanceRegisterRequest, List attendanceRegistersListFromDB) { + RequestInfo requestInfo = attendanceRegisterRequest.getRequestInfo(); + List attendanceRegistersListInUpdateReq = attendanceRegisterRequest.getAttendanceRegister(); + + for (AttendanceRegister attendanceRegisterInUpdateReq : attendanceRegistersListInUpdateReq) { + log.info("Enriching register " + attendanceRegisterInUpdateReq.getId()); + String registerId = String.valueOf(attendanceRegisterInUpdateReq.getId()); + AttendanceRegister attendanceRegisterFromDB = attendanceRegistersListFromDB.stream().filter(ar -> registerId.equals(String.valueOf(ar.getId()))).findFirst().orElse(null); + + // Set read only values i.e register number, attendees, staff to the attendance register update request as in attendance register from DB + attendanceRegisterInUpdateReq.setRegisterNumber(attendanceRegisterFromDB.getRegisterNumber()); + attendanceRegisterInUpdateReq.setAttendees(attendanceRegisterFromDB.getAttendees()); + attendanceRegisterInUpdateReq.setStaff(attendanceRegisterFromDB.getStaff()); + log.info("Update attendance register request for register " + attendanceRegisterInUpdateReq.getId() + " enriched with register number, attendees and staff"); + + // Set audit details for register update request + attendanceRegisterInUpdateReq.setAuditDetails(attendanceRegisterFromDB.getAuditDetails()); + AuditDetails auditDetails = attendanceServiceUtil.getAuditDetails(requestInfo.getUserInfo().getUuid(), attendanceRegisterFromDB.getAuditDetails(), false); + attendanceRegisterInUpdateReq.setAuditDetails(auditDetails); + log.info("Update attendance register request for register " + attendanceRegisterInUpdateReq.getId() + " enriched with audit details"); + } + } + + /* Adds staff details to the associated attendance register */ + public void enrichStaffInRegister(List attendanceRegisters, StaffPermissionRequest staffPermissionResponse) { + for (AttendanceRegister attendanceRegister : attendanceRegisters) { + String registerId = String.valueOf(attendanceRegister.getId()); + List staff = staffPermissionResponse.getStaff().stream().filter(st -> registerId.equals(st.getRegisterId())).collect(Collectors.toList()); + attendanceRegister.setStaff(staff); + log.info("Created staff details associated with attendance register " + attendanceRegister.getId() + " in create request"); + } + } + + /* Get id list from IdGen service */ + private List getIdList(RequestInfo requestInfo, String tenantId, String idKey, + String idformat, int count) { + List idResponses = idGenRepository.getId(requestInfo, tenantId, idKey, idformat, count).getIdResponses(); + + if (CollectionUtils.isEmpty(idResponses)) { + log.error("No ids returned from idgen Service"); + throw new CustomException("IDGEN ERROR", "No ids returned from idgen Service"); + } + + return idResponses.stream() + .map(IdResponse::getId).collect(Collectors.toList()); + } + + + public void enrichSearchRegisterRequest(RequestInfo requestInfo, AttendanceRegisterSearchCriteria searchCriteria) { + + if (searchCriteria.getLimit() == null) + searchCriteria.setLimit(config.getAttendanceRegisterDefaultLimit()); + + if (searchCriteria.getOffset() == null) + searchCriteria.setOffset(config.getAttendanceRegisterDefaultOffset()); + + if (searchCriteria.getLimit() != null && searchCriteria.getLimit() > config.getAttendanceRegisterMaxLimit()) + searchCriteria.setLimit(config.getAttendanceRegisterMaxLimit()); + + } +} diff --git a/core-services/attendance/src/main/java/org/egov/enrichment/StaffEnrichmentService.java b/core-services/attendance/src/main/java/org/egov/enrichment/StaffEnrichmentService.java new file mode 100644 index 00000000000..abbb77fbf72 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/enrichment/StaffEnrichmentService.java @@ -0,0 +1,60 @@ +package org.egov.enrichment; + +import digit.models.coremodels.AuditDetails; +import org.egov.common.contract.request.RequestInfo; +import org.egov.util.AttendanceServiceUtil; +import org.egov.web.models.StaffPermission; +import org.egov.web.models.StaffPermissionRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.List; +import java.util.UUID; + +@Service +public class StaffEnrichmentService { + + @Autowired + private AttendanceServiceUtil attendanceServiceUtil; + + public void enrichStaffPermissionOnCreate(StaffPermissionRequest request) { + RequestInfo requestInfo = request.getRequestInfo(); + List staffPermissionListFromRequest = request.getStaff(); + + for (StaffPermission staffPermissionFromRequest : staffPermissionListFromRequest) { + AuditDetails auditDetails = attendanceServiceUtil.getAuditDetails(requestInfo.getUserInfo().getUuid(), staffPermissionFromRequest.getAuditDetails(), true); + staffPermissionFromRequest.setAuditDetails(auditDetails); + staffPermissionFromRequest.setId(UUID.randomUUID().toString()); + BigDecimal enrollmentDate = new BigDecimal(System.currentTimeMillis()); + staffPermissionFromRequest.setEnrollmentDate(enrollmentDate); + } + } + + public void enrichStaffPermissionOnDelete(StaffPermissionRequest request, List staffPermissionListFromDB) { + RequestInfo requestInfo = request.getRequestInfo(); + List staffPermissionListFromRequest = request.getStaff(); + + for (StaffPermission staffPermissionFromRequest : staffPermissionListFromRequest) { + for (StaffPermission staffPermissionFromDB : staffPermissionListFromDB) { + if (staffPermissionFromDB.getUserId().equals(staffPermissionFromRequest.getUserId()) + && staffPermissionFromDB.getRegisterId().equals(staffPermissionFromRequest.getRegisterId()) + && staffPermissionFromDB.getDenrollmentDate() == null) { + staffPermissionFromRequest.setId(staffPermissionFromDB.getId()); + staffPermissionFromRequest.setEnrollmentDate(staffPermissionFromDB.getEnrollmentDate()); + + AuditDetails auditDetails = attendanceServiceUtil.getAuditDetails(requestInfo.getUserInfo().getUuid(), staffPermissionFromDB.getAuditDetails(), false); + + staffPermissionFromRequest.setAuditDetails(auditDetails); + + BigDecimal deenrollmentDate = new BigDecimal(System.currentTimeMillis()); + staffPermissionFromRequest.setDenrollmentDate(deenrollmentDate); + } + } + } + + + } + + +} diff --git a/core-services/attendance/src/main/java/org/egov/kafka/Consumer.java b/core-services/attendance/src/main/java/org/egov/kafka/Consumer.java new file mode 100644 index 00000000000..bd8693b4cdd --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/kafka/Consumer.java @@ -0,0 +1,60 @@ +package org.egov.kafka; + + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.service.AttendanceRegisterService; +import org.egov.service.OrganisationContactDetailsStaffUpdateService; +import org.egov.web.models.Organisation.OrgContactUpdateDiff; +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.math.BigDecimal; + +@Component +@Slf4j +public class Consumer { + + @Autowired + private ObjectMapper objectMapper; + @Autowired + private OrganisationContactDetailsStaffUpdateService organisationContactDetailsStaffUpdateService; + @Autowired + private AttendanceRegisterService attendanceRegisterService; + + @KafkaListener(topics = "${organisation.contact.details.update.topic}") + public void updateAttendanceStaff(String consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic){ + try { + OrgContactUpdateDiff orgContactUpdateDiff = objectMapper.readValue(consumerRecord, OrgContactUpdateDiff.class); + organisationContactDetailsStaffUpdateService.updateStaffPermissionsForContactDetails(orgContactUpdateDiff); + } catch(Exception e){ + log.error("Error updating staff permissions for update in organisation contact details", e); + } + } + + /** + * Update end date for approved time extension request + * @param consumerRecord + * @param topic + */ + @KafkaListener(topics = "${contracts.revision.topic}") + public void updateEndDate(String consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + JsonNode attendanceContractRevisionRequest = objectMapper.readValue(consumerRecord, JsonNode.class); + RequestInfo requestInfo = objectMapper.convertValue(attendanceContractRevisionRequest.get("RequestInfo"), RequestInfo.class); + String tenantId = attendanceContractRevisionRequest.get("tenantId").asText(); + String referenceId = attendanceContractRevisionRequest.get("referenceId").asText(); + BigDecimal endDate = attendanceContractRevisionRequest.get("endDate").decimalValue(); + attendanceRegisterService.updateEndDateForRevisedContract(requestInfo, tenantId, referenceId, endDate); + }catch (Exception e) { + log.error("Error end date for contract"); + } + } + +} diff --git a/core-services/attendance/src/main/java/org/egov/kafka/Producer.java b/core-services/attendance/src/main/java/org/egov/kafka/Producer.java new file mode 100644 index 00000000000..b226368be08 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/kafka/Producer.java @@ -0,0 +1,16 @@ +package org.egov.kafka; + +import org.egov.tracer.kafka.CustomKafkaTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class Producer { + + @Autowired + private CustomKafkaTemplate kafkaTemplate; + + public void push(String topic, Object value) { + kafkaTemplate.send(topic, value); + } +} diff --git a/core-services/attendance/src/main/java/org/egov/repository/AttendanceLogRepository.java b/core-services/attendance/src/main/java/org/egov/repository/AttendanceLogRepository.java new file mode 100644 index 00000000000..13f19c885ea --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/repository/AttendanceLogRepository.java @@ -0,0 +1,36 @@ +package org.egov.repository; + +import lombok.extern.slf4j.Slf4j; +import org.egov.repository.querybuilder.AttendanceLogQueryBuilder; +import org.egov.repository.rowmapper.AttendanceLogRowMapper; +import org.egov.web.models.AttendanceLog; +import org.egov.web.models.AttendanceLogSearchCriteria; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +import java.util.ArrayList; +import java.util.List; + +@Repository +@Slf4j +public class AttendanceLogRepository { + @Autowired + private AttendanceLogRowMapper rowMapper; + + @Autowired + private AttendanceLogQueryBuilder queryBuilder; + + @Autowired + private JdbcTemplate jdbcTemplate; + + public List getAttendanceLogs(AttendanceLogSearchCriteria searchCriteria) { + List preparedStmtList = new ArrayList<>(); + log.info("Fetching Attendance Log list. RegisterId ["+searchCriteria.getRegisterId()+"]"); + String query = queryBuilder.getAttendanceLogSearchQuery(searchCriteria, preparedStmtList); + log.info("Query build successfully. RegisterId ["+searchCriteria.getRegisterId()+"]"); + List attendanceLogList = jdbcTemplate.query(query, rowMapper, preparedStmtList.toArray()); + log.info("Fetched Attendance Log list. RegisterId ["+searchCriteria.getRegisterId()+"]"); + return attendanceLogList; + } +} diff --git a/core-services/attendance/src/main/java/org/egov/repository/AttendeeRepository.java b/core-services/attendance/src/main/java/org/egov/repository/AttendeeRepository.java new file mode 100644 index 00000000000..c9fc386bef0 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/repository/AttendeeRepository.java @@ -0,0 +1,31 @@ +package org.egov.repository; + +import org.egov.repository.querybuilder.AttendeeQueryBuilder; +import org.egov.repository.rowmapper.AttendeeRowMapper; +import org.egov.web.models.AttendeeSearchCriteria; +import org.egov.web.models.IndividualEntry; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +import java.util.ArrayList; +import java.util.List; + +@Repository +public class AttendeeRepository { + @Autowired + private AttendeeRowMapper attendeeRowMapper; + + @Autowired + private AttendeeQueryBuilder queryBuilder; + + @Autowired + private JdbcTemplate jdbcTemplate; + + public List getAttendees(AttendeeSearchCriteria searchCriteria) { + List preparedStmtList = new ArrayList<>(); + String query = queryBuilder.getAttendanceAttendeeSearchQuery(searchCriteria, preparedStmtList); + List attendanceStaffList = jdbcTemplate.query(query, attendeeRowMapper, preparedStmtList.toArray()); + return attendanceStaffList; + } +} diff --git a/core-services/attendance/src/main/java/org/egov/repository/IdGenRepository.java b/core-services/attendance/src/main/java/org/egov/repository/IdGenRepository.java new file mode 100644 index 00000000000..da28aa64584 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/repository/IdGenRepository.java @@ -0,0 +1,59 @@ +package org.egov.repository; + +import digit.models.coremodels.IdGenerationRequest; +import digit.models.coremodels.IdGenerationResponse; +import digit.models.coremodels.IdRequest; +import org.egov.common.contract.request.RequestInfo; +import org.egov.config.AttendanceServiceConfiguration; +import org.egov.tracer.model.CustomException; +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.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Repository +public class IdGenRepository { + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private AttendanceServiceConfiguration config; + + /** + * Call iDgen to generateIds + * + * @param requestInfo The rquestInfo of the request + * @param tenantId The tenantiD of the service request + * @param name Name of the foramt + * @param format Format of the ids + * @param count Total Number of idGen ids required + * @return + */ + public IdGenerationResponse getId(RequestInfo requestInfo, String tenantId, String name, String format, int count) { + + List reqList = new ArrayList<>(); + for (int i = 0; i < count; i++) { + reqList.add(IdRequest.builder().idName(name).format(format).tenantId(tenantId).build()); + } + IdGenerationRequest req = IdGenerationRequest.builder().idRequests(reqList).requestInfo(requestInfo).build(); + IdGenerationResponse response = null; + try { + response = restTemplate.postForObject(config.getIdGenHost() + config.getIdGenPath(), req, IdGenerationResponse.class); + } catch (HttpClientErrorException e) { + throw new ServiceCallException(e.getResponseBodyAsString()); + } catch (Exception e) { + Map map = new HashMap<>(); + map.put(e.getCause().getClass().getName(), e.getMessage()); + throw new CustomException(map); + } + return response; + } + +} diff --git a/core-services/attendance/src/main/java/org/egov/repository/RegisterRepository.java b/core-services/attendance/src/main/java/org/egov/repository/RegisterRepository.java new file mode 100644 index 00000000000..a4de6ea2422 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/repository/RegisterRepository.java @@ -0,0 +1,37 @@ +package org.egov.repository; + +import lombok.extern.slf4j.Slf4j; +import org.egov.repository.querybuilder.RegisterQueryBuilder; +import org.egov.repository.rowmapper.RegisterRowMapper; +import org.egov.web.models.AttendanceRegister; +import org.egov.web.models.AttendanceRegisterSearchCriteria; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +import java.util.ArrayList; +import java.util.List; + +@Repository +@Slf4j +public class RegisterRepository { + + @Autowired + private RegisterRowMapper rowMapper; + + @Autowired + private RegisterQueryBuilder queryBuilder; + + @Autowired + private JdbcTemplate jdbcTemplate; + + public List getRegister(AttendanceRegisterSearchCriteria searchCriteria) { + List preparedStmtList = new ArrayList<>(); + String query = queryBuilder.getAttendanceRegisterSearchQuery(searchCriteria, preparedStmtList); + log.info("Query of get register : " + query); + log.info("preparedStmtList of get register : " + preparedStmtList.toString()); + List attendanceRegisterList = jdbcTemplate.query(query, rowMapper, preparedStmtList.toArray()); + return attendanceRegisterList; + } + +} diff --git a/core-services/attendance/src/main/java/org/egov/repository/ServiceRequestRepository.java b/core-services/attendance/src/main/java/org/egov/repository/ServiceRequestRepository.java new file mode 100644 index 00000000000..a0c82610808 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/repository/ServiceRequestRepository.java @@ -0,0 +1,39 @@ +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 { + + @Autowired + private ObjectMapper mapper; + + @Autowired + private 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 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/core-services/attendance/src/main/java/org/egov/repository/StaffRepository.java b/core-services/attendance/src/main/java/org/egov/repository/StaffRepository.java new file mode 100644 index 00000000000..20d0d433fc7 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/repository/StaffRepository.java @@ -0,0 +1,40 @@ +package org.egov.repository; + +import lombok.extern.slf4j.Slf4j; +import org.egov.repository.querybuilder.StaffQueryBuilder; +import org.egov.repository.rowmapper.StaffRowMapper; +import org.egov.web.models.StaffPermission; +import org.egov.web.models.StaffSearchCriteria; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +import java.util.ArrayList; +import java.util.List; + +@Repository +@Slf4j +public class StaffRepository { + @Autowired + private StaffRowMapper rowMapper; + + @Autowired + private StaffQueryBuilder queryBuilder; + + @Autowired + private JdbcTemplate jdbcTemplate; + + public List getActiveStaff(StaffSearchCriteria searchCriteria) { + List preparedStmtList = new ArrayList<>(); + String query = queryBuilder.getActiveAttendanceStaffSearchQuery(searchCriteria, preparedStmtList); + List attendanceStaffList = jdbcTemplate.query(query, rowMapper, preparedStmtList.toArray()); + return attendanceStaffList; + } + + public List getAllStaff(StaffSearchCriteria searchCriteria) { + List preparedStmtList = new ArrayList<>(); + String query = queryBuilder.getAttendanceStaffSearchQuery(searchCriteria, preparedStmtList); + List attendanceStaffList = jdbcTemplate.query(query, rowMapper, preparedStmtList.toArray()); + return attendanceStaffList; + } +} diff --git a/core-services/attendance/src/main/java/org/egov/repository/querybuilder/AttendanceLogQueryBuilder.java b/core-services/attendance/src/main/java/org/egov/repository/querybuilder/AttendanceLogQueryBuilder.java new file mode 100644 index 00000000000..2a678b23dc6 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/repository/querybuilder/AttendanceLogQueryBuilder.java @@ -0,0 +1,152 @@ +package org.egov.repository.querybuilder; + +import org.apache.commons.lang3.StringUtils; +import org.egov.tracer.model.CustomException; +import org.egov.web.models.AttendanceLogSearchCriteria; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.time.Instant; +import java.util.Collection; +import java.util.List; + +@Component +public class AttendanceLogQueryBuilder { + + private static final String ATTENDANCE_LOG_SELECT_QUERY = " SELECT log.id as logid, " + + "log.individual_id as logIndividualId, " + + "log.tenantId as logTenantId, " + + "log.register_id as logRegisterId, " + + "log.status as logStatus, " + + "log.time as logTime, " + + "log.event_type as logEventType, " + + "log.additionaldetails as logAdditionalDetails, " + + "log.createdby as logCreatedBy, " + + "log.lastmodifiedby as logLastModifiedBy, " + + "log.createdtime as logCreatedTime, " + + "log.lastmodifiedtime as logLastModifiedTime, " + + "doc.id as docId, " + + "doc.filestore_id as docFileStoreId, " + + "doc.document_type as docDocumentType, " + + "doc.attendance_log_id as docAttendanceLogId, " + + "doc.tenantid as docTenantId, " + + "doc.status as docStatus, " + + "doc.additionaldetails as docAdditionalDetails, " + + "doc.createdby as docCreatedBy, " + + "doc.lastmodifiedby as docLastModifiedBy, " + + "doc.createdtime as docCreatedTime, " + + "doc.lastmodifiedtime as docLastModifiedTime " + + "FROM eg_wms_attendance_log AS log " + + "LEFT JOIN " + + "eg_wms_attendance_document AS doc " + + "ON (log.id=doc.attendance_log_id) "; + + + public String getAttendanceLogSearchQuery(AttendanceLogSearchCriteria criteria, List preparedStmtList) { + StringBuilder query = new StringBuilder(ATTENDANCE_LOG_SELECT_QUERY); + + List ids = criteria.getIds(); + if (ids != null && !ids.isEmpty()) { + addClauseIfRequired(query, preparedStmtList); + query.append(" log.id IN (").append(createQuery(ids)).append(")"); + addToPreparedStatement(preparedStmtList, ids); + } + + if (StringUtils.isNotBlank(criteria.getTenantId())) { + addClauseIfRequired(query, preparedStmtList); + query.append(" log.tenantid=? "); + preparedStmtList.add(criteria.getTenantId()); + } + + if (StringUtils.isNotBlank(criteria.getRegisterId())) { + addClauseIfRequired(query, preparedStmtList); + query.append(" log.register_id=? "); + preparedStmtList.add(criteria.getRegisterId()); + } + + if (criteria.getFromTime() != null) { + addClauseIfRequired(query, preparedStmtList); + + //If user does not specify toDate, take today's date as toDate by default. + if (criteria.getToTime() == null) { + criteria.setToTime(BigDecimal.valueOf(Instant.now().toEpochMilli())); + } + + query.append(" log.time BETWEEN ? AND ?"); + preparedStmtList.add(criteria.getFromTime()); + preparedStmtList.add(criteria.getToTime()); + + } else { + //if only toDate is provided as parameter without fromDate parameter, throw an exception. + if (criteria.getToTime() != null) { + throw new CustomException("INVALID_SEARCH_PARAM", "Cannot specify getToTime without a getFromTime"); + } + } + + List individualIds = criteria.getIndividualIds(); + if (individualIds != null && !individualIds.isEmpty()) { + addClauseIfRequired(query, preparedStmtList); + query.append(" log.individual_id IN (").append(createQuery(individualIds)).append(")"); + addToPreparedStatement(preparedStmtList, individualIds); + } + + if (criteria.getStatus() != null) { + addClauseIfRequired(query, preparedStmtList); + query.append(" log.status=? "); + preparedStmtList.add(criteria.getStatus().toString()); + } + + addOrderByClause(query, criteria); + + addLimitAndOffset(query, criteria, preparedStmtList); + + return query.toString(); + } + + private void addOrderByClause(StringBuilder queryBuilder, AttendanceLogSearchCriteria criteria) { + + //default + if (criteria.getSortBy() == null || StringUtils.isEmpty(criteria.getSortBy().name())) { + queryBuilder.append(" ORDER BY log.lastmodifiedtime "); + } + + if (criteria.getSortOrder() == AttendanceLogSearchCriteria.SortOrder.ASC) + queryBuilder.append(" ASC "); + else queryBuilder.append(" DESC "); + } + + private void addLimitAndOffset(StringBuilder queryBuilder, AttendanceLogSearchCriteria criteria, List preparedStmtList) { + queryBuilder.append(" OFFSET ? "); + preparedStmtList.add(criteria.getOffset()); + + queryBuilder.append(" LIMIT ? "); + preparedStmtList.add(criteria.getLimit()); + + } + + private String createQuery(Collection ids) { + StringBuilder builder = new StringBuilder(); + int length = ids.size(); + for (int i = 0; i < length; i++) { + builder.append(" ? "); + if (i != length - 1) builder.append(","); + } + return builder.toString(); + } + + private void addClauseIfRequired(StringBuilder query, List preparedStmtList) { + if (preparedStmtList.isEmpty()) { + query.append(" WHERE "); + } else { + query.append(" AND "); + } + } + + private void addToPreparedStatement(List preparedStmtList, Collection ids) { +// ids.forEach(id -> { +// preparedStmtList.add(id); +// }); + + preparedStmtList.addAll(ids); + } +} diff --git a/core-services/attendance/src/main/java/org/egov/repository/querybuilder/AttendeeQueryBuilder.java b/core-services/attendance/src/main/java/org/egov/repository/querybuilder/AttendeeQueryBuilder.java new file mode 100644 index 00000000000..1e963ef6bad --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/repository/querybuilder/AttendeeQueryBuilder.java @@ -0,0 +1,104 @@ +package org.egov.repository.querybuilder; + +import org.egov.tracer.model.CustomException; +import org.egov.web.models.AttendeeSearchCriteria; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.time.Instant; +import java.util.Collection; +import java.util.List; + +@Component +public class AttendeeQueryBuilder { + + private static final String ATTENDANCE_ATTENDEE_SELECT_QUERY = " SELECT att.id, " + + "att.individual_id, " + + "att.register_id, " + + "att.enrollment_date , " + + "att.deenrollment_date, " + + "att.additionaldetails, " + + "att.createdby, " + + "att.lastmodifiedby, " + + "att.createdtime, " + + "att.lastmodifiedtime, " + + "att.tenantid " + + "FROM eg_wms_attendance_attendee att "; + + public String getAttendanceAttendeeSearchQuery(AttendeeSearchCriteria criteria, List preparedStmtList) { + StringBuilder query = new StringBuilder(ATTENDANCE_ATTENDEE_SELECT_QUERY); + + List ids=criteria.getIds(); + if (ids!=null && !ids.isEmpty()) { + addClauseIfRequired(query, preparedStmtList); + query.append(" att.id IN (").append(createQuery(ids)).append(")"); + addToPreparedStatement(preparedStmtList, ids); + } + + List individualIds=criteria.getIndividualIds(); + if (individualIds!=null && !individualIds.isEmpty()) { + addClauseIfRequired(query, preparedStmtList); + query.append(" att.individual_id IN (").append(createQuery(individualIds)).append(")"); + addToPreparedStatement(preparedStmtList, individualIds); + } + + List registerIds = criteria.getRegisterIds(); + if (registerIds != null && !registerIds.isEmpty()) { + addClauseIfRequired(query, preparedStmtList); + query.append(" att.register_id IN (").append(createQuery(registerIds)).append(")"); + addToPreparedStatement(preparedStmtList, registerIds); + } + + if (criteria.getEnrollmentDate() != null) { + addClauseIfRequired(query, preparedStmtList); + + //If user does not specify toDate, take today's date as toDate by default. + if (criteria.getDenrollmentDate() == null) { + criteria.setDenrollmentDate(BigDecimal.valueOf(Instant.now().toEpochMilli())); + } + + query.append(" att.enrollment_date BETWEEN ? AND ?"); + preparedStmtList.add(criteria.getEnrollmentDate()); + preparedStmtList.add(criteria.getDenrollmentDate()); + + } else { + //if only toDate is provided as parameter without fromDate parameter, throw an exception. + if (criteria.getDenrollmentDate() != null) { + throw new CustomException("INVALID_SEARCH_PARAM", "Cannot specify getEnrollmentDate without a getEnrollmentDate"); + } + } + + addLimitAndOffset(query, criteria, preparedStmtList); + + return query.toString(); + } + private void addLimitAndOffset(StringBuilder query, AttendeeSearchCriteria criteria, List preparedStmtList) { + query.append(" OFFSET ? "); + preparedStmtList.add(criteria.getOffset()); + + query.append(" LIMIT ? "); + preparedStmtList.add(criteria.getLimit()); + + } + + private String createQuery(Collection ids) { + StringBuilder builder = new StringBuilder(); + int length = ids.size(); + for (int i = 0; i < length; i++) { + builder.append(" ? "); + if (i != length - 1) builder.append(","); + } + return builder.toString(); + } + private void addClauseIfRequired(StringBuilder query, List preparedStmtList) { + if (preparedStmtList.isEmpty()) { + query.append(" WHERE "); + } else { + query.append(" AND "); + } + } + + private void addToPreparedStatement(List preparedStmtList, Collection ids) { + preparedStmtList.addAll(ids); + } +} diff --git a/core-services/attendance/src/main/java/org/egov/repository/querybuilder/RegisterQueryBuilder.java b/core-services/attendance/src/main/java/org/egov/repository/querybuilder/RegisterQueryBuilder.java new file mode 100644 index 00000000000..4357df11cd6 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/repository/querybuilder/RegisterQueryBuilder.java @@ -0,0 +1,197 @@ +package org.egov.repository.querybuilder; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.config.AttendanceServiceConfiguration; +import org.egov.tracer.model.CustomException; +import org.egov.web.models.AttendanceRegisterSearchCriteria; +import org.egov.web.models.Status; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.math.BigDecimal; +import java.time.Instant; +import java.util.Collection; +import java.util.List; + +@Component +@Slf4j +public class RegisterQueryBuilder { + + @Autowired + private AttendanceServiceConfiguration config; + + private static final String ATTENDANCE_REGISTER_SELECT_QUERY = " SELECT reg.id, " + + "reg.tenantid, " + + "reg.registernumber, " + + "reg.name , " + + "reg.startdate, " + + "reg.enddate, " + + "reg.status, " + + "reg.additionaldetails, " + + "reg.createdby, " + + "reg.lastmodifiedby, " + + "reg.createdtime, " + + "reg.lastmodifiedtime, " + + "reg.referenceid, " + + "reg.servicecode " + + "FROM eg_wms_attendance_register reg "; + + + private final String paginationWrapper = "SELECT * FROM " + + "(SELECT *, DENSE_RANK() OVER (ORDER BY lastmodifiedtime DESC , id) offset_ FROM " + + "({})" + + " result) result_offset " + + "WHERE offset_ > ? AND offset_ <= ?"; + + + public String getAttendanceRegisterSearchQuery(AttendanceRegisterSearchCriteria searchCriteria, List preparedStmtList) { + + log.info("Search criteria of attendance search : " + searchCriteria.toString()); + StringBuilder query = new StringBuilder(ATTENDANCE_REGISTER_SELECT_QUERY); + + if (!ObjectUtils.isEmpty(searchCriteria.getTenantId())) { + addClauseIfRequired(query, preparedStmtList); + query.append(" reg.tenantid like ? "); + preparedStmtList.add(searchCriteria.getTenantId()+"%"); + } + + List registerIds = searchCriteria.getIds(); + if (registerIds != null && !registerIds.isEmpty()) { + addClauseIfRequired(query, preparedStmtList); + query.append(" reg.id IN (").append(createQuery(registerIds)).append(")"); + preparedStmtList.addAll(registerIds); + } + + if (!ObjectUtils.isEmpty(searchCriteria.getRegisterNumber())) { + String registerNumber = searchCriteria.getRegisterNumber(); + addClauseIfRequired(query, preparedStmtList); + query.append(" reg.registernumber = ? "); + preparedStmtList.add(registerNumber); + } + + if (!ObjectUtils.isEmpty(searchCriteria.getReferenceId())) { + String referenceId = searchCriteria.getReferenceId(); + addClauseIfRequired(query, preparedStmtList); + query.append(" reg.referenceid = ? "); + preparedStmtList.add(referenceId); + } + + if (!ObjectUtils.isEmpty(searchCriteria.getServiceCode())) { + String serviceCode = searchCriteria.getServiceCode(); + addClauseIfRequired(query, preparedStmtList); + query.append(" reg.servicecode = ? "); + preparedStmtList.add(serviceCode); + } + + if (!ObjectUtils.isEmpty(searchCriteria.getName())) { + String name = searchCriteria.getName(); + addClauseIfRequired(query, preparedStmtList); + query.append(" reg.name = ? "); + preparedStmtList.add(name); + } + + if (searchCriteria.getFromDate() != null) { + addClauseIfRequired(query, preparedStmtList); + + //If user does not specify toDate, take today's date as toDate by default. + if (searchCriteria.getToDate() == null) { + searchCriteria.setToDate(BigDecimal.valueOf(Instant.now().toEpochMilli())); + } + + query.append(" reg.startdate BETWEEN ? AND ?"); + preparedStmtList.add(searchCriteria.getFromDate()); + preparedStmtList.add(searchCriteria.getToDate()); + + } else { + //if only toDate is provided as parameter without fromDate parameter, throw an exception. + if (searchCriteria.getToDate() != null) { + throw new CustomException("INVALID_SEARCH_PARAM", "Cannot specify toDate without a fromDate"); + } + } + + if (!ObjectUtils.isEmpty(searchCriteria.getStatus())) { + Status status = searchCriteria.getStatus(); + addClauseIfRequired(query, preparedStmtList); + query.append(" reg.status = ? "); + preparedStmtList.add(status.toString()); + } + + addOrderByClause(query, searchCriteria); + //addLimitAndOffset(query, searchCriteria, preparedStmtList); + return addPaginationWrapper(query.toString(), preparedStmtList, searchCriteria); + } + + private String addPaginationWrapper(String query,List preparedStmtList, + AttendanceRegisterSearchCriteria criteria){ + int limit = config.getAttendanceRegisterDefaultLimit(); + int offset = config.getAttendanceRegisterDefaultOffset(); + + String finalQuery = paginationWrapper.replace("{}",query); + + if(criteria.getLimit()!=null && criteria.getLimit()<=config.getAttendanceRegisterMaxLimit()) + limit = criteria.getLimit(); + + if(criteria.getLimit()!=null && criteria.getLimit()>config.getAttendanceRegisterMaxLimit()) + limit = config.getAttendanceRegisterMaxLimit(); + + if(criteria.getOffset()!=null) + offset = criteria.getOffset(); + + preparedStmtList.add(offset); + preparedStmtList.add(limit+offset); + + return finalQuery; + } + + private void addOrderByClause(StringBuilder queryBuilder, AttendanceRegisterSearchCriteria criteria) { + //default + if (criteria.getSortBy() == null || StringUtils.isEmpty(criteria.getSortBy().name())) { + queryBuilder.append(" ORDER BY reg.lastmodifiedtime "); + } else { + switch (AttendanceRegisterSearchCriteria.SortBy.valueOf(criteria.getSortBy().name())) { + case fromDate: + queryBuilder.append(" ORDER BY reg.startdate "); + break; + case toDate: + queryBuilder.append(" ORDER BY reg.enddate "); + break; + default: + queryBuilder.append(" ORDER BY reg.lastmodifiedtime "); + break; + } + } + + if (criteria.getSortOrder() == AttendanceRegisterSearchCriteria.SortOrder.ASC) + queryBuilder.append(" ASC "); + else queryBuilder.append(" DESC "); + } + + private void addLimitAndOffset(StringBuilder queryBuilder, AttendanceRegisterSearchCriteria criteria, List preparedStmtList) { + queryBuilder.append(" OFFSET ? "); + preparedStmtList.add(criteria.getOffset()); + + queryBuilder.append(" LIMIT ? "); + preparedStmtList.add(criteria.getLimit()); + + } + + private String createQuery(Collection ids) { + StringBuilder builder = new StringBuilder(); + int length = ids.size(); + for (int i = 0; i < length; i++) { + builder.append(" ? "); + if (i != length - 1) builder.append(","); + } + return builder.toString(); + } + + private void addClauseIfRequired(StringBuilder query, List preparedStmtList) { + if (preparedStmtList.isEmpty()) { + query.append(" WHERE "); + } else { + query.append(" AND "); + } + } +} diff --git a/core-services/attendance/src/main/java/org/egov/repository/querybuilder/StaffQueryBuilder.java b/core-services/attendance/src/main/java/org/egov/repository/querybuilder/StaffQueryBuilder.java new file mode 100644 index 00000000000..f4aabcecd49 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/repository/querybuilder/StaffQueryBuilder.java @@ -0,0 +1,87 @@ +package org.egov.repository.querybuilder; + +import org.egov.web.models.StaffSearchCriteria; +import org.springframework.stereotype.Component; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +@Component +public class StaffQueryBuilder { + + private static final String ATTENDANCE_STAFF_SELECT_QUERY = " SELECT stf.id, " + + "stf.individual_id, " + + "stf.register_id, " + + "stf.tenantid, " + + "stf.enrollment_date , " + + "stf.deenrollment_date, " + + "stf.additionaldetails, " + + "stf.createdby, " + + "stf.lastmodifiedby, " + + "stf.createdtime, " + + "stf.lastmodifiedtime, " + + "stf.tenantid " + + "FROM eg_wms_attendance_staff stf "; + + public String getActiveAttendanceStaffSearchQuery(StaffSearchCriteria criteria, List preparedStmtList) { + StringBuilder query = new StringBuilder(getAttendanceStaffSearchQuery(criteria, preparedStmtList)); + addClauseIfRequired(query, preparedStmtList); + query.append(" stf.deenrollment_date is null "); + + return query.toString(); + } + + public String getAttendanceStaffSearchQuery(StaffSearchCriteria criteria, List preparedStmtList) { + StringBuilder query = new StringBuilder(ATTENDANCE_STAFF_SELECT_QUERY); + + List staffUserIds = criteria.getIndividualIds(); + if (staffUserIds != null && !staffUserIds.isEmpty()) { + addClauseIfRequired(query, preparedStmtList); + query.append(" stf.individual_id IN (").append(createQuery(staffUserIds)).append(")"); + preparedStmtList.addAll(criteria.getIndividualIds()); + } + + List registerIds = criteria.getRegisterIds(); + if (registerIds != null && !registerIds.isEmpty()) { + addClauseIfRequired(query, preparedStmtList); + query.append(" stf.register_id IN (").append(createQuery(registerIds)).append(")"); + preparedStmtList.addAll(criteria.getRegisterIds()); + } + + String tenantId = criteria.getTenantId(); + if (tenantId != null && !tenantId.isEmpty()) { + addClauseIfRequired(query, preparedStmtList); + query.append(" stf.tenantid IN (").append(createQuery(Collections.singletonList(tenantId))).append(")"); + preparedStmtList.add(criteria.getTenantId()); + } + return query.toString(); + } + private void addClauseIfRequired(StringBuilder query, List preparedStmtList) { + if (preparedStmtList.isEmpty()) { + query.append(" WHERE "); + } else { + query.append(" AND "); + } + } + + private String createQuery(Collection ids) { + StringBuilder builder = new StringBuilder(); + int length = ids.size(); + for (int i = 0; i < length; i++) { + builder.append(" ? "); + if (i != length - 1) builder.append(","); + } + return builder.toString(); + } + + + private void addLimitAndOffset(StringBuilder query, StaffSearchCriteria criteria, List preparedStmtList) { + query.append(" OFFSET ? "); + preparedStmtList.add(criteria.getOffset()); + + query.append(" LIMIT ? "); + preparedStmtList.add(criteria.getLimit()); + + } +} diff --git a/core-services/attendance/src/main/java/org/egov/repository/rowmapper/AttendanceLogRowMapper.java b/core-services/attendance/src/main/java/org/egov/repository/rowmapper/AttendanceLogRowMapper.java new file mode 100644 index 00000000000..c2e506e221a --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/repository/rowmapper/AttendanceLogRowMapper.java @@ -0,0 +1,120 @@ +package org.egov.repository.rowmapper; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.tracer.model.CustomException; +import org.egov.web.models.AttendanceLog; +import org.egov.web.models.Document; +import org.egov.web.models.Status; +import org.postgresql.util.PGobject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +@Component +@Slf4j +public class AttendanceLogRowMapper implements ResultSetExtractor> { + + @Autowired + private ObjectMapper mapper; + + @Override + public List extractData(ResultSet rs) throws SQLException, DataAccessException { + + Map attendanceLogMap = new LinkedHashMap<>(); + + while (rs.next()) { + String id = rs.getString("logid"); + String individualId = rs.getString("logIndividualId"); + String tenantId = rs.getString("logTenantId"); + String registerId = rs.getString("logRegisterId"); + String status = rs.getString("logStatus"); + BigDecimal time = rs.getBigDecimal("logTime"); + String eventType = rs.getString("logEventType"); + String createdby = rs.getString("logCreatedBy"); + String lastmodifiedby = rs.getString("logLastModifiedBy"); + Long createdtime = rs.getLong("logCreatedTime"); + Long lastmodifiedtime = rs.getLong("logLastModifiedTime"); + + AuditDetails auditDetails = AuditDetails.builder().createdBy(createdby).createdTime(createdtime) + .lastModifiedBy(lastmodifiedby).lastModifiedTime(lastmodifiedtime) + .build(); + + JsonNode additionalDetails = getAdditionalDetail("logAdditionalDetails", rs); + + AttendanceLog attendanceLog = AttendanceLog.builder() + .id(id) + .individualId(individualId) + .tenantId(tenantId) + .registerId(registerId) + .status(Status.fromValue(status)) + .time(time) + .type(eventType) + .additionalDetails(additionalDetails) + .auditDetails(auditDetails) + .build(); + + if (!attendanceLogMap.containsKey(id)) { + attendanceLogMap.put(id, attendanceLog); + } + + addDocumentsDetails(rs, attendanceLogMap.get(id)); + } + return new ArrayList<>(attendanceLogMap.values()); + } + + private void addDocumentsDetails(ResultSet rs, AttendanceLog attendanceLog) throws SQLException { + String documentId = rs.getString("docId"); + String attendanceLogId = rs.getString("docAttendanceLogId"); + if (StringUtils.isNotBlank(documentId) && attendanceLogId.equalsIgnoreCase(attendanceLog.getId().toString())) { + Document document = Document.builder() + .id(documentId) + .documentType(rs.getString("docDocumentType")) + .fileStore(rs.getString("docFileStoreId")) + .documentUid(rs.getString("docFileStoreId")) + .status(Status.fromValue(rs.getString("docStatus"))) + .build(); + + JsonNode additionalDetails = getAdditionalDetail("docAdditionalDetails", rs); + document.setAdditionalDetails(additionalDetails); + + if (attendanceLog.getDocumentIds() == null || attendanceLog.getDocumentIds().isEmpty()) { + List documentIdList = new LinkedList<>(); + documentIdList.add(document); + attendanceLog.setDocumentIds(documentIdList); + } else { + attendanceLog.getDocumentIds().add(document); + } + } + } + + private JsonNode getAdditionalDetail(String columnName, ResultSet rs) throws SQLException { + JsonNode additionalDetails = null; + try { + PGobject obj = (PGobject) rs.getObject(columnName); + if (obj != null) { + additionalDetails = mapper.readTree(obj.getValue()); + } + } catch (IOException e) { + log.error("Failed to parse additionalDetail object"); + throw new CustomException("PARSING_ERROR", "Failed to parse additionalDetail object"); + } + if (additionalDetails.isEmpty()) + additionalDetails = null; + return additionalDetails; + } +} diff --git a/core-services/attendance/src/main/java/org/egov/repository/rowmapper/AttendeeRowMapper.java b/core-services/attendance/src/main/java/org/egov/repository/rowmapper/AttendeeRowMapper.java new file mode 100644 index 00000000000..1583ff89e04 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/repository/rowmapper/AttendeeRowMapper.java @@ -0,0 +1,84 @@ +package org.egov.repository.rowmapper; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import org.egov.tracer.model.CustomException; +import org.egov.web.models.IndividualEntry; +import org.postgresql.util.PGobject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +@Component +public class AttendeeRowMapper implements ResultSetExtractor> { + + @Autowired + private ObjectMapper mapper; + + @Override + public List extractData(ResultSet rs) throws SQLException, DataAccessException { + Map attendanceAttendeeMap = new LinkedHashMap<>(); + while (rs.next()) { + String id = rs.getString("id"); + String registerId = rs.getString("register_id"); + String individuaId = rs.getString("individual_id"); + String tenantId= rs.getString("tenantid"); + BigDecimal enrollmentDate = rs.getBigDecimal("enrollment_date"); + BigDecimal deenrollmentDate = rs.getBigDecimal("deenrollment_date"); + String createdby = rs.getString("createdby"); + String lastmodifiedby = rs.getString("lastmodifiedby"); + Long createdtime = rs.getLong("createdtime"); + Long lastmodifiedtime = rs.getLong("lastmodifiedtime"); + + AuditDetails auditDetails = AuditDetails.builder().createdBy(createdby).createdTime(createdtime) + .lastModifiedBy(lastmodifiedby).lastModifiedTime(lastmodifiedtime) + .build(); + + JsonNode additionalDetails = getAdditionalDetail("additionaldetails", rs); + + IndividualEntry attendanceAttendee = IndividualEntry.builder() + .additionalDetails(additionalDetails) + .id(id) + .individualId(individuaId) + .registerId(registerId) + .tenantId(tenantId) + .additionalDetails(additionalDetails) + .enrollmentDate(enrollmentDate) + .denrollmentDate(deenrollmentDate) + .auditDetails(auditDetails) + .build(); + + if (!attendanceAttendeeMap.containsKey(id)) { + attendanceAttendeeMap.put(id, attendanceAttendee); + } + } + return new ArrayList<>(attendanceAttendeeMap.values()); + + } + + private JsonNode getAdditionalDetail(String columnName, ResultSet rs) throws SQLException { + JsonNode additionalDetails = null; + try { + PGobject obj = (PGobject) rs.getObject(columnName); + if (obj != null) { + additionalDetails = mapper.readTree(obj.getValue()); + } + } catch (IOException e) { + throw new CustomException("PARSING ERROR", "Failed to parse additionalDetail object"); + } + if (additionalDetails.isEmpty()) + additionalDetails = null; + return additionalDetails; + } +} diff --git a/core-services/attendance/src/main/java/org/egov/repository/rowmapper/RegisterRowMapper.java b/core-services/attendance/src/main/java/org/egov/repository/rowmapper/RegisterRowMapper.java new file mode 100644 index 00000000000..e6ffb4090aa --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/repository/rowmapper/RegisterRowMapper.java @@ -0,0 +1,92 @@ +package org.egov.repository.rowmapper; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import org.egov.tracer.model.CustomException; +import org.egov.web.models.AttendanceRegister; +import org.egov.web.models.Status; +import org.postgresql.util.PGobject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +@Component +public class RegisterRowMapper implements ResultSetExtractor> { + + @Autowired + private ObjectMapper mapper; + + @Override + public List extractData(ResultSet rs) throws SQLException, DataAccessException { + + Map attendanceRegisterMap = new LinkedHashMap<>(); + + while (rs.next()) { + String id = rs.getString("id"); + String tenantId = rs.getString("tenantid"); + String registerNumber = rs.getString("registernumber"); + String name = rs.getString("name"); + BigDecimal startDate = rs.getBigDecimal("startdate"); + BigDecimal endDate = rs.getBigDecimal("enddate"); + String status = rs.getString("status"); + String createdby = rs.getString("createdby"); + String lastmodifiedby = rs.getString("lastmodifiedby"); + Long createdtime = rs.getLong("createdtime"); + Long lastmodifiedtime = rs.getLong("lastmodifiedtime"); + String referenceId = rs.getString("referenceid"); + String serviceCode = rs.getString("servicecode"); + + AuditDetails auditDetails = AuditDetails.builder().createdBy(createdby).createdTime(createdtime) + .lastModifiedBy(lastmodifiedby).lastModifiedTime(lastmodifiedtime) + .build(); + + JsonNode additionalDetails = getAdditionalDetail("additionaldetails", rs); + + AttendanceRegister attendanceRegister = AttendanceRegister.builder() + .additionalDetails(additionalDetails) + .id(id) + .tenantId(tenantId) + .status(Status.fromValue(status)) + .registerNumber(registerNumber) + .referenceId(referenceId) + .serviceCode(serviceCode) + .name(name) + .startDate(startDate) + .endDate(endDate) + .auditDetails(auditDetails) + .build(); + + if (!attendanceRegisterMap.containsKey(id)) { + attendanceRegisterMap.put(id, attendanceRegister); + } + } + return new ArrayList<>(attendanceRegisterMap.values()); + + } + + private JsonNode getAdditionalDetail(String columnName, ResultSet rs) throws SQLException { + JsonNode additionalDetails = null; + try { + PGobject obj = (PGobject) rs.getObject(columnName); + if (obj != null) { + additionalDetails = mapper.readTree(obj.getValue()); + } + } catch (IOException e) { + throw new CustomException("PARSING ERROR", "Failed to parse additionalDetail object"); + } + if (additionalDetails.isEmpty()) + additionalDetails = null; + return additionalDetails; + } +} diff --git a/core-services/attendance/src/main/java/org/egov/repository/rowmapper/StaffRowMapper.java b/core-services/attendance/src/main/java/org/egov/repository/rowmapper/StaffRowMapper.java new file mode 100644 index 00000000000..60851bc94c4 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/repository/rowmapper/StaffRowMapper.java @@ -0,0 +1,84 @@ +package org.egov.repository.rowmapper; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import org.egov.tracer.model.CustomException; +import org.egov.web.models.StaffPermission; +import org.postgresql.util.PGobject; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.math.BigDecimal; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +@Component +public class StaffRowMapper implements ResultSetExtractor> { + + @Autowired + private ObjectMapper mapper; + + @Override + public List extractData(ResultSet rs) throws SQLException, DataAccessException { + Map attendanceStaffMap = new LinkedHashMap<>(); + while (rs.next()) { + String id = rs.getString("id"); + String tenantId = rs.getString("tenantid"); + String individuaId = rs.getString("individual_id"); + String registerId = rs.getString("register_id"); + BigDecimal enrollmentDate = rs.getBigDecimal("enrollment_date"); + BigDecimal deenrollmentDate = rs.getBigDecimal("deenrollment_date"); + String createdby = rs.getString("createdby"); + String lastmodifiedby = rs.getString("lastmodifiedby"); + Long createdtime = rs.getLong("createdtime"); + Long lastmodifiedtime = rs.getLong("lastmodifiedtime"); + + AuditDetails auditDetails = AuditDetails.builder().createdBy(createdby).createdTime(createdtime) + .lastModifiedBy(lastmodifiedby).lastModifiedTime(lastmodifiedtime) + .build(); + + JsonNode additionalDetails = getAdditionalDetail("additionaldetails", rs); + + StaffPermission attendanceStaff = StaffPermission.builder() + .additionalDetails(additionalDetails) + .id(id) + .tenantId(tenantId) + .userId(individuaId) + .registerId(registerId) + .additionalDetails(additionalDetails) + .enrollmentDate(enrollmentDate) + .denrollmentDate(deenrollmentDate) + .auditDetails(auditDetails) + .build(); + + if (!attendanceStaffMap.containsKey(id)) { + attendanceStaffMap.put(id, attendanceStaff); + } + } + return new ArrayList<>(attendanceStaffMap.values()); + } + + + private JsonNode getAdditionalDetail(String columnName, ResultSet rs) throws SQLException { + JsonNode additionalDetails = null; + try { + PGobject obj = (PGobject) rs.getObject(columnName); + if (obj != null) { + additionalDetails = mapper.readTree(obj.getValue()); + } + } catch (IOException e) { + throw new CustomException("PARSING ERROR", "Failed to parse additionalDetail object"); + } + if (additionalDetails.isEmpty()) + additionalDetails = null; + return additionalDetails; + } +} diff --git a/core-services/attendance/src/main/java/org/egov/service/AttendanceLogService.java b/core-services/attendance/src/main/java/org/egov/service/AttendanceLogService.java new file mode 100644 index 00000000000..ba835a82bba --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/service/AttendanceLogService.java @@ -0,0 +1,105 @@ +package org.egov.service; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.config.AttendanceServiceConfiguration; +import org.egov.enrichment.AttendanceLogEnrichment; +import org.egov.kafka.Producer; +import org.egov.repository.AttendanceLogRepository; +import org.egov.util.ResponseInfoFactory; +import org.egov.validator.AttendanceLogServiceValidator; +import org.egov.web.models.AttendanceLog; +import org.egov.web.models.AttendanceLogRequest; +import org.egov.web.models.AttendanceLogResponse; +import org.egov.web.models.AttendanceLogSearchCriteria; +import org.egov.web.models.RequestInfoWrapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@Slf4j +public class AttendanceLogService { + @Autowired + private AttendanceLogServiceValidator attendanceLogServiceValidator; + + @Autowired + private ResponseInfoFactory responseInfoFactory; + + + @Autowired + private AttendanceLogEnrichment attendanceLogEnricher; + + @Autowired + private Producer producer; + + @Autowired + private AttendanceServiceConfiguration config; + + @Autowired + private AttendanceLogRepository attendanceLogRepository; + + /** + * Create Attendance Log + * + * @param attendanceLogRequest + * @return attendanceLogResponse + */ + public AttendanceLogResponse createAttendanceLog(AttendanceLogRequest attendanceLogRequest) { + //Validate the incoming request + attendanceLogServiceValidator.validateCreateAttendanceLogRequest(attendanceLogRequest); + //Enrich the incoming request + attendanceLogEnricher.enrichAttendanceLogCreateRequest(attendanceLogRequest); + // Push the request object to the topic for persister to listen and persist + producer.push(config.getCreateAttendanceLogTopic(), attendanceLogRequest); + // Create the response + ResponseInfo responseInfo = responseInfoFactory.createResponseInfoFromRequestInfo(attendanceLogRequest.getRequestInfo(), true); + AttendanceLogResponse attendanceLogResponse = AttendanceLogResponse.builder().responseInfo(responseInfo).attendance(attendanceLogRequest.getAttendance()).build(); + String registerId = attendanceLogRequest.getAttendance().get(0).getRegisterId(); + log.info("Attendance logs created successfully for register ["+registerId+"]"); + return attendanceLogResponse; + } + + /** + * Search attendace logs based on given search criteria + * + * @param requestInfoWrapper + * @param searchCriteria + * @return attendanceLogResponse + */ + public AttendanceLogResponse searchAttendanceLog(RequestInfoWrapper requestInfoWrapper, AttendanceLogSearchCriteria searchCriteria) { + //Validate the incoming request + attendanceLogServiceValidator.validateSearchAttendanceLogRequest(requestInfoWrapper, searchCriteria); + //Enrich the incoming request + attendanceLogEnricher.enrichAttendanceLogSearchRequest(requestInfoWrapper.getRequestInfo(), searchCriteria); + //Fetch attendance logs from registry + List attendanceLogs = attendanceLogRepository.getAttendanceLogs(searchCriteria); + // Create the response + ResponseInfo responseInfo = responseInfoFactory.createResponseInfoFromRequestInfo(requestInfoWrapper.getRequestInfo(), true); + AttendanceLogResponse attendanceLogResponse = AttendanceLogResponse.builder().responseInfo(responseInfo).attendance(attendanceLogs).build(); + log.info("Attendance log response created for register ["+searchCriteria.getRegisterId()+"]"); + return attendanceLogResponse; + } + + /** + * Update the given attendance log details + * + * @param attendanceLogRequest + * @return AttendanceLogResponse + */ + public AttendanceLogResponse updateAttendanceLog(AttendanceLogRequest attendanceLogRequest) { + //Validate the incoming request + attendanceLogServiceValidator.validateUpdateAttendanceLogRequest(attendanceLogRequest); + //Enrich the incoming request + attendanceLogEnricher.enrichAttendanceLogUpdateRequest(attendanceLogRequest); + // Push the request object to the topic for persister to listen and persist + producer.push(config.getUpdateAttendanceLogTopic(), attendanceLogRequest); + // Create the response + ResponseInfo responseInfo = responseInfoFactory.createResponseInfoFromRequestInfo(attendanceLogRequest.getRequestInfo(), true); + AttendanceLogResponse attendanceLogResponse = AttendanceLogResponse.builder().responseInfo(responseInfo).attendance(attendanceLogRequest.getAttendance()).build(); + String registerId = attendanceLogRequest.getAttendance().get(0).getRegisterId(); + log.info("Attendance logs updated successfully for register ["+registerId+"]"); + return attendanceLogResponse; + } +} diff --git a/core-services/attendance/src/main/java/org/egov/service/AttendanceRegisterService.java b/core-services/attendance/src/main/java/org/egov/service/AttendanceRegisterService.java new file mode 100644 index 00000000000..37e8fae18ee --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/service/AttendanceRegisterService.java @@ -0,0 +1,377 @@ +package org.egov.service; + +import digit.models.coremodels.RequestInfoWrapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.request.Role; +import org.egov.config.AttendanceServiceConfiguration; +import org.egov.enrichment.RegisterEnrichment; +import org.egov.enrichment.StaffEnrichmentService; +import org.egov.kafka.Producer; +import org.egov.repository.AttendeeRepository; +import org.egov.repository.RegisterRepository; +import org.egov.tracer.model.CustomException; +import org.egov.util.IndividualServiceUtil; +import org.egov.util.ResponseInfoFactory; +import org.egov.validator.AttendanceServiceValidator; +import org.egov.web.models.AttendanceRegister; +import org.egov.web.models.AttendanceRegisterRequest; +import org.egov.web.models.AttendanceRegisterSearchCriteria; +import org.egov.web.models.AttendeeSearchCriteria; +import org.egov.web.models.IndividualEntry; +import org.egov.web.models.StaffPermission; +import org.egov.web.models.StaffSearchCriteria; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@Service +@Slf4j +public class AttendanceRegisterService { + @Autowired + private AttendanceServiceValidator attendanceServiceValidator; + + @Autowired + private ResponseInfoFactory responseInfoFactory; + + @Autowired + private Producer producer; + + @Autowired + private AttendanceServiceConfiguration attendanceServiceConfiguration; + + @Autowired + private RegisterEnrichment registerEnrichment; + + + @Autowired + private StaffService staffService; + + @Autowired + private RegisterRepository registerRepository; + + @Autowired + private AttendeeRepository attendeeRepository; + + @Autowired + private StaffEnrichmentService staffEnrichmentService; + @Autowired + private IndividualServiceUtil individualServiceUtil; + + /** + * Create Attendance register + * + * @param request + * @return + */ + public AttendanceRegisterRequest createAttendanceRegister(AttendanceRegisterRequest request) { + attendanceServiceValidator.validateCreateAttendanceRegister(request); + registerEnrichment.enrichRegisterOnCreate(request); + log.info("Enriched Register with Register number, Ids, first staff and audit details"); + producer.push(attendanceServiceConfiguration.getSaveAttendanceRegisterTopic(), request); + log.info("Pushed create attendance register request to kafka"); + return request; + } + + /** + * Search attendance register based on given search criteria + * + * @param requestInfoWrapper + * @param searchCriteria + * @return + */ + public List searchAttendanceRegister(RequestInfoWrapper requestInfoWrapper, AttendanceRegisterSearchCriteria searchCriteria) { + //Validate the requested parameters + attendanceServiceValidator.validateSearchRegisterRequest(requestInfoWrapper, searchCriteria); + + //Enrich requested search criteria + registerEnrichment.enrichSearchRegisterRequest(requestInfoWrapper.getRequestInfo(),searchCriteria); + + //Get the logged-in user roles + Set userRoles = getUserRoleCodes(requestInfoWrapper.getRequestInfo()); + + //Get the roles enabled for open serach + Set openSearchEnabledRoles = getRegisterOpenSearchEnabledRoles(); + + List resultAttendanceRegisters = new ArrayList<>(); + + if(isUserEnabledForOpenSearch(userRoles,openSearchEnabledRoles)){ + /* + User having the role to perform open search on attendance register. + */ + log.info("Searching registers for Superuser or Engineer"); + fetchAndFilterRegisters(searchCriteria, resultAttendanceRegisters); + }else{ + /* + Make sure response register list should contain only those register for which logged-in is associated. + */ + Long userId = requestInfoWrapper.getRequestInfo().getUserInfo().getId(); + + String individualId = individualServiceUtil.getIndividualDetailsFromUserId(userId,requestInfoWrapper.getRequestInfo(), searchCriteria.getTenantId()).get(0).getId(); + Set registers = fetchRegistersAssociatedToLoggedInStaffUser(individualId); + updateSearchCriteriaAndFetchAndFilterRegisters(registers, searchCriteria, resultAttendanceRegisters); + } + return resultAttendanceRegisters; + } + + private boolean isUserEnabledForOpenSearch(Set userRoles, Set openSearchEnabledRoles) { + for(String userRole : userRoles){ + if(openSearchEnabledRoles.contains(userRole)){ + return true; + } + } + return false; + } + + private Set getRegisterOpenSearchEnabledRoles() { + Set openSearchEnabledRoles = new HashSet<>(); + String registerOpenSearchEnabledRoles = attendanceServiceConfiguration.getRegisterOpenSearchEnabledRoles(); + if(!StringUtils.isBlank(registerOpenSearchEnabledRoles)){ + String[] roles = registerOpenSearchEnabledRoles.split(","); + for(String role :roles){ + if(!StringUtils.isBlank(role)){ + openSearchEnabledRoles.add(role); + } + } + } + return openSearchEnabledRoles; + } + + /** + * Update the search criteria with list of registerIds if it does not contain registerId + * then fetch the all registers based on the search criteria + * but keep only those registers at last which contains attendees or staff in given search criteria + * + * @param registers + * @param searchCriteria + * @param resultAttendanceRegisters + */ + public void updateSearchCriteriaAndFetchAndFilterRegisters(Set registers, AttendanceRegisterSearchCriteria searchCriteria, List resultAttendanceRegisters) { + + if (registers == null || registers.isEmpty()) { + log.info("Registers are empty or null"); + return; + } + if (searchCriteria.getIds() == null) { + log.info("Register search criteria does not contain any register ids"); + List registerIds = new ArrayList<>(); + registerIds.addAll(registers); + searchCriteria.setIds(registerIds); + } else { + log.info("Register search criteria does contains register ids"); + for (String id : searchCriteria.getIds()) { + if (!registers.contains(id)) { + log.error( "User can search only associated registers"); + throw new CustomException("INVALID_REGISTER_ID", "User can search only associated registers"); + } + } + } + fetchAndFilterRegisters(searchCriteria, resultAttendanceRegisters); + } + + /** + * Fetch the all registers based on the supplied search criteria + * but keep only those registers which contains attendees or staff given in search criteria + * + * @param searchCriteria + * @param resultAttendanceRegisters + */ + private void fetchAndFilterRegisters(AttendanceRegisterSearchCriteria searchCriteria, List resultAttendanceRegisters) { + log.info("Fetching registers based on supplied search criteria"); + // Fetch the all registers based on the supplied search criteria + List attendanceRegisters = registerRepository.getRegister(searchCriteria); + // Create a map with key as registerId and corresponding register list as value + Map> registerIdVsAttendanceRegisters = attendanceRegisters.stream().collect(Collectors.groupingBy(AttendanceRegister::getId)); + + List registerIdsToSearch = new ArrayList<>(); + registerIdsToSearch.addAll(registerIdVsAttendanceRegisters.keySet()); + + // Fetch and filer staff members based on the supplied search criteria. + log.info("Fetch all staff members based on the supplied search criteria"); + List staffMembers = fetchAllStaffMembersAssociatedToRegisterIds(registerIdsToSearch,searchCriteria); + // Create a map with key as registerId and corresponding staff list as value + Map> registerIdStaffMapping = staffMembers.stream().collect(Collectors.groupingBy(StaffPermission::getRegisterId)); + + // If staffId present in search criteria then update the registerIDToSearch list with new set of registerIds + if (searchCriteria.getStaffId() != null){ + registerIdsToSearch.clear(); + registerIdsToSearch.addAll(registerIdStaffMapping.keySet()); + } + + // Fetch and filer attendees based on the supplied search criteria. + List attendees = fetchAllAttendeesAssociatedToRegisterIds(registerIdsToSearch,searchCriteria); + // Create a map with key as registerId and corresponding attendee list as value + Map> registerIdAttendeeMapping = attendees.stream().collect(Collectors.groupingBy(IndividualEntry::getRegisterId)); + + // If AttendeeId present in search criteria then update the registerIDToSearch list with new set of registerIds + if(searchCriteria.getAttendeeId() != null){ + List registerIdsAssociatedToAttendees = new ArrayList<>(); + registerIdsAssociatedToAttendees.addAll(registerIdAttendeeMapping.keySet()); + registerIdsToSearch.clear(); + registerIdsToSearch.addAll(registerIdsAssociatedToAttendees); + } + + // Populate final list of registers to be return + for(String registerId : registerIdsToSearch ){ + List registers = registerIdVsAttendanceRegisters.get(registerId); + for(AttendanceRegister register : registers){ + register.setStaff(registerIdStaffMapping.get(registerId)); + register.setAttendees(registerIdAttendeeMapping.get(registerId)); + resultAttendanceRegisters.add(register); + } + } + } + + private List fetchAllAttendeesAssociatedToRegisterIds(List registerIdsToSearch, AttendanceRegisterSearchCriteria searchCriteria) { + AttendeeSearchCriteria attendeeSearchCriteria = null; + if(searchCriteria.getAttendeeId() != null){ + attendeeSearchCriteria = AttendeeSearchCriteria.builder().registerIds(registerIdsToSearch).individualIds(Collections.singletonList(searchCriteria.getAttendeeId())).build(); + } else { + attendeeSearchCriteria = AttendeeSearchCriteria.builder().registerIds(registerIdsToSearch).build(); + } + return attendeeRepository.getAttendees(attendeeSearchCriteria); + } + + /* Get all staff members associated for the register */ + private List fetchAllStaffMembersAssociatedToRegisterIds(List registerIdsToSearch, AttendanceRegisterSearchCriteria searchCriteria) { + StaffSearchCriteria staffSearchCriteria = null ; + if(searchCriteria.getStaffId() != null){ + staffSearchCriteria = StaffSearchCriteria.builder().registerIds(registerIdsToSearch).individualIds(Collections.singletonList(searchCriteria.getStaffId())).build(); + } else { + staffSearchCriteria = StaffSearchCriteria.builder().registerIds(registerIdsToSearch).build(); + } + return staffService.getAllStaff(staffSearchCriteria); + } + + /* Returns list of user roles */ + private Set getUserRoleCodes(RequestInfo requestInfo) { + Set userRoles = new HashSet<>(); + List roles = requestInfo.getUserInfo().getRoles(); + if(roles == null) + return userRoles; + return roles.stream().map(e->e.getCode()).collect(Collectors.toSet()); + } + + /* Get all registers associated for the logged in staff */ + private Set fetchRegistersAssociatedToLoggedInStaffUser(String uuid) { + List individualIds = new ArrayList<>(); + individualIds.add(uuid); + StaffSearchCriteria staffSearchCriteria = StaffSearchCriteria.builder().individualIds(individualIds).build(); + List staffMembers = staffService.getAllStaff(staffSearchCriteria); + return staffMembers.stream().map(e -> e.getRegisterId()).collect(Collectors.toSet()); + } + + /* Get all registers associated for the logged in attendee */ + private Set fetchRegistersAssociatedToLoggedInAttendeeUser(String uuid) { + AttendeeSearchCriteria attendeeSearchCriteria = AttendeeSearchCriteria.builder().individualIds(Collections.singletonList(uuid)).build(); + List attendees = attendeeRepository.getAttendees(attendeeSearchCriteria); + return attendees.stream().map(e -> e.getRegisterId()).collect(Collectors.toSet()); + } + + /** + * Update the given attendance register details + * + * @param attendanceRegisterRequest + * @return + */ + public AttendanceRegisterRequest updateAttendanceRegister(AttendanceRegisterRequest attendanceRegisterRequest) { + attendanceServiceValidator.validateUpdateAttendanceRegisterRequest(attendanceRegisterRequest); + log.info("Validated update attendance register request"); + + //Create requestInfoWrapper from attendanceRegister request, collect ids in list for search attendance register request parameters + RequestInfoWrapper requestInfoWrapper = RequestInfoWrapper.builder().requestInfo(attendanceRegisterRequest.getRequestInfo()).build(); + List registerIds = getAttendanceRegisterIdList(attendanceRegisterRequest); + String tenantId = attendanceRegisterRequest.getAttendanceRegister().get(0).getTenantId(); + //Get Attendance registers from DB based on register ids, tenantId and requestInfo + List attendanceRegistersFromDB = getAttendanceRegisters(requestInfoWrapper, registerIds, tenantId); + log.info("Fetched attendance registers for update request"); + + //Validate Update attendance register request against attendance registers fetched from database + attendanceServiceValidator.validateUpdateAgainstDB(attendanceRegisterRequest, attendanceRegistersFromDB); + + registerEnrichment.enrichRegisterOnUpdate(attendanceRegisterRequest, attendanceRegistersFromDB); + log.info("Enriched with register Number, Ids and AuditDetails"); + producer.push(attendanceServiceConfiguration.getUpdateAttendanceRegisterTopic(), attendanceRegisterRequest); + log.info("Pushed update attendance register request to kafka"); + + return attendanceRegisterRequest; + } + + public List getAttendanceRegisters(RequestInfoWrapper requestInfoWrapper, List registerIds, String tenantId) { + + //Search criteria for attendance register search request + AttendanceRegisterSearchCriteria searchCriteria = AttendanceRegisterSearchCriteria.builder().ids(registerIds) + .tenantId(tenantId).build(); + List attendanceRegisterList; + + // Calls search attendance register with created request. If some error in searching attendance register, throws error + try { + attendanceRegisterList = searchAttendanceRegister(requestInfoWrapper, searchCriteria); + log.info("Attendance register search successful"); + } catch (Exception e) { + log.info("Error in searching attendance register", e); + throw new CustomException("SEARCH_ATTENDANCE_REGISTER", "Error in searching attendance register"); + } + + return attendanceRegisterList; + } + + /* Get attendance registers Id list from attendance register request */ + private List getAttendanceRegisterIdList(AttendanceRegisterRequest request) { + List attendanceRegisters = request.getAttendanceRegister(); + + List registerIds = new ArrayList<>(); + for (AttendanceRegister attendanceRegister : attendanceRegisters) { + registerIds.add(String.valueOf(attendanceRegister.getId())); + } + return registerIds; + } + + /** + * Validate and update the end date of Attendance register as per revised contract + * @param requestInfo + * @param tenantId + * @param referenceId + * @param endDate + */ + public void updateEndDateForRevisedContract(RequestInfo requestInfo, String tenantId, String referenceId, BigDecimal endDate) { + AttendanceRegisterSearchCriteria attendanceRegisterSearchCriteria = AttendanceRegisterSearchCriteria.builder() + .tenantId(tenantId) + .referenceId(referenceId) + .limit(attendanceServiceConfiguration.getAttendanceRegisterDefaultLimit()) + .offset(attendanceServiceConfiguration.getAttendanceRegisterDefaultOffset()).build(); + + + List attendanceRegisters = registerRepository.getRegister(attendanceRegisterSearchCriteria); + + if (attendanceRegisters != null && !attendanceRegisters.isEmpty()) { + for (AttendanceRegister attendanceRegister : attendanceRegisters) { + int comparisonResult = endDate.compareTo(attendanceRegister.getEndDate()); + if (comparisonResult < 0) { + throw new CustomException("END_DATE_NOT_EXTENDED","End date should not be earlier than previous end date"); + } + + attendanceRegister.setEndDate(endDate); + AttendanceRegisterRequest attendanceRegisterRequest = AttendanceRegisterRequest.builder() + .attendanceRegister(Collections.singletonList(attendanceRegister)). + requestInfo(requestInfo).build(); + + registerEnrichment.enrichRegisterOnUpdate(attendanceRegisterRequest, Collections.singletonList(attendanceRegister)); + producer.push(attendanceServiceConfiguration.getUpdateAttendanceRegisterTopic(), attendanceRegisterRequest); + } + }else { + throw new CustomException("ATTENDANCE_REGISTER_NOT_FOUND", "Attendance registers not found for the referenceId"); + } + + } + +} diff --git a/core-services/attendance/src/main/java/org/egov/service/AttendeeService.java b/core-services/attendance/src/main/java/org/egov/service/AttendeeService.java new file mode 100644 index 00000000000..268109ad38e --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/service/AttendeeService.java @@ -0,0 +1,195 @@ +package org.egov.service; + +import digit.models.coremodels.RequestInfoWrapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.config.AttendanceServiceConfiguration; +import org.egov.enrichment.AttendeeEnrichmentService; +import org.egov.kafka.Producer; +import org.egov.repository.AttendeeRepository; +import org.egov.util.ResponseInfoFactory; +import org.egov.validator.AttendanceServiceValidator; +import org.egov.validator.AttendeeServiceValidator; +import org.egov.web.models.AttendanceRegister; +import org.egov.web.models.AttendeeCreateRequest; +import org.egov.web.models.AttendeeDeleteRequest; +import org.egov.web.models.AttendeeSearchCriteria; +import org.egov.web.models.IndividualEntry; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Service +@Slf4j +public class AttendeeService { + @Autowired + private AttendeeServiceValidator attendeeServiceValidator; + + @Autowired + private ResponseInfoFactory responseInfoFactory; + + @Autowired + private AttendeeRepository attendeeRepository; + + @Autowired + private AttendanceRegisterService attendanceRegisterService; + + @Autowired + private AttendanceServiceValidator attendanceServiceValidator; + + @Autowired + private AttendeeEnrichmentService attendeeEnrichmentService; + + @Autowired + private AttendanceServiceConfiguration attendanceServiceConfiguration; + + @Autowired + private Producer producer; + + + /** + * Create Attendee + * + * @param attendeeCreateRequest + * @return + */ + public AttendeeCreateRequest createAttendee(AttendeeCreateRequest attendeeCreateRequest) { + //incoming createRequest validation + log.info("validating create attendee request parameters"); + attendeeServiceValidator.validateAttendeeCreateRequestParameters(attendeeCreateRequest); + + //extract registerIds and attendee IndividualIds from client request + String tenantId = attendeeCreateRequest.getAttendees().get(0).getTenantId(); + List attendeeIds = extractAttendeeIdsFromCreateRequest(attendeeCreateRequest); + List registerIds = extractRegisterIdsFromCreateRequest(attendeeCreateRequest); + + //db call to get the attendeeList data + List attendeeListFromDB = getAttendees(registerIds,attendeeIds); + + //db call to get registers from db + List attendanceRegisterListFromDB = getAttendanceRegisters(attendeeCreateRequest,registerIds,tenantId); + + //validate registers from request with registers from DB + log.info("validating register ids from request against DB"); + attendanceServiceValidator.validateRegisterAgainstDB(registerIds, attendanceRegisterListFromDB, tenantId); + + + //validator call by passing attendee request and the data from db call + log.info("attendeeServiceValidator called to validate Create attendee request"); + attendeeServiceValidator.validateAttendeeOnCreate(attendeeCreateRequest, attendeeListFromDB, attendanceRegisterListFromDB); + + //enrichment call by passing attendee request and data from db call + log.info("attendeeServiceValidator called to enrich Create attendee request"); + attendeeEnrichmentService.enrichAttendeeOnCreate(attendeeCreateRequest); + + //push to producer + log.info("attendee objects pushed via producer"); + producer.push(attendanceServiceConfiguration.getSaveAttendeeTopic(), attendeeCreateRequest); + log.info("attendees present in Create attendee request are enrolled to the registers"); + return attendeeCreateRequest; + } + + public List getAttendees(List registerIds,List attendeeIds){ + AttendeeSearchCriteria attendeeSearchCriteria = AttendeeSearchCriteria.builder().registerIds(registerIds).individualIds(attendeeIds).build(); + List attendeeListFromDB = attendeeRepository.getAttendees(attendeeSearchCriteria); + log.info("attendee List received From DB : " + attendeeListFromDB.size()); + return attendeeListFromDB; + } + + public List getAttendanceRegisters(AttendeeCreateRequest attendeeCreateRequest,List registerIds,String tenantId){ + RequestInfoWrapper requestInfoWrapper = RequestInfoWrapper.builder().requestInfo(attendeeCreateRequest.getRequestInfo()).build(); + List attendanceRegisterListFromDB = attendanceRegisterService.getAttendanceRegisters(requestInfoWrapper, registerIds, tenantId); + log.info("attendance register List received From DB : " + attendanceRegisterListFromDB.size()); + return attendanceRegisterListFromDB; + } + + public List getAttendanceRegisters(AttendeeDeleteRequest attendeeDeleteRequest,List registerIds,String tenantId){ + RequestInfoWrapper requestInfoWrapper = RequestInfoWrapper.builder().requestInfo(attendeeDeleteRequest.getRequestInfo()).build(); + List attendanceRegisterListFromDB = attendanceRegisterService.getAttendanceRegisters(requestInfoWrapper, registerIds, tenantId); + log.info("attendance register List received From DB : " + attendanceRegisterListFromDB.size()); + return attendanceRegisterListFromDB; + } + + /** + * Update(Soft Delete) the given attendee + * + * @param + * @return + */ + public AttendeeDeleteRequest deleteAttendee(AttendeeDeleteRequest attendeeDeleteRequest) { + //incoming deleteRequest validation + log.info("validating delete attendee request parameters"); + Map errorMap = new HashMap<>(); + attendeeServiceValidator.validateAttendeeDeleteRequestParameters(attendeeDeleteRequest, errorMap); + + //extract registerIds and attendee IndividualIds from client request + String tenantId = attendeeDeleteRequest.getAttendees().get(0).getTenantId(); + List attendeeIds = extractAttendeeIdsFromDeleteRequest(attendeeDeleteRequest); + List registerIds = extractRegisterIdsFromDeleteRequest(attendeeDeleteRequest); + + //db call to get the attendeeList data + List attendeeListFromDB = getAttendees(registerIds,attendeeIds); + + //db call to get registers from db + List attendanceRegisterListFromDB = getAttendanceRegisters(attendeeDeleteRequest,registerIds,tenantId); + + //validate request registers with registers from DB + log.info("validating register ids from request against DB"); + attendanceServiceValidator.validateRegisterAgainstDB(registerIds, attendanceRegisterListFromDB, tenantId); + + + //validator call by passing attendee request and the data from db call + log.info("validating delete attendee request"); + attendeeServiceValidator.validateAttendeeOnDelete(attendeeDeleteRequest, attendeeListFromDB, attendanceRegisterListFromDB); + + //enrichment call by passing attendee request and data from db call + log.info("enriching delete attendee request"); + attendeeEnrichmentService.enrichAttendeeOnDelete(attendeeDeleteRequest, attendeeListFromDB); + + //push to producer + log.info("attendee objects updated via producer"); + producer.push(attendanceServiceConfiguration.getUpdateAttendeeTopic(), attendeeDeleteRequest); + log.info("attendees present in delete attendee request are deenrolled from the registers"); + return attendeeDeleteRequest; + } + + + private List extractRegisterIdsFromCreateRequest(AttendeeCreateRequest attendeeCreateRequest) { + List attendeeListFromRequest = attendeeCreateRequest.getAttendees(); + List registerIds = new ArrayList<>(); + for (IndividualEntry attendee : attendeeListFromRequest) { + registerIds.add(attendee.getRegisterId()); + } + return registerIds; + } + + private List extractAttendeeIdsFromCreateRequest(AttendeeCreateRequest attendeeCreateRequest) { + List attendeeListFromRequest = attendeeCreateRequest.getAttendees(); + List attendeeIds = new ArrayList<>(); + for (IndividualEntry attendee : attendeeListFromRequest) { + attendeeIds.add(attendee.getIndividualId()); + } + return attendeeIds; + } + + private List extractRegisterIdsFromDeleteRequest(AttendeeDeleteRequest attendeeDeleteRequest) { + List attendeeListFromRequest = attendeeDeleteRequest.getAttendees(); + List registerIds = new ArrayList<>(); + for (IndividualEntry attendee : attendeeListFromRequest) { + registerIds.add(attendee.getRegisterId()); + } + return registerIds; + } + + private List extractAttendeeIdsFromDeleteRequest(AttendeeDeleteRequest attendeeDeleteRequest) { + List attendeeListFromRequest = attendeeDeleteRequest.getAttendees(); + List attendeeIds = new ArrayList<>(); + for (IndividualEntry attendee : attendeeListFromRequest) { + attendeeIds.add(attendee.getIndividualId()); + } + return attendeeIds; + } +} diff --git a/core-services/attendance/src/main/java/org/egov/service/OrganisationContactDetailsStaffUpdateService.java b/core-services/attendance/src/main/java/org/egov/service/OrganisationContactDetailsStaffUpdateService.java new file mode 100644 index 00000000000..0fb18e46985 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/service/OrganisationContactDetailsStaffUpdateService.java @@ -0,0 +1,98 @@ +package org.egov.service; + +import digit.models.coremodels.RequestInfoWrapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.config.AttendanceServiceConfiguration; +import org.egov.util.IndividualServiceUtil; +import org.egov.web.models.AttendanceRegister; +import org.egov.web.models.AttendanceRegisterSearchCriteria; +import org.egov.web.models.Organisation.ContactDetails; +import org.egov.web.models.Organisation.OrgContactUpdateDiff; +import org.egov.web.models.StaffPermission; +import org.egov.web.models.StaffPermissionRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@Slf4j +@Service +public class OrganisationContactDetailsStaffUpdateService { + + @Autowired + private AttendanceRegisterService attendanceRegisterService; + @Autowired + private StaffService staffService; + @Autowired + private IndividualServiceUtil individualServiceUtil; + + @Autowired + private AttendanceServiceConfiguration configuration; + + public void updateStaffPermissionsForContactDetails(OrgContactUpdateDiff orgContactUpdateDiff) { + RequestInfoWrapper requestInfoWrapper = RequestInfoWrapper.builder().requestInfo(orgContactUpdateDiff.getRequestInfo()).build(); + String tenantId = orgContactUpdateDiff.getTenantId(); + List oldContacts = orgContactUpdateDiff.getOldContacts(); + + for(ContactDetails oldContact : oldContacts) { + AttendanceRegisterSearchCriteria attendanceRegisterSearchCriteria = + AttendanceRegisterSearchCriteria.builder().tenantId(tenantId).staffId(oldContact.getIndividualId()).limit(configuration.getAttendanceRegisterMaxLimit()).build(); + List attendanceRegisterList = attendanceRegisterService.searchAttendanceRegister(requestInfoWrapper, attendanceRegisterSearchCriteria); + if(CollectionUtils.isEmpty(attendanceRegisterList)) { + try { + String userUuid = individualServiceUtil.getIndividualDetails(Collections.singletonList(oldContact.getIndividualId()), requestInfoWrapper.getRequestInfo(), tenantId).get(0).getUserUuid(); + attendanceRegisterSearchCriteria = AttendanceRegisterSearchCriteria.builder().tenantId(tenantId).staffId(userUuid).limit(configuration.getAttendanceRegisterMaxLimit()).build(); + attendanceRegisterList = attendanceRegisterService.searchAttendanceRegister(requestInfoWrapper, attendanceRegisterSearchCriteria); + }catch (Exception e){ + log.error(e.toString()); + } + } + List newContacts = orgContactUpdateDiff.getNewContacts(); + grantPermission(attendanceRegisterList, newContacts, orgContactUpdateDiff.getRequestInfo()); + revokePermission(attendanceRegisterList, oldContact.getIndividualId(), orgContactUpdateDiff.getRequestInfo()); + } + } + + private void revokePermission(List attendanceRegisters, String individualOrUserId, RequestInfo requestInfo) { + if(attendanceRegisters.isEmpty()) { + log.info("No attendance registers to revoke permissions on"); + return; + } + List staffPermissionList = new ArrayList<>(); + for(AttendanceRegister attendanceRegister : attendanceRegisters) { + String tenantId = attendanceRegister.getTenantId(); + StaffPermission staffPermission = StaffPermission.builder() + .tenantId(tenantId).registerId(attendanceRegister.getId()).userId(individualOrUserId).build(); + staffPermissionList.add(staffPermission); + } + StaffPermissionRequest staffPermissionRequest = StaffPermissionRequest.builder() + .requestInfo(requestInfo).staff(staffPermissionList).build(); + staffService.deleteAttendanceStaff(staffPermissionRequest); + log.info("Revoked permission for: " + individualOrUserId + " on " + attendanceRegisters.size() + " registers."); + } + + private void grantPermission(List attendanceRegisters, List newContacts, RequestInfo requestInfo) { + if(attendanceRegisters.isEmpty()) { + log.info("No attendance registers to grant permission on"); + return; + } + List staffPermissionList = new ArrayList<>(); + for(AttendanceRegister attendanceRegister : attendanceRegisters) { + String tenantId = attendanceRegister.getTenantId(); + for(ContactDetails newContact : newContacts) { + StaffPermission staffPermission = StaffPermission.builder().tenantId(tenantId) + .registerId(attendanceRegister.getId()).userId(newContact.getIndividualId()).build(); + staffPermissionList.add(staffPermission); + } + } + StaffPermissionRequest staffPermissionRequest = StaffPermissionRequest.builder() + .requestInfo(requestInfo).staff(staffPermissionList).build(); + staffService.createAttendanceStaff(staffPermissionRequest, true); + log.info("Granted permission on " + attendanceRegisters.size() + " registers for " + newContacts.size() + " new contacts."); + } + +} diff --git a/core-services/attendance/src/main/java/org/egov/service/StaffService.java b/core-services/attendance/src/main/java/org/egov/service/StaffService.java new file mode 100644 index 00000000000..a20bc3898c7 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/service/StaffService.java @@ -0,0 +1,179 @@ +package org.egov.service; + +import digit.models.coremodels.RequestInfoWrapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.config.AttendanceServiceConfiguration; +import org.egov.enrichment.StaffEnrichmentService; +import org.egov.kafka.Producer; +import org.egov.repository.RegisterRepository; +import org.egov.repository.StaffRepository; +import org.egov.util.ResponseInfoFactory; +import org.egov.validator.AttendanceServiceValidator; +import org.egov.validator.StaffServiceValidator; +import org.egov.web.models.AttendanceRegister; +import org.egov.web.models.StaffPermission; +import org.egov.web.models.StaffPermissionRequest; +import org.egov.web.models.StaffSearchCriteria; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +@Slf4j +public class StaffService { + @Autowired + private StaffServiceValidator staffServiceValidator; + + @Autowired + private ResponseInfoFactory responseInfoFactory; + + @Autowired + private StaffEnrichmentService staffEnrichmentService; + + @Autowired + private StaffRepository staffRepository; + + @Autowired + private RegisterRepository registerRepository; + + + @Autowired + private Producer producer; + + @Autowired + private AttendanceServiceConfiguration serviceConfiguration; + + @Autowired + private AttendanceRegisterService attendanceRegisterService; + + @Autowired + private AttendanceServiceValidator attendanceServiceValidator; + + + /** + * Create attendance staff + * + * @param staffPermissionRequest + * @return + */ + public StaffPermissionRequest createAttendanceStaff(StaffPermissionRequest staffPermissionRequest, Boolean cboMigrationReq) { + //incoming createRequest validation + log.info("Validating incoming staff request"); + staffServiceValidator.validateStaffPermissionRequestParameters(staffPermissionRequest); + + //extract registerIds and staffUserIds from client request + String tenantId = staffPermissionRequest.getStaff().get(0).getTenantId(); + List staffIds = extractStaffIdsFromRequest(staffPermissionRequest); + List registerIds = extractRegisterIdsFromRequest(staffPermissionRequest); + + //db call to get the staffList data whose de enrollment date is null + List staffPermissionListFromDB = getActiveStaff(registerIds, staffIds, tenantId); + + //db call to get registers from db + List attendanceRegisterListFromDB = getRegistersFromDB(staffPermissionRequest, registerIds, tenantId); + + //validate request registers with DB registers + attendanceServiceValidator.validateRegisterAgainstDB(registerIds, attendanceRegisterListFromDB, tenantId); + + //validator call by passing staff request and the data from db call + log.info("staffServiceValidator called to validate Create StaffPermission request"); + // When changing the CBO skip this validation + if (!cboMigrationReq) { + staffServiceValidator.validateStaffPermissionOnCreate(staffPermissionRequest, staffPermissionListFromDB, attendanceRegisterListFromDB); + } + + //enrichment call by passing staff request and data from db call + log.info("staffEnrichmentService called to enrich Create StaffPermission request"); + staffEnrichmentService.enrichStaffPermissionOnCreate(staffPermissionRequest); + + //push to producer + log.info("staff objects pushed via producer"); + producer.push(serviceConfiguration.getSaveStaffTopic(), staffPermissionRequest); + log.info("staff present in Create StaffPermission request are enrolled to the register"); + return staffPermissionRequest; + } + + public List getActiveStaff(List registerIds, List staffIds, String tenantId) { + StaffSearchCriteria staffSearchCriteria = StaffSearchCriteria.builder().registerIds(registerIds).individualIds(staffIds).tenantId(tenantId).build(); + List staffPermissionListFromDB = staffRepository.getActiveStaff(staffSearchCriteria); + log.info("size of active staffPermission List received From DB :" + staffPermissionListFromDB.size()); + return staffPermissionListFromDB; + } + + public List getRegistersFromDB(StaffPermissionRequest staffPermissionRequest, List registerIds, String tenantId) { + RequestInfoWrapper requestInfoWrapper = RequestInfoWrapper.builder().requestInfo(staffPermissionRequest.getRequestInfo()).build(); + List attendanceRegisterListFromDB = attendanceRegisterService.getAttendanceRegisters(requestInfoWrapper, registerIds, tenantId); + log.info("size of Attendance Registers list received from DB : " + attendanceRegisterListFromDB.size()); + return attendanceRegisterListFromDB; + } + + /** + * Update(Soft Delete) the given attendance staff + * + * @param staffPermissionRequest + * @return + */ + public StaffPermissionRequest deleteAttendanceStaff(StaffPermissionRequest staffPermissionRequest) { + //incoming deleteRequest validation + log.info("Validating incoming staff request"); + staffServiceValidator.validateStaffPermissionRequestParameters(staffPermissionRequest); + + //extract registerIds and staffUserIds from client request + String tenantId = staffPermissionRequest.getStaff().get(0).getTenantId(); + List staffIds = extractStaffIdsFromRequest(staffPermissionRequest); + List registerIds = extractRegisterIdsFromRequest(staffPermissionRequest); + + //db call to get registers from db + List attendanceRegisterListFromDB = getRegistersFromDB(staffPermissionRequest, registerIds, tenantId); + + + //validate request registers against registers from DB + log.info("Validating register ids from request against the DB"); + attendanceServiceValidator.validateRegisterAgainstDB(registerIds, attendanceRegisterListFromDB, tenantId); + + + // db call to get staff data + StaffSearchCriteria staffSearchCriteria = StaffSearchCriteria.builder().registerIds(registerIds).tenantId(tenantId).build(); + List staffPermissionListFromDB = getAllStaff(staffSearchCriteria); + + + //validator call by passing staff request and the data from db call + log.info("staffServiceValidator called to validate Delete StaffPermission request"); + staffServiceValidator.validateStaffPermissionOnDelete(staffPermissionRequest, staffPermissionListFromDB, attendanceRegisterListFromDB); + + log.info("staffEnrichmentService called to enrich Delete StaffPermission request"); + staffEnrichmentService.enrichStaffPermissionOnDelete(staffPermissionRequest, staffPermissionListFromDB); + + log.info("staff objects pushed via producer"); + producer.push(serviceConfiguration.getUpdateStaffTopic(), staffPermissionRequest); + log.info("staff present in Delete StaffPermission request are deenrolled from the register"); + return staffPermissionRequest; + } + + public List getAllStaff(StaffSearchCriteria staffSearchCriteria) { + List staffPermissionListFromDB = staffRepository.getAllStaff(staffSearchCriteria); + log.info("size of staffPermission list received from DB : " + staffPermissionListFromDB.size()); + return staffPermissionListFromDB; + } + + private List extractRegisterIdsFromRequest(StaffPermissionRequest staffPermissionRequest) { + List staffPermissionListFromRequest = staffPermissionRequest.getStaff(); + List registerIds = new ArrayList<>(); + for (StaffPermission staffPermission : staffPermissionListFromRequest) { + registerIds.add(staffPermission.getRegisterId()); + } + return registerIds; + } + + private List extractStaffIdsFromRequest(StaffPermissionRequest staffPermissionRequest) { + List staffPermissionListFromRequest = staffPermissionRequest.getStaff(); + List staffIds = new ArrayList<>(); + for (StaffPermission staffPermission : staffPermissionListFromRequest) { + staffIds.add(staffPermission.getUserId()); + } + return staffIds; + } + +} diff --git a/core-services/attendance/src/main/java/org/egov/util/AttendanceServiceConstants.java b/core-services/attendance/src/main/java/org/egov/util/AttendanceServiceConstants.java new file mode 100644 index 00000000000..702bc4ba0be --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/util/AttendanceServiceConstants.java @@ -0,0 +1,6 @@ +package org.egov.util; + +public class AttendanceServiceConstants { + public static final String MASTER_TENANTS = "tenants"; + public static final String MDMS_TENANT_MODULE_NAME = "tenant"; +} diff --git a/core-services/attendance/src/main/java/org/egov/util/AttendanceServiceUtil.java b/core-services/attendance/src/main/java/org/egov/util/AttendanceServiceUtil.java new file mode 100644 index 00000000000..daf344e8ac0 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/util/AttendanceServiceUtil.java @@ -0,0 +1,16 @@ +package org.egov.util; + +import digit.models.coremodels.AuditDetails; +import org.springframework.stereotype.Component; + +@Component +public class AttendanceServiceUtil { + public AuditDetails getAuditDetails(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/core-services/attendance/src/main/java/org/egov/util/IndividualServiceUtil.java b/core-services/attendance/src/main/java/org/egov/util/IndividualServiceUtil.java new file mode 100644 index 00000000000..89c521de0f6 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/util/IndividualServiceUtil.java @@ -0,0 +1,113 @@ +package org.egov.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.individual.Individual; +import org.egov.common.models.individual.IndividualBulkResponse; +import org.egov.common.models.individual.IndividualSearch; +import org.egov.common.models.individual.IndividualSearchRequest; +import org.egov.common.utils.MultiStateInstanceUtil; +import org.egov.config.AttendanceServiceConfiguration; +import org.egov.repository.ServiceRequestRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.HttpServerErrorException; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.List; +import java.util.stream.Collectors; + +@Component +@Slf4j +public class IndividualServiceUtil { + + @Autowired + private ServiceRequestRepository serviceRequestRepository; + + @Autowired + private AttendanceServiceConfiguration config; + + @Autowired + private ObjectMapper mapper; + + @Autowired + private RestTemplate restTemplate; + @Autowired + private MultiStateInstanceUtil multiStateInstanceUtil; + + public List fetchIndividualIds(List individualIds, RequestInfo requestInfo, String tenantId) { + + List individualList = getIndividualDetails(individualIds, requestInfo, tenantId); + + List ids = null; + try { + ids = individualList.stream().map(Individual::getId).collect(Collectors.toList()); + } catch (Exception e) { + throw new CustomException("PARSING_ERROR", "Failed to parse Individual service response"); + } + log.info("Individual search fetched successfully"); + return ids; + } + + public List getIndividualDetails(List individualIds, RequestInfo requestInfo, String tenantId) { + + String uri = getSearchURLWithParams(tenantId).toUriString(); + + IndividualSearch individualSearch = IndividualSearch.builder().id(individualIds).build(); + IndividualSearchRequest individualSearchRequest = IndividualSearchRequest.builder() + .requestInfo(requestInfo).individual(individualSearch).build(); + + IndividualBulkResponse response = null; + log.info("call individual search with tenantId::" + tenantId + "::individual ids::" + individualIds); + + try { + response = restTemplate.postForObject(uri, individualSearchRequest, IndividualBulkResponse.class); + } catch (HttpClientErrorException | HttpServerErrorException httpClientOrServerExc) { + log.error("Error thrown from individual search service::" + httpClientOrServerExc.getStatusCode()); + throw new CustomException("INDIVIDUAL_SEARCH_SERVICE_EXCEPTION", "Error thrown from individual search service::" + httpClientOrServerExc.getStatusCode()); + } + if (response == null || CollectionUtils.isEmpty(response.getIndividual())) { + throw new CustomException("INDIVIDUAL_SEARCH_RESPONSE_IS_EMPTY", "Individuals not found"); + } + + return response.getIndividual(); + } + + private UriComponentsBuilder getSearchURLWithParams(String tenantId) { + StringBuilder uri = new StringBuilder(); + uri.append(config.getIndividualHost()).append(config.getIndividualSearchEndpoint()); + UriComponentsBuilder uriBuilder = UriComponentsBuilder.fromHttpUrl(uri.toString()) + .queryParam("limit", 100) + .queryParam("offset", 0) + .queryParam("tenantId", tenantId); + + return uriBuilder; + } + + public List getIndividualDetailsFromUserId(Long userId, RequestInfo requestInfo, String tenantId) { + String uri = getSearchURLWithParams(multiStateInstanceUtil.getStateLevelTenant(tenantId)).toUriString(); + IndividualSearch individualSearch = IndividualSearch.builder().userId(userId).build(); + IndividualSearchRequest individualSearchRequest = IndividualSearchRequest.builder() + .requestInfo(requestInfo).individual(individualSearch).build(); + + IndividualBulkResponse response = null; + log.info("call individual search with tenantId::" + tenantId + "::user id::" + userId); + + try { + response = restTemplate.postForObject(uri, individualSearchRequest, IndividualBulkResponse.class); + } catch (HttpClientErrorException | HttpServerErrorException httpClientOrServerExc) { + log.error("Error thrown from individual search service::" + httpClientOrServerExc.getStatusCode()); + throw new CustomException("INDIVIDUAL_SEARCH_SERVICE_EXCEPTION", "Error thrown from individual search service::" + httpClientOrServerExc.getStatusCode()); + } + if (response == null || CollectionUtils.isEmpty(response.getIndividual())) { + throw new CustomException("INDIVIDUAL_SEARCH_RESPONSE_IS_EMPTY", "Individuals not found"); + } + + return response.getIndividual(); + } +} diff --git a/core-services/attendance/src/main/java/org/egov/util/MDMSUtils.java b/core-services/attendance/src/main/java/org/egov/util/MDMSUtils.java new file mode 100644 index 00000000000..d8a48ac95b4 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/util/MDMSUtils.java @@ -0,0 +1,72 @@ +package org.egov.util; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.config.AttendanceServiceConfiguration; +import org.egov.mdms.model.MasterDetail; +import org.egov.mdms.model.MdmsCriteria; +import org.egov.mdms.model.MdmsCriteriaReq; +import org.egov.mdms.model.ModuleDetail; +import org.egov.repository.ServiceRequestRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; + +import static org.egov.util.AttendanceServiceConstants.MASTER_TENANTS; +import static org.egov.util.AttendanceServiceConstants.MDMS_TENANT_MODULE_NAME; + +@Component +@Slf4j +public class MDMSUtils { + + @Autowired + private ServiceRequestRepository serviceRequestRepository; + + @Autowired + private AttendanceServiceConfiguration config; + + public static final String filterCode = "$.*.code"; + + public Object mDMSCall(RequestInfo requestInfo, String tenantId) { + MdmsCriteriaReq mdmsCriteriaReq = getMDMSRequest(requestInfo, tenantId); + Object result = serviceRequestRepository.fetchResult(getMdmsSearchUrl(), mdmsCriteriaReq); + return result; + } + + public MdmsCriteriaReq getMDMSRequest(RequestInfo requestInfo, String tenantId) { + + ModuleDetail tenantModuleDetail = getTenantModuleRequestData(); + + List moduleDetails = new LinkedList<>(); + moduleDetails.add(tenantModuleDetail); + + MdmsCriteria mdmsCriteria = MdmsCriteria.builder().moduleDetails(moduleDetails).tenantId(tenantId) + .build(); + + MdmsCriteriaReq mdmsCriteriaReq = MdmsCriteriaReq.builder().mdmsCriteria(mdmsCriteria) + .requestInfo(requestInfo).build(); + return mdmsCriteriaReq; + } + + public StringBuilder getMdmsSearchUrl() { + return new StringBuilder().append(config.getMdmsHost()).append(config.getMdmsEndPoint()); + } + + private ModuleDetail getTenantModuleRequestData() { + List tenantMasterDetails = new ArrayList<>(); + + MasterDetail tenantMasterDetail = MasterDetail.builder().name(MASTER_TENANTS) + .filter(filterCode).build(); + + tenantMasterDetails.add(tenantMasterDetail); + + ModuleDetail tenantModuleDetail = ModuleDetail.builder().masterDetails(tenantMasterDetails) + .moduleName(MDMS_TENANT_MODULE_NAME).build(); + + return tenantModuleDetail; + } + +} diff --git a/core-services/attendance/src/main/java/org/egov/util/ResponseInfoFactory.java b/core-services/attendance/src/main/java/org/egov/util/ResponseInfoFactory.java new file mode 100644 index 00000000000..8bcab7b536d --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/util/ResponseInfoFactory.java @@ -0,0 +1,25 @@ +package org.egov.util; + +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.stereotype.Component; + +@Component +public class ResponseInfoFactory { + + public ResponseInfo createResponseInfoFromRequestInfo(final RequestInfo requestInfo, final Boolean success) { + + final String apiId = requestInfo != null ? requestInfo.getApiId() : ""; + final String ver = requestInfo != null ? requestInfo.getVer() : ""; + Long ts = null; + if (requestInfo != null) + ts = requestInfo.getTs(); + final String resMsgId = "uief87324"; // FIXME : Hard-coded + final String msgId = requestInfo != null ? requestInfo.getMsgId() : ""; + final String responseStatus = success ? "successful" : "failed"; + + return ResponseInfo.builder().apiId(apiId).ver(ver).ts(ts).resMsgId(resMsgId).msgId(msgId).resMsgId(resMsgId) + .status(responseStatus).build(); + } + +} \ No newline at end of file diff --git a/core-services/attendance/src/main/java/org/egov/validator/AttendanceLogServiceValidator.java b/core-services/attendance/src/main/java/org/egov/validator/AttendanceLogServiceValidator.java new file mode 100644 index 00000000000..a788e5bd45a --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/validator/AttendanceLogServiceValidator.java @@ -0,0 +1,503 @@ +package org.egov.validator; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.config.AttendanceServiceConfiguration; +import org.egov.repository.AttendanceLogRepository; +import org.egov.repository.AttendeeRepository; +import org.egov.repository.RegisterRepository; +import org.egov.repository.StaffRepository; +import org.egov.tracer.model.CustomException; +import org.egov.util.IndividualServiceUtil; +import org.egov.web.models.AttendanceLog; +import org.egov.web.models.AttendanceLogRequest; +import org.egov.web.models.AttendanceLogSearchCriteria; +import org.egov.web.models.AttendanceRegister; +import org.egov.web.models.AttendanceRegisterSearchCriteria; +import org.egov.web.models.AttendeeSearchCriteria; +import org.egov.web.models.IndividualEntry; +import org.egov.web.models.RequestInfoWrapper; +import org.egov.web.models.StaffPermission; +import org.egov.web.models.StaffSearchCriteria; +import org.egov.web.models.Status; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.time.Instant; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +@Component +@Slf4j +public class AttendanceLogServiceValidator { + + @Autowired + private StaffRepository attendanceStaffRepository; + + @Autowired + private RegisterRepository attendanceRegisterRepository; + + @Autowired + private AttendeeRepository attendanceAttendeeRepository; + + @Autowired + private AttendanceLogRepository attendanceLogRepository; + + @Autowired + private AttendanceServiceConfiguration config; + + @Autowired + private IndividualServiceUtil individualServiceUtil; + + public void validateCreateAttendanceLogRequest(AttendanceLogRequest attendanceLogRequest) { + log.info("Validate attendance log create request"); + validateAttendanceLogRequest(attendanceLogRequest); + + // Verify all the attendance logs should below to same registerId + validateMultipleRegisterIds(attendanceLogRequest); + + // Verify all the attendance logs should below to same tenantId + validateMultipleTenantIds(attendanceLogRequest); + + // Verify the Logged-in user is associated to the given register. + validateLoggedInUser(attendanceLogRequest); + + // Verify given attendance log against register params + validateAttendanceLogsAgainstRegisterParams(attendanceLogRequest); + + // Verify if individuals are part of the given register and individuals were active during given attendance log time. + validateAttendees(attendanceLogRequest); + + // Verify provided documentIds are valid. + validateDocumentIds(attendanceLogRequest); + log.info("Attendance log create request validation done"); + } + + private void validateMultipleTenantIds(AttendanceLogRequest attendanceLogRequest) { + List attendanceLogs = attendanceLogRequest.getAttendance(); + Set tenantIds = new HashSet<>(); + for(AttendanceLog attendanceLog : attendanceLogs){ + String tenantId = attendanceLog.getTenantId(); + if(tenantIds.isEmpty()){ + tenantIds.add(tenantId); + }else{ + if(!tenantIds.contains(tenantId)){ + log.error("Attendance logs should below to same tenantId"); + throw new CustomException("MULTIPLE_TENANTIDS","Attendance logs should belong to same tenantId"); + } + } + } + } + + private void validateMultipleRegisterIds(AttendanceLogRequest attendanceLogRequest) { + List attendanceLogs = attendanceLogRequest.getAttendance(); + Set registerIds = new HashSet<>(); + for(AttendanceLog attendanceLog : attendanceLogs){ + String registerId = attendanceLog.getRegisterId(); + if(registerIds.isEmpty()){ + registerIds.add(registerId); + }else{ + if(!registerIds.contains(registerId)){ + log.error("Attendance logs should below to same registerId"); + throw new CustomException("MULTIPLE_REGISTERIDS","Attendance logs should belong to same registerId"); + } + } + } + } + + public void validateUpdateAttendanceLogRequest(AttendanceLogRequest attendanceLogRequest) { + log.info("Validate attendance log update request"); + validateAttendanceLogRequest(attendanceLogRequest); + + // Verify all the attendance logs should below to same registerId + validateMultipleRegisterIds(attendanceLogRequest); + + // Verify all the attendance logs should below to same tenantId + validateMultipleTenantIds(attendanceLogRequest); + + // Verify the Logged-in user is associated to the given register. + validateLoggedInUser(attendanceLogRequest); + + // Verify provided log ids are present + validateAttendanceLogIds(attendanceLogRequest); + + // Verify given attendance log against register params + validateAttendanceLogsAgainstRegisterParams(attendanceLogRequest); + + // Verify if individuals are part of the given register and individuals were active during given attendance log time. + validateAttendees(attendanceLogRequest); + + // Verify provided documentIds are valid. + validateDocumentIds(attendanceLogRequest); + + log.info("Attendance log update request validation done"); + } + + private void validateAttendanceLogsAgainstRegisterParams(AttendanceLogRequest attendanceLogRequest){ + String registerId = attendanceLogRequest.getAttendance().get(0).getRegisterId(); + String tenantId = attendanceLogRequest.getAttendance().get(0).getTenantId(); + + // Fetch register for given registerId + List attendanceRegisters = fetchRegisterWithId(registerId); + + // Check existence of register + checkRegisterExistence(attendanceRegisters,registerId); + + AttendanceRegister attendanceRegister = attendanceRegisters.get(0); + + // Check register is active ? + checkRegisterStatus(attendanceRegister); + + // Check register association with tenantId + validateTenantIdAssociationWithRegisterId(attendanceRegister,tenantId); + + // Check attendance log time against register start and end date + validateAttendanceLogTimeWithRegisterStartEndDate(attendanceRegister,attendanceLogRequest); + + log.info("Attendance log verification against register params are done. RegisterId ["+registerId+"]"); + } + + private void checkRegisterStatus(AttendanceRegister attendanceRegister) { + if(Status.INACTIVE.equals(attendanceRegister.getStatus())){ + String registerId = attendanceRegister.getId(); + log.error("Register ["+registerId+"] is inactive"); + throw new CustomException("INACTIVE_REGISTER", "Given RegisterId ["+registerId+"] is inactive"); + } + } + + private void checkRegisterExistence(List attendanceRegisters,String registerId) { + if (attendanceRegisters == null || attendanceRegisters.isEmpty()) { + log.error("Register ["+registerId+"] does not exists"); + throw new CustomException("REGISTER_NOT_FOUND", "Given RegisterId ["+registerId+"] does not exists"); + } + } + + private void validateTenantIdAssociationWithRegisterId(AttendanceRegister attendanceRegister,String tenantId) { + if(!tenantId.equals(attendanceRegister.getTenantId())){ + log.error("TenantId ["+tenantId+"] is not associated with register ["+attendanceRegister.getId()+"]"); + throw new CustomException("INVALID_TENANTID", "TenantId ["+tenantId+"] is not associated with register ["+attendanceRegister.getId()+"]"); + } + } + + private List fetchRegisterWithId(String registerId) { + AttendanceRegisterSearchCriteria searchCriteria = AttendanceRegisterSearchCriteria + .builder() + .ids(Collections.singletonList(registerId)) + .build(); + return attendanceRegisterRepository.getRegister(searchCriteria); + } + + private void validateAttendanceLogTimeWithRegisterStartEndDate(AttendanceRegister attendanceRegister,AttendanceLogRequest attendanceLogRequest) { + Instant registerStartTime = Instant.ofEpochMilli(attendanceRegister.getStartDate().longValue()); + + Instant registerEndTime = null; + if(attendanceRegister.getEndDate() != null) + registerEndTime = Instant.ofEpochMilli(attendanceRegister.getEndDate().longValue()); + + List attendanceLogs = attendanceLogRequest.getAttendance(); + + if(registerEndTime != null){ + for(AttendanceLog attendanceLog : attendanceLogs){ + Instant instantAttendanceAttendeeLogTime = Instant.ofEpochMilli(attendanceLog.getTime().longValue()); + if(!(instantAttendanceAttendeeLogTime.compareTo(registerStartTime) >=0 && instantAttendanceAttendeeLogTime.compareTo(registerEndTime) <=0)){ + log.error("Attendance time ["+instantAttendanceAttendeeLogTime+"] is invalid for register ["+attendanceRegister.getId()+"]"); + throw new CustomException("INVALID_ATTENDANCE_TIME", "Attendance time ["+instantAttendanceAttendeeLogTime+"] is invalid for register ["+attendanceRegister.getId()+"]"); + } + } + }else{ + for(AttendanceLog attendanceLog : attendanceLogs){ + Instant instantAttendanceAttendeeLogTime = Instant.ofEpochMilli(attendanceLog.getTime().longValue()); + if(!(instantAttendanceAttendeeLogTime.compareTo(registerStartTime) >=0)){ + log.error("Attendance time ["+instantAttendanceAttendeeLogTime+"] is invalid for register ["+attendanceRegister.getId()+"]"); + throw new CustomException("INVALID_ATTENDANCE_TIME", "Attendance time ["+instantAttendanceAttendeeLogTime+"] is invalid for register ["+attendanceRegister.getId()+"]"); + } + } + } + } + private void validateDocumentIds(AttendanceLogRequest attendanceLogRequest) { + if ("TRUE".equalsIgnoreCase(config.getDocumentIdVerificationRequired())) { + //TODO + // For now throwing exception. Later implementation will be done + log.error("Document service not integrated yet"); + throw new CustomException("SERVICE_UNAVAILABLE", "Service not integrated yet"); + } + } + + private void validateAttendanceLogIds(AttendanceLogRequest attendanceLogRequest) { + String registerId = attendanceLogRequest.getAttendance().get(0).getRegisterId(); + List attendance = attendanceLogRequest.getAttendance(); + List providedAttendanceLogIds = attendance.stream().map(e -> String.valueOf(e.getId())).collect(Collectors.toList()); + List fetchedAttendanceLogList = fetchAttendanceLogsByIds(providedAttendanceLogIds); + Set fetchedAttendanceLogIds = fetchedAttendanceLogList.stream().map(e -> String.valueOf(e.getId())).collect(Collectors.toSet()); + for (String providedAttendanceLogId : providedAttendanceLogIds) { + if (!fetchedAttendanceLogIds.contains(providedAttendanceLogId)) { + log.error("Provided attendance id ["+providedAttendanceLogId+"] is invalid for register ["+registerId+"]"); + throw new CustomException("ATTENDANCE_LOG", "Provided attendance id ["+providedAttendanceLogId+"] is invalid for register ["+registerId+"]"); + } + } + + log.info("Attendance Log Ids are validated successfully for register ["+registerId+"]"); + } + + private List fetchAttendanceLogsByIds(List ids) { + //AttendanceLogSearchCriteria searchCriteria = AttendanceLogSearchCriteria.builder().ids(ids).status(Status.ACTIVE).build(); + AttendanceLogSearchCriteria searchCriteria = AttendanceLogSearchCriteria.builder().ids(ids).build(); + return attendanceLogRepository.getAttendanceLogs(searchCriteria); + } + + private void validateAttendees(AttendanceLogRequest attendanceLogRequest) { + + /* + For now, we are validating attendees on below basis. + 1. Verify that each attendee is associated to given register. + 2. Make the entry in attendance log table only if attendee was active during the given attendance time. + + Future: + Once Individual service will be available will integrate it for further validation. + */ + + + if ("TRUE".equalsIgnoreCase(config.getIndividualServiceIntegrationRequired())) { + //TODO + // For now throwing exception. Since individual service is under discussion. + log.error("Individual service integration is under development"); + throw new CustomException("INTEGRATION_UNDERDEVELOPMENT", "Individual service integration is under development"); + } + + // Fetch all attendees for given register_id. + String registerId = attendanceLogRequest.getAttendance().get(0).getRegisterId(); + List fetchAttendanceAttendeeLst = fetchAllAttendeesEnrolledInARegister(registerId); + + log.info("All attendees are fetched successfully for register ["+registerId+"]"); + + // Convert the fetched Attendee List into a Map with individualId as key and corresponding Attendee list as value. + Map> attendanceAttendeeListMap = fetchAttendanceAttendeeLst + .stream() + .collect(Collectors.groupingBy(IndividualEntry::getIndividualId)); + + // Identify unassociated(Attendees not associated with given register) and ineligible attendees + identifyUnassociatedAndIneligibleAttendees(attendanceLogRequest, attendanceAttendeeListMap); + log.info("Attendee validation is done for register ["+registerId+"]"); + } + + private void identifyUnassociatedAndIneligibleAttendees(AttendanceLogRequest attendanceLogRequest, Map> attendanceAttendeeListMap) { + List unassociatedAttendees = new ArrayList<>(); + Set eligibleAttendanceAttendeeIdSet = new HashSet<>(); + + List attendanceLogs = attendanceLogRequest.getAttendance(); + for (AttendanceLog attendanceLog : attendanceLogs) { + String givenIndividualId = attendanceLog.getIndividualId(); + if (attendanceAttendeeListMap.containsKey(givenIndividualId)) { + List lst = attendanceAttendeeListMap.get(givenIndividualId); + for (IndividualEntry attendee : lst) { + Instant instantAttendanceAttendeeLogTime = Instant.ofEpochMilli(attendanceLog.getTime().longValue()); + Instant instantEnrollmentDate = Instant.ofEpochMilli(attendee.getEnrollmentDate().longValue()); + if (attendee.getDenrollmentDate()==null) { + if (instantAttendanceAttendeeLogTime.compareTo(instantEnrollmentDate) >= 0) { + eligibleAttendanceAttendeeIdSet.add(attendee.getIndividualId()); + } + } else { + Instant instantDenrollmentDate = Instant.ofEpochMilli(attendee.getDenrollmentDate().longValue()); + if (instantAttendanceAttendeeLogTime.compareTo(instantEnrollmentDate) >= 0 && instantAttendanceAttendeeLogTime.compareTo(instantDenrollmentDate) <= 0) { + eligibleAttendanceAttendeeIdSet.add(attendee.getIndividualId()); + } + } + } + } else { + unassociatedAttendees.add(givenIndividualId); + } + + } + + String registerId = attendanceLogRequest.getAttendance().get(0).getRegisterId(); + + if (!unassociatedAttendees.isEmpty()) { + log.error("Attendees are not enrolled against register ["+registerId+"]"); + throw new CustomException("UNENROLLED_ATTENDEES", "Attendees are not enrolled against register ["+registerId+"]"); + } + + //find ineligible list + Set inEligibleAttendanceAttendeeIdSet = new HashSet<>(); + for (AttendanceLog attendanceLog : attendanceLogs) { + if (!eligibleAttendanceAttendeeIdSet.contains(attendanceLog.getIndividualId())) { + inEligibleAttendanceAttendeeIdSet.add(attendanceLog.getIndividualId()); + } + } + + if (!inEligibleAttendanceAttendeeIdSet.isEmpty()) { + log.error("Attendees are ineligible for given date range for register ["+registerId+"]"); + throw new CustomException("INELIGIBLE_ATTENDEES", "Attendees are ineligible for given date range for register ["+registerId+"]"); + } + } + + private List fetchAllAttendeesEnrolledInARegister(String registerId) { + AttendeeSearchCriteria searchCriteria = AttendeeSearchCriteria + .builder() + .registerIds(Collections.singletonList(registerId)) + .build(); + + return attendanceAttendeeRepository.getAttendees(searchCriteria); + } + + private void validateLoggedInUser(AttendanceLogRequest attendanceLogRequest) { + /* + For now, we are validating logged-in user on below basis. + 1. Logged-in user should be active user for provided register_id. Query eg_wms_attendance_staff table for same. + + Future + Once Staff service will be available will integrate it for further validation. + */ + + if ("TRUE".equalsIgnoreCase(config.getStaffServiceIntegrationRequired())) { + //TODO + // For now throwing exception. Since Staff service is under development. + log.error("Staff service integration is under development"); + throw new CustomException("INTEGRATION_UNDERDEVELOPMENT", "Staff service integration is under development"); + } + + String userUUID = attendanceLogRequest.getRequestInfo().getUserInfo().getUuid(); + String registerId = attendanceLogRequest.getAttendance().get(0).getRegisterId(); + String individualId = individualServiceUtil.getIndividualDetailsFromUserId(attendanceLogRequest.getRequestInfo().getUserInfo().getId(), attendanceLogRequest.getRequestInfo(), attendanceLogRequest.getAttendance().get(0).getTenantId()).get(0).getId(); + validateLoggedInUser(individualId, registerId); + log.info("User ["+userUUID+"] validation is done for register ["+registerId+"]"); + } + + public void validateSearchAttendanceLogRequest(RequestInfoWrapper requestInfoWrapper, AttendanceLogSearchCriteria searchCriteria) { + + log.info("Validate attendance log search request"); + + // Verify given parameters + validateSearchAttendanceLogParameters(requestInfoWrapper, searchCriteria); + + // Fetch register for given Id + List attendanceRegisters = fetchRegisterWithId(searchCriteria.getRegisterId()); + + if (attendanceRegisters == null || attendanceRegisters.isEmpty()) { + throw new CustomException("INVALID_REGISTERID", "Register Not found "); + } + + // Verify TenantId association with register + validateTenantIdAssociationWithRegisterId(attendanceRegisters.get(0), searchCriteria.getTenantId()); + + // Verify the Logged-in user is associated to the given register. + String individualId = individualServiceUtil.getIndividualDetailsFromUserId(requestInfoWrapper.getRequestInfo().getUserInfo().getId(), requestInfoWrapper.getRequestInfo(), searchCriteria.getTenantId()).get(0).getId(); + validateLoggedInUser(individualId, searchCriteria.getRegisterId()); + + log.info("Attendance log search request validated successfully"); + } + + private void validateSearchAttendanceLogParameters(RequestInfoWrapper requestInfoWrapper, AttendanceLogSearchCriteria searchCriteria) { + if (searchCriteria == null || requestInfoWrapper == null) { + log.error("Attendance log search criteria and request info is mandatory"); + throw new CustomException("ATTENDANCE_LOG_SEARCH_REQUEST", "Attendance log search criteria and request info is mandatory"); + } + + Map errorMap = new HashMap<>(); + + validateRequestInfo(requestInfoWrapper.getRequestInfo(), errorMap); + + if (StringUtils.isBlank(searchCriteria.getTenantId())) { + log.error("Attendance log search, Tenant is mandatory"); + throw new CustomException("TENANT_ID", "Tenant is mandatory"); + } + if (StringUtils.isBlank(searchCriteria.getRegisterId())) { + log.error("Attendance log search, RegisterId is mandatory"); + throw new CustomException("REGISTER_ID", "RegisterId is mandatory"); + } + + // Throw exception if required parameters are missing + if (!errorMap.isEmpty()) + throw new CustomException(errorMap); + + if (searchCriteria.getIndividualIds() != null && !searchCriteria.getIndividualIds().isEmpty() && searchCriteria.getIndividualIds().size() > 10) { + log.error("Attendance log search, only 10 IndividualIds are allowed to search"); + throw new CustomException("INDIVIDUALIDS", "only 10 IndividualIds are allowed to search"); + } + } + + + + private void validateLoggedInUser(String userUUID, String registerId) { + StaffSearchCriteria searchCriteria = StaffSearchCriteria + .builder() + .individualIds(Collections.singletonList(userUUID)) + .registerIds(Collections.singletonList(registerId)) + .build(); + List attendanceStaff = attendanceStaffRepository.getActiveStaff(searchCriteria); + if (attendanceStaff == null || attendanceStaff.isEmpty()) { + log.error("User ["+userUUID+"] is not authorised for register ["+registerId+"]"); + throw new CustomException("UNAUTHORISED_USER", "User ["+userUUID+"] is not authorised for register ["+registerId+"]"); + } + } + + private void validateRequestInfo(RequestInfo requestInfo, Map errorMap) { + if (requestInfo == null) { + log.error("Request info is mandatory"); + throw new CustomException("REQUEST_INFO", "Request info is mandatory"); + } + if (requestInfo.getUserInfo() == null) { + log.error("UserInfo is mandatory"); + throw new CustomException("USERINFO", "UserInfo is mandatory"); + } + if (requestInfo.getUserInfo() != null && StringUtils.isBlank(requestInfo.getUserInfo().getUuid())) { + log.error("UUID is mandatory"); + throw new CustomException("USERINFO_UUID", "UUID is mandatory"); + } + + log.info("Request Info object validation done"); + } + + private void validateAttendanceLogRequest(AttendanceLogRequest attendanceLogRequest) { + + Map errorMap = new HashMap<>(); + // Validate the Request Info object + RequestInfo requestInfo = attendanceLogRequest.getRequestInfo(); + validateRequestInfo(requestInfo, errorMap); + + // Validate the Attendance Log parameters + validateAttendanceLogParameters(attendanceLogRequest.getAttendance(), errorMap); + + // Throw exception if required parameters are missing + if (!errorMap.isEmpty()){ + log.error("Attendance log request validation failed"); + throw new CustomException(errorMap); + } + } + + private void validateAttendanceLogParameters(List attendance, Map errorMap) { + if (attendance == null || attendance.isEmpty()) { + log.error("Attendance array is mandatory"); + throw new CustomException("ATTENDANCE", "Attendance array is mandatory"); + } + + for (AttendanceLog attendeeLog : attendance) { + if (StringUtils.isBlank(attendeeLog.getTenantId())) { + log.error("TenantId is mandatory"); + errorMap.put("ATTENDANCE.TENANTID", "TenantId is mandatory"); + } + if (StringUtils.isBlank(attendeeLog.getRegisterId())) { + log.error("Attendance registerid is mandatory"); + errorMap.put("ATTENDANCE.REGISTERID", "Attendance registerid is mandatory"); + } + if (StringUtils.isBlank(attendeeLog.getIndividualId() )) { + log.error("Attendance indidualid is mandatory"); + errorMap.put("ATTENDANCE.INDIVIDUALID", "Attendance indidualid is mandatory"); + } + if (StringUtils.isBlank(attendeeLog.getType())) { + log.error("Attendance type is mandatory"); + errorMap.put("ATTENDANCE.TYPE", "Attendance type is mandatory"); + } + if (attendeeLog.getTime() == null) { + log.error("Attendance time is mandatory"); + errorMap.put("ATTENDANCE.TIME", "Attendance time is mandatory"); + } + } + } +} diff --git a/core-services/attendance/src/main/java/org/egov/validator/AttendanceServiceValidator.java b/core-services/attendance/src/main/java/org/egov/validator/AttendanceServiceValidator.java new file mode 100644 index 00000000000..a8c88ed9867 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/validator/AttendanceServiceValidator.java @@ -0,0 +1,285 @@ +package org.egov.validator; + +import com.jayway.jsonpath.JsonPath; +import digit.models.coremodels.RequestInfoWrapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.repository.RegisterRepository; +import org.egov.tracer.model.CustomException; +import org.egov.util.IndividualServiceUtil; +import org.egov.util.MDMSUtils; +import org.egov.web.models.AttendanceRegister; +import org.egov.web.models.AttendanceRegisterRequest; +import org.egov.web.models.AttendanceRegisterSearchCriteria; +import org.egov.web.models.StaffPermission; +import org.egov.web.models.Status; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.egov.util.AttendanceServiceConstants.MASTER_TENANTS; +import static org.egov.util.AttendanceServiceConstants.MDMS_TENANT_MODULE_NAME; + +@Component +@Slf4j +public class AttendanceServiceValidator { + + @Autowired + private MDMSUtils mdmsUtils; + + @Autowired + private RegisterRepository registerRepository; + @Autowired + private IndividualServiceUtil individualServiceUtil; + + /* Validates create Attendance Register request body */ + public void validateCreateAttendanceRegister(AttendanceRegisterRequest request) { + Map errorMap = new HashMap<>(); + List attendanceRegisters = request.getAttendanceRegister(); + RequestInfo requestInfo = request.getRequestInfo(); + + //Verify if RequestInfo and UserInfo is present + validateRequestInfo(requestInfo, errorMap); + log.info("Request Info validated for attendance create request"); + + //Verify if attendance register request and mandatory fields are present + validateAttendanceRegisterRequest(attendanceRegisters, errorMap); + log.info("Attendance registers validated for create request"); + + //Verify referenceId and ServiceCode are present + validateReferenceIdAndServiceCodeParams(attendanceRegisters, errorMap); + log.info("Attendance registers referenceId and ServiceCode are validated"); + + String tenantId = attendanceRegisters.get(0).getTenantId(); + String rootTenantId = tenantId.split("\\.")[0]; + + //Get MDMS data using create attendance register request and tenantId + Object mdmsData = mdmsUtils.mDMSCall(requestInfo, rootTenantId); + validateMDMSData(attendanceRegisters, mdmsData, errorMap); + log.info("Request data validated with MDMS"); + + if (!errorMap.isEmpty()) + throw new CustomException(errorMap); + + //Verify that active attendance register is not already present for provided tenantId, referenceId and serviceCode + validateAttendanceRegisterAgainstDB(attendanceRegisters); + log.info("Attendance registers validated against DB"); + } + + private void validateAttendanceRegisterAgainstDB(List attendanceRegisters) { + for (AttendanceRegister attendanceRegister: attendanceRegisters) { + String tenantId = attendanceRegister.getTenantId(); + String referenceId = attendanceRegister.getReferenceId(); + String serviceCode = attendanceRegister.getServiceCode(); + + AttendanceRegisterSearchCriteria attendanceRegisterSearchCriteria = AttendanceRegisterSearchCriteria.builder() + .tenantId(tenantId) + .status(Status.ACTIVE) + .referenceId(referenceId) + .serviceCode(serviceCode) + .build(); + List registers = registerRepository.getRegister(attendanceRegisterSearchCriteria); + if(!registers.isEmpty()){ + log.error("Attendance register exists for provided referenceId ["+referenceId+"] and serviceCode ["+serviceCode+"]"); + throw new CustomException("REGISTER_ALREADY_EXISTS", "Register exists for provided referenceId ["+referenceId+"] and serviceCode ["+serviceCode+"]"); + } + } + } + + /* Validates Update Attendance register request body */ + public void validateUpdateAttendanceRegisterRequest(AttendanceRegisterRequest request) { + Map errorMap = new HashMap<>(); + List attendanceRegisters = request.getAttendanceRegister(); + RequestInfo requestInfo = request.getRequestInfo(); + + //Verify if RequestInfo and UserInfo is present + validateRequestInfo(requestInfo, errorMap); + log.info("Request Info validated for attendance update request"); + //Verify attendance register request and if mandatory fields are present + validateAttendanceRegisterRequest(attendanceRegisters, errorMap); + log.info("Attendance registers validated for update request"); + + for (AttendanceRegister attendanceRegister: attendanceRegisters) { + if (StringUtils.isBlank(attendanceRegister.getId())) { + log.error("Attendance register id is mandatory in register update request"); + errorMap.put("ATTENDANCE_REGISTER_ID", "Attendance register id is mandatory"); + } + } + + String tenantId = attendanceRegisters.get(0).getTenantId(); + String rootTenantId = tenantId.split("\\.")[0]; + + //Get MDMS data using create attendance register request and tenantId + Object mdmsData = mdmsUtils.mDMSCall(requestInfo, rootTenantId); + validateMDMSData(attendanceRegisters, mdmsData, errorMap); + log.info("Request data validated with MDMS"); + + if (!errorMap.isEmpty()) + throw new CustomException(errorMap); + } + + /* Validates attendance register data in update request against attendance register data fetched from database */ + public void validateUpdateAgainstDB(AttendanceRegisterRequest attendanceRegisterRequest, List attendanceRegistersFromDB) { + if (CollectionUtils.isEmpty(attendanceRegistersFromDB)) { + log.error("The record that you are trying to update does not exists in the system"); + throw new CustomException("INVALID_REGISTER_MODIFY", "The record that you are trying to update does not exists in the system"); + } + + for (AttendanceRegister registerFromRequest: attendanceRegisterRequest.getAttendanceRegister()) { + + AttendanceRegister registerFromDB = attendanceRegistersFromDB.stream().filter(ar -> ar.getId().equals(registerFromRequest.getId())).findFirst().orElse(null); + if (registerFromDB == null) { + log.error("The register Id " + registerFromRequest.getId() + " that you are trying to update does not exists in the system"); + throw new CustomException("INVALID_REGISTER_MODIFY", "The register Id " + registerFromRequest.getId() + " that you are trying to update does not exists in the system"); + } + + // If the user who is trying to update the register is not associated with the register, throw error that the user does not have permission to modify the attendance register + if (registerFromDB.getStaff() != null) { + Set staffUserIdsFromDB = registerFromDB.getStaff().stream().map(StaffPermission:: getUserId).collect(Collectors.toSet()); + String individualId = individualServiceUtil.getIndividualDetailsFromUserId(attendanceRegisterRequest.getRequestInfo().getUserInfo().getId(),attendanceRegisterRequest.getRequestInfo(), registerFromRequest.getTenantId()).get(0).getId(); + if (!staffUserIdsFromDB.contains(individualId)) { + log.error("The user " + attendanceRegisterRequest.getRequestInfo().getUserInfo().getUuid() + " does not have permission to modify the register " + registerFromDB.getId()); + throw new CustomException("INVALID_REGISTER_MODIFY", "The user " + attendanceRegisterRequest.getRequestInfo().getUserInfo().getUuid() + " does not have permission to modify the register " + registerFromDB.getId()); + } + } else { + log.error("The user " + attendanceRegisterRequest.getRequestInfo().getUserInfo().getUuid() + " does not have permission to modify the register " + registerFromDB.getId()); + throw new CustomException("INVALID_REGISTER_MODIFY", "The user " + attendanceRegisterRequest.getRequestInfo().getUserInfo().getUuid() + " does not have permission to modify the register " + registerFromDB.getId()); + } + } + } + + /* Validates Request Info and User Info */ + private void validateRequestInfo(RequestInfo requestInfo, Map errorMap) { + if (requestInfo == null) { + log.error("Request info is mandatory"); + throw new CustomException("REQUEST_INFO", "Request info is mandatory"); + } + if (requestInfo.getUserInfo() == null) { + log.error("UserInfo is mandatory"); + throw new CustomException("USERINFO", "UserInfo is mandatory"); + } + if (requestInfo.getUserInfo() != null && StringUtils.isBlank(requestInfo.getUserInfo().getUuid())) { + log.error("UUID is mandatory"); + throw new CustomException("USERINFO_UUID", "UUID is mandatory"); + } + } + + private void validateReferenceIdAndServiceCodeParams(List attendanceRegisters, Map errorMap) { + for (int i = 0; i < attendanceRegisters.size(); i++) { + if (StringUtils.isBlank(attendanceRegisters.get(i).getReferenceId())) { + log.error("ReferenceId is mandatory"); + errorMap.put("REFERENCE_ID", "ReferenceId is mandatory"); + } + + if (StringUtils.isBlank(attendanceRegisters.get(i).getServiceCode())) { + log.error("ServiceCode is mandatory"); + errorMap.put("SERVICE_CODE", "ServiceCode is mandatory"); + } + } + } + + /* Validates Attendance register request body for create and update apis */ + private void validateAttendanceRegisterRequest(List attendanceRegisters, Map errorMap) { + if (attendanceRegisters == null || attendanceRegisters.size() == 0) { + log.error("Attendance Register is mandatory"); + throw new CustomException("ATTENDANCE_REGISTER", "Attendance Register is mandatory"); + } + + for (int i = 0; i < attendanceRegisters.size(); i++) { + if (attendanceRegisters.get(i) == null) { + log.error("Attendance Register is mandatory"); + throw new CustomException("ATTENDANCE_REGISTER", "Attendance Register is mandatory"); + } + if (StringUtils.isBlank(attendanceRegisters.get(i).getTenantId())) { + log.error("Tenant is mandatory"); + throw new CustomException("TENANT_ID", "Tenant is mandatory"); + } + if (StringUtils.isBlank(attendanceRegisters.get(i).getName())) { + log.error("Name is mandatory"); + errorMap.put("NAME", "Name is mandatory"); + } + + if (attendanceRegisters.get(i).getStartDate() == null || + (attendanceRegisters.get(i).getStartDate() != null && attendanceRegisters.get(i).getStartDate().compareTo(BigDecimal.ZERO) == 0)) { + log.error("Start date is mandatory for attendance register " + attendanceRegisters.get(i).getName()); + throw new CustomException("START_DATE", "Start date is mandatory"); + } + if (attendanceRegisters.get(i).getStartDate().compareTo(BigDecimal.ZERO) < 0) { + log.error("Start date is less than zero " + attendanceRegisters.get(i).getName()); + throw new CustomException("START_DATE", "Start date should be valid"); + } + if (attendanceRegisters.get(i).getEndDate() != null && attendanceRegisters.get(i).getStartDate().compareTo(attendanceRegisters.get(i).getEndDate()) > 0) { + log.error("Start date should be less than end date for attendance register " + attendanceRegisters.get(i).getName()); + errorMap.put("DATE", "Start date should be less than end date"); + } + if (!attendanceRegisters.get(i).getTenantId().equals(attendanceRegisters.get(0).getTenantId())) { + log.error("All registers must have same tenant Id. Please create new request for different tenant id"); + throw new CustomException("MULTIPLE_TENANTS", "All registers must have same tenant Id. Please create new request for different tenant id"); + } + } + } + + private void validateMDMSData(List attendanceRegisters, Object mdmsData, Map errorMap) { + + final String jsonPathForTenants = "$.MdmsRes." + MDMS_TENANT_MODULE_NAME + "." + MASTER_TENANTS + ".*"; + + List tenantRes = null; + try { + tenantRes = JsonPath.read(mdmsData, jsonPathForTenants); + } catch (Exception e) { + log.error(e.getMessage()); + throw new CustomException("JSONPATH_ERROR", "Failed to parse mdms response"); + } + + if (CollectionUtils.isEmpty(tenantRes)){ + log.error("The tenant: " + attendanceRegisters.get(0).getTenantId() + " is not present in MDMS"); + errorMap.put("INVALID_TENANT", "The tenant: " + attendanceRegisters.get(0).getTenantId() + " is not present in MDMS"); + } + } + + public void validateSearchRegisterRequest(RequestInfoWrapper requestInfoWrapper, AttendanceRegisterSearchCriteria searchCriteria) { + if (searchCriteria == null || requestInfoWrapper == null) { + log.error("Register search criteria request is mandatory"); + throw new CustomException("REGISTER_SEARCH_CRITERIA_REQUEST", "Register search criteria request is mandatory"); + } + + Map errorMap = new HashMap<>(); + + validateRequestInfo(requestInfoWrapper.getRequestInfo(),errorMap); + + if (StringUtils.isBlank(searchCriteria.getTenantId())) { + log.error("Tenant is mandatory"); + throw new CustomException("TENANT_ID", "Tenant is mandatory"); + } + + // Throw exception if required parameters are missing + if (!errorMap.isEmpty()) + throw new CustomException(errorMap); + } + + public void validateRegisterAgainstDB(List registerIds, List attendanceRegisterListFromDB, String tenantId) { + + Set uniqueRegisterIdsFromRequest = new HashSet<>(registerIds); + + Set uniqueRegisterIdsFromDB = attendanceRegisterListFromDB.stream() + .map(register -> register.getId()).collect(Collectors.toSet()); + + //check if all register ids from request exist in db + for (String idFromRequest : uniqueRegisterIdsFromRequest) { + if (!uniqueRegisterIdsFromDB.contains(idFromRequest)) { + log.error("Attendance Registers with register id : " + idFromRequest + " does not exist for tenantId"); + throw new CustomException("REGISTER_ID", "Attendance Registers with register id : " + idFromRequest + " does not exist for tenantId"); + } + } + + } +} diff --git a/core-services/attendance/src/main/java/org/egov/validator/AttendeeServiceValidator.java b/core-services/attendance/src/main/java/org/egov/validator/AttendeeServiceValidator.java new file mode 100644 index 00000000000..216d92de71b --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/validator/AttendeeServiceValidator.java @@ -0,0 +1,383 @@ +package org.egov.validator; + +import com.jayway.jsonpath.JsonPath; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.tracer.model.CustomException; +import org.egov.util.IndividualServiceUtil; +import org.egov.util.MDMSUtils; +import org.egov.web.models.AttendanceRegister; +import org.egov.web.models.AttendeeCreateRequest; +import org.egov.web.models.AttendeeDeleteRequest; +import org.egov.web.models.IndividualEntry; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.egov.util.AttendanceServiceConstants.MASTER_TENANTS; +import static org.egov.util.AttendanceServiceConstants.MDMS_TENANT_MODULE_NAME; + +@Component +@Slf4j +public class AttendeeServiceValidator { + + @Autowired + private MDMSUtils mdmsUtils; + + @Autowired + private IndividualServiceUtil individualServiceUtil; + + public void validateAttendeeCreateRequestParameters(AttendeeCreateRequest attendeeCreateRequest) { + List attendeeList = attendeeCreateRequest.getAttendees(); + Map errorMap = new HashMap<>(); + + if (attendeeList == null || attendeeList.isEmpty()) { + log.error("ATTENDEE Object is empty in attendee request"); + throw new CustomException("ATTENDEE", "ATTENDEE Object is empty in attendee request"); + } + + String tenantId = attendeeList.get(0).getTenantId(); + for (IndividualEntry attendee : attendeeList) { + + //validate request parameters for each attendee object + if (StringUtils.isBlank(attendee.getRegisterId())) { + log.error("register id is empty in attendee request"); + errorMap.put("REGISTER_ID", "Register id is mandatory"); + } + + if (StringUtils.isBlank(attendee.getIndividualId())) { + log.error("individual id is empty in attendee request"); + errorMap.put("INDIVIDUAL_ID", "Individual id is mandatory"); + } + + if (StringUtils.isBlank(attendee.getTenantId())) { + log.error("tenant id is empty in attendee request"); + errorMap.put("TENANT_ID", "Tenant id is mandatory"); + } + } + + if (!errorMap.isEmpty()) { + log.error("Attendee request validation failed"); + throw new CustomException(errorMap); + } + validateTenantIds(attendeeCreateRequest, tenantId); + validateDuplicateAttendeeObjects(attendeeCreateRequest); + + //validate tenantId with MDMS + log.info("validating tenant id from MDMS and Request info"); + validateMDMSAndRequestInfoForCreateAttendee(attendeeCreateRequest); + + //validate individualId with Individual Service + log.info("validating tenant id from MDMS and Request info"); + validateIndividualId(attendeeCreateRequest); + } + + private void validateIndividualId(AttendeeCreateRequest attendeeCreateRequest) { + RequestInfo requestInfo=attendeeCreateRequest.getRequestInfo(); + String tenantId=attendeeCreateRequest.getAttendees().get(0).getTenantId(); + List individualIds=attendeeCreateRequest.getAttendees().stream().map(attendee->attendee.getIndividualId()).collect(Collectors.toList()); + List ids= individualServiceUtil.fetchIndividualIds(individualIds,requestInfo,tenantId); + + for(String individualId:individualIds){ + if(!ids.contains(individualId)){ + throw new CustomException("INDIVIDUAL_ID_NOT_FOUND","Individual with id: "+individualId+" not found"); + } + } + } + + public void validateTenantIds(AttendeeCreateRequest attendeeCreateRequest, String tenantId) { + List attendeeList = attendeeCreateRequest.getAttendees(); + //validate if all attendee in the list have the same tenant id + for (IndividualEntry attendee : attendeeList) { + if (!attendee.getTenantId().equals(tenantId)) { + log.error("All attendees dont have the same tenant id in attendee request"); + throw new CustomException("TENANT_ID", "All Attendees to be enrolled or de enrolled must have the same tenant id. Please raise new request for different tenant id"); + } + } + + } + + public void validateDuplicateAttendeeObjects(AttendeeCreateRequest attendeeCreateRequest) { + List attendeeList = attendeeCreateRequest.getAttendees(); + + Set uniqueIds = new HashSet<>(); + for (IndividualEntry attendee : attendeeList) { + String uniqueId = attendee.getRegisterId() + attendee.getIndividualId(); + if (uniqueIds.isEmpty()) { + uniqueIds.add(attendee.getRegisterId() + attendee.getIndividualId()); + } else if (uniqueIds.contains(uniqueId)) { + log.error("Duplicate Attendee Objects found in request"); + throw new CustomException("ATTENDEE", "Duplicate attendee Objects present in request"); + } + uniqueIds.add(attendee.getRegisterId() + attendee.getIndividualId()); + } + } + + + public void validateAttendeeDeleteRequestParameters(AttendeeDeleteRequest attendeeDeleteRequest, Map errorMap) { + + List attendeeList = attendeeDeleteRequest.getAttendees(); + + if (attendeeList == null || attendeeList.isEmpty()) { + log.error("ATTENDEE Object is empty in attendee request"); + throw new CustomException("ATTENDEES", "ATTENDEE object is mandatory"); + } + + String tenantId = attendeeList.get(0).getTenantId(); + for (IndividualEntry attendee : attendeeList) { + + //validate request parameters for each attendee object + if (StringUtils.isBlank(attendee.getRegisterId())) { + log.error("REGISTER_ID is empty in attendee request"); + errorMap.put("REGISTER_ID", "Register id is mandatory"); + } + + if (StringUtils.isBlank(attendee.getIndividualId())) { + log.error("INDIVIDUAL_ID is empty in attendee request"); + errorMap.put("INDIVIDUAL_ID", "Individual id is mandatory"); + } + + if (StringUtils.isBlank(attendee.getTenantId())) { + log.error("TENANT_ID is empty in attendee request"); + errorMap.put("TENANT_ID", "Tenant id is mandatory"); + } + } + + if (!errorMap.isEmpty()) { + log.error("Attendee request validation failed"); + throw new CustomException(errorMap); + } + + validateTenantIds(attendeeDeleteRequest, tenantId); + validateDuplicateAttendeeObjects(attendeeDeleteRequest); + + //validate tenantId with MDMS + log.info("validating tenant id from MDMS and Request info"); + validateMDMSAndRequestInfoForDeleteAttendee(attendeeDeleteRequest); + + //validate individualId with Individual Service + log.info("validating tenant id from MDMS and Request info"); + validateIndividualId(attendeeDeleteRequest); + } + + private void validateIndividualId(AttendeeDeleteRequest attendeeDeleteRequest) { + RequestInfo requestInfo=attendeeDeleteRequest.getRequestInfo(); + String tenantId=attendeeDeleteRequest.getAttendees().get(0).getTenantId(); + List individualIds=attendeeDeleteRequest.getAttendees().stream().map(attendee->attendee.getIndividualId()).collect(Collectors.toList()); + List ids= individualServiceUtil.fetchIndividualIds(individualIds,requestInfo,tenantId); + + for(String individualId:individualIds){ + if(!ids.contains(individualId)){ + throw new CustomException("INDIVIDUAL_ID_NOT_FOUND","Individual with id: "+individualId+" not found"); + } + } + } + + public void validateTenantIds(AttendeeDeleteRequest attendeeDeleteRequest, String tenantId) { + List attendeeList = attendeeDeleteRequest.getAttendees(); + //validate if all attendee in the list have the same tenant id + for (IndividualEntry attendee : attendeeList) { + if (!attendee.getTenantId().equals(tenantId)) { + log.error("All attendees dont have the same tenant id in attendee request"); + throw new CustomException("TENANT_ID", "All Attendees to be enrolled or de enrolled must have the same tenant id. Please raise new request for different tenant id"); + } + } + + } + + public void validateDuplicateAttendeeObjects(AttendeeDeleteRequest attendeeDeleteRequest) { + List attendeeList = attendeeDeleteRequest.getAttendees(); + + Set uniqueIds = new HashSet<>(); + for (IndividualEntry attendee : attendeeList) { + String uniqueId = attendee.getRegisterId() + attendee.getIndividualId(); + if (uniqueIds.isEmpty()) { + uniqueIds.add(attendee.getRegisterId() + attendee.getIndividualId()); + } else if (uniqueIds.contains(uniqueId)) { + log.error("Duplicate Attendee Objects found in request"); + throw new CustomException("ATTENDEE", "Duplicate attendee Objects present in request"); + } + uniqueIds.add(attendee.getRegisterId() + attendee.getIndividualId()); + } + } + + public void validateMDMSAndRequestInfoForCreateAttendee(AttendeeCreateRequest attendeeCreateRequest) { + + RequestInfo requestInfo = attendeeCreateRequest.getRequestInfo(); + List attendeeListFromRequest = attendeeCreateRequest.getAttendees(); + Map errorMap = new HashMap<>(); + + String tenantId = attendeeListFromRequest.get(0).getTenantId(); + //split the tenantId + String rootTenantId = tenantId.split("\\.")[0]; + + Object mdmsData = mdmsUtils.mDMSCall(requestInfo, rootTenantId); + + //check tenant Id + log.info("validate tenantId with MDMS"); + validateMDMSData(tenantId, mdmsData, errorMap); + + + //validate request-info + log.info("validate request info coming from api request"); + validateRequestInfo(requestInfo, errorMap); + + if (!errorMap.isEmpty()) + throw new CustomException(errorMap); + } + + public void validateMDMSAndRequestInfoForDeleteAttendee(AttendeeDeleteRequest attendeeDeleteRequest) { + + RequestInfo requestInfo = attendeeDeleteRequest.getRequestInfo(); + List attendeeListFromRequest = attendeeDeleteRequest.getAttendees(); + Map errorMap = new HashMap<>(); + + String tenantId = attendeeListFromRequest.get(0).getTenantId(); + //split the tenantId + String rootTenantId = tenantId.split("\\.")[0]; + + Object mdmsData = mdmsUtils.mDMSCall(requestInfo, rootTenantId); + + //check tenant Id + log.info("validate tenantId with MDMS"); + validateMDMSData(tenantId, mdmsData, errorMap); + + + //validate request-info + log.info("validate request info coming from api request"); + validateRequestInfo(requestInfo, errorMap); + + if (!errorMap.isEmpty()) + throw new CustomException(errorMap); + } + + + public void validateAttendeeOnCreate(AttendeeCreateRequest attendeeCreateRequest + , List attendeeListFromDB, List attendanceRegisterListFromDB) { + + List attendeeListFromRequest = attendeeCreateRequest.getAttendees(); + + + // attendee cannot be added to register if register's end date has passed + log.info("verifying that attendee cannot be added to register if register's end date has passed"); + BigDecimal currentDate = new BigDecimal(System.currentTimeMillis()); + for (AttendanceRegister attendanceRegister : attendanceRegisterListFromDB) { + int dateComparisonResult = attendanceRegister.getEndDate().compareTo(currentDate); + if (dateComparisonResult < 0) { + throw new CustomException("END_DATE", "Attendee cannot be enrolled as END_DATE of register id " + attendanceRegister.getId() + " has already passed."); + } + } + + //attendee enrollment date, if present in request should be after start date and before end date of register + log.info("checking attendee enrollment date should be after start date and before end date of register"); + for (AttendanceRegister attendanceRegister : attendanceRegisterListFromDB) { + for (IndividualEntry attendeeFromRequest : attendeeListFromRequest) { + if (attendanceRegister.getId().equals(attendeeFromRequest.getRegisterId())) { + if (attendeeFromRequest.getEnrollmentDate() != null) { + int startDateCompare = attendeeFromRequest.getEnrollmentDate().compareTo(attendanceRegister.getStartDate()); + int endDateCompare = attendanceRegister.getEndDate().compareTo(attendeeFromRequest.getEnrollmentDate()); + if (startDateCompare < 0 || endDateCompare < 0) { + throw new CustomException("ENROLLMENT_DATE" + , "Enrollment date for attendee : " + attendeeFromRequest.getIndividualId() + " must be within start and end date of the register"); + } + } + } + } + } + + //check if attendee is already enrolled to the register + log.info("checking if attendee is already enrolled to the register"); + for (IndividualEntry attendeeFromRequest : attendeeListFromRequest) { + for (IndividualEntry attendeeFromDB : attendeeListFromDB) { + if (attendeeFromRequest.getRegisterId().equals(attendeeFromDB.getRegisterId()) + && attendeeFromRequest.getIndividualId().equals(attendeeFromDB.getIndividualId())) {//attendee present in db + if (attendeeFromDB.getDenrollmentDate() == null) { // already enrolled to the register + throw new CustomException("INDIVIDUAL_ID", "Attendee " + attendeeFromRequest.getIndividualId() + " is already enrolled in the register " + attendeeFromRequest.getRegisterId()); + + } + } + } + } + } + + public void validateAttendeeOnDelete(AttendeeDeleteRequest attendeeDeleteRequest, + List attendeeListFromDB, List attendanceRegisterListFromDB) { + + List attendeeListFromRequest = attendeeDeleteRequest.getAttendees(); + + + //attendee de-enrollment date, if present in request should be before end date and after start date of register + log.info("verifying attendee de-enrollment date, if present in request should be before end date and after start date of register"); + for (AttendanceRegister attendanceRegister : attendanceRegisterListFromDB) { + for (IndividualEntry attendeeFromRequest : attendeeListFromRequest) { + if (attendeeFromRequest.getDenrollmentDate() != null) { + int startDateCompare = attendeeFromRequest.getDenrollmentDate().compareTo(attendanceRegister.getStartDate()); + int endDateCompare = attendanceRegister.getEndDate().compareTo(attendeeFromRequest.getDenrollmentDate()); + if (startDateCompare < 0 || endDateCompare < 0) { + throw new CustomException("DE ENROLLMENT_DATE" + , "De enrollment date for attendee : " + attendeeFromRequest.getIndividualId() + " must be between start date and end date of the register"); + } + } + } + } + + //check if attendee is already de-enrolled from the register + log.info("checking if attendee is already de-enrolled from the register"); + boolean attendeeDeEnrolled = true; + for (IndividualEntry attendeeFromRequest : attendeeListFromRequest) { + for (IndividualEntry attendeeFromDB : attendeeListFromDB) { + if (attendeeFromRequest.getRegisterId().equals(attendeeFromDB.getRegisterId()) && attendeeFromDB.getIndividualId().equals(attendeeFromRequest.getIndividualId())) { //attendee present in db + if (attendeeFromDB.getDenrollmentDate() == null) { + attendeeDeEnrolled = false; + break; + } + } + } + if (attendeeDeEnrolled) { + throw new CustomException("INDIVIDUAL_ID", "Attendee " + attendeeFromRequest.getIndividualId() + " is already de enrolled from the register " + attendeeFromRequest.getRegisterId()); + } + } + + } + + private void validateRequestInfo(RequestInfo requestInfo, Map errorMap) { + if (requestInfo == null) { + log.error("Request info is null"); + throw new CustomException("REQUEST_INFO", "Request info is mandatory"); + } + if (requestInfo.getUserInfo() == null) { + log.error("User info is null"); + throw new CustomException("USERINFO", "UserInfo is mandatory"); + } + if (requestInfo.getUserInfo() != null && StringUtils.isBlank(requestInfo.getUserInfo().getUuid())) { + log.error("User's UUID field is empty"); + throw new CustomException("USERINFO_UUID", "User's UUID is mandatory"); + } + } + + private void validateMDMSData(String tenantId, Object mdmsData, Map errorMap) { + final String jsonPathForTenants = "$.MdmsRes." + MDMS_TENANT_MODULE_NAME + "." + MASTER_TENANTS + ".*"; + + List tenantRes = null; + try { + tenantRes = JsonPath.read(mdmsData, jsonPathForTenants); + } catch (Exception e) { + log.error(e.getMessage()); + throw new CustomException("JSONPATH_ERROR", "Failed to parse mdms response"); + } + + if (CollectionUtils.isEmpty(tenantRes)) + errorMap.put("INVALID_TENANT", "The tenant: " + tenantId + " is not present in MDMS"); + } +} + + diff --git a/core-services/attendance/src/main/java/org/egov/validator/StaffServiceValidator.java b/core-services/attendance/src/main/java/org/egov/validator/StaffServiceValidator.java new file mode 100644 index 00000000000..9c2d594e564 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/validator/StaffServiceValidator.java @@ -0,0 +1,271 @@ +package org.egov.validator; + +import com.jayway.jsonpath.JsonPath; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.service.AttendanceRegisterService; +import org.egov.tracer.model.CustomException; +import org.egov.util.MDMSUtils; +import org.egov.web.models.AttendanceRegister; +import org.egov.web.models.StaffPermission; +import org.egov.web.models.StaffPermissionRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static org.egov.util.AttendanceServiceConstants.MASTER_TENANTS; +import static org.egov.util.AttendanceServiceConstants.MDMS_TENANT_MODULE_NAME; + + +@Component +@Slf4j +public class StaffServiceValidator { + + @Autowired + private MDMSUtils mdmsUtils; + + @Autowired + private AttendanceRegisterService attendanceRegisterService; + + + public void validateMDMSAndRequestInfoForStaff(StaffPermissionRequest request) { + RequestInfo requestInfo = request.getRequestInfo(); + List staffPermissionListFromRequest = request.getStaff(); + Map errorMap = new HashMap<>(); + + String tenantId = staffPermissionListFromRequest.get(0).getTenantId(); + //split the tenantId + String rootTenantId = tenantId.split("\\.")[0]; + + Object mdmsData = mdmsUtils.mDMSCall(requestInfo, rootTenantId); + + //validate request-info + log.info("validate request info coming from api request"); + validateRequestInfo(requestInfo, errorMap); + + //check tenant Id + log.info("validate tenantId with MDMS"); + validateMDMSData(tenantId, mdmsData, errorMap); + + if (!errorMap.isEmpty()) + throw new CustomException(errorMap); + } + + private void validateRequestInfo(RequestInfo requestInfo, Map errorMap) { + if (requestInfo == null) { + log.error("Request info is null"); + throw new CustomException("REQUEST_INFO", "Request info is mandatory"); + } + if (requestInfo.getUserInfo() == null) { + log.error("UserInfo is null"); + throw new CustomException("USERINFO", "UserInfo is mandatory"); + } + if (requestInfo.getUserInfo() != null && StringUtils.isBlank(requestInfo.getUserInfo().getUuid())) { + log.error("User's UUID field is empty"); + throw new CustomException("USERINFO_UUID", "User's UUID is mandatory"); + } + } + + + public void validateStaffPermissionRequestParameters(StaffPermissionRequest staffPermissionRequest) { + List staffPermissionList = staffPermissionRequest.getStaff(); + Map errorMap = new HashMap<>(); + + if (staffPermissionList == null || staffPermissionList.isEmpty()) { + log.error("Staff Object is empty in staff request"); + throw new CustomException("STAFF", "Staff is mandatory"); + } + + String baseTenantId = staffPermissionList.get(0).getTenantId(); + for (StaffPermission staffPermission : staffPermissionList) { + + //validate request parameters for each staff object + if (StringUtils.isBlank(staffPermission.getRegisterId())) { + log.error("Register id is empty in staff request"); + errorMap.put("REGISTER_ID", "Register id is mandatory"); + } + + if (StringUtils.isBlank(staffPermission.getUserId())) { + log.error("User id is empty in staff request"); + errorMap.put("USER_ID", "User id is mandatory"); + } + + if (StringUtils.isBlank(staffPermission.getTenantId())) { + log.error("Tenant id is empty in staff request"); + errorMap.put("TENANT_ID", "Tenant id is mandatory"); + } + } + + if (!errorMap.isEmpty()) { + log.error("Attendee request validation failed"); + throw new CustomException(errorMap); + } + + validateTenantIds(staffPermissionRequest, baseTenantId); + validateDuplicateStaffObjects(staffPermissionRequest); + + + //validate tenant id with mdms and request info + log.info("validating tenant id from MDMS and Request info"); + validateMDMSAndRequestInfoForStaff(staffPermissionRequest); + } + + public void validateTenantIds(StaffPermissionRequest staffPermissionRequest, String tenantId) { + List staffPermissionList = staffPermissionRequest.getStaff(); + //validate if all staff in the list have the same tenant id + for (StaffPermission staffPermission : staffPermissionList) { + if (!staffPermission.getTenantId().equals(tenantId)) { + log.error("All staff objects do not have the same tenant id"); + throw new CustomException("TENANT_ID", "All Staff to be enrolled or de enrolled must have the same tenant id. Please raise new request for different tenant id"); + } + } + + } + + public void validateDuplicateStaffObjects(StaffPermissionRequest staffPermissionRequest) { + List staffPermissionList = staffPermissionRequest.getStaff(); + + Set uniqueIds = new HashSet<>(); + for (StaffPermission staffPermission : staffPermissionList) { + String uniqueId = staffPermission.getRegisterId() + staffPermission.getUserId(); + if (uniqueIds.isEmpty()) { + uniqueIds.add(staffPermission.getRegisterId() + staffPermission.getUserId()); + } else if (uniqueIds.contains(uniqueId)) { + log.error("Duplicate Staff Objects found in request"); + throw new CustomException("STAFF", "Duplicate Staff Objects present in request"); + } + uniqueIds.add(staffPermission.getRegisterId() + staffPermission.getUserId()); + } + } + + public void validateStaffPermissionOnCreate(StaffPermissionRequest request, List staffPermissionListFromDB, + List attendanceRegisterListFromDB) { + + List staffPermissionListFromRequest = request.getStaff(); + + // staff cannot be added to register if register's end date has passed + log.info("checking that staff cannot be added to register if register's end date has passed"); + BigDecimal enrollmentDate = new BigDecimal(System.currentTimeMillis()); + for (AttendanceRegister attendanceRegister : attendanceRegisterListFromDB) { + int dateComparisonResult = attendanceRegister.getEndDate().compareTo(enrollmentDate); + if (dateComparisonResult < 0) { + log.error("Staff cannot be enrolled as END_DATE of register id " + attendanceRegister.getId() + " has already passed."); + throw new CustomException("END_DATE", "Staff cannot be enrolled as END_DATE of register id " + attendanceRegister.getId() + " has already passed."); + } + } + + //check if staff user id exists in staff table for the given register id. If yes check the deenrollment date. If staffId does not exist new staff can still be enrolled to the register + if (staffPermissionListFromDB != null) { + for (StaffPermission staffFromRequest : staffPermissionListFromRequest) {//list of staff from request + StaffPermission staff = staffPermissionListFromDB.stream() + .filter(s -> s.getUserId().equals(staffFromRequest.getUserId()) && s.getRegisterId().equals(staffFromRequest.getRegisterId())) + .findFirst().orElse(null); + if (staff != null && staff.getDenrollmentDate() == null) { + throw new CustomException("USER_id", "Staff " + staff.getUserId() + " is already enrolled in the register " + staff.getRegisterId()); + } + } + } + + } + + + public void validateStaffPermissionOnDelete(StaffPermissionRequest staffPermissionRequest + , List staffPermissionListFromDB, List attendanceRegisterListFromDB) { + + RequestInfo requestInfo = staffPermissionRequest.getRequestInfo(); + List staffPermissionListFromRequest = staffPermissionRequest.getStaff(); + + boolean staffExists = false; + boolean staffDeenrolled = true; + + + //check is staff user id exists in staff table. If yes check if the de enrollment date is null + log.info("checking if the de enrollment date of staff is null"); + for (StaffPermission staffPermissionFromRequest : staffPermissionListFromRequest) { + for (StaffPermission staffPermissionFromDB : staffPermissionListFromDB) { + if (staffPermissionFromRequest.getRegisterId().equals(staffPermissionFromDB.getRegisterId()) && + staffPermissionFromRequest.getUserId().equals(staffPermissionFromDB.getUserId())) { + staffExists = true; + if (staffPermissionFromDB.getDenrollmentDate() == null) { + staffDeenrolled = false; + break; + } + } + } + if (!staffExists) + throw new CustomException("USER_ID", "Staff with the given user id: " + staffPermissionFromRequest.getUserId() + " is not linked with the given register id");//handled + if (staffDeenrolled) + throw new CustomException("USER_ID", "Staff with the given user id : " + staffPermissionFromRequest.getUserId() + " is already de enrolled from the register"); + } + + + //staff list size associated with the register (At least one staff should remain with a register before de enrollment) + //initialize request and DB hashmaps with registerId as key + log.info("checking that atleast one staff should remain enrolled to a register before de enrollment"); + HashMap staffCountInEachRegisterIdFromRequest = new HashMap<>(); + HashMap staffCountInEachRegisterIdFromDB = new HashMap<>(); + for (AttendanceRegister attendanceRegister : attendanceRegisterListFromDB) { + staffCountInEachRegisterIdFromRequest.put(attendanceRegister.getId().toString(), 0); + staffCountInEachRegisterIdFromDB.put(attendanceRegister.getId().toString(), 0); + } + + + // from staffRequest - number of de enrollments from each register + for (StaffPermission staffPermissionFromRequest : staffPermissionListFromRequest) { + String staffRegisterId = staffPermissionFromRequest.getRegisterId(); + if (staffCountInEachRegisterIdFromRequest.containsKey(staffRegisterId)) { + int count = staffCountInEachRegisterIdFromRequest.get(staffRegisterId); + count++; + staffCountInEachRegisterIdFromRequest.put(staffRegisterId, count); + } + } + + + // from StaffDB data number of staff enrolled to each register in db + for (StaffPermission staffPermissionFromDB : staffPermissionListFromDB) { + String staffRegisterId = staffPermissionFromDB.getRegisterId(); + if (staffCountInEachRegisterIdFromDB.containsKey(staffRegisterId) && staffPermissionFromDB.getDenrollmentDate() == null) { + int count = staffCountInEachRegisterIdFromDB.get(staffRegisterId); + count++; + staffCountInEachRegisterIdFromDB.put(staffRegisterId, count); + } + } + + //match the regitser ids between request and db. subtract the staff, If <1 throw error + for (String registerId : staffCountInEachRegisterIdFromRequest.keySet()) { + if (staffCountInEachRegisterIdFromDB.containsKey(registerId)) { + int result = staffCountInEachRegisterIdFromDB.get(registerId) - staffCountInEachRegisterIdFromRequest.get(registerId); + if (result < 1) { + throw new CustomException("MIN_STAFF_REQUIRED", "Atleast one staff should be associated" + + "with the register. Number of staff in register id : " + registerId + " after de enrollment operation would be " + result); + } + } + } + } + + + private void validateMDMSData(String tenantId, Object mdmsData, Map errorMap) { + final String jsonPathForTenants = "$.MdmsRes." + MDMS_TENANT_MODULE_NAME + "." + MASTER_TENANTS + ".*"; + + List tenantRes = null; + try { + tenantRes = JsonPath.read(mdmsData, jsonPathForTenants); + } catch (Exception e) { + log.error(e.getMessage()); + throw new CustomException("JSONPATH_ERROR", "Failed to parse mdms response"); + } + + if (CollectionUtils.isEmpty(tenantRes)) + errorMap.put("INVALID_TENANT", "The tenant: " + tenantId + " is not present in MDMS"); + } + + +} diff --git a/core-services/attendance/src/main/java/org/egov/web/controllers/AttendanceApiController.java b/core-services/attendance/src/main/java/org/egov/web/controllers/AttendanceApiController.java new file mode 100644 index 00000000000..23a4b0ef330 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/controllers/AttendanceApiController.java @@ -0,0 +1,75 @@ +package org.egov.web.controllers; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.RequestInfoWrapper; +import io.swagger.annotations.ApiParam; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.service.AttendanceRegisterService; +import org.egov.util.ResponseInfoFactory; +import org.egov.web.models.AttendanceRegister; +import org.egov.web.models.AttendanceRegisterRequest; +import org.egov.web.models.AttendanceRegisterResponse; +import org.egov.web.models.AttendanceRegisterSearchCriteria; +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.ModelAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +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 = "2022-11-14T14:44:21.051+05:30") + +@Controller +@RequestMapping("/v1") +public class AttendanceApiController { + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private HttpServletRequest request; + + @Autowired + private ResponseInfoFactory responseInfoCreator; + + @Autowired + private AttendanceRegisterService attendanceRegisterService; + @Autowired + private ResponseInfoFactory responseInfoFactory; + + @RequestMapping(value = "/_create", method = RequestMethod.POST) + public ResponseEntity createAttendanceRegister(@ApiParam(value = "", allowableValues = "application/json") @RequestHeader(value = "Content-Type", required = false) String contentType, @ApiParam(value = "") @Valid @RequestBody AttendanceRegisterRequest attendanceRegisterRequest) { + AttendanceRegisterRequest enrichedAttendanceRegisterRequest = attendanceRegisterService.createAttendanceRegister(attendanceRegisterRequest); + + ResponseInfo responseInfo = responseInfoFactory.createResponseInfoFromRequestInfo(attendanceRegisterRequest.getRequestInfo(), true); + AttendanceRegisterResponse attendanceRegisterResponse = AttendanceRegisterResponse.builder().responseInfo(responseInfo).attendanceRegister(enrichedAttendanceRegisterRequest.getAttendanceRegister()).build(); + return new ResponseEntity(attendanceRegisterResponse, HttpStatus.OK); + } + + @RequestMapping(value = "/_search", method = RequestMethod.POST) + public ResponseEntity searchAttendanceRegister(@Valid @ModelAttribute AttendanceRegisterSearchCriteria searchCriteria, @Valid @RequestBody RequestInfoWrapper requestInfoWrapper) { + List attendanceRegisterList = attendanceRegisterService.searchAttendanceRegister(requestInfoWrapper, searchCriteria); + ResponseInfo responseInfo = responseInfoCreator.createResponseInfoFromRequestInfo(requestInfoWrapper.getRequestInfo(), true); + AttendanceRegisterResponse attendanceRegisterResponse = AttendanceRegisterResponse.builder().responseInfo(responseInfo).attendanceRegister(attendanceRegisterList).build(); + return new ResponseEntity(attendanceRegisterResponse, HttpStatus.OK); + } + + @RequestMapping(value = "/_update", method = RequestMethod.POST) + public ResponseEntity updateAttendanceRegister(@ApiParam(value = "", allowableValues = "application/json") @RequestHeader(value = "Content-Type", required = false) String contentType, @ApiParam(value = "") @Valid @RequestBody AttendanceRegisterRequest attendanceRegisterRequest) { + AttendanceRegisterRequest enrichedAttendanceRegisterRequest = attendanceRegisterService.updateAttendanceRegister(attendanceRegisterRequest); + + ResponseInfo responseInfo = responseInfoFactory.createResponseInfoFromRequestInfo(attendanceRegisterRequest.getRequestInfo(), true); + AttendanceRegisterResponse attendanceRegisterResponse = AttendanceRegisterResponse.builder().responseInfo(responseInfo).attendanceRegister(enrichedAttendanceRegisterRequest.getAttendanceRegister()).build(); + return new ResponseEntity(attendanceRegisterResponse, HttpStatus.OK); + } + + +} diff --git a/core-services/attendance/src/main/java/org/egov/web/controllers/AttendanceLogApiController.java b/core-services/attendance/src/main/java/org/egov/web/controllers/AttendanceLogApiController.java new file mode 100644 index 00000000000..1deab99977a --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/controllers/AttendanceLogApiController.java @@ -0,0 +1,55 @@ +package org.egov.web.controllers; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.annotations.ApiParam; +import org.egov.service.AttendanceLogService; +import org.egov.web.models.AttendanceLogRequest; +import org.egov.web.models.AttendanceLogResponse; +import org.egov.web.models.AttendanceLogSearchCriteria; +import org.egov.web.models.RequestInfoWrapper; +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.ModelAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; + +@Controller +@RequestMapping("/log/v1") +public class AttendanceLogApiController { + + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private HttpServletRequest request; + + @Autowired + private AttendanceLogService attendanceLogService; + + @RequestMapping(value = "/_create", method = RequestMethod.POST) + public ResponseEntity attendanceLogV1CreatePOST(@ApiParam(value = "", allowableValues = "application/json") @RequestHeader(value = "Content-Type", required = false) String contentType, @ApiParam(value = "") @Valid @RequestBody AttendanceLogRequest attendanceLogRequest) { + AttendanceLogResponse attendanceLogResponse = attendanceLogService.createAttendanceLog(attendanceLogRequest); + return new ResponseEntity(attendanceLogResponse, HttpStatus.OK); + } + + @RequestMapping(value = "/_search", method = RequestMethod.POST) + public ResponseEntity attendanceLogV1SearchPOST(@Valid @ModelAttribute AttendanceLogSearchCriteria searchCriteria, @ApiParam(value = "") @Valid @RequestBody RequestInfoWrapper requestInfoWrapper) { + AttendanceLogResponse attendanceLogResponse = attendanceLogService.searchAttendanceLog(requestInfoWrapper, searchCriteria); + return new ResponseEntity(attendanceLogResponse, HttpStatus.OK); + } + + @RequestMapping(value = "/_update", method = RequestMethod.POST) + public ResponseEntity attendanceLogV1UpdatePOST(@ApiParam(value = "", allowableValues = "application/json") @RequestHeader(value = "Content-Type", required = false) String contentType, @ApiParam(value = "") @Valid @RequestBody AttendanceLogRequest attendanceLogRequest) { + AttendanceLogResponse attendanceLogResponse = attendanceLogService.updateAttendanceLog(attendanceLogRequest); + return new ResponseEntity(attendanceLogResponse, HttpStatus.OK); + } + +} diff --git a/core-services/attendance/src/main/java/org/egov/web/controllers/AttendeeApiController.java b/core-services/attendance/src/main/java/org/egov/web/controllers/AttendeeApiController.java new file mode 100644 index 00000000000..60844961927 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/controllers/AttendeeApiController.java @@ -0,0 +1,57 @@ +package org.egov.web.controllers; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.annotations.ApiParam; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.service.AttendeeService; +import org.egov.util.ResponseInfoFactory; +import org.egov.web.models.AttendeeCreateRequest; +import org.egov.web.models.AttendeeCreateResponse; +import org.egov.web.models.AttendeeDeleteRequest; +import org.egov.web.models.AttendeeDeleteResponse; +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.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; + +@Controller +@RequestMapping("/attendee/v1") +public class AttendeeApiController { + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private HttpServletRequest request; + + @Autowired + private AttendeeService attendeeService; + + @Autowired + private ResponseInfoFactory responseInfoFactory; + + @RequestMapping(value = "/_create", method = RequestMethod.POST) + public ResponseEntity createAttendee(@ApiParam(value = "", allowableValues = "application/json") @RequestHeader(value = "Content-Type", required = false) String contentType, @ApiParam(value = "") @Valid @RequestBody AttendeeCreateRequest attendeeCreateRequest) { + AttendeeCreateRequest enrichedRequest = attendeeService.createAttendee(attendeeCreateRequest); + ResponseInfo responseInfo = responseInfoFactory.createResponseInfoFromRequestInfo(attendeeCreateRequest.getRequestInfo(), true); + AttendeeCreateResponse attendeeCreateResponse = AttendeeCreateResponse.builder().responseInfo(responseInfo).attendees(enrichedRequest.getAttendees()).build(); + return new ResponseEntity(attendeeCreateResponse, HttpStatus.OK); + } + + + @RequestMapping(value = "/_delete", method = RequestMethod.POST) + public ResponseEntity deleteAttendee(@ApiParam(value = "", allowableValues = "application/json") @RequestHeader(value = "Content-Type", required = false) String contentType, @ApiParam(value = "") @Valid @RequestBody AttendeeDeleteRequest attendeeDeleteRequest) { + AttendeeDeleteRequest enrichedRequest = attendeeService.deleteAttendee(attendeeDeleteRequest); + ResponseInfo responseInfo = responseInfoFactory.createResponseInfoFromRequestInfo(attendeeDeleteRequest.getRequestInfo(), true); + AttendeeDeleteResponse attendeeDeleteResponse = AttendeeDeleteResponse.builder().responseInfo(responseInfo).attendees(enrichedRequest.getAttendees()).build(); + return new ResponseEntity(attendeeDeleteResponse, HttpStatus.OK); + } + +} diff --git a/core-services/attendance/src/main/java/org/egov/web/controllers/StaffApiController.java b/core-services/attendance/src/main/java/org/egov/web/controllers/StaffApiController.java new file mode 100644 index 00000000000..523fdeddb77 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/controllers/StaffApiController.java @@ -0,0 +1,57 @@ +package org.egov.web.controllers; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.annotations.ApiParam; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.service.StaffService; +import org.egov.util.ResponseInfoFactory; +import org.egov.web.models.StaffPermissionRequest; +import org.egov.web.models.StaffPermissionResponse; +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.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; + +@Controller +@RequestMapping("/staff/v1") +public class StaffApiController { + + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private HttpServletRequest request; + + @Autowired + private StaffService staffService; + + @Autowired + private ResponseInfoFactory responseInfoFactory; + + @RequestMapping(value = "/_create", method = RequestMethod.POST) + public ResponseEntity createStaff(@ApiParam(value = "", allowableValues = "application/json") @RequestHeader(value = "Content-Type", required = false) String contentType, @ApiParam(value = "") @Valid @RequestBody StaffPermissionRequest staffPermissionRequest) { + StaffPermissionRequest enrichedRequest = staffService.createAttendanceStaff(staffPermissionRequest, false); + ResponseInfo responseInfo = responseInfoFactory.createResponseInfoFromRequestInfo(staffPermissionRequest.getRequestInfo(), true); + StaffPermissionResponse staffPermissionResponse = StaffPermissionResponse.builder().responseInfo(responseInfo) + .staff(enrichedRequest.getStaff()).build(); + return new ResponseEntity(staffPermissionResponse, HttpStatus.OK); + } + + @RequestMapping(value = "/_delete", method = RequestMethod.POST) + public ResponseEntity deleteStaff(@ApiParam(value = "", allowableValues = "application/json") @RequestHeader(value = "Content-Type", required = false) String contentType, @ApiParam(value = "") @Valid @RequestBody StaffPermissionRequest staffPermissionRequest) { + StaffPermissionRequest enrichedRequest = staffService.deleteAttendanceStaff(staffPermissionRequest); + ResponseInfo responseInfo = responseInfoFactory.createResponseInfoFromRequestInfo(staffPermissionRequest.getRequestInfo(), true); + StaffPermissionResponse staffPermissionResponse = StaffPermissionResponse.builder().responseInfo(responseInfo) + .staff(enrichedRequest.getStaff()).build(); + return new ResponseEntity(staffPermissionResponse, HttpStatus.OK); + } + +} diff --git a/core-services/attendance/src/main/java/org/egov/web/models/AttendanceLog.java b/core-services/attendance/src/main/java/org/egov/web/models/AttendanceLog.java new file mode 100644 index 00000000000..1da8c810f6e --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/AttendanceLog.java @@ -0,0 +1,70 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +/** + * AttendanceLog + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-11-14T14:44:21.051+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AttendanceLog { + @JsonProperty("id") + private String id = null; + + @JsonProperty("registerId") + private String registerId = null; + + @JsonProperty("individualId") + private String individualId = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("time") + private BigDecimal time = null; + + @JsonProperty("type") + private String type = null; + + @JsonProperty("status") + private Status status = null; + + @JsonProperty("documentIds") + @Valid + private List documentIds = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + + public AttendanceLog addDocumentIdsItem(Document documentIdsItem) { + if (this.documentIds == null) { + this.documentIds = new ArrayList<>(); + } + this.documentIds.add(documentIdsItem); + return this; + } + +} + diff --git a/core-services/attendance/src/main/java/org/egov/web/models/AttendanceLogRequest.java b/core-services/attendance/src/main/java/org/egov/web/models/AttendanceLogRequest.java new file mode 100644 index 00000000000..d401167a257 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/AttendanceLogRequest.java @@ -0,0 +1,45 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * AttendanceLogRequest + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-11-14T14:44:21.051+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AttendanceLogRequest { + @JsonProperty("RequestInfo") + private RequestInfo requestInfo = null; + + @JsonProperty("attendance") + @Valid + private List attendance = null; + + + public AttendanceLogRequest addAttendanceItem(AttendanceLog attendanceItem) { + if (this.attendance == null) { + this.attendance = new ArrayList<>(); + } + this.attendance.add(attendanceItem); + return this; + } + +} + diff --git a/core-services/attendance/src/main/java/org/egov/web/models/AttendanceLogResponse.java b/core-services/attendance/src/main/java/org/egov/web/models/AttendanceLogResponse.java new file mode 100644 index 00000000000..fe581e7f350 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/AttendanceLogResponse.java @@ -0,0 +1,45 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * AttendanceLogResponse + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-11-14T14:44:21.051+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AttendanceLogResponse { + @JsonProperty("ResponseInfo") + private ResponseInfo responseInfo = null; + + @JsonProperty("attendance") + @Valid + private List attendance = null; + + + public AttendanceLogResponse addAttendanceItem(AttendanceLog attendanceItem) { + if (this.attendance == null) { + this.attendance = new ArrayList<>(); + } + this.attendance.add(attendanceItem); + return this; + } + +} + diff --git a/core-services/attendance/src/main/java/org/egov/web/models/AttendanceLogSearchCriteria.java b/core-services/attendance/src/main/java/org/egov/web/models/AttendanceLogSearchCriteria.java new file mode 100644 index 00000000000..77c80abec1c --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/AttendanceLogSearchCriteria.java @@ -0,0 +1,62 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.math.BigDecimal; +import java.util.List; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AttendanceLogSearchCriteria { + + @JsonProperty("ids") + private List ids; + + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("registerId") + private String registerId; + + @JsonProperty("fromTime") + private BigDecimal fromTime; + + @JsonProperty("toTime") + private BigDecimal toTime; + + @JsonProperty("individualIds") + private List individualIds; + + @JsonProperty("status") + private Status status; + + @JsonProperty("limit") + private Integer limit; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("sortBy") + private SortBy sortBy; + + @JsonProperty("sortOrder") + private SortOrder sortOrder; + + public enum SortOrder { + ASC, + DESC + } + + public enum SortBy { + lastModifiedTime + } + +} diff --git a/core-services/attendance/src/main/java/org/egov/web/models/AttendanceRegister.java b/core-services/attendance/src/main/java/org/egov/web/models/AttendanceRegister.java new file mode 100644 index 00000000000..74d3af82333 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/AttendanceRegister.java @@ -0,0 +1,88 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +/** + * AttendanceRegister + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-11-14T14:44:21.051+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AttendanceRegister { + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("registerNumber") + private String registerNumber = null; + + @JsonProperty("name") + private String name = null; + + @JsonProperty("referenceId") + private String referenceId; + + @JsonProperty("serviceCode") + private String serviceCode; + + @JsonProperty("startDate") + private BigDecimal startDate = null; + + @JsonProperty("endDate") + private BigDecimal endDate = null; + + @JsonProperty("status") + private Status status = Status.ACTIVE; + + @JsonProperty("staff") + @Valid + private List staff = null; + + @JsonProperty("attendees") + @Valid + private List attendees = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + + public AttendanceRegister addStaffItem(StaffPermission staffItem) { + if (this.staff == null) { + this.staff = new ArrayList<>(); + } + this.staff.add(staffItem); + return this; + } + + public AttendanceRegister addAttendeesItem(IndividualEntry attendeesItem) { + if (this.attendees == null) { + this.attendees = new ArrayList<>(); + } + this.attendees.add(attendeesItem); + return this; + } + +} + diff --git a/core-services/attendance/src/main/java/org/egov/web/models/AttendanceRegisterRequest.java b/core-services/attendance/src/main/java/org/egov/web/models/AttendanceRegisterRequest.java new file mode 100644 index 00000000000..593402b649d --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/AttendanceRegisterRequest.java @@ -0,0 +1,34 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +/** + * AttendanceRegisterRequest + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-11-14T14:44:21.051+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AttendanceRegisterRequest { + @JsonProperty("RequestInfo") + private RequestInfo requestInfo = null; + + @JsonProperty("attendanceRegister") + private List attendanceRegister = null; + + +} + diff --git a/core-services/attendance/src/main/java/org/egov/web/models/AttendanceRegisterResponse.java b/core-services/attendance/src/main/java/org/egov/web/models/AttendanceRegisterResponse.java new file mode 100644 index 00000000000..022f6fdf109 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/AttendanceRegisterResponse.java @@ -0,0 +1,45 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * AttendanceRegisterResponse + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-11-14T14:44:21.051+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AttendanceRegisterResponse { + @JsonProperty("ResponseInfo") + private ResponseInfo responseInfo = null; + + @JsonProperty("attendanceRegister") + @Valid + private List attendanceRegister = null; + + + public AttendanceRegisterResponse addAttendanceRegisterItem(AttendanceRegister attendanceRegisterItem) { + if (this.attendanceRegister == null) { + this.attendanceRegister = new ArrayList<>(); + } + this.attendanceRegister.add(attendanceRegisterItem); + return this; + } + +} + diff --git a/core-services/attendance/src/main/java/org/egov/web/models/AttendanceRegisterSearchCriteria.java b/core-services/attendance/src/main/java/org/egov/web/models/AttendanceRegisterSearchCriteria.java new file mode 100644 index 00000000000..06869e833a3 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/AttendanceRegisterSearchCriteria.java @@ -0,0 +1,79 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +import java.math.BigDecimal; +import java.util.List; + + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ToString +public class AttendanceRegisterSearchCriteria { + + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("ids") + private List ids; + + @JsonProperty("registerNumber") + private String registerNumber; + + @JsonProperty("name") + private String name; + + @JsonProperty("fromDate") + private BigDecimal fromDate; + + @JsonProperty("toDate") + private BigDecimal toDate; + + @JsonProperty("status") + private Status status; + + @JsonProperty("attendeeId") + private String attendeeId; + + @JsonProperty("staffId") + private String staffId; + + @JsonProperty("referenceId") + private String referenceId; + + @JsonProperty("serviceCode") + private String serviceCode; + + @JsonProperty("limit") + private Integer limit; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("sortBy") + private SortBy sortBy; + + @JsonProperty("sortOrder") + private SortOrder sortOrder; + + public enum SortOrder { + ASC, + DESC + } + + public enum SortBy { + lastModifiedTime, + fromDate, + toDate + } + +} diff --git a/core-services/attendance/src/main/java/org/egov/web/models/AttendeeCreateRequest.java b/core-services/attendance/src/main/java/org/egov/web/models/AttendeeCreateRequest.java new file mode 100644 index 00000000000..bbb9ef4ab24 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/AttendeeCreateRequest.java @@ -0,0 +1,44 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * AttendeeCreateRequest + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-11-14T14:44:21.051+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AttendeeCreateRequest { + @JsonProperty("RequestInfo") + private RequestInfo requestInfo = null; + + @JsonProperty("attendees") + @Valid + private List attendees = null; + + public AttendeeCreateRequest addAttendeesItem(IndividualEntry attendeesItem) { + if (this.attendees == null) { + this.attendees = new ArrayList<>(); + } + this.attendees.add(attendeesItem); + return this; + } + +} + diff --git a/core-services/attendance/src/main/java/org/egov/web/models/AttendeeCreateResponse.java b/core-services/attendance/src/main/java/org/egov/web/models/AttendeeCreateResponse.java new file mode 100644 index 00000000000..4a9745c8ccf --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/AttendeeCreateResponse.java @@ -0,0 +1,45 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * AttendeeCreateResponse + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-11-14T14:44:21.051+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AttendeeCreateResponse { + @JsonProperty("ResponseInfo") + private ResponseInfo responseInfo = null; + + @JsonProperty("attendees") + @Valid + private List attendees = null; + + + public AttendeeCreateResponse addAttendeesItem(IndividualEntry attendeesItem) { + if (this.attendees == null) { + this.attendees = new ArrayList<>(); + } + this.attendees.add(attendeesItem); + return this; + } + +} + diff --git a/core-services/attendance/src/main/java/org/egov/web/models/AttendeeDeleteRequest.java b/core-services/attendance/src/main/java/org/egov/web/models/AttendeeDeleteRequest.java new file mode 100644 index 00000000000..48e7def64a2 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/AttendeeDeleteRequest.java @@ -0,0 +1,44 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * AttendeeDeleteRequest + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-11-14T14:44:21.051+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AttendeeDeleteRequest { + @JsonProperty("RequestInfo") + private RequestInfo requestInfo = null; + + @JsonProperty("attendees") + @Valid + private List attendees = null; + + public AttendeeDeleteRequest addAttendeesItem(IndividualEntry attendeesItem) { + if (this.attendees == null) { + this.attendees = new ArrayList<>(); + } + this.attendees.add(attendeesItem); + return this; + } + +} + diff --git a/core-services/attendance/src/main/java/org/egov/web/models/AttendeeDeleteResponse.java b/core-services/attendance/src/main/java/org/egov/web/models/AttendeeDeleteResponse.java new file mode 100644 index 00000000000..89fce4ccc4f --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/AttendeeDeleteResponse.java @@ -0,0 +1,45 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * AttendeeDeleteResponse + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-11-14T14:44:21.051+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AttendeeDeleteResponse { + @JsonProperty("ResponseInfo") + private ResponseInfo responseInfo; + + @JsonProperty("attendees") + @Valid + private List attendees = null; + + + public AttendeeDeleteResponse addAttendeesItem(IndividualEntry attendeesItem) { + if (this.attendees == null) { + this.attendees = new ArrayList<>(); + } + this.attendees.add(attendeesItem); + return this; + } + +} + diff --git a/core-services/attendance/src/main/java/org/egov/web/models/AttendeeSearchCriteria.java b/core-services/attendance/src/main/java/org/egov/web/models/AttendeeSearchCriteria.java new file mode 100644 index 00000000000..41be1e2e04d --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/AttendeeSearchCriteria.java @@ -0,0 +1,40 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.math.BigDecimal; +import java.util.List; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AttendeeSearchCriteria { + + @JsonProperty("ids") + private List ids; + + @JsonProperty("individualIds") + private List individualIds; + + @JsonProperty("registerIds") + private List registerIds; + + @JsonProperty("enrollmentDate") + private BigDecimal enrollmentDate = null; + + @JsonProperty("denrollmentDate") + private BigDecimal denrollmentDate = null; + + @JsonProperty("limit") + private Integer limit; + + @JsonProperty("offset") + private Integer offset; +} diff --git a/core-services/attendance/src/main/java/org/egov/web/models/Document.java b/core-services/attendance/src/main/java/org/egov/web/models/Document.java new file mode 100644 index 00000000000..3dbbde0be74 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/Document.java @@ -0,0 +1,34 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Document { + @JsonProperty("id") + private String id = null; + + @JsonProperty("documentType") + private String documentType = null; + + @JsonProperty("fileStore") + private String fileStore = null; + + @JsonProperty("documentUid") + private String documentUid = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("status") + @Builder.Default + private Status status = Status.ACTIVE; +} \ No newline at end of file diff --git a/core-services/attendance/src/main/java/org/egov/web/models/IndividualEntry.java b/core-services/attendance/src/main/java/org/egov/web/models/IndividualEntry.java new file mode 100644 index 00000000000..4c85d144de7 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/IndividualEntry.java @@ -0,0 +1,52 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; + +/** + * IndividualEntry + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-11-14T14:44:21.051+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class IndividualEntry { + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("registerId") + private String registerId = null; + + @JsonProperty("individualId") + private String individualId = null; + + @JsonProperty("enrollmentDate") + private BigDecimal enrollmentDate = null; + + @JsonProperty("denrollmentDate") + private BigDecimal denrollmentDate = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + +} + diff --git a/core-services/attendance/src/main/java/org/egov/web/models/Organisation/ContactDetails.java b/core-services/attendance/src/main/java/org/egov/web/models/Organisation/ContactDetails.java new file mode 100644 index 00000000000..da1b95c2785 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/Organisation/ContactDetails.java @@ -0,0 +1,83 @@ +package org.egov.web.models.Organisation; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.models.core.Role; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.Size; +import java.util.List; + +/** + * Captures details of a contact person + */ +@ApiModel(description = "Captures details of a contact person") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-15T14:49:42.141+05:30") + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ContactDetails { + + @JsonProperty("id") + @Valid + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("individualId") + private String individualId = null; + + @JsonProperty("orgId") + private String orgId = null; + + @JsonProperty("contactName") + @Size(min = 2, max = 64) + private String contactName = null; + + @JsonProperty("contactMobileNumber") + @Size(max = 20) + private String contactMobileNumber = null; + + @JsonProperty("contactEmail") + @Size(min = 5, max = 200) + private String contactEmail = null; + + @JsonProperty("active") + private Boolean active; + + @JsonProperty("roles") + @Valid + private List roles; + + @Size(max=50) + @JsonProperty("type") + private String type; + + @Size(max=64) + //@DiffIgnore + @JsonProperty("createdBy") + private String createdBy; + + //@DiffIgnore + @JsonProperty("createdDate") + private Long createdDate; + + @Size(max=64) + //@DiffIgnore + @JsonProperty("lastModifiedBy") + private String lastModifiedBy; + + //@DiffIgnore + @JsonProperty("lastModifiedDate") + private Long lastModifiedDate; + +} diff --git a/core-services/attendance/src/main/java/org/egov/web/models/Organisation/OrgContactUpdateDiff.java b/core-services/attendance/src/main/java/org/egov/web/models/Organisation/OrgContactUpdateDiff.java new file mode 100644 index 00000000000..aa4a91ee880 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/Organisation/OrgContactUpdateDiff.java @@ -0,0 +1,29 @@ +package org.egov.web.models.Organisation; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class OrgContactUpdateDiff { + + @JsonProperty("RequestInfo") + private RequestInfo requestInfo; + + private String tenantId; + + private String organisationId; + + private List oldContacts; + + private List newContacts; + +} diff --git a/core-services/attendance/src/main/java/org/egov/web/models/RequestInfoWrapper.java b/core-services/attendance/src/main/java/org/egov/web/models/RequestInfoWrapper.java new file mode 100644 index 00000000000..b503df65e07 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/RequestInfoWrapper.java @@ -0,0 +1,29 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * RequestInfoWrapper + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-11-14T14:44:21.051+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class RequestInfoWrapper { + @JsonProperty("RequestInfo") + private RequestInfo requestInfo = null; + + +} + diff --git a/core-services/attendance/src/main/java/org/egov/web/models/StaffPermission.java b/core-services/attendance/src/main/java/org/egov/web/models/StaffPermission.java new file mode 100644 index 00000000000..428926f22c0 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/StaffPermission.java @@ -0,0 +1,52 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; + +/** + * StaffPermission + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-11-14T14:44:21.051+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class StaffPermission { + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("registerId") + private String registerId = null; + + @JsonProperty("userId") + private String userId = null; + + @JsonProperty("enrollmentDate") + private BigDecimal enrollmentDate = null; + + @JsonProperty("denrollmentDate") + private BigDecimal denrollmentDate = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + +} + diff --git a/core-services/attendance/src/main/java/org/egov/web/models/StaffPermissionRequest.java b/core-services/attendance/src/main/java/org/egov/web/models/StaffPermissionRequest.java new file mode 100644 index 00000000000..09a2d4e91d6 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/StaffPermissionRequest.java @@ -0,0 +1,34 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +/** + * StaffPermissionRequest + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-11-14T14:44:21.051+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class StaffPermissionRequest { + @JsonProperty("RequestInfo") + private RequestInfo requestInfo = null; + + @JsonProperty("staff") + private List staff = null; + + +} + diff --git a/core-services/attendance/src/main/java/org/egov/web/models/StaffPermissionResponse.java b/core-services/attendance/src/main/java/org/egov/web/models/StaffPermissionResponse.java new file mode 100644 index 00000000000..c3dd6c40fa8 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/StaffPermissionResponse.java @@ -0,0 +1,34 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +/** + * StaffPermissionResponse + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-11-14T14:44:21.051+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class StaffPermissionResponse { + @JsonProperty("ResponseInfo") + private ResponseInfo responseInfo = null; + + @JsonProperty("staff") + private List staff = null; + + +} + diff --git a/core-services/attendance/src/main/java/org/egov/web/models/StaffSearchCriteria.java b/core-services/attendance/src/main/java/org/egov/web/models/StaffSearchCriteria.java new file mode 100644 index 00000000000..e83287100e5 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/StaffSearchCriteria.java @@ -0,0 +1,33 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.List; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class StaffSearchCriteria { + + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("individualIds") + private List individualIds; + + @JsonProperty("registerIds") + private List registerIds; + + @JsonProperty("limit") + private Integer limit; + + @JsonProperty("offset") + private Integer offset; +} diff --git a/core-services/attendance/src/main/java/org/egov/web/models/Status.java b/core-services/attendance/src/main/java/org/egov/web/models/Status.java new file mode 100644 index 00000000000..1f86601f113 --- /dev/null +++ b/core-services/attendance/src/main/java/org/egov/web/models/Status.java @@ -0,0 +1,37 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Stores if the register is active or not. Inactive registers can be archieved later. + */ +public enum Status { + + ACTIVE("ACTIVE"), + + INACTIVE("INACTIVE"); + + private final String value; + + Status(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static Status fromValue(String text) { + for (Status b : Status.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} + diff --git a/core-services/attendance/src/main/resources/Attendace Service Postman Scripts.postman_scripts_collection.json b/core-services/attendance/src/main/resources/Attendace Service Postman Scripts.postman_scripts_collection.json new file mode 100644 index 00000000000..d27e9f0effc --- /dev/null +++ b/core-services/attendance/src/main/resources/Attendace Service Postman Scripts.postman_scripts_collection.json @@ -0,0 +1,3671 @@ +{ + "info": { + "_postman_id": "25632b98-5918-4908-8a85-9500d8a81afa", + "name": "Attendace Service Postman Scripts", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Attendance Register", + "item": [ + { + "name": "Create Attendance Register - Success - Single Register", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendance Registers are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendanceRegister).to.not.be.undefined;", + " pm.expect(req.attendanceRegister).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.tenantId).to.be.not.null;", + " pm.expect(register.tenantId).to.be.not.undefined;", + " pm.expect(register.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Register Name is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.name).to.be.not.null;", + " pm.expect(register.name).to.be.not.undefined;", + " pm.expect(register.name).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Register start date is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.startDate).to.be.not.null;", + " pm.expect(register.startDate).to.be.not.undefined;", + " pm.expect(register.startDate).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Start date should be less than end date\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " if (Number.isFinite(register.endDate) && (register.endDate != undefined || register.endDate != null )) {", + " pm.expect(register.endDate).to.be.not.below(register.startDate);", + " }", + " }", + ");", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Register Number is enriched\", function () {", + " var res = pm.response.json();", + " var registerNumber = res.attendanceRegister[0].registerNumber;", + " pm.expect(registerNumber.substring(0,2)).to.eql(\"WR\");", + " }", + ");", + "", + "pm.test(\"Register status is set to Active if status not passed\", function () {", + " var res = pm.response.json();", + " var status = res.attendanceRegister[0].status;", + " pm.expect(status).to.eql(\"ACTIVE\");", + " }", + ");", + "", + "pm.test(\"Staff is created for register\", function () {", + " var res = pm.response.json();", + " var staff = res.attendanceRegister[0].staff;", + " pm.expect(staff).to.be.not.null;", + " pm.expect(staff).to.be.not.undefined;", + " pm.expect(staff.length).to.eql(1);", + " }", + ");", + "", + "pm.test(\"Staff created have same userId as UUID of user\", function () {", + " var res = pm.response.json();", + " var userInRequest = res.attendanceRegister[0].auditDetails.createdBy;", + " var staff = res.attendanceRegister[0].staff;", + " pm.expect(staff[0].userId).to.eql(userInRequest);", + " }", + ");", + "", + "let responseData = pm.response.json();", + "pm.collectionVariables.set(\"tenantId\", responseData.attendanceRegister[0].tenantId);", + "pm.collectionVariables.set(\"stateLevelTenant\", responseData.attendanceRegister[0].tenantId.split('.', 1)[0]);", + "pm.collectionVariables.set(\"registerId\", responseData.attendanceRegister[0].id);", + "pm.collectionVariables.set(\"registerNumber\", responseData.attendanceRegister[0].registerNumber);", + "", + "pm.collectionVariables.set(\"registerStartDate\", responseData.attendanceRegister[0].startDate);", + "pm.collectionVariables.set(\"registerEndDate\", responseData.attendanceRegister[0].endDate);", + "pm.collectionVariables.set(\"invalidRegisterEndDate\", responseData.attendanceRegister[0].endDate+24*60*60*1000);" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "pm.collectionVariables.set(\"tenantId\", \"pb.amritsar\");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_01\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Success - Multiple Registers", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendance Registers are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendanceRegister).to.not.be.undefined;", + " pm.expect(req.attendanceRegister).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.tenantId).to.be.not.null;", + " pm.expect(register.tenantId).to.be.not.undefined;", + " pm.expect(register.tenantId).not.to.eql(\"\");", + " });", + " }", + ");", + "", + "pm.test(\"Register Name is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.name).to.be.not.null;", + " pm.expect(register.name).to.be.not.undefined;", + " pm.expect(register.name).not.to.eql(\"\");", + " });", + " }", + ");", + "", + "pm.test(\"Register start date is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.startDate).to.be.not.null;", + " pm.expect(register.startDate).to.be.not.undefined;", + " pm.expect(register.startDate).not.to.eql(\"\");", + " });", + " }", + ");", + " ", + "", + "pm.test(\"Start date should be less than end date\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " if (Number.isFinite(register.endDate) && (register.endDate != undefined || register.endDate != null )) {", + " pm.expect(register.endDate).to.be.not.below(register.startDate);", + " }", + " });", + " }", + ");", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Register Number is enriched\", function () {", + " var res = pm.response.json();", + " res.attendanceRegister.forEach(register => {", + " var registerNumber = register.registerNumber;", + " pm.expect(registerNumber.substring(0,2)).to.eql(\"WR\");", + " });", + " }", + ");", + "", + "pm.test(\"Staff is created for register\", function () {", + " var res = pm.response.json();", + " res.attendanceRegister.forEach(register => {", + " var staff = register.staff;", + " pm.expect(staff).to.be.not.null;", + " pm.expect(staff).to.be.not.undefined;", + " pm.expect(staff.length).to.eql(1);", + " }); ", + " }", + ");", + "", + "pm.test(\"Staff created have same userId as UUID of user\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var res = pm.response.json();", + " res.attendanceRegister.forEach(register => {", + " var userInRequest = register.auditDetails.createdBy;", + " var staff =register.staff;", + " pm.expect(staff[0].userId).to.eql(userInRequest);", + " }); ", + " }", + ");", + "", + "let responseData = pm.response.json();", + "pm.collectionVariables.set(\"registerId2\", responseData.attendanceRegister[1].id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_01\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000\n },\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_02\",\n \"startDate\": 1640995200000,\n \"additionalDetails\": {}\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Validation Error - Registers not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"ATTENDANCE_REGISTER\");", + " pm.expect(message).to.eql(\"Attendance Register is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": []\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Validation Error - TenantId not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"TENANT_ID\");", + " pm.expect(message).to.eql(\"Tenant is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"name\": \"TestRegister_01\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Validation Error - Name not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"NAME\");", + " pm.expect(message).to.eql(\"Name is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Validation Error - Start Date not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"START_DATE\");", + " pm.expect(message).to.eql(\"Start date is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_01\",\n \"endDate\": 1703980800000\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Validation Error - Start Date greater than End Date", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"DATE\");", + " pm.expect(message).to.eql(\"Start date should be less than end date\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_01\",\n \"startDate\": 1803980800000,\n \"endDate\": 1703980800000\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Create Attendance Register - Validation Error - Start Date Equal to 0", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"START_DATE\");", + " pm.expect(message).to.eql(\"Start date is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_01\",\n \"startDate\": 0,\n \"endDate\": 1703980800000\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Success", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200)));", + "", + "pm.test(\"Register Search response is received\", function () {", + " var res = pm.response.json();", + " var id = res.attendanceRegister[0].id;", + " pm.expect(id).to.eql(pm.collectionVariables.get(\"registerId\"));", + " }", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"{{token}}\"\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?tenantId={{tenantId}}&ids={{registerId}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + }, + { + "key": "ids", + "value": "{{registerId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Success - State level tenant", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200)));", + "", + "pm.test(\"Register Search response is received\", function () {", + " var res = pm.response.json();", + " var id = res.attendanceRegister[0].id;", + " pm.expect(id).to.eql(pm.collectionVariables.get(\"registerId\"));", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"{{token}}\"\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?tenantId={{stateLevelTenant}}&ids={{registerId}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{stateLevelTenant}}" + }, + { + "key": "ids", + "value": "{{registerId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Success - Unassociated AttendeeId", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200)));", + "", + "pm.test(\"Register Search response is received\", function () {", + " var res = pm.response.json();", + " pm.expect(res.attendanceRegister.length).to.equal(0);", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"{{token}}\"\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?tenantId={{tenantId}}&ids={{registerId}}&attendeeId={{$guid}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + }, + { + "key": "ids", + "value": "{{registerId}}" + }, + { + "key": "attendeeId", + "value": "{{$guid}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Success - Unassociated StaffId", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200)));", + "", + "pm.test(\"Register Search response is received\", function () {", + " var res = pm.response.json();", + " pm.expect(res.attendanceRegister.length).to.equal(0);", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"{{token}}\"\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?tenantId={{tenantId}}&ids={{registerId}}&staffId={{$guid}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + }, + { + "key": "ids", + "value": "{{registerId}}" + }, + { + "key": "staffId", + "value": "{{$guid}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Success - SuperUser - Non existing RegisterID", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200)));", + "", + "pm.test(\"Register Search response is received\", function () {", + " var res = pm.response.json();", + " pm.expect(res.attendanceRegister.length).to.equal(0);", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"{{token}}\"\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?tenantId={{tenantId}}&ids={{$guid}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + }, + { + "key": "ids", + "value": "{{$guid}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Validation Error - Unassociated Register Id", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200)));", + "", + "pm.test(\"Register Search response is received\", function () {", + " var res = pm.response.json();", + " var code = res.attendanceRegister.length;", + " pm.expect(code).to.eql(0);", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"{{token}}\"\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?tenantId={{tenantId}}&ids=96d1055c-0251-498d-b98d-26d6c232925f", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + }, + { + "key": "ids", + "value": "96d1055c-0251-498d-b98d-26d6c232925f" + } + ] + } + }, + "response": [] + }, + { + "name": "Search Attendance Register - Validation Error - Tenant Id not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"TENANT_ID\");", + " pm.expect(message).to.eql(\"Tenant is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"action\": \"\",\n \"did\": 1,\n \"key\": \"\",\n \"msgId\": \"20170310130900|en_IN\",\n \"requesterId\": \"\",\n \"ts\": 1513579888683,\n \"ver\": \".01\",\n \"authToken\": \"{{token}}\"\n }\n}\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_search?ids={{registerId}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_search" + ], + "query": [ + { + "key": "ids", + "value": "{{registerId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Update Attendance Register - Success - Single Register", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "", + "pm.test(\"Attendance Registers are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendanceRegister).to.not.be.undefined;", + " pm.expect(req.attendanceRegister).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.tenantId).to.be.not.null;", + " pm.expect(register.tenantId).to.be.not.undefined;", + " pm.expect(register.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Register Id is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.id).to.be.not.null;", + " pm.expect(register.id).to.be.not.undefined;", + " pm.expect(register.id).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Register Name is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.name).to.be.not.null;", + " pm.expect(register.name).to.be.not.undefined;", + " pm.expect(register.name).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Register start date is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " pm.expect(register.startDate).to.be.not.null;", + " pm.expect(register.startDate).to.be.not.undefined;", + " pm.expect(register.startDate).not.to.eql(\"\");", + " }", + ");", + " ", + "", + "pm.test(\"Start date should be less than end date\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var register = req.attendanceRegister[0];", + " if (Number.isFinite(register.endDate) && (register.endDate != undefined || register.endDate != null )) {", + " pm.expect(register.endDate).to.be.not.below(register.startDate);", + " }", + " }", + ");", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Staff is created for register\", function () {", + " var res = pm.response.json();", + " var staff = res.attendanceRegister[0].staff;", + " pm.expect(staff).to.be.not.null;", + " pm.expect(staff).to.be.not.undefined;", + " pm.expect(staff.length).to.eql(1);", + " }", + ");", + "", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"id\": \"{{registerId}}\",\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_010\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000,\n \"status\": \"ACTIVE\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Update Attendance Register - Success - Multiple Registers", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "", + "pm.test(\"Attendance Registers are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendanceRegister).to.not.be.undefined;", + " pm.expect(req.attendanceRegister).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.tenantId).to.be.not.null;", + " pm.expect(register.tenantId).to.be.not.undefined;", + " pm.expect(register.tenantId).not.to.eql(\"\");", + " });", + " }", + ");", + "", + "pm.test(\"Register Id is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.id).to.be.not.null;", + " pm.expect(register.id).to.be.not.undefined;", + " pm.expect(register.id).not.to.eql(\"\");", + " });", + " }", + ");", + "", + "pm.test(\"Register Name is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.name).to.be.not.null;", + " pm.expect(register.name).to.be.not.undefined;", + " pm.expect(register.name).not.to.eql(\"\");", + " });", + " }", + ");", + "", + "pm.test(\"Register start date is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " pm.expect(register.startDate).to.be.not.null;", + " pm.expect(register.startDate).to.be.not.undefined;", + " pm.expect(register.startDate).not.to.eql(\"\");", + " });", + " }", + ");", + " ", + "", + "pm.test(\"Start date should be less than end date\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendanceRegister.forEach(register => {", + " if (Number.isFinite(register.endDate) && (register.endDate != undefined || register.endDate != null )) {", + " pm.expect(register.endDate).to.be.not.below(register.startDate);", + " }", + " });", + " }", + ");", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"id\": \"{{registerId}}\",\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_010\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000,\n \"status\": \"ACTIVE\"\n },\n {\n \"id\": \"{{registerId2}}\",\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_020\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000,\n \"status\": \"INACTIVE\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Update Attendance Register - Validation Error - Register Id not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"ATTENDANCE_REGISTER_ID\");", + " pm.expect(message).to.eql(\"Attendance register id is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_010\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000,\n \"status\": \"ACTIVE\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Update Attendance Register - Validation Error - Tenant Id not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"TENANT_ID\");", + " pm.expect(message).to.eql(\"Tenant is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"id\": \"{{registerId}}\",\n \"name\": \"TestRegister_010\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000,\n \"status\": \"ACTIVE\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Update Attendance Register - Validation Error - Name not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"NAME\");", + " pm.expect(message).to.eql(\"Name is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"id\": \"{{registerId}}\",\n \"tenantId\": \"{{tenantId}}\",\n \"startDate\": 1640995200000,\n \"endDate\": 1703980800000,\n \"status\": \"ACTIVE\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Update Attendance Register - Validation Error - Start Date not provided", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Correct Error with message and code is received\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " var message = res.Errors[0].message;", + " pm.expect(code).to.eql(\"START_DATE\");", + " pm.expect(message).to.eql(\"Start date is mandatory\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Create Attendance Register\",\n \"authToken\": \"{{token}}\"\n },\n \"attendanceRegister\": [\n {\n \"id\": \"{{registerId}}\",\n \"tenantId\": \"{{tenantId}}\",\n \"name\": \"TestRegister_010\",\n \"endDate\": 1703980800000,\n \"status\": \"ACTIVE\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "v1", + "_update" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Register Permission", + "item": [ + { + "name": "Staff - Enroll - Single Staff", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Enrollment date is enriched\", function () {", + " var res = pm.response.json();", + " var enrollmentDate = res.staff[0].enrollmentDate;", + " pm.expect(enrollmentDate).to.be.not.null;", + " }", + ");", + "", + "// let requestData = JSON.parse(pm.request.body.raw);", + "// pm.collectionVariables.set(\"userId\", requestData.staff[0].userId);", + "", + "let responseData = pm.response.json();", + "pm.collectionVariables.set(\"userId\", responseData.staff[0].userId);", + "console.log(pm.collectionVariables.get(\"userId\"));", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Enroll the user to register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{$randomUUID}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Enroll - Validation Error - Staff already enrolled to the register", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"response is 400. Staff is already enrolled to the register\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "console.log(pm.collectionVariables.get(\"userId\"))" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Enroll the user to register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Enroll - Validation Error - Duplicate staff objects not allowed in enrollment request", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + "", + " req.staff.forEach(staff => {", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }); ", + "", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "", + "pm.test(\"Response is 400. Duplicate objects in request\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Enroll the user to register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"928ca23a-9bec-11ed-a8fc-0242ac120002\",\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"928ca23a-9bec-11ed-a8fc-0242ac120002\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Enroll - Multiple staff", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + "", + " req.staff.forEach(staff => {", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }); ", + "", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Enrollment date is enriched\", function () {", + " var res = pm.response.json();", + " res.staff.forEach(staff => {", + " pm.expect(staff.enrollmentDate).to.be.not.null;", + " }); ", + " }", + ");", + "", + "let requestData = JSON.parse(pm.request.body.raw);", + "pm.collectionVariables.set(\"userId-1\", requestData.staff[0].userId);", + "pm.collectionVariables.set(\"userId-2\", requestData.staff[1].userId);", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Enroll the user to register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{$randomUUID}}\",\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{$randomUUID}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Deenroll - Single staff", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Deenrollment date is enriched\", function () {", + " var res = pm.response.json();", + " var deenrollmentDate = res.staff[0].deenrollmentDate;", + " pm.expect(deenrollmentDate).to.be.not.null;", + " }", + ");", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Deenroll staff from register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Deenroll - Validation Error - Staff already denrolled from the register", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var staff = req.staff[0];", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is 400. Staff already deenrolled from the register\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Deenroll staff from register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Deenroll - Validation Error - Duplicate staff objects in deenrollment request", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + "", + " req.staff.forEach(staff => {", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }); ", + "", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Response is 400. Duplicate staff objects in de enrollment request\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Deenroll staff from register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId-1}}\",\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId-1}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "Staff - Deenroll - Multiple staff", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Staff are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.staff).to.not.be.undefined;", + " pm.expect(req.staff).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + "", + " req.staff.forEach(staff => {", + " pm.expect(staff.tenantId).to.be.not.null;", + " pm.expect(staff.tenantId).to.be.not.undefined;", + " pm.expect(staff.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Staff registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.registerId).to.be.not.null;", + " pm.expect(staff.registerId).to.be.not.undefined;", + " pm.expect(staff.registerId).not.to.eql(\"\");", + " }); ", + "", + " }", + ");", + "", + "pm.test(\"Staff userId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.staff.forEach(staff => {", + " pm.expect(staff.userId).to.be.not.null;", + " pm.expect(staff.userId).to.be.not.undefined;", + " pm.expect(staff.userId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Deenrollment date is enriched\", function () {", + " var res = pm.response.json();", + " res.staff.forEach(staff => {", + " pm.expect(staff.deenrollmentDate).to.be.not.null;", + " }); ", + " }", + ");", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"Deenroll staff from register\",\n \"authToken\":\"{{token}}\"\n },\n \"staff\":[\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId-1}}\",\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\":\"{{registerId}}\",\n \"userId\":\"{{userId-2}}\",\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/staff/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "staff", + "v1", + "_delete" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Individual Enrollment", + "item": [ + { + "name": "Attendee - Enroll - Attendee", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendee are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Enrollment date is enriched\", function () {", + " var res = pm.response.json();", + " var enrollmentDate = res.attendees[0].enrollmentDate;", + " pm.expect(enrollmentDate).to.be.not.null;", + " }", + ");", + "", + "// let requestData = JSON.parse(pm.request.body.raw);", + "// pm.collectionVariables.set(\"individualId\", requestData.attendees[0].individualId);", + "let responseData = pm.response.json();", + "pm.collectionVariables.set(\"individualId\", responseData.attendees[0].individualId);", + "pm.collectionVariables.set(\"attendeeEnrollmentDate\", responseData.attendees[0].enrollmentDate);", + "", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Enroll attendee to register\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{$randomUUID}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n } \n\n ]\n\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Enroll - Validation Error - Attendee already enrolled", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendee are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is 400. Attendee already enrolled to the register\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Enroll attendee to register\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n } \n\n ]\n\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Enroll - Validation Error - Duplicate attendee objects not allowed in request", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendee are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "", + "pm.test(\"Response is 400. Duplicate attendee objects in the request\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Enroll attendee to register\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"928ca23a-9bec-11ed-a8fc-0242ac120002\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"928ca23a-9bec-11ed-a8fc-0242ac120002\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n } \n\n ]\n\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Enroll - Multiple Attendees", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendee are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Enrollment date is enriched\", function () {", + " var res = pm.response.json();", + " res.attendees.forEach(attendee => {", + " pm.expect(attendee.enrollmentDate).to.be.not.null;", + " }); ", + " }", + ");", + "", + "let requestData = JSON.parse(pm.request.body.raw);", + "pm.collectionVariables.set(\"individualId-1\", requestData.attendees[0].individualId);", + "pm.collectionVariables.set(\"individualId-2\", requestData.attendees[1].individualId);", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"mukta-services\",\n \"ver\": null,\n \"ts\": null,\n \"action\": null,\n \"did\": null,\n \"key\": null,\n \"msgId\": \"Enroll attendee to register\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{$randomUUID}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{$randomUUID}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n } \n\n ]\n\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Deenroll- Single Attendee", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendees are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Deenrollment date is enriched\", function () {", + " var res = pm.response.json();", + " var deenrollmentDate = res.attendees[0].deenrollmentDate;", + " pm.expect(deenrollmentDate).to.be.not.null;", + " }", + ");", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"search with from and to values\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Deenroll- Validation Error - Attendee already deenrolled from the register", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendees are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " var attendee = req.attendees[0];", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }", + ");", + "", + "", + "pm.test(\"Response is 400. Attendee already deenrolled from the register\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"search with from and to values\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Deenroll- Validation Error - Duplicate attendee objects in deenrollment request", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendees are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "", + "pm.test(\"Response is 400. Duplicate attendee objects in deenrollment request.\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"search with from and to values\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId-1}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId-1}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_delete" + ] + } + }, + "response": [] + }, + { + "name": "Attendee - Deenroll- Multiple Attendees", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"RequestInfo is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.RequestInfo).to.not.be.null;", + " pm.expect(req.RequestInfo).to.not.be.undefined;", + " }", + ");", + "", + "pm.test(\"Attendees are required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " pm.expect(req.attendees).to.not.be.undefined;", + " pm.expect(req.attendees).to.not.be.null;", + " }", + ");", + "", + "pm.test(\"TenantId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.tenantId).to.be.not.null;", + " pm.expect(attendee.tenantId).to.be.not.undefined;", + " pm.expect(attendee.tenantId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee registerId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.registerId).to.be.not.null;", + " pm.expect(attendee.registerId).to.be.not.undefined;", + " pm.expect(attendee.registerId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "pm.test(\"Attendee individualId is required\", function () {", + " var req = JSON.parse(pm.request.body.raw);", + " req.attendees.forEach(attendee => {", + " pm.expect(attendee.individualId).to.be.not.null;", + " pm.expect(attendee.individualId).to.be.not.undefined;", + " pm.expect(attendee.individualId).not.to.eql(\"\");", + " }); ", + " }", + ");", + "", + "", + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Deenrollment date is enriched\", function () {", + " var res = pm.response.json();", + " res.attendees.forEach(attendee => {", + " pm.expect(attendee.denrollmentDate).to.be.not.null;", + " }); ", + " }", + ");", + "", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\":\"mukta-services\",\n \"ver\":null,\n \"ts\":null,\n \"action\":null,\n \"did\":null,\n \"key\":null,\n \"msgId\":\"search with from and to values\",\n \"authToken\":\"{{token}}\"\n },\n \"attendees\":[\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId-1}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n },\n {\n \"registerId\": \"{{registerId}}\",\n \"individualId\": \"{{individualId-2}}\",\n \"enrollmentDate\":null,\n \"denrollmentDate\":null,\n \"tenantId\":\"{{tenantId}}\"\n }\n ]\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/attendee/v1/_delete", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "attendee", + "v1", + "_delete" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Attendance Log", + "item": [ + { + "name": "Attendance Log - Create - Success", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + " setTimeout( () => {", + "", + " pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var id = res.attendance[0].id;", + " pm.expect(id).to.be.not.null;", + " }", + ");", + " ", + " }, 1000);", + "", + "", + "", + "let responseData = pm.response.json();", + "pm.collectionVariables.set(\"attendanceLogId\", responseData.attendance[0].id);" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Update - Success", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Attendance Log updated successfully\", function () {", + " var res = pm.response.json();", + " var status = res.attendance[0].status;", + " pm.expect(status).to.eql(\"INACTIVE\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"id\": \"{{attendanceLogId}}\",\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"INACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ],\r\n \"auditDetails\": {\r\n \"createdBy\": \"47b5ea82-249c-4435-9646-16167fec06df\",\r\n \"lastModifiedBy\": \"47b5ea82-249c-4435-9646-16167fec06df\",\r\n \"createdTime\": 1671090269007,\r\n \"lastModifiedTime\": 1671090269007\r\n }\r\n \r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Update - fail - attendanceId is not valid", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log updated successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"ATTENDANCE_LOG\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"id\": \"{{$randomUUID}}\",\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"INACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ],\r\n \"auditDetails\": {\r\n \"createdBy\": \"47b5ea82-249c-4435-9646-16167fec06df\",\r\n \"lastModifiedBy\": \"47b5ea82-249c-4435-9646-16167fec06df\",\r\n \"createdTime\": 1671090269007,\r\n \"lastModifiedTime\": 1671090269007\r\n }\r\n \r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_update", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_update" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Create - Fail - All logs should belong to same tenantId", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"MULTIPLE_TENANTIDS\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n },\r\n {\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"tenant.id\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Create - Fail - Validate Attendance Log time", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"INVALID_ATTENDANCE_TIME\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{invalidRegisterEndDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Create - Fail - Register should belongs to tenenatId", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": \"{{$randomUUID}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Create - Fail - All logs should belong to same registerId", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"MULTIPLE_REGISTERIDS\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": \"{{registerId}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n },\r\n {\r\n \"registerId\": \"{{$randomUUID}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Create - Fail - User is not authorised", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"UNAUTHORISED_USER\");", + " }", + ");" + ], + "type": "text/javascript" + } + }, + { + "listen": "prerequest", + "script": { + "exec": [ + "" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": \"{{$randomUUID}}\",\r\n \"individualId\": \"{{individualId}}\",\r\n \"time\": {{attendeeEnrollmentDate}},\r\n \"type\": \"ENTRY\",\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": \"{{tenantId}}\",\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Rearch - Fail - TenantId is required", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"TENANT_ID\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n }\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_search", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_search" + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Rearch - Fail - RegisterId is required", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " var code = res.Errors[0].code;", + " pm.expect(code).to.eql(\"REGISTER_ID\");", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n }\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_search?tenantId={{tenantId}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Rearch - Success", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(200))", + ");", + "", + "pm.test(\"Attendance Log created successfully\", function () {", + " var res = pm.response.json();", + " pm.expect(res.attendance).to.be.not.null;", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n }\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_search?tenantId={{tenantId}}®isterId={{registerId}}", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "{{tenantId}}" + }, + { + "key": "registerId", + "value": "{{registerId}}" + } + ] + } + }, + "response": [] + }, + { + "name": "Attendance Log - Create - Fail - required fields are missing", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "pm.test(\"Response is successful\", () => ", + " pm.expect(pm.response.to.have.status(400)));", + "", + "pm.test(\"Register Search response is received\", function () {", + " var res = pm.response.json();", + " pm.expect(res.Errors.length).to.equal(5);", + " }", + ");" + ], + "type": "text/javascript" + } + } + ], + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"RequestInfo\": {\r\n \"apiId\": \"mukta-services\",\r\n \"action\": \"\",\r\n \"did\": 1,\r\n \"key\": \"\",\r\n \"msgId\": \"20170310130900|en_IN\",\r\n \"requesterId\": \"\",\r\n \"ts\": 1513579888683,\r\n \"ver\": \".01\",\r\n \"authToken\":\"{{token}}\"\r\n },\r\n \"attendance\": [\r\n {\r\n \"registerId\": null,\r\n \"individualId\": null,\r\n \"time\": null,\r\n \"type\": null,\r\n \"status\": \"ACTIVE\",\r\n \"tenantId\": null,\r\n \"documentIds\":[\r\n {\r\n \"documentType\": \"documentType\",\r\n \"fileStore\": \"fileStore\",\r\n \"documentUid\": \"documentUid\"\r\n }\r\n \r\n ]\r\n }\r\n ]\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/attendance/log/v1/_create", + "host": [ + "{{base_url}}" + ], + "path": [ + "attendance", + "log", + "v1", + "_create" + ] + } + }, + "response": [] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "if (pm.environment.get(\"base_url\").includes(\"localhost\")) {", + "", + " var tenantId = \"pb.amritsar\";", + " var id = 1;", + " var uuid = \"11b0e02b-0145-4de2-bc42-c97b96264807\";", + "", + " var roles = [{", + " \"code\": \"SUPERUSER\",", + " \"name\": \"SUPER USER\",", + " \"tenantId\": tenantId", + " }];", + "", + " var userInfo = {", + " \"id\": id,", + " \"uuid\": uuid,", + " \"userName\": \"\",", + " \"name\": \"\",", + " \"mobileNumber\": \"\",", + " \"emailId\": \"\",", + " \"type\": \"\",", + " \"roles\": roles,", + " \"active\": true,", + " \"tenantId\": \"pb.amritsar\"", + " };", + "", + " pm.request.body.raw = pm.request.body.raw.replace('\"{{token}}\"', '\"\", \\n \"userInfo\": ' + JSON.stringify(userInfo));", + "}" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "tenantId", + "value": "" + }, + { + "key": "stateLevelTenant", + "value": "" + }, + { + "key": "registerId", + "value": "" + }, + { + "key": "registerNumber", + "value": "" + }, + { + "key": "registerId2", + "value": "" + }, + { + "key": "registerStartDate", + "value": "" + }, + { + "key": "registerEndDate", + "value": "" + }, + { + "key": "invalidRegisterEndDate", + "value": "" + }, + { + "key": "userId", + "value": "" + }, + { + "key": "userId-1", + "value": "" + }, + { + "key": "userId-2", + "value": "" + }, + { + "key": "individualId", + "value": "" + }, + { + "key": "attendeeEnrollmentDate", + "value": "" + }, + { + "key": "individualId-1", + "value": "" + }, + { + "key": "individualId-2", + "value": "" + }, + { + "key": "attendanceLogId", + "value": "" + } + ] +} \ No newline at end of file diff --git a/core-services/attendance/src/main/resources/application.properties b/core-services/attendance/src/main/resources/application.properties new file mode 100644 index 00000000000..014b80f276d --- /dev/null +++ b/core-services/attendance/src/main/resources/application.properties @@ -0,0 +1,91 @@ +server.contextPath=/attendance +server.servlet.contextPath=/attendance +server.port=8023 +app.timezone=UTC +org.egov.detailed.tracing.enabled=true + +#-----------------KAFKA SERVER CONFIGURATIONS--------------------------------# +kafka.config.bootstrap_server_config=localhost:9092 +spring.kafka.consumer.properties.spring.deserializer.value.delegate.class=org.springframework.kafka.support.serializer.JsonDeserializer +spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer +spring.kafka.consumer.group-id=egov-attendance-service +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 + +#----------------Postgres Configurations----------------# +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/digit-works +spring.datasource.username=postgres +spring.datasource.password=root + +#----------------flyway config----------------# +spring.flyway.enabled=true +spring.flyway.table=attendance_service_schema +spring.flyway.baseline-on-migrate=true + +#----------------MDMS config---------------------# +egov.mdms.host=https://works-dev.digit.org +egov.mdms.search.endpoint=/egov-mdms-service/v1/_search + +#----------------Idgen Config---------------------# +egov.idgen.host=https://works-dev.digit.org +egov.idgen.path=/egov-idgen/id/_generate +egov.idgen.attendance.register.number.name=attendance.register.number + +#---------------Individual service----------------# +works.individual.host=https://works-dev.digit.org +#works.individual.host=http://localhost:9090 +works.individual.search.endpoint=/individual/v1/_search + + +#----------Individual/Staff service integration--------------# +attendance.individual.service.integration.required=false +attendance.staff.service.integration.required=false + +#----------Document Id Verification ----------------------# +attendance.document.id.verification.required=false + +#---------- Attendance log Search config ------------------# +#attendance.service.log.default.offset=0 +#attendance.service.log.default.limit=100 +#attendance.service.log.search.max.limit=200 + +#---------------- Attendance log Topic Config----------------# +attendance.log.kafka.create.topic=save-attendance-log +attendance.log.kafka.update.topic=update-attendance-log + +#--------------Attendance Register Topic Config------------------# +attendance.register.kafka.create.topic=save-attendance +attendance.register.kafka.update.topic=update-attendance +attendance.register.default.offset=0 +attendance.register.default.limit=10 +attendance.register.search.max.limit=1000 + +#-------------- Staff Topic Config------------------# +attendance.staff.kafka.create.topic=save-staff +attendance.staff.kafka.update.topic=update-staff + +#-------------- Attendee Topic Config------------------# +attendance.attendee.kafka.create.topic=save-attendee +attendance.attendee.kafka.update.topic=update-attendee + +#-------------- Update staff for change in contact detail of an organisation------------------# +organisation.contact.details.update.topic=organisation.contact.details.update + +#------------------------Attendance Register Time Extension topic------------------------------# +contracts.revision.topic=contracts-revision + +#------------------------------------------------------------------------------------------------# +#---Attendance Register Search : Comma separated roles that can do open search ------------------# +#------------------------------------------------------------------------------------------------# +attendance.register.open.search.enabled.roles=SUPERUSER,EMPLOYEE \ No newline at end of file diff --git a/core-services/attendance/src/main/resources/attendance-service-db-schema.png b/core-services/attendance/src/main/resources/attendance-service-db-schema.png new file mode 100644 index 0000000000000000000000000000000000000000..8fc615db9636d0ad10cb4e6ebef2563bd158dec0 GIT binary patch literal 190121 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�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 literal 0 HcmV?d00001 diff --git a/core-services/attendance/src/main/resources/attendance-service-test-coverage-report.png b/core-services/attendance/src/main/resources/attendance-service-test-coverage-report.png new file mode 100644 index 0000000000000000000000000000000000000000..a4246e0442f6fb129ce365af31c4ce3a18f28807 GIT binary patch literal 962886 zcmeFZcT^Nj*Dp#G6%`c)0SSVNh(nMhaRekMC1*rL7|ChK3_&Gl$vLa!oP&~c7;+i} z2}2rk7$)4t=Xsy^{l0Vmxoe$s*1h)#tGjEecGcd!yQ;ct*KhB@m&!6%FVkKoARxFZ zC;LJbxOfu~kYr!H0OY)$RKXJvToHpvO1_knlw^8oZ}SdfX-YsK8yKTSrmfaZm8usN z@!Xt{B>TfWNhIxa`HP@~u-7d22_*u#ud8o%W%^o(OOaTveGBlteO>sC*{e;@()7%N zVAA@%hop{kT20PPHrrSf*bL{eGFxj(@KSi-MxgymCj$GAr;C%XVd$D)w}g;v&j~Jf zc@vEa&WhaN5fZxloK6ToH*erSKU6fSP>Gwu8!7p94lWUSzmQDs=v`WoXka90_{4s5 zmH7GRy?5|EDb*`1r?J;(X@}T1=&evP_WIV)6Fj(mO(vPpd;LKdoVCUTH7+p!7iP?oIX-o`RYFO*UiI0wTLKF3{7f}62(M-9|Ee)AuLq2HV ze&gS;S;O^laPo(u=C6ow?VIfVh`Wp0OkMd7!zgZpcdAUIV z%p>-~kg*`8H*%R`)z@H=JmHe05T?QIr=-KrU1FkThtAa9kC*H&r%+^i;I&V+lbL%0 zHBXjuG0CslY%Z577>Xyqd6F7WL7lD7s6xFg)7iV&37*;tqmi>sjVD#^n zW!xh;Hb4=fT^CfC21t#W$P5+UW_@TKzWLpx>mu$(3Nan^N)mBW1s<_4x#|4rQi3fh z3r&!$7Twyxz(@m1ht?V$s8ksE%olIcZDjZZK}J4Dwmk%oqGjO3yU($OUpdUGQt)ZcRy_xR7AOk9fmcA8U6A+ z#UMwVd0#8t=)X?>^yxlQ@kD9?J|$7q`lv2CE1HL31Qm=qJbWm9H22(5sL6pGN6>OM zxv;R1fzn^&COE2T?ZhuQ43ay0MZ01G$ba4C5WT*jCvjB_;?{C8p3veMBkRJ2 z25-iTBpFPX+x*^gU3!;xX`=RyB5`?($4jD~7W)!fb)T!Rc_yzxeHzng?p|PRf!Gr2 z6HTs&V#MM^{j=Vk36U^_>hAY3|8Tx8| zPd9`^ihWquk#+h*>T}NYi6QF)QXy|bMH={bMK1RcpVE>?Pe>Iy+a~W8+{$lxUwWb7 z_WUZlw!pZ*XItR2t9eUDwxs?Gm!46l1r2_WThKUxHe9mlEMB14@xsvg$a67G-VnKD z`Qw?y1!LNb4==?h<)1x&Mw*tx@I#n6@{42zb6u+$cS5{WvYftzzKrF423F_|#v5d^ z_oEoP!+t3RG26+WX5Spq9Z??P9x+v=K>9_MMU_THt462>MZNqg`&9zsKk_Q4S6(GX zEPAY)>aB|Xtpu4=aYN~O3F`+&_m3mMYP^p$Z`sI;JP3Z8rYZ+XPtKgpX?Ufn$**zr zGVB%Aqd~PI_4z^%%~PK}ncGUY^=`-ZklYUJQH`;B+^J#xwIM_GYpgo>{bjziy3e{Y zqH>KY*mQX{rfo_T}b~)meUYTDRZtlGCS}0b?GUaZHsgS!<(S`@D z@iSjRU+|mVfKNB#WEv*uzi#C9PJqU&MjLa_lR$_*X82=-@P*;jY~4RYzu$NwTiLOvw*XnWNApt zgt~=7I>b7NmNYs#L(<@tNJY16jZyQ;C;@J+OWcw1mQRtqrSgf~U9#cg+qFLinYj|J zQnP95$%z@T?U3C?=STMDP#3{z567Oh+gXDlxRtf__@$cm-GMv(+!-c89Tj1&TW>eo zoW4Qp))k$u*{5#IE@FDx2R@?8=9hEX`}ux2WmqI_XbCtAl!fBgLu*k){Lc!N@-;Cxa;z2}

14i|=dgD1wJbW#hZ3YG}9pW8l%JU2^! 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 fMXd=uFTI3+;2xB_U`u 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≥0mABvy`03xB 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 z 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

5ht7iWa$~%fTo;1nrbSDd)8OeN>3oY#uzlaBD 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

0BL9 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

Ff@dADcvPxc(QpXwE*O z*FHyQ%z={=M6%xVEF#wV$=A?vvFqD}H?E4YBKA|+X=H2FxjOdCclsP4+}tSRbZc$j z^su?K$hT(0HP#a?o|JFA!8C+xS|Jc=*f}QaGcU@oe4%dwHpH+2k-2HruJ8}N1}p(h zu?Ncqj!h4fvqoE8RD-^Tj!o6e8$2%P$JeKOF0G4K>Q(u5cKzY4y3M8l?VynJf1w5{&Twnj1iikx@z-5t$$n(1{L` zHAv~+PsX8sWqE?#6Z>=n`aU_@36B$>$p|7&9H-F8GWCg3O0nvZMjCs^N;<=RUp_*i zK4ie9=N=Tf49I=Aqt#-)3wnVVE97V3JD$E;XZyY3t%I0NS|kHZVm1Z6C-hCOQMzoX zOt`4CM=tkM%}c8Elnof;SSxkH_I`IQJrEB$#rb_YGw`?=a?zA35j?s_X58acg~gZz zCWU+Qpf9tESzV{FvJQv#>%ZVx-1A3ix> zMo=H+P;qFQv>7FeYeci)m*W$Bg-UvBqJ@n73I-%FJ2VXsjkBG%-@-$QyHhJyea_$+ zjT`63@QhEj_@5U%tONJ&k$Jt^y=mv4jM6zUa>C2PU-?A`N&%Vuu7O9IHG5UG`+U17 z?WfTEu*D8p##NfPH=u&sL>tb%3HF$0h)AAQO#Xa))2P4;j>ZRzli_j4yT!IoxmXK}a=#RwP)pxVaHqQv2>57?AG4p`@7tR&x z-KU6r;|`qH?7)%mnotwPZ>L;`SFTu5>zFV5lqlhiJ}tN=uV|cx+nnBarb1{%4=Zq+ zzqPuFWOwn$zC(15V%_5G%$1JX+OtwZ4yDnv)svu<8uQY21vxq36Et@Swstoe3ZM-o zRY^hyCkyA!o$HA*fU2lAz9;JbL&C<|5Fg~kTt(RfZMSamCwgtOgwpoWiCO%ieHICA zP%M9v;t2`un_5upAs9*Ct>#Yh7=H~tuu2HYyS{kQqVw<0rph-;mxqKGA1y)>N)jK5 z=pT*l$5nl!5u@_HOR~L1oUy{0SYgaNi9&N6xTz^55*izNFY!y%Kv0GG(W86%H+=2) zQYehLsRZuk?W3IN=sgr@MIxQ**?rAj)7{!+XkzM?*lA2_0x@I$h^{e5^JeP6XwK%V zn+}YC4m;ZVw3p?j;E6_xaL+iTGDf@a4=RlnrTfZYC*P3J0B$E zN)%}thm4;M+=BJlDYY;ws>9DN0dH`lah6yQ=OeL4eb5G#(1MOUcH%V>RT%q$Zem_o z2q}_C#3P&zX$aW~%^IMk-9#rw$xZ80&C!l|HJ6LODBYHqkbxN_-~p00*RLykW!;63 zrNvHBPbZ#*)a~?2qcZ5QsD0^?#qo0lH9WSi9Q>MJs$8W7@zk3K_^b3~bX>{zF_&jF zKQ-5BB}ubjuFsv+n~|EU9*tkH{JF|*`hqSl*Zn>oErb^jm>2aVlOMKy!*-IfEpqn2 z$}yq*d2S=8w=~DQ-n9*$)}WTdKibx^U<#dB=-hqShHyI1FseZ$;Mh3)m3f4U^Fg^n zF(u)nhW*fr@rBP?I=Pi%*T%3yW4FET^#DbM@ShPdK`(&t9M0sZDQD2ytJjVb_>;rY z@$}m;PByn&x)o1%fX`W+W$!xPEsxDZrO&` zB!COpQvs8Dhn-&=J)s!}^F4q*ZT7msb9r&{9{+e!Fa8x-npt#k-JYMwGm~*XUT^%I z7QPI2v1Vvdf%1({Q)d&MZDRpK6I$2qtdP_t5?OGCRv*(8`=hJ% z+pY~)oAA&WJC-W_T^xUA>|HKjz~jBQxw>hi{*+!^7=DU0M-e#dU?p#Rl^yYGTPa#1 zbo~4>tiXJB0#Ad!=Wf*h{C5klI!-*OYiZ|K-@9l@3|8Q@G=tq?J&M#S-S|wc-F&%9 zKH2E`54RML?eF@W{G2kzt;?ZmN2hVPyIR?w7j*;+F7F2KIkY>%J`SqsX&aZp;C?u7R>hH!(++M^e z|Di_UXuCE;WXB84*E4vwd<>gzi*x0U$Q&0FcPU!M?LPU7+l4AB4pLy+F*46+3QldW z=_tH@)MuanYc@HVudC!?55jId!kZBkEbAjl9>dYBhpP>Boie_-q8{I}c-C25Qtqg_ zl9aLau~;x(KBt%j|kDFiD?OSx+_HGEtv$~ElyguL0}Sf-~c0@K1;r}thw~O zK*yS2Ik(?98c&W$W!zT(UY$25q7OJ+6`>QdVRcWH>>ZEe&y8G-n-JPa6TX_rd)R!C za~p??A4kg8%D64NSMX$|`$F~lX+t#2=DPL$)TbTXOTwc6c5~9ut%XXul#j#QOAr2b=`3yG*nP?JpQ*1ZEcp*l+nD4_tJ*|k`a37Mm&*TkDRXp= zXSrbeRnsr+inHRUEmnI~0s7)P*K6L~OYMKV)a1dx`^zy$^ip{oW_zNk)&S_tr@C0fK#d5J z!W~SEkZMA6*S+Hpgl@dA4AybqJ!V_swDyq#L1RT67q%<~vWjhW&N%)*- zLLh3Y9ecdxQ?embI_)87JGP{D#gBD7GaKCDIUv-_ws(2Vupar5@`XuGyuVuh^yLWU zF<58cLu?ZO+#U;g@cQca%&%~UuWP{}f73)dA;GXApl?oArO6ji(stj0M&62Dt9Bx5 z)jeBwQc?0tHvNj2)th4IjHB)a346%jU*(Jsdh(d?)bieDLTl<_+q>ScKOUP_BfU>{61gJqZx&5eeG$@xQlsuG44&g}$rUEm!jy+k(x)A_V`U^P-Lfe=#)wdh z!dLf$C}+8s3{$ZFBRdX-TaqghjEJ~PM(YPKpGg+1O^twE@GaKderUoC>TbCvF+Zy^ zMBR4?cOv)>Z>&!OY`HYbutpjE(&z+9-M_A|A$N5{^n^;6na@7iICXNc{&nGT>ycAe zUo%+b_M)wEuPZz@XqH-{*aCH;tnS!z5|{|HJPNnQ#jl`+{aTRJ!?vbr&LQtS{QA`j znz0tX;<~j@|5BlxAC4mg6)9(A11e-?koJ-yT`|ap=;=eaoLIN6s<6#9M#zG+*c@M= zNn7|J<59h%OifLtLpzPQ754X}yd+cQObNsydlqN+Qu1P>8e^xZg@M0zc{=ors#Vp~ z9O+?N5V>r$G+4zX!oF0dFraNUi{pQdG1=nvnoJ%2Rk*e5kOw>$>a}j4+Ej{NUoAMsl*V0Hk;o1-m3=3W9oAMp+K)~Cmu_dv zcP}fjql-~@9lw*n4kT<}R1cGqgw1`M4>`6^VspLGyZ6l^&i7k0nSPFvoA!Q#Nk>-S z?L#_D9w_Kseyujl!KU_2EvE+`?kvC3nNLTdxwqPJEO=sFe&xFLH5&|2dd#*#mu^bGz9eTs=-$C!Ta{cE z;cp+rQ*ep(Y)ATwMoEV);<9S>iz9DQqo3d+CtcxKK_7&2?xfeNOTm^=HdZ|=IP*d{ zz16^!{PvPbZ5D6{4EE3bq*DF+D-7h(t}(zzgVZfqH(4iBv#TukGiQ9$RKNsCKm#8fZ?HcWeMP0!WifUQ2j9u)& zh`{LH_#bKsok#5PMQDs*5!x_wGym6L1{y`ofk8qh;Lr(Yj_^rDrwLN6<`|UX{h%{t zoYi{hz0cy)tS8Tm_NE!Jf?)uo4o}j(E{T^Tl za9z4EuX?T}0W1&N;-4WO?e}4J1)~EV=+yHVio^D?r#znQi8wYqiNB}ic$f{fjq`l+ zJz><6$sUE#3@V+DhnUmeRlwbz4f{;)?C`I$H$gddIB1M44Udux;y>sOui*X-Hqxg* z=KZN@y&&z7mOP6V*g}@ZA*{(!3SsoxZX%=SMW?K4;}+n^cDt4`774$3$z&CbQTW|p z5|VHF8jN-cAAoeE7=8gqg;4-~w6qUX6U>S_n)h(^8LD)l@?niM)8hW&UhZzbGS^uw zW66-hnM(m8xq56w5@uM13H2bK21k#-DuzzjVCtNtVP~^Gi$=A4?%>Kodf7DmmF~}9 zF;&X=N3#}B1`q}M?oXm%WmbRDHsCzRzWs@L`6-BzVA6Y}FlRcAckdZey$}k_y=>*w zf>^4xqiKJkCyi0%u3$|C@e~36b(nBl@$cs4jS})#{XrA{KiWmW+J$rgmVkqGzY=^3 zjFPnBrEC(iq~BR>;6$GIMb(b@m0Dc{D|WZbut*|W;)PL9K| z84)vmF*7b^o{^dPVrK6A=UPXshFEjc2{5fy*p{!``Jw%*0F(nDQe?j2F|);qkx zXD#2e3PsiR^iuoIvtLB{Pb>BBz1wLy;TLg;wU=+pBg;$s+wPJ-e0-%er^Kq^?xNq~ zPp&Lzd|bGg5cKqb^@1Bk$%{q)5WmGOM4@jLz?x$1@d;{}7+qSmFD- z<^em)gg?aFWz5{z%r7=G6lb2Xe~HNh2^{`pO>Cedad#IS)*w!rMlazwpq5T|Zf6s> z`hhI>TDX0pkL~y7UZ7F>-C>ed4;&v`^0MPq`Of!c^SlBcDy|`)z52BVxS4@7cTpCn zS8in4XR$GhKN#G^n|W7uW1D2;#>K6W%Zhwd*FK?j_EPZ|&c-gYJT}}8 zcjN9?`4!c|`uZ=~M_lIZ+Q--|o*^M(xyNb|3s$+9;Wd$8K&Lc5{DiUbK;M zTBgvaV|8;opt)PtVYV!Zj0bCH&7nN)o*ph2*OmOjT^0J;yKw8oAJD$ku{+gM66 z*|!I`4O-56#PAE6I+{=Z$~DS;&>^;sg(y4veD}tJ*a(N0$~_R=@#JVj^KdDHHEiw{+T8jkq0LWW zyKgEHF6}t>Hk0C(d=;arr4Z}88`aaU3`B`pofp8!M!h+8fj&l_p94fvdEPOkH;(lVYgbqsiwL zh7V#RMQVZa1?127!F}*tt(cxCf%k%4on?W+3dys~ps7#WG*bt()MVb(u9|Xk=(p)* zy9dY7sRLoop?7lfFz2Wa>j`9Hm;xdhSRgmIyIQ9IM!EFuLm8r?w41xlUj)7n9!#+k zP0Sl&u$)$&Ff819qV9(D?boW2(R*Ohw!&110*%LH>-4E+?B4N{6ny~z;sCD=bHk&6 z$OdZP!nRe(v2&&At7tK>}IBtwcKAOyf!!ZeFHv=m&E`}XG zdb;;}Kky65!5j_hmlrCZ)L%Hkqu9BiVgQ=Q^V7>=(|Hxn`vaRd9Z6#L--^vczaeag zOKtx^tD7fnjtr`~?lex#c{+CEr2%7a??HO7?ZP<#Dkn31W!4)jIm?BS*S6f;12}Z+ zhZy>sIBH&|t%?=SRZb^_SJaVLza_Wkk0^cwB)YIY0BEP((m#Wyn<4G}hvtvwpvZx)J@#?CUNoEI8o0I`^QtrIBpOa`SAVd8`95jQYSXa{L7Hx zUj5I5+o35mN2HI!5-;K4Qv04p-)VibuS2xrUCf+&qYfO;rU@L9Uf(UVTBKxAi-~zINM|&Z+S{;I4(%KIz<{8W81z35ndBIG25%~ z&>IPUtK?fir1jL9y4xeU&o+R7H%$;ZrA@@aVkWEYh&U6$SxP6~o7B%Jt7v|B9s+(kF3Te z2ObpTGr0<&Bc@6g(^BmCjNf-9KCmddYItno)o>XrA$Zo&xuHoLt}#ky1o3)$rjKUE z(aa-Kzc{|zk1@>xn3+;$X3Los<^N%^9FU?>?4O8}H{ozcJ*_p6ynY&4snuWD%zrjO(xswum5KUv996~X!@0|PmQ`Wi z5;!<*FGenor`qI5Ee9w%S5yq6+W}u*`>}>E4z#u&#M}XR)|=hLqXD*A&GwjLGc@m_ zqu&kHQ^{0mjB?k{$AGhPj*K;$g=?=E8YtG;b{6cytM&nd(_Q*my^+hqN})w({8yTP zwx5(q`=#Q(j2HOiW3{Ui3sL}zR`+FYOcPL%ESHQwTXa6QqTPSTwwRj|j{a*0n3QA7 z3$CjTutNu@Vje)aKffEP@$>Sx6)YsoeIUV|BvJ0G;zqA+|2bMZr%^epo!C&g2gTSc<`pvSJ;`uU+H z1QharQEgcM>tqBlv*ttp6!D89B0K4acHj&Q{F1WEF9) z>XC+t_8axK@2KvFU#Qx2A6BH^30qK_`h8ocM5lrLo?AkTeQ~78ATsp&W6;e=3;3Gg zNSw%;vioz(2pyacWRvA)=kD+5#>(DkocZuC9r6op)DX4Pz9K zP`-+dHqKYspvyNW?xNY5ZpPSP>7~+J?`i7Nea`i|C&bSA@0`yVS#(;}=KT-nh@}jm zrzZ(y0XU$i$K0*q>8F3~thvVmSZNbqGus;NqC)=Xh9|d9NYHeAfR4YpELoWrZDlp9 zdc&4g-T|X8wM-4qhS)SbcRs3=#&>S{N&zj>hRmw14%IsoLQVOy7A~Gg=KkPFmk+i4T&uRj+my?CTOKnQ7)sZ_bR(nMY`5LYkR3{{>c| z`&En_$e%coge*CI);8+cjyrJ9?M<>bE|83f*UBXwKHy}Hn5-hy2Whzcqq|2(wN7YU&pp~+aq4yB&LiS zHfotacT0XrmToDl9A^{3fgIIU+-1j{-1Qn!tPq)@lR8Z4clT0$!|XCKb1ndAov|f$b2u7Ww6aFhC zr~SJm(}?LPhsEd*WT@Rpq0S4xcSWgkGCWA-z?g)(^MemUrrklR?*%n>sI;%~6pYBz z?Yu8Px<9E?|^KWm9Qs^eLiU zUNX7dC}`*Vt=a>6RO*>i0G=u+klC#@MD5TT8!O33wDjIYj(fOZ%9qdcR3Y-=IGVT5!H}yN+pu z4g`%cO(AF;K+@;H@SE}6)wbJ72r@t?BS`1oF{V2NF_~&PKgA}CrNVA(IHcxMv2*HE za4Ar)mP)-Cn53-d%yEQ~D1%hutV0mr?6IN8eq!6%Y9B0g!{ZKC3cP^D&nm`zJ}zrJ z?=!Mwn`qs+H&2vrpF`(`JvyId{PDSV7IeFM-&?c9v(?c}MD6Z%&09>iovR(7u5lK+ z{A{zB%K34}$9eZv4MJwb&UC`eNSJvX{{3?T$)aDh1RqFsL9;loN9{r$y**)>FFSYc zSooDUol5hmXy?%PfJfi@10_$g&xFg!)v|H#E^tcUjN3$oe~Agpqy~B--NgVfmOSAh7J`ud+ZvAH~+-ic$V8D4E9T>s?YY2*{o=)q+}9O z)TqK0(_k1!VHW)w6!89N^{R{81)eBL53C$*dH-_FXF}g$Hk*=$t^3xa;P;26CIX4b z3x#&iF-Wt-quO-R?&>|;WFk5NdvUUFWE3{6(~vPKSNrTBOikRTVNYjxp=?e?zP@F0yN9$LCg_zBhy;U(uF+>98zba6`L~ zp1XQw)AWV9r9+Z2M5qm!JARo65O$J9c|3q!3(Ra%=#g<*(*EteZXvlxkfhE7WC08j z>wS^V7}FX;yEN>hR@5vE%K500U#47xM=?zR2P0gP9-v7xj}$w1ANU!u%p+VgRzsp= zfO&)nvEZ+CLeG4rU>&BMbpEGA3|li15Wf%n{5u@cW`ndJkN|}y{l$5E2729?!Pmho zZg8yJmz^eKn!5484_tA=PLthxfGUc^U21RIXgfFZNzgT)UAsj?0LQLx7K?+$Dv$<; zyH!oFtKeRLmSg3jd|Av!@Kf1(V}O_55OM0eVh1Sk z6z6XUDK>F_4;v_lbZK`IJ?zSXHnju%D-cZJ7~Bso1WpO`L9bIC4CXZELh^~8H+Y80 zRiE+CC$)24VYlftuTr5dXxWb+9A0ApN^f1 zI0+pPqk`W$rDgg@2^E#@ns>DVL3-$c*xORHI9faR#BiDN9qxaJjzJIu(-;{{%J-Ys zO&i5$=bpjzM|%hwnWEX<4VK)C6%eH*fba}<5|PNo)TK6Js%{-%HmGqbdjNkfckjU^ zFEO?Bw)3~COKpZJw*008Q+2nA<88+-JI%6K8|Pb#m3Y6iZ|V~Lb%XLv`EjN`rohgp zFCi+k03a{*@o^n)!+%IHm?Wr%c@ID965@N}f>Ci<{@sOF(sqz5kL^xX4nB|WHhLXK$v4s%@1EpA~c5{ZNxBnfG{U{TI0SjK-1Oyfu@@l`(R739GHSgcsK4Cjdu~* z7|3ovz=P;H&u+{?gGx>=|1uL;zk+w1@k|@Fer@! zV~cwz!EjEzD+bUYmR59;Lqr!^A|$z81PyK z(0tSEw`=#V)|%wL1@fjhRKk{&vG=+~?Fsz8R>DO@VerY-H@u0V6*^b;t9Y5^Mw0%} zGQs>sp>79qf5X}_Mji&j3(~lAJ2fWGQdn`?8vc#6`yg4WZTjW0O zr{lKb?cZAA5-A~_r=#Ap*`itY=W*We4}Lq}pFV3fjzn`?@$lI{wt`FQ1D#}f*Pvj% z#b0oI7;}%?iaM+nh&-Fjs!z)(v2er{j|E3);4_qVdas7*gDrL)IaOBpf?pP8d4Op5 z?uDg7xNyOa$~KhdXb7fNwmUr7mPJx`w@5ujC1%dfIIp0&apkaL(SESZ7}hlc&h4x2Il>KB-VbwwCkIaFf2;`w79~0Yk>8D!3mlq?ts8|o^P`!g}W-@ z(Qg_y^ngPX8l+)2i&x0xM%8_`M2HRY&r&aKTFy0RVI;-c{@g}zE#vVQ zQwA~v<{&ae(D2MOaDl7H3HmlO5@GoST#Zt$qTv8 znJuv6wM21$oV0v^C_mAzshTME(`97Gc^wJXXuY5+;oas;Sv z@Mw9{{S>DNc!yxk2L_v@Dr>`A)TQZ(qgTfMpxbE`8-d@b=s~2D1dvamG zmjJb2>TI%cAA!H1$mOAm#&`rt*9l6W+EnNX&mz>=gC@t4q{85@hdW~`o#Y%W?%MVs zw&8%92Nts-9I67-$S8w|Q0NfcZ{4A)H+rh$;z^x$a>peD z8H8|VOz>`nPP1S8nFtdM=bY66silRgtx(kGj(wYU$33=xFOy*Rz;2i#{4-M_vV(Se;SZEK(e=oRIQLl1-0J0qAGUCqT(y{-(f>+5(4I4k&^V8LuVZ()YA10-LDfE%i)C zLRc|G{xljBtYPvY>qn54spAqKw9*ZD1=zm^>+?vVT-RZdkuBH%^{OdD)tG^?4BEt? z!MH8m_>%6j<7LHmW!}0joTW0t`q@{v)>0DsMlqO!d1UPuq5cO>XpU*BQb2nYD2{gQU zt`qUh=NzZ!gV1XL%lq00P;tfbPG=j#KW>QP4$7`o$wtce)D_s(6Lmo{hX7CRb;hw) z$lJ92L%P~iLrrd=MwRl(_%nh|r^dsEV`cQ812UbVZ7g_CEf2DB+z@_U3tO>*ZPO1| zNVLBlQ0dUu4*>hD!{L>B;N9|pOj+9@)nRY0&OkaH321p2n(QkB10-w!El-!dkU231?5^;Gw^)-|1CoQ?N6ma*jj)F<kF`nbnlZwP0#e2_EJ zEKW*Udd>cwa$a6~*Mq+PTAJ|f$Tor&l(7^jZ#F0GUr7WP?UpJ0aA9J;ao@(UBLrgO zJuRqzYqH95!K$_>A*;^qoY|WhPpjj})&n{OqU)*#u}$;s9LWp*Xf#b}92^4e66p5} zzMYw4KXsSz`qAD|QFblOaprdZtzQSZN2UTte>}`$kgPjGOGc!tkSw8YYvFO)#75Op zy3iOofU{H?{Yk~Qd|veRe7kQEo(>U+#avK4wulnRN_R|Uaq=uSn0*#Vi9Zu(?8o-M zVYvRUZw$`f>n0;vF_`7iPi7W8o!{m0jK$6Zkh?#|^&{Edrs%g?aJImpEE#~MY5m12V66V^VT)>9-MzjQY8dQA*oby3rW7Q%IbB`@ zgT%3p5cJF6sdCb@E6)miKF)TR@Z%b5P6B{=ClL^mdyWlju=;)M^l~}u2dEz9kj>-&47yN)%#u0uEEjF12AGHj=2ib&#$9seZipv{&_<+DC5uMJ31iW zkzw%$+J(lHYii#vMSL=S+T_9f-syge> zoba1-p*^VWTjorGnSPiV4>Qlj%=|DjPyTZ*2m2^WH-O^g0IN2ViQnQzIw%Fl=kH$W z%_+9nb%#%PLqU0Zp*SJT=z!v!HC7G#7JVuh4%->hxtDLwY7Xf6^hDR=#}=}#!nW{x*zHqR626S``lsKyk$2&oC#g^%)LX!dGp7+ zeC40=_uF`=X{p3Nu~@L@Y=(irZ|UuJmaqP(II~gK_qX)nOvU4WRBSdNT=rY~bu-aT ze^k81?ZF??3zHwM_+7E?%9-2x-JdhR*32NBesX7?t$&&+V+2Q1f?z9%9lCPe&JOQx z>zk^-=&*Z5kYGJhx>dN`jO`t4xu@Fiyh=?xg$_&Gza$e<`9lN3g_(2o1Q-$_;Nm6h zB6dXSv=V?*HjlwvqFr)g(5GWfbIZR(TdySKaW{=rYW6avE$clQGZwQq+2UIDp zIj8zojJsn-R>ydEA{g%u;NVWwf9OgW;6HPrhfc^41wc7VY&+lm`_mz!heCJAsw0C^ zThCmt!D^`XRqgP`PGiOGU(yMwd!c`jaMU#XpSb=BM-DOxlhSbGRK9VhG{|zR#MaUL zIT)C~diIhhMmBLou>U24&l_M)1TyS*Ri6DGKSA~)w7&lGF1G=k;+EUGdjj_WSWJ2= zcCK3eG#yatVMGjUQr%3ywI5 zxQX<9fV880YrT1J>>+~m0q;AeBTSdJ4;_TiW{_GIZlzM$?9<+gQ@(dh&m94`ucG+z zwBCZ*Aw4480@H68liwO1HAOk~IEX>Ec9>sDyEYB2>rhRWmIMhbSVx|^&)-}JsQf(I z-2eeM4ZfTH(;1Q;B3Cf}pxPDQFG=-Ws!r1#CDILy=gwOw68!f5o*mY!4mZeFJ=ESi zS5{%&(a)m3PhB5mo_Ty!`@o|G#-n$Cp0$igUbWu%=$Cc;_1-q>W}$NOGhdzQrkNq} z&-Ub0xE0NxW&zAR_A^u5e{ecq4|2t04rDp6bOanzB_;hro0%QPX{e`2d*x6_t%WtRXh%x7g43lGD~4!KhGu3nW$;H;|lo@fXhvJ(NR7L zyPpkI2asR-ry&{cW;+oB+1<>gf4-`S72|qIF_V_($kMA_L{cy}fL7|-#)$m$sg=)VlKhVg2TgSRfHU`Os9xM6k&8N@KKfm0xyT@WOx zseQA{snX2i#m4bVV)#R^FH1A>kEXbSezZL4)h=$UvHBP3Ro>@~a!1h&fd)2k$n&b( zwU+U`G3*7n-~leAd)M&X@qouF4_L>KJl~!(IcF|#dz1Xt+Qaqu_>HAoGGY7Wd-w7c zC$;RS{dKZDZ>i1emjg%vK~C<@cjnVqdH#(BysNXILoZsqZ}GQ6m4Xvj{)V$tzHnu9 z;i4^stZ7f5-#9zx`S|Y=Eecat!FdKI){+OiyMf#A`LdSwO%VDs-&^e;xqDN$@r-OX z?Var{6a zUI9v7C&atfTRybB7NK$z6q@gt1`Rc|hkkbc=rpumE)(bVYaAgIWKY0fuXoqiczeGp#%pX~+l4VJGPoqB|1MgedGh+VN_YHBdfq)V2u1pc` z0)G?kEJZ&=TJ;zb4qPjjOWCr08~0chSFrXLKi*~@{%gFygz`c8#r}tQzOe(o3l>e> z6`L?5s7{sVdE#b?uao;BdhUmsPxA+%*teOrA9#+epgaAF$Wf;-m`Nok?}Xh+)TPaY4I(aABE z?V};$6H;4!WIr7EsF~(CxM!yX&r^30Tdvq_TR0U*SSIsK^lqI_&Z5(b_we&Zp zksxUe3{!FF7#V^`>F4K;rWumsw?D+A=QZYBOA<7eoLb51PgQlTdNt*+#ljGG2=Z&` zgD-Mywn59V%xq5>cuh++HV zM4ciS+^xPJixqRn-k9g-!tfv=DDK!eGv}R7iCWT+zMkJl>TL=!+wW;3OJU@#HJ?1x zK5V_Xd)LOzt&UGl#f)t#lVK%1A)N&z40omKa{cz;pT*lwJv$+5Y8c$+fAPVWc!9v4 z*n{&*L{0$&M(bjVaNH3wsXF}-fgAE~0V$(EG*$K>VVh=5;ASyC)AL+076!pucGq>K zO}6o+)?TaE9kR-OCg)T2>%LavSw4%G0EPFx=&HgoR`5?DALEaFxqCmEEYI`$`MWi< zuHJnH;CRf^Y~5ZXU;VLTva^3IQZO~_9J=c;(;)2kn(3jLF*Ng(&CEkH6XU<&(%}?1 z>R7spOdxjuiDp-tbEx2KGoab!0h*n+;Z}ulzjEZW+H&c~#E@7DEp(`IWs}tWw{_Qw zP+OG-{Mh8E%JR@lL!TQ%uWgj396^(oVY+3ndt(Y|4k!i8!E?#*A2_=vfU{%1qT*Dtfsd|T!BKB#)Kv>{zfPGc*l@xip2KT)eLEDDQkf3rD8E}H>RE0 z?tMAuEnY5bIGrYdU1NxkW zx2^xf^J_>sm0QP|l#Gqz?XBrlq67hxirJi!8mH;2yhiU_%EP18?gNc!c=Vad^0bCL zwOGO!8O@MXvW1|lK2xFow%H54Nb|rQf*AhrjB(qD@JuCVQTtSEv%tq=_(~qv@P|;X z0=ucmsuapC9|NpUhW(W{BTAe}lzDwP#hQ=pjQk|WbM8eP5OqtsdVtZO7cAQNb(LxB zEUA^Eo^XAlkHK3X0QvX70L=mJuqo+qZQjn3vi7~0a^GR}G4M_R*X5b5a*C!C&89am zYFXL}xOQ6t<0UC3S&@6tbYK#_XaDvTev_Pr||@0b`^=5x|wDkhBQDu^Io#BFa+ zp#lIepiXe?qa45iILKeZ)r>EMu;SC6lv1B#P*_^hd73ORReXIdm4Fow7}~^2&jtUP zQaE?!?}MO3yLmkrg@B79kZ9dQI0PD#hc%`rDrV`U#ZzS`3B&LtZ9*a4Bdc<`XtGrn z>_dz3SblEs+erA<#oFa2=Du8-n%veY#2Ux`#cGlAH}xC2=(Np;W_W5d*tZ#o-VBm( zhMYLVp`5{G&cH|i$1qZLyI3v6N^6b@I&W*HGC5&&Dbn&jSh(cv6k@KE@Z^mb+=hbF zFx9KhW8r?^g<=HEb1|A-51TZ8{>VKLlQii2PVa^xtG6)BzW!LD?GhiPQR-a^m5TvL zZi!A>TO!*uMWxF}(|2FGJbgssCwbIiS@eN{>wTsHxwcE*EpQeDVNuy)0~W~b9#}~u zdP)0$-*a@sC4#~sz{sNo4%*nVVJfCw=P$`$&2RB!ic0sAy|ksQVJb`=B;K5rJ#W^F z@_=|e#@0LiXe(_ii0TS|U((uTf+__mTn>luii-Y5Cj}u3m$JmYoA2>|)hD}z?o{gqVLPlVq;r5qU z)~6xje}D`3KNn<24n>|4`MSfQRJUueP}GC?bV>{!knM7iAM$xhD+F2R)eC2Scm0{cnvbw-;}zGYAOa zw{#NZ+Q!_sI<@mllazIxxn^K{$Tq8$9e2jq`jn1Y1N?Kh+fd`P!wjOP&$q#$wcge? z75$u(dr?lB^aU*948)N2(9;;LE|SSN=WVxHxyLl3ESMKbwu}WQ^=ByRSp*=HAYG3& zE;ChS+AzNuxU_^>v475Xn-?$TYq-RaB<%3Pc{@15F!r+WSAGF3ZZ3l4+FBO70OWOL zhqwIl^R^B=v}gHiaV~d{`zd(Sm+7H9W|Qhy#qLCM@DN#+LgjmnyD`hteg6!nZU)vj zLoA%ZHvW%*Ouk1yx8=xP@NCKTj9@|?*ID~t@!iUIAwic9kKamrr@L%UoY|?EZ-;lu zjF5jkm&eZ8H- zK(^b|zm;idV(-aze_)mHVUg9XJ98|OR;8t7Hzq+THS%k(FBBHeMPf_ZP#@F!A$50a z)6@yxr`J&rbdux0`{>4)j?p=ZUua63uWmXpEWCdG>DEV1aQ4bJ$ZM`*ecsVFD3<@2 z=qACnH_24Fr&K}_tzoE<+%~3Ew^$_Xy}{$hH?l;WEwzy~i56pbM_AK^`*BsBqg1lR zV1R4!i#%N=<5zQ(wD!hfKX&p=;L8q9|1MJ1D%3c!0@m z{vo@6{|{E+-brN8KGlts$Iic2VZ9KmtpuQU$u!4-o4bT02^)`wXhFwr8XS0tiRicT z>rc!6g|x_DeN%IH1Q8dxpTFN}!9s6DFN}i>?9Oo`;m2P?SWgLHJr$AiynoTi{9|1) zO2HKAslpcMu?++i-+j?Nd9=P-*7M~$S*#QP++A*CeMenSJ>4OU{XV%@l&!2CUUnVw z26AiXVfRRZR#Y(^an9KqHLa8odF0>%thP3&4MGQNsMf$AeK-(@MiBYN*$zK&2*>%| z{r(2jZ8k+UaO_j`qKd~LJv(Cua;n54%34uZ=n( z^6;e#>coA0#9yT^!=r@&WS3&qlWf1w@gmcj`=VxAW#uLfQnrF0w-?W+mX zn9H8CGUww3lb5RwQgOwQH#&iEWnzDRi&Sx6G`?`lm8aY`@~#fUPvIYJYq5fFH0*~~ z3@ktSeM7v--7|7N;G)r&j z6-UGa{%;7xrkvX4hbRXVp#Ai2lW=uJj7M?)rS{x4({yvlm(oGXov)BIP=5=Nidjq_PCe zt(vkj37l^i1@h4RKV)in)?7c>R~WQzPdm3fjSOB(r^;(VxpXsO{uM)xX6KgvKsvzd zc1PA>y;V`dpjJZ0{K`!~pRFmWoHPe_nhPQp^3nE*yyQf9EemqK4(7%D?h=R1h1dG^8bguHvy;WdmH{KA(SMUQ%N*Pl9^6YGzkfXND3K3 zGG*9Jq)ZLUSB4{!O6FvCkf9_eWh@+H$9!;bIK$rmwa=mN@ArML|9f5k>wW&u`##U> zI@fhB&YJGM_S$RT_qy-(S=B^-iuQ>^H>()(U&h!wA@t)O(E6GCqe&lVRcWq5O{Q}_ zN4py9qHQPyB#+?}|D0fB1JHG0ZuB))rVsp*eU02pKde-`R)EVtv5)OzB*9&hYyMtG z4v+jRqeJ}fK)2^y_RRVe$<8;*Ad-oo<}ZL;x1W1ZoN;iY{-bJ5}NS9eMZE>(ETU)PY2uu=G?boDooZIZSUWCQim;cx#@*`ko= z6fTH~t8+H7uuZI5QQ&NlQe;|S$0uwCht1aoSmWT;=C=1EZz%3#=iw{4?QZ)fPV|@Z zIJE@!?JX#K+L&YWoKqY`cPi|>d98vdHpK&p6*{PX;aDNEiT0T}5(~Ucy&}oUI&(rQ&%>*NQyUq? z*J-pU@G%_SIU+$ka%XIp%l-*W-U>Oc-K!}CI}8}D;PWB#ZKH?v{!isqdQXfCvzv<$ z3BXE6XO1i9k0kV$Iz9{xj;Lign6VAsl<9^2ftcvzLHMVb6l@Bhw4}{P;6k`A$1)pEVZ#C-tnl{sT#0~U%t4F z(3Ax-^AneFn0CnP*NZZF)pCQ(Cl5RY z;vsXvBU<+(nJKIOnKGuKya^THDBr|-qk14M`T@APao!fc^-R%@^87QU!^=tQqIgcx zBau#-q-f@ih@t^{-B01Stya0{DXmy|;@}R}1Vq7h?0v6rhIs5c zGiAp=Q!cf=nF@8S{;hY>J?7@=rTIJ0*3ss5wJDtfFl1W$AYeVQ6JJ9#|s2gQMTQ9I?{PhAo zpXXA7S}~Xm2WUCo_i0(+GQLayHP0@^y!X06HGV88c6u(taNJZ!;+L0H;8i9Ky$*fYDf3MS;}AD%9?ZLlmxni zUcAlnO|_OI;LdG`MDe2F1oE<4)+!I<nndyF3qYjfWyf6}o^{YB5~=#47ySn}{o2{j z5H8u~ESNvNknZ_p)tlUgpM{8{X=oQ{bsnxU9R4LQIIiqJwsDG~q;ZrUqcv$Z#Sj#- zwObV$p~OkRygr)u=QV0zTXH##wkxFY{42d(gEU!ZlYCvT$M+SFYk-WWqi?e^>JUQh z0kvg1rL4LKF0lwPtEU)FMC^{}8_6p2&}*PXZAeXGb=Ldz#=Ksdtj6K@&131F@mMrx z>-JqKYOx|I?sk(5=_5P9k|ZUHBsKn)>@pAEUn?N5OmlkQ^tOR&=)Z5{&zfz|6xY}F zz`H<3=6x82<0NfIbDON~CUKCZyot{P2>x7V?9bKmhE@X*bgdVgKa==7HmqWR$@n9Q zf97k4A+dn&nAKrd@QHdw)-D!pTpCbu(CcB1UnCYLk75xzu?+)HMR|zj`PGQ5aW>Yg+ZL>b_v@y0#F(i#MVYtX{k(L9LTBUZi#O)K?s*ENMz65XP|fVE*!ERH;>^_Tan=ioYf)ov)x z(<81e&@;6A$v&GBxqdXB@oc;+EupW#iNzW30js|b0dV6-@`azVPK~kd|4A2tI5bLq zXw91X74y38?U{{RCGUm=G>IiVpOLCm?%xm?VZsQ*8Q(fruJ^j#LJ%r_6Nd#_!!MQ4 z^NRO6k2zy(EftF^ddiTQmoJPCKo(Csv`gd6%TEk_ zLouE~IK}j{{GFdC-TD@az>M_XbzRBDwMCY#iA@>0M;>%SXhjnkP|?2SivCyoXch~M z0icSHjsiqCS!x?>Mdgn|9;!~e6}tW$Zg884rtcH86WkhUU^H$?9m5fGrthOZ!+`j`E(!*O<}Z$Asn}5?&vSMbghqCL+j}`E#T|F ziHsPpNjU85I{%lh(WZ&Ee}p2#Uo?D?8v9V~?<(~>@r&1hNm%ehE=!go7nQ0vT@k4hLJ$d60Ot1-p7&ov9Kjnzl)3hHXLmY_RnqmDx@EP*+tcQF@DKTg^Z6wbb zhan)98uxi>9I1*Pr`i5@O%v@8AY9%<#WNrI+srA(Ps3?>wU}uLKOLgri zpG`%dBhwh1yo&4IrLeI=joelXKsBX}S|61x70F<30 zt1`#I+ZTtat(^qsRaVX#K%sMqb4t?hEBA_tDl;{O5rNrTL+9cGDCN znWRap)Oz{MGiHk|h%K5~<^gTf3uwAZ2vaoiPRr_c34uaACNs|5o}&};plLlApvm&| z106y0`KSD-c_P;IFJ~{fj)3WJEALZaJiws~VISfAppQ2QYtl_KLo6bcu4|t)@OjE* zdzMFROXNXE&3vtg+3SATv)Q)Gms;KDx%LHin&d`8%U^>#C=JOMG_h zqRF3(bGdt7|1ELN#pO#|zH7?^5`8F_pSAx^(+C~V+HvK5Zb;uD?o*n$1@oje^n5r| z?e3GOxV?Pr?Xmtr;hagbhunWO;zvthI|W~4O0MTy@5=%8TU>Et2lk2GO#D<~pozhv zo_pZ{*mpw!oU4>%ay=_gH2qN%+syF_fUwJ9F13Z1^}rufdf+DsFMRlYv)^>+>#h7I zC|Y=hh&uk1=5EvYqi)j-y*aNxnDA1uQwEh=ucpJI`De9N-}a#a>PW}9L(YfLc%THC5oFetz=>~qad9p=3Ha{+anMwIoC>r#3s|B%1E#oi?dU7xm7C`2aZ3Xw|=L;om^ zE<^s^H|zvL1L8Vfq zp(0=s<7U%0*zJo?qa&09B`0fg<%qM!s_hvX!0$!K3aFT;7a#(#efCLo1h^cPz zz+tk_zbe~RQRP(o33aXm_j&v#mg^&vW@{x3FW@Oz1S#LMT?9kw^I|k(2)YJBCEyka zn8rP$5HiAA{>Y+K`tF%$Erxg~M@G0qm{DhHCL3?M=)W$KpsOH*SR9=k1HsdH8{=D3 zR&#hPyzm19MgCZa(ddSPnz7qSJlWaL!4e9CoCd)&i|JINAwnNUe zr*2qIUhbCV;jsJ|EYA+hv*LgF+rYR7oZN}SO&7d;a?%y=*s17m;H|H0o}@SlG5Q~W zYqglF^<&WGOHPbWoH28&T@g_^8)M_!`Ji>~=L6+N5WJ`Wo5i{IYjt&MD@iy4_wE6R z?mFX2cyFC|F#=UmJdlo4Uwy77Ccfd`&&dj?p~YVD`TBT&BkFu7U??9wFOz2)jFJ>t z0dvF~XQ#v83Gfgwnm+$H?O^{_jL3B2V`;rb zxn9qJc&tj>K7J=XmjPi1_%9>UtRRRo)u>%1jbB4oiQPfh^2?#Ddo>i2953moY4X_S z^eEI1FiN9zYh{jUs7h~i@J7W9U9L+?(Rb)t@?43j48110j5&Pc#OH~ z;|Tqu>%?ZWh41{Rc%IQvQ296`qg!~SXvB}9#cM1mAAV+kZ-I_+SmeVb#7;DEltjf_ zZ_s?{CfH#j7$m+SV~Bh8p|nH_7X9FDW;k5=z8kLx3HczQ6VhAtUW^rKGJ$Ine6M&^ z-(cR=s5x1B8+XEur7##)0vaqe|3U4ve3QWXyQj37-3=m`hF1R+d6}|}t|I3I5`gB$ zQUh-NVS|lfRN)9|2dPG0O^^>x7b-34O5Au1Qyqmlli7F(Y1<pvofpIm}F`0TEU`zxs~mA6{&(3qsQ72w6FP zL>v07^UbWOf}4z6HY=RP16&r`+(!D0-dLad&Te8pa&Yi;R`f+4?tRpw!kw$5n@Gyv5=)e)_k2FSBQy3UD8y-zg)`qp zKQR@3+UhAs{SZaW@jOyy(QES{ExPaRHX~5Y!BHxyg$FsUmAb)P<`%O|8|F4x6 z!~XeIxDAFoYD|wMg$HHbYMmvd3&E+rpq=9@F3l;oT`!kHa8B}K zP@ICH9f_wOq(43=%CKIUF}f_uf4N>U&ku^QfuHBho0iiQ`~xGHOuJXOBcI<2o=II< zHZOXZPsOApMq;ZqVU_|v5j=D>iOar67;`za(%y;kSht!P#cFtpd&{j&f8Da7M{nVb zd((AdtpG4Z!AE_|U5*@YF zO$_sCqY`WNHVpq;ip`lM*R@y-h(5GI!|xbyC}Flv@M62SacIfZWA=6-G;UWBGP1Gx zCGl~J27q?+L<~aLw5X&z{}^?SsG{(H(J@N>X=KiNcf@3*N=EiFLw(Vh-*B@Y%Dn^I zEK+7@VS}5$T~zJ_6)rFaQMY{hk@vs%N-R0;@l8B*xY^;1b94}tE5Tv$E~KRDZ!C$RhvY+m)0JAwFV37Lu|1*v@=zc^iC2vM_CL z>5s`DBcGz#la6Pa$-f+_&<^fR2*H}^zv5#vy~b>8Vh0~-KmEPNzRPT{AE%r0zR__1 zBhSi%PpvX6j<($L=lQ6)29ptaQk3oOfK$t%w`)6>MOwOR%e}NbmX@Em<#}m&s{Fs@ zg;G+xplTaVY9lRBZbl$o@PcKN>zn3a$JCR4u%gUHXmZl-_Krtx9IbBUtNjkrGbF5~ zaMx9jZ&N-cmr@OO{e{222e=urT9@)vQud6W+*B6@_;yV5T+(}3arNcszi4 zipSKRpJ=2ZLZfuZGngTjS%n)1?AP7Xh7j8O*L{=*2xt(O!9`)QR5vtl!tPQ zUBl8JZAuk4PA&y@N{rt$)LVhWrGUI;fmN7o#}_>pK~R)^FNEBSELz+;HcTNpas})Y zm}iKlKD^=5^<-j;@gG&v^ExjM)3Hx*o-s^GL${hmUagQ7yhXqo^Sr5R)gIooUWU#L zBE=&QD8#HO%M0X75eocgG4`W@X)hgl%_as$49?y^nEmKi$n%v8&FeSogx(y+djx%| zLkyqja*hp9%{@0`EmmCO7TC*BZ{%M959{ZXignD)2X`N?m?5fR2HM^RZ&Rv~a9%rL za)K>q9s3V#KmDOi`o_l%8$92sKQxqQuRg?a5{e}21_8xzpGiZ`?}G>OIo9zmSGwG% z%R_4UiCUge(8+gsK3#sDEWb_v|57F%iUJbDd>D>OU<+|xL6YASP>A0@v;qDT$xzs>zS0R$5C6}?ZcltG(C5v8nfS;OJD{>uctg{#O#HJAIh#0nBlj&r9uve^nTW8cW_?{F5O z8_PVPCLINZ$v|4CAmF#5!uS6J>NWlUQZG^qlW7zZ2JEN`BXGvWU6l`EsLIc6dslmN zml?NWd#Hr%mP>ik4i<73lsT<(4uw|g4RG`J&NA=>np9ozMp=$$?Ce6jw)Nf=P_H_~ z!bFVM)lvwrQN-Q%9f``+Q-iS5i0=ktZkDOx;P&XrbaNq6n!e$Y^zOUNTY=9j_;k$A zsT1lpeeg+OV-<5ZJh8)a;H8!_z}xLSg0{)rSWh04zjiuNjDq!fy7k)KV0WhD({FC0 z`VPYg8ouN>Dh104rsW?NADvdqAf8V}FM{Q5ODsEbs@|j@CTE^L9GSh2b;t1CTV)5| zcp!e}JGSbdU!MTvP2Jf^J=rB+tw1pVNo^F2fTcb7Kf#w@+uvF z!H&S=_=?X)Ru@8-9EERpaQ}?^G+}as^HfOR3f%!_hxEfH20Gum4|`+3E4lC6AS|+V zX_LPb&+WPGxwPoSTTfmTR;*ic4xTYt_g?i;SK7>?h|IpOW28O5om6&z>_DnR&n3A% zdk-%S=Kl!MVNV7z3wUwo>#)dte;YWqY<8B2g?{&j-vKl`0sYx2%UJGFn=g;JAWhi) zW23DEeZko#O#dvACKd+vxCyi&RLh)Vo9uJf6kIiVuC}ZD0tOL!L4Y&2NA&$YN4^e; z+KkyD$C73)TYB_l3$Dp?kAS78vcz8K4UF-hCiZP2D8=6Gm} z{ff?P&%dIXd)B1q;lZiUJCE*t#2_>xGXF?mxsg6mYp6xHF z+d*G?lJ;a=QOr(7pXH$tx%9%`?s$#=I&KQ;<|6C&=t_D`f-3NSdo&WS`Q#`Pm@ z6pGb8m~$`8&XMFJE0cKe5yYt|{I22qjwy}@bfwUu3zwgrx-V-qfYoVOwJY!Xajjch z5x$Fi&c>#i^sU~o;IPiKvVM2Mdc&kom^***n%NIW`>r?wi&k4@?>muJEhsmQ-~9Xb z({mcjRWEnQ@(5XeWd1YekjSDw;fnHFw_?NzHym(o@KDWLCMym%Y<7}yZIWS_S)W>H zWDT9!JhHWB%Qkn0er&BmeC}FL!Wpku1yIaT@Pl_K1g;|g!4%aZtc=<=Qo0@m#oZdk z@Qg7CKBnW5o)oXa2RPQR%t#2kQhrYzl zgL+@ALHTc)h+H&@fP&@XOR{#E)1R(GTPsCMfqGlJ>9t_fl-~-|VY0ALVf0J1itLG+ zLfC?rgezMSGh!u20)ULyVH@r}tN`GT&m?@er?bzPgBum?sRm|Gbv!7_+zhQV-9tU( z$5_fdD|LB#frK*jG;F?FB@6F7&FsW~>8`8#S!+$xl+Q^s@6YJQ{@MJE7LC=QULIHU z8o{l35rE7onV0l;2A(hK%eu>i^D&4Fz&WNfX2JG-1O%-wfVE&8C)|(6ID{2mWw@!j zyONLM_}&`v4Yx_z*z{+uY8WiqnEYca?_AB5Q@xgEM~Gw0sE;p7FVa?}aY&2}+_HV4 zow0L+?l2P))(e7xgK^xTrBG{!|)+e^WZ z+FT%v1UKF=n|b98Hol`D?UGeg?qaau`lpRWrHk1H9q7(k6Y)hR*@hQ9;^I+4-V8HX z9z^Cd>qO(`yVO0?E?_JARMeR=vQRh#CUUO|C@k1w&)=si58SG8y=Gx57xJAIRtJzq zQk|N2(Xc%)Vnf31z!hP?2Ht~CNkxA`x8YyH6#9fh1O|DOLL%5K6hIlNABUuL7Z&a{ zi#%_~U5(YQm@mtk|6174>h=2V>`?*wXxM|t9V>kU+n@t3)0Udjd_JGKcVM21eQCfc z0XQ8>SR`TMH)%U)$#``i71%t*1j&&BdX0Q<5hRDjbW(P&X6K<4?9St2>E4x7=VYb% z4DW+Z#<#ERk9I$??m|DE1%^Yz-aJ@fxP7bQKMwxmnWpt6LhpzmK`d^4&e|7Z=mw4P|faqgVpA;hT8ltwo z$MuXB-n58ZL%ja3(|aa z?b`8&n^ei`+>9WzF4_xWV17Y$Zx$G{$_Qund@Z5EH1#jp2VAS_oHh4K`_L>)wyoSd zHovCL<0kZ%Wcs&@JTfyCfI%T;sX}=$CQ^}&S_GhGTzALhQq@pA{RDT?ztypuYD3ZU11)n1>GU}#j&SslQJVnf`Og}@RYQEjJ@+h@K z;cKfE zNfr9NW4C)r>;C7KUYfP;wu87(sDU^;igg!yHuPFpS}>_1dl$Fxv*OsC^FK0iqfx>^ zzbuC(XsK7SD=(BG$$%~Q4#1C2SP$0)vFxTR=S`O&a@$h?2an8vn7lV&!*~fT0qcN; zc#b`K<+HmqQVy0Cf@x`Py2QHsEN69gq!Ws~fpW(H=O;6H30MdA8tnoAy~pl|_S_TZ zuyPxH`-gQW8q9klfrd9WWZ8(Vrp-%Sy-vt}mC@R>>nCuinCR5u`VTQZ5%rN_=IrsK z_`wpe4%n>k*y`C&R52*+hOF4rjP$olth-Aa_U!hWz_4I_a0~@Yz#(GL%CmIs3mN`L zEkz=1B{=Bg7skZTZ|WBK75X(J9x&drNK}8MH|CO_VR?MnvEkS^A5HtDBheIA@EaD_ zaSYJk9R647Z%YOu%7y!sY0{4h5K-N;hdp)4UbX-Dt=uRTG(9&Yaq|3Ve&!=>`m&n zYc}tUe2%wCKiGOd1x$v9%p+ zrAUejZ`p+nSd&=r=C<-um%$2-2xMRnuc9nq`5Q6C$bM{PVfS=cHpEX;95>^p9T(6 zaOO8guyE?3Ej@9Ej`Qlg}+N87~f*(yeRK8E#?hY-?tyI zH}N#pprUuTIslZD?I7E+!#Zb>745snc6ZTRGlZUAQdiD}JudHFQHQCx7=xQn5`E<3$H4PK!t zrkZDD0fz47zhUTRA{;mNyYI&QJi#}COTX-x8h{LRfBG($2|pKis187m8uPH2vHB$= zTH@tUvhLv%U&}S>7OsGtmt1rAJ$Q0okw^7kX?abV8u$AWmG@r?R+$a`74 z7w1o26h$#~I21#-7|`7z@L`YmxH2a~D`?s0l?EU-o#OdEMhV3>bP~Z{UN3#r_73a4@0mKAr$o-WcBhQ!rRm*!6D(B580}5nv@1$IVT|exp62*d&F7D+i~?C?Pt1_*7(ap5IRz3HkLZp^>g<_*o%EQDsYC`=vqTd^7q}X;7<9 zl>4q`9{xqvStexmh2}Q?yi-!~L&WL0kw2iiHq2-bS!x+O$07j!_oC;)AHgm!PH^BT zAiWdkWwNRFa$%RfWQElf}7B(dT)n^fG!Z?jUg zQEO2^Y?L?vox3%<-2=J*qaUUP8PR}hBUsk|^B_}0p{;Za?`j+sBFxS+DRU|zsNodu z>h30B=XtnC41ndRqhZW%)n|4l38Vyj&5d*kT zGd({Kphl6M3m@8fV!wL2x7Pj+txz7J)D2}(>Omv4l`$meC(PE0?=jc^#jQvJ2#p_y zxoBtQbB|z?mF{I-M!r$wBadaK+c7hLs4P1Y{#D?Xb2Gzdrp^DdUIjzA0H1Oc=ox!a z9U=Soi7Hby+Bi`A$XVtqg5>Bkj^37iwE0{{g7}BFIo%r0N1skU)ZTFa zZF+)c#5qNdOMP2N&1dfT?#fp>y4AjB-NXC$N=;1G^kp@@);%zIe7gqTt%TSYGzfD6bb)fAU?* z(dYY8FlBaXyXO|RshmA${?501F4T5GrMv#~r9B**53~mJ{K@yIW|QJ>Lan8GY(p?x zbzQO1-}!Rer9=J*JAYPq=bwCsH!fe);vHSSQ%l2idH5|od&|$%(uDGV+C%{p=LfTF zM%|F_heDMa9bh5HmB>%XT;f{xoN&mNbq?czo=#zU~yaK*f8;>6QQH zYZ?t)qsPW#WN7Dg#&)@+)V4TE%;9WPt5LTY`u2^4|jKfiBc?iQ2q1AOi??Br+kW1f zD(b{Q06+(ra)oO~^}*Ue6#Qf07yF5s2k=531dm}cG$Q_=e|8e?(L6l@r6O$UZSN`k z(kA9xv(w90HZu8h>rHRz9A0(AY^%}NC_dTI^_OclC*R(>OW^fy{g5YK_j50`s3%~!{-!3UnhM!&hd8PQSYVm$?rrCpE0^5v!aFm$vti3DK8?g~1g@oBR4LDl&@;w86ePx<|vj4Vitr{2O+!757%cbU>&qAFCPnjc*I z4ZKz-eO)Znoh^4+VQ~kbQMY{cwT%v9X%6+g5ifv(fMKXmJ+2agf7My?~nuxICU zLaK-VE4vqp*O77f7lRV$P+wwi$yrwOHpc6 zh7#$^gfw_DqsPc!S%U-@lD@j{L9@-#3J5q-x?q6}so}a%CTJ8Mrr>GQS{vbW!Xb(Odw=Gfp9qb7yEiE@9pI{$a^?#twW3L6M+- zN|#pRSh=dMr6b>>0N9vRaJY>nl@X`ynfUmVN*h6n!I;8K(faWa0@MSTI-1oLG1jx1 zXLpoCd`(SJw!@c6OGQ`O>$YI042QCy&ft96a>WlR?9i^~zXEQrn3ekS=?3DDI4D@i zzT70JX(9-l?ax}^SoI8_cK`~6sdR8OpmwGB9k1w{IH9ku2Xt`58(e%ZpC6bpp{8Zb`60$Q-G?U zErO+rXZ6?2TQ+qr6+>?$P;FVw6(bFj^W(qUuf`f0U0Bcp2W9?ixz&s1hF~S{3ZE3T z!U_@Y!f zA{(xjuwsr2$6>a1UTxY2_vTCLHC)$A-VlW@-pf02CXtudanDjV#rp6br5uW_ABwgU zb& z-eY2$Trt93L;@4WvJLZoyL1XsteKR(65Y*M5)) zFnks_ikGbp9Xw(?Txq!~TZ2kV0c;fh5!#M>cH0;X0GdM$N;1iD6*rA8Og<$NsC4OpvW-@nxW{UUv-YF7>r)2^{K{ll$Z~?6{_hyBSWMt7#=~te#$5B zzxQZ{;s8N&=vSoKHv$$GH5I!IK~9<+0eL)`kuW?)!Y_VVX&OE6KT4&Q;BYkbOMll8 z$qfnL9g&N};@9JoA~Y@b(u|!6N@&i>(VUKTA_zKW2Ad6~nA1|M2v&C;BtSGAny{_Lv(COawdM zA9%7oYAEG6XN8be=JQWoylv}0%NlHI(tpZ#b6262@}m;rOqs`q&$W`Hc8ao@yB9fa z^--`|l5ZbdW)Bc(!n$x-pyeJ~9z)Ad+44NZoVb@K#{Y(|4vHGGJ$#D3K%x6r)FM|A zdd5)hnfYf|Vov(g6%8z*$){PXU)3aT86yNJP2UD!xv~QQEcfBloLW-Et64be>seY8 z5syD~B>_WR zJ3}EAs-y=p?eCIXKUMV(iW`iQqH;u?F|DgcDEI>hn(T<(e97((6v=0{qp(txF=_zP za^EE;Tkg*^TIamqRT=v&n(DK}vCR?bAF+lD{OU(!z0=)~&$jBlOy4E<36CB_e8!&dHlTqrg_(FW1FmW@FQQbAK_qaiRNPv9`);>5 zf54IA_q$cSORx$OwBHh1==9~Gr;$Py+bX@?A`22kU2PalqW*(o@^kznFRLmw#ODkmbRU#kTw)EYA$fvm$tVEI$a#55oV}2jTD_^%t(z zhHi>*?rr|d;mn$g$oPfF9DB!or|}Zk>cplEKR1^JksvJ2OT18>YM?j4Z5(2t<@rg{ zd5Bgw=V-{)M06Vu`Ji{xfZFA!gnygjTPH@P=V-fF;=n?y7jmvZ$6WX3iQN9r7-k{( z<6L$=%d-O33dVP~cGB05(S z&Bptncy)(p4g`Oax1fF8K7Ll0fcbFm{3r=K0sLtH0TROty9yk~`QzT(tqDZhH+g5^ zfGZ2=!Cjo^*Rb#T94U)5Z1H*bg2w;rW2-lCNRe^b2pvE_pm#WS7lul^)^&fyMnZV} zv1I3-=JhWGVy=DGYqw3a*ONHhR`EvWko2Cx#}PxbG%SRLGQ+m2-j%C7=yd<2wfl}3 zm&2?D@kZw#BwUU(nb3bWZN4*wPy}3Kfu$-b{!5 zV9RQ*)~5kop0YAZ6K!6GfM#S*}oWhvnF-06+%_Abmf*rz4cr z@d5w&)e>bHvJiWNDq=O>Fsok}9QR1QaxX&+aUGZvekem6iXUhgEMxsTOD#iyFA~0N zviG{mBc+(xjaT)4b9`)OdG97L9UJ%(3OQ-gp zTpGPk3@X2M9B#B~wJa2k734En8hw}k3sk>A8pR;+EC~b8wxK7Z5)haI@N?8%dx*t< z^$QCWy_Lc}y*~!Y>s!(LsZTQ1?s-fRvjSZ=br5OF8%eX2$Qc*|?P|sI-jiwk?vZ@d zJYE+I{4;3Z0OFkWzW4W9M3U9R`G24WsSh?3wf@?WdjidJYEse@U)Glm49UIR)%ar3 znx)dDshs1s${~(x8H^@^P3h^{FBjt<1|dT?tSa^x9h9C6w1_JjQlCM+57GkAph=oRWFA4iQy3xWZ@Qq1w7v_1Rq1JA$C;DDn;bL}A<P%O~97R?b1ky3x z5JhWz252|r*dzYB`dx_l4Go`T#?Wbt=|E7rc4n=}*C}We(C4l()?A>j6iM>ox*V&M zhwz=D_3T+<0qhfQvVRkOne!{G^vUXQTWKPg}i`QJGe*kyvvLO2vYcP{A1LQef1i}XF+hjrK)uPpa1e5oX1iZl!Q zb!Mq{T&?Bpzqxs4;3!uyocr6rzlhs?9PEi?BdO-M7Nz%Zudvt^YfYf^bux$(0YbY$ z9k;rXoXS9W^iBN_4{Z5JC)K>N&tSubA#xiLjTK+%C%v=WElHCGXGr?G9Gl+G!{bPJ zGR&Zq4Uv5&D(rkVodIX4uXMI?@#I)Vg(F-?Ncf+gT1Zom0wbu#K};^gF#Iv)FF zUVzs5T&4a)$Pt`7HNVqSra;WdB{)Lqp=xs9wb|*@ra!~ZpJU3dippM9 zpfsr)X!NDTS8&y;8%UkrEUlosNK2A3oZgrLv99S~tDtcf=aC3MZ`D29=9Zjvb51+9 z8zO`qfQW0gyooxq3*wsDb2TdZMoA<>`zsiJr>$yO=SQ)J(Jr$>n|&@HOXQj3@*uvF zI+KO*zAzr<8kuyEgtWgZM`jxbhubOXckfY?%s&6K-}aa*D43>}wLfL{f!CAa*+7K= z&6SvDuKdz4Rb!(h3giObl%ok>{)et7A%y^bj6>jlz@$}%*vCjVE0L)-o4g}hQLr1o z`zEp}EYjI4G78RFXNW=a7j|dm8#%muFkja(LC8Gj8Y|C9=E|U1mn($ozeHsodx9sQK*`AW3%hia0D)b{OO96AHtlBwPTo z;YpSHmT8ru6itc#F^b`05d9DrX>Aj_bU&c!khr07^`nB%%o-MxgAisFs4^oV_o**qt-;{rE5XqTgZ*_*Iac%HMG6y^w_S~dpkz%hN>sB>hu>saM2KkvmH<`ZnZqcGJ%LM!TAJ7 zdm$qC_Qp+?qV66z_w}q!!As^g2hLjgrbp{~dgy3bR$ybyVp-kmK{w8)%;7efY9C}7 z7KNHY`0FR8%kQsGn#4SKy9peUgCICWi9{;w<_Qw*Znf)V30vuv#3oqp)SZg)R<+_K>{NmkVs21CCi5F#%771 z7cacF>vzQWBfU2yh3%U+LC!IzY~~WUUX4AIn1;rk4^H;pwP^ zsDlzh5DB!@VlzMbeKS*wRnte6W+@PN)77l8-Mwbfm(o+#tExxX$X_A!ct05ZLnQu2 z<3+)IRr4cPTjeZj-@b115lsa(E8T;)tzn7j*-Vf^Jj*dNycfu-?~lh#OSa0NoV<}y zB&I)GSo`uYO`*?*JWE|LR8ut@`l+x(FuSr^{_*<3IH5Y{VhZRm1^TrQTZv8-bbenZs}Yq#7N&KkbDS&E>J|*VJ_1YhA*^E#}RRXlUmJ&CspI zh&AyIYnY{`-&jgLBqLMb#vuO0FNxB(Bnle6d2@X8gCW=-2+DL|J^P2C6s$9*gc%QP zQv5)+EzrX_@JPffaQYPchdXk~G?G^$D>~J(`0Y~a_A{rG1G=D0<^>XwDVPjmLN`Gx z+o}E)$0^w#_KJNhp25;vtmaF|AvB z#y3Y^7m}aYqSmrBA?Mlp+Jt64=}(ocew0~Nqs@`Vn%Th zs$62BBIE5GUWQQI3}zR=$=met?z}qRi9)OVa_BPGMeKfbl}3;d<#(KQYvU+7LjfRz zudtR}d55l;9V;~0>*K~D)*Hoybl56f@kZXHaCrZDY7&(p7?+$wz|9{0nzHEc?K-R- zzox~ruH?6l7ZPF6)DGOhSl=mN5+i+v?|`5F&XV7@Xi8`JB!gIR zu105<0JDAOA3-EcIl^MkDa&@e;cwwxd_2)6yv|ThQbH@{fFgvHX$y#uh zT9i;7?=3>^*eo%qF^vMbe$=q`sEte*CKsGKHum*rdO76hc2W151~UFFE8E>(*}!p8`I@n;@jR zBQ(P!o}s+9@f($47xy@u6;L1L)8eN}W#nm8JH2T#C#p#?^LAG^s;vd}_SgPfy`|}m zB|tZ5*{7{9K@2A!r7 zv1;Oe-t7qixEUN2=dU>T28S6l+BU}Wc=J<#kEM}27M!x0?D#Ju?*%QIQ3=xB`MMw% zllADZ`@taM(h&Lr2ChTqXR{!Nb7!riwX@Y4XCr#-bY@WU>C=x(1|G}WA~IR49L{Ay zZrxlabMLqLRLW3b3K-1=Vv(6ur7B&}#P6xf=tPja=W+fp&4y?d;ve~Bhm4GRLR*#y z$(%sdt+t$$8X<{BsUt7o$8F!8hi2=3&(R=k_5>y?eQuyWVdrO8+<@0?>o+i#%n7(a zdn()&L%g%Y=PlY^R(e4QnB_~T@VL?s3aMO6>SU3LOcC!Mzw>3vGYs)xEfhCwY&k?3 zT)2SNb>98+=t#y3pzmguL$rn&Mu`HR%Vgrrv5DI!tj*oP;%TinU@JPjA`t@p4*Yd3 z?f5letLfq!VC`A;Lpq6YKq(NJ_(HCX)-**gs;$LRmw?MTABfDw4%2*W68T?szIoia zDyB5ETMU>4<0G^JJlIu9n-17Jc4Dr&d*Xj7Bv{)c$ zI~lOeY2S!$%PIfO`e2d}0Jjp@=747i*xUejN57YgxZGWcxyw+8??+5Jb1?FB5rYP3 zK8xU;SG8ZP$d;)yf-Mw4WdiHu!xR!Dc=Gdr1K7`wSyY(s$G23C!r+ zb%X&YO`zI?8Oc`#I1xaM9}Y8LtJWV-Hm#Kfen))*dd%GlYMi8vifilECpzIEeJGIB zu&x-Ho?B>t8HBux7zPH1&;CaaQo~q?Qmf?yYldQn8-c5)rR@tkXlgLNzfAQP7JAS3p2kyWe6=+r|4U*PbHvxB{W3vKY+KxCaZN} zBq7T@kvIp|kO;W`3ryv#U!>HsT211F@7u2bxomSlHX=f$;OFzRW@CafaO`7k^Y<7; zc+Dtz|Cm{kxRXlbVERRst}^XUhedg8@9UI4{VBRlAnzjgr)u5qH*Ywn%$yt^9&UKB zWwRi^U)n3NYRfkXI_nj8h1@);HIVS!X`NfDH|MeHcOonHO+EB+db?b~avv;@gXL#o zc|KU46aP297oKL?u+eBFT$|e+1{_m-CWwB+d^*Xwa+EUoeGA9teI3gHxMft|GJo(7 zEO8mCxCC}vCPn^dGd;b#AIQ9wK1Q2bV)lqC*>$(_I`< zG~GF|nJ;}Nam>}Ozu|N*y!rQC^ldao>*fS?qrM4IhZnS{%tI9H5a0C&&rMa{qg=S% zYZwfrxr>y}{9Wi`ZlwQrhH6$#>H7XR|A5b-WPwF?9`Nb@n*hx%uT+>ZsDH!hbjLSc zs-BGhBR;x1p$+m=>!9AZ#s_376-vZka)@z=vY7aC4sDcU6lsjeQG zZ4QLcx``RE;!IOIZ~+bdjg__4MmYmYYd>o6kG4z&LGD)e0h$-?TPr#-!F9mI{skZe zsD18(ld2s}hTu_(8wCA7?7ay*l;7L<-zG&-R0#Q$N~K83l4V+yvZRtFVPuI=NcNZ{ zS;Dl4WEqjjPRVX4QOJa{RE%sxmZ33*S?>FH?ioJY_j#WG@A?0}zvuaXpZ~n-7a0)FMaC|(*fydE)@;#g!Norr3d`vyZr^DcNaTFtEa@O&T` z)lmW*a?Kh;x3ST9fA9i;w;r!l;?%<6Th_^(}TZ27W5K@m5Q*DgEU^6|lAA1C^2`As@M zt+yQmSVf^2>C^8-1h;t=O(q-Z6m7e0K`1+G6h&$oOYPU6<|5oq@xHeFVA>;V|-ik6e-%H+4 z3y`%`I`KHFSwHT8nsG@IN(18yNfZw~6fd^lwPB+!ftZBXz>vM3S2(?X<~na?pNJ(j z)Q!hI4X$hDxVDje&-X=*tv`mx4EcAtKjS#)%cuSz<}-R$4IZ&!Z+XYgGcXN4N{|@Jqe-T6W_crhHcRB71D$DWxue6K_fTLayTa;f| zCu~c&KkxHE`{8Css}w6hYQ0m%sP#mTO+>SG->;Xy-TW$_<&N6CSJ*{w$du(NTwL>|w+BQ>T+58!<~7o`JG& zIk=hnxHIm_q|K*S&jF3@APwN{K-Yp(0zWR3TBUSmNx-TnU$5U#>5b##^WlQ`<@!}M?biP1ck|jr?FO(hE8&tDhhk)w} z#C|Ne8h7fn)yVfzwnP^K@qqA+y`5SsXB8YA+g9>TGsPq)uTKB9z~%D=#xz%QhQ&1V zykZS+kbZO$>g7_Yc$@BhiOJQir5#8e;m>mnKZ%|>5e!STmo|H$8tRL!Zdfd(4UH>% zl%C5ij-S5yRF`^WM28%0vvS!M`g!T8O^aVx?yy*ycx`v!AuW{C)(Lv*dMLg!%Ow`U z+o`P#AGTlpm2}y{C)O6B&?Sckv?q_#?TceDmjQ(Cy8xM0f%y!E9C!weS-HGtq1IMu?zSHFW4@R*dH5P=Mp~W zawcssbh|QEJqSHFsO|b;XV*4e!Q9#=z(eY^=<~{-{CMRq1$`LBc_Ec^F7C)e0&a znTtN$LY68z`r8GM$aCgV{o#mrR=5Ohv$Sp{Izff~%mjsezPu0Zq;l>|1pg#AZ>kIwjp zl5R{MBfAtGt&TTxHJbk2bWUD-=FVGJC_Vu5RsQB9)YNPqk9(rrACn=LB`$MQk zJFy=N9k-asH`QtPKAWoCXa3xHd)9WH@#6=M{dia>IGS~K`JwgZ#`*(4gPp?P$V5uD zo20F}xvM1m$@?$-9qWP(Hlnigbi@`Jxt>38KT9NcCm(KqfGPUXzD1e6Y{BM+>ohMj z^Q(5*Ejm|Y_eCq$vgG-W8?Cb!{f!zHW!!4a3^T8E)ju=)Z0apNGkWo9o>)N1^ZoIA z{gx*4$pL;B^$oW|+#ceNA?{PgorgFRH+N$EpZDtU%%ixx5hY;J6!KzmxST~PPSJhw zX-~_kxL>n2X3ngdSiI6>A;05R@KF4H!S}?57V2DDdCQhjw?h~9w6ml>nzDu|B>U}h zU1J}IbxR*&N7G@WP-G!Dtv04)v*fE|K@uueEK3T}&?CCcE{&@L&Cf^7iS4d|srl5YKDB-#x)&JBHI#{_}pP4&2u`7h#zdK&GMMJ)btRVLw%hp z{4>d}{V_ta1HC{dwnTiv0^&aUl8Aja;%n#cGj+9$y`O-AHPZnjnC-Wi({amRciF2i z)>DxR`ygJ33Hw#dw#(mSJ;uyZcEX$OKZR-RN;q2;x%M5;jM9)Sd68h4umvX4(IxC_ z2dl$LkF|D~QfzjS^{G^~`e+}Un9*v%mrX47>%XodN>2Q&1=#|6^gxU9h5Dij;2e0p+1)X9nmAnbYDs9M>0V}Oa|jcxHTNCOK0x~oZML`;kn$jN z($N58ecQOr?N9vf$>%Jxmfo-mlS|o*%GzGow8rV9#`{>~MFng5@1Q#7?%|At&tD2H z8rn3VD|@pul;pZ>C38wZZW+=!VnVTo6V)@e#Rtzo$E8lG6x@>&K%-CUfr9gcSH zrj`TxSNoOTp$IgVUBe0*GBF8)CQl>+2_)m{%cnGYmYk$o3GweqdS2)^AD7FCpJwKS@Hp3TdBV zj?A@zJx#*!&Er9fj#|$bX>+X8eFb3SUHXJD>{#-Wr-M|~-p&xDx>CMKJ$ZHIfIsXY zh#>5efD*8Pup9q?_J4mRYh>=IpTm^}%TR=X!~PX}x4zbx%MvWTa=`euMo2P&=(s$w z5woTnZe4sJ^rfOR%zU)RjP>*+Xe$kLLlFdx%z@zDf3Lz6j2pzHQ%Cct$~SX}%i}|? ziu5z}8{=wyS0xl^)#l6oS|NThBr)Og87qzD&8AzdJJ~9I>Xc<+_fMAyg`iyL0c3-K`<5M@_G1>`uSXw>Nl0~n*cLk@=DklyMl>at z2+rB*pvi~adg>mUQ1y&Z{qVj@%^K?burUzeIZ9fi>VFa!C?oB5Yx7U`U;=uL1mB(J z&DZD;G&#~ggCWM&c2oiM?&!euHvi>G5w$DtWGomZuk8>$81jBZm%d6}EKGRSnT6pq zaC+}`f%|Q-)ARLNcnUr|wHlV#k}f}@IBC1})Ltz_Pn`ypdU&+vld9G!bgO;uhZ6}_ zp`2gaC^G+?2Eb)=6ogMh?*PZtQ2P;54LFgMP?9ie9fj5!$gE--Z@&mTsrL0rbx3)2 zl}6k}VaA;(xBcXyS|r~*KE`CwZ+#%kZgV|yDD81i@ zo_VdFD1=-W2=GvVFUujukyc-~BjUdV>gqlyPENi_Ptv0i{aQ%mvFbE6kxT+{xccYa z18mxxgCPdf9v7e9U*Xq=*OLF-U|zw)!}IFGz7B-;HuzlrT!)mTseb|B>49?N=}?DS zY`P6G&l;)V*?%aQgQ|O|QHWGD$@!^IlOxDs^fT{z{r)tDa;AtrYVppK9mmJ{iwFG_< zaRTf)BEAJ7)hV(`bD-S8R3jNMJMZ_`f9||7) zIhdCDO2*H2YQws9r@L*-s%US%iOmXCp4Kg&@Ap(XpxOXbA8913K@y{DiZlsvz+$*~ z!4L%2pcocY6@cnG$bm3@&OIu0v<3FQNqL+Hq67HqPhemwgEs55IJLrYZDP#sF>#V= zn9F&w#Bwjz1i)OE2nSp!+2-2$A*jFs*S`Z+P+0bNfPduZkCb z?A1*hg`~RYv9#Xmv4I-XR|cbe^*a_4WQJ<|k4)1D-|*E{)Vm+(W5fF0z*h=*UnSuQ zmun<0I$FsH)}{EHnW!A^T3C%K2u=v6fYl5`oLmsMxBEM&?*FX_*pG~p0?vkXNerVyt}+5vNWfuEU=?a1 z|E#gab!7h>V#HnNJZYnL;cb&-kppRkyu_Ez78Bv&pL zXhsz_Y)a;Iq&dLO#kA}ZJ4{M%w;6yK#$5~WyYhaTUh!6P{Eo#!@O`71KcnL!IOsUX zutkv!Z6pVK?aap1?JL{HHn9ATsgpWyC-{kd+t9g$D$uT&h-8Z4sKPZE>4ks5)P=$C zclq7q_}{o8jJ@N<&&X0_zap)hbu6UGoaOJ^`6eTa=Q=UbVlC|>H-jjgc7LPL;BRwk zS3l+v@g(A+*GW^#u6BP=>IM)>o!z2XNj9ZU$}>HD_XU+7BCmnhl4_xw@mTGm*m0mA zAVwT?<;mq%hg3|ajw*lwF~DnsfDZtt?y;DHtg|(^?)Ou7CdvHE0nHAz4uI#t!m)SL zAAE?90=4CDdPJ-3<`EDNY0nKJs%ej8pA7@}ToxXWz~|UJyTP{4+qb)R{S`hZQoa7H z!y2|>Bq4P^Y4Wn8uyBbp;++Ff6q7xZ;;Alo`Fr_x{+&`cyT2%GrTOc>QtEhIgV$}; zLNfD`GVmzqcS>Eu<6i=!8@88JwyU!#btR^NQiqxuMJRRRveUz{TZBJZjS2Kwr^Sl_ zN*#m9BJtxBa$Gl&(i~K*IyJ$3_iE`kn#-$gmLpioyn?jPsN3heh@fMx!zZnEBC-~E zSc)~qnGoW3O{h=Y``5mEr_(_pwGcQ;R`iR$=Kd=0)9%NDo&#sm zMdQ`s!*dK31CDuWkKvcZdjF~9q44GUT5bicRHo1LOO7^Ymsvt7k>B*$yd`;LPEqZU zTK*PaNVD0Hs)ur?uJPmRGk-VyvMx`q#>xfw52UFImrA~OS4IOz}Y7m@?Ue1s4$_{vr;77 zWoAWW5oh8oyU5RGm9n50UR&hqO#Mw~`Rk@mRi0)+Vb2}FG36R(DZ?C>U@yTl%A`Xc z#Hr@e(;Ar6oo0xMmum3D$79}ad-g7AFt|@%v|j$#F{fWqxUI`4IF81ZPV+9~KNIu4 zw3jmz`@Lo5&cRG!{g$sBCv9cz2CeyXWJeQCd*+USV%U|4WLE;2urAo^&(B-FGQgqx zpliVC60&#k#E}B++jT%p2aQZ0ETr>Wy)1a?LFsbI`Es(TO&XBuYK?oR1ow7!UK`Gh z4LBzuzbv4!aFhT@bqxI1{3w%zf>cGYAGkBDC)<+BYV;Fc{o!>}&opx?cLm`8A@rEJ zohZvcN&>1*S_PGNkq9Rr5uQIud1sND+qv1 z4TWYnFZ`(&2g%3rnD*PI(g%iqnv?nyf6@%5w;$|Rd0doR7YV3&?Z4yiZe+4Cbq6-L zpNK3it8?(Y1Y`WRynY2Rb)z~Gx&$<+!GeW8GR#%4>wslPD-2!1>Y;W5d|*PPy4rOa zqCAMTyCi=cM`yehIQC|K#~jz|p2zNsF`Va?4XRN==h;$`c5$XBW=9iF3Z4T0 z8ECK{Qxd6A(O$N^J$Y7f(8B-Nwloz&w6?d<4EmRu>vIp5J;m~IYg?bX@TMQgx~mG~ z)H}SZ$q89dsarnYXBbY=^S=FMnw96i=@w~|jN#dE_gzwW>k730sNhaxisCsNyWoL4cNPHiT9H8eL2kCUqVMN2^em2Q<2OKHJsb0O(vAndmSN zu+xwy@B`?aThdDGBw)*pFqFT}bLt3`QZWv{x_4F+6VT>xj))@bBy8|itOTe!WbS68>b7xEbd*5v8olv?RP7HPM?ClH^mbic87fOA(koKJ(J(s>YWWC0L(1mdz zbUTlHrT_?C5itQhZ9OS_q+J*r#C?fvA?FIw`OAjWG&8(vQp2Z(Z5d<^w zMN|7{64BjB7cGa^F&95#jx?nc(9=%|#Dl9wBcg)}zbVcaj!K-Hp1Z3#J$E7GV&eU4 zr#=1d_&hb7YQAbI0rL&2wN zq)vapHQ%5!k4XX3%G>4?Oq z1m$!V%7uaGC3MCp753^T;>a+T^@n@aADGH*Ig!!J|g-0vz^P__Oe3|>J&<_ zp>8V1y&Hj{;Bg+UIpPoj-J>b54^F3b)I%2UHlgOE6EL$}+$Tsc#J& zo&6h|ju8sjbUe8&z%vkm=7G358m~OD_$WJGE^4F&S&>EAxcXzK@i55hu{SpzVC{M= zb0}Zb(0S?|e`C{q*9L4lS=UJ5?uUq5J3QC;jg)p0SRW&St&rli>i(z%;O2SS?n6GK@cGDxj6F$TVf&? zT^w86lY4A+O3vq*-wHzQqz{Su-7a=I6XYOUq;X=mb=QhDb(?;Sn|=Q6tIiccp}VF^ zOKulvdzWuGz!kym3+}k!J|o=uf;)HqYrRJX5uhD)w1a*npMd|IHr?M*{(x75Pcr~5 zxBkeY-SHOACwhVj?>{_~Usi4T^GNW3#cV`^9vvjTlT+GCeq%pi+bXieO5Wq?kzaB* zj-T4@zj;xNwTSowuOEun_Kol_&W|lSz1c@ZQ(ER>)tW`R1$S3}D4!HljhhZ$)TwKc zaj$|OcmLr@^opBlo$v1aE`2Ob?%W>*pB=M4`n&X*vm(3xD0ru5!5`B7UhuE~qu_Pr zoqtHL{2a{pd%>pR+-CjWpWM5}9fS){F8A5`mzgqHQvI>`fIK`)H+aPSoxN)O#^V!vsm(ha}RF!|wR~ z;p^+^&^ueJv*+>(*ESlp@C>9K!td6!VegRHCj=*<%J?)e*84t>1ct2sSh}n1ruxGg zeKq!G6@bsprDlDi$ZTKwFva&#q-k!r+;8$c0B`48U_bFw2hkk+lct#;ofPtFy?;(u zzr8bLzTV!(;>ycf5oAb- zj0T2c)+DQtbWme5|EcP~*#nHfHQ|Y)qSD`*crG3){(9)0POmevZW-+C=}h`Atxt^ zut2^8r_lZ7qdP`wg7A*&zdvRQ-PVJOXeyBiOr%~t-5d$PH#ntAumA_s4Kd+&yGHAHb6PGiomKo8nP^#AJ>*B@n2EwUS-3;Q??HqmXoh<6(e4 z{uX}`K;#Njq1% zxU(In;4q>T3W6A9A_@b2Z+kD01i))0_2-^V$n@7v+(~M`M2mw?69GSueCgYx?E!K8+=3 zD^HgR9UL@W5(s#7C%#j)Wtqx;CPcZ9?hS69LhD)x8($IH%6`dx07SaPLu*;thrdw? zSNFiJ>gf{pGKbkeuu$biOkGOCwS>fF$EIH{ze0lzF0|S&umHx|f64zzTsQpkLL+`Z zVP}2U$2D_bMFmnW=-_Fxk=1D8J}ByzkA$UJ7CF*}3 zC5nq+=U zljhg0GWrrdIXVb$w3$s86-qOBqEd0;5yBfyVADmn>EQOec^B_Oc%!OL09$IV8?AY{ zZ}O@U!W+HTj?hJ8cKEl}{^-uM1-#M0Y^0y|oS{Dpds}Yw0pX3FN9dwvDbpu~L%gyc zAiU9+2wk*DYvkc}0kZKnWWuy(<4(i475cx}L*JV5D{XF|0tk3sXC`@uKn#~N489uX z`60Sqs_ojSU{&9N>gY~oA%-$B;>ID!I4TK;E)&`9&h$8Jw-lIqzLk*2*iQTmA5bTr$q5K8gws7$1u(F(ZAA2xvvY z_17vo!J#)d=&TkpHUN{YbP;gwUdD_vymr@_VGCRu%9@N4N~) z`{FU030S1DigJ1UbeHXSD)qLB2!{hvFedV@3u{Ryb}j^k|0Q*8dtztKo1I@Sh@Y{v z60|A!DKL3YrG=7bJg%EEI7;m}@SM7Km{lC}ru`^`O|e4)JR{Q|xU9UwKB8zw(Ts64 znL#$=yC9etzf^teDX{MXePb1qaV?6QP-WoYb)-h4ro#>EhH3TSGHid>)5*eNDjQd`}n3AetUv*>bo?k;=zg;&@B+RGH;ie#_LIA&WQufrl#aZ>vcyhx2D{rzB&8t?vTyq;;^lm`(v##u+ zz_t9x)yJ6`Bvji#Mzuk1fa-E;E8pphwYSz9sG)wkw`&=TS$9bU`Etl%wQbEulmWs(s4y{`x2lLxr2!N z^Z@Q9ciQ02m-BBQ?u&x^hWz(e8*3l^0kV5vr;_T(2HEK>YMGJ2L~bt5lY^sIbyH|` z8gwB&@L?*^b|9j6TW9ToJKw9yG%>re?bp{-!tIU@mzSA7BhLVmo#eZ3CLIjy;KeRF z1Pneb`^4pvs}~D=n3tE!5Nv$g>Iu%IYy(SSg6ZO-<%^%x&L=i+zu2@HEFm`pJpydF zO304q)uFM(9~9#4@ycKa#!p|kKz+9}5$?v6!MSb8shg`ecR>Sr3Ij7=Jm8Byre7ye zND?@2Q#QH%w?hv*=M%fOMyM_W)wIsPHYb?UfzQ6VA+%EQ2F$##`>H+U*jIK_1hd-7 zV4dv`Xa6%KKl)EehWHr-G7%4hV@W!JCvNG;jO`eHr0bzKAy6?kR3gA`(`9MrmxhWO zd=;eXI9)9P{66ffwHg?hLS_-%?vrl!KH7V)R4c~P6}gggI+WL@_$s(Aya|J~N$m58 ztTOa~#YSgMwWN{5KF1-(*9&9MDjdt;ioDha_15FaF`;cNQc-c|NuMv*VIOqbBcErH zh(-i%laouq!(W*r5T!~-mU2S81^fn1J?-eRmKihxnfxCa58YQvL4KP+^Ar{l_CTf@EAmF_FXOviD6d<%p8!#||~Bw`09z@J42 zBu7B1>F>xxqk+*k;%%wG(Cjg-sGp54b`NIoG13B%8*^nW?vey^&IuhaGv4nX`N0pW z+)@d35W}ggHVL{n4|r5J6#v%gSO4e(4PvAp?9*L@20PinW8 z^L+wTXK0*J4DjtM>NMQ1FTm_LI&}*ofsoQDFLgkMXd1<=YV}Sk18Bx@4omJCLCb(VeM?hMBr{nqfHZcA(B73Q;zJVyL=? z1x?Vr@OahL1_Xw$Ey(hPorSG&mJ^9cmJ6ILFq%koZvgRUBZ5{pdnBWe0rZ@h?e2=m zvpeqsrk&z@Q*ZIKvl{@@&i-D(q>@hB?tKow2*260L-p#(|h4FQ?Wh>RS+eU(tvhDx}3eMxq6@K2Vqu~p99J%9&?!x!kWpll6guX>-EOE*4P zW*C)v>jEC!E8ASfPN~{Q@l~faVAH@Nxz{SUmQ+GEadc*fVr;n$F0T)%qYk@9J(x-u zY*lL9lS%2jHvQ|g(bu~gFWF*xY<&aJ{OIQD*s)-^npbS&;n{DtuS0AeXZP1m_J>B}8oLV!CT>WL zw*9^5+*EyiGIou>OFGXMW-wWY0Kq2S1IXHe`~CzC+i%)Va&EA7lylVBEGdU%Be^PCn%AZ_%ujl}H_9Z+e6E&@eAeUneokc)&_y*-=h&-9J`Qd~r>QU0&28=aGK%R_BSVbeC z`MS=piZG$%Nhu#A!B3<-0vZQSf&uWmk?85U{;G}#EAn08_gTI-IZH&>8#5nFPo+OY z7MKORbvs*P)>!p3r9lNaDnR2@myC^S;)DCw0~|H9$MF-OEF2ib{*a2=ziwG9)Hh81 zi#Znc0K7b(8i@~-jkQkNA-OK9!_DgW_*Ajyc^=ofDe>I?MexPzm+srIkYQHOFe@SF zu1?w4Ha8n-Y_&C=k$3gMVuv-&M$FTzz<9Z_cZOr0Xi-ctF|A)DM?_YMY|{-?m3(-f zc?W(7a{o-uL)MR3M6^3kUv9qm(vlk-i-N&~K3O!793%Z~>^C~=3t4{V3}SWxAIQ(! z6#^S+h#`mt_4Z5(rxw5CalIYAQ46to)M)a}Mb!RmFG#>>bcO2MjRK`_NLSLd`ozY*-g zC;UD40HMxUBT8X&4|I1HJLL;8WfJ&hr%mPUwp#^Gshtdsy=pAcaXk-{hmvO&7H{z$ zi%q#0^urI%S#PB}31;rX+DA~Q0Y{D6Y4Ihf-e>9=J$$3S?aHZEDhoCxa7JZxZeLA* zh4)$iW062fG+!LER6d14wn2Gtj6v6p1UHf1J^U%_xc~mPTHOv7sUT@V=DXiz(r~3q zcJo?l(TMc{KM@-e!(}9MlX~-AnJ*@v9k%F(#^y2zHX7w@&C#$doEJ;!J4s!C0H~Vo zJf;E_p%Zv4>oby#Mr<|G@Jyl%J8yPpJbIb>g@Ki2lRK~+NK$+@@>Zy)t(Cq2=9^McKF1qRCa#9GD? z&zM8l?}sIR>@xel?Z>%=nXc*15C6?&r@m@W{1)Z9UT)%nYvzI`dFkzB)xAW(vGZD^ zT@t>*3lz1We7?NsjSkIyICEbuRN6fFZu!=Pp9}hG*WL(x@y4x7gc;3yQR&_#ImC@WIPc zr9mohj7myCvldj>xYch#vy%Rgn?*%;VcPQoB3BOGU{GGj3>Nf@%%vQa8O68|<;3wu zGrztClO#5&P0U?+asEr;jsml{GjtTjDU*iA;YVF)Ng8!F^@ADIIa%2?qg%freN-Xk z9?LOHDieY}`P6%ld5f6u=o!1e@iphB9|Rmb&YOg)S6d_69v_U}8|5_;{F5QG;n-_3 zu`F$dVKIE+T(n#kevy)hr(8F4Ca1{w zY~x5A3oCm~c50Sa)OnTa^^T*cOA;bW@OE7k0yP1h2bXtL?m;FLB$kxx5%o1)YbUGO_!l>V{?IP#3e3WSV(OM!( zGH<33V2!)?-AJQDVU=rj`&AfD&I$KN|8!};g-23k6~;Kkbk70$&sP-6BXDopw;R{F z?QP5r76<2VT!_BSSr1^nzW6B7q4Sc~MW2VWvLc5X#$XqNff!H4z>m3aE|$SxQ?`zA zrWYDfQipZ6As*#yxOI#(S05%Ou&xKF zS&kp@9lPI!8rPC@l;C|iwoBqU1G`7(4d+Q<`q2qkcozJpGsyV*%Mn9GV~(aleS~Ox z>iS0ygw%C6jhyVnd~m8c-%de^kb`$RnccFlk?tNPGV;I~8Y&0*D4k%lP6;dWd^%c4 zoqyBiJ%HA%Dp=zl@o?w1Z7PqjXoVgVBK>IXp4kvODYX7ECIj=V<8$LQ)5eVf5!JF8 zgz*fE(reFkCZkcUqr-dJNG`igaQI4lI#WXsaO#@RtxV#Ot86u9blx4&I^_6XdA#dI*zC4a?Szy(w@l2i@-ERqr)Lj7 zs?PQ6cQbv#V!3d2d+y`yo~=Cw&a!sOqBlU?CWaw@sh|T1_)1P*uAM>`ddu^wsgmP-;*zEw_HsxyO$%+kStGRyT(Etl)Gv z=7y1VW4@B&6Yl_IQjWfo@A+3) z_?snk;Z9LpOD$y-d8s%D70Esi>n@~4xJUwG9;@D9BmWmxy~(!MtDF>5!$^oTj6v6O zClfv4ayzmZ5n=B!u({6stS{#g8V1bQDbrbkx58 zvW|jSEK)t#q^}BK&Wgdm&AHE^)LBP0-(%LqT(sYdZ!zqbKj_nkI{LU?4vliNUVL+PH{VV zf-46i$67Vi!H{o%N+W(<<%ErnER3};VdL%60+v%oSt6sK7%o@t6lpgc?`l;1&IaY3 zMFq`Kp}QWyilX%PtF&F}*r3=18$9;{SHtv$-yNKWF2r9Pzh8J}=GQ738;SRsU=>ga zTTA-FIUn<9PIT??^SLu$W6-c3Oo0Hfom?{Yd*&Qnss8qlN|W)XAw3u;#cYkUN)47t zKR6gYI%qi!oqd#y=QiixyF0VWWIO^UgIJ6_Tz_o!FR2FT<&Pn>(2NaJSbV}sh4oSz zjwE1ai;12u->lnMdJ!mx$dr%F2*5-&&0^fxT(NI1dzcmiyR1>)uv_HkeLB!MSkO<7 zFV`225;8h>#M|!Id9WuQ062CiwbC<5elIw#QwwfR0hlU)v5RkmaK-bvEn!Rt3%UVg z#%K(%r9Hpn&EWV|p#z$|Q-7WRg2GJCbL^&CcNU&e=V4K_{|$~E0Ris)4zWYy0ZuO= zc62UByJM?-Y0c1^q+qp`{(FdDhzF*VF!C&q#eS@Ms4Pzpj2=}w^BteL@<|%b!?z5s zLS-<(vdNwr<+OAJ+4~Q`OxCHeDlF%6>(j}^DolMHTM4RDDk%;vP&Mv*GS2Xt?qD=T zXwlGDak0mKGVJ$&rNab1HO!oWFziHz$_^r3>5fvS3?U-X#=T!P*}iiH3W!>kSFn0w zkF|5uqmoO&RgXUEZ$}3qbG)(SZ`;{5Xwd-Q8D7poqZ$Bf3v@Rp8*?vhK(Nbg_n|hA zJ|dUhKo((YO2>)do<&`8by;iUo?Uz38|y!;*h{2ha6cJ0<%AxUXCXGhj@b~F4Sa`M zD(;!}ef0rxQtKC6rS3}gXH!D!-Yh}*bkZl(t>;eMtCJd$G;0TZy73i4SW``*XH(j~ zAu$M_PVH8$bPRUcW#;{!r*;V9F6y_b&_U_L8!^wk9L{q^aQlKgF1XJKcfR1xo&Q?z z5z8OQkxO_?9&tGXiY+@A!1Oiwm0W)tON`YGUbBc`B_f3&;oSF$@h_f?^-ey-_*?e1mO=pi;cE>1NrB6yMa z_VQT-D;M|hgXxN!_$Cfra|(gcDat%7ShENd$Klj*#K(>GAqYE8$Y>jkYU-b5&YvzM@5sFF`rsaE1Ik_HF(?O&Og7 z`l979D?PRPY5%iY)y;2s{mkq{PTTG)86hD@fDt?S{h{mY0CC?w+3<5l;eFk#u_fVW zlhGS+rR=RN#hD{CDaqgoREwA+?YB1}L$4a-lHUWe9B1dLK%@*F-fZ?ZRq%o&4RH>+8y3E&Gh_pcPV2+IE%S+yc;gDE7u)o#il;n)-<)b8u;5 z%JD~$=1A+JZw0^+MV%U6IXZ|!+n;b9{%E6st)2aQ3xI(bUm!wfj_d%Zv;9TF5|5&| zc=rCHjr?`E<;*Z7ocPpJaLWycQ%DEtEmvl-w*$reo-(jeM}YNy)%Ea=MoQN%Ke9M< zh7UqjVX7cHs{<0R4q#C!B;rhn_nU809tW0h+*tG$Pi!dU|dYQuKO5F9V9QBG|DK9Q|2BlyZ(8A@iA5m_z_q zKg3vKpP0n)`ST(Q_LmLgV74MIn8jdxKpO(kT#qcGuM@z|Jc}%4A3KhLzs|>i;RWm5 zpK|svXk{DgkC)(atONcg)qRyIf8N)w!5s|TXMsBvaA(5*#7ua<7coTP`--0ht-6x4)Ulu~RJ0|OQg~Zo^`1;W=T#1UL zY^fBOtTdU<@SeLH$psk!pGBc`}L5oGb}&UK{vBs zO?pN@I8G2a#*flMpO_6B*%9${sB}||FTm*iMMzJ4{iANur2*t3u+h(eDmQ_1*6Is~ zbGvodN!rrxbJhm59`)QYO=am~q(+GE1DTpX%~Fd2C$EjgxyNd~Dn%Tp`cYG?sf93y z@7?c}5VoCnt)+Q_%#6cGmHu;Q7wW+?IaF{8*vtI(T9G>A{k_E}4dYLpPKIp6&H(o( zcxx4QVQO%|IPN6Fy0gLGp|3?}QWB)2Wp0|}c#M=l@% zEHrAwgFHUpByQKgg23iLHefMDjKaq3Y-zyBD$qrw-njAlttGmoGk>j&&U|GK0T;m~ zRU0{!fpMtZ_m=YV(Tv4-{U=}Nv#~{%!P)FK=pYVQM7gM(n2}{XG0kk|0h~TV%q#FA zp_x>hn|TX-yVaVn*?hYUa~By7-)>(thi^CI7g<}*^UU|@s%_UB3YIOo&$5(uBcNj5 zU|xFVe6yPZxH{RD;bSxaxa%(aDfbQl?(QD~7X`g0p-i0K#l8asyxgrj3W-jiX6U%A zqQ1sH)j<^#p> zEsVVVC2)}uE77+&dvW4u^DC%pu*O`(tD4T*BvE&NzPIxt1p4+i(9sLQ}_SokUy`9;hw2 z#5IQ(qxLSvPZ=H;kV-qi7X{p05Qn|7+bj5H1I1<|ar>^#?#MagYD)($e4`Y58LiXR zf=$&f%;@`XwJ%5Bl5XSp?y7CRwIsl5c|d=9#C!o9zrU`PYu8OKRh$$@*$qsdF-z@z z57ZW;9MSMJF`h@3@i41bG3yM(RBuGL?@$3QIY`+r zg}3bJ<-OFa9MJIoN9wENHTRLJK9BG((FFJcfyn%V9N;yFG0!o$^-F1I zZ{kvCA_=>d2z{mC=X1=-U|+BmibjaZF~0bs?8<#S{e zT8@ujuxHmzz^?=DyG>G`X(mebE9fjD3Z5olSQN4Y4<%2Zkhed)3iC>0N$EM>Oz;Wu zx--d1lZXPrU2GR!fG2U_VL_82T9>0)Q0ui7v)1d)*Z*#OFS?+0SwQ+vBoRJ3YlM)| zx`V-bF}P;(-L8^d^aUmf2s3ly(Q%hJjK|Mg*s;c+$SweLcf5=2vM1!Gym1YvEg2!2 z0AqalvFM?_x8Ubw0|rn2FPTknkyVs?N-OKq=>@#eFVWp>D3RFgiG=+HgjKO=k3O6i zPV-FVl8m^lCoT<(%M0TI%(#d*E(Gtt2os1OXU6ZXqxI96e${pGRhXGGyw7Mj#vxYE zhpDiq80wX^T&fr5FI|A4e0qx)<@go_dqOXDRK^TqIbc->k)>+_8{ zLofTzn9QD63)RFR`vRKsk~WCu4pvl@*Yixag52ePx;$)dTx7VzZ}k^!Rxnr|*Avr@AZ zxT9pYUH&HPF=mz`3vae>4eQ>OaJI5&?I6$0-VIq3iv+`jHDJdtRa?!fEHM@~W>SH` zmvyJJ#w!;#*AB5AdGDHw`2^|@sDP-{BGfWK9ZAclekxV1KH3LDj}Q%<0f}k!Po-Yq z>~54t1?TDo0`eZXOeIN@1DInkHRl(Ot&s(X=kam@m?+O=nbbpge8<^N--Pjpvk2*K z!P`>%?0(xGX;7MFm{86qmlZ{*W`5WXVN%@~q)v zC%Mqp{}x*9nNnybZ%PF71;04LIYKdWc>(OXH*MLPE0|v$qSqKde;IuEq=Cu9kntWH zRaEKv$D3DJ-qJU>c|V>tN~!jR(@ils2+X4! z(|-9=%bMPM&hzrh;C%JnR~7=WBi5gGT9bToA<u@wTeP(4P;a?jkjNhomBgJrRs66bC>IC zaQK-bpH|JDj>i=wqHOCZhLvMVly{El)UA)&Vjl3M2bgh?C|JozEAxFE5?w^dWh4ZB zLb3%>qajp8^6?r-G(ak5c$>ENW+rCLA}~g@^a_Oz!Px$8oo9<~J-Fnb6ubX&kdObC z6}KKVKHM?BO*|wqh$t0+nPvT;Y0s>F72>d}OM(eaGWbmzN_N)?OtIefyDd^Zv@+O~ zv@=|6TH*$9aig*TxqbgFH-dBbmK89QAa(f$JPT17Z^?Py$`-trlUD{mUg`R_`Qq6s z42Um_>}AB(OA8#|BmgtXIJjTCy;GP|BJa2U#gkQ{fwzz7DSXd&p9B)*@hBD~5m`+( zcwO%h(IvrxrWtKy1Bn%QJPVp(h^PN}<&DOkII{Wq#;cvGv#fDiF_9R6!5;6WDSxxs zU*{YJXOYRJw#?O5%%v+1kx%KU2X4XeDu`q^weFl+7S5EcHP7Ftn_ert+-cw}E*=U&Y14er?BJ}LiSmGjDi&eaSh}5g#~`Ps`$&%I#&Em{dKmeV25h+y>>>hS!omXS-bf z@R23W#!VhPb3qx`T0|N~vGW(_!aE)kFevvTwe~s3A)(6C_l1z=RKOMR4S?6n5N>f( z^YzF$nDb%dN_Mr2k!pXsw!I3-bqI?6ZFAr#if@onj4S;rNtzgKSdY;G%jVn5dN4g0 zgmCvcYS))>YXV zU2mSCS^yErp;okH zepw;!Nbl`S@tWy7HfRH!9M%zmg3K{tuX(}dJn#6Nmm7;yI)J)?9>nXnweDnat9x0V zx7SNu@##zETrT2*Bs-20!&W z)LfG+@uk0%)mS{UN+rnbPFi>(w{Bsv*gi6x`)o}jZdD&e;;gm36^^{e$8W;NVj|i( zDt-8j;qaravy2D9k6RYq^d;f694AfHC0BWVStg5lDpK=bcxg9FO^G<3fI4UMgq$OAB-6u+n`8>PF<w#YqCYSlTrYPVD z?8!N;BlL1T9@9>jTh6_Lj&_&*Y`Ye^3spmQBe$K8=SwZia)v(x*69{>GSUjGpZ*R6 zU8ZR1FHzhg|wPWV=?vvOOD*75i4MQdSk zS5%&cE&olhv^ZWm!0Ext(sfq$pxP{S8&m^yu{itxs%q633RGsn6-|h5Y<*(%JSnSm z^g@IE^~O=53je3bR#*{F%EXl$o=-?L4>{?_Q<1Ux;`yP=RUW5`;0%oU>@}y?t|O6e z%6RVr;FJ|{o3g-iE9doEg7F1Bj%p~$-OxR3D&gSFM&%bF<^Hd0>4?4_T>>2VCc~d< zwGVh(jGOJ-ahI2zS#y5<7@->Lg1Cd@nwep2&qw=*zW$-x6K`BfaYfXI*z>=kFnE8p zSN&$j3eivoF^%gh_la_d-mEu9K#%m)x2`dQtKVg2)!S^4mvbM(=xTPb-p32Z`V>_K z5gUt3iOxvW#sg}W$MO+zz$W_M=lz{ch?1Pd2nUDW@Q$HPlp}XXb~^4I!{qSDER|bM zCtG6*kV0^L$aq`pY`*t%Nx4phety=^0%Q}-4ZJOL=xUF_g%Y^sVDYRb%~!iZs&=p8 zfjxH5gv#?#gRWKf8`Vn1Jt28Q#mM-HJ&Dp5wVkh~zy0jqF|ke;Eg|Ar2YF;$tKi$5 zZTqc6vkM+=Xa^-Mw!#?zR<2d>-SE$wmC9DGl8X5!4#={`6^v}l?)M7kD97AbC9;1n zu_2{QpbY3(-H7x%%U%{h&o0?pB-cg^uu9JUz2tL-LC?CjpzooTUGm(o*%KT*w2Hct zGqKY3tdduMFL`K|R3-UgU9{-^GBcjz1q%!Dw}5!x`2Bhbtde7YFWFLbI#kzDQdwpF z-J-=$Tv+=6cv`Eq8He0o9%hw1z5`0;jc4$)jhWe{7oB_yr(gXvW^U%&@4ksf9W}ku zllN5|TXe%h+xL^X#qrR$9};YGs|M!rgnfNLbnt{mJBzE6GxNpv;R!~!)A)7Kckvdc zN#2?D;-ya=cu!Uw+G)OAaD~&%s?d7Y`w=NE=SKyrI7q09`g~VW=bC_bnT&ag;8(hy zfPW&0s|L7r?EB45o%`N-rqTGLi~JLY6DUMiJFP4I_2@1Gb_#P1KEYt~-N6#Q2Xm&v z@Y{GjSj~>weFwV;XaPF;xkI13*mZ-#C;v$z#$-bns-Din>Cg5&Vy`)jsAWzBw1u+@ zPpD+M6}sp`1U$OtJ>XO8;0xi{?YEGy6(f8rXd5$sn8|#56t4(AS@sdv6InB_;P<_} z_Q!Xpjtlz7o*76EOBh#ey}?{`QaNc;;c&df&ajo-1lvKHohF4cuPbcj(Y+&u2tn0#e$4lo_cpZZrY$Z@gr^ zBq&sgmyAh1np1*9RqqKX;?$)g+a$(1?RI&C#HW)`L~crJ{QfVMLQ-OPsS>is526En z3yE_&oFf!yJy&mTbptWmrMg3s+|v z)oS(7nhp_9^e2Y2LqSeAQ>eWv0pnUMZ0Mg0>7>FrD|zB}|2`UQaM92AGZ0_+%kXTdfw z-#?NxWr}@I8p$@bf!;@Ce?uF8q{>T2`@>%7aC*qxY&8a+pph(ap$*T!@2s*vf43Z; zQadDhRrb4@LD=}VUPAB28*jXzoSS?nQ?Izz-jf`e_d({EM=HAYpI28w6i0Eslf$4g zf7tE^C9r$#7F9}f)UzKkW?szTiNg6`e2?iTa|#tvD?eCHR@_@ z)Q$f+O^jQ(!dbamRZbQO;;Cm%g51`MOdfG?yZQsSEJHYHz#(Rc57t?7c}^tW%Hb4q z;>~reIhp3vw%Oy;CKu^+=-#zY13Y)>a6?4Ep*iLiLzlcb<%Z~+SaiX?CR&;CTzl+U zuASTPnMYgc5}H?Jz`AZEmAC4uQt^EX1qe+I9}bQLtMy(t@zKd!vr*OssRx7#z|3>0 z;Sl=Ij?qs70hPo7829XK6ta1O@&k918Tj!LuIs~LA6R$Y|3ddA@qzVB-rQRxOllvL=W%K*OsGvKSOCd=dUn_h zTvHhZqpUsh=!3qISAbXCiE+`NlSxV#Dk1GI-NG@TS@K$9+T^M!^lsK2oj8-FR6_Hr zY~5BJlRn}8+wx^jXKL`Z%#X;sH2_Uc*ed*e=)12<-xitOA;&$##LjskwqhRD zE26ef?Vc|!TueB)3%7r23a;6I6Zv#GNb`sC*B!*&d~VCJcQ3$h{S+wDeH?!9eXY-{ zYflVcF7${w_>IU=818}uqqoc)ZIemWsL-gBnq7T$4s@Sx(NxAz;B@5gPXy_Q1Odbt zg+d9(11P#7iLdiHW#0(fMo=iaeg`2qN1G{Xii|rEMz`OW+Te09lge7xQE>>>EqzMX zibr`H%|h{r=wjWnw`X(*0#PksL1|$BAORdYn<0~KR6&p++9fG}Er?{YP0pw)f!dyl z6!qzkYJHfGG)4_DPZPwE90vjhkKFZTo21*QPQQOpYly;n=QLB9Q-L^moG1a$^~4*T zOH^F~&sAV>vlKpr*^S5iE~TvOew1S8kAw3e=ETJC)YLHL<3+lHxLL%GBB67q63-YR-&Z`imm$5P2OfsiUwqCD zpQVrupF6mtGDQJC+G`3}^&wzQX=CX{A)%~cvKDPOt!&=3E?)-_FqweGbxr!V zZev;d$GU;6L~Z6J`BWls1vR``h}6+dCp9$g&+POn{#Ephh)Pn~il`$&tgWkaYgKAoRYeSWxjk7O78pp6oLv;>#18`U{bNW35%Y~o*FL_wI45_WVa{38?KSC>>_M#5>L zO^oa3(_Qxcyc!cfTz0iERbyGj*}7%Uix0J>^xeMa|6F;|vWn~7eaFvjejj^5{OI|h zD@uO5M+D3>4lm(U;fxFCW#CK_&dR`94msPzzqdEu=n*W{!eDyx%1V&e@^737orW59 z*m~5=QLHR}8JEBVGsojE{q1b*zDo1>6{oG-Aw?`#dZ*OK&s}Pj{ovGJL?Yb} zzV0=-spIkH)>f|bavs@#5t(@>pZr8)CGm6Z6TQV;4?f8&|3$>SY01;S_{whn^yUwd z=9xOkCWz$eyu%i1efn#Y-u+(rzqn0a#`6abqvt4!;8D1>O?>7z=+3`#o~_d7@zIA zytgh=8D-vrfg|61e6B|yD5$l5r|XMrFQ@6~EUMedjWfAb)sNcVlxFTQ_`>fn^gIGO zHM`2*T$T`CeL&Bq>rE^kcwYeM+!#h<1#nyo*U1)=T0$C8;!@)byPsCH_T*q-@dv1O zAdO6}|B;XdReapiASXP8H%@xbjfPqx1@*@-!DGai5OD95;tbp}bA(eL)pJcBFU?T4 zoE!(aQ%6HGJ^5~CrL^dR{_zXvU!kC`RF#=KM2YY_z$g7r{977FXV0N_iICzh zxFWF&j);x_``!OEHoR`ZWA4h<`}TYDpZ2Tl zA2x4%3}OpulDL8q2PT20AFL=`YXBoYc(XTFCQqj3lSN02#7JZYRZ?O%8Wi9vT}gq5 z8Fs)t#^>zbPUUlqyh2@(mGwf=h3!b-PpU?Z2xP)AR)_>_6I0MIeW|z+ogPv0W(=)} z+5qqX&<>`D=hV!T!FR$~A$Y^SyI-!v;uzpR&x@hflI>*T{EL#ErR7%x(D*#`ItbKb z*+J$g3J9|gPhd_NpR?46gr<^k@H7$Mv$v9kW=BKO?Bvoe&rX>H7S8LynFgHIfwL<9m+uBL;}dgpb599Uu{KwIbb7*C9NwwF zE#L{gjSNdf-uuuLtWrBnacVKU>Y4P;TS>rvRR)1s-edIs1IZ}O8I5F|$ZK^JrPP1# zP^!3Hg$8Ik3&ktnjuMc$ioqbSy7MJ==fE8dD$Tjo#CfnKHINk(5T7| z6lmuoK26WrV84nTU;xnXuq3(rRJ@nDk;DWD{|6@iVy}xW?$>qX>V()i0X~{?B{*G^ zo1~2Owo6TXS-uD|f!^ z;}>xx+)P6A7T@U4FJFwe#n~UxJ-T*34UH>BBTEyc?X4e%Jq88Ipr8v@+7Z{t9yfO+ z^krP=!TkU(?{0#C*p`C>KT#18J?^s#fOm6O>R3qkZfGP z&>Z^we)DmBfsfk^VzQr61uHs+1gUu6QRW>?{@vqv10pN>s~VDK7095GQ)B_%w^9qu z4Z{pvE`kmHu8#c54CgMXBJ<2FA}nrFo^77gBcwdge(kMxZ0Sj}ltoWZ6rT;2-TZlg zE)s0KQpP>bMfTir#U+b{A#?3)lEmve@47uF50&9b^c|Z zuiz&8V%R)=T;Y?!ac9HzGKpk|ICqGC)gLGO@@#PG;{$-qqV!>c@lNK6i6>_-K3&YZ z#|$aH&~5P#M2F|8jVq9|8m~7POWocxU(9=fgv&IVjr=A1I)BIVC-u~Qb%n4`ZaHCt zp6n;XV{swa%-c;ga_UC-_08k58OM2Sr+rqx&p6+HxYOKgKqw?DAFmW9>?yQ4%S7roR2l%%S>oK`@ZW&NmXWKC{ke&Z9KL25;Qe2p9sET_CafSh2KV5$w`r@+IK3imL#cy{$2oX-?NmpA_{o8Ht z^PY!5pb58#ye5<7mfjXf?amlyEI9SecO~o#>}Cd*VEP10Tk$uUq&v-Z1p}33uG_45MAIhDtU4 zyJG|JM!IiSaT&VgUfp82bWC;?buaV%{ynx_$&XVFSElU0p?B$KQg>40BiTg;GxCPj1uQv;>)?9-&iCXeVnyqJYsc6QOJ zs>=0RXsUtP>T{h!%Wa=LCrcy>>4&QxD8V(&d=Xc7PztIV?eIJr0Ek?dM02a$&nF~} zZwQrqayVrDgMNPavjg*+*gYcZB%yi@E<+O@GEt~IG-nJ=Ocmtd6emA)J*L27D*Ue(j1bQ`>ea0v!7=G1?^5HgnQEJx4haKTAR6 zsw)QQOT)t1cmV6J9U5y!yG5shzFUt(8%3IY5}pF77WD34X75oK0Zgann9j3BFy~#L zO}EB}tglh2`aFwa!`%G>aRdDlSfmw+P)e@6y79Q8MeDMj#SS79QF*tu6Yi11jnbtq z&0WNqTc`2erdvEYG*srBgO&hs8GzgkKI@u6wQ&=o{TLq)oh;-3^DgD`qQJw;!3cqa zj7hZHgejb30TQT$Ey+B|L%<|#I2%6Na*+N|hLtA9P9^|>pC1(k#!(~zR1VxU>Zhjz zq`pK@x7fEFv+ej_KmwP$aY$fTK^hs4#Q}6=I>mnJtv%~zA>r2#y&XFu#AYJt71%9GXtp6@a8w#y4JDxLwx@Mt=z>&*KW0(ca4#loIo0SA9AY~z>S+eCq3g5KD78G zE^JC03*^B)2H&z-mDjFZw;NKc<(mVN6*)h`y!{ak-Q?r`ZeMHSOadh5SU>C+~M zHN6HWxU$!BH{g4i4=qv!9)H{5nx^(pZx?qZhbU)EIjVS%k?3>`zggG!&FExiCa35@Fhrz z=S11o46V<$MH6${UgsMQ-b9YkWx9y_ zMddqn9POZdTd3R}wZKw_Lh$XcjhJO5f}!7%@=oC<4DQ_h1TC2#?>c6g@fyi5$e1yZ zQ~c|{fUe7hkl!~)WQi=wIKQRRQqtv~|HJQLF<0XK z8ij6rTCs&!^pT|8JrW&*qvAFRUWi$Ho_F!Nw1@W=>GUpJ+0C-A=Shf?afw@}$UR4s zZl=|H?x5rKs}q9`ZO6S#-GI_(jU>_9 z=~2XFvNPh9arSUn)>?Mje0cGZ(_a%oc5cD(b!z2+D0*o8|4p=W8b7~e_b#}kb!;m9 z2Jh*BUp(5=`{1_EJqnw5p03yWGG^ezzS@f-v0(6ot1IrzY=6gi^73{>e17TL-?{nc z4A#C^dDM|Ky((tarzHWO7kqe0FYd$@-yhL>ZP#TZBftCbZ^(eg4U0!l+0bP*7fEY7 z-`?^&TR-K^W_zctMS6q6s=~o5S3O#I6ZQ5jIq1XR;(MG}`sK_;%b?#N0&iuPwMKs) zGw@zuabY?boH|(7dDsL0L+Qqz4T3@-N0#kZ{;yyiDS@Ykhe_cCEKKY9{WY_16~aqh znOnDp4OKYVZcW4O(iLZp&Q`2e4|E= z{}Kg&5>25lRCSTEe49G)1VtNHAwC1tM@W?;JRj+EKGn|pp?&-CjG7e4xSwc z&yIuc$H6+}fI0pj25tFYhiCUo-*@CU761p^j)QH-!M5XI+i|e%IM{X^Y&#CN9S7Tv zgKfvbw&P&i{kOsAaj@%_roP5s63(j&H zRllrycrDlK>dMW8IZm?x*veNOQUtj`6c{@VvE}j90Sx zz+R@`ap+`!14DvQN5_c;xa)j9*wUs{zA`pI;!Fzu%dL6lC#~r@)4)ryk6g~o%!G^| zO6p#EZpdyAUJIAa=L1TK8WDxRU>gpWKmL?^aBN57@2%U>|_2%htF`sVIA4>eHnjN&M#msn(m5h<4c zAsmJWsNv4LS;JPPn4cHqtorPRA%kI!5(6y}FgNE)#2%ydJ>9}te>UA6_IZUsp!Kx7 z&YEHnM4P!9o7p+%-B)nk0kP$~5K5x0%S>FP;W!yn0J?>xf zQqg)E@#W&O10T~?ZhYq1W1trG&7bSAKv8AZM^XIOFE;XvH=8&4uc#@SNQpVwe~4@A z12e1houPVtHhTnl)+!7i^6%@IJ$HJ$>lUs@pX3$gs8vZWd!kly2SvKamrq{5wL?0h zV6ES0t4N_g)GKQW&-~S}P4nr|HziA@4 z2BnwlUwW{Yk#GO{FDKe~9PnH(r&VTj=LVMeX9L_>4nj z!oVuG;1`CD`ckCR(HZ#$9l9enGRj&~L)L$K2jHJ{$fC4W(uwh@Sqdm%=iOA2!H_D*(4jd?l6I1IT>HXTH;x?7zF^NByJc(L; zy=u-48HAN;578ye{Kx)wH>`j~Zb39kCZysAK_n^}d4~&<{s<*zR2{h6d+z)oiA1uP zsIj%^LDDS-g(95szYsEGMEU85PX*?9UrF(z1_qfzHNI6k4GqIedgb1QKn1qj6yPr2 zl-dKsUHRW`dX}y)w)#2ENFsx@ER(z>G68}|=~OHxgmeU9f;K_5iXj;4wJ`8pDp$|4 zO<)*g0*!!+G5df(4mcd0?uo-usdpy|>d0gW>L8Pc8&%hoLyQ)}8|s?#3C7cC1y(I^ zVi_E0L)naA9p(ShtS|a{zOyQ!MLnCNM)VC`5QJ2M3S* z{U_v`j}au%>xHUtr+kpzd)%dXiiR}1V)(x!B?|f*g$|!PVWf#ZA1eiHDwUHntW^>cwNVj+n#m4iA>#n`LP$ur;imw+; z6)t8<5NthLiqtn2spR@s)iIn1<2M~Is5zMKyoe`g;f9@Z)z;KHh$Pv4T^Sk=GPN;~ z^1So)0#!5O!^ULH&`h*^pf)RET&Wqp%M_sn0BDm;W$bj{wr1T?qh0?mF>_ zfQUBwFEDuz+um1yrwcyE9!0mMKSGVzz=Hlh06E-FzpN^VR%1YIR5GLSe%oWu%Y`dQ zR6J^ar(nG@96MhFCKvwqHW@0q43fr`s5N7f=w1&j^VIJ>U&nlu-lMgE$6|&-_cob_ z)IS`dwiX|$Kj?76k`%{2*H;hA(=8Y#ReYo=1A%42U=UP8fl zX_+&~d7UN(nSt@C-@k?SygBN{xM}^ze*O*TwTSaf+T1X3t2ogXJFRNc=fUoL(RS+& z50I_a%wBf`L)Zr8F{ne!JB88`d6`Cg^X3*Wc}C1Zr7v{MO*G3y@47z$2)s*6IySZK znp(a>4sVA_cIfaIdEZgt9hTuHZ2W#r>)`D%jP=r6D(olI26?huT(r<)4aEc%DN(X% zFS|m^_8+I?3l@>DhmAg4Xp+DtYsPNUj~v{ujE_4&$7e4p5&h>DlYh6^H8WF9N1pV=EZ;Ch7ynoc7ntrO{6mE{25zkBt3ov8Nl*K+Gl0(c42&r?ey&%OzvTu*1d^E$0o8@t$lzIdq<72%Ni-##|T2UAqhJarA)L53oWOR5wU zLdhGZ$O%6)R`#A&n6A=W7b^66-^w+wS#DE1mBVLB6~2`^G2h3pOMHL1419(fMY|+k z4~p}%cz&BadqrDP=gRjx+Jh{JGJMC{gWQDOiwF}90XiW+UMvax!Gh1m6m7Y~gT2Iy z?MYg_Kp#cSD8YGXFJ8hdU&XA_6BSWB?jW$~I2(X-Bw*Q!S%2Z#P`vV9t0zrzs!!NR zoh_@^Z5UsvG%kv{W?w0jZgK;BR~uD%b40hwbO~PWQo**?1?gYN=>p%=rU6#}1v-Fa zb`s`NEry-ArV!6u%<|xoV;y_3`i|mp@LN?*CS*-_rSqHzzSMevi?WmkJ*iN948v4B zzzin<=k5DDbEG#E1Cb*H+hWIKeVT5J!_m;wsDS>9ilg(490G=co^*E(Q1y_I9ii_Cm|QWQ5|bsyz^gk$ zw_7-6h{=3+-o{c(S*OH})AT$X_~dE}ncTXDo1AthHIYDIFpAKVPhQZEO*)ep@Yy*m zcN&vF9J#QYq^3WJRZ5Y1toK4AA$*6|$!DqCUFhW}Z!MEPHMX_0-x>+TjySVk(^I{%za}?B#TV$ z;mKnWy3_hni@H|G8=vYO^LM!48?ilnAn`bF>Bfs0FFtpyB(47|%C~WKsw#P+K9`T3x9}eTqNN_8;=1PcxX?H5 zh%j0U)z0coPh`g0B{G~kBCtq|dL0O1YfYPJL3QRa-m7FG?rVF~37D$OY0!DWWHN>^ zdpJDSM=7X0w!`y$Kstk{p@V9FV>R!*gRj@;A3B&;|Gx2-k=D=(jKk7;cDx|vMD=r2 zZwEnZ{cQ;gGEq}%S;=djR{IOLtV4tCH&^FX?Vh2NvZZH!b!3qVn}96F)+)u+EvZ62 zQ;V-%AmIAdJw}WPxSFW@#>4H=^?LIZq&X}yn}EsJVo7Kal-+u-*m@D5O2AbEmW3#9 zMrztWrO<#cfS{nzd5Vr&7$7RyE^h=4GX$}Qv8qp5-yw~JB382|44vg9&vg)w_(`a^b*7QgWhD|r~7|J zN!H8FlaYEw&k-sShFPagqX+OOc_63&@Yyr)^0z-ERee!|ALaIgqriLz7E&0lvK9X=4KF?*fL(_$}T`7dt?%D-Ck(DjT$ zCf5=jIia~t6m3leb1H1buil{u*5!>0mwmzhy`v&ckrHQa&i##ZQJXU$oR@(!5x|1+ zf5b!(f8{Lw8w-H5Mse2X|3h9&&a3#}@hS#=rRCv53A3s2YRhCrVzNjj+*Y=2xn=7_ zZ>Cyr*uGwjlmUId7y*e;*Sh)#RD=s84+|?hf8XMn7EhIEOVkuQj3?xZwu*2o4;D>b zerc#X5w>r7&f2H>0~P_+RghV7HzR;6(xy6s(Em`qsSXMpz2s2Da;Y^yb|Zcl?sA>7 zS}3%9u$!_QBx6OF)%Hmors7(-udTJSt7NKNVmMxE%?{AQIr53NQ4!SVLb_JhxVG!@ z$jwR8CYNfFLL^Jm@!D@MPl(tVhqZCXeiu5f>)!-!c2H_AVBQ^o6x8EZ{~8Ht#^8Dd z(xFQc9;~iZWYFlW^q;i0xYRABQY{N3;D%iCX>MhEk3is&dR)`y0};&&h0R;PsjUKI zb2-a(ZfQNk!sCEwWs7h&4*t690;6L4=y`22=0l*_FqLI}HOV_@tnGK=UC$Q_*Uw@O z18~JmRxaw5Vyeu5TqT&93-e~t+AOE)Mn9?Ilw7vo&$w-H;-1dMuiDDxYt;8C{n}i} zdwSP85ocMxmLPKi!elUA%{CNlIlP?r>#(iw)Q`##EULZ-(F}7BCTY&s zHiE(KvE~mQV0+yhoU)@QhX&!Pk`w4nsE4xwqU7c^pYo!)AztLyuQhBW*`Cj-R@0F; zA3-G2N9vEW;_ue6y>nipyF3icH9K&fo>x$A*aP%&MxaPG^W_+ZTJ-)&pyOfo12Ok` z(DB3=sAF`q3!p0rY`D&`>;8SvKdGmG=n8DYFvcCB|EU}dJEp7Z);RX+U#0uKi8 z2u<=7>UD1;OF&R=Np!~DeRY01-*|p(r0h;X+x6UZ4~q!h0EZ4-0~nPrQ~>vY#Pt zc3pSv*>RK0btCwL{aah*p1%7Q*MhnG?Z|tR9kx*ib8x&-5A1W!ecf~SGO}uqVEyHk zC$_xbVPPBjgzsl%YgWC0ls;cP9R2z%hcIU-IBx}Kg8Ub*71kNFl^`Kjr33er>{gQI z65sUpfr|c_1BAh6Ct;Uy2;Uyt<{a-0WiN8DaCBX~#2cwr4z*Bi)cWQcQKXbJRgf%r z)o@qm;e*`iPfuo2eVoT&chAlh0!|5W2dGGMmli@h*Ee|cWyw(cylL65QyVr6Opz#= zRI=(KFUcL)&I6t^kg58OmdCxIsIEl1fkE}Dr%>B(*Nk0E*1}mYZ7ON*U$$Zz5^Vzs z*SX;Ho~qQ&Zwf>H7oM{C%#m_6D}xWV7Ywd!91a&d&#;P?l&NE2KBQ1_#jalaXP_P3 z3FgU$?{4xhS;C4`VyM&}=nM+3X{0o5$Lx{fB7PYtnqPzpvXc z07fNMFAVqx5&fH;4u9$!>U;h6yfSCJv;}lS92yU09TxRYWyH~-pRbHolnHs)zoiQiS2}Fzb<%C`B>s5dC zmL2{`99UDW%7EQj!lm?lS+Vv5ALV^fDy&efMWqy0 zO#OZA4eDAnR6_4RM*{Js;w^wsKNn1Z92AQ0Al9lFWQ$qieTb6ycBv47o{LqIf9oq& z;G(I|gUlWIo-)Mk4Rs=Om-vZV!aE0^tokxH=(cMI@+EnQn;lD6Jv!m@#`H1$)Dtd$ zMCPrxA3Ng3*>~pq`Ga|{s1j74YxlWC>EQ`)m$D^iK9U_dWTV>&cG84p`+BkE+-qtv z!EeRm*kgGS@2g}~w@Wx-s$p0p7nwubVui(2cl-;tg*Y*&`TKAsCH-Ws4=*QFZuA*_ z6Mg-loVH*7Te2qHB%jKap^B|=zt|;l*>2;JH#f=^95cxb;-ktcXo4qC*Taza+LO-|CMSBM@g%w>c(twp)nh*;q&7>j)Zbw1g;!b0F0NDclEMc5(S6OE(LNf1btFtp+XE%6{v5T6mRdGK`|Dl=}W1r z35xR{^0_h|zB6MmKD({a+Pl`3|I(fq~m^cDv=>`=;BZzN+jDBe_ule7D7HpW~59RfSI#+>$eMrs}00 zYZ+isyKg+-qrsl{Np6OE;`C2PXdCyvICJd&B#nV&@6##iyygPX22U0j@mPJ1mJ^YOQVFOfwmvIHfsf*;Jfl!9fa z(Ev5{!=B`kZJmPeau$2rFLi#EYVRyqmh#&q5w*I4amX!plLVkPxZ`5`ksEJ+uZEW^ z#!DW?O4n(t2T7V8c~G?M^ujY?5FLd&1rvsQXY1DdI%?egOa6|*?{!y6G=T0uqH!DL zZg9tiztdZ5CS4uqu~xTmg`nrUm?4&a4pjS=-5(WfD9fi=^y>c&y@CB|TJP_w{xHnX zf6#UAx4!)?pxbwgx?UWMUa-L5=^ZA0nTQvwe3ViC$!u{F+Zq9kM#`(GD_gvHG+FfC z1A0Gkc8CdKexJbe;nC{Imrp2R79$VV;B^omhDXb6`nyQ7yas8!-8s|A^n1p$Q};VW ztf|OU-Wzn=EP_3#E!G;I7c(x93GWtV>xrPosr%Gw4Jr29^qsNUtprr~xKe%td1Omy zHhbMHytHy*zew@iDqkg3Y%;sDYC^vF3<%9gUS(Y3m0`Vftw@>i8s2cQ|FF7GDwdJy}) zh_ck55=L(_lj&b}B?N+feUS_c`BVazvWmy`j$1RP4x_I=G(3f>H@2=9$N802J*n_4 zp0@rpai}X#&Ic;MPYpsAZCPQ)G1=C3^UQRE^*%W>Z>biY(ajIrpA`U!@s{zuBA|2w zuQc-s_M@$lPpG($3c%7lS~+|gh?$^oc7k+Gi&pka&x&+pndKeUO`gVt@1ZWgXa>9+q9-EhxF zFO_*HXMg3@lzL-h(eJS>$Q3>Nnxd#u<&1JgHzfDev1az1A0yPS3zIKu9Tu4<6Gop6 zO25Xz_j4ZE1$KO)pFkLS1%lT2c}B&WBjpQgahy{vc0WEgb4EmS=FE(qdi;^l9?Pcu z71ec6wX)PD_MCtm2VgyG(J+7h!{GR&+|AFe(@>_XcmQRSw88P? zF8d`2Rv#^Vhb6Xl-ogCD*lF}Lo;onE;h}NYJ+;!v8uTRwtA16UuGE?&c zN^sUi^YExr1D)#SW&YeHiA8pJC_SD^Zq6vdF}_VhKISh4-?XQotV|YqI}9*XKBQ8~ zT1vji%Sej9tmoTp#5;i>Gde|p$U8d3$RnO46DWONm%hgC_>$B0Kd>3ZX-q{L`mJ}g~;qF>qKzQ zsC;zE>9X>~Ep(-nt+tE}R;#?yVpkO&w&~Ik+@lg23eH9Abpwi{S}LbdgKyHNyY4&s z*CyHGg)#eG?xiro$$ORGGQz3HHwn*NzRXW#nPgp7HKjb)j(O&LnK|%z-J3BC%G4MJ zFlF<mfs#adO1 zObya77!)iLb{FI}K#<~JsBpk_5D80mU`d>ocy>|6ShjC~tEX z2rNvP$%TJp(p3C>Lop*343#uuLzZdZ_2d@S$jsmtH~P$Gep{J)QXGUj4oV*fsgQ%# z$U&^+pmzQ%BbOQ%f{=B9<~y8MR)V~ie=0%fe5x^!-PJ?y`>|#5<~=POK)62udmNlQ z4k{rBY>@?C$-$8P4?|-PAX%Qu7oNqczVj#`Bcat#1=m{0R9=<{C%!;Zi!aBYky+fh zXW5U2mL;Vq{^ysXabdNnX@9Qs0!7UaKd!_-ia2Jm%&!=rhCcS}R&v=hxRN_d&Lew^ zm!OuUbVSKoE*}8Oxs6(G*K6}bkjK(w#7cWo{+7<^?T|%JBmvt*hF|+HJFQM&VcX>Z zY`gNZRtq5=E_GKtK4Il&r7i96r-o@ou(iT8+@Rl8=X~~8OxLBmnz}~>AKLB7zd`{a z1VnN(ihQ?Wo_WMB&fr|;yLC1C^-FqRA0WtSSx*fEvzOfnKyKT=q63$p^mFWX;Og&c zI|}_YBFavwv-IgIa{&F8h(f{GS^(g3H=FBX64A~Hqn-O_ z_UdHc8n*=XB@ggSo&|U?`VTr>jSX4qD&-Z!N&JD=wkqSIrQ*taDQK0Gyegwi)Ke_# z6Hmm49U_1Z{v(CB4CVjK03iNUJRXBZvJu`a0z5lK#I;ELTJD7V*(hZHaAd^^Xl`y! z5?e50$E==z8muTxk%gx^?ebF22~fO!hXOR;HqfXLeW&gDAAX9`<-C_$M?q(Q80M8EY1ju$52k4%_QUMibRAsLlquSw4kvC?YCoWv=pi;3o zIts1NhO}d$+mYUu-jt^k@hoUNwbK>z^%L+^BC^-ZxYSA$L=FBMJiFg0cXY-LfNRG9 zo;|{wVw_Nvvl@^3a7P>)*Um_I8NjtGcUk;)_E)@(S=uYkznszFybPSVz*!17E8%}+ zCEPYkW6-Ji*t>NBV&A#X~wRxj)Z20z)IirGW9SvGwo`I|MRcDZWKg`%51Hji z`6Az@-Z74nfmATVMy|t0uQLUlf`8lSR9eo~?M zPJ>ELWCE$;2c0T&f=p;pqR20Ia)saldNr<#(L=HTSq@VaJZ|i|ji}xk%PZ~H3i7p! zd_L@zxGURcS}cFgwPTppBbWB#=B2a*ZVd0KYx@u0o)5RZX@+DVBS#zpe_pflxmq56 zu;In&GnRwx!w`v)NeALyBmYOm^SaAt745G!EMEbVgf@;}{Wth_LVI%u0lr;r@$a~u zKlpYzJQ5GA8~4P8vUGF5zxJLEsPeswll zzoDKe@}AgHI4S=Hz|ut>SO=vYY#YWmUVvZU1Q(9q0aWgO7{(bn%tihJPy- zuz$ep&NVK1_hV)8gwoMfqA86l!;WT>fp%gi4Z!U9P%yhE>ne1v((Xw901BlA9;1$e z(^;b6bRj~@XHx|?J<`IVD`?Ad05-P>1)H<2%zAX8xGRVi2u>lM2IzMZDEghOWI*W8 zp(VPnP{mLS=Wz(2*_EPbcEXB|uZ$E_x3a>w=W_S~I^9wfo$hPUCCOaxvUP)KJUkH} z3*hoFC|sU_&H|?>8DDth9)Q2Qjl$pUv1&e=Zhqr1J4X0lp$ngp#wisX4gKa8EMZJL zcBXvnXTrn-D^vYD6?4J_b7eT3psYZVEoV|1hQrr);H1J^8^5|kJ#jOz=|-98L?R2% z4&8y;sNujKps^)jm!N;aQYYckw*z!t0L8*L#Ml{atqT1e&dylm2pO{@@W8X71BUhJ ze&LI}%>}@BF<9I*BN6zDVWIRmvIP84CiETIVn?8#U}_g22{O6np+;(E$JXPnLZ?9> zFVsRMVsT+cbyPi^&QqNhs@_xW(g%h&45t}6AXf|?q1zEK#!HU7ZaR(Xp)8Fv9MpDV zA=y!#{?ulvtYdWg^>we+R#9*RY#_V))wo^Hdt#E^2!lU2`0I&a(!!6kf$V4i$Zqjz z5wdYW&CjpBZ||Qi(m$m?`)ZCLT8G@l(E#HjD|*9;#;$=_fb6Gl|xZblEOZt%szpWvT0)&FR&P-`87p z;B*v?G+8-a#kte11pxTG=>^cnjp6{nT{8f4fNdFnbl+sZ4n+@uZkJtx>lafW zYNR{0C^_fWwuWGTU=Uq3^C~Rv#;tj%o*ItDr72(XbUYxss|jfDfZb-5*YY{RN=?9A zKu{2*zCrB>c?iT9c?Q8ls5sV?Yl%YJU6AV(lI%gD?JzyRObJ{w4sbUylNlIuP}(E) z#__o(oehG`4bL+_F4EX`dU`(9(C65>k_TL+I~wzsJ7NLVE^ibS8(G3-{hDc;^#gPY-~fQy zu}QOJ&KZWQ+XF1_tu61sUzJz?-&BTmKVop9WS(eghg;62LyB!wb?H;lyIrLtoyt!x zzGQq|*k#S+>y4Ysf|gX^dzhaon1ePm5yv3SJ|GN{xpemS3!B_+#;HF)#1r&E zb1s#y;M%^qB%2{~!Z4ZP6w7-$3>)!C>CRJ2eq#xjwyX0@eep)OwZ(|hzH=hn!P8d= zQJ4E3eZ01>7?I(#9cBRYFCFhL;bAC*%*Md>4==_rPXd1|WQH?{$!rk2wg|%f z!!{#p0Ajax8aDkD=Q78aFl@0SjwjnQ;5&~016?5DTIwLA>m}nzM*c7M-UJ@1?|=L+ zWr?DNC|e~-6cUnU(n1@OEM+HDND`9eCPZa0lW$)fI=DIP~i(*UeMQt=b3e<$F5?B9`!| z9GJ$SQzOBWluR5)Z0rrWI!5dZjfe9>hwUDQ+L-*@q+G46rrPql^6vV$oD(%4WPWoA zf1eSq&6MMF#;C3ruP}T>Cit_JC~w9YisOrWUjzOe zvICSK;LlyKR090DjE}n_Kl}}q?!V!$xH&Y9U0#k++&wlCIkR4U+rusEzhf6&B_c8R zWL0(WyHn++6lbpN){{R`?%#nye2&iC51RMfqCC}Hqpv-*_IN9cZ!nGO;$I)H`*Tjx zk0T+hX5E9dWAY%!>Ksy&}A>7RP6nvyoYfWZ?Kimo*b^)xC|Q5S7tx%xJA|P zG&(>^!tMUfKY;=NnhRi1DOf8MM4!z@!SnUm08TT3$D-h{PsO~WiziP+jDK~t-@Jf% zA;HUVqq#-Le>%KK?5I%I@5EELJtk2~cUiy_uC)|@o4gv!BcA-zx$eK{!0iHB4Z+Jv z9``W~-}&m(otF#1aZTvogqVF3@F%Y8{F9M3B%6npw{G+I+T*_=1}xL$`>t}8FGJx3 zpw#JLFhv*Y>=isu;ZR4!_^dhiCT;?|cG(`d%gZtzfr*~HDeP|uc8E)T0r()SCi-rR zz7OCyWV>hJfLh4udBpqO$>j%+-+3RnDdbOpos<5Om3iLBcU8Zj#Kv!-(sdS|yokr! z1hFDjw*%vIiC>3!D;B8F)_iA%zENXaW>+DY4WEfsLDMDd6C`eSFL-+lm42`Th zp{7~P99<*Y99r{|v5MnYpH__Hx1Ttz(Q3e{JBUqezyvl1=L1e%g4Q#LGls_ru&2}m z_rSad1=|6q&YMG*A$sM&d%&q9u75>S`)qCsICZ1j4w1e7DEHxfDMZkCVKcWZXWqACTDcpN`F!Z*`o{Zu35CTE@=K zUcyMOEQcquzVyxZ`WY1uyRLg&mveORs#pyTR=I`J*2C zDHDYJUvw|yfeZ0GZ9u89ZmWF+XmohjsCP_u-SlB>|D4=+p8SJ?u3B2Fn_e_}uu}tz zZnX%ecZds^dgKgoao?uv#87A*iqWNZ=xo~qAoGQ-Aag)JR1SlwON~FIUJu=x`+eT1 z`xq7|SCC7+`+-fO6M)q5|b zKo2d`o)MP)mWM)=zjsaq* z@UD{q>YD_jlcPh@eRwhx(~D-+ z$PM}iLa=af5nwP7a1d<*i^78&&)BvYiGt(y50%WLZVdE}%FquMRV(}e!R!8YRy;yq zo%X+Oc^d3DtS&XXUnUtr*8$T&t~m(3Rd1b$=WlD-?o^LpyC@`19U&t#Np$_tz2dPk zS?o5~@ns#!+mnaFWwA!hTYl?QOG&lDm*s>dgq$~3u(R;)_e*Gj@^`FVOMB>~uKm9x zZf}_US!McBe}cPy?=lOU$;X?cX5%1ld}DmIX4S1&^-LL&qq;^ecOFul`g)U?m@6Zfj=NHthD_tR1}kb74rCX{-@?AX0Jdj_&Wtz5k$ zI?Vp|8SQW6ck@EUu>W5d&^7CxV)zsfXnYUh&-;Atu|k5}d>0x_wNu|<#YyF7b{!pL zAk|>0&x1?VK$LGgzA(er`*&8>ky+P0#h}72uxRQi35%r(SGKD#II?7G)eVm970Dj1 z4C@_soyuK5kUOkmUcZ_V+jZ&W3+cF-H9Zqv^sd|-6X*I>(NjyBt5x6bHB1;?lF$hp ziflc}3d>A(Jdyn&Vzqez66C@RlA-x&1>VdW3b6&a!(Sv$d>Ww9v79Ro>_b@}gx3@~ zvz!t7)4Bwq0D^?hsqcV;mw~gIOh(pTfG_>JnRaZ^Q%J}Sg2>HGN*x#Tvvqmm!7Zn=h>qz7oBa=^8dc=K%s zl7Vl*0O0EE`o$^iAIQR&-|Bh?dvI^*%~Fc2GuDVuIMB{`yckKoOQ%W21qd zO{6^9u6qKUIZubv{)EoC;oU6N(<)wTgC#`9;M|k9VZX^#)?Q98vc{W-%kG>9EW16g zi%iE#VD<4op>w_7ae{p5*=gTz!!ZJhBBsDv6{o&qg=N0YC?Ot}6GK>b5BDB0E}2F} z-u)9g=Ou=(4IG!beh7)^+{9MVF7e4#_OZzmW;)+NIAR4f=o!!fI!=^EB= zeN4@S!fiy>GCbwy!}nSBOL%S!iB*lhXUH@`#WA}T@BSW{)ct}zCzi#J8v1F@rpMgx z8Cij~OslKm9lB}qW9Y!@zo)l-_qgTDOd9&9Bn0ec%js4mbIlDD#kwBA_(Pa<2t$sU zb36hJh}^N&-M>zAH7Q@zLgrO7#1YI zKA!p=?yrbf1_R7UArDrm*QS?M0vJ&#NyY6p7?(LT}j& zq{5Lls-Y@)on}D{iRxVOUSZS-uj=5TCb1+1jWOT{1(d>+XAWZVECKa^R>xB-CsZ%@ z`(y?&0==7Kn$;mSoRGH@2=La};^}pzk|0uV=9WakqxU|lW5t21n0-01WczAt`Kl&& zkt9lJ~d+C*S$<)~~D(|M!Ovto8qz+ku{sv+97J+qh(R+UeMX_;-uV z`Iqv?iP88y+)wRe^2Zp%Mw>w05f?K6)%70CDA$hE*ag<4@#Zqlij^6GHE03`cI@xN z6+xhS+NqqS%fq3*^GBF@mSEaH+=zZRduE=#CBLEDARfTn&Kvl6c?YR*&z79Gednx&O@_ek^p_1bvu--ritTn#^4F|| zk_QZuYpFd&Zww9Dy8i4>I^vC)!$7h5LLTF!5SK?mO9S(-*gSNzE0xs_)YSOUlMx7_ zZZm?Yd-U`JYc2^!5Oo-O4~9-d5Ot}`h&m`mJtI5q4L?5SH`fxP?xQ7qsZ21X_2Xe| zkWLZMvB1!9{qPZPVkg*RLOD_}WiDz+eT$flfFC>&7c!t)-w+iw6!)b*TZoY1O5ZuO zl@?3Ght?{ zdGcfWYnUroQ=J3zWkxra+7q_nj$8;zqeh|+aktUyGd7z&=sxE8gX za!FyXqSD7&>Gk^Cg8`w==;8k3E-5OrG(?y;T%7`q!?K6Ql={9yKQSStLO2Rxfz z^CC&PCH9U#GWtcieDJIlu`Qg`7&g;+1g0KmpJ@Zq<{cy3ujgaObk&)0EMJsOOKo{` z%oY-6GbK)fdCSGq$>;l^vVA%BX-#u`5|D^ul)dnK3x$x*{XW>m_9wee^g*;Y1^{(u z`MmRBtHa$bSY%=lox7nu>*evu7v+w=6Q?$T8B_lsdoPm2v(GqhyRKON5Z{5!#V)ne z*M7wck2hQfBypsfsF5a;1?&H#nu$&#p{+0ghE1I4K+p0$MMVQV9qMNwjq^r~=Mkc? zhGa!(Ru0$0yoMieYT7xqc=9~OfD={y_Pm;UBTxK&jFu#3LcDF9Ug)Je8KLwd{AuiX zuwE4|@hK{v>_JcF^<#86nEJeNjPfDFr}qQzB*Ph%w4eHp z{^js%-g3BorI`QJMx&_^Fu=7#M_fFpdbxlRR21FuQzK^gWXGbEawArr;;2IlY=RaG zah`cK{M(Cdn5!w4Ceo2NoL|L8%NSqdIVu=+xWw4M9@97m>;qsxEEyck;Cg>Z!-^~W zoTd!(FDrthl*$)(Ik3k2&wzSnWE4ql&fC2kCKj;H?wEiHB{(zzj--P{-K-_x)2!9s zAnN`rFxW3@W>D~v3^JHG|Aj_b9yzJ}C^eD!{cnC|ejO$wXu3<^QBbcxV{snLDWIU{ zuk*C_WT&Umoz{6D9EW(1S+#gAq(11MApEf6>6{m*PFTkDLr(5<U6cf$dXNuelB%d+kK3 zTp{-C6QFwpBluviLrM7Ob7N_dtK3Vgg;bnkx3kn?~uXe`y#rTnzA+` zJi_Is>n1z*_mxWB^#8|td4hV8tspqeih3Cu>!1i%`qwQn>H3zLbXgpEW7EGk)}1-e z<-Y!PX6wR^oKSm-qe4DGg-!;6S7q`wPRZJKac!&<8=Sh_x}*Dy3*Y9)rpjzVIXZVr zwgkQN|yuI3cPhhMkbM7mw{2N_ICyA5xJd;QOSbF3Z zgI}b7kkH!Z;QS9IJm}V#`H-ag7i{nEtM|9Cy+j-;d21;?D;-%2rq&F66Y5)ur^2#5 z`P7}SHX}T~nDsZh$%w;9W#JeaB^nHNfBAb{pM}f6rvVr|I1~z^G3?+C)*w6(kA`zm zHCy@_X&DONc6156pb&{f9onrf>|*4+jDX$2W24<*2JUn^{d<9=Wda=v4D{AYpKsb4NOq+axUP=gYvzWs|NGM-m zNE@C0Gy5GAYllp9ID&m)7^KL&uL~GxY6(z>;~Xyj#tO>wu?V-5=*3|fuPS7$a}t(9 z^;m!aG>U@HW{@)=#yA=Sz8VG0nopxqR6LeJc8_~7pFB**>%iB3XWgs4s}0k-P|(5> z%I@#KPLl@x4`h+P3)MloKCt}3;ah7x+e@`nrCzywNG@1r0l0PdY(F}9mnjx z!IXN*r1$y5!2r8fIC&ty)X<=O8vwppK-A#+KGRY@!*I(Ujw6+1II|SoTc_ z!5p=?CW}*3=3a@)n6nl#L>Lkq!dnytc*2udVKpR0!|7N1rOlT(btrWcWj*ZrzeUas zg-vb(EFfapq$YEM+zIRIqdGW6^B@7F=>v22pyPleb)*$h~6eSj9 z4#CzD07dG*17r?~KFLZL2(LPFrZQ5?Fjnt;BC_PlB$;)em#KD2OH{iLx2Knvo?yq< z^$WdEMq;iOO+_+ZEaCSseGpu@fJ5ha4+CzP87s}6*Alnv@{+b0wH*%5=K@fLLFEE9! za2YK3qU|);ZjZrShyD|C=g5lo z1uMm}xT8i7gWOB*bTN<{#|V=Jxp9By_FCfFF_C!9@HbK_oz0ZIB@(_YU$1H~=HK#8 znj3w{-&Fkh@0YSBxW-UuOxGH_%R@;dz%c7LMzCRXi{4Rc3m3IHD(U#)7gZ~Ev z(NGJ`M^FFJtDM{22E#e|?z=0aPkl&t$mGS5eM7i8|2VZfbW`*RqwKcr7aNQ^j%D%o zo{g%wHZ*s`D0fx*&vd7qCY;lfXK;ty?iTL5w94pKTmByzYe<{ly1qJGZuVUE-oE1T z%b(i;N#(T(fRJhS!ab90aVKgTP}PmIOx(IXg3@+6+gD%pC=W5DwDobHxXuZ*Yc z=Os-nc#4nQlrx~DJZvd7YG6xynvoT3E?N}5*RQ2!tS|k_>XquOw9ZQ3S$VQn#+{W> z`G4~zQ9q4YXQu(t@?o(L^OznCBvX=q#v)X&;RRm2<<=}`d{ zY5vKA`gKj0Z!ADA+LQHhD3qdi!$SXiziVE<-RN@|ZUvI-G}=F;&*9v$yceEeV?Pm4c$~X77%X}oVqoc5Hb2F(UUut1U<7Pib1e~S_ zIWn4Q7HZZ6As^yymtt>t(rdCi+Z!%We3so_uHux?h=q$q#XT!fMVdsq0#2Mr-(*+a zpM$hQKL)9Bd+{}Du9q8rl&(m?MG6v<@N_i-j!Yu>Tn2^tLQN!-vaOS5yOJ(_9Z{)E zUld;?!rAjfkF8cw?chN|Dm|q4v{ZB2%`@}L+EIdsznZ=;;Q`>fbFffbg=BX{7gS#N z5yj@tu$6H}-M(>P=8wZjE8{2^e@i3{D-s=wDBOYn#;mg0COUvWLa|8;+I~+r*K|V6$B_Z<954my$-j@U{nGuJ4m=7OChp`dq zqCl)$r2Y^ydjf$#W`GYR*-;#(uTQ)-SWUBM=CRSaS>eAQeId9hlbwc*m_i)G`y=QN@_SSy;lX+Z8x$i)@5uA zitKi{zG3{WKw@R+y=|_g;^SoON7a2Zu@m~4TIC8fNTwkMjK}cpinW_6VqVv~m-@vy1;Zk90PSvl@%H!pf1LHHGjd`#O=SQu$_>l=* zP<&qSuf^$6T8@VEWEt$pXrzVrBxdZalvHJmTG@RbE{!FBTKJH!2swbH7;>KH(PXWA zJKbnan7Tjey&QE--PeI?I(%@S=d)eFOx;rs&C8?FXa;8d)K7avaeck0f)I;X0#K@n zjEDaU$wvPs$u!qE00o=xKn=OBdW_@f37I}LOmo4;)cEk47a#jM^Thj2_=it=O$&Qx z64sbxZB+HWB6dw81*Q?vM6AaX{DXn#^5=_>z2Fs!(diB?hTP#%Mqh^mSmvX%fT_

In;qAqrxkZ=G-Lp+(PYBrhTd)KM{zvr+12cdDnN?#)3hSz&k zwc_lR-3LCLz_dfc-gNdWwW=k8#dg=w4*}3EK=KtM4|ZpaGTP3|-{yOw_F^sufaC;C zU&o+Wo#$PW^)InqUb16LQkJ`v;qj_(8YiYre>e^`oHDn5$Z9V|V(NqYNj{;yId8Bv z&z=-jZf*kI59!?c8`zJNHWu5RUM_dJ%Wvm?Fun6u{Zq{?fP}|(_7GwO0V5El#J|4p z_|FJQzdeA2$Nu6f>sLkS`d*=ukk6uLDdzxZk4N@9k{78|>%Zgzh&UC9F%K3-FM^OW zTD>?->A?8Y$#}H4>acB=)rp_!{xst~*I*~r-$Pa%XnC6Q#1O%XdPM!26`|w0CLJ5m z$iOg+-=hV2&nCQ`II-yg&Y>CCi$UtxvBOkuTix;X4@7t;KHcs|5g8g%w*BAIdqGx}<)7BF=wPaKd!;t{Lx5h2CIZq1>jO{Mohonv1i`8%{; zlCraO%)`n=h(wr16G!FN#Vpy7eBt$+15{hd&D(Qog9Zy@5E-wSmSmuH1xiWGPJZ+z z)3S^s=pU%@g|H-&FXS$qkU*Gte)?*S@fL916&O6#hxxGq7>n(9!m3_=nuULXy>hm( zsB|y;PG7q6?I$YmeQ=@C5&I`v&*1gBTl<*_vm*;vb znO9n4rEjb}DgPCQf`Q92{;MZDD7qw6x9btiZSSPlPBSm~`M?k6|h2ld5g-yhg7 zy;q)!QNGg*p^Q9^B&24`=rb~Q+&Rn5-AIll0u?eopk$LM$~932`sb3Q$blv*LE zNG13v;0gT!(S6=YqqI!XP`{j}P5dvZg$36tP}IiE7B^hEDCUY)TH5;lr}x<|XTI#< zUEp*ZNwP{C!+7pks8!ZEZw)4cTY6!C{P^uSYFqEwh2Td|nKi<@B5yGdj&beVy;+tP z>3Tjnj?Btawj!1HRoj9{{>I^YS}ULn&Nm=3ro6KB>WOn6BMp$iTI6R{2+=b#70;`@ z9>#CDJ<^Nm42a$@jnt)^Wa|L?$&J$b)Mj$kyLBFCn}Q((yE+ablDn51|9U@$-rP2J zC!r!soxF5UkQRVFNCadX(nyFw#xvMIVEp&f0I9B5Vrc#sys)Z6A@aB2Fn9eau%&B9 z_IwAMgU|e~QVpX;xn?JBjFFLNwkF*X#?waPXL_pl2YhlB3)7*_W!((B#hmvBD#9(X zGW}43xOM;Bxfl3HuH(yEn71C!D3{?HjJLelR7)v9)h#D9c+Y6=9HrtXtgJCpg3soQ zlfg+C)=aqH|I10P74Ud`o<28zEw<<9n8l#bNEw7oe51YLpXzte8<8n^{c`t((}QsX z-m&WCfMyp*!Y<{B<0NdcMbwLTUd@`)aa+_~pQU;M=pJ$sGtV>PfZwr3s$)NDzPU>( z*!@1<Olgti_zSCXbEF4TK%?29v#Gt z7?oG{Vh|IcNE7c6)UrQ@T2Hk!+f`XdH?wTxL98Q1V#tL14ei5yPmxw_-)35PLg(1M zK%%R+k(@ly3wSH6varS525+A={z1;17s-dcv&Y#-8BO$9YJK0VPm0+E5`f4B!!Jzc zL5D>WhADBeoAe5=Op6nITpq3xCb488s;&5vEJR_xqT5Ld=cReE`JA&tO&_R6vCkxm5XLsEm*=$>!Y4lEqYu zm#-O7w&Mdl&fea=_V8h5J&`WLfYhLlO!7oWHeKajZ5|-jbwBb;zHLxs*%5pxzXR88 zFHku%p<>>_&WLRr+lAe%w-_7`>;;i7bs10FdxLlyXaXSG#Pun=(8gvD+Id;fCFZLR z6L8*eGgZY=yO}#ysB&h>*8&_a48N*-H?xLAY&S7~>rF1^!O<)h=CQ^w1YG?R?v9Mvqr;=dyeoLo>rsTU8cE`%- zg0tcix-dn`Tv%qVQ_f!5I&fC%bZGPq6Z7n`F1QP-nCa>IGT>(U>cN@^VCq1v(sKaM z$aHBip$x0DETmLjBR(-w?Xy=h+YiM^)|^!#!1eyk%-)%*EAVHMBDBE!LG;chMMxZf z4e_JJU|iDg&J@Wdw3>fUY>?e)SrUVaq{lI>EB)AgV(Qb6rIbt#U3Fkgidw79>~dge zHn*@kTF=G#0XHl4cg3%@o?SXtc3Tk=qpGsZFJ&Y3JH3MX*R!sEYov7{)jior^NUMm z4J`%l#;b-a?p$y`8Mr4e=+2k}Lw&)WWuLjE-&w86z7Ze+sR+b!6YHgnrZ6>US(Fzlq-StOkEf_XX=5es>Rqb^`XMhP>~A)}N>6K3miXXdB#=TbH_Q&^q$1NAsw9 ze9^om=oV}s)C-DQ9(=pjd;&!!{C6sf;nj>@Y|C!5CaFah_D9u6pnhtl>a_!MonZkW z*9{l)5X8jP5*P(-lh=EqdNb`EVKhcb2@jl<6RxCw#X7tCsq`kgliDBD-D-$g?~iJi zjv=doVbZmaGl?oXoHJ}Vb8NOL;hjC=jg2Q~2yeA!4f*<*E#3+*=4}Q6d@gk^_!UY2 z#-qtHi29^k$C1^Q9Yae>In(PS^qY8;h$<>4J&~~&e$!}Y=vb2-4TyG0?;d$E&{^Kp@Eb-Rw{M)G6B zr#@SJlt|grx;IX_eC>~oK~>09D+04!kznP22Gf5~!P33XGR7Nzziu-u$yZ@CO5dXP zx{5nAFt4!;>U=VavW+fo2vmtjg z^5P{jY;M$iFpVCrQLwCTq-jWe^19xS@>ag(B+}vA6qt95$jH%^KFpF?pE_P43}*Y* zZIV#Jj~7s9CNq%K3%FnK)>9maKRn0<}>3}VO&CE z@PhoqChft4ijWJa0J!zcUZEG{^ri0321S@L6?P6KO(g0kgdb6x)GN0d#bKt(O{rkC z_T0LWfJZ zsojkO5lCTqxuYRlX|s@YrjT`-`4OS}AB|S1ca?X*T0Jj+U`>V(8K( zL^D5~gY%1t43w1fD7MGQXQVs+dX*vLRDBzdBFWXIqZi}uFv`%7!*aGvU*t((kGySO zE)O(V&nCK>qr)_g_}f>0N-uxl(#*;!JVY3%NmuDP{?w=R!)nikpR9f-iTdbRxMw)> z=Owqt{+VX<5dY-+M*f)>bK0Jv`rD@*DOg6K-NsbgSoPC*b+`9X8rHM!3|dN#fjjJL z^84cl6}9d=K!bB&d}QU?k8fQ3{$$rlMF`2H2!TwWS2F#_H33W~;v#9`b$&63n;v`hXroQwL0nTv|`dk+h-*T+e5q z>DazkL@zzvgoqDQiLFVL#It}c*G8~L<-x^#?(ndD&9-ZtBhJ`c;hCMZ3N~>Bb7uBo@r=x1o32xFh`Z$r|ZdL z?|@yvjOzNk4-L#l%^1r2mxy6P8KzFRYI!HT{VUpO=^M>IL=zXc0GGut88BEFH}4Di z!>EPjY45)#z$-9T{>_W8$MdfHGhU)mqxeWNdD!kkYvLVl=6AclerA15u;N0W^D}P5 zio1ek@UzIyIP-Y_;(mSK+b+K)3p=|zOJ{Z`S$)-?CvZ^aP-bvRKps5dTTW;M9bd#9 zzQt+D*U*SA(olpjs5GYH@KQ8;%@stui6`(?DBQqUWvgd*I3hn-aI%~YqJgAMIlMZ% zE%U%{#CbnQW7|-QsA-7A=Ikyq!xWJQvf;$bd@;NYh_9kFrJng;MAd}P6$TyHXf;)L zG(?H?`T6U8+5PmpBi?-#OvOwzjP>82wF9mcUq4*T^OxkWJ$SokKur=>MC|nKyRzM{ z_%l?6i6v_AFxc;^qhd&o{s@E2(}mFM$r~o9hvE#pIj(PL{x*MQLtmc8o7v5Ws@Vds zs(I`>rEW_;_eY)8*p|!fJG%Aaxi&|dYHoQmYeETn0T_0MQuk{lUSQW=qdnJ5vfuD} zs`cTH+0YS1t?kfT{i~P$Yl#pI`#G}A0{9w<#@?UolTmD@5^Zcpn zprSii?7w>Ekk70%d8?+Pieb*iRqzkNeSe9+wlHM)d%v&4jTGCRs~B(PF8(FHWwJK) z&ys0ptCDK}=ITaqi{KcP>b95s8spBRU-k(fHCQ)F zb)2e=DbA5W{6bki2Z@DQwH2Eu###co(64$xmM0AZ1vo6?xSfz~q_-HoB%tHgpL-@r3Yjj>_De6x$rDr8#A ziQ)w-+7LUMR3_d&Ve8L`MV8mi*vvENKdlT2+@@tF%(;+eu&)dR7o|?ps2$AJVPu9T zj&s7@W@$2GxUGn{no7!pbTKm4vz7`t9FeZE{6Vaz(Uee76V{4I?4Z#E)IMlNTzBM9^PIQU76x>qx-#TaUCnJ2VbIu;UO+KpG>r0T4>_$*j+k$ zYP$-{?T)AaF3a`y@!a?A;F5FQQtoX36FUR&-o`~M>L7FL;JtltJ7Wu@H}>uNkHEjr z4D=^uJS%)V-Ds?IgB2TrrH**pPaFW1T>5*$evI%+0z}$X$T>zV1vdDJi)Bw1tH=mm z1z`rvn1}3Wdl2eiHkYMg7PaMP|aYmgj9*ns1or8dmx0vRq}%OEF*X~U=A z2bqf#7(8G{&&3W5STcb{!Rjrac@q+kUR58G<-kA8yIhRhbJjEBu4}84#w&)mpsl{I zowLpshVr%RE$g`FAX%ALbTl28w^#2JYL91%GR@`3$CNGnT=6X~ZX9$l9sS^+UACr)1#*1b_9syN)|w_&?W|)SR2Cvfg4p zitP`;-H4b%aCAs2aEc&e>zJvMgRaj~lmVm?Ln$fcufoB5)3=IPWF5qRUIkv z+#J<~bNZ&K@6=k(uQpO-%x1qp+WxTx?#~RhQU(aS{AY=c49h^zg_U1cTI1i<6PyYe zrWjhj`)r0U0W&%8MF0JRqN@P!KQmQwbn14ZoWE4VVBSZah9@!1O1Z{rE82@EpB%46K9vA*HpnPjy7NApzs*+0P+^#e=2@R8 zkr-C^U)P3B{4+dxGlCfVpEH-blYf40WX8y1Z-ge^vw9hfS==uXg8d;Tse=sGz`FE2 zzLuR0Vj9N_PKI=pTypybBmK(M~&VQ^PKM5-F{=4vMC(6UhIjb94|gM$TK1uCe?{URB=|_ysL5VAC%fI#r%#^C&EINMT`MuWQjyltX<^`Q5-J{M-l1orZ&zrT`!Uu zrMg$3@T?C-&%_P&pdMgd8gp@4wt+l=;BD*T81aRi)YkguZJ&O$WZ(h@isG*Bo2FIp zTO4|U$9hV?jNw#ejz8u?nMzy+v;E95W#ZjreI;+a>Qwt=bj>l{Dd~q;>k2k*g<`kD z_*)?$uJ9pO=$R`p&wnNAlwwE11?4257~K$GCj~c!!wB?UetY0V>Xom=$ZN%mfjS~Q z&JQ(Y-2916pE-ZJj=W^he)M(k>KR5DbYKxBAl5ab(J^ILd|cZrKB|$6{3%w!$YLse z%%>ZQdjQ1^Kp5r4M+B@&6~Re@UQVXjpIad$&)*0>9RKz9I>V||&dxQlPNwxXmuONsOgkw>VgS zhY;Y7s0iLU6~|n%=C_ahkm*FeRBE=-?mwgY&9)@I3No7&W=($;Pf(N6HT!T~#RL~*#8s{1qL|My|AYIy z^@+-`!alxvnq#+!z+%&UYI~yP<<Xx9=}E7U|fHr{nHi@Tk(x zT|X%oU+!=N8@cc**#6Rkk9d8AX#`|~2NROJj??7K>3k~La$q>PZ z&@SiyaV6!YT~mPX^>sV8?y{!1$BF-TYCHBc#x_EU^Y=T+d#0iH#;|VwpRHkwZR2HCuiN$YL-pNqJ>ewrFM+va z29fLzKWwQ4Xu9LMlg(Cse|+^EW(59D{5Xwb9m#CY8`fUk{B@efl$XmjD#AvJ z0`D+~jaP5w@^S2>sMt8UYJGH8=?BGePf&66db*03Q^=JtKw_0pZI41O(?W=;>hNjGCR-7y(&LnrDy-#Z?-YkyBT7SuMK zOdn=UP^JC_a!vj%a%qAK=CPH!iCaOzGZY4%K#v?g_IL~1*L(LK2|T@787gA4)0cr93wFa)*Naye zJ|biMkxG;|x8Q9a>W}sYQM188uycL#?01?Q?45N15ze|1k>w}#z9iSt@x^C0sa79j zwWIpNR#oZ9?IbjQ-^rg`JcEp3a1cAqe!fw^-U}sU@IR4|4WdSZ1N$E>bW|69XSJ$j zh>$U*33E9PT-kd-{se9q6Ryr+%N^pMdN!${>osy8O;yD;v(6TZi^StRr2Tt2_4dwBcP2y$3^V$A2=feVAdWtM#q_ zgeUrk;?0Bnf-hmo%{a6o?L2FLcp`6qRNfMOFi+T;l__DPx?~l*2k@{Wq{^NUM8C+|az=XS z1Vqm??UU=2Esib_WmlOLDT93(NK@%Z2t}{&K7QzdGw-m?IJKTc=-yNTwpSg8<=KSU z7wSJue7GXlb%eY3gZm8i6M+wGfy4M*5wNf^d}nMRPTU_FJhLsjwsU6%bVr?c2j||T zjT7o86#^3i3061^A}B&zemW-8Z0#T#CQF19#BmsZXpt^JNSWBN;ZV{>#nm@DRnL7P zWfO2Yn|$HlcWSCWe*$^wM2PlzyH7Q%L~9@QRsDhzf1D4Mejx10i%1wDrQ*=Zn-=K} z3qs)v0QHIXhbZ)iYX(V$IGjH;d?;=!VPeziy)_p@s<`&!`9Nf;bff-#7k{o?ZKhCR$_u;o#ZS znk{>Odu?>D`XU>@l6j>yR{F-ulk#6-D7e`ufLXPm;om}cr0U|o?i1W+yutE*&{~>q zq3w8dAOX5%bf7l)Hzk?PKv0@@XTSvN%OU^4D36!alyt>%dg%$di&xm?w2rZ58HIIp zT%K&h7~`dP-dVSKa}guCvLE&{X`4RmWo44JXn1U9^X}a<3?g_T3;QJMov6pJyZ9Ds zb#dUr(;>-Irz%SXhbd0`%islW^K|#5GFY4a^??f_$Jo#qgFP6O4>q$e2VFj9^;&S> z!NBMpJ6Ai(jF#M|Xer6(U9~%R&ya=fe^c{F zz1^bJu2_cT-K1TLNW(-gW277TBdgDJg zIMvmQ;Sc%IfdY_C=CQWIt$`QkoeDxH+To%Ar&t||{rOio|S{kH%jP)q5=4 zDW&JmjmzD4#F0eF!jP;I)@kfNEID8;#kZbk>Y7oK&>1v}r2tKGl6YrnYZ`SUn{PGW zF)UqDfa3bt{MK5m@%&x+;ah^Sz@wzwOFB)1|4qV1e^{N)Gig@-?GpA;f9o`cbvPCt z71!#x7q2ca`!Urh*miH`;uXEP7uLz%c-E4BOd+ZQ@`V=}v-D^5 zf&QJy*LP};)BKZLOndh*&-Y`d4pXJ5RprN#jD}v#z0#dhABuGKGPrBcQ@~HdKy%Sw z2=ob=0bf(6S9!*Smi`1gJ|;%*S*cA=&bfB^1D`32S(H9$<<{r za@@Q-7dIQ#>Me2dUJWJ}WXEH{!B_7XA11FZsR)D?x+O+q6bfjqN_uJND;s&X9@V_|)~?z0U9g zKAeB`X86lNpH*lSa)_Wk4pz@ZEz$-n98YtdFJe}Lsi<-;RRU2^?fAkBtM_Z&3n!Yq z=vq?*mw;nv@%^(+4^pqJeU82yzLR8C_-E}Mb+Fs?PsgiVSbK^l0~&^9ncVbkZ{Yf5 zI7AGgCP?l)I>k8MdR&KVsymk6x9Y+CvVQuF#J)Y~mZ&Qe0&Rj{VkbIKgZpH^8^~$zIT~PNvhjedhoW6+iUrgmE=MaU{GqyVw#7QI z>Mnee{XDNJ7<*ro{fMNqY@n8s^dt4&-*-^Cg>|(Dt1sZGa9S$Un9`rvH!gxd88|89 zd}tb#$F`SKb{z?4hbm@vm4dAFW;e@2pDU`hpBWT=Xf1|C=2?TmHH(w+!(~_h@Cy#F zqdOX}8o4Jq$ncqzB3Xe0*KX9N+WeTK%cS$_L2khpM@Z=81eU#&nUUrmC%7Ru`@{Dl zxRE2&v`-IC}oEnhf{W7MAhlA>a`~e66)0pbSjgORJ;Sya=Kaa?rgH0JK78 zCPw(fa@((1*(5jYH8&mag(B`E^9nRM0?Nt?Q;%D<72-3U5c{!J+fImcHKZm))s7DF zs!_Iem%(p7{{=ki{Se^SeSaqB=z8IK05V?mogy;s3{!+=HI_ zeo064Uo%rqBPn!~1%z9dQ)%w%S2Fje)r7W#?}&%UJYmZ0+Hm0)G5^w=R>%EnEv?Rk zrx(1wl3(|W0=RV};Kk@gpXx8KPs=V6RYGHo1Kw}Z0WE;`MYSJrgFV2JNj&-yr!X#K zxlWMVbzyz@cX|gnqNQZ-0b3GP0a0Q;2P$a0Y`t5x*Ycg<7n1(g;AF6W>)X+G*7+8? z7n}Oex0#gPIuJ#51&PQsisrS^@2rsYi ze~&L5!9B^xJui^`!(wmalOzQS!w>8c7X6h1p7ZMFA5E@(mkmz8FqD`OH>uloleXrZ za;iwlM3T5n1kY-W{n)&t1|Cn**=FlABG$8Sm@Zhl+i6SwZ*qqFGxm46jon4?Rin^8 zP_0Eqt^Qcg{w-5VK9gH#>54~A(W2F7jA!Xv1Z?csL&Ft0aHzCXd4Ilfb!|%RQ>ls% ziY!vJWk#q{PKNo%J)S;PICBJKybyJtl~D^9>Y%_||2w(7W`I$8`GGNL<>_$Q@S*YS zVmIwZQY8P|MApstn9-a!NR>Kr;$!P%hI0jVY4H|YT zo#?#Cc*whHzY_KO$M5Nl6nNo^?8nEaW$kuHRMAZyUHHbl(H(RZwd!{JesW_qA!yaN@br+!WT3{3|vO-Rw&KZkbnqxBUfn?*w}T4W zLqfgKo4xETRfM5I$KxSdJ-HY2mlXv`md* zqL)|#XG;9L(YSRwha)W4YeLE9nvfHAkrp3<4*>Cus*cs0B9a9IvADg_SX{TFCWIgK zw(gF(-W+o?X!uv{08!=32(fS>42$!=BlglW<(2y$k^ebG&;abK^D?U5)#|la#)V6v zw>NJ8ebVXn^&b#d*0$7NK5^q{S~z#(Z;fOBi@i4ir|NtAhf!20X&@9$LPAI~o9c?Iu$hN`_=Oq)_H08IK4RIbwT{Odp*zl ze}3iOUC*OtPA(!N zU1EK}9Hr&$@Qq{F)0AiF$V}LMIM`Y~s8_}bH`<=E`}j1<`-hPvSu9)shEVGj@69+I zvh8>MLFZPtFMaP8LvQTZe|8v5g$3P$n%@q`tO)v#j!^~xKorWt0*yw%p(%Wu09i&* z9q>hjB6uVIjw(q+LmV4g+xalq?pZWclwqKjNbzE1JrEr<%h)P9a!>Y?m{Gk4qrejW zgiOcqba4LlsBTj}m~if{C3t&;Ky}#R3)(4u7QH57AMNmbP04EDs0^S=B7ya)o>0w| zV2vM#zwO5z{8NJw>plZM{=U)Y)%B=zNtZ-NH__P(>0=Ezn%u+yLoj~V;)x!~O!aDY zn1^naBc&w{Lq@lMqRAcBo_zYj*vu=?3+BOF(>j-~h$3RM9+1(_ft`D z@MZimbnx#7&aWY2J9+cV05?byBrjcF-z1z?a^?g)w3<~Zt zWWS>fvR&!O-|onaOFsZdVEp`G|5%AhK9_|OX`r8~@(%}Wt9|*ZfjhxK-U1)A*mEP& zLTi`cJmL;xa2VJ?%SE=N2|R;O-#7%|#i-b0H@9SQyFc_tc9>yLfaN$aeQ6^h;RmhR7UFR`mFB;i?hCf}Nq?}GixiG*vT0Jqh4#F4WF*qo~@An3@%kLk= zdf3A<)ySlif&g#^Ck9f6QcO%!k8pyNY80?U;DhLc7}W2p%L)SEM+SWs&OCx0AFtwR zw0g-tuaNa0xJxB+c8)qxzk#hy<=}os;oTgl6HWdGKieZSlzMI}p#P;6B>(}sqLI9vzfJyh(L@PJ3GW1*u^;_J z9}UwaxZyAxsP^JZVZ;&vf9|=HJL0exW8%F?OW*?IF}GC@>=*e1p<#o_=-G+%UijR( zo&TdQ1Kh?~un|Ib{|Dy$y7w|e1Ji@Bg+%P+>hSptfz>doY+Fa)Ai1NZO*OaQtNdqa z42~HWkoSe{tsOlB{kv;Nf-9BAK{e_`xx$_S@No|zs%WH`>N`rGmc(WD^!1yx3T34+oevKGOG~ol_D$Svhpyjyd*0#!^(8HvP}GYYvW+8 z9AbvSSQtO>wQQOTw*Q=ZQ~tm#?bhp^9CvFj3&uw}3<`C{&4sXCl$*G(|FvKybn-Ms zhb_-y($-||fchRa6HR`$NqcJ}DKCMfr-@RSwQK^9t)2Cg0vs+oe3Rg~Tb{+UUmRDZ z_)hWHX7)(`jX_cf9Z8VptSRk5TEmcrhoLRv0drh%AH$zELYw+_R9ag z6AH8)OJCRl&;$jwZgx|?V>zx55EndZb|qxd11_ztZ0sf39b(hqzaM|cA4cwp`Fx^9 z=&=WFkPyeMQ}4V?e%j17ufuhtn?j*e=wampq`K4rQfwl7;!B^z?-pU9T*>Af;Jc;J z@5qLm!z3qJOq7$1ndB|^seEAYT~k5$Zqk=Z12rUSjma161w6O(0`C-)O>XBF2xTI| z^#{nfjGFOca$@NSxFk#WKN4}z8W8hQT6)~apM-49zq$R?>KMvo?qY0>U`$Lx< zj;4>=I4GL!No606zH5EGc7y-}1{D|Y)A%Cp(+uwf{=GIcbjvf1Qs>-j6B_jCW_8nG%1LH`zN7rv!xM<5W7rrVo;)- z*uUvtnRD2VRl z;e8Q2&bM-jUJNxPZp6UbBN%ui3iY|o6^qKVPAiwLta7aVvK(+v5M_lra%h*V1VIYy zt>eW!E&A|=)E6a4!9ZmHgo?*f@Tf-F2>=>rVe@jypFCxk7*oi9u1euyHv!ay6E%m8 zCsW8Dps~)wKaeeuUl=T%6bpcJIJEJ-S*t}H2Bfs0fbf=$DAj(zzZJ8O$eow>0^TWM zkkSEge)&3;U#J=f~Js#h?QSxD35piIEG++E z8wO)A!N=IPD?LXdZcHZ$Z8*e*V8Ot{)DJF}x##n1Sy&C{^pR)r=??oj!agy>>16*a z-PQ$r!$?d_9F8$#)upbXxaBG@E7D&q8l%3)>0uQar!JQnf$Zo{&;+vw(RmZSy!OfR ztP^Da+jH+*ixaC{$u;o%nY=1Z@f^o1Ho@2J5nhy?Nb(6<~n zMcaF|11wC$#HCq=+PA9GJJFJAU&i;aAQk1x5z?iN--9`Ym$L_QgKEe`$;U+ec${18 ztD+-F^1+g!FF>a=Xk>CO8f&H;8K!q)qwqqW;DeUR7ugMU7r(Zf5qTD@7RvmS0y07b zboalQu`_CYxo7VvWD!W9mVyO>H5}B`RuW)VLTohTFN9g?5e=7BS@-iqp$@E%>H-Um z)CZ(WT(x@=9=WW-O-N{KlOqdzR|4r8Hr4Ljp)^>RoN;`)5(|{`l3D2|s3<*?f8?x8 zGykTCXEc~_D%hkQUDv(sRq9^)wk?IDYuEJxx}5KYe?u>uH@}xZp=YopFX^~kX*s`z zRSAJv`5p*2J$3ux>J$?k{6LTaM~ERB?*Z1JQEQe&0iI4i`X-B>0lRt>BTaTg^!Ts6 zI}WaZN9j>N-|jWi zML8vFcsLDPM@FBuQe?NEFW|Dw#hOdgPt8W1wTfQ-ZPa1?`y9w7dq%FtMBnw?CP`Rq zQwiu(ScTnUC{=UrWOAr~`_Tz1v5gx#tNwb6x%fS}p;g%vD?nky z=<{{gPZ9zC`ybH-uqX*j$wb3Z_c6e#J^d(8X3OJ1^p*>c1hzMlmlod50!vOL$E1B( zfTj%)H3~|5WmxAXOkmcu(d70w9S-^vd-n%E6RAV%D!ZRDc`Y;U_BW%u<17n}t_hAy@e&Ww->WLv zvt>kPp5u9=deiWdXZm1z+f%7kN29H>El;%F^Wm;mTaU^PKP|-ecG$5^>+ObKlWqOi zmae&9{>Ek`Zk{P{)_owUYUWI}VdfqauDkn-nT?UR1bPVjTkeQcU^D&N_BOzD$H%|) zVNcf2F_U>UUa1i7sL(@W!JJ9n$lao4#u(<>_dzH2L^wDK&iym2e@(#ll%ud<+6 z57FZf){;q1pvJ`^pa=lXZeQ5%zROa|BndbjQX{5Le|}MaSmfS9yo;9TMnF2KqfV|b zY}3iG&EF*DJAf^F#s?YcKKuB(vc6}WQhQc6I|S{22wQ<-K#;ZfX)Ph~5m50F{{oT; zCRARy&|R$D3-}oLLX%r(Xdc_+uVN5aIEQP$OXx!d{RU!$acG9#_MLc?6YX+DVxf@E z(Bib(UTs)N(NiSCpn9O$#Pd-tzy5CBkmICvz_614$c8Ec5=haF9A*-( z3-_jg*M0Wowx5r0Hl&k)n4wGav{iL=tjzr2!@E43k#5mE;J(W*8f4aI{R~Am252{D zWxElOAw(m0$t(jRKMD-XJT=k{`6Xg^naN`3W92)`a}h-l^M|^DFG8lah1{>7%Uyry zdS5AQsiCKGmvPmEUS@k_o^K8+SH3-{k|w9WYhj?G3%PJ}%HeNIIEMQeckkn7*Z zv&2}&bB5okl-P3*k4MV(YYvKS5~njs1YiuOUcn3&(yp^=N7Bd`;5^Ok{VL5km|Gz9 z>yrcRZ0Tz80WZkbhsEZ?MzR3;8{o|5hoeYYB!N|n=fP&f*lWw`72N^1jd=%KW`+8cw?!_uf>!zazmL+t& z4cMz#v)yUKu*oU5{Eh4_m?8QTbf!RL!xpzJl_!QW?4MVJu8ir*Ben8ItxPB@^XbZR zva*`~|7uKJuEm2&;Llu8`R=Y4q|mHmS=b$+yEuYl`Y4%vx4LeO8-~0oNA`II)7d40 zuwR1}IZl1roum21zI2wN?Pbw&%o94UWFgG4Wvs=2v%&B#udW+qkdbKAcV@beVFH)v zdXDXp_8#E)1FH`rWU;6(fK0Ghs=0I&PBMUqP=U!u7g*^|gy?NrdlDz=jU^{GrBYzI2ceC%Y8Q69u zVyQc0r*s8AC1}GLWHm>Bjf*{;!0)f*xJ2Zgz@Xmh7>gMmaB2L_1+e8>*9~9LNYwN@ zQH+enqy7`xz#?t@pUNd*^B`Y1p(+^5e!ySE`9?|MwnhB=&S(F~WB25Hc*3=myKUQU z)^P9Q5<&RnI>;!12y7R$OxS3_wc0f6$-`B;2>BdyXS+yD1P`R{CgF!pquCoLls6m?V!ymfEq=l(UAyS5|I1RnEm9}m=Sm}OKCxw5GoT^C?Mka{FEzn$esPS89K-FL+~ z_w8N_(Q#tekUThqfh5;c*?P^j=$UL05DGL?>dPA-(p_ z%?ODd%udoX#6DB8?cPJJ)AGw4dvb_Jxjn3sX!xP-YG~JX#Jz<5#_elase>ZvgYP}j z5ht{Er3u5_d4B>Fx&vh89=k)e&fyRmk9YeDr@k$%*?6}k3O#|o^ZE;-@47NJi|o8?K*s_s=jmpC?s zNBG*LnS5>8wq+IVwz*)Ts^Pk2hB(eekXZWmPF*pr!4(|wqa?j9Kfn~C_&Rqnf0 zH4T&Z`++YxVk5U8By;WM+d9xrgN!2cfwPG`zZlBVYxB$Vb#o6}iDeV&jP1mo#7j3izTkygL` zL6F;jQ|ja_Ofq+|@3AYRP@o_1;goGFHtGj{vjD;zBG2%cazgubC$4{9u9;_R95OI> z3%0sh9|L#3wVMBD%D`a~9^un-uXs@m69&HeJE2~0xXq5YXPn;YBIC&3AyYfyB=bHY z1d-d#WWl3GXi>l^hn#;i;CP^vM5awlzy^T-cQhM~D!Npci!L~BRRq?px9U;^Bx@+VE#7bZ(F=bBYYndH`Ur$?`Sl44(@=5^8Hsv(mV4o0ve zyTX@IA3cHzVi#|C-;QysjqhGI%L$VLqkBe$^Pa5<3|M^s)`<7@GFcOgMUF-oLtn&? z2Q+${&8M*#f!raDQcmjH60XVNdzVr)vSFphmT85V%yo2-M9ckmnCAu&in=}(xAcpc z%Abc-nDtp)ICxYS-}H_um=*_9;x=;Tljgme>$fb=Ne2F4Q4m!COzJ!&bKjlNka*vZ z<8jY0Q)d?IjxVc|PzjAd=;-M10H@GSV+W~qM*iR~rNDiQxfibR9rPzk`zy*8xbJxD zsBv~RM1A@4@**3YqJiOyr?)q*t+rOs`eyjLR)OTA3zN1XoP~^_mQ+G$`m06}DUQ7$ z!cWHnz%29A%~GoUaFH96Zvysl8h4qa#}|%M6}sf9kC@)IqTA9RUbxRDLSQl9AzV&1 zEatnfYxkoHg|(-#H{gm)jEq=gc#>jLq^irSwNI81emWL5XOP8D_nE*));Ohgw~E0e z$zzg_FDron@PvFWCTzN~j>9>D#e9eGLkTW3-|fkuw>t8|6lQ<4SMzT4)E_TRtTp8rb*tS))PrstkeaSy&*THeez@A*8s6Dh+(`$B|E(ZL@#_V3vI zTi`t(Z9`tXfZ*LdpPS%fGqhE3F($=x(|=a62q=NP24Hsv1I?UFEH5QhaTGZjq!ynm zvf~vr10OHd`PyK?b>^2s!oB4c*tvO2@87)iCSIsVX$ppFdJYzqM>po9UvP==w!^rg zySFN-^ssls(f%;K90F~`{GDD759w*JNS-Xsjej%2xk7PUkE&ce`4JMOePzbDirmlr zCXss)S{3lRkwN&M#DYfv;OU-9)qsTJ9_CwJmDD$)4cH|1{P1Xboo*|5Jk^cpZam5fFwb*#{)dyUuo~hVqEm0SAXQN&T zx1a}q!Z=eJe7WmjncQWXu{evSv&VBs&c)*k;tpsWa9Q50zW|+*B z_ecPiM^8WEVVk;dItynURJ^*(o_w zJkrQ=iEbwFiu0x!WsX7Cgmpo_qLrlN5q?V|oW5Q{8QoUl$%d#wfaTGV8l#rY7KZ z!}i#%^CR82q1ki%(_jy*G?pIa->Z;Wt{b5dRRQR(IS+~RRh*-O=cQlPa$ATv@cKb{ zyTun-9rS~AOpe^>iUTdHORUrC%-<3*7V%bUW)jbpa>RFN<53?Z*U?ymMXhxd7`i#> zTNtZ!8|ss(M#^@I4s2eN91a z;Y~Z32v0!#66+=oS-U5NRRCr|7BWiIamUnR1sZB<-E}YJ&7HO9js#9)VFg$>zK5Z# zTGecC?qjVD(Te&M{L<&)JEDAxn5XK6oyP+4PV((FD8Wz?X^9>=Yc{B1aSO!Oc^AM3V&565b$U=TyC&MoG#snK*pEq92$PL_ zc#Eh~7TzxmFAl%PNk!z-7%WVTcj;T){;vfCyK+;D0%79lVk&(~qlG~9^0aw=D-G_F z=l{ND27&JsJ12%P*6*wLWb~te;MLbUm8Zt%b->-z%4b?SjAS+jE|4PrfS0bef%2-sVe0p{^Y;#h}p9oibV98}=nJXHt8SESMs%Q^p6k z)c$nO={|t|D&MFN@I7Z+pLbX>-cu8qi=(dR-Kp7bTQsRLbU`otpgT1CtX2y?o(q9r z+Xm;K6lAhC`S7WGt6Om2J94PY4wb4_MxCKBPaC7oT>JyClVU*#0h#O#ySSXp8+P5P z?^mpFA6{!h7DJRGi@{1M{A(++zUEzBaJZxCz@z3*8>anzUg+=D=xQzf!l>@ROi79@t3BazB68&3!TwQA6#QP?x28y z>FqX@L+vZg{Fe?IJ&25_id4eS5~B_?6k9n5FAxR%Bj`{?7+*|6OGY zl=IDaG=s4)!I&J@^_qSSf|EqtKOTIs+8E_@Mo{}GI2DQ94(|pM&H21 z9v`PU$ec!uJA||D1Vk?t94S#nM7p7rNh4#hX@xc$=+>mtQn9GoTIP5Pv*_CB$spVKCgSM7%mm$(lxY3z?OS#oKq29d4xx~loNr=Lhs!b0(r3)2L?7mX7@kvNfnTg5z zpV_UAJ42pt)jqmUbnc9SQgG2(wFi4`&3M`4Jin+Zwe9TJpW=-SJ}d!@zB}WZxLvszUch(8JNg!Y$L};uP*Vx zUwuoaXZE@6Vw+WvGqvasGyHW~L6Bo(+~lU}xf{OwC7u;;yz3b!xc>mLHvN`D91nZ& z={q5pyp%PgpMAAjd$g>9XKRedkcmoMLjar3zS7TmWg?hwUoXq9-f1%uz+GQD`zGP^ zh!)%KXV$iVq|1@C0{&|F=~r3#Khk5pQmX!H_{-(kZGTDsTwiANr{T-*PVxRF{inT6 z#-D~2R=V|PJXh}4%0u}3&0Tr7{>MxikT6V8R|qc389Y2Pnq1HROnAcoKtt~hkEEhVZzySu)B!WJ1!w}Q z+%O72u}R9&tgGo(RLR|Uhel&-(hoC33$-?*U}|a;Lqb)1O7!yQnS@kC_Ig-0GbXX9 zMHbr;FpX*!8r`Cl>3mg1-}>lzVJgibt7f{`=^WF~BEZ}HqL01y)|!;A5t3IYNV>Dz zUwIJks_6&9yP4%p1Vgg;PvSH+BOO-&*D0B%pe#2EF2D9yl&GPR2#Hq9si=CNat93Xnv-+$6*Hv!okVyb*7 z^kNabba`BV^_@1KN)_}Wh*qIknv%q;zn1Bomk-WJ{-VG7EhTdBvdzn^ zZ91k#m&G~Se81jQkTW*p-MwG(-KKkv6_=01#Y#$Z@o(L7KIEtpS|Op~RMgf7!Q79s zbdq1l37r`c|MuvZ4(D;R-A3PIc_m1j>}z(uyuVwTKV#%n;4`m~ceX3dt_ zkoKWzn>S-hP&DGWw9j>?fC)wi&4rPDxUSaAz>a*{D@A^uGC@km>!KD7#*{8dTd}|q z@HalKh0`5W1%$Pc-R(Yr=#bW{)N}SDvJ8*Wm_%_2Nm4S00+&yCTl@^2%hEe?#6ZLwVbTPGNgN z5~{Jvax;3{h332XMLg#aVTxjyRQ&8)5TOY?Nm*b=thDH}D>d2txlF=A! z+vYNP3%zwq*;j9n)^WpTmGnSnGoy%w!pM~Hw95+@p1IK6JFmBn;j~mtmZ6%LbuMejWRF6uo6~_ z>z7+RfN}VZqbcydugovgnN5~Lpy3o2ZAWUvE=_c>p@&@9 zX%EmG(jvajlp=iVFQa1onIEeH<@$K+_hU`M?KiGn@QG+B<$UFna@zj(w|riX6o2B= zVuIMIL2OrP`_wznGb)YIs{^RzYlv<|IVGp^O~OeA$wpZ6z!U}7W=XN1O}LdHy^edq zhp*oTaw|0RKd+v?ouGeTi_!m}r~|Ufjz$aMr0R+zS(O%0=1#w2YuvuM=IoVhC2Dy3 zFjmC;%a2V_8&%1l;^a7CPMO9|E-3kXU8AQxhXh`mS?@IWPEq!MboH}j_W7HV8bB^U zM5*n%&*2Xf&kd!o58L)yiDv`+!E_9a{JNvHnv)Lm$kiH(2+Qj`32fI#&ia9q57%-p z!L)E;n8Sx`quLJ~i9*g&>0Rsix6Hsqbt0(i%kq)43zUM*yCnx;-Z^Fe?xtX4%Yp$T z%vx~9EH_uBXS+K8{4i^C*t zJjRYXxC%Sl5~v&c;{|8X5BMw^^FN>i6lj6|9nG)=Ry~KXnF}Y4E*p-&oPBKDWBmE4 zZx~um1gb;F#}cJ#>7+4A-KIW3JfbjDx?@6YO(7X?dGDRdKSZ<{jC}tNjA1Z;{qaj< zpDu9bsWO*<5x#MnRJ`3@1_O_R=5YXnM7+vL$~C~HA9_>)yx-1IY`W$x{ApNZtufDj zy*>QtJXsF_n1@iaCcGH9%UIYR0IsR5_RZ(c3I7uz@7t~Kw(TSUERr3N158TCV2ojm zUmGuy(_^$N1v3Z6NB=QQUdZuUCHxf@OQV${2cP%%L2wcG<%cAVcAwvYFjl?E+$Q(k@D zL(Pa}zsVU}u7ybB6QCke3US|4i(+il$hu^F$v!_QLAnW#9qP_VLK(tF*? zx=3kaME*7>jdpezz~+J(&3C)bW&E*#wxK@H9g6G8Kpa*-3p2xJDPcXyV5JuyUf{mz zSr0l)?PS?kw6fcwNX7vk1fLfjUp9`iGCx(k=IFj^>1!AE=<3e8qS}Lt$n~y~u(PS`~$h-XR zhkg0%*AHbA@rc5;6;cxl=B|zi#Ey1r_C^Ua9)QQgVBW?RJ!kJ#;vB(+++f>>zXy9H4mJbXW5*v;Te9T8IN&{ zW2e#zuqYaG&{J-bcy<&3a$e^x94Sfv0rzSdt4YsY0_jTrJkCj3v!B^B>zo0+%C-K7 z=hceo`x>-1y0*pa!XGOy&3O(ONHkw=0-)4`#?W19yJ&dHd%|BWfA3 z=4=K0Ji3~76eCQ*zIWdaIyHD0$>p+L*&`6@8%|2mbTGIaeX0F9G1Htz+pib{x+ZC`=SO_n;F{d%l)3v)PPhchQ$KM1chYg_RwJj4$tQnbbl%jj!VBk5+2-A% ztZAM=n;qr(+%F^#8Fcnvcz!1)%B{vFy-A2L-2+6w1qZVEGFpn z)b9-Fd=AI;9EU=dFFr7+QVU9fw?ui(WTBnjjC$^?_d3<~EaJq9b)5VxUa`88=g45R zFp7v6cj4QIRv+2>djzIY2l!6)AgOzZ)^?n&!mF=tTE55?|IlLtl0LRA%L+U;PmSH$ z#F6izJBh*G3Tdb2olt9UB1HVU)JCPj20tD(acJ}^OsIE9o#M2i*lv9v01wj#L@rbd zvuu!wsCGQt2PP|>h7ip~cX4mC(oM&Zrr=XvUvxXKq+ik9uG3NZMqF!;?5|xS%_K4g z=A;XMyj$X-(YqWe1wzEBHhzEm1qS=wNy0)nuC$}Whqp# zD4-^ln>39gX16R# z!$QQ&mZZ>zb%A3}^rEMA=%XZ}axr zple7n`1Fou#N`H2p~0dA`2aeo-1|@3B(s+;S4b+KbWY_DVaU& zIp-^Bn5Yg3o2wnx!edoMCoX;-9K}F10<^GaqWiZGnzFdW=8NXtmCWCAy5#3}BrJku zx{G>yMu~=nb#2>HRhEMo5^G*A2Pjn5jR2c7jZj@ySp#!w~sqk0C0H;Hus;Es^@*d zQ2bIFycnZ@{z}s%=2-vn_eG}P6dqiGc;{qamcKq5BXo%7@Wg|EN+$YULvk1DLD}Q0 zE^k&uuMEh_6SDHk{NI>Ej`SD$vrjtF(`dPK@r|+PWm{jk&+g;q9#!s({EFUC0X-{q zQ7yhG+y}h z(_qV%(FHM{UK)1#ZSM|TpLya1K-!`#N>UsUEl|vq| z(c=bHYk_XZ*bL?I}faHaTX*`j5`SaHN zoYA@N$JXbOhF>VhCE+`&Vijj#$@Qh4n>jhX8Fg9a>mchG~YUL@^7jSu*e3XdoM>cFlzic*k zRq^)9*gsX1gXqNmJ^nO~=rmX_v;<53Wz8I9&@P1vW+O7($ma;{c<#SMK)6IK7J$GZ z*gQx;63CneP$1pyL-0g9bY~UeF#1>Qryb$>{*2iLCD5|+xs6*&=V*a~$h zN{(n!`iBa?&3mLmGalsvanL^4+-@g4>hDF2S_I8Sn-rMmFX3{XySTgG;dYQ+!fy!J zX2wAOE-Eb-3(YmgsRj6H4IlQ>^*B=7g-`(@JLs$euo)piOei+#l+d~Hj41%Q#^eiX zhS}_1BG~)?h=8A1B1l<)ZT;M(9_(VP^b#tNL=yX<^r90hc21*msXTWf-qm=D^d*`U zvT2Ddp_Kl1%_zl(K?pKX_i@NdwpQ3nNN*|3pi88}7no2xvGh7z+?kU}%Ela9z|@R! zb{0^kZnjIpjx#Y*6X+#dZekah7CU~9uZcP0V&OPVA?eX5Rys%J5%KO#FwGpW<(vk* znU6RKDw?#*S;-~}I)wBNCHPyae}s0;x}}*!5)7i)0wBq^-gjBvhO6)5SBqomuW(}I z@)(`F0W>}1wpA?SAEux)tmRe}NA5$Y#=$coA0EQwc`RKJEFgMW7v5&dn0r_^fchi! z4n1KkYS?SD_|ZYsqqm~TEP&B=jGuy8lhhcg&M#M-|KcEMY`Vb4y32!0lh5++pE=2N z)c8V8UdrsMtfjDYfgcU*2MC68(k7h1^%p0EfK}$QFsYrYwpub2Ae$qH4y$_~r6+6Ia(>4#dgJ@$Iq-Vn zPg;-7BSrEfsI*MP5UnqL<9>SJ(Xy5NseDjE7pAtW*IB{g zA||lsqcZ*TXwOfMBU+JM%qYtz&GBWeh-vNe_oNqDIG#1+K+HD33s!7;Cw}Z?*6h?{ zFlNytMhcoO9-DHmJ1RHt%%%H1g(Hs6ZA06hZJNRcL!M|H2B<2|(~4M#RAA>h-Md@L zxZ=F4RSV3c0s0QcmT&!Phuy*_650uG4zSf9n}oTI#B=8B{FgngvA0R;jgKFXOFJG) ziQM#Sf(GR$v2LN1b(q8(}(0DAkJp(vr|_`+7D7e*&T z=G-B#EC-hFs&76!>}q3WiZ)J#dDG1A{@VFy6r^<;vL*%@>$cxw_nDr3>Dvd0PIR$m zpC9Mcy%Gck+ss?9BB0ZYD#5!;Ak9S+)|+t3eBrm)bt0gY}t%E^eb&(GA128j*4;_96iR{vS)!kKBd53n+6g_z3 zVoLjlFuh%Cw_2T!Fc|d%^vH(MudxNnQYb~Qk3Z;5Z;IERK~QiAvJF4Ew_osG!D{cT zYg}JtUUe1x^yW7-HEw-1P3v~zb}=SzoYmiXr#V$M)~nP10u3MLCGvE6acD4k?cT$@cCCN|bRJ7p+V`9^RhOO= zMF>YvKHh-Qg?wmtx|Xuv#o}ev2{XN}IG0o3-^LsdX%n`~g-Atdh^0{q-XV6`se4$3 zTVk;9IP%ZH+;X>}5Mo^~Jc}XA%y-hx+x_xMYWU%c4!-Rx>`*buC*0;g*cOx*3RM_!mL_#j`qal^K z()dA3HKbc9OPoVXH5FIg`)8khu4J{G?U2pN{(9q3H66Z%-soDkL+~vChQK0NIP)u~ z;xbqhQnrJwJt1Jcc*xotUfGdGSS8wRV3HLCPu{NB41>b&ksegJ)%lFcZXvF{7U~C8 z^kXMt>&NBpeh)}IrHt`&%8qWmRq_t{sCA)gi0@#h=dT%SKE`ubtF`nPdmO664JKD| z5^7(3q;V(fG`tmd%JzD@kMg{E1f9@Xc&R6}E z%L!LMBt7)pm5oBpw=r+K17DiPDR z%j{HGg=!sTNq>Q{*=e)%&=HsuFF@puyeCoB6|KOS>n8sd(&E%$VA1_>Po6^$BYGN_!14daNGjpJ6aA#qYkfJXbd(~#_mwAQcj?fBp5fB zRq^ud*+_@4+DQ)?v1I}Y_8O4etj+UxY2sc2>chyq;Rl*kHyb~%gXho!ud;)$)1!vZ z&pas{rJ)Jxyf}}9(^67j$9(CJW-F-eD4pK>s8$r-vy2o(4Ju2s(Z-Bu+lB9py^%6p{Kif(tQD6TnrIs-hInMLK-? zU)T)f)F^ggqGM_5RJ&cS=>eU+C#oy1nWsz43A$okUsTk-0bk=Y24v9M`iBX_VlLE? z7TD;BWiif4Off!xh%EUu-~&-k!Uj5>^7iwMOV_U)p7llMKB=CIQ;$?W-{|tGEehWb z?_&;0gayFI%uN>p3*)*zlbAER^MgX^k&UJHL?OKDt%q-D5tu^)Z{gQc-&v^r%9YJH z=GOKyTV71LgYU!_{H;Pyi_=Imx?A5PA#W>uk)a=8OT3a25XZE0> zvDegT_$Jq>F7eCq6#nA389hY5tM8W!WSJ4M0$a4e*o*C`?@>|LzGLqXN`sN}P#XOwyHvHK{aXr-C|(m@+Ul|gVA2w`bKf!ndG zV*p7SChQ;-nTH-Sbbgr2KkpC(8Z@BjJuao^FA0bB<`IYsLzmG%2gN+$+l zkIh)*S!D#x!Njwowu4%xGKDIe zTBg41fF?_@C_MCl@ehgOf2EAqK)yx&o<0Ei`pK4i=iFF#)fNZD}9E;QlhC4bAeze`@ zDUY{)yb(E#nwY;0`9aCkFa{6Prk1n*71REqJ#YzCY@CQDc>5w*aURa0OvfyL{j`j& zbGW!wTgAW25r;=O;t*ILhE^P>Y>3!P?>IUZnZA_#VO^#Z*U3c|kUw0vDaR22LP2kI z95V&Ko_zfol6FTN6=en=K73jb9Rnb^rjwnO2Ye^Wt+Pqvi5=27cgnJ6i2u0b4;3D$ zMxF4p4{Tz@_7Lo!!m0i|h}lTIy1PU32MU@DD9&kwmS_(2?hfiHEb_1@fqB3bK2Ou5 z`bKnV%9SCjiv3qw`syE?j!M}Wv+eVRH;KnK$x8>`J*_^R_`-3c%j-K_CqHLx<4~A= z;^FxASXp$p&|dxm+qGXlYxlo-!!>K>=x+Bm4CUr4g+){w5* z4>}|BAG><+_?8RuQ<`ye0c;kJtey4y18`ryM#-(N zv>DfWJ#4)cnsAz;#de@Z_OLjy%3=8OH$jeza_%W-=VX0#&!qY8VvDgAjF0pfRJ^6| zi-$cgw!}!vOHgxM3wPio<5U8uf6-avnK5?>65Qz zP5(4}cGA}5FX@YC1^54HSn5vxAL%}Cc%uI_yrs1BkM#1^0R6ujUg_4#-CB7FSugd< zyY*i_Wk6Oi&z%}bjpgR=y@R3|Cd<%iq@tf|C7ghRp=@^unqtRSeNo)i`+*imZGjeK z8))gNl_^87hE+aQ@AJud#P!5M;p26(BEh8*?=3h&ACqjL)PJpfHEQFaXqNeseK`6k z_CSRlEsml{awz9fgqhr~fWwzZTUPPKzi>Nu=&t&+PuEK^aVSNgz4RbSPw&!*;Tf)d z$H}Vk`IcMP@62882AwZoYUmyP)_{-0P9!wYv+eRDK6_K=E34B+tl%QJ%Qt(b9UAco zSXezui}7>X-z2Rmj0JGVe6^IS9Aoc=*FrtLAV zAuOkXo=7Qe{Mvw56`-BSN;l+FcXn(D?u0(fCcTLjfS2yy|7P}cZaj{TH!SsdWyAL^kLLd3${2ZHkyEh za^j5(Z)6$`{HTE%C5j9TnTRW^Y@ozb3h)m-uYiqYhjQLo&ClsWAY;J2Ycc0;jd$(0 zI3ms$7@=)Wcc{RU7>Pt8ftIH!NFw2V0Rs35{yZ))*VAgv{&*p@82HX`0~tMZTAhYH z0gr8D_)O#7Ah4IO-Te~sD~aaeE8Ow;CY%L!oywHnizR>>WMVOZWBB-k&oS5$LN0~k zxfG=t0-!m=)=CmEV{C{?mUt2s2^Z8`1s_bm+#2 z>E5vluaubROYRk!g39I0gx2cZZmPPqx@75R$}3s3v#WQjUcIEkVeLC>bXHJWii3a0 z`@HSwYO($v`<=Ry;^B@Wsp}Msg)P#zu9#0 z$Z`8NHnxMiPwE^qU74}|&zA)b0HiKVcz`jtBi~F3h51a{#P=CbZM`Z(g^6BIUMm9QgM8?9Z|i%HrhB%({*0`>>wcp7O zh^%68^1r|w5*4%1f=rBr8pwd5&qBV%5>4*az15p zL@_{L(+^`9X++pmS?EAxu3eT(NF2XrtfOn3M2@0n*|5?Ot zhryCvQ)}AhEu&E30T(KYfiIBke*(VfR4W{eIM(vwjM2{9)8A>zM0^?G2HNghx|kOd zIa8PX#y~>yAj!eKvQ(brF+xPFM)}RY2Rn6s%Uhf1qX=998{lEztoUio1B0kIROu?z z;kpug)noUXik1Jl+R0@#o>K}`2l}2<)L56FuhZP-{Bj>%{;FfkI_`&!<%kK3NDYY_ zc<^c8w+2k#J+XMZK83{Oqocj?|6FbFae8@UjQ6ndW^mh~!m-ty zT7>=vrrCN0{Cs-m)5Xp9Be?0xi0}C~;#hr$tI<&IAZQ~;1gp`2?2Hd%YaVJzJa6%S zt~ofR?5<*(Q}k^9?i*?MF^%T(c#Y zMP0n?cbKEjeN$93M(HZX#c9|&GVzv`+C2qo0oPP3s&p&(+Utx;&YAnn6Z6od*;4F? z%CC>A>%NWRgx|M71s4XTYxS?Zej1?jOf@6|> z0mwmv-T6!BDrj;(3>$3Odw-J#;PF{&!HhF&yoWrVY&&dH8oT}J8x-uQEECHG;Fo0f z1b%Ow7T3Fs_;xDGOm_$9wJt*P&S`h#RCc?8h}X5uTsNrfUmtu)vC!u$e;i2}_D7eQ z=yaNO#9>ZUK#gQDjM*(qb z6PBs#1pJ4JLYFl~#EdL+=@ra~VC_HW#dVht2P0Fv@^5au|K44IvI#EGxH+BkAQX`a zZn=8N!@Fhacz(o7&RCKU!@G-$0-bH9S{^Roajj^X5=dXPd?GO(Bpgd5%c(ZmgsT9^ zdy;#jXFV_eCYGAlcW89zw8bO%T4Vrf{6^U|#Ox0GGonP-!(~Ba2Dr8(S&Nqe@6xqM}LG?r(=@+w$f z195#`Q|}?)k-`$ z(qMK4`&Cq{iHKpPTj`W-1udPC1V) zi1fhcRMs0O`wf^zW%#zA6-@Q{K@}*;D-l=VSe+ zZwb%cse($vrVt>L+ctpw+3k7tDVWJF+9@q{#E0O%Q*Z0ADwdVfG(;yeqYnd@wFX#c z#FUZ``eBjw9?+TXwmUzI78HS*?S36mMQP{p@Y7)~;JG~=2Zf{vWPIK>RjxT-(;ta- zHYiY=Y&;kB)qS9nEg&+Pf4}4A3wy<8(jr_t`2i5vN+Mk!)R6t=U)kVOdJBj}0)U5F z6HBZD$wczl)j*p0SPSMqO&&!msV7NBzSKvDBf<{mWODRN8a4dMb7;K&yq)I{f?xc+ z4XtB^s;s7vB5~HhYRqw<;+s)tJIP<4$yO?>h#nhI9@-l04fl(|cQF{D7k*znPcYfU z@s%L*)m^>#CeKwaseyrh!^9c25a6@?$STSb+6%e8%6+pKMW6x(%^BGMfI(q80z`Lx z6`5F|t%cVQ!9pQ;JUz14c}Hv=)>f-jt!?feH_b#J294mS0j@;8qq@PH-%#@Txje1( z<^g1(TyLt+wZEdkzH+J1r);%gfEU8w)Nkc7*}keb^(!@+T69j*X@)Z4a4K<2;ONUo z3tP~xD`ao2&J=hsZL9#?9y{^S5dKrk4;fA|Yt>giCiL;s&?hBb&L-9Ls*WDfis?^? z8K+%AjyiwY_W>xktbY3Lkrhm`2_I|kS9580fK`j9$(wo`5TI7(ihhQ4f5CX;sv z*%T{q!WDSL%eD+fvN7tJ}Hp>&I&+Kvoc1$rYY~}P{pzsSV4MUp%=p^zzYLy?}&uUR5`s?74bwlt@)`qK%VG_~)y<-AB5nM~a*Yw83cVH`Udqu5ekHO1o{ z*G>|ADuTO`9}oiI*yd!s32c3rYRP^k&8{3I^71XKL!s&bqI{eXhKiyJvP<2m+%{Dw z$`Bkd7(30E*XIYR9E%IP`XCoiC^^ujmNf@{n_Xym`TPv{O)4m~v9_~`v6-#Z#LjO8 zhY5$QzS-LeL1VlLHk!|wx8sRbu+CTTKSw3e1?NASC(bL>ddDYtsn4!f^3pXo{a(;~ zZSCpGeJvF-;eX!F1-{BbHb>VS1IXsZUeP#9nuuQQ}>Qm(x zWwEO`EWZL711tt49HVj}BRC@i?2r15ckKETU^=Uz6Y{Og!XatyNgvb$Ti`x>U?AVR z4kDhZb6`|vk2gFPRBQ zfF1quD8b^bEmRJGw_JG%`qq6R^1^8+_N#iS!yFyM4Dzk>KPzasx^r7<1(+^$J^X)5 zH;97bugo+CN<%puyD;&Gw_3y=j4?TA^>XB1r<}r&^zMv>&0)J`Uz_tL-<%t_25{IEI3UfUJ-Pz+j@y}*J>5Y_UFnYhH$5FNTZEwb8SZFG@{_>eoNEA z|34JWZhja)!dYvvIZ<*~*V4r9Ii`16>P~mY++w>+Y~j;<&oSj~#k%7LzkIjrRP0}x zu#PrwKAG-!K!3&zwI4j~nFx=C0i*cF_56^8oTegDbNZdyW?7g##!yiIP6q%Qg+wNR z)-&KwpeIw20O(Oi#`5Q#RXa^GCl@{H4)p`O>{LOIx{(`$AI(_Yz9uURFEWk!ht)h% z1t)+!>d5jQ4@!=|fyI2k;SH zC-Eco4DzN1rd|K|#dkAjpu$dA3SYXQr|PXYdJ+1Ez$z+DZM|kg;TDe2MM7g_73rp^ zE@B>Yk?ICn>VWm7G@`!t^-MfyI@bZI*~}qEp|x@Rb-#$cUyDQYy7~X3&AQ-9o=us~6bQ`g>yL5S>L*3Wh zd*R~t0u^7~(&^7T8Edn6<{vyxeShRg*=)$Zn$}qH@<=h!z;BkeCBo}`h64`sX_Rce z@b;Td?ru_EJ0Wf=zQ*0`%tPyREaIzVK>g*vEaG+mQZM9tL&ui`FAv4?tXN(k|KeUT z^i2!2p<{CFnaJ-!X6TaBPo5|?h=B%a*%w-SbP;5r-JN~>^pmFqv-MGxl+_YP0q5*q z-JB9>ZsXILKw6|um!zD_8@FS}_SPifI6soBxP3DX8lpkg*0JM&|E~ssUsm#JguQU( zZ%x62^-yF;HwCiq*ANr?FY_#7pXV^-Rcfn?!Xzamp3qv40*&$vL9R;eW$L~T5Z1u0 z64`F&v$z<1-F#>cCWxCc7N0~M(gv;X29xTXKodIW=rKv7d1pj{ZZBwA2R7WD14L6M zrdc`VXQ2#tLK%W*mf-+}S9UeeVSn57*q8i?YR!o4!gep{JCY-Yr;kP^dOZ0gzLA@r+ivlsljxok^R= ztf*@6ml=GpYf6b~8Xx2$H&~D2j{^Iy zLM_s{H_BfAp2pJe3!+?|O>9kI+Ea8yY4 zK9OBT-uPp~E_8bFm3W_fiyAu$H=QwLwNnWh7dM%5?T0Pj%o>FYvw*~PM5rYwjh{#wmq9HD{VJ%S$ILyc5kR4nhCP_7-y(>5 zHYL_ei)syef97T1ostR2h%Pzn#8=6q;21Xbk21my-i~RzY^A>X?1N*YoX+U#L83Q? zAov>O*wzC%w*5rD_{+l+7Ro5&N$sl(9d}bxX^pPi_KpbdoLpE51IuAnq=T(O?p+9e z_L^5XBzmk_;gN&&z2Ddj3FQnxCpvt(jBT;6ST5N$^$wTj1~vwZU^-Lq2Dx|5f(k?r z^6Z?xO2Sf?)Ded1X0OYKDLi_k^AS|1Y~=c2z>Y>A{N%$1V>tFs^4;G&p|dZ{S!rQ zbA@>bC&p7c^e^U1P)&BKWJkt@oX z_ak^;bUupQa3>7Emih&pxmxn!Mf`?n&tkzG-gysMF2X0qi@FG6%bT`K>TSuHWaXb~ z0q4wH6If$ujIr&M$W~~sSOl#U!7x)&{Lc^-Tj8|Qj;4u)kgJNWR*_@-wLi=K(=6~jOQl_!~Uh83eib{d*dqc zTXdXW=LSbUE(W@>7g*DShpF@?!*#j}p+5*?BGb*C;C|eW;*3PW^%N?*WCrx1Ll`+5 z`t43izJH+!NR5UUc(J|QRnTcJE=x<%&;T2X@IyGY5Xo&^LwJqvIXMWryGi>$_xt3# zQC@41h_^#xz(LpZuNA=GNB3#tdo~2`<{IpZ@F|X$U(Oav%;Y zc4xqDCS|g@VR%@!`~7jr?|g3k^nR4hW{gpxDiHWcC6%MGeToX#Q1~=2+ZoH?>8|ST?R6Ok%10wbYB$=@~sVCyaOEf5gi%tFiJ%1lQhC7|rV8OhoI|b? zP#=Y_o(Fd`f_qr+MKZnTl~ebZ-g{HMuEhX}oRtMZjrms*q|GBuBcVMMUX7G5z8adE z>CCokN8m^6MztQ}y|1OQ(l6%MR$=_g;FFUtYb5pHt-ctaXrT}=?=`HZ(1!1kG$P{z zlX}^L1!sSP8GJ8)?Qvu3-YaCfCJ0-29gqDWsQ9$NAU$SXg&vd;@IfqY)keh5%BNO M0f+t1_jz9bFHdqG`v3p{ literal 0 HcmV?d00001 diff --git a/core-services/attendance/src/main/resources/db/Dockerfile b/core-services/attendance/src/main/resources/db/Dockerfile new file mode 100644 index 00000000000..a5699ff7d99 --- /dev/null +++ b/core-services/attendance/src/main/resources/db/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/core-services/attendance/src/main/resources/db/migrate.sh b/core-services/attendance/src/main/resources/db/migrate.sh new file mode 100644 index 00000000000..43960b25cdb --- /dev/null +++ b/core-services/attendance/src/main/resources/db/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/core-services/attendance/src/main/resources/db/migration/main/V20221122105730__create_attendance_table.sql b/core-services/attendance/src/main/resources/db/migration/main/V20221122105730__create_attendance_table.sql new file mode 100644 index 00000000000..749f02fee46 --- /dev/null +++ b/core-services/attendance/src/main/resources/db/migration/main/V20221122105730__create_attendance_table.sql @@ -0,0 +1,91 @@ +CREATE TABLE eg_wms_attendance_register( +id character varying(256), +tenantid character varying(64) NOT NULL, +registernumber character varying(128) NOT NULL, +name character varying(128), +startdate bigint NOT NULL, +enddate bigint NOT NULL, +status character varying(64) NOT NULL, +additionaldetails JSONB, +createdby character varying(256) NOT NULL, +lastmodifiedby character varying(256), +createdtime bigint, +lastmodifiedtime bigint, +CONSTRAINT uk_eg_wms_attendance_register UNIQUE (registernumber), +CONSTRAINT pk_eg_wms_attendance_register PRIMARY KEY (id) +); + +CREATE TABLE eg_wms_attendance_staff( +id character varying(256), +individual_id character varying(64) NOT NULL, +register_id character varying(64) NOT NULL, +enrollment_date bigint NOT NULL, +deenrollment_date bigint NOT NULL, +additionaldetails JSONB, +createdby character varying(256) NOT NULL, +lastmodifiedby character varying(256), +createdtime bigint, +lastmodifiedtime bigint, +CONSTRAINT pk_eg_wms_attendance_staff PRIMARY KEY (id), +CONSTRAINT fk_eg_wms_attendance_staff FOREIGN KEY (register_id) REFERENCES eg_wms_attendance_register (id) +); + +CREATE TABLE eg_wms_staff_permissions( +id character varying(256), +permission_type character varying(64) NOT NULL, +staff_id character varying(64) NOT NULL, +register_id character varying(64) NOT NULL, +additionaldetails JSONB, +createdby character varying(256) NOT NULL, +lastmodifiedby character varying(256), +createdtime bigint, +lastmodifiedtime bigint, +CONSTRAINT pk_eg_wms_staff_permissions PRIMARY KEY (id), +CONSTRAINT fk_eg_wms_register_staff_permissions FOREIGN KEY (register_id) REFERENCES eg_wms_attendance_register (id), +CONSTRAINT fk_eg_wms_staff_permissions FOREIGN KEY (staff_id) REFERENCES eg_wms_attendance_staff (id) +); + +CREATE TABLE eg_wms_attendance_attendee( +id character varying(256), +individual_id character varying(64) NOT NULL, +register_id character varying(64) NOT NULL, +enrollment_date bigint NOT NULL, +deenrollment_date bigint NOT NULL, +additionaldetails JSONB, +createdby character varying(256) NOT NULL, +lastmodifiedby character varying(256), +createdtime bigint, +lastmodifiedtime bigint, +CONSTRAINT pk_eg_wms_attendance_attendee PRIMARY KEY (id), +CONSTRAINT fk_eg_wms_attendance_attendee FOREIGN KEY (register_id) REFERENCES eg_wms_attendance_register (id) +); + +CREATE TABLE eg_wms_attendance_log( +id character varying(256), +individual_id character varying(64) NOT NULL, +register_id character varying(64) NOT NULL, +status character varying(64), +time bigint NOT NULL, +event_type character varying(64), +additionaldetails JSONB, +createdby character varying(256) NOT NULL, +lastmodifiedby character varying(256), +createdtime bigint, +lastmodifiedtime bigint, +CONSTRAINT pk_eg_wms_attendance_log PRIMARY KEY (id), +CONSTRAINT fk_eg_wms_attendance_log FOREIGN KEY (register_id) REFERENCES eg_wms_attendance_register (id) +); + +CREATE TABLE eg_wms_attendance_document( +id character varying(256), +filestore_id character varying(64) NOT NULL, +document_type character varying(64), +attendance_log_id character varying(64) NOT NULL, +additionaldetails JSONB, +createdby character varying(256) NOT NULL, +lastmodifiedby character varying(256), +createdtime bigint, +lastmodifiedtime bigint, +CONSTRAINT pk_eg_wms_attendance_document PRIMARY KEY (id), +CONSTRAINT fk_eg_wms_attendance_document FOREIGN KEY (attendance_log_id) REFERENCES eg_wms_attendance_log (id) +); \ No newline at end of file diff --git a/core-services/attendance/src/main/resources/db/migration/main/V20221124154130__alter_attendance_table.sql b/core-services/attendance/src/main/resources/db/migration/main/V20221124154130__alter_attendance_table.sql new file mode 100644 index 00000000000..3d50ee881db --- /dev/null +++ b/core-services/attendance/src/main/resources/db/migration/main/V20221124154130__alter_attendance_table.sql @@ -0,0 +1,36 @@ +ALTER TABLE eg_wms_attendance_register ALTER COLUMN registernumber TYPE character varying(256); +ALTER TABLE eg_wms_attendance_register ALTER COLUMN name TYPE character varying(256); + +ALTER TABLE eg_wms_attendance_attendee ALTER COLUMN individual_id TYPE character varying(256); +ALTER TABLE eg_wms_attendance_attendee ALTER COLUMN register_id TYPE character varying(256); +ALTER TABLE eg_wms_attendance_attendee ADD COLUMN attendee_type character varying(256); +ALTER TABLE eg_wms_attendance_attendee ADD COLUMN permission_type character varying(256); +ALTER TABLE eg_wms_attendance_attendee ADD COLUMN tenantid character varying(64); + +ALTER TABLE eg_wms_attendance_log ALTER COLUMN individual_id TYPE character varying(256); +ALTER TABLE eg_wms_attendance_log ALTER COLUMN register_id TYPE character varying(256); +ALTER TABLE eg_wms_attendance_log ADD COLUMN tenantid character varying(64); + +ALTER TABLE eg_wms_attendance_document ALTER COLUMN filestore_id TYPE character varying(256); +ALTER TABLE eg_wms_attendance_document ALTER COLUMN attendance_log_id TYPE character varying(256); +ALTER TABLE eg_wms_attendance_document ALTER COLUMN document_type TYPE character varying(256); +ALTER TABLE eg_wms_attendance_document ADD COLUMN tenantid character varying(64); + + +CREATE INDEX IF NOT EXISTS index_eg_wms_attendance_log_tenantId ON eg_wms_attendance_log (tenantId); +CREATE INDEX IF NOT EXISTS index_eg_wms_attendance_log_register_id ON eg_wms_attendance_log (register_id); +CREATE INDEX IF NOT EXISTS index_eg_wms_attendance_log_time ON eg_wms_attendance_log (time); +CREATE INDEX IF NOT EXISTS index_eg_wms_attendance_log_individual_id ON eg_wms_attendance_log (individual_id); +CREATE INDEX IF NOT EXISTS index_eg_wms_attendance_log_status ON eg_wms_attendance_log (status); +CREATE INDEX IF NOT EXISTS index_eg_wms_attendance_log_createdtime ON eg_wms_attendance_log (createdtime); + +CREATE INDEX IF NOT EXISTS index_eg_wms_attendance_register_tenantId ON eg_wms_attendance_register (tenantId); +CREATE INDEX IF NOT EXISTS index_eg_wms_attendance_register_id ON eg_wms_attendance_register (id); +CREATE INDEX IF NOT EXISTS index_eg_wms_attendance_register_registernumber ON eg_wms_attendance_register (registernumber); +CREATE INDEX IF NOT EXISTS index_eg_wms_attendance_register_name ON eg_wms_attendance_register (name); +CREATE INDEX IF NOT EXISTS index_eg_wms_attendance_register_startdate ON eg_wms_attendance_register (startdate); +CREATE INDEX IF NOT EXISTS index_eg_wms_attendance_register_enddate ON eg_wms_attendance_register (enddate); +CREATE INDEX IF NOT EXISTS index_eg_wms_attendance_register_status ON eg_wms_attendance_register (status); +CREATE INDEX IF NOT EXISTS index_eg_wms_attendance_register_createdtime ON eg_wms_attendance_register (createdtime); + +DROP TABLE IF EXISTS eg_wms_attendance_staff, eg_wms_staff_permissions CASCADE; \ No newline at end of file diff --git a/core-services/attendance/src/main/resources/db/migration/main/V20221130172200__create_attendance_staff_table.sql b/core-services/attendance/src/main/resources/db/migration/main/V20221130172200__create_attendance_staff_table.sql new file mode 100644 index 00000000000..736d2802323 --- /dev/null +++ b/core-services/attendance/src/main/resources/db/migration/main/V20221130172200__create_attendance_staff_table.sql @@ -0,0 +1,17 @@ +CREATE TABLE eg_wms_attendance_staff( +id character varying(256), +individual_id character varying(256) NOT NULL, +register_id character varying(256) NOT NULL, +tenantid character varying(64), +enrollment_date bigint NOT NULL, +deenrollment_date bigint, +additionaldetails JSONB, +createdby character varying(256) NOT NULL, +lastmodifiedby character varying(256), +createdtime bigint, +lastmodifiedtime bigint, +CONSTRAINT pk_eg_wms_attendance_staff PRIMARY KEY (id), +CONSTRAINT fk_eg_wms_attendance_staff FOREIGN KEY (register_id) REFERENCES eg_wms_attendance_register (id) +); + +ALTER TABLE eg_wms_attendance_attendee ALTER COLUMN deenrollment_date DROP NOT NULL; \ No newline at end of file diff --git a/core-services/attendance/src/main/resources/db/migration/main/V20221208175400__alter_attendance_attendee_table.sql b/core-services/attendance/src/main/resources/db/migration/main/V20221208175400__alter_attendance_attendee_table.sql new file mode 100644 index 00000000000..65e87f7e6dc --- /dev/null +++ b/core-services/attendance/src/main/resources/db/migration/main/V20221208175400__alter_attendance_attendee_table.sql @@ -0,0 +1,4 @@ +ALTER TABLE eg_wms_attendance_attendee DROP COLUMN attendee_type; +ALTER TABLE eg_wms_attendance_attendee DROP COLUMN permission_type; +ALTER TABLE eg_wms_attendance_document ADD COLUMN status character varying(64); +ALTER TABLE eg_wms_attendance_register ALTER COLUMN enddate DROP NOT NULL; \ No newline at end of file diff --git a/core-services/attendance/src/main/resources/db/migration/main/V20230404011400__alter_attendance_attendee_table.sql b/core-services/attendance/src/main/resources/db/migration/main/V20230404011400__alter_attendance_attendee_table.sql new file mode 100644 index 00000000000..34641634808 --- /dev/null +++ b/core-services/attendance/src/main/resources/db/migration/main/V20230404011400__alter_attendance_attendee_table.sql @@ -0,0 +1,4 @@ +ALTER TABLE eg_wms_attendance_register ADD COLUMN referenceid character varying(256); +ALTER TABLE eg_wms_attendance_register ADD COLUMN servicecode character varying(64); +CREATE INDEX IF NOT EXISTS index_eg_wms_attendance_register_reference_id ON eg_wms_attendance_register (referenceid); +CREATE INDEX IF NOT EXISTS index_eg_wms_attendance_register_service_code ON eg_wms_attendance_register (servicecode); \ No newline at end of file diff --git a/core-services/attendance/src/test/java/org/egov/TestConfiguration.java b/core-services/attendance/src/test/java/org/egov/TestConfiguration.java new file mode 100644 index 00000000000..d13056a19e6 --- /dev/null +++ b/core-services/attendance/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/core-services/attendance/src/test/java/org/egov/enrichment/AttendanceLogEnrichmentTest.java b/core-services/attendance/src/test/java/org/egov/enrichment/AttendanceLogEnrichmentTest.java new file mode 100644 index 00000000000..606b6913854 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/enrichment/AttendanceLogEnrichmentTest.java @@ -0,0 +1,43 @@ +package org.egov.enrichment; + +import digit.models.coremodels.AuditDetails; +import lombok.extern.slf4j.Slf4j; +import org.egov.helper.AttendanceLogRequestTestBuilder; +import org.egov.util.AttendanceServiceUtil; +import org.egov.web.models.AttendanceLogRequest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.lenient; + +@Slf4j +@ExtendWith(MockitoExtension.class) +public class AttendanceLogEnrichmentTest { + + @InjectMocks + private AttendanceLogEnrichment attendanceLogEnrichment; + + @Mock + private AttendanceServiceUtil attendanceServiceUtil; + + @DisplayName("Method validateAttendanceLogRequest: With good request") + @Test + public void enrichAttendanceLogCreateRequestTest_1(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addAttendanceLogWithoutIdAndAuditDetails().build(); + String byUser = attendanceLogRequest.getRequestInfo().getUserInfo().getUuid(); + Long time = System.currentTimeMillis(); + AuditDetails auditDetails = AuditDetails.builder().createdBy(byUser).lastModifiedBy(byUser).createdTime(time).lastModifiedTime(time).build(); + lenient().when(attendanceServiceUtil.getAuditDetails(any(String.class),eq(null),eq(true))).thenReturn(auditDetails); + attendanceLogEnrichment.enrichAttendanceLogCreateRequest(attendanceLogRequest); + assertNotNull(attendanceLogRequest.getAttendance().get(0).getId()); + assertNotNull(attendanceLogRequest.getAttendance().get(0).getAuditDetails()); + assertNotNull(attendanceLogRequest.getAttendance().get(0).getDocumentIds().get(0).getId()); + } +} diff --git a/core-services/attendance/src/test/java/org/egov/enrichment/AttendeeEnrichmentServiceTest.java b/core-services/attendance/src/test/java/org/egov/enrichment/AttendeeEnrichmentServiceTest.java new file mode 100644 index 00000000000..c8b4af9f365 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/enrichment/AttendeeEnrichmentServiceTest.java @@ -0,0 +1,39 @@ +package org.egov.enrichment; + +import lombok.extern.slf4j.Slf4j; +import org.egov.helper.AttendeeRequestBuilderTest; +import org.egov.util.AttendanceServiceUtil; +import org.egov.web.models.AttendeeCreateRequest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@Slf4j +@ExtendWith(MockitoExtension.class) +public class AttendeeEnrichmentServiceTest { + + @Mock + private AttendanceServiceUtil attendanceServiceUtil; + + + @InjectMocks + private AttendeeEnrichmentService attendeeEnrichmentService; + + + + @DisplayName("update enrollmentDate for attendee if enrollment date is null") + @Test + public void shouldEnrichEnrollmentDateWhenEnrollmentDateIsNull() { + AttendeeCreateRequest attendeeCreateRequest = AttendeeRequestBuilderTest.getAttendeeCreateRequest(); + + attendeeCreateRequest.getAttendees().get(0).setEnrollmentDate(null); + attendeeEnrichmentService.enrichAttendeeOnCreate(attendeeCreateRequest); + + assertNotNull(attendeeCreateRequest.getAttendees().get(0).getEnrollmentDate()); + } +} diff --git a/core-services/attendance/src/test/java/org/egov/enrichment/RegisterEnrichmentTest.java b/core-services/attendance/src/test/java/org/egov/enrichment/RegisterEnrichmentTest.java new file mode 100644 index 00000000000..a4a5740f7e7 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/enrichment/RegisterEnrichmentTest.java @@ -0,0 +1,95 @@ +package org.egov.enrichment; + +import digit.models.coremodels.IdGenerationResponse; +import digit.models.coremodels.IdResponse; +import lombok.extern.slf4j.Slf4j; +import org.egov.config.AttendanceServiceConfiguration; +import org.egov.helper.AttendanceRegisterRequestBuilderTest; +import org.egov.repository.IdGenRepository; +import org.egov.tracer.model.CustomException; +import org.egov.util.AttendanceServiceUtil; +import org.egov.util.IndividualServiceUtil; +import org.egov.web.models.AttendanceRegisterRequest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.ArrayList; +import java.util.List; + +import static junit.framework.TestCase.assertTrue; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.when; + +@Slf4j +@ExtendWith(MockitoExtension.class) +public class RegisterEnrichmentTest { + + @InjectMocks + private RegisterEnrichment registerEnrichment; + + @Mock + private AttendanceServiceConfiguration config; + + @Mock + private IdGenRepository idGenRepository; + + @Mock + private AttendanceServiceUtil attendanceServiceUtil; + @Mock + private IndividualServiceUtil individualServiceUtil; + + @BeforeEach + void setupBeforeEach() { + when(config.getIdgenAttendanceRegisterNumberName()).thenReturn("attendance.register.number"); + // when(config.getIdgenAttendanceRegisterNumberFormat()).thenReturn("WR/[fy:yyyy-yy]/[cy:MM]/[cy:dd]/[SEQ_ATTENDANCE_REGISTER_NUM]"); + } + + + @DisplayName("Method enrichCreateAttendanceRegister: With IDGEN ERROR code") + @Test + public void enrichCreateAttendanceRegisterTest_1(){ + AttendanceRegisterRequest attendanceRegisterRequest = AttendanceRegisterRequestBuilderTest.builder().withRequestInfo().addGoodRegister().build(); + + List idResponses = new ArrayList<>(); + IdGenerationResponse idGenerationResponse = IdGenerationResponse.builder().idResponses(idResponses).build(); + + lenient().when(idGenRepository.getId(eq(attendanceRegisterRequest.getRequestInfo()), eq("pb"), eq("attendance.register.number"), eq(""), eq(1))) + .thenReturn(idGenerationResponse); + + CustomException exception = assertThrows(CustomException.class,()->registerEnrichment.enrichRegisterOnCreate(attendanceRegisterRequest)); + assertTrue(exception.getCode().contentEquals("IDGEN ERROR")); + } + + +// @DisplayName("Method enrichCreateAttendanceRegister: With IDGEN ERROR code") +// @Test +// public void enrichCreateAttendanceRegisterTest_2(){ +// AttendanceRegisterRequest attendanceRegisterRequest = AttendanceRegisterRequestBuilderTest.builder().withRequestInfo().attendanceRegistersWithoutIdAuditDetailsAndNumber().build(); +// +// IdResponse idResponse = IdResponse.builder().id("WR/2022-23/01/05/01").build(); +// List idResponses = new ArrayList<>(); +// idResponses.add(idResponse); +// IdGenerationResponse idGenerationResponse = IdGenerationResponse.builder().idResponses(idResponses).build(); +// +// lenient().when(idGenRepository.getId(eq(attendanceRegisterRequest.getRequestInfo()), eq("pb"), eq("attendance.register.number"), eq(""), eq(1))) +// .thenReturn(idGenerationResponse); +// +// AuditDetails auditDetails = AuditDetailsTestBuilder.builder().withAuditDetails().build(); +// when(attendanceServiceUtil.getAuditDetails(attendanceRegisterRequest.getRequestInfo().getUserInfo().getUuid(),null,true)).thenReturn(auditDetails); +// Individual dummyIndividual = Individual.builder().individualId(UUID.randomUUID().toString()).build(); +// when(individualServiceUtil.getIndividualDetails(any(), any(), any())).thenReturn(Collections.singletonList(dummyIndividual)); +// +// registerEnrichment.enrichRegisterOnCreate(attendanceRegisterRequest); +// +// assertTrue(attendanceRegisterRequest.getAttendanceRegister().get(0).getId()!=null); +// +// } + +} diff --git a/core-services/attendance/src/test/java/org/egov/enrichment/StaffEnrichmentServiceTest.java b/core-services/attendance/src/test/java/org/egov/enrichment/StaffEnrichmentServiceTest.java new file mode 100644 index 00000000000..a327b2a45b8 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/enrichment/StaffEnrichmentServiceTest.java @@ -0,0 +1,36 @@ +package org.egov.enrichment; + +import lombok.extern.slf4j.Slf4j; +import org.egov.helper.StaffRequestBuilderTest; +import org.egov.util.AttendanceServiceUtil; +import org.egov.web.models.StaffPermissionRequest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +@Slf4j +@ExtendWith(MockitoExtension.class) +public class StaffEnrichmentServiceTest { + + @Mock + private AttendanceServiceUtil attendanceServiceUtil; + + @InjectMocks + private StaffEnrichmentService staffEnrichmentService; + + @DisplayName("update enrollmentDate for staff") + @Test + public void shouldEnrichEnrollmentDateWhenEnrollmentDateIsNull() { + StaffPermissionRequest staffPermissionRequest = StaffRequestBuilderTest.getStaffPermissionRequest(); + + staffPermissionRequest.getStaff().get(0).setEnrollmentDate(null); + staffEnrichmentService.enrichStaffPermissionOnCreate(staffPermissionRequest); + + assertNotNull(staffPermissionRequest.getStaff().get(0).getEnrollmentDate()); + } +} diff --git a/core-services/attendance/src/test/java/org/egov/helper/AdditionalFields.java b/core-services/attendance/src/test/java/org/egov/helper/AdditionalFields.java new file mode 100644 index 00000000000..b44d55cd0b1 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/helper/AdditionalFields.java @@ -0,0 +1,43 @@ +package org.egov.helper; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * AdditionalFields + */ + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AdditionalFields { + @JsonProperty("schema") + private String schema = null; + + @JsonProperty("version") + private Integer version = null; + + @JsonProperty("fields") + @Valid + private List fields = null; + + + public AdditionalFields addFieldsItem(Field fieldsItem) { + if (this.fields == null) { + this.fields = new ArrayList<>(); + } + this.fields.add(fieldsItem); + return this; + } + +} \ No newline at end of file diff --git a/core-services/attendance/src/test/java/org/egov/helper/AttendanceLogRequestTestBuilder.java b/core-services/attendance/src/test/java/org/egov/helper/AttendanceLogRequestTestBuilder.java new file mode 100644 index 00000000000..1e11a4ab2a6 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/helper/AttendanceLogRequestTestBuilder.java @@ -0,0 +1,98 @@ +package org.egov.helper; + +import org.egov.web.models.AttendanceLog; +import org.egov.web.models.AttendanceLogRequest; + +import java.util.ArrayList; + +public class AttendanceLogRequestTestBuilder { + + private AttendanceLogRequest.AttendanceLogRequestBuilder builder ; + + public AttendanceLogRequestTestBuilder(){ + this.builder = AttendanceLogRequest.builder(); + } + + public static AttendanceLogRequestTestBuilder builder(){ + return new AttendanceLogRequestTestBuilder(); + } + + public AttendanceLogRequest build(){ + return this.builder.build(); + } + + public AttendanceLogRequestTestBuilder withRequestInfo(){ + this.builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()); + return this; + } + + public AttendanceLogRequestTestBuilder withoutRequestInfo(){ + this.builder.requestInfo(null); + return this; + } + + public AttendanceLogRequestTestBuilder withRequestInfoButWithoutUserInfo(){ + this.builder.requestInfo(RequestInfoTestBuilder.builder().requestInfoWithoutUserInfo().build()); + return this; + } + + public AttendanceLogRequestTestBuilder withRequestInfoWithUserInfoButWithOutUUID(){ + this.builder.requestInfo(RequestInfoTestBuilder.builder().requestInfoWithUserInfoButWithOutUUID().build()); + return this; + } + + public AttendanceLogRequestTestBuilder addGoodAttendanceLog(){ + ArrayList logs = new ArrayList<>(); + logs.add(AttendanceLogTestBuilder.builder().addGoodAttendanceLog().build()); + this.builder.attendance(logs); + return this; + } + + public AttendanceLogRequestTestBuilder addAttendanceLogWithoutIdAndAuditDetails(){ + ArrayList logs = new ArrayList<>(); + logs.add(AttendanceLogTestBuilder.builder().addAttendanceLogWithoutIdAndAuditDetails().build()); + this.builder.attendance(logs); + return this; + } + + public AttendanceLogRequestTestBuilder withoutAttendanceLog(){ + this.builder.attendance(null); + return this; + } + + public AttendanceLogRequestTestBuilder attendanceLogWithoutTenantId(){ + ArrayList logs = new ArrayList<>(); + logs.add(AttendanceLogTestBuilder.builder().attendanceLogWithoutTenantId().build()); + this.builder.attendance(logs); + return this; + } + + + public AttendanceLogRequestTestBuilder attendanceLogWithoutIndividualId(){ + ArrayList logs = new ArrayList<>(); + logs.add(AttendanceLogTestBuilder.builder().attendanceLogWithoutIndividualId().build()); + this.builder.attendance(logs); + return this; + } + + public AttendanceLogRequestTestBuilder attendanceLogWithoutType(){ + ArrayList logs = new ArrayList<>(); + logs.add(AttendanceLogTestBuilder.builder().attendanceLogWithoutType().build()); + this.builder.attendance(logs); + return this; + } + + public AttendanceLogRequestTestBuilder attendanceLogWithoutTime(){ + ArrayList logs = new ArrayList<>(); + logs.add(AttendanceLogTestBuilder.builder().attendanceLogWithoutTime().build()); + this.builder.attendance(logs); + return this; + } + + public AttendanceLogRequestTestBuilder attendanceLogWithoutRegisterId() { + ArrayList logs = new ArrayList<>(); + logs.add(AttendanceLogTestBuilder.builder().attendanceLogWithoutRegisterId().build()); + this.builder.attendance(logs); + return this; + } +} diff --git a/core-services/attendance/src/test/java/org/egov/helper/AttendanceLogTestBuilder.java b/core-services/attendance/src/test/java/org/egov/helper/AttendanceLogTestBuilder.java new file mode 100644 index 00000000000..4f3b3100973 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/helper/AttendanceLogTestBuilder.java @@ -0,0 +1,123 @@ +package org.egov.helper; + +import org.egov.web.models.AttendanceLog; +import org.egov.web.models.Status; + +import java.math.BigDecimal; +import java.util.Collections; + +public class AttendanceLogTestBuilder { + private AttendanceLog.AttendanceLogBuilder builder ; + public AttendanceLogTestBuilder(){ + this.builder = AttendanceLog.builder(); + } + + public static AttendanceLogTestBuilder builder(){ + return new AttendanceLogTestBuilder(); + } + + public AttendanceLog build(){ + return this.builder.build(); + } + + public AttendanceLogTestBuilder addGoodAttendanceLog(){ + this.builder + .id("some-id") + .tenantId("some-tenantId") + .registerId("some-registerId") + .individualId("some-individualId") + .time(BigDecimal.valueOf(1672813896627L)) + .type("some-type") + .status(Status.ACTIVE) + .documentIds(Collections.singletonList(DocumentTestBuilder.builder().addGoodDocument().build())) + .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()) + ; + return this; + } + + public AttendanceLogTestBuilder addAttendanceLogWithoutIdAndAuditDetails(){ + this.builder + .tenantId("some-tenantId") + .registerId("some-registerId") + .individualId("some-individualId") + .time(BigDecimal.valueOf(1672813896627L)) + .type("some-type") + .status(Status.ACTIVE) + .documentIds(Collections.singletonList(DocumentTestBuilder.builder().addDocumentWithoutId().build())) + .auditDetails(null) + ; + return this; + } + + public AttendanceLogTestBuilder attendanceLogWithoutTenantId(){ + this.builder + .id("some-id") + .registerId("some-registerId") + .individualId("some-individualId") + .time(BigDecimal.valueOf(1L)) + .type("some-type") + .status(Status.ACTIVE) + .documentIds(Collections.singletonList(DocumentTestBuilder.builder().addGoodDocument().build())) + .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()) + ; + return this; + } + + public AttendanceLogTestBuilder attendanceLogWithoutRegisterId(){ + this.builder + .id("some-id") + .tenantId("some-tenantId") + .individualId("some-individualId") + .time(BigDecimal.valueOf(1L)) + .type("some-type") + .status(Status.ACTIVE) + .documentIds(Collections.singletonList(DocumentTestBuilder.builder().addGoodDocument().build())) + .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()) + ; + return this; + } + + public AttendanceLogTestBuilder attendanceLogWithoutIndividualId(){ + this.builder + .id("some-id") + .tenantId("some-tenantId") + .registerId("some-registerId") + .time(BigDecimal.valueOf(1L)) + .type("some-type") + .status(Status.ACTIVE) + .documentIds(Collections.singletonList(DocumentTestBuilder.builder().addGoodDocument().build())) + .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()) + ; + return this; + } + + public AttendanceLogTestBuilder attendanceLogWithoutType(){ + this.builder + .id("some-id") + .tenantId("some-tenantId") + .registerId("some-registerId") + .individualId("some-individualId") + .time(BigDecimal.valueOf(1L)) + .status(Status.ACTIVE) + .documentIds(Collections.singletonList(DocumentTestBuilder.builder().addGoodDocument().build())) + .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()) + ; + return this; + } + + public AttendanceLogTestBuilder attendanceLogWithoutTime(){ + this.builder + .id("some-id") + .tenantId("some-tenantId") + .registerId("some-registerId") + .individualId("some-individualId") + .type("some-type") + .status(Status.ACTIVE) + .documentIds(Collections.singletonList(DocumentTestBuilder.builder().addGoodDocument().build())) + .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()) + ; + return this; + } + + +} diff --git a/core-services/attendance/src/test/java/org/egov/helper/AttendanceRegisterBuilderTest.java b/core-services/attendance/src/test/java/org/egov/helper/AttendanceRegisterBuilderTest.java new file mode 100644 index 00000000000..5a45b759b80 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/helper/AttendanceRegisterBuilderTest.java @@ -0,0 +1,107 @@ +package org.egov.helper; + +import digit.models.coremodels.AuditDetails; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.request.Role; +import org.egov.common.contract.request.User; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.web.models.AttendanceRegister; +import org.egov.web.models.IndividualEntry; +import org.egov.web.models.StaffPermission; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Slf4j +public class AttendanceRegisterBuilderTest { + + public static AttendanceRegister getAttendanceRegister(){ + AttendanceRegister attendanceRegister=AttendanceRegister.builder().id("97ed7da3-753e-426a-b0b0-95dd61029785") + .registerNumber("RGN-67124").name("self help3").startDate(new BigDecimal("1673740800000")) + .endDate(new BigDecimal("1692057600000")).auditDetails(getAuditDetails()).attendees(getAttendees()) + .tenantId("pb.amritsar").staff(getStaff()).build(); + return attendanceRegister; + } + + public static AttendanceRegister getAttendanceRegisterWithoutEndDate(){ + AttendanceRegister attendanceRegister=AttendanceRegister.builder().id("97ed7da3-753e-426a-b0b0-95dd61029785") + .registerNumber("RGN-67124").name("self help3").startDate(new BigDecimal("1673740800000")) + .auditDetails(getAuditDetails()).attendees(getAttendees()) + .tenantId("pb.amritsar").staff(getStaff()).build(); + return attendanceRegister; + } + public static List getAttendees() { + IndividualEntry attendeeOne = IndividualEntry.builder().tenantId("pb.amritsar").id("047dc725-3088-45b4-877a-6bfbaf377df9") + .individualId("8ybdd-3rdh3").registerId("97ed7da3-753e-426a-b0b0-95dd61029785").enrollmentDate(new BigDecimal("1672129633890")) + .denrollmentDate(null).auditDetails(getAuditDetails()).build(); + + IndividualEntry attendeeTwo = IndividualEntry.builder().tenantId("pb.amritsar").id("11b88488-9a7a-48da-b110-dfdc077ef467") + .individualId("8ybdd-3rdha").registerId("97ed7da3-753e-426a-b0b0-95dd61029785").enrollmentDate(new BigDecimal("1671701038563")) + .denrollmentDate(null).auditDetails(getAuditDetails()).build(); + + List attendees=new ArrayList<>(Arrays.asList(attendeeOne,attendeeTwo)); + return attendees; + } + + public static List getStaff(){ + StaffPermission staffOne=StaffPermission.builder().id("03901adb-07c3-4539-9346-4ee5c87e5e1c").userId("8ybdd-3rdhd") + .registerId("97ed7da3-753e-426a-b0b0-95dd61029785").tenantId("pb.amritsar").enrollmentDate(new BigDecimal("1670421853937")) + .denrollmentDate(null).auditDetails(getAuditDetails()).build(); + + StaffPermission staffTwo=StaffPermission.builder().id("156d07fd-2c0c-4882-be03-6b68b98fb15e").userId("8ybdd-3rdhe") + .registerId("97ed7da3-753e-426a-b0b0-95dd61029785").tenantId("pb.amritsar").enrollmentDate(new BigDecimal("1670424209106")) + .denrollmentDate(null).auditDetails(getAuditDetails()).build(); + + List staffList=new ArrayList<>(Arrays.asList(staffOne,staffTwo)); + return staffList; + } + + + + public static AuditDetails getAuditDetails(){ + AuditDetails auditDetails=AuditDetails.builder().createdBy("11b0e02b-0145-4de2-bc42-c97b96264807") + .lastModifiedBy("11b0e02b-0145-4de2-bc42-c97b96264807").createdTime(Long.valueOf("1672129633890")) + .lastModifiedTime(Long.valueOf("1672129855564")).build(); + return auditDetails; + } + + public static List getAttendanceRegisterList(){ + + AttendanceRegister attendanceRegisterOne=AttendanceRegister.builder().id("54215cb7-c7f7-4521-8965-09647454a1f0") + .registerNumber("RGN-67124").name("self help3").startDate(new BigDecimal("1673740800000")) + .endDate(new BigDecimal("1692057600000")).tenantId("pb.amritsar").auditDetails(getAuditDetails()).build(); + + AttendanceRegister attendanceRegisterTwo=AttendanceRegister.builder().id("54215cb7-c7f7-4521-8965-09647454a1f1") + .registerNumber("RGN-67124").name("self help3").startDate(new BigDecimal("1673740800000")) + .endDate(new BigDecimal("1692057600000")).auditDetails(getAuditDetails()).tenantId("pb.amritsar").build(); + + AttendanceRegister attendanceRegisterThree=AttendanceRegister.builder().id("54215cb7-c7f7-4521-8965-09647454a1f2") + .registerNumber("RGN-67124").name("self help3").startDate(new BigDecimal("1673740800000")) + .endDate(new BigDecimal("1692057600000")).auditDetails(getAuditDetails()).tenantId("pb.amritsar").build(); + + List attendanceRegisterList=new ArrayList<>(Arrays.asList(attendanceRegisterOne,attendanceRegisterTwo,attendanceRegisterThree)); + + return attendanceRegisterList; + + + } + + public static RequestInfo getRequestInfo(){ + Role role = new Role(1L,"Organization staff","ORG_STAFF","pb.amritsar"); + List roles = new ArrayList<>(); + roles.add(role); + User userInfo = User.builder().id(172L).uuid("5ce80dd3-b1c0-42fd-b8f6-a2be456db31c").userName("8070102021").name("test3").mobileNumber("8070102021") + .emailId("xyz@egovernments.org").type("EMPLOYEE").roles(roles).build(); + RequestInfo requestInfo = RequestInfo.builder().apiId("attendance-services").msgId("search with from and to values").userInfo(userInfo).build(); + return requestInfo; + } + + public static ResponseInfo getResponseInfo_Success() { + ResponseInfo responseInfo = ResponseInfo.builder().apiId("attendance-services").ver(null).ts(null).resMsgId(null).msgId("search with from and to values") + .status("successful").build(); + return responseInfo; + } +} diff --git a/core-services/attendance/src/test/java/org/egov/helper/AttendanceRegisterRequestBuilderTest.java b/core-services/attendance/src/test/java/org/egov/helper/AttendanceRegisterRequestBuilderTest.java new file mode 100644 index 00000000000..e85e94bf423 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/helper/AttendanceRegisterRequestBuilderTest.java @@ -0,0 +1,181 @@ +package org.egov.helper; + +import org.egov.web.models.AttendanceRegister; +import org.egov.web.models.AttendanceRegisterRequest; +import org.egov.web.models.IndividualEntry; +import org.egov.web.models.StaffPermission; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; + +public class AttendanceRegisterRequestBuilderTest { + + private AttendanceRegisterRequest.AttendanceRegisterRequestBuilder builder ; + + public AttendanceRegisterRequestBuilderTest(){ + this.builder = AttendanceRegisterRequest.builder(); + } + + public static AttendanceRegisterRequestBuilderTest builder(){ + return new AttendanceRegisterRequestBuilderTest(); + } + + public AttendanceRegisterRequest build(){ + return this.builder.build(); + } + + public AttendanceRegisterRequestBuilderTest withRequestInfo(){ + this.builder.requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()); + return this; + } + + public AttendanceRegisterRequestBuilderTest requestInfoWithoutUserInfo(){ + this.builder.requestInfo(RequestInfoTestBuilder.builder().requestInfoWithoutUserInfo().build()); + return this; + } + + public AttendanceRegisterRequestBuilderTest requestInfoWithUserInfoButWithOutUUID(){ + this.builder.requestInfo(RequestInfoTestBuilder.builder().requestInfoWithUserInfoButWithOutUUID().build()); + return this; + } + + public AttendanceRegisterRequestBuilderTest addGoodRegister(){ + ArrayList registers = new ArrayList<>(); + AttendanceRegister attendanceRegister=AttendanceRegister.builder() + .id("97ed7da3-753e-426a-b0b0-95dd61029785") + .registerNumber("RGN-67124") + .tenantId("pb.amritsar") + .name("self help3") + .startDate(new BigDecimal("1673740800000")) + .endDate(new BigDecimal("1692057600000")) + .serviceCode("serviceCode") + .referenceId("referenceId") + .auditDetails(AuditDetailsTestBuilder.builder().build()) + .attendees(Collections.singletonList(IndividualEntry.builder().build())) + .staff(Collections.singletonList(StaffPermission.builder().build())) + .build(); + registers.add(attendanceRegister); + this.builder.attendanceRegister(registers); + return this; + } + + + public AttendanceRegisterRequestBuilderTest attendanceRegistersWithoutIdAuditDetailsAndNumber(){ + ArrayList registers = new ArrayList<>(); + AttendanceRegister attendanceRegister=AttendanceRegister.builder() + .tenantId("pb.amritsar") + .name("self help3") + .startDate(new BigDecimal("1673740800000")) + .endDate(new BigDecimal("1692057600000")) + .auditDetails(null) + .attendees(Collections.singletonList(IndividualEntry.builder().build())) + .staff(Collections.singletonList(StaffPermission.builder().build())) + .build(); + registers.add(attendanceRegister); + this.builder.attendanceRegister(registers); + return this; + } + + public AttendanceRegisterRequestBuilderTest attendanceRegistersWithMultipleTenantIds(){ + ArrayList registers = new ArrayList<>(); + AttendanceRegister attendanceRegister1=AttendanceRegister.builder() + .id("97ed7da3-753e-426a-b0b0-95dd61029785") + .registerNumber("RGN-67124") + .tenantId("pb.amritsar") + .name("self help3") + .startDate(new BigDecimal("1673740800000")) + .endDate(new BigDecimal("1692057600000")) + .auditDetails(AuditDetailsTestBuilder.builder().build()) + .attendees(Collections.singletonList(IndividualEntry.builder().build())) + .staff(Collections.singletonList(StaffPermission.builder().build())) + .build(); + + AttendanceRegister attendanceRegister2=AttendanceRegister.builder() + .id("97ed7da3-753e-426a-b0b0-95dd61029785") + .registerNumber("RGN-67124") + .tenantId("pb.jalandhar") + .name("self help3") + .startDate(new BigDecimal("1673740800000")) + .endDate(new BigDecimal("1692057600000")) + .auditDetails(AuditDetailsTestBuilder.builder().build()) + .attendees(Collections.singletonList(IndividualEntry.builder().build())) + .staff(Collections.singletonList(StaffPermission.builder().build())) + .build(); + + registers.add(attendanceRegister1); + registers.add(attendanceRegister2); + this.builder.attendanceRegister(registers); + return this; + } + + public AttendanceRegisterRequestBuilderTest attendanceRegisterWithoutTenantId(){ + ArrayList registers = new ArrayList<>(); + AttendanceRegister attendanceRegister=AttendanceRegister.builder() + .id("97ed7da3-753e-426a-b0b0-95dd61029785") + .registerNumber("RGN-67124") + .name("self help3") + .startDate(new BigDecimal("1673740800000")) + .endDate(new BigDecimal("1692057600000")) + .auditDetails(AuditDetailsTestBuilder.builder().build()) + .attendees(Collections.singletonList(IndividualEntry.builder().build())) + .staff(Collections.singletonList(StaffPermission.builder().build())) + .build(); + registers.add(attendanceRegister); + this.builder.attendanceRegister(registers); + return this; + } + + public AttendanceRegisterRequestBuilderTest attendanceRegisterWithoutName(){ + ArrayList registers = new ArrayList<>(); + AttendanceRegister attendanceRegister=AttendanceRegister.builder() + .id("97ed7da3-753e-426a-b0b0-95dd61029785") + .registerNumber("RGN-67124") + .tenantId("tenant.id") + .startDate(new BigDecimal("1673740800000")) + .endDate(new BigDecimal("1692057600000")) + .auditDetails(AuditDetailsTestBuilder.builder().build()) + .attendees(Collections.singletonList(IndividualEntry.builder().build())) + .staff(Collections.singletonList(StaffPermission.builder().build())) + .build(); + registers.add(attendanceRegister); + this.builder.attendanceRegister(registers); + return this; + } + + public AttendanceRegisterRequestBuilderTest attendanceRegisterWithoutStartDate(){ + ArrayList registers = new ArrayList<>(); + AttendanceRegister attendanceRegister=AttendanceRegister.builder() + .id("97ed7da3-753e-426a-b0b0-95dd61029785") + .registerNumber("RGN-67124") + .name("some-name") + .tenantId("tenant.id") + .endDate(new BigDecimal("1692057600000")) + .auditDetails(AuditDetailsTestBuilder.builder().build()) + .attendees(Collections.singletonList(IndividualEntry.builder().build())) + .staff(Collections.singletonList(StaffPermission.builder().build())) + .build(); + registers.add(attendanceRegister); + this.builder.attendanceRegister(registers); + return this; + } + + public AttendanceRegisterRequestBuilderTest attendanceRegisterWithStartDateGTEndDate(){ + ArrayList registers = new ArrayList<>(); + AttendanceRegister attendanceRegister=AttendanceRegister.builder() + .id("97ed7da3-753e-426a-b0b0-95dd61029785") + .registerNumber("RGN-67124") + .name("some-name") + .tenantId("tenant.id") + .startDate(new BigDecimal("1692057600000")) + .endDate(new BigDecimal("1673740800000")) + .auditDetails(AuditDetailsTestBuilder.builder().build()) + .attendees(Collections.singletonList(IndividualEntry.builder().build())) + .staff(Collections.singletonList(StaffPermission.builder().build())) + .build(); + registers.add(attendanceRegister); + this.builder.attendanceRegister(registers); + return this; + } + +} diff --git a/core-services/attendance/src/test/java/org/egov/helper/AttendeeRequestBuilderTest.java b/core-services/attendance/src/test/java/org/egov/helper/AttendeeRequestBuilderTest.java new file mode 100644 index 00000000000..ee49a09103f --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/helper/AttendeeRequestBuilderTest.java @@ -0,0 +1,97 @@ +package org.egov.helper; + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.request.Role; +import org.egov.common.contract.request.User; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.web.models.AttendeeCreateRequest; +import org.egov.web.models.IndividualEntry; + +import java.io.File; +import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Slf4j +public class AttendeeRequestBuilderTest { + + public static AttendeeCreateRequest getAttendeeCreateRequest(){ + AttendeeCreateRequest attendeeCreateRequest=AttendeeCreateRequest.builder().requestInfo(getRequestInfo()) + .attendees(getAttendees()).build(); + return attendeeCreateRequest; + } + + public static List getAttendees(){ + IndividualEntry attendeeOne=IndividualEntry.builder().tenantId("pb.amritsar").id("047dc725-3088-45b4-877a-6bfbaf377df9") + .individualId("8ybdd-3rdh3").registerId("97ed7da3-753e-426a-b0b0-95dd61029785").enrollmentDate(new BigDecimal("1676101018000")) + .denrollmentDate(new BigDecimal("1676073600000")).auditDetails(getAuditDetails()).build(); + + IndividualEntry attendeeTwo=IndividualEntry.builder().tenantId("pb.amritsar").id("11b88488-9a7a-48da-b110-dfdc077ef467") + .individualId("8ybdd-3rdha").registerId("97ed7da3-753e-426a-b0b0-95dd61029785").enrollmentDate(new BigDecimal("1676101018000")) + .denrollmentDate(new BigDecimal("1671707969802")).auditDetails(getAuditDetails()).build(); + + + + List attendeeList=new ArrayList<>(Arrays.asList(attendeeOne,attendeeTwo)); + return attendeeList; + } + + public static AuditDetails getAuditDetails(){ + AuditDetails auditDetails=AuditDetails.builder().createdBy("11b0e02b-0145-4de2-bc42-c97b96264807") + .lastModifiedBy("11b0e02b-0145-4de2-bc42-c97b96264807").createdTime(Long.valueOf("1672129633890")) + .lastModifiedTime(Long.valueOf("1672129855564")).build(); + return auditDetails; + } + + public static RequestInfo getRequestInfo(){ + Role role = new Role(1L,"Organization staff","ORG_STAFF","pb.amritsar"); + List roles = new ArrayList<>(); + roles.add(role); + User userInfo = User.builder().id(172L).uuid("5ce80dd3-b1c0-42fd-b8f6-a2be456db31c").userName("8070102021").name("test3").mobileNumber("8070102021") + .emailId("xyz@egovernments.org").type("EMPLOYEE").roles(roles).build(); + RequestInfo requestInfo = RequestInfo.builder().apiId("attendance-services").msgId("search with from and to values").userInfo(userInfo).build(); + return requestInfo; + } + + public static Object getMdmsResponseForValidTenant() { + + Object mdmsResponse = null; + + try { + ObjectMapper objectMapper = new ObjectMapper(); + File file = new File("src/test/resources/TenantMDMSData.json"); + String exampleRequest = FileUtils.readFileToString(file, StandardCharsets.UTF_8); + mdmsResponse = objectMapper.readValue(exampleRequest, Object.class); + } catch (Exception exception) { + log.error("AttendeeRequestBuilderTest::getMdmsResponse::Exception while parsing mdms json"); + } + return mdmsResponse; + } + + public static Object getMdmsResponseForInvalidTenant() { + + Object mdmsResponse = null; + + try { + ObjectMapper objectMapper = new ObjectMapper(); + File file = new File("src/test/resources/InvalidTenantMDMSData.json"); + String exampleRequest = FileUtils.readFileToString(file, StandardCharsets.UTF_8); + mdmsResponse = objectMapper.readValue(exampleRequest, Object.class); + } catch (Exception exception) { + log.error("AttendeeRequestBuilderTest::getMdmsResponse::Exception while parsing mdms json"); + } + return mdmsResponse; + } + + public static ResponseInfo getResponseInfo_Success() { + ResponseInfo responseInfo = ResponseInfo.builder().apiId("attendance-services").ver(null).ts(null).resMsgId(null).msgId("search with from and to values") + .status("successful").build(); + return responseInfo; + } +} diff --git a/core-services/attendance/src/test/java/org/egov/helper/AuditDetailsTestBuilder.java b/core-services/attendance/src/test/java/org/egov/helper/AuditDetailsTestBuilder.java new file mode 100644 index 00000000000..2dd9a6fa044 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/helper/AuditDetailsTestBuilder.java @@ -0,0 +1,27 @@ +package org.egov.helper; + +import digit.models.coremodels.AuditDetails; + +public class AuditDetailsTestBuilder { + private AuditDetails.AuditDetailsBuilder builder; + + public AuditDetailsTestBuilder() { + this.builder = AuditDetails.builder(); + } + + public static AuditDetailsTestBuilder builder() { + return new AuditDetailsTestBuilder(); + } + + public AuditDetails build() { + return this.builder.build(); + } + + public AuditDetailsTestBuilder withAuditDetails() { + this.builder.createdTime(System.currentTimeMillis()) + .createdBy("some-uuid") + .lastModifiedTime(System.currentTimeMillis()) + .lastModifiedBy("some-uuid"); + return this; + } +} \ No newline at end of file diff --git a/core-services/attendance/src/test/java/org/egov/helper/DocumentTestBuilder.java b/core-services/attendance/src/test/java/org/egov/helper/DocumentTestBuilder.java new file mode 100644 index 00000000000..ef1a0872e51 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/helper/DocumentTestBuilder.java @@ -0,0 +1,45 @@ +package org.egov.helper; + + +import org.egov.web.models.Document; +import org.egov.web.models.Status; + +public class DocumentTestBuilder { + private Document.DocumentBuilder builder; + + public DocumentTestBuilder(){ + this.builder = Document.builder(); + } + + public Document build(){ + return this.builder.build(); + } + + public static DocumentTestBuilder builder(){ + return new DocumentTestBuilder(); + } + + public DocumentTestBuilder addGoodDocument(){ + this.builder + .id("Id-1") + .fileStore("FileStore-1") + .documentUid("DocumentUid-1") + .additionalDetails(new Object()) + .status(Status.fromValue("ACTIVE")) + .additionalDetails(AdditionalFields.builder().build()); + + return this; + } + + public DocumentTestBuilder addDocumentWithoutId(){ + this.builder + .fileStore("FileStore-1") + .documentUid("DocumentUid-1") + .additionalDetails(new Object()) + .status(Status.fromValue("ACTIVE")) + .additionalDetails(AdditionalFields.builder().build()); + + return this; + } + +} diff --git a/core-services/attendance/src/test/java/org/egov/helper/Field.java b/core-services/attendance/src/test/java/org/egov/helper/Field.java new file mode 100644 index 00000000000..f23ea8cea75 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/helper/Field.java @@ -0,0 +1,28 @@ +package org.egov.helper; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +/** + * Field + */ + + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Field { + @JsonProperty("key") + private String key = null; + + @JsonProperty("value") + private String value = null; + + +} \ No newline at end of file diff --git a/core-services/attendance/src/test/java/org/egov/helper/IndividualEntryBuilderTest.java b/core-services/attendance/src/test/java/org/egov/helper/IndividualEntryBuilderTest.java new file mode 100644 index 00000000000..484f9d5f7a3 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/helper/IndividualEntryBuilderTest.java @@ -0,0 +1,34 @@ +package org.egov.helper; + + + +import org.egov.web.models.IndividualEntry; + +import java.math.BigDecimal; + +public class IndividualEntryBuilderTest { + private IndividualEntry.IndividualEntryBuilder builder; + public IndividualEntryBuilderTest() { + this.builder = IndividualEntry.builder(); + } + + public static StaffPermissionBuilderTest builder() { + return new StaffPermissionBuilderTest(); + } + + public IndividualEntry build() { + return this.builder.build(); + } + + public void addGoodStaffPermission(){ + this.builder.id("some_id") + .tenantId("some_tenantId") + .registerId("some_registerId") + .individualId("some_individualId") + .enrollmentDate(BigDecimal.valueOf(1640995200000L)) + .denrollmentDate(BigDecimal.valueOf(1703980800000L)) + .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()) + .additionalDetails(AdditionalFields.builder().build()); + } + +} diff --git a/core-services/attendance/src/test/java/org/egov/helper/RequestInfoTestBuilder.java b/core-services/attendance/src/test/java/org/egov/helper/RequestInfoTestBuilder.java new file mode 100644 index 00000000000..a4173a112b3 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/helper/RequestInfoTestBuilder.java @@ -0,0 +1,62 @@ +package org.egov.helper; + +import org.egov.common.contract.request.RequestInfo; + + +public class RequestInfoTestBuilder { + private RequestInfo.RequestInfoBuilder builder; + + public RequestInfoTestBuilder() { + this.builder = RequestInfo.builder(); + } + + public static RequestInfoTestBuilder builder() { + return new RequestInfoTestBuilder(); + } + + public RequestInfo build() { + return this.builder.build(); + } + + public RequestInfoTestBuilder withCompleteRequestInfo() { + this.builder.userInfo(UserTestBuilder.builder().withCompleteUserInfo().build()) + .action("create") + .apiId("some-api-id") + .authToken("some-auth-token") + .did("some-did") + .correlationId("some-correlation-id") + .key("some-key") + .msgId("some-msg-id") + .ts(System.currentTimeMillis()) + .ver("1"); + return this; + } + + public RequestInfoTestBuilder requestInfoWithUserInfoButWithOutUUID() { + this.builder.userInfo(UserTestBuilder.builder().userInfoWithOutUUID().build()) + .action("create") + .apiId("some-api-id") + .authToken("some-auth-token") + .did("some-did") + .correlationId("some-correlation-id") + .key("some-key") + .msgId("some-msg-id") + .ts(System.currentTimeMillis()) + .ver("1"); + return this; + } + + public RequestInfoTestBuilder requestInfoWithoutUserInfo() { + this.builder.userInfo(null) + .action("create") + .apiId("some-api-id") + .authToken("some-auth-token") + .did("some-did") + .correlationId("some-correlation-id") + .key("some-key") + .msgId("some-msg-id") + .ts(System.currentTimeMillis()) + .ver("1"); + return this; + } +} \ No newline at end of file diff --git a/core-services/attendance/src/test/java/org/egov/helper/StaffPermissionBuilderTest.java b/core-services/attendance/src/test/java/org/egov/helper/StaffPermissionBuilderTest.java new file mode 100644 index 00000000000..3d784d5235b --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/helper/StaffPermissionBuilderTest.java @@ -0,0 +1,33 @@ +package org.egov.helper; + +import org.egov.web.models.StaffPermission; + +import java.math.BigDecimal; + +public class StaffPermissionBuilderTest { + + private StaffPermission.StaffPermissionBuilder builder; + public StaffPermissionBuilderTest() { + this.builder = StaffPermission.builder(); + } + + public static StaffPermissionBuilderTest builder() { + return new StaffPermissionBuilderTest(); + } + + public StaffPermission build() { + return this.builder.build(); + } + + public void addGoodStaffPermission(){ + this.builder.id("some_id") + .tenantId("some_tenantId") + .registerId("some_registerId") + .userId("some_userId") + .enrollmentDate(BigDecimal.valueOf(1640995200000L)) + .denrollmentDate(BigDecimal.valueOf(1703980800000L)) + .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()) + .additionalDetails(AdditionalFields.builder().build()); + } + +} diff --git a/core-services/attendance/src/test/java/org/egov/helper/StaffRequestBuilderTest.java b/core-services/attendance/src/test/java/org/egov/helper/StaffRequestBuilderTest.java new file mode 100644 index 00000000000..d0ab6f0b901 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/helper/StaffRequestBuilderTest.java @@ -0,0 +1,97 @@ +package org.egov.helper; + +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.request.Role; +import org.egov.common.contract.request.User; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.web.models.StaffPermission; +import org.egov.web.models.StaffPermissionRequest; + +import java.io.File; +import java.math.BigDecimal; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Slf4j +public class StaffRequestBuilderTest { + + public static StaffPermissionRequest getStaffPermissionRequest() { + StaffPermissionRequest staffPermissionRequest = StaffPermissionRequest.builder().requestInfo(getRequestInfo()) + .staff(getStaff()).build(); + return staffPermissionRequest; + } + + + public static List getStaff() { + StaffPermission staffOne = StaffPermission.builder().id("03901adb-07c3-4539-9346-4ee5c87e5e1c").userId("8ybdd-3rdhd") + .registerId("97ed7da3-753e-426a-b0b0-95dd61029785").tenantId("pb.amritsar").enrollmentDate(new BigDecimal("1670421853937")) + .denrollmentDate(null).auditDetails(getAuditDetails()).build(); + + StaffPermission staffTwo = StaffPermission.builder().id("156d07fd-2c0c-4882-be03-6b68b98fb15e").userId("8ybdd-3rdhe") + .registerId("97ed7da3-753e-426a-b0b0-95dd61029785").tenantId("pb.amritsar").enrollmentDate(new BigDecimal("1670424209106")) + .denrollmentDate(null).auditDetails(getAuditDetails()).build(); + + List staffList = new ArrayList<>(Arrays.asList(staffOne, staffTwo)); + return staffList; + } + + + public static AuditDetails getAuditDetails() { + AuditDetails auditDetails = AuditDetails.builder().createdBy("11b0e02b-0145-4de2-bc42-c97b96264807") + .lastModifiedBy("11b0e02b-0145-4de2-bc42-c97b96264807").createdTime(Long.valueOf("1672129633890")) + .lastModifiedTime(Long.valueOf("1672129855564")).build(); + return auditDetails; + } + + public static RequestInfo getRequestInfo() { + Role role = new Role(1L, "Organization staff", "ORG_STAFF", "pb.amritsar"); + List roles = new ArrayList<>(); + roles.add(role); + User userInfo = User.builder().id(172L).uuid("5ce80dd3-b1c0-42fd-b8f6-a2be456db31c").userName("8070102021").name("test3").mobileNumber("8070102021") + .emailId("xyz@egovernments.org").type("EMPLOYEE").roles(roles).build(); + RequestInfo requestInfo = RequestInfo.builder().apiId("attendance-services").msgId("search with from and to values").userInfo(userInfo).build(); + return requestInfo; + } + + public static Object getMdmsResponseForValidTenant() { + + Object mdmsResponse = null; + + try { + ObjectMapper objectMapper = new ObjectMapper(); + File file = new File("src/test/resources/TenantMDMSData.json"); + String exampleRequest = FileUtils.readFileToString(file, StandardCharsets.UTF_8); + mdmsResponse = objectMapper.readValue(exampleRequest, Object.class); + } catch (Exception exception) { + log.error("AttendeeRequestBuilderTest::getMdmsResponse::Exception while parsing mdms json"); + } + return mdmsResponse; + } + + public static Object getMdmsResponseForInvalidTenant() { + + Object mdmsResponse = null; + + try { + ObjectMapper objectMapper = new ObjectMapper(); + File file = new File("src/test/resources/InvalidTenantMDMSData.json"); + String exampleRequest = FileUtils.readFileToString(file, StandardCharsets.UTF_8); + mdmsResponse = objectMapper.readValue(exampleRequest, Object.class); + } catch (Exception exception) { + log.error("AttendeeRequestBuilderTest::getMdmsResponse::Exception while parsing mdms json"); + } + return mdmsResponse; + } + + public static ResponseInfo getResponseInfo_Success() { + ResponseInfo responseInfo = ResponseInfo.builder().apiId("attendance-services").ver(null).ts(null).resMsgId(null).msgId("search with from and to values") + .status("successful").build(); + return responseInfo; + } +} diff --git a/core-services/attendance/src/test/java/org/egov/helper/UserTestBuilder.java b/core-services/attendance/src/test/java/org/egov/helper/UserTestBuilder.java new file mode 100644 index 00000000000..2aca7685ecc --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/helper/UserTestBuilder.java @@ -0,0 +1,58 @@ +package org.egov.helper; + +import org.egov.common.contract.request.Role; +import org.egov.common.contract.request.User; + +import java.util.ArrayList; +import java.util.List; + +public class UserTestBuilder { + private User.UserBuilder builder; + + public UserTestBuilder() { + this.builder = User.builder(); + } + + public static UserTestBuilder builder() { + return new UserTestBuilder(); + } + + public User build() { + return this.builder.build(); + } + + public UserTestBuilder withCompleteUserInfo() { + Role role = Role.builder() + .id(123L) + .name("System Administrator") + .build(); + List roles = new ArrayList<>(); + roles.add(role); + this.builder.userName("some-username") + .roles(roles) + .id(123L) + .name("some-name") + .type("EMPLOYEE") + .emailId("some-email-id") + .mobileNumber("9893212345") + .uuid("some-uuid"); + return this; + } + + public UserTestBuilder userInfoWithOutUUID() { + Role role = Role.builder() + .id(123L) + .name("System Administrator") + .build(); + List roles = new ArrayList<>(); + roles.add(role); + this.builder.userName("some-username") + .roles(roles) + .id(123L) + .name("some-name") + .type("EMPLOYEE") + .emailId("some-email-id") + .mobileNumber("9893212345"); + return this; + } +} \ No newline at end of file diff --git a/core-services/attendance/src/test/java/org/egov/service/AttendanceLogServiceTest.java b/core-services/attendance/src/test/java/org/egov/service/AttendanceLogServiceTest.java new file mode 100644 index 00000000000..ef3743f700a --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/service/AttendanceLogServiceTest.java @@ -0,0 +1,66 @@ +package org.egov.service; + +import lombok.extern.slf4j.Slf4j; +import org.egov.config.AttendanceServiceConfiguration; +import org.egov.enrichment.AttendanceLogEnrichment; +import org.egov.helper.AttendanceLogRequestTestBuilder; +import org.egov.kafka.Producer; +import org.egov.util.ResponseInfoFactory; +import org.egov.validator.AttendanceLogServiceValidator; +import org.egov.web.models.AttendanceLogRequest; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.hibernate.validator.internal.util.Contracts.assertNotNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@Slf4j +@ExtendWith(MockitoExtension.class) +public class AttendanceLogServiceTest { + + @InjectMocks + private AttendanceLogService attendanceLogService; + + @Mock + private AttendanceLogServiceValidator attendanceLogServiceValidator; + + + @Mock + private ResponseInfoFactory responseInfoFactory; + + + @Mock + private AttendanceLogEnrichment attendanceLogEnricher; + + @Mock + private Producer producer; + + @Mock + private AttendanceServiceConfiguration config; + + + @DisplayName("create attendance log successfully") + @Test + public void createAttendanceLogTest_1(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); + when(config.getCreateAttendanceLogTopic()).thenReturn("save-attendance-log"); + + attendanceLogService.createAttendanceLog(attendanceLogRequest); + + verify(attendanceLogServiceValidator, times(1)).validateCreateAttendanceLogRequest(attendanceLogRequest); + + verify(attendanceLogEnricher, times(1)).enrichAttendanceLogCreateRequest(attendanceLogRequest); + + verify(producer, times(1)).push(eq("save-attendance-log"), any(AttendanceLogRequest.class)); + + assertNotNull(attendanceLogRequest.getAttendance()); + } +} diff --git a/core-services/attendance/src/test/java/org/egov/validator/AttendanceLogServiceValidatorTest.java b/core-services/attendance/src/test/java/org/egov/validator/AttendanceLogServiceValidatorTest.java new file mode 100644 index 00000000000..e723bb14f86 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/validator/AttendanceLogServiceValidatorTest.java @@ -0,0 +1,458 @@ +package org.egov.validator; + +import lombok.extern.slf4j.Slf4j; +import org.egov.config.AttendanceServiceConfiguration; +import org.egov.helper.AttendanceLogRequestTestBuilder; +import org.egov.helper.AttendanceRegisterBuilderTest; +import org.egov.repository.AttendeeRepository; +import org.egov.repository.RegisterRepository; +import org.egov.repository.StaffRepository; +import org.egov.tracer.model.CustomException; +import org.egov.web.models.AttendanceLog; +import org.egov.web.models.AttendanceLogRequest; +import org.egov.web.models.AttendanceRegister; +import org.egov.web.models.AttendeeSearchCriteria; +import org.egov.web.models.IndividualEntry; +import org.egov.web.models.Status; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.util.ReflectionTestUtils; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +@Slf4j +@ExtendWith(MockitoExtension.class) +public class AttendanceLogServiceValidatorTest { + + @InjectMocks + private AttendanceLogServiceValidator attendanceLogServiceValidator; + + @Mock + private AttendanceServiceConfiguration config; + + @Mock + private StaffRepository attendanceStaffRepository; + + @Mock + private RegisterRepository attendanceRegisterRepository; + + @Mock + private AttendeeRepository attendanceAttendeeRepository; + + @DisplayName("Method validateAttendanceLogRequest: With good request") + @Test + public void validateCreateAttendanceLogRequest_validateAttendanceLogRequest_1(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); + assertDoesNotThrow(()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendanceLogRequest", attendanceLogRequest)); + } + + @DisplayName("Method validateAttendanceLogRequest: With null RequestInfo object") + @Test + public void validateCreateAttendanceLogRequest_validateAttendanceLogRequest_2(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withoutRequestInfo().addGoodAttendanceLog().build(); + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendanceLogRequest", attendanceLogRequest)); + assertTrue(exception.getCode().equals("REQUEST_INFO")); + } + + @DisplayName("Method validateAttendanceLogRequest: RequestInfo object with null UserInfo") + @Test + public void validateCreateAttendanceLogRequest_validateAttendanceLogRequest_3(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfoButWithoutUserInfo().addGoodAttendanceLog().build(); + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendanceLogRequest", attendanceLogRequest)); + assertTrue(exception.getCode().equals("USERINFO")); + } + + @DisplayName("Method validateAttendanceLogRequest: RequestInfo object with UserInfo but without UUID") + @Test + public void validateCreateAttendanceLogRequest_validateAttendanceLogRequest_4(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfoWithUserInfoButWithOutUUID().addGoodAttendanceLog().build(); + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendanceLogRequest", attendanceLogRequest)); + assertTrue(exception.getCode().equals("USERINFO_UUID")); + } + + @DisplayName("Method validateAttendanceLogRequest: RequestInfo object with UserInfo but without UUID") + @Test + public void validateCreateAttendanceLogRequest_validateAttendanceLogRequest_5(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfoWithUserInfoButWithOutUUID().addGoodAttendanceLog().build(); + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendanceLogRequest", attendanceLogRequest)); + assertTrue(exception.getCode().equals("USERINFO_UUID")); + } + + @DisplayName("Method validateAttendanceLogRequest: RequestInfo object with UserInfo but without Attendance Log list") + @Test + public void validateCreateAttendanceLogRequest_validateAttendanceLogRequest_6(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().withoutAttendanceLog().build(); + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendanceLogRequest", attendanceLogRequest)); + assertTrue(exception.getCode().equals("ATTENDANCE")); + } + + @DisplayName("Method validateAttendanceLogRequest: RequestInfo object with UserInfo but without Attendance Log TenantId") + @Test + public void validateCreateAttendanceLogRequest_validateAttendanceLogRequest_7(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().attendanceLogWithoutTenantId().build(); + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendanceLogRequest", attendanceLogRequest)); + assertTrue(exception.toString().contains("TenantId is mandatory")); + } + + @DisplayName("Method validateAttendanceLogRequest: RequestInfo object with UserInfo but without Attendance Log RegisterId") + @Test + public void validateCreateAttendanceLogRequest_validateAttendanceLogRequest_8(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().attendanceLogWithoutRegisterId().build(); + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendanceLogRequest", attendanceLogRequest)); + log.info(exception.toString()); + assertTrue(exception.toString().contains("Attendance registerid is mandatory")); + } + + @DisplayName("Method validateAttendanceLogRequest: RequestInfo object with UserInfo but without Attendance Log IndividualId") + @Test + public void validateCreateAttendanceLogRequest_validateAttendanceLogRequest_9(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().attendanceLogWithoutIndividualId().build(); + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendanceLogRequest", attendanceLogRequest)); + assertTrue(exception.toString().contains("Attendance indidualid is mandatory")); + } + + @DisplayName("Method validateAttendanceLogRequest: RequestInfo object with UserInfo but without Attendance Log Type") + @Test + public void validateCreateAttendanceLogRequest_validateAttendanceLogRequest_10(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().attendanceLogWithoutType().build(); + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendanceLogRequest", attendanceLogRequest)); + assertTrue(exception.toString().contains("Attendance type is mandatory")); + } + + @DisplayName("Method validateAttendanceLogRequest: RequestInfo object with UserInfo but without Attendance Log Time") + @Test + public void validateCreateAttendanceLogRequest_validateAttendanceLogRequest_11(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().attendanceLogWithoutTime().build();; + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendanceLogRequest", attendanceLogRequest)); + assertTrue(exception.toString().contains("Attendance time is mandatory")); + } + + + @DisplayName("Method validateLoggedInUser: should throw exception with code INTEGRATION_UNDERDEVELOPMENT") + @Test + public void validateCreateAttendanceLogRequest_validateLoggedInUser_1(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); + when(config.getStaffServiceIntegrationRequired()).thenReturn("TRUE"); + + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateLoggedInUser", attendanceLogRequest)); + assertTrue(exception.getCode().equals("INTEGRATION_UNDERDEVELOPMENT")); + } + +// @DisplayName("Method validateLoggedInUser: should through exception with error code UNAUTHORISED_USER") +// @Test +// public void validateCreateAttendanceLogRequest_validateLoggedInUser_2(){ +// AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); +// when(config.getStaffServiceIntegrationRequired()).thenReturn("FALSE"); +// when(attendanceStaffRepository.getActiveStaff(any(StaffSearchCriteria.class))).thenReturn(null); +// +// CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateLoggedInUser", attendanceLogRequest)); +// assertTrue(exception.getCode().equals("UNAUTHORISED_USER")); +// +// } + +// @DisplayName("Method validateLoggedInUser: should through exception with error code UNAUTHORISED_USER") +// @Test +// public void validateCreateAttendanceLogRequest_validateLoggedInUser_3(){ +// AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); +// when(config.getStaffServiceIntegrationRequired()).thenReturn("FALSE"); +// List attendanceStaff = new ArrayList<>(); +// when(attendanceStaffRepository.getActiveStaff(any(StaffSearchCriteria.class))).thenReturn(attendanceStaff); +// +// CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateLoggedInUser", attendanceLogRequest)); +// assertTrue(exception.getCode().equals("UNAUTHORISED_USER")); +// +// } + +// @DisplayName("Method validateLoggedInUser: should run successfully") +// @Test +// public void validateCreateAttendanceLogRequest_validateLoggedInUser_4(){ +// AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); +// when(config.getStaffServiceIntegrationRequired()).thenReturn("FALSE"); +// StaffPermission staff = StaffPermission.builder() +// .id("staff-uuid") +// .tenantId("tenantId") +// .userId("staffId") +// .registerId("registerId") +// .enrollmentDate(BigDecimal.valueOf(1L)) +// .denrollmentDate(BigDecimal.valueOf(1L)) +// .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()) +// .additionalDetails(AdditionalFields.builder().build()) +// .build(); +// List attendanceStaff = new ArrayList<>(); +// attendanceStaff.add(staff); +// when(attendanceStaffRepository.getActiveStaff(any(StaffSearchCriteria.class))).thenReturn(attendanceStaff); +// +// assertDoesNotThrow(()->ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateLoggedInUser", attendanceLogRequest)); +// +// } + + @DisplayName("Method validateTenantIdAssociationWithRegisterId: should through exception with error code INVALID_TENANTID") + @Test + public void validateCreateAttendanceLogRequest_validateTenantIdAssociationWithRegisterId_1(){ + AttendanceRegister attendanceRegister = AttendanceRegisterBuilderTest.getAttendanceRegister(); + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateTenantIdAssociationWithRegisterId", attendanceRegister,"other.tenantId")); + assertTrue(exception.getCode().equals("INVALID_TENANTID")); + } + @DisplayName("Method validateTenantIdAssociationWithRegisterId: should run successfully") + @Test + public void validateCreateAttendanceLogRequest_validateTenantIdAssociationWithRegisterId_2(){ + AttendanceRegister attendanceRegister = AttendanceRegisterBuilderTest.getAttendanceRegister(); + assertDoesNotThrow(()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateTenantIdAssociationWithRegisterId", attendanceRegister,"pb.amritsar")); + } + + @DisplayName("Method validateAttendees: should through exception with error code INTEGRATION_UNDERDEVELOPMENT") + @Test + public void validateCreateAttendanceLogRequest_validateAttendees_1(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); + when(config.getIndividualServiceIntegrationRequired()).thenReturn("TRUE"); + + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendees", attendanceLogRequest)); + assertTrue(exception.getCode().equals("INTEGRATION_UNDERDEVELOPMENT")); + } + + @DisplayName("Method validateAttendees: should run successfully") + @Test + public void validateCreateAttendanceLogRequest_validateAttendees_2(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); + when(config.getIndividualServiceIntegrationRequired()).thenReturn("FALSE"); + + IndividualEntry individual = IndividualEntry.builder() + .registerId("some-registerId") + .id("uuid") + .individualId("some-individualId") + .enrollmentDate(BigDecimal.valueOf(1640995200000L)) + .denrollmentDate(BigDecimal.valueOf(1703980800000L)) + .build(); + List individualEntries = new ArrayList<>(); + individualEntries.add(individual); + when(attendanceAttendeeRepository.getAttendees(any(AttendeeSearchCriteria.class))).thenReturn(individualEntries); + assertDoesNotThrow( ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendees", attendanceLogRequest)); + } + + @DisplayName("Method validateAttendees: should run successfully") + @Test + public void validateCreateAttendanceLogRequest_validateAttendees_3(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); + when(config.getIndividualServiceIntegrationRequired()).thenReturn("FALSE"); + + IndividualEntry individual = IndividualEntry.builder() + .registerId("some-registerId") + .id("uuid") + .individualId("some-individualId") + .enrollmentDate(BigDecimal.valueOf(1640995200000L)) + .build(); + List individualEntries = new ArrayList<>(); + individualEntries.add(individual); + when(attendanceAttendeeRepository.getAttendees(any(AttendeeSearchCriteria.class))).thenReturn(individualEntries); + assertDoesNotThrow( ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendees", attendanceLogRequest)); + } + + @DisplayName("Method validateAttendees: should run successfully") + @Test + public void validateCreateAttendanceLogRequest_validateAttendees_4(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); + when(config.getIndividualServiceIntegrationRequired()).thenReturn("FALSE"); + + IndividualEntry individual = IndividualEntry.builder() + .registerId("some-registerId") + .id("uuid") + .individualId("some-individualId") + .enrollmentDate(BigDecimal.valueOf(1672813896627L)) + .build(); + List individualEntries = new ArrayList<>(); + individualEntries.add(individual); + when(attendanceAttendeeRepository.getAttendees(any(AttendeeSearchCriteria.class))).thenReturn(individualEntries); + assertDoesNotThrow( ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendees", attendanceLogRequest)); + } + + @DisplayName("Method validateAttendees: should through exception with error code INELIGIBLE_ATTENDEES") + @Test + public void validateCreateAttendanceLogRequest_validateAttendees_5(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); + when(config.getIndividualServiceIntegrationRequired()).thenReturn("FALSE"); + + IndividualEntry individual = IndividualEntry.builder() + .registerId("some-registerId") + .id("uuid") + .individualId("some-individualId") + .enrollmentDate(BigDecimal.valueOf(1705491134000L)) + .build(); + List individualEntries = new ArrayList<>(); + individualEntries.add(individual); + when(attendanceAttendeeRepository.getAttendees(any(AttendeeSearchCriteria.class))).thenReturn(individualEntries); + CustomException exception = assertThrows(CustomException.class, ( ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendees", attendanceLogRequest))); + assertTrue(exception.getCode().equals("INELIGIBLE_ATTENDEES")); + } + + @DisplayName("Method validateAttendees: should through exception with error code INELIGIBLE_ATTENDEES") + @Test + public void validateCreateAttendanceLogRequest_validateAttendees_6(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); + when(config.getIndividualServiceIntegrationRequired()).thenReturn("FALSE"); + + IndividualEntry individual = IndividualEntry.builder() + .registerId("some-registerId") + .id("uuid") + .individualId("some-individualId") + .enrollmentDate(BigDecimal.valueOf(1579260734000L)) + .denrollmentDate(BigDecimal.valueOf(1589715134000L)) + .build(); + List individualEntries = new ArrayList<>(); + individualEntries.add(individual); + when(attendanceAttendeeRepository.getAttendees(any(AttendeeSearchCriteria.class))).thenReturn(individualEntries); + CustomException exception = assertThrows(CustomException.class, ( ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendees", attendanceLogRequest))); + assertTrue(exception.getCode().equals("INELIGIBLE_ATTENDEES")); + } + + @DisplayName("Method validateDocumentIds: should through exception with error code SERVICE_UNAVAILABLE") + @Test + public void validateCreateAttendanceLogRequest_validateDocumentIds_1(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); + when(config.getDocumentIdVerificationRequired()).thenReturn("TRUE"); + CustomException exception = assertThrows(CustomException.class, ( ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateDocumentIds", attendanceLogRequest))); + assertTrue(exception.getCode().equals("SERVICE_UNAVAILABLE")); + } + + @DisplayName("Method validateDocumentIds: should run successfully") + @Test + public void validateCreateAttendanceLogRequest_validateDocumentIds_2(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); + when(config.getDocumentIdVerificationRequired()).thenReturn("FALSE"); + assertDoesNotThrow( ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateDocumentIds", attendanceLogRequest)); + } + + @DisplayName("Method validateAttendanceLogTimeWithRegisterStartEndDate: should run successfully") + @Test + public void validateCreateAttendanceLogRequest_validateAttendanceLogTimeWithRegisterStartEndDate_1(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); + AttendanceLog attendanceLog = attendanceLogRequest.getAttendance().get(0); + attendanceLog.setTime(new BigDecimal("1673740800000")); + AttendanceRegister attendanceRegister = AttendanceRegisterBuilderTest.getAttendanceRegister(); + assertDoesNotThrow( ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendanceLogTimeWithRegisterStartEndDate",attendanceRegister, attendanceLogRequest)); + } + + @DisplayName("Method validateAttendanceLogTimeWithRegisterStartEndDate: should through exception with error code INVALID_ATTENDANCE_TIME") + @Test + public void validateCreateAttendanceLogRequest_validateAttendanceLogTimeWithRegisterStartEndDate_2(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); + AttendanceLog attendanceLog = attendanceLogRequest.getAttendance().get(0); + attendanceLog.setTime(new BigDecimal("1573740800000")); + AttendanceRegister attendanceRegister = AttendanceRegisterBuilderTest.getAttendanceRegister(); + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendanceLogTimeWithRegisterStartEndDate",attendanceRegister, attendanceLogRequest)); + assertTrue(exception.getCode().equals("INVALID_ATTENDANCE_TIME")); + } + + @DisplayName("Method validateAttendanceLogTimeWithRegisterStartEndDate: should through exception with error code INVALID_ATTENDANCE_TIME") + @Test + public void validateCreateAttendanceLogRequest_validateAttendanceLogTimeWithRegisterStartEndDate_3(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); + AttendanceLog attendanceLog = attendanceLogRequest.getAttendance().get(0); + attendanceLog.setTime(new BigDecimal("1792057600000")); + AttendanceRegister attendanceRegister = AttendanceRegisterBuilderTest.getAttendanceRegister(); + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendanceLogTimeWithRegisterStartEndDate",attendanceRegister, attendanceLogRequest)); + assertTrue(exception.getCode().equals("INVALID_ATTENDANCE_TIME")); + } + + @DisplayName("Method validateAttendanceLogTimeWithRegisterStartEndDate: should run successfully") + @Test + public void validateCreateAttendanceLogRequest_validateAttendanceLogTimeWithRegisterStartEndDate_4(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); + AttendanceLog attendanceLog = attendanceLogRequest.getAttendance().get(0); + attendanceLog.setTime(new BigDecimal("1673740800000")); + AttendanceRegister attendanceRegister = AttendanceRegisterBuilderTest.getAttendanceRegister(); + assertDoesNotThrow(()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendanceLogTimeWithRegisterStartEndDate",attendanceRegister, attendanceLogRequest)); + } + + @DisplayName("Method validateAttendanceLogTimeWithRegisterStartEndDate: should run successfully") + @Test + public void validateCreateAttendanceLogRequest_validateAttendanceLogTimeWithRegisterStartEndDate_5(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); + AttendanceLog attendanceLog = attendanceLogRequest.getAttendance().get(0); + attendanceLog.setTime(new BigDecimal("1692057600000")); + AttendanceRegister attendanceRegister = AttendanceRegisterBuilderTest.getAttendanceRegister(); + assertDoesNotThrow(()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendanceLogTimeWithRegisterStartEndDate",attendanceRegister, attendanceLogRequest)); + } + + @DisplayName("Method validateAttendanceLogTimeWithRegisterStartEndDate: should run successfully") + @Test + public void validateCreateAttendanceLogRequest_validateAttendanceLogTimeWithRegisterStartEndDate_6(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); + AttendanceLog attendanceLog = attendanceLogRequest.getAttendance().get(0); + attendanceLog.setTime(new BigDecimal("1673740800000")); + AttendanceRegister attendanceRegister = AttendanceRegisterBuilderTest.getAttendanceRegisterWithoutEndDate(); + assertDoesNotThrow(()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendanceLogTimeWithRegisterStartEndDate",attendanceRegister, attendanceLogRequest)); + } + + @DisplayName("Method validateAttendanceLogTimeWithRegisterStartEndDate: should run successfully") + @Test + public void validateCreateAttendanceLogRequest_validateAttendanceLogTimeWithRegisterStartEndDate_7(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); + AttendanceLog attendanceLog = attendanceLogRequest.getAttendance().get(0); + attendanceLog.setTime(new BigDecimal("1773740800000")); + AttendanceRegister attendanceRegister = AttendanceRegisterBuilderTest.getAttendanceRegisterWithoutEndDate(); + assertDoesNotThrow(()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendanceLogTimeWithRegisterStartEndDate",attendanceRegister, attendanceLogRequest)); + } + + @DisplayName("Method validateAttendanceLogTimeWithRegisterStartEndDate: should run successfully") + @Test + public void validateCreateAttendanceLogRequest_validateAttendanceLogTimeWithRegisterStartEndDate_8(){ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); + AttendanceLog attendanceLog = attendanceLogRequest.getAttendance().get(0); + attendanceLog.setTime(new BigDecimal("1573740800000")); + AttendanceRegister attendanceRegister = AttendanceRegisterBuilderTest.getAttendanceRegisterWithoutEndDate(); + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "validateAttendanceLogTimeWithRegisterStartEndDate",attendanceRegister, attendanceLogRequest)); + assertTrue(exception.getCode().equals("INVALID_ATTENDANCE_TIME")); + } + @DisplayName("Method checkRegisterStatus: should run successfully") + @Test + public void validateCreateAttendanceLogRequest_checkRegisterStatus_1(){ + AttendanceRegister attendanceRegister = AttendanceRegisterBuilderTest.getAttendanceRegister(); + attendanceRegister.setStatus(Status.ACTIVE); + assertDoesNotThrow( ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "checkRegisterStatus",attendanceRegister)); + } + @DisplayName("Method checkRegisterStatus: should through exception with error code INACTIVE_REGISTER") + @Test + public void validateCreateAttendanceLogRequest_checkRegisterStatus_2(){ + AttendanceRegister attendanceRegister = AttendanceRegisterBuilderTest.getAttendanceRegister(); + attendanceRegister.setStatus(Status.INACTIVE); + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "checkRegisterStatus",attendanceRegister)); + assertTrue(exception.getCode().equals("INACTIVE_REGISTER")); + } + + @DisplayName("Method checkRegisterExistence: should run successfully") + @Test + public void validateCreateAttendanceLogRequest_checkRegisterExistence_1(){ + AttendanceRegister attendanceRegister = AttendanceRegisterBuilderTest.getAttendanceRegister(); + List attendanceRegisters = Collections.singletonList(attendanceRegister); + assertDoesNotThrow( ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "checkRegisterExistence",attendanceRegisters,"TestRegisterId")); + } + + @DisplayName("Method checkRegisterExistence: should through exception with error code REGISTER_NOT_FOUND") + @Test + public void validateCreateAttendanceLogRequest_checkRegisterExistence_2(){ + List attendanceRegisters = null; + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "checkRegisterExistence",attendanceRegisters,"TestRegisterId")); + assertTrue(exception.getCode().equals("REGISTER_NOT_FOUND")); + } + + @DisplayName("Method checkRegisterExistence: should through exception with error code REGISTER_NOT_FOUND") + @Test + public void validateCreateAttendanceLogRequest_checkRegisterExistence_3(){ + List attendanceRegisters = new ArrayList<>(); + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceLogServiceValidator, "checkRegisterExistence",attendanceRegisters,"TestRegisterId")); + assertTrue(exception.getCode().equals("REGISTER_NOT_FOUND")); + } +} diff --git a/core-services/attendance/src/test/java/org/egov/validator/AttendanceServiceValidatorTest.java b/core-services/attendance/src/test/java/org/egov/validator/AttendanceServiceValidatorTest.java new file mode 100644 index 00000000000..ab670ad60e6 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/validator/AttendanceServiceValidatorTest.java @@ -0,0 +1,181 @@ +package org.egov.validator; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.helper.AttendanceRegisterRequestBuilderTest; +import org.egov.helper.AttendeeRequestBuilderTest; +import org.egov.repository.RegisterRepository; +import org.egov.tracer.model.CustomException; +import org.egov.util.MDMSUtils; +import org.egov.web.models.AttendanceRegister; +import org.egov.web.models.AttendanceRegisterRequest; +import org.egov.web.models.AttendanceRegisterSearchCriteria; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.test.util.ReflectionTestUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.when; + +@Slf4j +@ExtendWith(MockitoExtension.class) +public class AttendanceServiceValidatorTest { + + @InjectMocks + private AttendanceServiceValidator attendanceServiceValidator; + + @Mock + private MDMSUtils mdmsUtils; + + @Mock + private RegisterRepository registerRepository; + + @DisplayName("Method validateRequestInfo: With good request") + @Test + public void validateCreateAttendanceRegister_validateRequestInfo_1(){ + AttendanceRegisterRequest attendanceRegisterRequest = AttendanceRegisterRequestBuilderTest.builder().withRequestInfo().addGoodRegister().build(); + assertDoesNotThrow(()-> ReflectionTestUtils.invokeMethod(attendanceServiceValidator, "validateRequestInfo", attendanceRegisterRequest.getRequestInfo(), new HashMap<>())); + } + + @DisplayName("Method validateRequestInfo: Should throw exception with error code REQUEST_INFO") + @Test + public void validateCreateAttendanceRegister_validateRequestInfo_2(){ + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceServiceValidator, "validateRequestInfo", null,new HashMap<>())); + assertTrue(exception.getCode().equals("REQUEST_INFO")); + } + + @DisplayName("Method validateRequestInfo: Should throw exception with error code USERINFO") + @Test + public void validateCreateAttendanceRegister_validateRequestInfo_3(){ + AttendanceRegisterRequest attendanceRegisterRequest = AttendanceRegisterRequestBuilderTest.builder().requestInfoWithoutUserInfo().addGoodRegister().build(); + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceServiceValidator, "validateRequestInfo", attendanceRegisterRequest.getRequestInfo(),new HashMap<>())); + assertTrue(exception.getCode().equals("USERINFO")); + } + + @DisplayName("Method validateRequestInfo: Should throw exception with error code USERINFO") + @Test + public void validateCreateAttendanceRegister_validateRequestInfo_4(){ + AttendanceRegisterRequest attendanceRegisterRequest = AttendanceRegisterRequestBuilderTest.builder().requestInfoWithUserInfoButWithOutUUID().build(); + CustomException exception = assertThrows(CustomException.class, ()-> ReflectionTestUtils.invokeMethod(attendanceServiceValidator, "validateRequestInfo", attendanceRegisterRequest.getRequestInfo(),new HashMap<>())); + assertTrue(exception.getCode().equals("USERINFO_UUID")); + } + + @DisplayName("Method validateAttendanceRegisterRequest: Should run successfully") + @Test + public void validateCreateAttendanceRegister_validateAttendanceRegisterRequest_1(){ + AttendanceRegisterRequest attendanceRegisterRequest = AttendanceRegisterRequestBuilderTest.builder().addGoodRegister().build(); + assertDoesNotThrow(()-> ReflectionTestUtils.invokeMethod(attendanceServiceValidator, "validateAttendanceRegisterRequest", attendanceRegisterRequest.getAttendanceRegister(),new HashMap<>())); + } + + @DisplayName("Method validateAttendanceRegisterRequest: Should throw exception with error code ATTENDANCE_REGISTER") + @Test + public void validateCreateAttendanceRegister_validateAttendanceRegisterRequest_2(){ + CustomException exception = assertThrows(CustomException.class,()-> ReflectionTestUtils.invokeMethod(attendanceServiceValidator, "validateAttendanceRegisterRequest", null,new HashMap<>())); + assertTrue(exception.getCode().equals("ATTENDANCE_REGISTER")); + } + + @DisplayName("Method validateAttendanceRegisterRequest: Should throw exception with error code ATTENDANCE_REGISTER") + @Test + public void validateCreateAttendanceRegister_validateAttendanceRegisterRequest_3(){ + // Empty list + List attendanceRegisters = new ArrayList<>(); + CustomException exception = assertThrows(CustomException.class,()-> ReflectionTestUtils.invokeMethod(attendanceServiceValidator, "validateAttendanceRegisterRequest", attendanceRegisters,new HashMap<>())); + assertTrue(exception.getCode().equals("ATTENDANCE_REGISTER")); + } + + @DisplayName("Method validateAttendanceRegisterRequest: Error code TENANT_ID") + @Test + public void validateCreateAttendanceRegister_validateAttendanceRegisterRequest_4(){ + AttendanceRegisterRequest attendanceRegisterRequest = AttendanceRegisterRequestBuilderTest.builder().attendanceRegisterWithoutTenantId().build(); + List attendanceRegister = attendanceRegisterRequest.getAttendanceRegister(); + Map errorMap = new HashMap<>(); + CustomException exception = assertThrows(CustomException.class,()->ReflectionTestUtils.invokeMethod(attendanceServiceValidator, "validateAttendanceRegisterRequest", attendanceRegister, errorMap)); + assertTrue(exception.getCode().equals("TENANT_ID")); + } + + @DisplayName("Method validateAttendanceRegisterRequest: Error code NAME") + @Test + public void validateCreateAttendanceRegister_validateAttendanceRegisterRequest_5(){ + AttendanceRegisterRequest attendanceRegisterRequest = AttendanceRegisterRequestBuilderTest.builder().attendanceRegisterWithoutName().build(); + Map errorMap = new HashMap<>(); + ReflectionTestUtils.invokeMethod(attendanceServiceValidator, "validateAttendanceRegisterRequest", attendanceRegisterRequest.getAttendanceRegister(),errorMap); + assertTrue(errorMap.keySet().contains("NAME")); + } + + @DisplayName("Method validateAttendanceRegisterRequest: Error code START_DATE") + @Test + public void validateCreateAttendanceRegister_validateAttendanceRegisterRequest_6(){ + AttendanceRegisterRequest attendanceRegisterRequest = AttendanceRegisterRequestBuilderTest.builder().attendanceRegisterWithoutStartDate().build(); + Map errorMap = new HashMap<>(); + CustomException exception = assertThrows(CustomException.class,()->ReflectionTestUtils.invokeMethod(attendanceServiceValidator, "validateAttendanceRegisterRequest", attendanceRegisterRequest.getAttendanceRegister(),errorMap)); + assertTrue(exception.getCode().equals("START_DATE")); + } + + @DisplayName("Method validateAttendanceRegisterRequest: Error code DATE") + @Test + public void validateCreateAttendanceRegister_validateAttendanceRegisterRequest_7(){ + AttendanceRegisterRequest attendanceRegisterRequest = AttendanceRegisterRequestBuilderTest.builder().attendanceRegisterWithStartDateGTEndDate().build(); + Map errorMap = new HashMap<>(); + ReflectionTestUtils.invokeMethod(attendanceServiceValidator, "validateAttendanceRegisterRequest", attendanceRegisterRequest.getAttendanceRegister(),errorMap); + assertTrue(errorMap.keySet().contains("DATE")); + } + + @DisplayName("Method validateAttendanceRegisterRequest: Error code DATE") + @Test + public void validateCreateAttendanceRegister_validateMultipleTenantIds(){ + AttendanceRegisterRequest attendanceRegisterRequest = AttendanceRegisterRequestBuilderTest.builder().withRequestInfo().attendanceRegistersWithMultipleTenantIds().build(); + Map errorMap = new HashMap<>(); + CustomException exception = assertThrows(CustomException.class,()->ReflectionTestUtils.invokeMethod(attendanceServiceValidator, "validateCreateAttendanceRegister", attendanceRegisterRequest)); + assertTrue(exception.getCode().equals("MULTIPLE_TENANTS")); + } + + @DisplayName("Method validateCreateAttendanceRegister: run successfully") + @Test + public void validateCreateAttendanceRegister_validateCreateAttendanceRegister_1(){ + AttendanceRegisterRequest attendanceRegisterRequest = AttendanceRegisterRequestBuilderTest.builder().withRequestInfo().addGoodRegister().build(); + Object mdmsResponse = AttendeeRequestBuilderTest.getMdmsResponseForValidTenant(); + lenient().when(mdmsUtils.mDMSCall(any(RequestInfo.class), + any(String.class))).thenReturn(mdmsResponse); + List registers = new ArrayList<>(); + AttendanceRegister register = AttendanceRegister.builder().build(); + registers.add(register); + when(registerRepository.getRegister(any(AttendanceRegisterSearchCriteria.class))).thenReturn(registers); + CustomException exception = assertThrows(CustomException.class, ()->attendanceServiceValidator.validateCreateAttendanceRegister(attendanceRegisterRequest)); + assertTrue(exception.getCode().equals("REGISTER_ALREADY_EXISTS")); + } + + @Test + public void validateCreateAttendanceRegister_validateCreateAttendanceRegister_3(){ + AttendanceRegisterRequest attendanceRegisterRequest = AttendanceRegisterRequestBuilderTest.builder().withRequestInfo().addGoodRegister().build(); + Object mdmsResponse = AttendeeRequestBuilderTest.getMdmsResponseForValidTenant(); + lenient().when(mdmsUtils.mDMSCall(any(RequestInfo.class), + any(String.class))).thenReturn(mdmsResponse); + List registers = new ArrayList<>(); + when(registerRepository.getRegister(any(AttendanceRegisterSearchCriteria.class))).thenReturn(registers); + attendanceServiceValidator.validateCreateAttendanceRegister(attendanceRegisterRequest); + } + + @DisplayName("Method validateCreateAttendanceRegister: Error code INVALID_TENANT") + @Test + public void validateCreateAttendanceRegister_validateCreateAttendanceRegister_2(){ + AttendanceRegisterRequest attendanceRegisterRequest = AttendanceRegisterRequestBuilderTest.builder().withRequestInfo().addGoodRegister().build(); + Object mdmsResponse = AttendeeRequestBuilderTest.getMdmsResponseForInvalidTenant(); + lenient().when(mdmsUtils.mDMSCall(any(RequestInfo.class), + any(String.class))).thenReturn(mdmsResponse); + CustomException exception = assertThrows(CustomException.class,()->attendanceServiceValidator.validateCreateAttendanceRegister(attendanceRegisterRequest)); + assertTrue(exception.getMessage().contains("INVALID_TENANT")); + } +} diff --git a/core-services/attendance/src/test/java/org/egov/validator/AttendeeServiceValidatorTest.java b/core-services/attendance/src/test/java/org/egov/validator/AttendeeServiceValidatorTest.java new file mode 100644 index 00000000000..6cfca07e9e8 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/validator/AttendeeServiceValidatorTest.java @@ -0,0 +1,177 @@ +package org.egov.validator; + + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.helper.AttendanceRegisterBuilderTest; +import org.egov.helper.AttendeeRequestBuilderTest; +import org.egov.tracer.model.CustomException; +import org.egov.util.MDMSUtils; +import org.egov.web.models.AttendanceRegister; +import org.egov.web.models.AttendeeCreateRequest; +import org.egov.web.models.IndividualEntry; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.math.BigDecimal; +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.when; + +@Slf4j +@ExtendWith(MockitoExtension.class) +public class AttendeeServiceValidatorTest { + + @InjectMocks + private AttendeeServiceValidator attendeeServiceValidator; + + @Mock + private MDMSUtils mdmsUtils; + + + @BeforeEach + void setupBeforeEach() { + Object mdmsResponse = AttendeeRequestBuilderTest.getMdmsResponseForValidTenant(); + lenient().when(mdmsUtils.mDMSCall(any(RequestInfo.class), + any(String.class))).thenReturn(mdmsResponse); + } + + @DisplayName("attendees is null in attendee request") + @Test + void shouldThrowExceptionWhenAttendeesIsNull_InAttendeeRequest() { + + AttendeeCreateRequest attendeeCreateRequest = AttendeeRequestBuilderTest.getAttendeeCreateRequest(); + attendeeCreateRequest.setAttendees(null); + + assertThrows(CustomException.class, () -> attendeeServiceValidator.validateAttendeeCreateRequestParameters(attendeeCreateRequest)); + } + + @DisplayName("register id is null in attendee request") + @Test + void shouldThrowExceptionWhenRegisterIdIsNull_InAttendeeRequest() { + + IndividualEntry attendee = IndividualEntry.builder().tenantId("pb.amritsar").id("047dc725-3088-45b4-877a-6bfbaf377df9") + .individualId("8ybdd-3rdh3").registerId("").enrollmentDate(new BigDecimal("1672129633890")) + .denrollmentDate(new BigDecimal("1676073600000")).build(); + + AttendeeCreateRequest attendeeCreateRequest = AttendeeRequestBuilderTest.getAttendeeCreateRequest(); + attendeeCreateRequest.setAttendees(Collections.singletonList(attendee)); + + assertThrows(CustomException.class, () -> attendeeServiceValidator.validateAttendeeCreateRequestParameters(attendeeCreateRequest)); + } + + @DisplayName("individual id is null in attendee request") + @Test + void shouldThrowExceptionWhenIndividualIdIsNull_InAttendeeRequest() { + + IndividualEntry attendee = IndividualEntry.builder().tenantId("pb.amritsar").id("047dc725-3088-45b4-877a-6bfbaf377df9") + .individualId("").registerId("97ed7da3-753e-426a-b0b0-95dd61029785").enrollmentDate(new BigDecimal("1672129633890")) + .denrollmentDate(new BigDecimal("1676073600000")).build(); + + AttendeeCreateRequest attendeeCreateRequest = AttendeeRequestBuilderTest.getAttendeeCreateRequest(); + attendeeCreateRequest.setAttendees(Collections.singletonList(attendee)); + + assertThrows(CustomException.class, () -> attendeeServiceValidator.validateAttendeeCreateRequestParameters(attendeeCreateRequest)); + } + + @DisplayName("tenantId is null in attendee request") + @Test + void shouldThrowExceptionWhenTenantIdIsNull_InAttendeeRequest() { + + IndividualEntry attendee = IndividualEntry.builder().tenantId("").id("047dc725-3088-45b4-877a-6bfbaf377df9") + .individualId("8ybdd-3rdh3").registerId("97ed7da3-753e-426a-b0b0-95dd61029785").enrollmentDate(new BigDecimal("1672129633890")) + .denrollmentDate(new BigDecimal("1676073600000")).build(); + + AttendeeCreateRequest attendeeCreateRequest = AttendeeRequestBuilderTest.getAttendeeCreateRequest(); + attendeeCreateRequest.setAttendees(Collections.singletonList(attendee)); + + assertThrows(CustomException.class, () -> attendeeServiceValidator.validateAttendeeCreateRequestParameters(attendeeCreateRequest)); + } + + @DisplayName("tenantId is same for all attendees in the attendee request") + @Test + void shouldThrowExceptionWhenTenantIdsAreNotSame_InAttendeeRequest() { + + AttendeeCreateRequest attendeeCreateRequest = AttendeeRequestBuilderTest.getAttendeeCreateRequest(); + attendeeCreateRequest.getAttendees().get(0).setTenantId("od"); + + assertThrows(CustomException.class, () -> attendeeServiceValidator.validateAttendeeCreateRequestParameters(attendeeCreateRequest)); + } + + @DisplayName("verify tenantId with mdms when tenantId is present in mdms") + @Test + void shouldNotThrowExceptionWhenTenantIdPresent_InMDMS() { + + AttendeeCreateRequest attendeeCreateRequest = AttendeeRequestBuilderTest.getAttendeeCreateRequest(); + + assertDoesNotThrow(() -> attendeeServiceValidator.validateMDMSAndRequestInfoForCreateAttendee(attendeeCreateRequest)); + } + + @DisplayName("verify tenantId with mdms when tenantId is not present in mdms") + @Test + void shouldThrowExceptionWhenTenantIdNotPresent_InMDMS() { + + AttendeeCreateRequest attendeeCreateRequest = AttendeeRequestBuilderTest.getAttendeeCreateRequest(); + attendeeCreateRequest.getAttendees().get(0).setTenantId("od.odisha"); + + Object mdmsResponse = AttendeeRequestBuilderTest.getMdmsResponseForInvalidTenant(); + when(mdmsUtils.mDMSCall(any(RequestInfo.class), + any(String.class))).thenReturn(mdmsResponse); + + assertThrows(CustomException.class, () -> attendeeServiceValidator.validateMDMSAndRequestInfoForCreateAttendee(attendeeCreateRequest)); + } + + //tests for create attendee validation + + @DisplayName("attendee cannot be added to register if register's end date has passed") + @Test + void shouldThrowExceptionWhenRegisterEndDateHasPassed() { + + AttendeeCreateRequest attendeeCreateRequest = AttendeeRequestBuilderTest.getAttendeeCreateRequest(); + AttendanceRegister attendanceRegister = AttendanceRegisterBuilderTest.getAttendanceRegister(); + List attendees = attendanceRegister.getAttendees(); + + attendanceRegister.setEndDate(new BigDecimal("1578728218000")); //set a past date + + assertThrows(CustomException.class, () -> attendeeServiceValidator + .validateAttendeeOnCreate(attendeeCreateRequest, attendees, Collections.singletonList(attendanceRegister))); + } + + @DisplayName("attendee enrollment date should be after start date and before end date of register") + @Test + void shouldThrowExceptionWhenEnrollmentDateIsBeforeStartDateOfRegister() { + + AttendeeCreateRequest attendeeCreateRequest = AttendeeRequestBuilderTest.getAttendeeCreateRequest(); + AttendanceRegister attendanceRegister = AttendanceRegisterBuilderTest.getAttendanceRegister(); + List attendees = attendanceRegister.getAttendees(); + + attendeeCreateRequest.getAttendees().get(0).setEnrollmentDate(new BigDecimal("1673422618000")); + + assertThrows(CustomException.class, () -> attendeeServiceValidator + .validateAttendeeOnCreate(attendeeCreateRequest, attendees, Collections.singletonList(attendanceRegister))); + } + + @DisplayName("check if attendee is already enrolled to the register") + @Test + void shouldThrowExceptionWhenAttendeeAlreadyEnrolledToRegister() { + + AttendeeCreateRequest attendeeCreateRequest = AttendeeRequestBuilderTest.getAttendeeCreateRequest(); + AttendanceRegister attendanceRegister = AttendanceRegisterBuilderTest.getAttendanceRegister(); + List attendees = attendanceRegister.getAttendees(); + + assertThrows(CustomException.class, () -> attendeeServiceValidator + .validateAttendeeOnCreate(attendeeCreateRequest, attendees, Collections.singletonList(attendanceRegister))); + + } + +} diff --git a/core-services/attendance/src/test/java/org/egov/validator/StaffServiceValidatorTest.java b/core-services/attendance/src/test/java/org/egov/validator/StaffServiceValidatorTest.java new file mode 100644 index 00000000000..073f70199df --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/validator/StaffServiceValidatorTest.java @@ -0,0 +1,172 @@ +package org.egov.validator; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.helper.AttendanceRegisterBuilderTest; +import org.egov.helper.AttendeeRequestBuilderTest; +import org.egov.helper.StaffRequestBuilderTest; +import org.egov.service.AttendanceRegisterService; +import org.egov.tracer.model.CustomException; +import org.egov.util.MDMSUtils; +import org.egov.web.models.AttendanceRegister; +import org.egov.web.models.StaffPermission; +import org.egov.web.models.StaffPermissionRequest; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.math.BigDecimal; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.when; + +@Slf4j +@ExtendWith(MockitoExtension.class) +public class StaffServiceValidatorTest { + + @Mock + private MDMSUtils mdmsUtils; + + @Mock + private AttendanceRegisterService attendanceRegisterService; + + @InjectMocks + private StaffServiceValidator staffServiceValidator; + + @BeforeEach + void setupBeforeEach() { + Object mdmsResponse = AttendeeRequestBuilderTest.getMdmsResponseForValidTenant(); + lenient().when(mdmsUtils.mDMSCall(any(RequestInfo.class), + any(String.class))).thenReturn(mdmsResponse); + } + + + //validate staff request parameters + @DisplayName("staff is null in staff Permission request") + @Test + void shouldThrowExceptionWhenStaffIsNull_InStaffPermissionRequest() { + + StaffPermissionRequest staffPermissionRequest = StaffRequestBuilderTest.getStaffPermissionRequest(); + staffPermissionRequest.setStaff(null); + + assertThrows(CustomException.class, () -> staffServiceValidator.validateStaffPermissionRequestParameters(staffPermissionRequest)); + } + + @DisplayName("register id is null in staff Permission request") + @Test + void shouldThrowExceptionWhenRegisterIdIsNull_InStaffPermissionRequest() { + + StaffPermissionRequest staffPermissionRequest = StaffRequestBuilderTest.getStaffPermissionRequest(); + staffPermissionRequest.getStaff().get(0).setRegisterId(null); + + assertThrows(CustomException.class, () -> staffServiceValidator.validateStaffPermissionRequestParameters(staffPermissionRequest)); + } + + @DisplayName("tenant id is null in staff Permission request") + @Test + void shouldThrowExceptionWhenTenantIdIsNull_InStaffPermissionRequest() { + + StaffPermissionRequest staffPermissionRequest = StaffRequestBuilderTest.getStaffPermissionRequest(); + staffPermissionRequest.getStaff().get(0).setTenantId(null); + + assertThrows(CustomException.class, () -> staffServiceValidator.validateStaffPermissionRequestParameters(staffPermissionRequest)); + } + + @DisplayName("All staff must have same tenant id in staff Permission request") + @Test + void shouldThrowExceptionWhenTenantIdIsNotSame_InStaffPermissionRequest() { + + StaffPermissionRequest staffPermissionRequest = StaffRequestBuilderTest.getStaffPermissionRequest(); + staffPermissionRequest.getStaff().get(0).setTenantId("od"); + + assertThrows(CustomException.class, () -> staffServiceValidator.validateStaffPermissionRequestParameters(staffPermissionRequest)); + } + + @DisplayName("Duplicate staff objects in staff Permission request") + @Test + void shouldThrowExceptionWhenDuplicateStaffIsPresent_InStaffPermissionRequest() { + + StaffPermission staffOne = StaffPermission.builder().id("03901adb-07c3-4539-9346-4ee5c87e5e1c").userId("8ybdd-3rdhd") + .registerId("97ed7da3-753e-426a-b0b0-95dd61029785").tenantId("pb.amritsar").enrollmentDate(new BigDecimal("1670421853937")) + .denrollmentDate(null).build(); + + StaffPermissionRequest staffPermissionRequest = StaffRequestBuilderTest.getStaffPermissionRequest(); + staffPermissionRequest.getStaff().set(1, staffOne); + + assertThrows(CustomException.class, () -> staffServiceValidator.validateStaffPermissionRequestParameters(staffPermissionRequest)); + } + + + //validate tenant id with mdms + @DisplayName("verify tenantId with mdms when tenantId is present in mdms") + @Test + void shouldNotThrowExceptionWhenTenantIdPresent_InMDMS() { + + StaffPermissionRequest staffPermissionRequest = StaffRequestBuilderTest.getStaffPermissionRequest(); + + assertDoesNotThrow(() -> staffServiceValidator.validateMDMSAndRequestInfoForStaff(staffPermissionRequest)); + } + + @DisplayName("verify tenantId with mdms when tenantId is not present in mdms") + @Test + void shouldThrowExceptionWhenTenantIdNotPresent_InMDMS() { + + StaffPermissionRequest staffPermissionRequest = StaffRequestBuilderTest.getStaffPermissionRequest(); + staffPermissionRequest.getStaff().get(0).setTenantId("od.odisha"); + + Object mdmsResponse = AttendeeRequestBuilderTest.getMdmsResponseForInvalidTenant(); + when(mdmsUtils.mDMSCall(any(RequestInfo.class), + any(String.class))).thenReturn(mdmsResponse); + + assertThrows(CustomException.class, () -> staffServiceValidator.validateMDMSAndRequestInfoForStaff(staffPermissionRequest)); + } + + //check if staff tenant id is same as register tenant id + @DisplayName("check if staff tenant id is same as register tenant id") + @Test + void shouldThrowExceptionWhenStaffTenantIdNotSameAsRegisterTenantId() { + + StaffPermissionRequest staffPermissionRequest = StaffRequestBuilderTest.getStaffPermissionRequest(); + List staffPermissionList = AttendanceRegisterBuilderTest.getStaff(); + List attendanceRegisterList = AttendanceRegisterBuilderTest.getAttendanceRegisterList(); + + attendanceRegisterList.get(0).setTenantId("od.odisha"); + + assertThrows(CustomException.class, () -> staffServiceValidator.validateStaffPermissionOnCreate(staffPermissionRequest, staffPermissionList, attendanceRegisterList)); + } + + @DisplayName("check if register end date has passed") + @Test + void shouldThrowExceptionIfRegisterEndDateHasPassed() { + + StaffPermissionRequest staffPermissionRequest = StaffRequestBuilderTest.getStaffPermissionRequest(); + List staffPermissionList = AttendanceRegisterBuilderTest.getStaff(); + List attendanceRegisterList = AttendanceRegisterBuilderTest.getAttendanceRegisterList(); + + attendanceRegisterList.get(0).setEndDate(new BigDecimal("1547733538000")); + + assertThrows(CustomException.class, () -> staffServiceValidator.validateStaffPermissionOnCreate(staffPermissionRequest, staffPermissionList, attendanceRegisterList)); + } + + @DisplayName("check if staff is already enrolled to the given register") + @Test + void shouldThrowExceptionIfStaffIsAlreadyEnrolledToTheRegister() { + + StaffPermissionRequest staffPermissionRequest = StaffRequestBuilderTest.getStaffPermissionRequest(); + List staffPermissionList = AttendanceRegisterBuilderTest.getStaff(); + List attendanceRegisterList = AttendanceRegisterBuilderTest.getAttendanceRegisterList(); + + + assertThrows(CustomException.class, () -> staffServiceValidator.validateStaffPermissionOnCreate(staffPermissionRequest, staffPermissionList, attendanceRegisterList)); + } + + +} diff --git a/core-services/attendance/src/test/java/org/egov/web/controllers/AttendanceApiControllerTest.java b/core-services/attendance/src/test/java/org/egov/web/controllers/AttendanceApiControllerTest.java new file mode 100644 index 00000000000..068c0910681 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/web/controllers/AttendanceApiControllerTest.java @@ -0,0 +1,126 @@ +package org.egov.web.controllers; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.egov.Main; +import org.egov.TestConfiguration; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.helper.AttendanceRegisterBuilderTest; +import org.egov.helper.AttendanceRegisterRequestBuilderTest; +import org.egov.repository.AttendanceLogRepository; +import org.egov.repository.AttendeeRepository; +import org.egov.repository.RegisterRepository; +import org.egov.repository.StaffRepository; +import org.egov.service.AttendanceRegisterService; +import org.egov.tracer.model.CustomException; +import org.egov.tracer.model.ErrorRes; +import org.egov.util.ResponseInfoFactory; +import org.egov.web.models.AttendanceRegisterRequest; +import org.egov.web.models.AttendanceRegisterResponse; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; + +import javax.servlet.http.HttpServletRequest; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * API tests for AttendanceApiController + */ +@ContextConfiguration(classes = Main.class) +@WebMvcTest(AttendanceApiController.class) +@Import(TestConfiguration.class) +@AutoConfigureMockMvc +public class AttendanceApiControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private HttpServletRequest request; + + @MockBean + private ResponseInfoFactory responseInfoFactory; + + @MockBean + private AttendanceLogRepository attendanceLogRepository; + + @MockBean + private AttendanceRegisterService attendanceRegisterService; + + @MockBean + private AttendeeRepository attendeeRepository; + + @MockBean + private RegisterRepository registerRepository; + + @MockBean + private StaffRepository staffRepository; + + @MockBean + private JdbcTemplate jdbcTemplate; + + @Test + @DisplayName("should pass for correct API operation for create attendance register") + public void RegisterCreatePostSuccess() throws Exception { + + AttendanceRegisterRequest attendanceRegisterRequest = AttendanceRegisterRequestBuilderTest.builder().addGoodRegister() + .requestInfoWithoutUserInfo().build(); + ResponseInfo responseInfo = AttendanceRegisterBuilderTest.getResponseInfo_Success(); + + when(attendanceRegisterService.createAttendanceRegister(any(AttendanceRegisterRequest.class))).thenReturn(attendanceRegisterRequest); + when(responseInfoFactory.createResponseInfoFromRequestInfo(any(RequestInfo.class), eq(true))).thenReturn(responseInfo); + + ObjectMapper objectMapper = new ObjectMapper(); + String content = objectMapper.writeValueAsString(attendanceRegisterRequest); + MvcResult result = mockMvc.perform(post("/v1/_create").contentType(MediaType + .APPLICATION_JSON).content(content)) + .andExpect(status().isOk()).andReturn(); + String responseStr = result.getResponse().getContentAsString(); + + AttendanceRegisterResponse response = objectMapper.readValue(responseStr, AttendanceRegisterResponse.class); + + assertEquals("successful", response.getResponseInfo().getStatus()); + + } + + @Test + @DisplayName("should fail for incomplete attendance register object in API request") + public void RegisterCreatePostFailure() throws Exception { + + AttendanceRegisterRequest attendanceRegisterRequest = AttendanceRegisterRequestBuilderTest.builder().attendanceRegisterWithoutStartDate() + .withRequestInfo().build(); + + when(attendanceRegisterService.createAttendanceRegister(any(AttendanceRegisterRequest.class))) + .thenThrow(new CustomException("START_DATE", "Start date is mandatory")); + + ObjectMapper objectMapper = new ObjectMapper(); + String content = objectMapper.writeValueAsString(attendanceRegisterRequest); + MvcResult result = mockMvc.perform(post("/v1/_create").contentType(MediaType.APPLICATION_JSON).content(content)) + .andExpect(status().isBadRequest()).andReturn(); + + String responseStr = result.getResponse().getContentAsString(); + ErrorRes response = objectMapper.readValue(responseStr, + ErrorRes.class); + + assertEquals("Start date is mandatory", response.getErrors().get(0).getMessage()); + } +} diff --git a/core-services/attendance/src/test/java/org/egov/web/controllers/AttendanceLogApiControllerTest.java b/core-services/attendance/src/test/java/org/egov/web/controllers/AttendanceLogApiControllerTest.java new file mode 100644 index 00000000000..73230c97ca9 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/web/controllers/AttendanceLogApiControllerTest.java @@ -0,0 +1,94 @@ +package org.egov.web.controllers; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.egov.Main; +import org.egov.TestConfiguration; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.helper.AttendanceLogRequestTestBuilder; +import org.egov.kafka.Producer; +import org.egov.repository.AttendanceLogRepository; +import org.egov.service.AttendanceLogService; +import org.egov.util.ResponseInfoFactory; +import org.egov.web.models.AttendanceLogRequest; +import org.egov.web.models.AttendanceLogResponse; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + + + +@ContextConfiguration(classes = Main.class) +@WebMvcTest(AttendanceLogApiController.class) +@Import(TestConfiguration.class) +@AutoConfigureMockMvc + +public class AttendanceLogApiControllerTest { + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private AttendanceLogService attendanceLogService; + + @MockBean + private ResponseInfoFactory responseInfoFactory; + + @MockBean + private Producer producer; + + @MockBean + private AttendanceLogRepository attendanceLogRepository; + + @MockBean + private JdbcTemplate jdbcTemplate; + + + @DisplayName("attendance log request should pass and create attendance log") + @Test + public void attendanceLogV1CreatePOSTSuccess() throws Exception{ + AttendanceLogRequest attendanceLogRequest = AttendanceLogRequestTestBuilder.builder().withRequestInfo().addGoodAttendanceLog().build(); + + ResponseInfo responseInfo = ResponseInfo.builder() + .apiId(attendanceLogRequest.getRequestInfo().getApiId()) + .ver(attendanceLogRequest.getRequestInfo().getVer()) + .ts(attendanceLogRequest.getRequestInfo().getTs()) + .resMsgId("uief87324") + .msgId(attendanceLogRequest.getRequestInfo().getMsgId()) + .status("successful").build(); + + AttendanceLogResponse attendanceLogResponse = AttendanceLogResponse.builder().responseInfo(responseInfo).attendance(attendanceLogRequest.getAttendance()).build(); + + + when(attendanceLogService.createAttendanceLog(any(AttendanceLogRequest.class))).thenReturn(attendanceLogResponse); + + MvcResult result = mockMvc.perform(post("/log/v1/_create").contentType(MediaType + .APPLICATION_JSON).content(objectMapper.writeValueAsString(attendanceLogRequest))) + .andExpect(status().isOk()).andReturn(); + + String responseStr = result.getResponse().getContentAsString(); + AttendanceLogResponse response = objectMapper.readValue(responseStr, + AttendanceLogResponse.class); + + assertEquals(1, response.getAttendance().size()); + assertNotNull(response.getAttendance().get(0).getId()); + assertEquals("successful", response.getResponseInfo().getStatus()); + } +} diff --git a/core-services/attendance/src/test/java/org/egov/web/controllers/AttendeeApiControllerTest.java b/core-services/attendance/src/test/java/org/egov/web/controllers/AttendeeApiControllerTest.java new file mode 100644 index 00000000000..b0a7f360df7 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/web/controllers/AttendeeApiControllerTest.java @@ -0,0 +1,126 @@ +package org.egov.web.controllers; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.egov.Main; +import org.egov.TestConfiguration; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.enrichment.StaffEnrichmentService; +import org.egov.helper.AttendeeRequestBuilderTest; +import org.egov.repository.AttendanceLogRepository; +import org.egov.repository.AttendeeRepository; +import org.egov.repository.RegisterRepository; +import org.egov.repository.StaffRepository; +import org.egov.service.AttendanceRegisterService; +import org.egov.service.AttendeeService; +import org.egov.service.StaffService; +import org.egov.tracer.model.CustomException; +import org.egov.tracer.model.ErrorRes; +import org.egov.util.ResponseInfoFactory; +import org.egov.web.models.AttendeeCreateRequest; +import org.egov.web.models.AttendeeCreateResponse; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@ContextConfiguration(classes=Main.class) +@WebMvcTest(AttendeeApiController.class) +@Import({TestConfiguration.class}) +//@SpringBootTest(classes = Main.class) +@AutoConfigureMockMvc +public class AttendeeApiControllerTest { + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean + private AttendeeService attendeeService; + @MockBean + private ResponseInfoFactory responseInfoFactory; + + @MockBean + private AttendeeRepository attendeeRepository; + + @MockBean + private StaffEnrichmentService staffEnrichmentService; + + @MockBean + private AttendanceRegisterService attendanceRegisterService; + + @MockBean + private StaffRepository staffRepository; + + @MockBean + private StaffService staffService; + + @MockBean + private AttendanceLogRepository attendanceLogRepository; + + @MockBean + private RegisterRepository registerRepository; + + + @Test + @DisplayName("should pass for correct API operation") + public void attendeeCreatePostSuccess() throws Exception { + + AttendeeCreateRequest attendeeCreateRequest = AttendeeRequestBuilderTest.getAttendeeCreateRequest(); + ResponseInfo responseInfo = AttendeeRequestBuilderTest.getResponseInfo_Success(); + + when(attendeeService.createAttendee(any(AttendeeCreateRequest.class))).thenReturn(attendeeCreateRequest); + when(responseInfoFactory.createResponseInfoFromRequestInfo(any(RequestInfo.class), eq(true))).thenReturn(responseInfo); + + ObjectMapper objectMapper = new ObjectMapper(); + String content = objectMapper.writeValueAsString(attendeeCreateRequest); + MvcResult result = mockMvc.perform(post("/attendee/v1/_create").contentType(MediaType + .APPLICATION_JSON).content(content)) + .andExpect(status().isOk()).andReturn(); + String responseStr = result.getResponse().getContentAsString(); + + AttendeeCreateResponse response = objectMapper.readValue(responseStr, AttendeeCreateResponse.class); + + assertEquals("successful", response.getResponseInfo().getStatus()); + + } + + @Test + @DisplayName("should fail for incomplete attendee object in API request") + public void attendeeCreatePostFailure() throws Exception { + + AttendeeCreateRequest attendeeCreateRequest = AttendeeRequestBuilderTest.getAttendeeCreateRequest(); + + attendeeCreateRequest.getAttendees().get(0).setIndividualId(null); + + when(attendeeService.createAttendee(any(AttendeeCreateRequest.class))).thenThrow(new CustomException("ATTENDEE", "ATTENDEE is mandatory")); + + ObjectMapper objectMapper = new ObjectMapper(); + String content = objectMapper.writeValueAsString(attendeeCreateRequest); + MvcResult result=mockMvc.perform(post("/attendee/v1/_create").contentType(MediaType + .APPLICATION_JSON).content(content)) + .andExpect(status().isBadRequest()).andReturn(); + + String responseStr = result.getResponse().getContentAsString(); + ErrorRes response = objectMapper.readValue(responseStr, + ErrorRes.class); + + assertEquals("ATTENDEE is mandatory",response.getErrors().get(0).getMessage()); + } + +} diff --git a/core-services/attendance/src/test/java/org/egov/web/controllers/StaffApiControllerTest.java b/core-services/attendance/src/test/java/org/egov/web/controllers/StaffApiControllerTest.java new file mode 100644 index 00000000000..285ef21cca4 --- /dev/null +++ b/core-services/attendance/src/test/java/org/egov/web/controllers/StaffApiControllerTest.java @@ -0,0 +1,108 @@ +package org.egov.web.controllers; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.egov.Main; +import org.egov.TestConfiguration; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.helper.StaffRequestBuilderTest; +import org.egov.repository.AttendanceLogRepository; +import org.egov.service.StaffService; +import org.egov.tracer.model.CustomException; +import org.egov.tracer.model.ErrorRes; +import org.egov.util.ResponseInfoFactory; +import org.egov.web.models.StaffPermissionRequest; +import org.egov.web.models.StaffPermissionResponse; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; + +import javax.servlet.http.HttpServletRequest; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@ContextConfiguration(classes = Main.class) +@WebMvcTest(StaffApiController.class) +@Import(TestConfiguration.class) +@AutoConfigureMockMvc +public class StaffApiControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private HttpServletRequest request; + + @MockBean + private ResponseInfoFactory responseInfoFactory; + + @MockBean + private StaffService staffService; + + @MockBean + private AttendanceLogRepository attendanceLogRepository; + + @MockBean + private JdbcTemplate jdbcTemplate; + + @Test + @DisplayName("should pass for correct API operation") + public void staffCreatePostSuccess() throws Exception { + + StaffPermissionRequest staffPermissionRequest = StaffRequestBuilderTest.getStaffPermissionRequest(); + ResponseInfo responseInfo = StaffRequestBuilderTest.getResponseInfo_Success(); + + when(staffService.createAttendanceStaff(any(StaffPermissionRequest.class), eq(false))).thenReturn(staffPermissionRequest); + when(responseInfoFactory.createResponseInfoFromRequestInfo(any(RequestInfo.class), eq(true))).thenReturn(responseInfo); + + ObjectMapper objectMapper = new ObjectMapper(); + String content = objectMapper.writeValueAsString(staffPermissionRequest); + MvcResult result = mockMvc.perform(post("/staff/v1/_create").contentType(MediaType + .APPLICATION_JSON).content(content)) + .andExpect(status().isOk()).andReturn(); + String responseStr = result.getResponse().getContentAsString(); + + StaffPermissionResponse response = objectMapper.readValue(responseStr, StaffPermissionResponse.class); + + assertEquals("successful", response.getResponseInfo().getStatus()); + + } + + @Test + @DisplayName("should fail for incomplete staff object in API request") + public void staffCreatePostFailure() throws Exception { + + StaffPermissionRequest staffPermissionRequest = StaffRequestBuilderTest.getStaffPermissionRequest(); + staffPermissionRequest.setStaff(null); + + when(staffService.createAttendanceStaff(any(StaffPermissionRequest.class), eq(false))).thenThrow(new CustomException("STAFF", "Staff is mandatory")); + + ObjectMapper objectMapper = new ObjectMapper(); + String content = objectMapper.writeValueAsString(staffPermissionRequest); + MvcResult result=mockMvc.perform(post("/staff/v1/_create").contentType(MediaType.APPLICATION_JSON).content(content)) + .andExpect(status().isBadRequest()).andReturn(); + + String responseStr = result.getResponse().getContentAsString(); + ErrorRes response = objectMapper.readValue(responseStr, + ErrorRes.class); + + assertEquals("Staff is mandatory",response.getErrors().get(0).getMessage()); + } +} diff --git a/core-services/attendance/src/test/resources/AttendeeCreateRequest.json b/core-services/attendance/src/test/resources/AttendeeCreateRequest.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/core-services/attendance/src/test/resources/InvalidTenantMDMSData.json b/core-services/attendance/src/test/resources/InvalidTenantMDMSData.json new file mode 100644 index 00000000000..d510372f9e1 --- /dev/null +++ b/core-services/attendance/src/test/resources/InvalidTenantMDMSData.json @@ -0,0 +1,8 @@ +{ + "ResponseInfo": null, + "MdmsRes": { + "tenant": { + "tenants": [] + } + } +} \ No newline at end of file diff --git a/core-services/attendance/src/test/resources/TenantMDMSData.json b/core-services/attendance/src/test/resources/TenantMDMSData.json new file mode 100644 index 00000000000..a28cc965f7e --- /dev/null +++ b/core-services/attendance/src/test/resources/TenantMDMSData.json @@ -0,0 +1,402 @@ +{ + "ResponseInfo": null, + "MdmsRes": { + "tenant": { + "tenants": [ + { + "code": "pb", + "name": "Punjab", + "description": "Punjab", + "logoId": "https://s3.ap-south-1.amazonaws.com/pb-egov-assets/pb.jalandhar/logo.png", + "imageId": "https://s3.ap-south-1.amazonaws.com/pb-egov-assets/pb.jalandhar/logo.png", + "domainUrl": "www.mcjalandhar.in", + "type": "CITY", + "twitterUrl": "https://twitter.com/search?q=%23jalandhar", + "facebookUrl": "https://www.facebook.com/city/jalandhar-Punjab", + "emailId": "complaints.mcj@gmail.com", + "OfficeTimings": { + "Mon - Fri": "9.00 AM - 6.00 PM" + }, + "city": { + "name": "Punjab", + "localName": "Punjab", + "districtCode": "0", + "districtName": "Punjab", + "districtTenantCode": "pb.punjab", + "regionName": "Punjab", + "ulbGrade": "ST", + "longitude": 75.3412, + "latitude": 31.1471, + "shapeFileLocation": null, + "captcha": null, + "code": "0", + "ddrName": null + }, + "address": "5 Punjab Municipal Bhawan, 3, Dakshin Marg, 35A, Sector 35A, Chandigarh, 160022", + "pincode": [], + "contactNumber": "0181-2227015", + "pdfHeader": "PB_PDF_HEADER", + "pdfContactDetails": "PB_CONTACT_DETAILS" + }, + { + "code": "pb.jalandhar", + "name": "Jalandhar", + "description": "Jalandhar", + "logoId": "", + "imageId": "", + "domainUrl": "www.mcjalandhar.in", + "type": "CITY", + "twitterUrl": "https://twitter.com/search?q=%23jalandhar", + "facebookUrl": "https://www.facebook.com/city/jalandhar-Punjab", + "emailId": "complaints.mcj@gmail.com", + "OfficeTimings": { + "Mon - Fri": "9.00 AM - 6.00 PM" + }, + "city": { + "name": "Jalandhar", + "localName": "Janlandhar", + "districtCode": "10", + "districtName": "Jalandhar", + "districtTenantCode": "pb.jalandhar", + "regionName": "Jalandhar Region", + "ulbGrade": "Municipal Corporation", + "ulbType": "Municipal Corporation", + "longitude": 75.5761829, + "latitude": 31.3260152, + "shapeFileLocation": null, + "captcha": null, + "code": "1013", + "regionCode": "4", + "municipalityName": "Janlandhar", + "ddrName": "Jalandhar-MC" + }, + "address": "Municipal Corporation Office, Dr. B.R.Ambedkar Admin Complex, Nehru Garden, Jalandhar City-144001", + "pincode": [ + 144001, + 144002, + 144003, + 144004, + 144005, + 144006, + 144007, + 144008, + 144009, + 144010 + ], + "contactNumber": "0181-2227015", + "pdfHeader": "PB_JALANDHAR_PDF_HEADER", + "pdfContactDetails": "PB_JALANDHAR_CONTACT_DETAILS" + }, + { + "code": "pb.phagwara", + "name": "Phagwara", + "description": "Phagwara", + "logoId": "https://s3.ap-south-1.amazonaws.com/pb-egov-assets/pb.phagwara/logo.png", + "imageId": "https://s3.ap-south-1.amazonaws.com/pb-egov-assets/pb.phagwara/logo.png", + "domainUrl": "http://www.mcphagwara.com/index.php", + "type": "CITY", + "twitterUrl": null, + "facebookUrl": null, + "emailId": "comm.mcpgr@punjab.gov.in", + "OfficeTimings": { + "Mon - Fri": "9.00 AM - 6.00 PM" + }, + "city": { + "name": "Phagwara", + "localName": "Phagwara", + "districtCode": "10", + "districtName": "Jalandhar", + "districtTenantCode": "pb.jalandhar", + "regionName": "Jalandhar Region", + "ulbGrade": "Municipal Corporation", + "ulbType": "Municipal Corporation", + "longitude": 75.7708, + "latitude": 31.224, + "shapeFileLocation": null, + "captcha": null, + "code": "1014", + "regionCode": "4", + "municipalityName": "Phagwara", + "ddrName": "Phagwara-MC" + }, + "address": "Town Hall, Phagwara, Punjab - 144401", + "pincode": [ + 144401, + 144402, + 144403 + ], + "contactNumber": "01824-260426", + "pdfHeader": "PB_PHAGWARA_PDF_HEADER", + "pdfContactDetails": "PB_PHAGWARA_CONTACT_DETAILS" + }, + { + "code": "pb.amritsar", + "name": "Amritsar", + "description": null, + "logoId": "https://s3.ap-south-1.amazonaws.com/pb-egov-assets/pb.amritsar/logo.png", + "imageId": "/pb-egov-assets/pb.amritsar/logo.png", + "domainUrl": "www.amritsarcorp.com", + "type": "CITY", + "twitterUrl": "https://twitter.com/search?q=%23AMRITSAR", + "facebookUrl": "https://www.facebook.com/city/Amritsar-Punjab", + "emailId": "cmcasr@gmail.com", + "OfficeTimings": { + "Mon - Fri": "9.00 AM - 6.00 PM", + "Sat": "9.00 AM - 12.00 PM" + }, + "city": { + "name": "Amritsar", + "localName": "Amritsar", + "districtCode": "1", + "districtName": "Amritsar", + "districtTenantCode": "pb.amritsar", + "regionName": "Amritsar Region", + "ulbGrade": "Municipal Corporation", + "ulbType": "Municipal Corporation", + "longitude": 74.8723, + "latitude": 31.634, + "shapeFileLocation": null, + "captcha": null, + "code": "107", + "regionCode": "1", + "municipalityName": "Amritsar", + "ddrName": "Amritsar-MC" + }, + "address": "Municipal Corporation Amritsar, C Block, Ranjit Avenue, Amritsar, Punjab", + "pincode": [ + 143001, + 143002, + 143003, + 143004, + 143005, + 143006, + 143007, + 143008, + 143009, + 143010 + ], + "contactNumber": "0183-2545155", + "helpLineNumber": "0183-2210300", + "pdfHeader": "PB_AMRITSAR_PDF_HEADER", + "pdfContactDetails": "PB_AMRITSAR_CONTACT_DETAILS" + }, + { + "code": "pb.nawanshahr", + "name": "Nawanshahr", + "description": null, + "logoId": "https://s3.ap-south-1.amazonaws.com/pb-egov-assets/pb.nawanshahr/logo.png", + "imageId": "https://s3.ap-south-1.amazonaws.com/pb-egov-assets/pb.nawanshahr/logo.png", + "domainUrl": "www.nawanshahr.com", + "type": "CITY", + "twitterUrl": null, + "facebookUrl": null, + "emailId": "", + "OfficeTimings": { + "Mon - Fri": "9.00 AM - 6.00 PM" + }, + "city": { + "name": "Nawanshahr", + "localName": "Nawanshahr", + "districtCode": "17", + "districtName": "Nawanshar", + "districtTenantCode": "pb.nawanshar", + "regionName": "Jalandhar Region", + "ulbGrade": "MC Class I", + "ulbType": "Municipal Council", + "longitude": 76.0392, + "latitude": 31.0913, + "shapeFileLocation": null, + "captcha": null, + "code": "1703", + "regionCode": "4", + "municipalityName": "SBS Nagar", + "ddrName": "Jalandhar-DDR" + }, + "address": "Committee Bazar", + "pincode": [ + 144513, + 144514, + 144516, + 144517 + ], + "contactNumber": "1823220085", + "helpLineNumber": "", + "pdfHeader": "PB_NAWANSHAHR_PDF_HEADER", + "pdfContactDetails": "PB_NAWANSHAHR_CONTACT_DETAILS" + }, + { + "code": "pb.mohali", + "name": "Mohali", + "description": "Mohali", + "logoId": "https://s3.ap-south-1.amazonaws.com/pb-egov-assets/pb.mohali/logo.png", + "imageId": "https://s3.ap-south-1.amazonaws.com/pb-egov-assets/pb.mohali/logo.png", + "domainUrl": "www.mcjalandhar.in", + "type": "CITY", + "twitterUrl": "https://twitter.com/search?q=%23mohali", + "facebookUrl": "https://www.facebook.com/city/mohali-Punjab", + "emailId": "complaints.mcj@gmail.com", + "OfficeTimings": { + "Mon - Fri": "9.00 AM - 6.00 PM" + }, + "city": { + "name": "Mohali", + "localName": "Mohali", + "districtCode": "15", + "districtName": "Mohali", + "districtTenantCode": "pb.mohali", + "regionName": "Patiala Region", + "ulbGrade": "Municipal Corporation", + "ulbType": "Municipal Corporation", + "longitude": 76.7179, + "latitude": 30.7046, + "shapeFileLocation": null, + "captcha": null, + "code": "1508", + "regionCode": "6", + "municipalityName": "SAS Nagar", + "ddrName": "Mohali-MC" + }, + "address": "Sector 68, Sahibzada Ajit Singh Nagar, Punjab 160062", + "pincode": [ + 140301, + 140302, + 140303, + 140304, + 140305, + 140306, + 140307 + ], + "contactNumber": "0172-5044907", + "pdfHeader": "PB_MOHALI_PDF_HEADER", + "pdfContactDetails": "PB_MOHALI_CONTACT_DETAILS" + }, + { + "code": "pb.nayagaon", + "name": "Nayagaon", + "description": "Nayagaon", + "logoId": "https://s3.ap-south-1.amazonaws.com/pb-egov-assets/pb.nayagaon/logo.png", + "imageId": null, + "domainUrl": "http://lgpunjab.gov.in/eSewa/nayagaon", + "type": "CITY", + "twitterUrl": null, + "facebookUrl": null, + "emailId": "eonpnayagaon@ymail.com", + "OfficeTimings": { + "Mon - Fri": "9.00 AM - 5.00 PM" + }, + "city": { + "name": "Nayagaon", + "localName": "NayaGaon", + "districtCode": "15", + "districtName": "Mohali", + "districtTenantCode": "pb.mohali", + "regionName": "Patiala Region", + "ulbGrade": "MC Class II", + "ulbType": "Municipal Council", + "longitude": 76.7943, + "latitude": 30.7761, + "shapeFileLocation": null, + "captcha": null, + "code": "1506", + "regionCode": "6", + "municipalityName": "NayaGaon", + "ddrName": "Patiala-DDR" + }, + "address": "Not available", + "pincode": [ + 147001, + 147002, + 147003, + 147004, + 147005 + ], + "contactNumber": "Not available", + "pdfHeader": "PB_NAYAGAON_PDF_HEADER", + "pdfContactDetails": "PB_NAYAGAON_CONTACT_DETAILS" + }, + { + "code": "pb.derabassi", + "name": "Derabassi", + "description": "Derabassi", + "logoId": "https://s3.ap-south-1.amazonaws.com/pb-egov-assets/pb.derabassi/logo.png", + "imageId": null, + "domainUrl": "http://lgpunjab.gov.in/eSewa/derabassi", + "type": "CITY", + "twitterUrl": null, + "facebookUrl": null, + "emailId": "eomcdera@gmail.com", + "OfficeTimings": { + "Mon - Fri": "9.00 AM - 5.00 PM" + }, + "city": { + "name": "Derabassi", + "localName": "DeraBassi", + "districtCode": "15", + "districtName": "Mohali", + "districtTenantCode": "pb.mohali", + "regionName": "Patiala Region", + "ulbGrade": "MC Class I", + "ulbType": "Municipal Council", + "longitude": 76.8433, + "latitude": 30.5964, + "shapeFileLocation": null, + "captcha": null, + "code": "1502", + "regionCode": "6", + "municipalityName": "DerraBassi", + "ddrName": "Patiala-DDR" + }, + "address": "Not available", + "pincode": [ + 140506, + 140507 + ], + "contactNumber": "1762281025", + "pdfHeader": "PB_DERABASSI_PDF_HEADER", + "pdfContactDetails": "PB_DERABASSI_CONTACT_DETAILS" + }, + { + "code": "pb.patiala", + "name": "Patiala", + "description": "Patiala", + "logoId": "http://mseva.lgpunjab.gov.in/pb-egov-assets/pb.patiala/logo.png", + "imageId": null, + "domainUrl": "https://patiala.nic.in/", + "type": "CITY", + "twitterUrl": null, + "facebookUrl": null, + "emailId": "dc.ptl@punjab.gov.in", + "OfficeTimings": { + "Mon - Fri": "9.00 AM - 6.00 PM" + }, + "city": { + "name": "Patiala", + "localName": "Patiala", + "districtCode": "19", + "districtName": "Patiala", + "districtTenantCode": "pb.patiala", + "regionName": "Patiala Region", + "ulbGrade": "Municipal Corporation", + "ulbType": "Municipal Corporation", + "longitude": 76.3869, + "latitude": 30.3398, + "shapeFileLocation": null, + "captcha": null, + "code": "1910", + "regionCode": "6", + "municipalityName": "Patiala", + "ddrName": "Patiala-MC" + }, + "address": "Office of the Deputy Commissioner District Administrative Complex, Patiala-147001", + "contactNumber": "0175-2311300", + "pincode": [ + 140506, + 140507 + ], + "pdfHeader": "PB_PATIALA_PDF_HEADER", + "pdfContactDetails": "PB_PATIALA_CONTACT_DETAILS" + } + ] + } + } +} \ No newline at end of file From 9342718302f1bc2904c42b49a91a7317877fffce Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Mon, 18 Dec 2023 12:55:19 +0530 Subject: [PATCH 226/283] HLM-4496: added build config for health attendance service (#592) --- build/build-config.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/build-config.yml b/build/build-config.yml index 685e18a3669..5f31009168a 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -71,6 +71,13 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "health-services/individual/src/main/resources/db" image-name: "health-individual-db" + - name: "builds/health-campaign-services/health-services/health-attendance" + build: + - work-dir: "health-services/attendance" + image-name: "health-attendance" + dockerfile: "build/maven/Dockerfile" + - work-dir: "health-services/attendance/src/main/resources/db" + image-name: "health-attendance-db" - name: "builds/health-campaign-services/health-services/household" build: - work-dir: "health-services/household" From d73e094ec35ae8e6afd9f1df76004865312966ed Mon Sep 17 00:00:00 2001 From: Priyanka-eGov Date: Wed, 7 Feb 2024 16:41:33 +0530 Subject: [PATCH 227/283] HLM-4894 moving hrms code from DIGIT-Dev branc health-moz-dev --- build/build-config.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/build-config.yml b/build/build-config.yml index 5f31009168a..05a6c671ae9 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -161,3 +161,10 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "core-services/attendance/src/main/resources/db" image-name: "attendance-db" + - name: "builds/health-campaign-services/core-services/egov-hrms" + build: + - work-dir: "core-services/egov-hrms" + image-name: "egov-hrms" + dockerfile: "build/maven/Dockerfile" + - work-dir: "core-services/egov-hrms/src/main/resources/db" + image-name: "egov-hrms-db" \ No newline at end of file From 0d83b4661cbdb50653d4d0f122027dff90c44abb Mon Sep 17 00:00:00 2001 From: Priyanka-eGov Date: Wed, 7 Feb 2024 16:43:23 +0530 Subject: [PATCH 228/283] HLM-4894 moving hrms code from DIGIT-Dev branc health-moz-dev --- build/build-config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/build-config.yml b/build/build-config.yml index 05a6c671ae9..acbbe4ce7b1 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -164,7 +164,7 @@ config: - name: "builds/health-campaign-services/core-services/egov-hrms" build: - work-dir: "core-services/egov-hrms" - image-name: "egov-hrms" + image-name: "health-hrms" dockerfile: "build/maven/Dockerfile" - work-dir: "core-services/egov-hrms/src/main/resources/db" - image-name: "egov-hrms-db" \ No newline at end of file + image-name: "health-hrms-db" \ No newline at end of file From c62f733f2d36099eaacb3de8f3a7c3b750cf37e4 Mon Sep 17 00:00:00 2001 From: Priyanka-eGov <74049060+Priyanka-eGov@users.noreply.github.com> Date: Thu, 8 Feb 2024 12:27:13 +0530 Subject: [PATCH 229/283] Update build-config.yml : Added health-hrms entry --- build/build-config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/build-config.yml b/build/build-config.yml index acbbe4ce7b1..235f7b72caa 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -161,10 +161,10 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "core-services/attendance/src/main/resources/db" image-name: "attendance-db" - - name: "builds/health-campaign-services/core-services/egov-hrms" + - name: "builds/health-campaign-services/core-services/health-hrms" build: - work-dir: "core-services/egov-hrms" image-name: "health-hrms" dockerfile: "build/maven/Dockerfile" - work-dir: "core-services/egov-hrms/src/main/resources/db" - image-name: "health-hrms-db" \ No newline at end of file + image-name: "health-hrms-db" From 48a843eafaebb6f8763a5143028c32b3c22ad70b Mon Sep 17 00:00:00 2001 From: amitverma-egov Date: Thu, 15 Feb 2024 22:09:37 +0530 Subject: [PATCH 230/283] Household transformer index for geoPoint --- .../config/TransformerProperties.java | 9 ++ .../consumer/HouseholdConsumer.java | 39 ++++++++ .../models/downstream/HouseholdIndexV1.java | 23 +++++ .../transformer/service/HouseholdService.java | 96 +++++++++++++++++++ .../src/main/resources/application.properties | 3 + 5 files changed, 170 insertions(+) create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/consumer/HouseholdConsumer.java create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/models/downstream/HouseholdIndexV1.java create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/service/HouseholdService.java diff --git a/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java b/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java index 2801294e64f..ce7b7ba3b15 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java @@ -29,6 +29,15 @@ public class TransformerProperties { @Value("${transformer.producer.bulk.stock.index.v1.topic}") private String transformerProducerBulkStockIndexV1Topic; + @Value("${transformer.producer.bulk.household.index.v1.topic}") + private String transformerProducerBulkHouseholdIndexV1Topic; + + @Value("${egov.household.host}") + private String householdHost; + + @Value("${egov.search.household.url}") + private String householdSearchUrl; + @Value("${egov.project.host}") private String projectHost; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/consumer/HouseholdConsumer.java b/health-services/transformer/src/main/java/org/egov/transformer/consumer/HouseholdConsumer.java new file mode 100644 index 00000000000..ec08f474e01 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/consumer/HouseholdConsumer.java @@ -0,0 +1,39 @@ +package org.egov.transformer.consumer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.egov.common.models.household.Household; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +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.Arrays; +import java.util.List; +@Component +@Slf4j +public class HouseholdConsumer { + private final ObjectMapper objectMapper; + + @Autowired + public HouseholdConsumer(@Qualifier("objectMapper")ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + @KafkaListener(topics = { "${transformer.consumer.create.household.topic}", + "${transformer.consumer.update.household.topic}"}) + public void consumeHouseholds(ConsumerRecord payload, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + List households = Arrays.asList(objectMapper + .readValue((String) payload.value(), + Household[].class)); + } catch (Exception exception) { + log.error("error in household consumer", exception); + } + } + } + diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/HouseholdIndexV1.java b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/HouseholdIndexV1.java new file mode 100644 index 00000000000..17fedcacdfa --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/HouseholdIndexV1.java @@ -0,0 +1,23 @@ +package org.egov.transformer.models.downstream; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.models.household.Household; + +import java.util.List; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class HouseholdIndexV1 { + @JsonProperty("household") + private Household household; + @JsonProperty("geoPoint") + private List geoPoint; +} \ No newline at end of file diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/HouseholdService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/HouseholdService.java new file mode 100644 index 00000000000..9ab928fcd59 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/HouseholdService.java @@ -0,0 +1,96 @@ +package org.egov.transformer.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.request.User; +import org.egov.common.models.household.*; +import org.egov.tracer.model.CustomException; +import org.egov.transformer.config.TransformerProperties; +import org.egov.transformer.http.client.ServiceRequestClient; +import org.egov.transformer.models.downstream.HouseholdIndexV1; +import org.egov.transformer.producer.Producer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +@Component +@Slf4j +public class HouseholdService { + private final TransformerProperties transformerProperties; + private final ServiceRequestClient serviceRequestClient; + private final Producer producer; + private final ObjectMapper objectMapper; + + public HouseholdService(TransformerProperties transformerProperties, ServiceRequestClient serviceRequestClient, Producer producer, ObjectMapper objectMapper) { + this.transformerProperties = transformerProperties; + this.serviceRequestClient = serviceRequestClient; + this.producer = producer; + this.objectMapper = objectMapper; + } + + public List searchHousehold(String clientRefId, String tenantId) { + HouseholdSearchRequest request = HouseholdSearchRequest.builder() + .requestInfo(RequestInfo.builder(). + userInfo(User.builder() + .uuid("transformer-uuid") + .build()) + .build()) + .household(HouseholdSearch.builder(). + clientReferenceId(Collections.singletonList(clientRefId)).build()) + .build(); + HouseholdBulkResponse response; + try { + StringBuilder uri = new StringBuilder(); + uri.append(transformerProperties.getHouseholdHost()) + .append(transformerProperties.getHouseholdSearchUrl()) + .append("?limit=").append(transformerProperties.getSearchApiLimit()) + .append("&offset=0") + .append("&tenantId=").append(tenantId); + response = serviceRequestClient.fetchResult(uri, + request, + HouseholdBulkResponse.class); + } catch (Exception e) { + log.error("error while fetching household {}", ExceptionUtils.getStackTrace(e)); + throw new CustomException("HOUSEHOLD_FETCH_ERROR", + "error while fetching household details for id: " + clientRefId); + } + return response.getHouseholds(); + } + + public void transform(List payloadList) { + String topic = transformerProperties.getTransformerProducerBulkHouseholdIndexV1Topic(); + log.info("transforming for ids {}", payloadList.stream() + .map(Household::getId).collect(Collectors.toList())); + List transformedPayloadList = payloadList.stream() + .map(this::transform) + .collect(Collectors.toList()); + if (!transformedPayloadList.isEmpty()) { + producer.push(topic, transformedPayloadList); + log.info("transformation successful"); + } + } + + public HouseholdIndexV1 transform(Household household) { + return HouseholdIndexV1.builder() + .household(household) + .geoPoint(getGeoPoint(household.getAddress())) + .build(); + } + + public List getGeoPoint(Address address) { + if (address == null || (address.getLongitude() == null && address.getLatitude() == null)) { + return null; + } + List geoPoints = new ArrayList<>(); + geoPoints.add(address.getLongitude()); + geoPoints.add(address.getLatitude()); + return geoPoints; + } + +} diff --git a/health-services/transformer/src/main/resources/application.properties b/health-services/transformer/src/main/resources/application.properties index bfa6972506b..87139a6b5e2 100644 --- a/health-services/transformer/src/main/resources/application.properties +++ b/health-services/transformer/src/main/resources/application.properties @@ -76,6 +76,9 @@ transformer.producer.bulk.stock.index.v1.topic=transformer-producer-bulk-stock-i transformer.consumer.create.service.topic=save-service transformer.producer.service.task.index.v1.topic=transformer-producer-service-task-index-v1-topic +transformer.producer.bulk.household.index.v1.topic=transformer-producer-household-index-v1-topic + + egov.project.host=http://localhost:8083 egov.search.project.url=/project/v1/_search From e9c1ffeb2762a8f9397be66c63fe554619b4c21d Mon Sep 17 00:00:00 2001 From: amitverma-egov Date: Thu, 15 Feb 2024 22:30:03 +0530 Subject: [PATCH 231/283] household topic name updated --- .../transformer/src/main/resources/application.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/transformer/src/main/resources/application.properties b/health-services/transformer/src/main/resources/application.properties index 87139a6b5e2..c3e13a3862f 100644 --- a/health-services/transformer/src/main/resources/application.properties +++ b/health-services/transformer/src/main/resources/application.properties @@ -76,7 +76,7 @@ transformer.producer.bulk.stock.index.v1.topic=transformer-producer-bulk-stock-i transformer.consumer.create.service.topic=save-service transformer.producer.service.task.index.v1.topic=transformer-producer-service-task-index-v1-topic -transformer.producer.bulk.household.index.v1.topic=transformer-producer-household-index-v1-topic +transformer.producer.bulk.household.index.v1.topic=transformer-producer-amp-household-index-v1-topic egov.project.host=http://localhost:8083 From 3f93a5dc7ac44025cb01fe178cc43d9f895571df Mon Sep 17 00:00:00 2001 From: amitverma-egov Date: Fri, 16 Feb 2024 10:58:45 +0530 Subject: [PATCH 232/283] added household urls --- .../transformer/src/main/resources/application.properties | 2 ++ 1 file changed, 2 insertions(+) diff --git a/health-services/transformer/src/main/resources/application.properties b/health-services/transformer/src/main/resources/application.properties index c3e13a3862f..a75a833a855 100644 --- a/health-services/transformer/src/main/resources/application.properties +++ b/health-services/transformer/src/main/resources/application.properties @@ -78,6 +78,8 @@ transformer.producer.service.task.index.v1.topic=transformer-producer-service-ta transformer.producer.bulk.household.index.v1.topic=transformer-producer-amp-household-index-v1-topic +egov.household.host=http://localhost:8904 +egov.search.household.url=/household/v1/_search egov.project.host=http://localhost:8083 egov.search.project.url=/project/v1/_search From fedf35c27b7a188c9de5cd2d1804c9eb8c69ab33 Mon Sep 17 00:00:00 2001 From: amitverma-egov Date: Fri, 16 Feb 2024 11:47:32 +0530 Subject: [PATCH 233/283] code refactoring and cleanup --- .../config/TransformerProperties.java | 6 ---- .../transformer/service/HouseholdService.java | 29 ------------------- .../src/main/resources/application.properties | 3 -- 3 files changed, 38 deletions(-) diff --git a/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java b/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java index ce7b7ba3b15..e837b143c8f 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java @@ -32,12 +32,6 @@ public class TransformerProperties { @Value("${transformer.producer.bulk.household.index.v1.topic}") private String transformerProducerBulkHouseholdIndexV1Topic; - @Value("${egov.household.host}") - private String householdHost; - - @Value("${egov.search.household.url}") - private String householdSearchUrl; - @Value("${egov.project.host}") private String projectHost; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/HouseholdService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/HouseholdService.java index 9ab928fcd59..18a3c44b8f2 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/HouseholdService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/HouseholdService.java @@ -34,35 +34,6 @@ public HouseholdService(TransformerProperties transformerProperties, ServiceRequ this.objectMapper = objectMapper; } - public List searchHousehold(String clientRefId, String tenantId) { - HouseholdSearchRequest request = HouseholdSearchRequest.builder() - .requestInfo(RequestInfo.builder(). - userInfo(User.builder() - .uuid("transformer-uuid") - .build()) - .build()) - .household(HouseholdSearch.builder(). - clientReferenceId(Collections.singletonList(clientRefId)).build()) - .build(); - HouseholdBulkResponse response; - try { - StringBuilder uri = new StringBuilder(); - uri.append(transformerProperties.getHouseholdHost()) - .append(transformerProperties.getHouseholdSearchUrl()) - .append("?limit=").append(transformerProperties.getSearchApiLimit()) - .append("&offset=0") - .append("&tenantId=").append(tenantId); - response = serviceRequestClient.fetchResult(uri, - request, - HouseholdBulkResponse.class); - } catch (Exception e) { - log.error("error while fetching household {}", ExceptionUtils.getStackTrace(e)); - throw new CustomException("HOUSEHOLD_FETCH_ERROR", - "error while fetching household details for id: " + clientRefId); - } - return response.getHouseholds(); - } - public void transform(List payloadList) { String topic = transformerProperties.getTransformerProducerBulkHouseholdIndexV1Topic(); log.info("transforming for ids {}", payloadList.stream() diff --git a/health-services/transformer/src/main/resources/application.properties b/health-services/transformer/src/main/resources/application.properties index a75a833a855..74c837dfc80 100644 --- a/health-services/transformer/src/main/resources/application.properties +++ b/health-services/transformer/src/main/resources/application.properties @@ -78,9 +78,6 @@ transformer.producer.service.task.index.v1.topic=transformer-producer-service-ta transformer.producer.bulk.household.index.v1.topic=transformer-producer-amp-household-index-v1-topic -egov.household.host=http://localhost:8904 -egov.search.household.url=/household/v1/_search - egov.project.host=http://localhost:8083 egov.search.project.url=/project/v1/_search From c266c49b6813e3d666b4ac0b4d2785bb14d88983 Mon Sep 17 00:00:00 2001 From: amitverma-egov Date: Fri, 16 Feb 2024 11:59:49 +0530 Subject: [PATCH 234/283] add geoPoint field to task --- .../models/downstream/ProjectTaskIndexV1.java | 4 ++++ .../service/ProjectTaskTransformationService.java | 13 +++++++++++++ 2 files changed, 17 insertions(+) diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ProjectTaskIndexV1.java b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ProjectTaskIndexV1.java index b72398700f3..9f86c868d2d 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ProjectTaskIndexV1.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ProjectTaskIndexV1.java @@ -7,6 +7,8 @@ import lombok.Data; import lombok.NoArgsConstructor; +import java.util.List; + @Data @AllArgsConstructor @NoArgsConstructor @@ -51,6 +53,8 @@ public class ProjectTaskIndexV1 { private Double longitude; @JsonProperty("createdBy") private String createdBy; + @JsonProperty("geoPoint") + private List geoPoint; @JsonProperty("lastModifiedBy") private String lastModifiedBy; @JsonProperty("createdTime") diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java index d4aa3898406..9b1f9b3ee3e 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java @@ -1,6 +1,7 @@ package org.egov.transformer.service; import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.project.Address; import org.egov.common.models.project.Task; import org.egov.transformer.config.TransformerProperties; import org.egov.transformer.enums.Operation; @@ -10,6 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; @@ -100,9 +102,20 @@ public List transform(Task task) { .createdBy(task.getAuditDetails().getCreatedBy()) .lastModifiedTime(task.getAuditDetails().getLastModifiedTime()) .lastModifiedBy(task.getAuditDetails().getLastModifiedBy()) + .geoPoint(getGeoPoint(task.getAddress())) .isDeleted(task.getIsDeleted()) .build() ).collect(Collectors.toList()); } + + public List getGeoPoint(Address address) { + if (address == null || (address.getLongitude() == null && address.getLatitude() == null)) { + return null; + } + List geoPoints = new ArrayList<>(); + geoPoints.add(address.getLongitude()); + geoPoints.add(address.getLatitude()); + return geoPoints; + } } } From eac4d30e446da77ff53d548cec52cd7eb0cb6e4f Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Mon, 19 Feb 2024 12:11:57 +0530 Subject: [PATCH 235/283] Revert "Household transformer amp demo" --- .../config/TransformerProperties.java | 3 - .../consumer/HouseholdConsumer.java | 39 ----------- .../models/downstream/HouseholdIndexV1.java | 23 ------- .../models/downstream/ProjectTaskIndexV1.java | 4 -- .../transformer/service/HouseholdService.java | 67 ------------------- .../ProjectTaskTransformationService.java | 13 ---- .../src/main/resources/application.properties | 2 - 7 files changed, 151 deletions(-) delete mode 100644 health-services/transformer/src/main/java/org/egov/transformer/consumer/HouseholdConsumer.java delete mode 100644 health-services/transformer/src/main/java/org/egov/transformer/models/downstream/HouseholdIndexV1.java delete mode 100644 health-services/transformer/src/main/java/org/egov/transformer/service/HouseholdService.java diff --git a/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java b/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java index e837b143c8f..2801294e64f 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java @@ -29,9 +29,6 @@ public class TransformerProperties { @Value("${transformer.producer.bulk.stock.index.v1.topic}") private String transformerProducerBulkStockIndexV1Topic; - @Value("${transformer.producer.bulk.household.index.v1.topic}") - private String transformerProducerBulkHouseholdIndexV1Topic; - @Value("${egov.project.host}") private String projectHost; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/consumer/HouseholdConsumer.java b/health-services/transformer/src/main/java/org/egov/transformer/consumer/HouseholdConsumer.java deleted file mode 100644 index ec08f474e01..00000000000 --- a/health-services/transformer/src/main/java/org/egov/transformer/consumer/HouseholdConsumer.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.egov.transformer.consumer; - -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.extern.slf4j.Slf4j; -import org.apache.kafka.clients.consumer.ConsumerRecord; -import org.egov.common.models.household.Household; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; -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.Arrays; -import java.util.List; -@Component -@Slf4j -public class HouseholdConsumer { - private final ObjectMapper objectMapper; - - @Autowired - public HouseholdConsumer(@Qualifier("objectMapper")ObjectMapper objectMapper) { - this.objectMapper = objectMapper; - } - - @KafkaListener(topics = { "${transformer.consumer.create.household.topic}", - "${transformer.consumer.update.household.topic}"}) - public void consumeHouseholds(ConsumerRecord payload, - @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { - try { - List households = Arrays.asList(objectMapper - .readValue((String) payload.value(), - Household[].class)); - } catch (Exception exception) { - log.error("error in household consumer", exception); - } - } - } - diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/HouseholdIndexV1.java b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/HouseholdIndexV1.java deleted file mode 100644 index 17fedcacdfa..00000000000 --- a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/HouseholdIndexV1.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.egov.transformer.models.downstream; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.models.household.Household; - -import java.util.List; - -@Data -@AllArgsConstructor -@NoArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class HouseholdIndexV1 { - @JsonProperty("household") - private Household household; - @JsonProperty("geoPoint") - private List geoPoint; -} \ No newline at end of file diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ProjectTaskIndexV1.java b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ProjectTaskIndexV1.java index 9f86c868d2d..b72398700f3 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ProjectTaskIndexV1.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ProjectTaskIndexV1.java @@ -7,8 +7,6 @@ import lombok.Data; import lombok.NoArgsConstructor; -import java.util.List; - @Data @AllArgsConstructor @NoArgsConstructor @@ -53,8 +51,6 @@ public class ProjectTaskIndexV1 { private Double longitude; @JsonProperty("createdBy") private String createdBy; - @JsonProperty("geoPoint") - private List geoPoint; @JsonProperty("lastModifiedBy") private String lastModifiedBy; @JsonProperty("createdTime") diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/HouseholdService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/HouseholdService.java deleted file mode 100644 index 18a3c44b8f2..00000000000 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/HouseholdService.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.egov.transformer.service; - -import com.fasterxml.jackson.databind.ObjectMapper; -import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.exception.ExceptionUtils; -import org.egov.common.contract.request.RequestInfo; -import org.egov.common.contract.request.User; -import org.egov.common.models.household.*; -import org.egov.tracer.model.CustomException; -import org.egov.transformer.config.TransformerProperties; -import org.egov.transformer.http.client.ServiceRequestClient; -import org.egov.transformer.models.downstream.HouseholdIndexV1; -import org.egov.transformer.producer.Producer; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - -@Component -@Slf4j -public class HouseholdService { - private final TransformerProperties transformerProperties; - private final ServiceRequestClient serviceRequestClient; - private final Producer producer; - private final ObjectMapper objectMapper; - - public HouseholdService(TransformerProperties transformerProperties, ServiceRequestClient serviceRequestClient, Producer producer, ObjectMapper objectMapper) { - this.transformerProperties = transformerProperties; - this.serviceRequestClient = serviceRequestClient; - this.producer = producer; - this.objectMapper = objectMapper; - } - - public void transform(List payloadList) { - String topic = transformerProperties.getTransformerProducerBulkHouseholdIndexV1Topic(); - log.info("transforming for ids {}", payloadList.stream() - .map(Household::getId).collect(Collectors.toList())); - List transformedPayloadList = payloadList.stream() - .map(this::transform) - .collect(Collectors.toList()); - if (!transformedPayloadList.isEmpty()) { - producer.push(topic, transformedPayloadList); - log.info("transformation successful"); - } - } - - public HouseholdIndexV1 transform(Household household) { - return HouseholdIndexV1.builder() - .household(household) - .geoPoint(getGeoPoint(household.getAddress())) - .build(); - } - - public List getGeoPoint(Address address) { - if (address == null || (address.getLongitude() == null && address.getLatitude() == null)) { - return null; - } - List geoPoints = new ArrayList<>(); - geoPoints.add(address.getLongitude()); - geoPoints.add(address.getLatitude()); - return geoPoints; - } - -} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java index 9b1f9b3ee3e..d4aa3898406 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java @@ -1,7 +1,6 @@ package org.egov.transformer.service; import lombok.extern.slf4j.Slf4j; -import org.egov.common.models.project.Address; import org.egov.common.models.project.Task; import org.egov.transformer.config.TransformerProperties; import org.egov.transformer.enums.Operation; @@ -11,7 +10,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; @@ -102,20 +100,9 @@ public List transform(Task task) { .createdBy(task.getAuditDetails().getCreatedBy()) .lastModifiedTime(task.getAuditDetails().getLastModifiedTime()) .lastModifiedBy(task.getAuditDetails().getLastModifiedBy()) - .geoPoint(getGeoPoint(task.getAddress())) .isDeleted(task.getIsDeleted()) .build() ).collect(Collectors.toList()); } - - public List getGeoPoint(Address address) { - if (address == null || (address.getLongitude() == null && address.getLatitude() == null)) { - return null; - } - List geoPoints = new ArrayList<>(); - geoPoints.add(address.getLongitude()); - geoPoints.add(address.getLatitude()); - return geoPoints; - } } } diff --git a/health-services/transformer/src/main/resources/application.properties b/health-services/transformer/src/main/resources/application.properties index 74c837dfc80..bfa6972506b 100644 --- a/health-services/transformer/src/main/resources/application.properties +++ b/health-services/transformer/src/main/resources/application.properties @@ -76,8 +76,6 @@ transformer.producer.bulk.stock.index.v1.topic=transformer-producer-bulk-stock-i transformer.consumer.create.service.topic=save-service transformer.producer.service.task.index.v1.topic=transformer-producer-service-task-index-v1-topic -transformer.producer.bulk.household.index.v1.topic=transformer-producer-amp-household-index-v1-topic - egov.project.host=http://localhost:8083 egov.search.project.url=/project/v1/_search From 69baa2050acfd1ad1a67882e59a9af509d195d14 Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Wed, 28 Feb 2024 17:29:09 +0530 Subject: [PATCH 236/283] dev to master - 28-02-24 (#654) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter * Project beneficiary tag cherrypick (#539) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * referral management project beneficiary validation fix * deleted persister and indexer file from project module resource folder --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * HH member clientrefid (#551) * adding clientRefId, Models version change, migration file * adding clientRefId for HouseholdMemberSearch as List * updated migration * adding Notnull for clientrefId --------- Co-authored-by: Vishal * Downsync smc referral module (#556) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Project beneficiary tag cherrypick (#549) * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * referral management project beneficiary validation fix --------- Co-authored-by: kanishq-egov Co-authored-by: Vishal * dummy api with same pagination response * dummy api with same pagination response * dummy api with same pagination response * downsync data test * data integrated till beneficiary * Update CHANGELOG.md * Delete health-services/project/src/main/resources/project-persistor.yml * skip on empty result added * skip on empty result added * beneficary searhc based on individual clientref id added * sideeffetc, ref, task fetch added * tasks earch fix * referral search fix --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * Dev downsync fix smc (#561) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: kanishq-egov * Dev master conflict fix (#562) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#563) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Dev master conflict fix (#565) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#566) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Added fix for testcases for householdmember (#570) Co-authored-by: kanishq-egov * updated the version, and added the changelog (#571) * updated the version, and added the changelog * updated ReferralManagement CHANGELOG * Update CHANGELOG.md --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * HLM-4062: removed pagination from fields excluding household api call * HLM-4062: missed in implementation (#574) * HLM-4062: missed in implementation * HLM-4062: default max is set to 1000 for not null limit value and 0 for offset value * project beneficiary tag update failed fix HLM-4444 * HLM-4444: added code review comments * sownsync bug fix for limit --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> * HLM-4444: project beneficiary update fix (#575) * Update CHANGELOG.md * updated changelog with dates (#577) * updated stock module changelog (#578) * Hlm 4501 smc referral flow (#602) * HLM-4501: Added changes for HFReferral flow * updated comments for common models * updated comments for common models removed ini file This reverts commit c1e226f961042f1162bb9ece8d2e1c01b62d220c. * HLM-4501: updated topics and hfreferal constants * HLM-4501: updated HFReferralService.java * HLM-4501: Added changes in project id validator * HLM-4501: updated HFReferralService.java * HLM-4501: fixed hfreferral changes * HLM-4501: added project facility id validator for hf_referral * HLM-4501: missing link for validator added * HLM-4501: updated HfrProjectFacilityIdValidator for NPE * HLM-4501 : updated hf referral symtoms character length to 256 * HLM-4501: updated additionalFields field value size from 2 to 1 * Hlm 3372 enhance inventory flow backend fixes (#623) * HLM-3372: added changes required to fix quantity, Sender Receiver enum * HLM-3372: Sender and Receiver id validator * HLM-3372: updated all reference for SenderType and Receiver Type enum * HLM-3372: stock model updated, removed size annotations from referenceidtype enum field * HLM-3372: Min validation added for integer type of quantity * HLM-3372: test cases updated * HLM-5004 Added max value and decimal condition for quantity in stock, added component and order annotation for SSenderIdReceiverIdEqualsValidator * HLM-5004 Custom JsonDeserializer validator IntegerValidator added in health-services-models * hlm-5004 added custom exception and a custom exception handler to handle the integer validator exception * hlm-5004 optimized imports and added code comments * hlm-5004 CustomIntegerSerializer added and unnecessary validators removed * hlm-5004 Registered the CustomIntegerDeserializer with objectMapper for Integer class * hlm-5004 Removed line of code that was removing all the invalid entities from the list in SSenderIdReceiverIdEqualsValidator * hlm-5004 changes in test configurations and optimized imports * hlm-5004 added row version validator for stock delete * hlm-5004 dateOfEntry field was handled in StockRowMapper to return null if no value is present and description was added to stock contact for transactionReason * updated pom.xml for health campaign models * Revert "updated pom.xml for health campaign models" This reverts commit 035c78720c610916000c8de76fa87e7904774b59. --------- Co-authored-by: syed-egov * Hlm 4501 smc referral flow code comments (#636) * Dev to master : beneficiary tag bug fix, downsync pagination fix (#576) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter * Project beneficiary tag cherrypick (#539) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * referral management project beneficiary validation fix * deleted persister and indexer file from project module resource folder --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * HH member clientrefid (#551) * adding clientRefId, Models version change, migration file * adding clientRefId for HouseholdMemberSearch as List * updated migration * adding Notnull for clientrefId --------- Co-authored-by: Vishal * Downsync smc referral module (#556) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Project beneficiary tag cherrypick (#549) * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * referral management project beneficiary validation fix --------- Co-authored-by: kanishq-egov Co-authored-by: Vishal * dummy api with same pagination response * dummy api with same pagination response * dummy api with same pagination response * downsync data test * data integrated till beneficiary * Update CHANGELOG.md * Delete health-services/project/src/main/resources/project-persistor.yml * skip on empty result added * skip on empty result added * beneficary searhc based on individual clientref id added * sideeffetc, ref, task fetch added * tasks earch fix * referral search fix --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * Dev downsync fix smc (#561) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: kanishq-egov * Dev master conflict fix (#562) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#563) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Dev master conflict fix (#565) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#566) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Added fix for testcases for householdmember (#570) Co-authored-by: kanishq-egov * updated the version, and added the changelog (#571) * updated the version, and added the changelog * updated ReferralManagement CHANGELOG * Update CHANGELOG.md --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * HLM-4062: removed pagination from fields excluding household api call * HLM-4062: missed in implementation (#574) * HLM-4062: missed in implementation * HLM-4062: default max is set to 1000 for not null limit value and 0 for offset value * project beneficiary tag update failed fix HLM-4444 * HLM-4444: added code review comments * sownsync bug fix for limit --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> * HLM-4444: project beneficiary update fix (#575) * Update CHANGELOG.md * updated changelog with dates (#577) * updated stock module changelog (#578) --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: bhanu prakash <109132521+bhanuprakash-egov@users.noreply.github.com> Co-authored-by: Naveen J <83631045+naveen-egov@users.noreply.github.com> Co-authored-by: talele08 * Referral and Side effect sequence diagram * HLM-4501: Added changes for HFReferral flow * updated comments for common models * updated comments for common models removed ini file This reverts commit c1e226f961042f1162bb9ece8d2e1c01b62d220c. * HLM-4501: updated topics and hfreferal constants * HLM-4501: updated HFReferralService.java * HLM-4501: Added changes in project id validator * HLM-4501: updated HFReferralService.java * HLM-4501: fixed hfreferral changes * HLM-4501: added project facility id validator for hf_referral * HLM-4501: missing link for validator added * HLM-4501: updated HfrProjectFacilityIdValidator for NPE * HLM-4501 : updated hf referral symtoms character length to 256 * HLM-4501: updated additionalFields field value size from 2 to 1 * HLM-4501: added code comments for all hf referral related classes * HLM-4501: hf-referral sequence diagram --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: bhanu prakash <109132521+bhanuprakash-egov@users.noreply.github.com> Co-authored-by: Naveen J <83631045+naveen-egov@users.noreply.github.com> Co-authored-by: talele08 * HLM-4496, HLM-4207 attendance module (#616) * HLM-4496: Added attendance module in HCM * HLM-4496: updated attendance directory, removed target folder and imi file * buil config added for hlm-4496 in feature branch * HLM-4207: offline enablement in attendance log * HLM-4207: added db migration script * HLM-4207: updated db migration script * HLM-4207: updated incorrect statements * HLM-4207: bulk api support, without redis cache * HLM-4207: updated Attendancelog consumer for bulk api * HLM-4207: consumer fix * HLM-4207: cache support added for attendance log create and update * HLM-4207: added health-individual endpoint * HLM-4207: added radis host * HLM-4207: updated qualified for objectmapper in attendance module * HLM-4496,HLM-4207: updated application.properties for redis config * HLM-4207: updated kafka listener topics * HLM-4207: changed kafka config * HLM-4894 adding hrms related flag to Individual object, adding another ApiOperation * HLM-4894 adding hrms related flag to Individual object, adding another ApiOperation * HLM-4207, HLM-4986, HLM-4987 : bug fix * HLM-4894 adding changes related to linking of HRMS Employee with Individual * HLM-4894 adding changes related to linking of HRMS Employee with Individual * HLM-4207: added clientreferenceid search, null check for document id * HLM-4894 reverting changes related to linking of HRMS Employee with Individual * HLM-4894 reverting changes related to linking of HRMS Employee with Individual from libraries, common-models * HLM-4207: code re-format * HLM-4894 adding changes for managing attendees while enrollment * HLM-4207: updated attendance search, register id or clientreference id are mandatory * hlm-5009 staffId in ProjectStaffSearch changed to list from string * HLM-4894 updating build config * HLM-4207: clientReferenceIds is changed to clientReferenceId for Attendance Log search criteria * HLM-4207: removed staff validation for search without register id * HLM-4894 adding changes for project staff validation * HLM-4894 adding @Qualifier annotation for object mapper * HLM-4894 fixing hrms url * HLM-4771: added changes for updating the registers on project date update * HLM-4771: project update changes * HLM-4771: updated the project start date update validation, can not update start date if it is already started * HLM-4771: updated attendance register consumer and service with comments * HLM-4771: updated the tenant id * HLM-4894 updating environment variables. * HLM-4894 updating code changes * HLM-4894 adding code changes * HLM-4894 adding code changes * HLM-4894 adding code changes * HLM-4771: updated the project validators, validation for start and end date of project * HLM-4894 adding useruuid as search param in individual search * HLM-4894 adding useruuid as search param in individual search * HLM-4894 adding useruuid as search param in individual search * HLM-4894 adding changes for registry creation when supervisor enrolls * HLM-4496, HLM-4894: first staff enrollment on attendance register creation is optional * HLM-4894 adding changes attendee enrollment * HLM-4894 adding changes for making staffId as list of staffId in ProjectStaffSearch * HLM-4894 adding changes for making staffId as list of staffId in ProjectStaffSearch * HLM-4894 adding changes for making staffId as list of staffId in ProjectStaffSearch * HLM-4894 removing staff-bulk-create-topic * HLM-4894 removing staff-bulk-create-topic * HLM-4894 removing staff-bulk-create-topic * HLM-4894 removing staff-bulk-create-topic * HLM-4894 changing health-attendance consumer group-id * HLM-4894 adding changes for projectstaff consumer * HLM-4894 adding changes for projectstaff consumer * HLM-4894 adding changes for projectstaff consumer * HLM-4894 adding changes for projectstaff consumer * HLM-4894 adding changes for projectstaff consumer * HLM-5045: added changes, project start date and end date difference should at least be 1 day. * HLM-4894 adding comments * HLM-4894 adding additional Details during attendance register creation * HLM-4894 adding additional Details during attendance register creation * hlm-4496 : bug fix on adding staff on updation of register * HLM-4894 increasing limit to 1000 * Added changelog for individual, health-services-models, project, stock * HLM-4496 : remove attendance module as it is moved to DIGIT-Works repository. * HLM-5076: added changes related to project module * updated individual user uuid search field for hlm-4496, hlm-4207 * changed common models build to 1.0.19-SNAPSHOT --------- Co-authored-by: Priyanka-eGov Co-authored-by: syed-egov Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * Hlm 4496 individual UUID search (#656) * HLM-4496: updated changedlog for individual, health-services-models, project, referralmanagement * HLM-4496: Added size annotations on individual search userUuid field * hlm-4496: Revert of application.properties changes * updated pom.xml version for individual, project, referralmanagement, stock (#657) --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: bhanu prakash <109132521+bhanuprakash-egov@users.noreply.github.com> Co-authored-by: Naveen J <83631045+naveen-egov@users.noreply.github.com> Co-authored-by: talele08 Co-authored-by: syed-egov Co-authored-by: Priyanka-eGov --- build/build-config.yml | 2 +- docs/health-api-specs/contracts/stock.yml | 1 + .../hfreferral/bulk_create.puml | 140 ++++++++++ .../hfreferral/bulk_delete.puml | 153 ++++++++++ .../hfreferral/bulk_update.puml | 205 ++++++++++++++ .../referralmanagement/hfreferral/create.puml | 137 +++++++++ .../referralmanagement/hfreferral/delete.puml | 143 ++++++++++ .../referralmanagement/hfreferral/update.puml | 196 +++++++++++++ .../referral/bulk_create.puml | 204 ++++++++++++++ .../referral/bulk_delete.puml | 133 +++++++++ .../referral/bulk_update.puml | 245 ++++++++++++++++ .../referralmanagement/referral/create.puml | 201 +++++++++++++ .../referralmanagement/referral/delete.puml | 124 +++++++++ .../referralmanagement/referral/update.puml | 237 ++++++++++++++++ .../side-effect/bulk_create.puml | 141 ++++++++++ .../side-effect/bulk_delete.puml | 125 +++++++++ .../side-effect/bulk_update.puml | 177 ++++++++++++ .../side-effect/create.puml | 140 ++++++++++ .../side-effect/delete.puml | 123 ++++++++ .../side-effect/update.puml | 175 ++++++++++++ health-services/individual/CHANGELOG.md | 3 + health-services/individual/pom.xml | 2 +- .../repository/IndividualRepository.java | 9 + .../web/models/IndividualSearch.java | 6 + .../helper/IndividualSearchTestBuilder.java | 10 + .../repository/IndividualRepositoryTest.java | 2 + .../health-services-models/CHANGELOG.md | 8 + .../libraries/health-services-models/pom.xml | 7 +- .../validator/CustomIntegerDeserializer.java | 43 +++ .../egov/common/models/facility/Field.java | 8 +- .../egov/common/models/household/Field.java | 27 +- .../egov/common/models/individual/Field.java | 27 +- .../models/individual/IndividualSearch.java | 5 + .../org/egov/common/models/product/Field.java | 27 +- .../org/egov/common/models/project/Field.java | 12 +- .../models/project/ProjectStaffSearch.java | 18 +- .../hfreferral/HFReferral.java | 84 ++++++ .../hfreferral/HFReferralBulkRequest.java | 46 +++ .../hfreferral/HFReferralBulkResponse.java | 44 +++ .../hfreferral/HFReferralRequest.java | 27 ++ .../hfreferral/HFReferralResponse.java | 27 ++ .../hfreferral/HFReferralSearch.java | 45 +++ .../hfreferral/HFReferralSearchRequest.java | 26 ++ .../org/egov/common/models/stock/Field.java | 27 +- .../common/models/stock/ReferenceIdType.java | 32 +++ .../models/stock/SenderReceiverType.java | 34 +++ .../org/egov/common/models/stock/Stock.java | 27 +- health-services/project/CHANGELOG.md | 4 + health-services/project/pom.xml | 2 +- .../project/config/ProjectConfiguration.java | 3 + .../project/service/ProjectStaffService.java | 12 +- .../java/org/egov/project/util/MDMSUtils.java | 31 ++- .../egov/project/util/ProjectConstants.java | 4 + .../validator/project/ProjectValidator.java | 146 +++++++++- .../web/models/ProjectStaffSearch.java | 3 +- .../src/main/resources/application.properties | 4 + .../ProjectStaffServiceSearchTest.java | 2 +- .../referralmanagement/CHANGELOG.md | 3 + health-services/referralmanagement/pom.xml | 4 +- .../egov/referralmanagement/Constants.java | 2 + .../ReferralManagementConfiguration.java | 24 ++ .../consumer/HFReferralConsumer.java | 110 ++++++++ .../repository/HFReferralRepository.java | 151 ++++++++++ .../rowmapper/HFReferralRowMapper.java | 78 ++++++ .../service/HFReferralService.java | 263 ++++++++++++++++++ .../HFReferralEnrichmentService.java | 57 ++++ .../hfreferral/HfrIsDeletedValidator.java | 45 +++ .../HfrNonExistentEntityValidator.java | 80 ++++++ .../hfreferral/HfrNullIdValidator.java | 38 +++ .../HfrProjectFacilityIdValidator.java | 134 +++++++++ .../hfreferral/HfrProjectIdValidator.java | 131 +++++++++ .../hfreferral/HfrRowVersionValidator.java | 74 +++++ .../hfreferral/HfrUniqueEntityValidator.java | 65 +++++ .../controllers/HFReferralApiController.java | 193 +++++++++++++ .../src/main/resources/application.properties | 12 +- ...20231214113400__hf_referral_create_ddl.sql | 25 ++ ...f_referral_project_facility_rename_ddl.sql | 1 + health-services/stock/CHANGELOG.md | 3 + health-services/stock/pom.xml | 4 +- .../egov/stock/config/MainConfiguration.java | 9 +- .../repository/rowmapper/StockRowMapper.java | 14 +- .../egov/stock/service/FacilityService.java | 5 +- .../org/egov/stock/service/StockService.java | 6 +- .../org/egov/stock/util/ValidatorUtil.java | 56 ++-- .../stock/SReferenceIdValidator.java | 8 +- .../SSenderIdReceiverIdEqualsValidator.java | 75 +++++ .../org/egov/stock/TestConfiguration.java | 16 ++ .../egov/stock/helper/StockTestBuilder.java | 13 +- 88 files changed, 5370 insertions(+), 175 deletions(-) create mode 100644 docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_create.puml create mode 100644 docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_delete.puml create mode 100644 docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_update.puml create mode 100644 docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/create.puml create mode 100644 docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/delete.puml create mode 100644 docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/update.puml create mode 100644 docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_create.puml create mode 100644 docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_delete.puml create mode 100644 docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_update.puml create mode 100644 docs/health-api-specs/sequence-diagrams/referralmanagement/referral/create.puml create mode 100644 docs/health-api-specs/sequence-diagrams/referralmanagement/referral/delete.puml create mode 100644 docs/health-api-specs/sequence-diagrams/referralmanagement/referral/update.puml create mode 100644 docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_create.puml create mode 100644 docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_delete.puml create mode 100644 docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_update.puml create mode 100644 docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/create.puml create mode 100644 docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/delete.puml create mode 100644 docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/update.puml create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/validator/CustomIntegerDeserializer.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferral.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkRequest.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkResponse.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralRequest.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralResponse.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearch.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearchRequest.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/ReferenceIdType.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/SenderReceiverType.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/HFReferralConsumer.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HFReferralRowMapper.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/HFReferralService.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/HFReferralEnrichmentService.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrIsDeletedValidator.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNonExistentEntityValidator.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNullIdValidator.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrProjectFacilityIdValidator.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrProjectIdValidator.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrRowVersionValidator.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrUniqueEntityValidator.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/HFReferralApiController.java create mode 100644 health-services/referralmanagement/src/main/resources/db/migration/main/V20231214113400__hf_referral_create_ddl.sql create mode 100644 health-services/referralmanagement/src/main/resources/db/migration/main/V20240103142200__hf_referral_project_facility_rename_ddl.sql create mode 100644 health-services/stock/src/main/java/org/egov/stock/validator/stock/SSenderIdReceiverIdEqualsValidator.java diff --git a/build/build-config.yml b/build/build-config.yml index 235f7b72caa..13bc1db43fa 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -89,7 +89,7 @@ config: build: - work-dir: "core-services/error-handler" image-name: "error-handler" - dockerfile: "build/maven/Dockerfile" + dockerfile: "build/maven/Dockerfile" - name: "builds/health-campaign-services/core-services/dashboard-analytics" build: - work-dir: "core-services/dashboard-analytics" diff --git a/docs/health-api-specs/contracts/stock.yml b/docs/health-api-specs/contracts/stock.yml index d2df236940d..2ee5512df51 100644 --- a/docs/health-api-specs/contracts/stock.yml +++ b/docs/health-api-specs/contracts/stock.yml @@ -504,6 +504,7 @@ definitions: - LOST_IN_TRANSIT - DAMAGED_IN_STORAGE - DAMAGED_IN_TRANSIT + description: This field accepts values from enum and if an invalid value is provided, it will default to null. wayBillNumber: type: string minLength: 2 diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_create.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_create.puml new file mode 100644 index 00000000000..031f8b42e19 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_create.puml @@ -0,0 +1,140 @@ +@startuml +title HFReferral - Bulk Create +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant FacilityService as fs +participant ProjectService as ps +participant RedisCache as rc +queue Kafka as k +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el +database Database as db + +c -> rm : /referralmanagement/hf-referral/v1/bulk/_create +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: HFReferral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +loop for each hfReferral + alt record already exists + alt record found in cache + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 1 row + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note + end + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Check if record already exists + activate db + db -> rm: 1 row + deactivate db + rm -> rc: Put data in cache using clientReferenceId/serverGeneratedId + activate rc + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note + end + alt projectId invalid + rm -> ps: Check if projectId exists + activate ps + ps -> db: Check if projectId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> ps: Check if projectId exists + activate ps + ps -> db: Check if projectId exists + activate db + db -> ps: n row + deactivate db + ps -> rm: n row + deactivate ps + alt projectFacilityId invalid + rm -> ps: Check if projectFacilityId exists + activate ps + ps -> db: Check if projectFacilityId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> ps: Check if projectFacilityId exists + activate ps + ps -> db: Check if projectFacilityId exists + activate db + db -> ps: n row + deactivate db + ps -> rm: n row + deactivate ps + rm -> k: HFReferral Data /persist_topic + activate k + rm -> rc: Put HFReferral Data against clientReferenceId/serverGeneratedId in cache + activate rc + deactivate rc + group async + prs -> k: Consume HFReferral Data + activate prs + idx -> k: Consume HFReferral Data + activate idx + idx -> el: Store HFReferral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist HFReferral Data + activate db + deactivate db + deactivate prs + end + deactivate k +end + +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_delete.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_delete.puml new file mode 100644 index 00000000000..0f8eab2fa9b --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_delete.puml @@ -0,0 +1,153 @@ +@startuml +title HFReferral - Bulk Delete +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant RedisCache as rc +queue Kafka as k +database Database as db +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant UserService as us +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el + +c -> rm : /referralmanagement/hf-referral/v1/bulk/_delete +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: HFReferral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +loop for each hfReferral + alt id is null + rm -> rm: Check if HFReferral object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note + end + rm -> rm: Check if HFReferral id is not null + alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: HFReferral Data /error_topic + activate k + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + s -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note + end + alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc + end + rm -> rc: Fetch the existing record + activate rc + rc -> rm: 1 row + deactivate rc + alt Duplicate Entry is present [Unique entity validation failed] + rm -> rm: Check if HFReferral object isDeleted is true + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: IS_DELETED_TRUE + end note + end + rm -> rm: Duplicate Entry is not present [Unique entity validation successful] + alt incorrect rowVersion + s -> s: Compare rowVersion between request and db + s -> s: Incorrect rowVersion [request: should be +1 only] + s -> k: HFReferral Data /error_topic + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + s -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: BAD_REQUEST + end note + end + s -> s: Compare rowVersion between request and db + s -> s: rowVersion in request = rowVersion in db + 1 + rm -> k: HFReferral Data /persist_topic + activate k + rm -> rc: Put HFReferral Data against clientReferenceId/serverGeneratedId in cache + activate rc + deactivate rc + group async + prs -> k: Consume HFReferral Data + activate prs + idx -> k: Consume HFReferral Data + activate idx + idx -> el: Store HFReferral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist HFReferral Data + activate db + deactivate db + deactivate prs + end + deactivate k +end +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_update.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_update.puml new file mode 100644 index 00000000000..693993065b6 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/bulk_update.puml @@ -0,0 +1,205 @@ +@startuml +title HFReferral - Bulk Update +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant RedisCache as rc +queue Kafka as k +database Database as db +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant UserService as us +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el + +c -> rm : /referralmanagement/hf-referral/v1/bulk/_update +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: HFReferral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +loop for each hfReferral + alt id is null + rm -> rm: Check if HFReferral object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note + end + rm -> rm: Check if HFReferral id is not null + alt isDeleted is true + rm -> rm: Check if HFReferral object isDeleted is true + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: IS_DELETED_TRUE + end note + end + rm -> rm: Check if HFReferral object isDeleted is not true + alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: HFReferral Data /error_topic + activate k + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note + end + alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: n row + deactivate db + rm -> rc: n record + activate rc + deactivate rc + end + rm -> rc: Fetch the existing record + activate rc + rc -> rm: n row + deactivate rc + alt projectId invalid + rm -> ps: Check if projectId exists + activate ps + ps -> db: Check if projectId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> ps: Check if projectId exists + activate ps + ps -> db: Check if projectId exists + activate db + db -> ps: n row + deactivate db + ps -> rm: n row + deactivate ps + alt projectFacilityId invalid + rm -> ps: Check if projectFacilityId exists + activate ps + ps -> db: Check if projectFacilityId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> ps: Check if projectFacilityId exists + activate ps + ps -> db: Check if projectFacilityId exists + activate db + db -> ps: n row + deactivate db + ps -> rm: n row + deactivate ps + alt Duplicate Entry is present [Unique entity validation failed] + rm -> rm: Check if HFReferral object isDeleted is true + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: IS_DELETED_TRUE + end note + end + rm -> rm: Duplicate Entry is not present [Unique entity validation successful] + alt incorrect rowVersion + s -> s: Compare rowVersion between request and db + s -> s: Incorrect rowVersion [request: should be +1 only] + s -> k: HFReferral Data /error_topic + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + s -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: BAD_REQUEST + end note + end + s -> s: Compare rowVersion between request and db + s -> s: rowVersion in request = rowVersion in db + 1 + rm -> k: HFReferral Data /persist_topic + activate k + rm -> rc: Put HFReferral Data against clientReferenceId/serverGeneratedId in cache + activate rc + deactivate rc + group async + prs -> k: Consume HFReferral Data + activate prs + idx -> k: Consume HFReferral Data + activate idx + idx -> el: Store HFReferral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist HFReferral Data + activate db + deactivate db + deactivate prs + end + deactivate k +end +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/create.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/create.puml new file mode 100644 index 00000000000..b83117a4e43 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/create.puml @@ -0,0 +1,137 @@ +@startuml +title HFReferral - Create +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant FacilityService as fs +participant ProjectService as ps +participant RedisCache as rc +queue Kafka as k +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el +database Database as db + +c -> rm : /referralmanagement/hf-referral/v1/_create +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: HFReferral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +alt record already exists + alt record found in cache + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 1 row + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note + end + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Check if record already exists + activate db + db -> rm: 1 row + deactivate db + rm -> rc: Put data in cache using clientReferenceId/serverGeneratedId + activate rc + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note +end +alt projectId invalid + rm -> ps: Check if projectId exists + activate ps + ps -> db: Check if projectId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> ps: Check if projectId exists +activate ps +ps -> db: Check if projectId exists +activate db +db -> ps: 1 row +deactivate db +ps -> rm: 1 row +deactivate ps +alt projectFacilityId invalid + rm -> ps: Check if projectFacilityId exists + activate ps + ps -> db: Check if projectFacilityId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> ps: Check if projectFacilityId exists +activate ps +ps -> db: Check if projectFacilityId exists +activate db +db -> ps: 1 row +deactivate db +ps -> rm: 1 row +deactivate ps +rm -> k: HFReferral Data /persist_topic +activate k +rm -> rc: Put HFReferral Data against clientReferenceId/serverGeneratedId in cache +activate rc +deactivate rc +group async + prs -> k: Consume HFReferral Data + activate prs + idx -> k: Consume HFReferral Data + activate idx + idx -> el: Store HFReferral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist HFReferral Data + activate db + deactivate db + deactivate prs +end +deactivate k +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/delete.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/delete.puml new file mode 100644 index 00000000000..e5d460e53b0 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/delete.puml @@ -0,0 +1,143 @@ +@startuml +title HFReferral - Delete +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant RedisCache as rc +queue Kafka as k +database Database as db +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant UserService as us +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el + +c -> rm : /referralmanagement/hf-referral/v1/_delete +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: HFReferral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +alt id is null + rm -> rm: Check if HFReferral object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note +end +rm -> rm: Check if HFReferral id is not null +alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: HFReferral Data /error_topic + activate k + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + s -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note +end +alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc +end +rm -> rc: Fetch the existing record +activate rc +rc -> rm: 1 row +deactivate rc +alt incorrect rowVersion + s -> s: Compare rowVersion between request and db + s -> s: Incorrect rowVersion [request: should be +1 only] + s -> k: HFReferral Data /error_topic + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + s -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: BAD_REQUEST + end note +end +s -> s: Compare rowVersion between request and db +s -> s: rowVersion in request = rowVersion in db + 1 +rm -> k: HFReferral Data /persist_topic +activate k +rm -> rc: Put HFReferral Data against clientReferenceId/serverGeneratedId in cache +activate rc +deactivate rc +group async + prs -> k: Consume HFReferral Data + activate prs + idx -> k: Consume HFReferral Data + activate idx + idx -> el: Store HFReferral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist HFReferral Data + activate db + deactivate db + deactivate prs +end +deactivate k +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/update.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/update.puml new file mode 100644 index 00000000000..b9db19c7578 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/hfreferral/update.puml @@ -0,0 +1,196 @@ +@startuml +title HFReferral - Update +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant RedisCache as rc +queue Kafka as k +database Database as db +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant UserService as us +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el + +c -> rm : /referralmanagement/hf-referral/v1/_update +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: HFReferral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +alt id is null + rm -> rm: Check if HFReferral object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note +end +rm -> rm: Check if HFReferral id is not null +alt isDeleted is true + rm -> rm: Check if HFReferral object isDeleted is true + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: IS_DELETED_TRUE + end note +end +rm -> rm: Check if HFReferral object isDeleted is not true +alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: HFReferral Data /error_topic + activate k + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note +end +alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc +end +rm -> rc: Fetch the existing record +activate rc +rc -> rm: 1 row +deactivate rc +alt projectId invalid + rm -> ps: Check if projectId exists + activate ps + ps -> db: Check if projectId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> ps: Check if projectId exists +activate ps +ps -> db: Check if projectId exists +activate db +db -> ps: n row +deactivate db +ps -> rm: n row +deactivate ps +alt projectFacilityId invalid + rm -> ps: Check if projectFacilityId exists + activate ps + ps -> db: Check if projectFacilityId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> ps: Check if projectFacilityId exists +activate ps +ps -> db: Check if projectFacilityId exists +activate db +db -> ps: n row +deactivate db +ps -> rm: n row +deactivate ps +alt incorrect rowVersion + s -> s: Compare rowVersion between request and db + s -> s: Incorrect rowVersion [request: should be +1 only] + s -> k: HFReferral Data /error_topic + group async + es -> k: Consume HFReferral Data + activate es + deactivate k + es -> db: Persist HFReferral Data /error_table + activate db + deactivate db + deactivate es + end + s -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: BAD_REQUEST + end note +end +s -> s: Compare rowVersion between request and db +s -> s: rowVersion in request = rowVersion in db + 1 +rm -> k: HFReferral Data /persist_topic +activate k +rm -> rc: Put HFReferral Data against clientReferenceId/serverGeneratedId in cache +activate rc +deactivate rc +group async + prs -> k: Consume HFReferral Data + activate prs + idx -> k: Consume HFReferral Data + activate idx + idx -> el: Store HFReferral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist HFReferral Data + activate db + deactivate db + deactivate prs +end +deactivate k + +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_create.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_create.puml new file mode 100644 index 00000000000..ad7d70f7540 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_create.puml @@ -0,0 +1,204 @@ +@startuml +title Referral - Bulk Create +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant UserService as us +participant RedisCache as rc +queue Kafka as k +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el +database Database as db + +c -> rm : /referralmanagement/v1/bulk/_create +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Referral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Referral Data + activate es + deactivate k + es -> db: Persist Referral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +loop for each referral + alt record already exists + alt record found in cache + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 1 row + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note + end + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Check if record already exists + activate db + db -> rm: 1 row + deactivate db + rm -> rc: Put data in cache using clientReferenceId/serverGeneratedId + activate rc + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note + end + alt projectBeneficiaryId invalid + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 1 row + deactivate db + ps -> rm: 1 row + deactivate ps + alt referrerId invalid + rm -> us: Check if referrerId exists + activate us + us -> db: Check if referrerId exists + activate db + db -> us: 0 rows + deactivate db + us -> rm: 0 rows + deactivate us + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> us: Check if referrerId exists + activate us + us -> db: Check if referrerId exists + activate db + db -> us: 1 row + deactivate db + us -> rm: 1 row + deactivate us + alt recipientId invalid + alt recipientType is STAFF + rm -> us: Check if recipientId exists + activate us + us -> db: Check if recipientId exists + activate db + db -> us: 0 rows + deactivate db + us -> rm: 0 rows + deactivate us + end + alt recipientType is FACILITY + rm -> fs: Check if recipientId exists + activate fs + fs -> db: Check if recipientId exists + activate db + db -> fs: 0 rows + deactivate db + fs -> rm: 0 rows + deactivate fs + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + alt recipientType is STAFF + rm -> us: Check if recipientId exists + activate us + us -> db: Check if recipientId exists + activate db + db -> us: 1 row + deactivate db + us -> rm: 1 row + deactivate us + end + alt recipientType is FACILITY + rm -> fs: Check if recipientId exists + activate fs + fs -> db: Check if recipientId exists + activate db + db -> fs: 1 row + deactivate db + fs -> rm: 1 row + deactivate fs + end + alt sideEffectId invalid + rm -> db: Check if sideEffectId exists + activate db + db -> rm: 0 rows + deactivate db + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> db: Check if referrerId exists + activate db + db -> rm: 1 row + deactivate db + + rm -> k: Referral Data /persist_topic + activate k + rm -> rc: Put Referral Data against clientReferenceId/serverGeneratedId in cache + activate rc + deactivate rc + group async + prs -> k: Consume Referral Data + activate prs + idx -> k: Consume Referral Data + activate idx + idx -> el: Store Referral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Referral Data + activate db + deactivate db + deactivate prs + end + deactivate k +end + +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_delete.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_delete.puml new file mode 100644 index 00000000000..38aae93d8b3 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_delete.puml @@ -0,0 +1,133 @@ +@startuml +title Referral - Bulk Delete +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant RedisCache as rc +queue Kafka as k +database Database as db +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant UserService as us +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el + +c -> rm : /referralmanagement/v1/bulk/_delete +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Referral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Referral Data + activate es + deactivate k + es -> db: Persist Referral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +loop for each referral + alt id is null + rm -> rm: Check if Referral object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note + end + rm -> rm: Check if Referral id is not null + alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: Referral Data /error_topic + activate k + group async + es -> k: Consume Referral Data + activate es + deactivate k + es -> db: Persist Referral Data /error_table + activate db + deactivate db + deactivate es + end + s -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note + end + alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc + end + rm -> rc: Fetch the existing record + activate rc + rc -> rm: 1 row + deactivate rc + alt Duplicate Entry is present [Unique entity validation failed] + rm -> rm: Check if Side Effect object isDeleted is true + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: IS_DELETED_TRUE + end note + end + rm -> rm: Duplicate Entry is not present [Unique entity validation successful] + rm -> k: Referral Data /persist_topic + activate k + rm -> rc: Put Referral Data against clientReferenceId/serverGeneratedId in cache + activate rc + deactivate rc + group async + prs -> k: Consume Referral Data + activate prs + idx -> k: Consume Referral Data + activate idx + idx -> el: Store Referral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Referral Data + activate db + deactivate db + deactivate prs + end + deactivate k +end +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_update.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_update.puml new file mode 100644 index 00000000000..10d2b662106 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/bulk_update.puml @@ -0,0 +1,245 @@ +@startuml +title Referral - Bulk Update +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant RedisCache as rc +queue Kafka as k +database Database as db +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant UserService as us +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el + +c -> rm : /referralmanagement/v1/bulk/_update +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Referral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Referral Data + activate es + deactivate k + es -> db: Persist Referral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +loop for each referral + alt id is null + rm -> rm: Check if Referral object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note + end + rm -> rm: Check if Referral id is not null + alt isDeleted is true + rm -> rm: Check if Referral object isDeleted is true + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: IS_DELETED_TRUE + end note + end + rm -> rm: Check if Referral object isDeleted is not true + alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: Referral Data /error_topic + activate k + group async + es -> k: Consume Referral Data + activate es + deactivate k + es -> db: Persist Referral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note + end + alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc + end + rm -> rc: Fetch the existing record + activate rc + rc -> rm: 1 row + deactivate rc + alt projectBeneficiaryId invalid + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 1 row + deactivate db + ps -> rm: 1 row + deactivate ps + alt referrerId invalid + rm -> us: Check if referrerId exists + activate us + us -> db: Check if referrerId exists + activate db + db -> us: 0 rows + deactivate db + us -> rm: 0 rows + deactivate us + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> us: Check if referrerId exists + activate us + us -> db: Check if referrerId exists + activate db + db -> us: 1 row + deactivate db + us -> rm: 1 row + deactivate us + alt recipientId invalid + alt recipientType is STAFF + rm -> us: Check if recipientId exists + activate us + us -> db: Check if recipientId exists + activate db + db -> us: 0 rows + deactivate db + us -> rm: 0 rows + deactivate us + end + alt recipientType is FACILITY + rm -> fs: Check if recipientId exists + activate fs + fs -> db: Check if recipientId exists + activate db + db -> fs: 0 rows + deactivate db + fs -> rm: 0 rows + deactivate fs + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + alt recipientType is STAFF + rm -> us: Check if recipientId exists + activate us + us -> db: Check if recipientId exists + activate db + db -> us: 1 row + deactivate db + us -> rm: 1 row + deactivate us + end + alt recipientType is FACILITY + rm -> fs: Check if recipientId exists + activate fs + fs -> db: Check if recipientId exists + activate db + db -> fs: 1 row + deactivate db + fs -> rm: 1 row + deactivate fs + end + alt sideEffectId invalid + rm -> db: Check if sideEffectId exists + activate db + db -> rm: 0 rows + deactivate db + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> db: Check if referrerId exists + activate db + db -> rm: 1 row + deactivate db + alt Duplicate Entry is present [Unique entity validation failed] + rm -> rm: Check if Side Effect object isDeleted is true + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: IS_DELETED_TRUE + end note + end + rm -> rm: Duplicate Entry is not present [Unique entity validation successful] + rm -> k: Referral Data /persist_topic + activate k + rm -> rc: Put Referral Data against clientReferenceId/serverGeneratedId in cache + activate rc + deactivate rc + group async + prs -> k: Consume Referral Data + activate prs + idx -> k: Consume Referral Data + activate idx + idx -> el: Store Referral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Referral Data + activate db + deactivate db + deactivate prs + end + deactivate k +end +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/create.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/create.puml new file mode 100644 index 00000000000..b3437b4a49c --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/create.puml @@ -0,0 +1,201 @@ +@startuml +title Referral - Create +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant UserService as us +participant RedisCache as rc +queue Kafka as k +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el +database Database as db + +c -> rm : /referralmanagement/v1/_create +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Referral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Referral Data + activate es + deactivate k + es -> db: Persist Referral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +alt record already exists + alt record found in cache + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 1 row + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note + end + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Check if record already exists + activate db + db -> rm: 1 row + deactivate db + rm -> rc: Put data in cache using clientReferenceId/serverGeneratedId + activate rc + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note +end +alt projectBeneficiaryId invalid + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> ps: Check if projectBeneficiaryId exists +activate ps +ps -> db: Check if projectBeneficiaryId exists +activate db +db -> ps: 1 row +deactivate db +ps -> rm: 1 row +deactivate ps +alt referrerId invalid + rm -> us: Check if referrerId exists + activate us + us -> db: Check if referrerId exists + activate db + db -> us: 0 rows + deactivate db + us -> rm: 0 rows + deactivate us + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> us: Check if referrerId exists +activate us +us -> db: Check if referrerId exists +activate db +db -> us: 1 row +deactivate db +us -> rm: 1 row +deactivate us +alt recipientId invalid + alt recipientType is STAFF + rm -> us: Check if recipientId exists + activate us + us -> db: Check if recipientId exists + activate db + db -> us: 0 rows + deactivate db + us -> rm: 0 rows + deactivate us + end + alt recipientType is FACILITY + rm -> fs: Check if recipientId exists + activate fs + fs -> db: Check if recipientId exists + activate db + db -> fs: 0 rows + deactivate db + fs -> rm: 0 rows + deactivate fs + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +alt recipientType is STAFF + rm -> us: Check if recipientId exists + activate us + us -> db: Check if recipientId exists + activate db + db -> us: 1 row + deactivate db + us -> rm: 1 row + deactivate us +end +alt recipientType is FACILITY + rm -> fs: Check if recipientId exists + activate fs + fs -> db: Check if recipientId exists + activate db + db -> fs: 1 row + deactivate db + fs -> rm: 1 row + deactivate fs +end +alt sideEffectId invalid + rm -> db: Check if sideEffectId exists + activate db + db -> rm: 0 rows + deactivate db + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> db: Check if referrerId exists +activate db +db -> rm: 1 row +deactivate db + +rm -> k: Referral Data /persist_topic +activate k +rm -> rc: Put Referral Data against clientReferenceId/serverGeneratedId in cache +activate rc +deactivate rc +group async + prs -> k: Consume Referral Data + activate prs + idx -> k: Consume Referral Data + activate idx + idx -> el: Store Referral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Referral Data + activate db + deactivate db + deactivate prs +end +deactivate k +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/delete.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/delete.puml new file mode 100644 index 00000000000..6e67539432a --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/delete.puml @@ -0,0 +1,124 @@ +@startuml +title Referral - Delete +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant RedisCache as rc +queue Kafka as k +database Database as db +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant UserService as us +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el + +c -> rm : /referralmanagement/v1/_delete +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Referral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Referral Data + activate es + deactivate k + es -> db: Persist Referral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +alt id is null + rm -> rm: Check if Referral object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note +end +rm -> rm: Check if Referral id is not null +alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: Referral Data /error_topic + activate k + group async + es -> k: Consume Referral Data + activate es + deactivate k + es -> db: Persist Referral Data /error_table + activate db + deactivate db + deactivate es + end + s -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note +end +alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc +end +rm -> rc: Fetch the existing record +activate rc +rc -> rm: 1 row +deactivate rc + +rm -> k: Referral Data /persist_topic +activate k +rm -> rc: Put Referral Data against clientReferenceId/serverGeneratedId in cache +activate rc +deactivate rc +group async + prs -> k: Consume Referral Data + activate prs + idx -> k: Consume Referral Data + activate idx + idx -> el: Store Referral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Referral Data + activate db + deactivate db + deactivate prs +end +deactivate k +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/update.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/update.puml new file mode 100644 index 00000000000..e08b8b98607 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/referral/update.puml @@ -0,0 +1,237 @@ +@startuml +title Referral - Update +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant RedisCache as rc +queue Kafka as k +database Database as db +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant UserService as us +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el + +c -> rm : /referralmanagement/v1/_update +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Referral Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Referral Data + activate es + deactivate k + es -> db: Persist Referral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +alt id is null + rm -> rm: Check if Referral object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note +end +rm -> rm: Check if Referral id is not null +alt isDeleted is true + rm -> rm: Check if Referral object isDeleted is true + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: IS_DELETED_TRUE + end note +end +rm -> rm: Check if Referral object isDeleted is not true +alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: Referral Data /error_topic + activate k + group async + es -> k: Consume Referral Data + activate es + deactivate k + es -> db: Persist Referral Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note +end +alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc +end +rm -> rc: Fetch the existing record +activate rc +rc -> rm: 1 row +deactivate rc +alt projectBeneficiaryId invalid + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> ps: Check if projectBeneficiaryId exists +activate ps +ps -> db: Check if projectBeneficiaryId exists +activate db +db -> ps: 1 row +deactivate db +ps -> rm: 1 row +deactivate ps +alt referrerId invalid + rm -> us: Check if referrerId exists + activate us + us -> db: Check if referrerId exists + activate db + db -> us: 0 rows + deactivate db + us -> rm: 0 rows + deactivate us + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> us: Check if referrerId exists +activate us +us -> db: Check if referrerId exists +activate db +db -> us: 1 row +deactivate db +us -> rm: 1 row +deactivate us +alt recipientId invalid + alt recipientType is STAFF + rm -> us: Check if recipientId exists + activate us + us -> db: Check if recipientId exists + activate db + db -> us: 0 rows + deactivate db + us -> rm: 0 rows + deactivate us + end + alt recipientType is FACILITY + rm -> fs: Check if recipientId exists + activate fs + fs -> db: Check if recipientId exists + activate db + db -> fs: 0 rows + deactivate db + fs -> rm: 0 rows + deactivate fs + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +alt recipientType is STAFF + rm -> us: Check if recipientId exists + activate us + us -> db: Check if recipientId exists + activate db + db -> us: 1 row + deactivate db + us -> rm: 1 row + deactivate us +end +alt recipientType is FACILITY + rm -> fs: Check if recipientId exists + activate fs + fs -> db: Check if recipientId exists + activate db + db -> fs: 1 row + deactivate db + fs -> rm: 1 row + deactivate fs +end +alt sideEffectId invalid + rm -> db: Check if sideEffectId exists + activate db + db -> rm: 0 rows + deactivate db + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> db: Check if referrerId exists +activate db +db -> rm: 1 row +deactivate db + +rm -> k: Referral Data /persist_topic +activate k +rm -> rc: Put Referral Data against clientReferenceId/serverGeneratedId in cache +activate rc +deactivate rc +group async + prs -> k: Consume Referral Data + activate prs + idx -> k: Consume Referral Data + activate idx + idx -> el: Store Referral Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Referral Data + activate db + deactivate db + deactivate prs +end +deactivate k + +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_create.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_create.puml new file mode 100644 index 00000000000..9808045815c --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_create.puml @@ -0,0 +1,141 @@ +@startuml +title Side Effect - Bulk Create +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant RedisCache as rc +queue Kafka as k +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el +database Database as db + +c -> rm : /referralmanagement/side-effect/v1/bulk/_create +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Side Effect Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Side Effect Data + activate es + deactivate k + es -> db: Persist Side Effect Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +loop for each side-effect + alt record already exists + alt record found in cache + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 1 row + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note + end + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Check if record already exists + activate db + db -> rm: 1 row + deactivate db + rm -> rc: Put data in cache using clientReferenceId/serverGeneratedId + activate rc + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note + end + alt projectTaskId invalid + rm -> ps: Check if projectTaskId exists + activate ps + ps -> db: Check if projectTaskId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: BAD_REQUEST + end note + end + rm -> ps: Check if projectTaskId exists + activate ps + ps -> db: Check if projectTaskId exists + activate db + db -> ps: 1 row + deactivate db + ps -> rm: 1 row + deactivate ps + alt projectBeneficiaryId invalid + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 1 row + deactivate db + ps -> rm: 1 row + deactivate ps + rm -> k: Side Effect Data /persist_topic + activate k + rm -> rc: Put Side Effect Data against clientReferenceId/serverGeneratedId in cache + activate rc + deactivate rc + group async + prs -> k: Consume Side Effect Data + activate prs + idx -> k: Consume Side Effect Data + activate idx + idx -> el: Store Side Effect Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Side Effect Data + activate db + deactivate db + deactivate prs + end + deactivate k +end +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_delete.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_delete.puml new file mode 100644 index 00000000000..1d95721ab4c --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_delete.puml @@ -0,0 +1,125 @@ +@startuml +title Side Effect - Bulk Delete +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant RedisCache as rc +queue Kafka as k +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el +database Database as db + +c -> rm : /referralmanagement/side-effect/v1/bulk/_delete +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Side Effect Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Side Effect Data + activate es + deactivate k + es -> db: Persist Side Effect Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +loop for each side-effect + alt id is null + rm -> rm: Check if Side Effect object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note + end + rm -> rm: Check if Side Effect id is not null + alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: Side Effect Data /error_topic + activate k + group async + es -> k: Consume Side Effect Data + activate es + deactivate k + es -> db: Persist Side Effect Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note + end + alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc + end + rm -> rc: Fetch the existing record + activate rc + rc -> rm: 1 row + deactivate rc + rm -> k: Side Effect Data /persist_topic + activate k + rm -> rc: Put Side Effect Data against clientReferenceId/serverGeneratedId in cache + activate rc + deactivate rc + group async + prs -> k: Consume Side Effect Data + activate prs + idx -> k: Consume Side Effect Data + activate idx + idx -> el: Store Side Effect Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Side Effect Data + activate db + deactivate db + deactivate prs + end + deactivate k +end + +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_update.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_update.puml new file mode 100644 index 00000000000..85606389c27 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/bulk_update.puml @@ -0,0 +1,177 @@ +@startuml +title Side Effect - Bulk Update +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant RedisCache as rc +queue Kafka as k +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el +database Database as db + +c -> rm : /referralmanagement/side-effect/v1/bulk/_update +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Side Effect Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Side Effect Data + activate es + deactivate k + es -> db: Persist Side Effect Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +loop for each side-effect + alt id is null + rm -> rm: Check if Side Effect object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note + end + rm -> rm: Check if Side Effect id is not null + alt isDeleted is true + rm -> rm: Check if Side Effect object isDeleted is true + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: IS_DELETED_TRUE + end note + end + rm -> rm: Check if Side Effect object isDeleted is not true + alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: Side Effect Data /error_topic + activate k + group async + es -> k: Consume Side Effect Data + activate es + deactivate k + es -> db: Persist Side Effect Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note + end + alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc + end + rm -> rc: Fetch the existing record + activate rc + rc -> rm: 1 row + deactivate rc + alt projectTaskId invalid + rm -> ps: Check if projectTaskId exists + activate ps + ps -> db: Check if projectTaskId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: BAD_REQUEST + end note + end + rm -> ps: Check if projectTaskId exists + activate ps + ps -> db: Check if projectTaskId exists + activate db + db -> ps: 1 row + deactivate db + ps -> rm: 1 row + deactivate ps + alt projectBeneficiaryId invalid + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note + end + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 1 row + deactivate db + ps -> rm: 1 row + deactivate ps + rm -> k: Side Effect Data /persist_topic + activate k + rm -> rc: Put Side Effect Data against clientReferenceId/serverGeneratedId in cache + activate rc + deactivate rc + group async + prs -> k: Consume Side Effect Data + activate prs + idx -> k: Consume Side Effect Data + activate idx + idx -> el: Store Side Effect Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Side Effect Data + activate db + deactivate db + deactivate prs + end + deactivate k +end + +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/create.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/create.puml new file mode 100644 index 00000000000..94d0a3b95ca --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/create.puml @@ -0,0 +1,140 @@ +@startuml +title Side Effect - Create +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant RedisCache as rc +queue Kafka as k +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el +database Database as db + +c -> rm : /referralmanagement/side-effect/v1/_create +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Side Effect Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Side Effect Data + activate es + deactivate k + es -> db: Persist Side Effect Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +alt record already exists + alt record found in cache + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 1 row + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note + end + rm -> rc: Check using clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Check if record already exists + activate db + db -> rm: 1 row + deactivate db + rm -> rc: Put data in cache using clientReferenceId/serverGeneratedId + activate rc + deactivate rc + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_ALREADY_EXISTS + end note +end +alt projectTaskId invalid + rm -> ps: Check if projectTaskId exists + activate ps + ps -> db: Check if projectTaskId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: BAD_REQUEST + end note +end +rm -> ps: Check if projectTaskId exists +activate ps +ps -> db: Check if projectTaskId exists +activate db +db -> ps: 1 row +deactivate db +ps -> rm: 1 row +deactivate ps +alt projectBeneficiaryId invalid + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> ps: Check if projectBeneficiaryId exists +activate ps +ps -> db: Check if projectBeneficiaryId exists +activate db +db -> ps: 1 row +deactivate db +ps -> rm: 1 row +deactivate ps +rm -> k: Side Effect Data /persist_topic +activate k +rm -> rc: Put Side Effect Data against clientReferenceId/serverGeneratedId in cache +activate rc +deactivate rc +group async + prs -> k: Consume Side Effect Data + activate prs + idx -> k: Consume Side Effect Data + activate idx + idx -> el: Store Side Effect Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Side Effect Data + activate db + deactivate db + deactivate prs +end +deactivate k + +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/delete.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/delete.puml new file mode 100644 index 00000000000..77727af23d2 --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/delete.puml @@ -0,0 +1,123 @@ +@startuml +title Side Effect - Delete +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant RedisCache as rc +queue Kafka as k +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el +database Database as db + +c -> rm : /referralmanagement/side-effect/v1/_delete +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Side Effect Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Side Effect Data + activate es + deactivate k + es -> db: Persist Side Effect Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +alt id is null + rm -> rm: Check if Side Effect object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note +end +rm -> rm: Check if Side Effect id is not null +alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: Side Effect Data /error_topic + activate k + group async + es -> k: Consume Side Effect Data + activate es + deactivate k + es -> db: Persist Side Effect Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note +end +alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc +end +rm -> rc: Fetch the existing record +activate rc +rc -> rm: 1 row +deactivate rc +rm -> k: Side Effect Data /persist_topic +activate k +rm -> rc: Put Side Effect Data against clientReferenceId/serverGeneratedId in cache +activate rc +deactivate rc +group async + prs -> k: Consume Side Effect Data + activate prs + idx -> k: Consume Side Effect Data + activate idx + idx -> el: Store Side Effect Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Side Effect Data + activate db + deactivate db + deactivate prs +end +deactivate k + +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/update.puml b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/update.puml new file mode 100644 index 00000000000..896e5d40fbc --- /dev/null +++ b/docs/health-api-specs/sequence-diagrams/referralmanagement/side-effect/update.puml @@ -0,0 +1,175 @@ +@startuml +title Side Effect - Update +!theme vibrant +participant Client as c +participant ReferralManagement as rm +participant FacilityService as fs +participant HouseholdService as hs +participant IndividualService as inds +participant ProjectService as ps +participant RedisCache as rc +queue Kafka as k +participant PersisterService as prs +participant IndexerService as idx +participant ErrorService as es +participant ElasticSearch as el +database Database as db + +c -> rm : /referralmanagement/side-effect/v1/_update +activate rm +rm -> rm : Validate request body + +alt request validation fails + rm -> rm: Request validation failed + rm -> k: Side Effect Data /error_topic + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + activate k + group async + es -> k: Consume Side Effect Data + activate es + deactivate k + es -> db: Persist Side Effect Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: REQUEST_VALIDATION_FAILED + end note +end +rm -> rm: Request validation successful +alt id is null + rm -> rm: Check if Side Effect object id is null + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: NULL_ID + end note +end +rm -> rm: Check if Side Effect id is not null +alt isDeleted is true + rm -> rm: Check if Side Effect object isDeleted is true + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: IS_DELETED_TRUE + end note +end +rm -> rm: Check if Side Effect object isDeleted is not true +alt record doesn't exist + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 0 row + deactivate db + note left + This will be marked as unrecoverable right away + and require manual intervention + end note + rm -> k: Side Effect Data /error_topic + activate k + group async + es -> k: Consume Side Effect Data + activate es + deactivate k + es -> db: Persist Side Effect Data /error_table + activate db + deactivate db + deactivate es + end + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: RECORD_NOT_FOUND + end note +end +alt record doesn't exists in cache + rm -> rc: Search record based on clientReferenceId/serverGeneratedId + activate rc + rc -> rm: 0 rows + deactivate rc + rm -> db: Search record based on clientReferenceId/serverGeneratedId + activate db + db -> rm: 1 row + deactivate db + rm -> rc: 1 record + activate rc + deactivate rc +end +rm -> rc: Fetch the existing record +activate rc +rc -> rm: 1 row +deactivate rc +alt projectTaskId invalid + rm -> ps: Check if projectTaskId exists + activate ps + ps -> db: Check if projectTaskId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: BAD_REQUEST + end note +end +rm -> ps: Check if projectTaskId exists +activate ps +ps -> db: Check if projectTaskId exists +activate db +db -> ps: 1 row +deactivate db +ps -> rm: 1 row +deactivate ps +alt projectBeneficiaryId invalid + rm -> ps: Check if projectBeneficiaryId exists + activate ps + ps -> db: Check if projectBeneficiaryId exists + activate db + db -> ps: 0 rows + deactivate db + ps -> rm: 0 rows + deactivate ps + rm -> c: HttpStatus: 400 with appropriate error code + note left + Error Code: DEPENDENCY_ERROR + end note +end +rm -> ps: Check if projectBeneficiaryId exists +activate ps +ps -> db: Check if projectBeneficiaryId exists +activate db +db -> ps: 1 row +deactivate db +ps -> rm: 1 row +deactivate ps +rm -> k: Side Effect Data /persist_topic +activate k +rm -> rc: Put Side Effect Data against clientReferenceId/serverGeneratedId in cache +activate rc +deactivate rc +group async + prs -> k: Consume Side Effect Data + activate prs + idx -> k: Consume Side Effect Data + activate idx + idx -> el: Store Side Effect Data + activate el + deactivate el + deactivate idx + prs -> db: Persist Side Effect Data + activate db + deactivate db + deactivate prs +end +deactivate k + +rm -> c : HttpStatus: 202 ACCEPTED +deactivate rm + +@enduml \ No newline at end of file diff --git a/health-services/individual/CHANGELOG.md b/health-services/individual/CHANGELOG.md index 6e8364117b0..6aaf8693ede 100644 --- a/health-services/individual/CHANGELOG.md +++ b/health-services/individual/CHANGELOG.md @@ -1,5 +1,8 @@ All notable changes to this module will be documented in this file. +## 1.1.3 +- Added ability to search by user UUID for individual search. + ## 1.1.2 - upgraded version from beta diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index b0cd415b742..075230f0166 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -5,7 +5,7 @@ individual jar individual - 1.1.2 + 1.1.3 1.8 ${java.version} diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index 4362e1f1811..eecf48c03d7 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -269,12 +269,21 @@ private String getQueryForIndividual(IndividualSearch searchObject, Integer limi query = query + "AND userId=:userId "; paramsMap.put("userId", String.valueOf(searchObject.getUserId())); } + + if (searchObject.getUserUuid() != null) { + query = query + "AND userUuid in (:userUuid) "; + paramsMap.put("userUuid", searchObject.getUserUuid()); + } + query = query + "ORDER BY id ASC LIMIT :limit OFFSET :offset"; paramsMap.put("tenantId", tenantId); paramsMap.put("isDeleted", includeDeleted); paramsMap.put("lastModifiedTime", lastChangedSince); paramsMap.put("limit", limit); paramsMap.put("offset", offset); + + log.info("query-------------------------->"); + log.info(query); return query; } diff --git a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java b/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java index 397b60304ce..51dec55ace1 100644 --- a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java +++ b/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java @@ -17,6 +17,7 @@ import javax.validation.Valid; import javax.validation.constraints.DecimalMax; import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.Size; import java.math.BigDecimal; import java.util.Date; import java.util.List; @@ -99,6 +100,11 @@ public class IndividualSearch { @JsonProperty("userId") private Long userId; + @Exclude + @JsonProperty("userUuid") + @Size(min = 1) + private List userUuid; + @Exclude @JsonProperty("latitude") @DecimalMin("-90") diff --git a/health-services/individual/src/test/java/org/egov/individual/helper/IndividualSearchTestBuilder.java b/health-services/individual/src/test/java/org/egov/individual/helper/IndividualSearchTestBuilder.java index 6db1b119462..ed10e84d6c5 100644 --- a/health-services/individual/src/test/java/org/egov/individual/helper/IndividualSearchTestBuilder.java +++ b/health-services/individual/src/test/java/org/egov/individual/helper/IndividualSearchTestBuilder.java @@ -53,7 +53,17 @@ public IndividualSearchTestBuilder byClientReferenceId(String... args) { this.builder.clientReferenceId(ids); return this; } + public IndividualSearchTestBuilder byUserUUID(String... args) { + ArrayList ids = new ArrayList<>(); + if (args != null && args.length > 0) { + ids.add(args[0]); + } else { + ids.add("some-user-uuid"); + } + this.builder.userUuid(ids); + return this; + } public IndividualSearchTestBuilder byName() { this.builder.name(Name.builder() diff --git a/health-services/individual/src/test/java/org/egov/individual/repository/IndividualRepositoryTest.java b/health-services/individual/src/test/java/org/egov/individual/repository/IndividualRepositoryTest.java index 3e73c932c08..8167285ff87 100644 --- a/health-services/individual/src/test/java/org/egov/individual/repository/IndividualRepositoryTest.java +++ b/health-services/individual/src/test/java/org/egov/individual/repository/IndividualRepositoryTest.java @@ -88,6 +88,7 @@ void shouldFindOtherParamsFromDbAndReturnAllTheDependentEntitiesAsWellIfPresent( IndividualSearch individualSearch = IndividualSearchTestBuilder.builder() .byId() .byClientReferenceId() + .byUserUUID() .byGender() .byName() .byDateOfBirth() @@ -145,6 +146,7 @@ void shouldFindOtherParamsAndIdentifierFromDbAndReturnAllTheDependentEntitiesAsW IndividualSearch individualSearch = IndividualSearchTestBuilder.builder() .byId() .byClientReferenceId() + .byUserUUID() .byGender() .byName() .byDateOfBirth() diff --git a/health-services/libraries/health-services-models/CHANGELOG.md b/health-services/libraries/health-services-models/CHANGELOG.md index 3f5b9c6ff4e..a09fe37f16c 100644 --- a/health-services/libraries/health-services-models/CHANGELOG.md +++ b/health-services/libraries/health-services-models/CHANGELOG.md @@ -1,5 +1,13 @@ All notable changes to this module will be documented in this file. + +## 1.0.19 - 2024-02-26 +- Updated project staff search to accept a list of staffIds +- Added senderId and receiverId fields to stock information. + +## 1.0.18 - 2024-02-13 +- Adding user uuid in individual search + ## 1.0.11 - 2023-11-15 - Client reference id added for member of household - revert of household search change diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index 683fa9392f1..3dafc7c24a0 100644 --- a/health-services/libraries/health-services-models/pom.xml +++ b/health-services/libraries/health-services-models/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.egov.common health-services-models - 1.0.11-SNAPSHOT + 1.0.19-SNAPSHOT 8 8 @@ -28,6 +28,11 @@ digit-models 1.0.0-SNAPSHOT + + org.egov.services + tracer + 2.1.4-SNAPSHOT + diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/validator/CustomIntegerDeserializer.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/validator/CustomIntegerDeserializer.java new file mode 100644 index 00000000000..b5cb00eac27 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/validator/CustomIntegerDeserializer.java @@ -0,0 +1,43 @@ +package org.egov.common.models.core.validator; + +import java.io.IOException; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.deser.std.StdDeserializer; +import org.egov.tracer.model.CustomException; + +// Custom deserializer for Integer values +public class CustomIntegerDeserializer extends StdDeserializer { + + public CustomIntegerDeserializer() { + this(null); + } + + public CustomIntegerDeserializer(Class vc) { + super(vc); + } + + @Override + public Integer deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException { + + // Read the JSON tree from the parser + JsonNode node = jsonParser.getCodec().readTree(jsonParser); + System.out.println(node.toString()); + if(node.asLong() > Integer.MAX_VALUE){ + throw new CustomException("INVALID_INPUT","Value must be an Integer"); + } + + // Parse the quantity as an integer + int quantity = node.asInt(); + + // Check if the parsed quantity matches the original string representation + if ((double) quantity != Double.parseDouble(node.asText())) { + throw new CustomException("INVALID_INPUT", "Quantity must be an integer"); + } + + // Return the parsed quantity + return quantity; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Field.java index e836f7dcc4b..78218ccbf63 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Field.java @@ -1,5 +1,8 @@ package org.egov.common.models.facility; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; @@ -8,9 +11,6 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * Field */ @@ -30,7 +30,7 @@ public class Field { @JsonProperty("value") @NotNull - @Size(min = 2, max = 10000) + @Size(min = 1, max = 10000) private String value = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Field.java index ba8246ab184..bb53d162286 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Field.java @@ -1,5 +1,8 @@ package org.egov.common.models.household; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; @@ -8,9 +11,6 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * Field */ @@ -22,23 +22,16 @@ @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class Field { - @JsonProperty("key") - @NotNull - - - @Size(min=2,max=64) - +public class Field { + @JsonProperty("key") + @NotNull + @Size(min = 2, max = 64) private String key = null; - @JsonProperty("value") - @NotNull - - - @Size(min=2,max=10000) - + @JsonProperty("value") + @NotNull + @Size(min = 1, max = 10000) private String value = null; - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Field.java index 62cc4f84377..b189fbe154e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Field.java @@ -1,5 +1,8 @@ package org.egov.common.models.individual; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; @@ -8,9 +11,6 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * Field */ @@ -22,23 +22,16 @@ @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class Field { - @JsonProperty("key") - @NotNull - - - @Size(min=2,max=64) - +public class Field { + @JsonProperty("key") + @NotNull + @Size(min = 2, max = 64) private String key = null; - @JsonProperty("value") - @NotNull - - - @Size(min=2,max=10000) - + @JsonProperty("value") + @NotNull + @Size(min = 1, max = 10000) private String value = null; - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java index 7dff5b261d7..d4471a9e29e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java @@ -11,6 +11,7 @@ import org.springframework.validation.annotation.Validated; import javax.validation.Valid; +import javax.validation.constraints.Size; import java.math.BigDecimal; import java.util.Date; import java.util.List; @@ -82,5 +83,9 @@ public class IndividualSearch { @JsonProperty("userId") private Long userId; + + @JsonProperty("userUuid") + @Size(min = 1) + private List userUuid; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Field.java index 2c2f099f003..828a1cad303 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Field.java @@ -1,5 +1,8 @@ package org.egov.common.models.product; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; @@ -8,9 +11,6 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * Field */ @@ -22,23 +22,16 @@ @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class Field { - @JsonProperty("key") - @NotNull - - - @Size(min=2,max=64) - +public class Field { + @JsonProperty("key") + @NotNull + @Size(min = 2, max = 64) private String key = null; - @JsonProperty("value") - @NotNull - - - @Size(min=2,max=10000) - + @JsonProperty("value") + @NotNull + @Size(min = 1, max = 10000) private String value = null; - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Field.java index 33a82b187b7..c4f47fe7a7e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Field.java @@ -1,5 +1,8 @@ package org.egov.common.models.project; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; @@ -8,9 +11,6 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * Field */ @@ -22,8 +22,7 @@ @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class Field { - +public class Field { @JsonProperty("key") @NotNull @Size(min = 2, max = 64) @@ -31,7 +30,8 @@ public class Field { @JsonProperty("value") @NotNull - @Size(min = 2, max = 10000) + @Size(min = 1, max = 10000) private String value = null; + } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffSearch.java index f32cc34aa7d..940ec9bfb63 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffSearch.java @@ -13,9 +13,9 @@ import java.util.List; /** -* This object defines the mapping of a system staff user to a project for a certain period. -*/ - @ApiModel(description = "This object defines the mapping of a system staff user to a project for a certain period.") + * This object defines the mapping of a system staff user to a project for a certain period. + */ +@ApiModel(description = "This object defines the mapping of a system staff user to a project for a certain period.") @Validated @javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") @@ -23,23 +23,23 @@ @NoArgsConstructor @AllArgsConstructor @Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectStaffSearch { +@JsonIgnoreProperties(ignoreUnknown = true) +public class ProjectStaffSearch { @JsonProperty("id") private List id = null; @JsonProperty("tenantId") - @Size(min=2,max=1000) + @Size(min = 2, max = 1000) private String tenantId = null; @JsonProperty("staffId") - @Size(min=2,max=64) - private String staffId = null; + @Size(min = 2, max = 64) + private List staffId = null; @JsonProperty("projectId") - @Size(min=2,max=64) + @Size(min = 2, max = 64) private String projectId = null; @JsonProperty("startDate") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferral.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferral.java new file mode 100644 index 00000000000..330b437df95 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferral.java @@ -0,0 +1,84 @@ +package org.egov.common.models.referralmanagement.hfreferral; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.models.project.AdditionalFields; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class HFReferral { + + @JsonProperty("id") + @Size(min = 2, max = 64) + private String id; + + @JsonProperty("clientReferenceId") + @Size(min = 2, max = 64) + private String clientReferenceId; + + @JsonProperty("tenantId") + @NotNull + @Size(min=2, max = 1000) + private String tenantId; + + @JsonProperty("projectId") + @Size(min = 2, max = 64) + private String projectId; + + @JsonProperty("projectFacilityId") + @Size(min = 2, max = 64) + private String projectFacilityId; + + @JsonProperty("symptom") + @NotNull + @Size(min = 2, max = 256) + private String symptom; + + @JsonProperty("symptomSurveyId") + @Size(min = 2, max = 100) + private String symptomSurveyId; + + @JsonProperty("beneficiaryId") + @Size(max=100) + private String beneficiaryId; + + @JsonProperty("referralCode") + @Size(max=100) + private String referralCode; + + @JsonProperty("nationalLevelId") + @Size(max=100) + private String nationalLevelId; + + @JsonProperty("isDeleted") + private Boolean isDeleted = Boolean.FALSE; + + @JsonProperty("rowVersion") + private Integer rowVersion; + + @JsonProperty("auditDetails") + @Valid + private AuditDetails auditDetails; + + @JsonProperty("clientAuditDetails") + @Valid + private AuditDetails clientAuditDetails; + + @JsonProperty("additionalFields") + @Valid + private AdditionalFields additionalFields; + + @JsonIgnore + private Boolean hasErrors = Boolean.FALSE; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkRequest.java new file mode 100644 index 00000000000..358cb03135c --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkRequest.java @@ -0,0 +1,46 @@ +package org.egov.common.models.referralmanagement.hfreferral; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class HFReferralBulkRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo; + + @JsonProperty("HFReferrals") + @NotNull + @Valid + @Size(min = 1) + private List hfReferrals; + + /** + * Add a HfReferral item to the list of HfReferrals in the bulk request. + * + * @param hfReferralItem The HfReferral item to add to the request. + * @return The updated HFReferralBulkRequest. + */ + public HFReferralBulkRequest addHFReferralItem(HFReferral hfReferralItem) { + if(Objects.isNull(hfReferrals)) + hfReferrals = new ArrayList<>(); + if(Objects.nonNull(hfReferralItem)) + hfReferrals.add(hfReferralItem); + return this; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkResponse.java new file mode 100644 index 00000000000..a0f1c04b090 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkResponse.java @@ -0,0 +1,44 @@ +package org.egov.common.models.referralmanagement.hfreferral; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class HFReferralBulkResponse { + @JsonProperty("ResponseInfo") + @NotNull + @Valid + private ResponseInfo responseInfo; + + @JsonProperty("HFReferrals") + @NotNull + @Valid + private List hfReferrals; + + /** + * Add a HfReferral item to the list of HfReferrals in the bulk response. + * + * @param hfReferralItem The HfReferral item to add to the response. + * @return The updated HFReferralBulkRequest. + */ + public HFReferralBulkResponse addReferralItem(HFReferral hfReferralItem) { + if(Objects.isNull(hfReferrals)) + hfReferrals = new ArrayList<>(); + if(Objects.nonNull(hfReferralItem)) + hfReferrals.add(hfReferralItem); + return this; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralRequest.java new file mode 100644 index 00000000000..3adc90053b6 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralRequest.java @@ -0,0 +1,27 @@ +package org.egov.common.models.referralmanagement.hfreferral; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class HFReferralRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo; + + @JsonProperty("HFReferral") + @NotNull + @Valid + private HFReferral hfReferral; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralResponse.java new file mode 100644 index 00000000000..24471207656 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralResponse.java @@ -0,0 +1,27 @@ +package org.egov.common.models.referralmanagement.hfreferral; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class HFReferralResponse { + @JsonProperty("ResponseInfo") + @NotNull + @Valid + private ResponseInfo responseInfo; + + @JsonProperty("HFReferral") + @NotNull + @Valid + private HFReferral hfReferral; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearch.java new file mode 100644 index 00000000000..02dbfdf899a --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearch.java @@ -0,0 +1,45 @@ +package org.egov.common.models.referralmanagement.hfreferral; + +import java.util.List; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class HFReferralSearch { + @JsonProperty("id") + private List id; + + @JsonProperty("clientReferenceId") + private List clientReferenceId; + + @JsonProperty("facilityId") + private List facilityId; + + @JsonProperty("projectId") + private String projectId; + + @JsonProperty("symptom") + private List symptom; + + @JsonProperty("symptomSurveyId") + private List symptomSurveyId; + + @JsonProperty("beneficiaryId") + private List beneficiaryId; + + @JsonProperty("referralCode") + private List referralCode; + + @JsonProperty("nationalLevelId") + private List nationalLevelId; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearchRequest.java new file mode 100644 index 00000000000..4784f9fbdad --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearchRequest.java @@ -0,0 +1,26 @@ +package org.egov.common.models.referralmanagement.hfreferral; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class HFReferralSearchRequest { + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo; + + @JsonProperty("HFReferral") + @Valid + private HFReferralSearch hfReferral; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Field.java index 73dab0bcb93..4994957dd27 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Field.java @@ -1,5 +1,8 @@ package org.egov.common.models.stock; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; @@ -8,9 +11,6 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * Field */ @@ -22,23 +22,16 @@ @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class Field { - @JsonProperty("key") - @NotNull - - - @Size(min=2,max=64) - +public class Field { + @JsonProperty("key") + @NotNull + @Size(min = 2, max = 64) private String key = null; - @JsonProperty("value") - @NotNull - - - @Size(min=1,max=10000) - + @JsonProperty("value") + @NotNull + @Size(min = 1, max = 10000) private String value = null; - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/ReferenceIdType.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/ReferenceIdType.java new file mode 100644 index 00000000000..7b5943c3493 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/ReferenceIdType.java @@ -0,0 +1,32 @@ +package org.egov.common.models.stock; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonValue; + +@JsonIgnoreProperties(ignoreUnknown = true) +public enum ReferenceIdType { + PROJECT("PROJECT"), + OTHER("OTHER"); + private String value; + + ReferenceIdType(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static ReferenceIdType fromValue(String text) { + for (ReferenceIdType b : ReferenceIdType.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/SenderReceiverType.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/SenderReceiverType.java new file mode 100644 index 00000000000..e5b1924574a --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/SenderReceiverType.java @@ -0,0 +1,34 @@ +package org.egov.common.models.stock; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonValue; + +@JsonIgnoreProperties(ignoreUnknown = true) +public enum SenderReceiverType { + WAREHOUSE("WAREHOUSE"), + + STAFF("STAFF"); + + private String value; + + SenderReceiverType(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static SenderReceiverType fromValue(String text) { + for (SenderReceiverType b : SenderReceiverType.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java index a08748daf49..c53164b370c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java @@ -1,21 +1,21 @@ package org.egov.common.models.stock; import javax.validation.Valid; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; -import org.springframework.validation.annotation.Validated; - import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; - import digit.models.coremodels.AuditDetails; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Builder.Default; import lombok.Data; import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; /** * Stock @@ -51,6 +51,8 @@ public class Stock { @JsonProperty("quantity") @NotNull + @Min(value = 1, message = "Minimum value cannot be less than 1") + @Max(value = Integer.MAX_VALUE, message = "Value exceeds maximum allowable limit") private Integer quantity; /* project id in-case of health */ @@ -58,12 +60,13 @@ public class Stock { private String referenceId; @JsonProperty("referenceIdType") - @Size(min=2, max=64) - private String referenceIdType; + @NotNull(message = "referenceIdType must be PROJECT or OTHER") + @Valid + private ReferenceIdType referenceIdType; // transaction fields @JsonProperty("transactionType") - @NotNull + @NotNull(message = "transactionType must be either RECEIVED or DISPATCHED") @Valid private TransactionType transactionType; @@ -77,9 +80,9 @@ public class Stock { private String senderId; @JsonProperty("senderType") - @NotNull - @Size(min=2, max=64) - private String senderType; + @NotNull(message = "Sender Type can be either WAREHOUSE or STAFF") + @Valid + private SenderReceiverType senderType; @JsonProperty("receiverId") @NotNull @@ -87,9 +90,9 @@ public class Stock { private String receiverId; @JsonProperty("receiverType") - @NotNull - @Size(min=2, max=64) - private String receiverType; + @NotNull(message = "Receiver Type can be either WAREHOUSE or STAFF") + @Valid + private SenderReceiverType receiverType; @JsonProperty("wayBillNumber") @Size(min = 2, max = 200) diff --git a/health-services/project/CHANGELOG.md b/health-services/project/CHANGELOG.md index df50f2ba974..3a1ba625f06 100644 --- a/health-services/project/CHANGELOG.md +++ b/health-services/project/CHANGELOG.md @@ -1,5 +1,9 @@ All notable changes to this module will be documented in this file. +## 1.1.2 - 2024-02-26 +- Implemented validation for updating project start date and end date. +- Added numberOfSessions field in additional details for attendance registry. + ## 1.1.1 - 2023-11-15 - Added tag in project beneficiary diff --git a/health-services/project/pom.xml b/health-services/project/pom.xml index ebb223d7d6f..bc89832e98c 100644 --- a/health-services/project/pom.xml +++ b/health-services/project/pom.xml @@ -5,7 +5,7 @@ project jar project - 1.1.1 + 1.1.2 1.8 ${java.version} diff --git a/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java b/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java index fe9291ab137..34308dd587f 100644 --- a/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java +++ b/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java @@ -183,4 +183,7 @@ public class ProjectConfiguration { @Value("${egov.user.id.validator}") private String egovUserIdValidator; + @Value("${project.staff.attendance.topic}") + private String projectStaffAttendanceTopic; + } diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java index 3c299826c90..c1eee50ec6c 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java @@ -6,6 +6,7 @@ import org.egov.common.models.project.ProjectStaff; import org.egov.common.models.project.ProjectStaffBulkRequest; import org.egov.common.models.project.ProjectStaffRequest; +import org.egov.common.producer.Producer; import org.egov.common.service.IdGenService; import org.egov.common.service.UserService; import org.egov.common.utils.CommonUtils; @@ -26,7 +27,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.lang.reflect.Type; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.function.Predicate; @@ -60,6 +63,8 @@ public class ProjectStaffService { private final List> validators; + private final Producer producer; + private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(PsUserIdValidator.class) || validator.getClass().equals(PsProjectIdValidator.class) @@ -86,7 +91,8 @@ public ProjectStaffService( ProjectService projectService, UserService userService, ProjectConfiguration projectConfiguration, - ProjectStaffEnrichmentService enrichmentService, List> validators) { + ProjectStaffEnrichmentService enrichmentService, + Producer producer, List> validators) { this.idGenService = idGenService; this.projectStaffRepository = projectStaffRepository; this.projectService = projectService; @@ -94,6 +100,7 @@ public ProjectStaffService( this.projectConfiguration = projectConfiguration; this.enrichmentService = enrichmentService; this.validators = validators; + this.producer = producer; } public ProjectStaff create(ProjectStaffRequest request) { @@ -117,6 +124,9 @@ public List create(ProjectStaffBulkRequest request, boolean isBulk if (!validEntities.isEmpty()) { log.info("processing {} valid entities", validEntities.size()); enrichmentService.create(validEntities, request); + // Pushing the data as ProjectStaffBulkRequest for Attendance Service Consumer + producer.push(projectConfiguration.getProjectStaffAttendanceTopic(), new ProjectStaffBulkRequest(request.getRequestInfo(),validEntities)); + // Pushing the data as list for persister consumer projectStaffRepository.save(validEntities, projectConfiguration.getCreateProjectStaffTopic()); log.info("successfully created project staff"); } diff --git a/health-services/project/src/main/java/org/egov/project/util/MDMSUtils.java b/health-services/project/src/main/java/org/egov/project/util/MDMSUtils.java index 950985ac246..27300bff902 100644 --- a/health-services/project/src/main/java/org/egov/project/util/MDMSUtils.java +++ b/health-services/project/src/main/java/org/egov/project/util/MDMSUtils.java @@ -1,5 +1,10 @@ package org.egov.project.util; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; + import digit.models.coremodels.mdms.MasterDetail; import digit.models.coremodels.mdms.MdmsCriteria; import digit.models.coremodels.mdms.MdmsCriteriaReq; @@ -14,16 +19,13 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; - +import static org.egov.project.util.ProjectConstants.MASTER_ATTENDANCE_SESSION; import static org.egov.project.util.ProjectConstants.MASTER_DEPARTMENT; import static org.egov.project.util.ProjectConstants.MASTER_NATUREOFWORK; import static org.egov.project.util.ProjectConstants.MASTER_PROJECTTYPE; import static org.egov.project.util.ProjectConstants.MASTER_TENANTS; import static org.egov.project.util.ProjectConstants.MDMS_COMMON_MASTERS_MODULE_NAME; +import static org.egov.project.util.ProjectConstants.MDMS_HCM_ATTENDANCE_MODULE_NAME; import static org.egov.project.util.ProjectConstants.MDMS_TENANT_MODULE_NAME; @Component @@ -58,11 +60,13 @@ public MdmsCriteriaReq getMDMSRequest(RequestInfo requestInfo, String tenantId, ModuleDetail projectMDMSModuleDetail = getMDMSModuleRequestData(request); ModuleDetail projectDepartmentModuleDetail = getDepartmentModuleRequestData(request); ModuleDetail projectTenantModuleDetail = getTenantModuleRequestData(request); + ModuleDetail attendanceModuleDetail = getAttendanceModuleRequestData(request); List moduleDetails = new LinkedList<>(); moduleDetails.add(projectMDMSModuleDetail); moduleDetails.add(projectDepartmentModuleDetail); moduleDetails.add(projectTenantModuleDetail); + moduleDetails.add(attendanceModuleDetail); MdmsCriteria mdmsCriteria = MdmsCriteria.builder().moduleDetails(moduleDetails).tenantId(tenantId) .build(); @@ -123,4 +127,19 @@ private ModuleDetail getTenantModuleRequestData(ProjectRequest request) { return tenantModuleDetail; } -} + private ModuleDetail getAttendanceModuleRequestData(ProjectRequest request) { + List attendanceMasterDetails = new ArrayList<>(); + + MasterDetail attendanceSessionsMasterDetails = MasterDetail.builder().name(MASTER_ATTENDANCE_SESSION) + .filter(filterCode) + .build(); + + attendanceMasterDetails.add(attendanceSessionsMasterDetails); + + ModuleDetail attendanceModuleDetail = ModuleDetail.builder().masterDetails(attendanceMasterDetails) + .moduleName(MDMS_HCM_ATTENDANCE_MODULE_NAME).build(); + + return attendanceModuleDetail; + } + +} \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java b/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java index 5a431833f41..b314eb59fbf 100644 --- a/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java +++ b/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java @@ -7,10 +7,12 @@ public class ProjectConstants { public static final String MASTER_TENANTS = "tenants"; public static final String MDMS_TENANT_MODULE_NAME = "tenant"; public static final String MDMS_COMMON_MASTERS_MODULE_NAME = "common-masters"; + public static final String MDMS_HCM_ATTENDANCE_MODULE_NAME = "HCM-ATTENDANCE"; public static final String MASTER_DEPARTMENT = "Department"; public static final String MASTER_PROJECTTYPE = "ProjectType"; //location public static final String MASTER_NATUREOFWORK = "NatureOfWork"; + public static final String MASTER_ATTENDANCE_SESSION = "AttendanceSessions"; public static final String CODE = "code"; //General public static final String SEMICOLON = ":"; @@ -19,6 +21,8 @@ public class ProjectConstants { public static final String TASK_NOT_ALLOWED = "TASK_NOT_ALLOWED"; public static final String TASK_NOT_ALLOWED_BENEFICIARY_REFUSED_RESOURCE_EMPTY_ERROR_MESSAGE = "Task not allowed as resources can not be provided when " + TaskStatus.BENEFICIARY_REFUSED; public static final String TASK_NOT_ALLOWED_RESOURCE_CANNOT_EMPTY_ERROR_MESSAGE = "Task not allowed as resources can not be empty when "; + public static final String NUMBER_OF_SESSIONS = "numberOfSessions"; + public enum TaskStatus { BENEFICIARY_REFUSED("BENEFICIARY_REFUSED"); private String value; diff --git a/health-services/project/src/main/java/org/egov/project/validator/project/ProjectValidator.java b/health-services/project/src/main/java/org/egov/project/validator/project/ProjectValidator.java index 9082f5a36a8..754fbc26fbe 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/project/ProjectValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/project/ProjectValidator.java @@ -1,5 +1,17 @@ package org.egov.project.validator.project; +import java.time.Duration; +import java.time.Instant; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +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; @@ -13,23 +25,17 @@ import org.egov.project.util.MDMSUtils; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Set; -import java.util.stream.Collectors; - +import static org.egov.project.util.ProjectConstants.MASTER_ATTENDANCE_SESSION; import static org.egov.project.util.ProjectConstants.MASTER_DEPARTMENT; import static org.egov.project.util.ProjectConstants.MASTER_NATUREOFWORK; import static org.egov.project.util.ProjectConstants.MASTER_PROJECTTYPE; import static org.egov.project.util.ProjectConstants.MASTER_TENANTS; import static org.egov.project.util.ProjectConstants.MDMS_COMMON_MASTERS_MODULE_NAME; +import static org.egov.project.util.ProjectConstants.MDMS_HCM_ATTENDANCE_MODULE_NAME; import static org.egov.project.util.ProjectConstants.MDMS_TENANT_MODULE_NAME; @Component @@ -45,6 +51,10 @@ public class ProjectValidator { @Autowired ProjectConfiguration config; + @Autowired + @Qualifier("objectMapper") + ObjectMapper mapper; + /* Validates create Project request body */ public void validateCreateProjectRequest(ProjectRequest request) { Map errorMap = new HashMap<>(); @@ -61,6 +71,7 @@ public void validateCreateProjectRequest(ProjectRequest request) { //Verify MDMS Data // TODO: Uncomment and fix as per HCM once we get clarity // validateRequestMDMSData(request, tenantId, errorMap); + validateAttendanceSessionAgainstMDMS(request,errorMap,tenantId); //Get boundaries in list from all Projects in request body for validation Map> boundariesForValidation = getBoundaryForValidation(request.getProjects()); @@ -183,6 +194,11 @@ private void validateProjectRequest(List projects) { log.error("Start date should be less than end date"); errorMap.put("INVALID_DATE", "Start date should be less than end date"); } + if (project.getStartDate() != null && project.getEndDate() != null && project.getEndDate() != 0 + && project.getEndDate().compareTo(Instant.ofEpochMilli(project.getStartDate()).plus(Duration.ofDays(1)).toEpochMilli()) < 0) { + log.error("Start date and end date difference should at least be 1 day."); + errorMap.put("INVALID_DATE", "Start date and end date difference should at least be 1 day."); + } if (project.getAddress() != null && StringUtils.isNotBlank(project.getAddress().getBoundary()) && StringUtils.isBlank(project.getAddress().getBoundaryType()) ) { log.error("Boundary Type is mandatory if boundary is present in Project request body"); errorMap.put("BOUNDARY", "Boundary Type is mandatory if boundary is present in Project request body"); @@ -303,6 +319,51 @@ private void validateMDMSData(List projects, Object mdmsData, Map errorMap, String tenantId) { + String rootTenantId = tenantId.split("\\.")[0]; + ObjectMapper objectMapper = new ObjectMapper(); + String numberOfSessions = null; + + //Get MDMS data using create project request and tenantId + Object mdmsData = mdmsUtils.mDMSCall(projectRequest, rootTenantId); + final String jsonPathForAttendanceSession = "$.MdmsRes." + MDMS_HCM_ATTENDANCE_MODULE_NAME + "." + MASTER_ATTENDANCE_SESSION + ".*"; + List attendanceRes = null; + try { + attendanceRes = JsonPath.read(mdmsData, jsonPathForAttendanceSession); + } catch (Exception e) { + log.error(e.getMessage()); + throw new CustomException("JSONPATH_ERROR", "Failed to parse mdms response"); + } + + for (Project project : projectRequest.getProjects()) { + JsonNode additionalDetails = null; + try { + Object additionalDetailsObj = project.getAdditionalDetails(); + String additionalDetailsStr = objectMapper.writeValueAsString(additionalDetailsObj); + additionalDetails = objectMapper.readTree(additionalDetailsStr); + + JsonNode numberOfSessionsNode = additionalDetails.get("numberOfSessions"); + if (numberOfSessionsNode != null && numberOfSessionsNode.isTextual()) { + numberOfSessions = numberOfSessionsNode.asText(); + log.info("Number of sessions: " + numberOfSessions); + } else { + log.info("numberOfSessions field not found in project's additonal Details"); + } + + } catch (ClassCastException e) { + log.error("Not able to parse additional details object", e); + } catch (Exception e) { + log.error("An unexpected error occurred while getting AdditionalDetails", e); + } + + // Validate numberOfSessions + if (!StringUtils.isBlank(numberOfSessions) && !attendanceRes.contains(numberOfSessions)) { + log.error("The number of attendance sessions " + numberOfSessions + " is not present in MDMS"); + errorMap.put("INVALID_NUMBER_OF_ATTENDANCE_SESSIONS", "The number of attendance sessions: " + numberOfSessions + " is not present in MDMS"); + } + } + } + /* Validate Project Request MDMS data */ private void validateRequestMDMSData(ProjectRequest request, String tenantId, Map errorMap) { String rootTenantId = tenantId.split("\\.")[0]; @@ -350,7 +411,17 @@ public void validateUpdateAgainstDB(List projectsFromRequest, List p.getId().equals(project.getId())).findFirst().orElse(null); @@ -359,6 +430,8 @@ public void validateUpdateAgainstDB(List projectsFromRequest, List projectsFromRequest, List projects, List parent } log.info("Parent projects validated against DB"); } -} +} \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/web/models/ProjectStaffSearch.java b/health-services/project/src/main/java/org/egov/project/web/models/ProjectStaffSearch.java index d5440bf84d5..c2279738914 100644 --- a/health-services/project/src/main/java/org/egov/project/web/models/ProjectStaffSearch.java +++ b/health-services/project/src/main/java/org/egov/project/web/models/ProjectStaffSearch.java @@ -37,8 +37,7 @@ public class ProjectStaffSearch { private String tenantId = null; @JsonProperty("staffId") - @Size(min=2,max=64) - private String staffId = null; + private List staffId = null; @JsonProperty("projectId") @Size(min=2,max=64) diff --git a/health-services/project/src/main/resources/application.properties b/health-services/project/src/main/resources/application.properties index 81fc4cd7f12..8364f5f71da 100644 --- a/health-services/project/src/main/resources/application.properties +++ b/health-services/project/src/main/resources/application.properties @@ -163,3 +163,7 @@ project.resource.consumer.bulk.delete.topic=delete-project-resource-bulk-topic project.mdms.module=HCM-PROJECT-TYPES egov.location.hierarchy.type=ADMIN + +#---------Attendance-----------# +project.staff.attendance.topic=project-staff-attendance-health-topic + diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectStaffServiceSearchTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectStaffServiceSearchTest.java index 5f8a6461f88..522b79708d3 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectStaffServiceSearchTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectStaffServiceSearchTest.java @@ -50,7 +50,7 @@ void shouldNotRaiseExceptionIfNoProjectStaffFound() throws Exception { any(Integer.class), any(String.class), eq(null), any(Boolean.class))) .thenReturn(Collections.emptyList()); ProjectStaffSearch projectStaffSearch = ProjectStaffSearch.builder() - .id(Collections.singletonList("ID101")).staffId("some-user-id").build(); + .id(Collections.singletonList("ID101")).staffId(Collections.singletonList("some-user-id")).build(); ProjectStaffSearchRequest projectStaffSearchRequest = ProjectStaffSearchRequest.builder() .projectStaff(projectStaffSearch).requestInfo(RequestInfoTestBuilder.builder() .withCompleteRequestInfo().build()).build(); diff --git a/health-services/referralmanagement/CHANGELOG.md b/health-services/referralmanagement/CHANGELOG.md index 266f4ddf3f5..55b1ba23b50 100644 --- a/health-services/referralmanagement/CHANGELOG.md +++ b/health-services/referralmanagement/CHANGELOG.md @@ -1,6 +1,9 @@ # Changelog All notable changes to this module will be documented in this file. +## 1.0.1 - 2024-02-28 +- Added functionality for referrals handled by health facilities, referred to as "hfreferral". + ## 1.0.0 - 2023-11-15 - Added Downsync Feature diff --git a/health-services/referralmanagement/pom.xml b/health-services/referralmanagement/pom.xml index 5ef135c8553..a13ab7a0182 100644 --- a/health-services/referralmanagement/pom.xml +++ b/health-services/referralmanagement/pom.xml @@ -6,7 +6,7 @@ referralmanagement jar referralmanagement - 1.0.0 + 1.0.1 1.8 ${java.version} @@ -50,7 +50,7 @@ org.egov.common health-services-models - 1.0.11-SNAPSHOT + 1.0.14-SNAPSHOT compile diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java index 7bd29b61cc1..f33a82c8bea 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java @@ -5,6 +5,8 @@ public interface Constants { String GET_SIDE_EFFECTS = "getSideEffects"; String SET_REFERRALS = "setReferrals"; String GET_REFERRALS = "getReferrals"; + String SET_HF_REFERRALS = "setHfReferrals"; + String GET_HF_REFERRALS = "getHfReferrals"; String VALIDATION_ERROR = "VALIDATION_ERROR"; String PROJECT_TYPES = "projectTypes"; String MDMS_RESPONSE = "MdmsRes"; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java index e529c27a4f2..1113ac58efb 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java @@ -61,9 +61,33 @@ public class ReferralManagementConfiguration { @Value("${referralmanagement.referral.consumer.bulk.delete.topic}") private String deleteReferralBulkTopic; + @Value("${referralmanagement.hfreferral.kafka.create.topic}") + private String createHFReferralTopic; + + @Value("${referralmanagement.hfreferral.kafka.update.topic}") + private String updateHFReferralTopic; + + @Value("${referralmanagement.hfreferral.kafka.delete.topic}") + private String deleteHFReferralTopic; + + @Value("${referralmanagement.hfreferral.consumer.bulk.create.topic}") + private String createHFReferralBulkTopic; + + @Value("${referralmanagement.hfreferral.consumer.bulk.update.topic}") + private String updateHFReferralBulkTopic; + + @Value("${referralmanagement.hfreferral.consumer.bulk.delete.topic}") + private String deleteHFReferralBulkTopic; + @Value("${egov.search.project.staff.url}") private String projectStaffSearchUrl; + @Value("${egov.search.project.facility.url}") + private String projectFacilitySearchUrl; + + @Value("${egov.search.project.url}") + private String projectSearchUrl; + @Value("${egov.facility.host}") private String facilityHost; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/HFReferralConsumer.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/HFReferralConsumer.java new file mode 100644 index 00000000000..d4b4469df52 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/HFReferralConsumer.java @@ -0,0 +1,110 @@ +package org.egov.referralmanagement.consumer; + +import java.util.Map; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.referralmanagement.service.HFReferralService; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Component; + +/** + * Kafka Consumer for handling HFReferral-related messages. + * Author: kanishq-egov + */ +@Component +@Slf4j +public class HFReferralConsumer { + + private final HFReferralService hfReferralService; + private final ObjectMapper objectMapper; + + @Autowired + public HFReferralConsumer(HFReferralService hfReferralService, + @Qualifier("objectMapper") ObjectMapper objectMapper) { + this.hfReferralService = hfReferralService; + this.objectMapper = objectMapper; + } + + /** + * Kafka listener method to handle bulk creation of HFReferrals. + * Author: kanishq-egov + * + * @param consumerRecord The Kafka message payload. + * @param topic The Kafka topic from which the message is received. + */ + @KafkaListener(topics = "${referralmanagement.hfreferral.consumer.bulk.create.topic}") + public void bulkCreate(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + // Convert the Kafka message payload to HFReferralBulkRequest + HFReferralBulkRequest request = objectMapper.convertValue(consumerRecord, HFReferralBulkRequest.class); + + // Invoke the HFReferralService to handle bulk creation + hfReferralService.create(request, true); + } catch (Exception exception) { + log.error("Error in HFReferral consumer bulk create", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + + // Throw a CustomException in case of an error during bulk creation + throw new CustomException("HCM_REFERRAL_MANAGEMENT_REFERRAL_CREATE", exception.getMessage()); + } + } + + /** + * Kafka listener method to handle bulk update of HFReferrals. + * Author: kanishq-egov + * + * @param consumerRecord The Kafka message payload. + * @param topic The Kafka topic from which the message is received. + */ + @KafkaListener(topics = "${referralmanagement.hfreferral.consumer.bulk.update.topic}") + public void bulkUpdate(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + // Convert the Kafka message payload to HFReferralBulkRequest + HFReferralBulkRequest request = objectMapper.convertValue(consumerRecord, HFReferralBulkRequest.class); + + // Invoke the HFReferralService to handle bulk update + hfReferralService.update(request, true); + } catch (Exception exception) { + log.error("Error in HFReferral consumer bulk update", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + + // Throw a CustomException in case of an error during bulk update + throw new CustomException("HCM_REFERRAL_MANAGEMENT_REFERRAL_UPDATE", exception.getMessage()); + } + } + + /** + * Kafka listener method to handle bulk deletion of HFReferrals. + * Author: kanishq-egov + * + * @param consumerRecord The Kafka message payload. + * @param topic The Kafka topic from which the message is received. + */ + @KafkaListener(topics = "${referralmanagement.hfreferral.consumer.bulk.delete.topic}") + public void bulkDelete(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + // Convert the Kafka message payload to HFReferralBulkRequest + HFReferralBulkRequest request = objectMapper.convertValue(consumerRecord, HFReferralBulkRequest.class); + + // Invoke the HFReferralService to handle bulk deletion + hfReferralService.delete(request, true); + } catch (Exception exception) { + log.error("Error in HFReferral consumer bulk delete", exception); + log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + + // Throw a CustomException in case of an error during bulk deletion + throw new CustomException("HCM_REFERRAL_MANAGEMENT_REFERRAL_DELETE", exception.getMessage()); + } + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java new file mode 100644 index 00000000000..f3b05004718 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java @@ -0,0 +1,151 @@ +package org.egov.referralmanagement.repository; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.builder.GenericQueryBuilder; +import org.egov.common.data.query.builder.QueryFieldChecker; +import org.egov.common.data.query.builder.SelectQueryBuilder; +import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralSearch; +import org.egov.common.producer.Producer; +import org.egov.referralmanagement.repository.rowmapper.HFReferralRowMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.stereotype.Repository; +import org.springframework.util.ReflectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdMethod; + +/** + * Repository class for managing the persistence and retrieval of HFReferral entities. + * This class extends GenericRepository for common CRUD operations. + * + * @author kanishq-egov + */ +@Repository +@Slf4j +public class HFReferralRepository extends GenericRepository { + + @Autowired + private HFReferralRowMapper rowMapper; + + /** + * Constructor for HFReferralRepository. + * + * @param producer The producer for publishing messages. + * @param namedParameterJdbcTemplate JDBC template for named parameters. + * @param redisTemplate Template for Redis operations. + * @param selectQueryBuilder Builder for creating SELECT queries. + * @param rowMapper Mapper for converting rows to HFReferral objects. + */ + @Autowired + protected HFReferralRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, + RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, + HFReferralRowMapper rowMapper) { + // Call the constructor of the GenericRepository with necessary parameters. + super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, rowMapper, Optional.of("hf_referral")); + } + + /** + * Retrieves a list of HFReferrals based on the provided search criteria. + * + * @param searchObject The search criteria for filtering HFReferrals. + * @param limit The maximum number of records to retrieve. + * @param offset The offset for pagination. + * @param tenantId The tenant ID for filtering. + * @param lastChangedSince Timestamp for filtering records changed since this time. + * @param includeDeleted Flag indicating whether to include deleted records. + * @return A list of HFReferral entities matching the search criteria. + */ + public List find(HFReferralSearch searchObject, Integer limit, Integer offset, String tenantId, + Long lastChangedSince, Boolean includeDeleted) { + // Initial query to select HFReferral fields from the table. + String query = "SELECT hf.id, hf.clientreferenceid, hf.tenantid, hf.projectid, hf.projectfacilityid, hf.symptom, hf.symptomsurveyid, hf.beneficiaryid, hf.referralcode, hf.nationallevelid, hf.createdby, hf.createdtime, hf.lastmodifiedby, hf.lastmodifiedtime, hf.clientcreatedby, hf.clientcreatedtime, hf.clientlastmodifiedby, hf.clientlastmodifiedtime, hf.rowversion, hf.isdeleted, hf.additionaldetails from hf_referral hf"; + Map paramsMap = new HashMap<>(); + + // Generate WHERE conditions based on non-null fields in the search object. + List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, + QueryFieldChecker.isNotNull, paramsMap); + + // Apply the WHERE conditions to the query. + query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); + query = query.replace("id IN (:id)", "hf.id IN (:id)"); + query = query.replace("clientReferenceId IN (:clientReferenceId)", "hf.clientReferenceId IN (:clientReferenceId)"); + + // Add additional conditions based on tenant ID, includeDeleted, and lastChangedSince. + query = query + " and hf.tenantId=:tenantId "; + if (Boolean.FALSE.equals(includeDeleted)) { + query = query + "and hf.isDeleted=:isDeleted "; + } + + if (lastChangedSince != null) { + query = query + "and hf.lastModifiedTime>=:lastModifiedTime "; + } + + // Add ORDER BY, LIMIT, and OFFSET clauses to the query. + query = query + "ORDER BY hf.id ASC LIMIT :limit OFFSET :offset"; + paramsMap.put("tenantId", tenantId); + paramsMap.put("isDeleted", includeDeleted); + paramsMap.put("lastModifiedTime", lastChangedSince); + paramsMap.put("limit", limit); + paramsMap.put("offset", offset); + + // Execute the query and retrieve the list of HFReferral entities. + List hfReferralList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + return hfReferralList; + } + + /** + * Retrieves a list of HFReferrals based on a list of IDs. + * + * @param ids The list of IDs to search for. + * @param includeDeleted Flag indicating whether to include deleted records. + * @param columnName The column name to search for IDs. + * @return A list of HFReferral entities matching the provided IDs. + */ + public List findById(List ids, Boolean includeDeleted, String columnName) { + // Find objects in the cache based on the provided IDs. + List objFound = findInCache(ids).stream() + .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) + .collect(Collectors.toList()); + + // If objects are found in the cache, check if there are any IDs remaining to be retrieved. + if (!objFound.isEmpty()) { + Method idMethod = getIdMethod(objFound, columnName); + ids.removeAll(objFound.stream() + .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) + .collect(Collectors.toList())); + + // If no IDs are remaining, return the objects found in the cache. + if (ids.isEmpty()) { + return objFound; + } + } + + // Generate a SELECT query based on the provided IDs and column name. + String query = String.format("SELECT hf.id, hf.clientreferenceid, hf.tenantid, hf.projectid, hf.projectfacilityid, hf.symptom, hf.symptomsurveyid, hf.beneficiaryid, hf.referralcode, hf.nationallevelid, hf.createdby, hf.createdtime, hf.lastmodifiedby, hf.lastmodifiedtime, hf.clientcreatedby, hf.clientcreatedtime, hf.clientlastmodifiedby, hf.clientlastmodifiedtime, hf.rowversion, hf.isdeleted, hf.additionaldetails from hf_referral hf WHERE hf.%s IN (:ids) ", columnName); + + // Add conditions to exclude deleted records if includeDeleted is false. + if (includeDeleted == null || !includeDeleted) { + query += " AND hf.isDeleted = false "; + } + + // Create parameter map for the query and execute it to retrieve HFReferral entities. + Map paramMap = new HashMap<>(); + paramMap.put("ids", ids); + List hfReferralList = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + + // Add the retrieved entities to the cache. + objFound.addAll(hfReferralList); + putInCache(objFound); + return objFound; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HFReferralRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HFReferralRowMapper.java new file mode 100644 index 00000000000..3f9b5084872 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HFReferralRowMapper.java @@ -0,0 +1,78 @@ +package org.egov.referralmanagement.repository.rowmapper; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import org.egov.common.models.project.AdditionalFields; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; + +/** + * RowMapper implementation for mapping ResultSet rows to HFReferral objects. + * This class is responsible for converting database query results into Java objects. + * + * @author kanishq-egov + */ +@Component +public class HFReferralRowMapper implements RowMapper { + + @Autowired + ObjectMapper objectMapper; + + /** + * Maps a ResultSet row to an HFReferral object. + * + * @param resultSet The result set containing the queried data. + * @param i The current row number. + * @return An HFReferral object mapped from the ResultSet row. + * @throws SQLException If there's an issue accessing ResultSet data. + */ + @Override + public HFReferral mapRow(ResultSet resultSet, int i) throws SQLException { + try { + // Create AuditDetails object from the ResultSet data. + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + + // Create clientAuditDetails object from the ResultSet data. + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("clientCreatedBy")) + .createdTime(resultSet.getLong("clientCreatedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .build(); + + // Build and return HFReferral object using ResultSet data and ObjectMapper for additionalFields. + return HFReferral.builder() + .id(resultSet.getString("id")) + .clientReferenceId(resultSet.getString("clientreferenceid")) + .tenantId(resultSet.getString("tenantid")) + .projectId(resultSet.getString("projectid")) + .projectFacilityId(resultSet.getString("projectfacilityid")) + .symptom(resultSet.getString("symptom")) + .symptomSurveyId(resultSet.getString("symptomsurveyid")) + .beneficiaryId(resultSet.getString("beneficiaryid")) + .referralCode(resultSet.getString("referralcode")) + .nationalLevelId(resultSet.getString("nationallevelid")) + .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper + .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) + .rowVersion(resultSet.getInt("rowversion")) + .isDeleted(resultSet.getBoolean("isdeleted")) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) + .build(); + } catch (JsonProcessingException e) { + // Wrap JsonProcessingException as a RuntimeException for simplicity. + throw new RuntimeException(e); + } + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/HFReferralService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/HFReferralService.java new file mode 100644 index 00000000000..aaf317acafc --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/HFReferralService.java @@ -0,0 +1,263 @@ +package org.egov.referralmanagement.service; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.ds.Tuple; +import org.egov.common.models.ErrorDetails; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralRequest; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralSearchRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.Constants; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.repository.HFReferralRepository; +import org.egov.referralmanagement.service.enrichment.HFReferralEnrichmentService; +import org.egov.referralmanagement.validator.hfreferral.HfrIsDeletedValidator; +import org.egov.referralmanagement.validator.hfreferral.HfrNonExistentEntityValidator; +import org.egov.referralmanagement.validator.hfreferral.HfrNullIdValidator; +import org.egov.referralmanagement.validator.hfreferral.HfrProjectFacilityIdValidator; +import org.egov.referralmanagement.validator.hfreferral.HfrProjectIdValidator; +import org.egov.referralmanagement.validator.hfreferral.HfrRowVersionValidator; +import org.egov.referralmanagement.validator.hfreferral.HfrUniqueEntityValidator; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Service; +import org.springframework.util.ReflectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +/** + * Service class for handling operations related to HFReferral entities. + * Manages creation, updating, searching, and deletion of HFReferrals. + * Includes validation and enrichment of HFReferrals before interacting with the repository. + * Author: kanishq-egov + */ +@Service +@Slf4j +public class HFReferralService { + + private final IdGenService idGenService; + private final HFReferralRepository hfReferralRepository; + private final ReferralManagementConfiguration referralManagementConfiguration; + private final HFReferralEnrichmentService hfReferralEnrichmentService; + private final List> validators; + + // Predicates to determine which validators are applicable for create, update, and delete operations + private final Predicate> isApplicableForCreate = validator -> + validator.getClass().equals(HfrProjectIdValidator.class) + || validator.getClass().equals(HfrProjectFacilityIdValidator.class); + + private final Predicate> isApplicableForUpdate = validator -> + validator.getClass().equals(HfrProjectIdValidator.class) + || validator.getClass().equals(HfrProjectFacilityIdValidator.class) + || validator.getClass().equals(HfrNullIdValidator.class) + || validator.getClass().equals(HfrIsDeletedValidator.class) + || validator.getClass().equals(HfrUniqueEntityValidator.class) + || validator.getClass().equals(HfrNonExistentEntityValidator.class) + || validator.getClass().equals(HfrRowVersionValidator.class); + + private final Predicate> isApplicableForDelete = validator -> + validator.getClass().equals(HfrNullIdValidator.class) + || validator.getClass().equals(HfrNonExistentEntityValidator.class) + || validator.getClass().equals(HfrRowVersionValidator.class); + + /** + * Constructor to initialize the service with required dependencies. + * + * @param idGenService The IdGenService for generating IDs. + * @param hfReferralRepository The repository for HFReferral entities. + * @param referralManagementConfiguration The configuration for referral management. + * @param hfReferralEnrichmentService The service for enriching HFReferral entities. + * @param validators The list of validators for HFReferral entities. + */ + public HFReferralService(IdGenService idGenService, HFReferralRepository hfReferralRepository, + ReferralManagementConfiguration referralManagementConfiguration, + HFReferralEnrichmentService hfReferralEnrichmentService, + List> validators) { + this.idGenService = idGenService; + this.hfReferralRepository = hfReferralRepository; + this.referralManagementConfiguration = referralManagementConfiguration; + this.hfReferralEnrichmentService = hfReferralEnrichmentService; + this.validators = validators; + } + + // Method to create a single HFReferral + public HFReferral create(HFReferralRequest request) { + log.info("Received request to create a referral"); + HFReferralBulkRequest bulkRequest = HFReferralBulkRequest.builder().requestInfo(request.getRequestInfo()) + .hfReferrals(Collections.singletonList(request.getHfReferral())).build(); + log.info("Creating bulk request"); + return create(bulkRequest, false).get(0); + } + + // Method to create multiple HFReferrals in bulk + public List create(HFReferralBulkRequest hfReferralRequest, boolean isBulk) { + log.info("Received request to create bulk referrals"); + Tuple, Map> tuple = validate(validators, + isApplicableForCreate, hfReferralRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validReferrals = tuple.getX(); + + try { + if (!validReferrals.isEmpty()) { + log.info("Processing {} valid entities", validReferrals.size()); + hfReferralEnrichmentService.create(validReferrals, hfReferralRequest); + hfReferralRepository.save(validReferrals, + referralManagementConfiguration.getCreateHFReferralTopic()); + log.info("Successfully created referrals"); + } + } catch (Exception exception) { + log.error("Error occurred while creating referrals: {}", exception.getMessage()); + populateErrorDetails(hfReferralRequest, errorDetailsMap, validReferrals, + exception, Constants.SET_HF_REFERRALS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validReferrals; + } + + // Method to update a single HFReferral + public HFReferral update(HFReferralRequest request) { + log.info("Received request to update a referral"); + HFReferralBulkRequest bulkRequest = HFReferralBulkRequest.builder().requestInfo(request.getRequestInfo()) + .hfReferrals(Collections.singletonList(request.getHfReferral())).build(); + log.info("Creating bulk request"); + return update(bulkRequest, false).get(0); + } + + // Method to update multiple HFReferrals in bulk + public List update(HFReferralBulkRequest hfReferralRequest, boolean isBulk) { + log.info("Received request to update bulk referrals"); + Tuple, Map> tuple = validate(validators, + isApplicableForUpdate, hfReferralRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validReferrals = tuple.getX(); + + try { + if (!validReferrals.isEmpty()) { + log.info("Processing {} valid entities", validReferrals.size()); + hfReferralEnrichmentService.update(validReferrals, hfReferralRequest); + hfReferralRepository.save(validReferrals, + referralManagementConfiguration.getUpdateHFReferralTopic()); + log.info("Successfully updated bulk referrals"); + } + } catch (Exception exception) { + log.error("Error occurred while updating referrals", exception); + populateErrorDetails(hfReferralRequest, errorDetailsMap, validReferrals, + exception, Constants.SET_HF_REFERRALS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validReferrals; + } + + // Method to search for HFReferrals based on certain criteria + public List search(HFReferralSearchRequest referralSearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) { + log.info("Received request to search referrals"); + String idFieldName = getIdFieldName(referralSearchRequest.getHfReferral()); + + // If searching by ID only, fetch referrals with specified IDs + if (isSearchByIdOnly(referralSearchRequest.getHfReferral(), idFieldName)) { + log.info("Searching referrals by ID"); + List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections + .singletonList(referralSearchRequest.getHfReferral())), + referralSearchRequest.getHfReferral()); + log.info("Fetching referrals with IDs: {}", ids); + + return hfReferralRepository.findById(ids, includeDeleted, idFieldName).stream() + .filter(lastChangedSince(lastChangedSince)) + .filter(havingTenantId(tenantId)) + .filter(includeDeleted(includeDeleted)) + .collect(Collectors.toList()); + } + + log.info("Searching referrals using criteria"); + return hfReferralRepository.find(referralSearchRequest.getHfReferral(), + limit, offset, tenantId, lastChangedSince, includeDeleted); + } + + // Method to delete a single HFReferral + public HFReferral delete(HFReferralRequest hfReferralRequest) { + log.info("Received request to delete a referral"); + HFReferralBulkRequest bulkRequest = HFReferralBulkRequest.builder().requestInfo(hfReferralRequest.getRequestInfo()) + .hfReferrals(Collections.singletonList(hfReferralRequest.getHfReferral())).build(); + log.info("Creating bulk request"); + return delete(bulkRequest, false).get(0); + } + + // Method to delete multiple HFReferrals in bulk + public List delete(HFReferralBulkRequest hfReferralRequest, boolean isBulk) { + Tuple, Map> tuple = validate(validators, + isApplicableForDelete, hfReferralRequest, isBulk); + Map errorDetailsMap = tuple.getY(); + List validReferrals = tuple.getX(); + + try { + if (!validReferrals.isEmpty()) { + log.info("Processing {} valid entities", validReferrals.size()); + List referralIds = validReferrals.stream().map(entity -> entity.getId()).collect(Collectors.toSet()).stream().collect(Collectors.toList()); + List existingReferrals = hfReferralRepository + .findById(referralIds, false); + hfReferralEnrichmentService.delete(existingReferrals, hfReferralRequest); + hfReferralRepository.save(existingReferrals, + referralManagementConfiguration.getDeleteHFReferralTopic()); + log.info("Successfully deleted entities"); + } + } catch (Exception exception) { + log.error("Error occurred while deleting entities: {}", exception); + populateErrorDetails(hfReferralRequest, errorDetailsMap, validReferrals, + exception, Constants.SET_HF_REFERRALS); + } + handleErrors(errorDetailsMap, isBulk, Constants.VALIDATION_ERROR); + + return validReferrals; + } + + // Method to put HFReferrals in cache + public void putInCache(List hfReferrals) { + log.info("Putting {} HFReferrals in cache", hfReferrals.size()); + hfReferralRepository.putInCache(hfReferrals); + log.info("Successfully put HFReferrals in cache"); + } + + // Method to validate HFReferralBulkRequest + private Tuple, Map> validate( + List> validators, + Predicate> isApplicable, + HFReferralBulkRequest request, + boolean isBulk + ) { + log.info("Validating request"); + Map errorDetailsMap = CommonUtils.validate(validators, + isApplicable, request, + Constants.SET_HF_REFERRALS); + if (!errorDetailsMap.isEmpty() && !isBulk) { + log.error("Validation error occurred. Error details: {}", errorDetailsMap.values()); + throw new CustomException(Constants.VALIDATION_ERROR, errorDetailsMap.values().toString()); + } + List validReferrals = request.getHfReferrals().stream() + .filter(notHavingErrors()).collect(Collectors.toList()); + log.info("Validation successful, found valid referrals"); + return new Tuple<>(validReferrals, errorDetailsMap); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/HFReferralEnrichmentService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/HFReferralEnrichmentService.java new file mode 100644 index 00000000000..158b17c126d --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/enrichment/HFReferralEnrichmentService.java @@ -0,0 +1,57 @@ +package org.egov.referralmanagement.service.enrichment; + +import java.util.List; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.utils.CommonUtils; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.enrichForCreate; +import static org.egov.common.utils.CommonUtils.enrichForDelete; +import static org.egov.common.utils.CommonUtils.enrichForUpdate; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; + +@Component +@Slf4j +public class HFReferralEnrichmentService { + + /** + * + * @param entities + * @param request + */ + public void create(List entities, HFReferralBulkRequest request) { + log.info("starting the enrichment for create hfReferrals"); + log.info("generating IDs using UUID"); + List idList = CommonUtils.uuidSupplier().apply(entities.size()); + log.info("enriching referrals with generated IDs"); + enrichForCreate(entities, idList, request.getRequestInfo()); + log.info("enrichment done"); + } + + /** + * + * @param entities + * @param request + */ + public void update(List entities, HFReferralBulkRequest request) { + log.info("starting the enrichment for create hfReferrals"); + Map referralMap = getIdToObjMap(entities); + enrichForUpdate(referralMap, entities, request); + log.info("enrichment done"); + } + + /** + * + * @param entities + * @param request + */ + public void delete(List entities, HFReferralBulkRequest request) { + log.info("starting the enrichment for delete hfReferrals"); + enrichForDelete(entities, request.getRequestInfo(), true); + log.info("enrichment done"); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrIsDeletedValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrIsDeletedValidator.java new file mode 100644 index 00000000000..92a2fcfdd53 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrIsDeletedValidator.java @@ -0,0 +1,45 @@ +package org.egov.referralmanagement.validator.hfreferral; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForIsDelete; + +/** + * Validator for checking the 'isDeleted' field in HFReferral entities. + * + * Author: kanishq-egov + */ +@Component +@Order(2) +@Slf4j +public class HfrIsDeletedValidator implements Validator { + + /** + * Validates the 'isDeleted' field for each HFReferral entity in the bulk request. + * + * @param request The HFReferralBulkRequest containing a list of HFReferral entities + * @return A Map containing HFReferral entities as keys and lists of errors as values + */ + @Override + public Map> validate(HFReferralBulkRequest request) { + log.info("validating isDeleted field"); + HashMap> errorDetailsMap = new HashMap<>(); + List validEntities = request.getHfReferrals(); + validEntities.stream().filter(HFReferral::getIsDeleted).forEach(hfReferral -> { + Error error = getErrorForIsDelete(); + populateErrorDetails(hfReferral, error, errorDetailsMap); + }); + return errorDetailsMap; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNonExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNonExistentEntityValidator.java new file mode 100644 index 00000000000..515d37624a4 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNonExistentEntityValidator.java @@ -0,0 +1,80 @@ +package org.egov.referralmanagement.validator.hfreferral; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.repository.HFReferralRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.getObjClass; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; +import static org.egov.referralmanagement.Constants.GET_ID; + +/** + * Validator for checking the existence of entities referred in HFReferral entities. + * + * Author: kanishq-egov + */ +@Component +@Order(value = 4) +@Slf4j +public class HfrNonExistentEntityValidator implements Validator { + + private final HFReferralRepository hfReferralRepository; + + private final ObjectMapper objectMapper; + + @Autowired + public HfrNonExistentEntityValidator(HFReferralRepository hfReferralRepository, ObjectMapper objectMapper) { + this.hfReferralRepository = hfReferralRepository; + this.objectMapper = objectMapper; + } + + /** + * Validates the existence of entities referred in HFReferral entities. + * + * @param request The HFReferralBulkRequest containing a list of HFReferral entities + * @return A Map containing HFReferral entities as keys and lists of errors as values + */ + @Override + public Map> validate(HFReferralBulkRequest request) { + log.info("validating for existence of entity"); + Map> errorDetailsMap = new HashMap<>(); + List hfReferrals = request.getHfReferrals(); + Class objClass = getObjClass(hfReferrals); + Method idMethod = getMethod(GET_ID, objClass); + Map iMap = getIdToObjMap(hfReferrals + .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + if (!iMap.isEmpty()) { + List referralIds = new ArrayList<>(iMap.keySet()); + List existingReferrals = hfReferralRepository + .findById(referralIds, false, getIdFieldName(idMethod)); + List nonExistentReferrals = checkNonExistentEntities(iMap, + existingReferrals, idMethod); + nonExistentReferrals.forEach(sideEffect -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(sideEffect, error, errorDetailsMap); + }); + } + + return errorDetailsMap; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNullIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNullIdValidator.java new file mode 100644 index 00000000000..26defef4fa4 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrNullIdValidator.java @@ -0,0 +1,38 @@ +package org.egov.referralmanagement.validator.hfreferral; + +import java.util.List; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.validateForNullId; +import static org.egov.referralmanagement.Constants.GET_HF_REFERRALS; + +/** + * Validator for checking null id in HFReferral entities. + * + * Author: kanishq-egov + */ +@Component +@Order(value = 1) +@Slf4j +public class HfrNullIdValidator implements Validator { + + /** + * Validates if HFReferral entities have null ids. + * + * @param request The HFReferralBulkRequest containing a list of HFReferral entities + * @return A Map containing HFReferral entities as keys and lists of errors as values + */ + @Override + public Map> validate(HFReferralBulkRequest request) { + log.info("validating for null id"); + return validateForNullId(request, GET_HF_REFERRALS); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrProjectFacilityIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrProjectFacilityIdValidator.java new file mode 100644 index 00000000000..82ac9dba00a --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrProjectFacilityIdValidator.java @@ -0,0 +1,134 @@ +package org.egov.referralmanagement.validator.hfreferral; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.project.ProjectFacility; +import org.egov.common.models.project.ProjectFacilityBulkResponse; +import org.egov.common.models.project.ProjectFacilitySearch; +import org.egov.common.models.project.ProjectFacilitySearchRequest; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + +/** + * Validator for checking the existence of ProjectFacility entities based on their IDs in HFReferral objects. + * + * Author: kanishq-egov + */ +@Component +@Order(value = 3) +@Slf4j +public class HfrProjectFacilityIdValidator implements Validator { + + private final ServiceRequestClient serviceRequestClient; + private final ReferralManagementConfiguration referralManagementConfiguration; + + public HfrProjectFacilityIdValidator(ServiceRequestClient serviceRequestClient, ReferralManagementConfiguration referralManagementConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.referralManagementConfiguration = referralManagementConfiguration; + } + + /** + * Validates whether project facilities exist in the database or not using project facility IDs for HFReferral objects. + * + * @param request The HFReferralBulkRequest containing a list of HFReferral entities + * @return A Map containing HFReferral entities as keys and lists of errors as values + */ + @Override + public Map> validate(HFReferralBulkRequest request) { + log.info("Validating project facility IDs"); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getHfReferrals(); + + // Grouping HFReferrals by tenantId to fetch project facilities for each tenant + Map> tenantIdReferralMap = entities.stream().collect(Collectors.groupingBy(HFReferral::getTenantId)); + tenantIdReferralMap.forEach((tenantId, hfReferralList) -> { + // Get all the existing project facilities in the HFReferral list from Project Service + List existingProjectFacilities = getExistingProjects(tenantId, hfReferralList, request); + // Validate project facilities and populate error map if invalid entities are found + validateAndPopulateErrors(existingProjectFacilities, entities, errorDetailsMap); + }); + + return errorDetailsMap; + } + + // Helper method to add an item to a list if it is not null + private void addIgnoreNull(List list, String item) { + if(Objects.nonNull(item)) list.add(item); + } + + // Fetches existing project facilities from Project Service based on their IDs + private List getExistingProjects(String tenantId, List hfReferrals, HFReferralBulkRequest request) { + List existingProjectFacilities = new ArrayList<>(); + final List projectFacilityIdList = new ArrayList<>(); + + // Collecting project facility IDs from HFReferrals + hfReferrals.forEach(hfReferral -> { + addIgnoreNull(projectFacilityIdList, hfReferral.getProjectFacilityId()); + }); + + if(!projectFacilityIdList.isEmpty()) { + ProjectFacilitySearch projectFacilitySearch = ProjectFacilitySearch.builder() + .id(!projectFacilityIdList.isEmpty()? projectFacilityIdList : null) + .tenantId(tenantId) + .build(); + + try { + // Using project facility search and fetching the valid IDs. + ProjectFacilityBulkResponse projectFacilityBulkResponse = serviceRequestClient.fetchResult( + new StringBuilder(referralManagementConfiguration.getProjectHost() + + referralManagementConfiguration.getProjectFacilitySearchUrl() + +"?limit=" + hfReferrals.size() + + "&offset=0&tenantId=" + tenantId), + ProjectFacilitySearchRequest.builder() + .requestInfo(request.getRequestInfo()) + .projectFacility(projectFacilitySearch) + .build(), + ProjectFacilityBulkResponse.class + ); + existingProjectFacilities = projectFacilityBulkResponse.getProjectFacilities(); + } catch (Exception e) { + throw new CustomException("Project Facilities failed to fetch", "Exception : "+e.getMessage()); + } + } + + return existingProjectFacilities; + } + + // Validates project facilities and populates the error map if invalid entities are found + private void validateAndPopulateErrors(List existingProjectFacilities, List entities, Map> errorDetailsMap) { + final List existingProjectFacilityIds = new ArrayList<>(); + + // Extracting IDs from existing project facilities + existingProjectFacilities.forEach(projectFacility -> { + existingProjectFacilityIds.add(projectFacility.getId()); + }); + + // Filtering invalid entities + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + Objects.nonNull(entity.getProjectFacilityId()) && !existingProjectFacilityIds.contains(entity.getProjectFacilityId()) + ).collect(Collectors.toList()); + + // Populating error details for invalid entities + invalidEntities.forEach(hfReferral -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(hfReferral, error, errorDetailsMap); + }); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrProjectIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrProjectIdValidator.java new file mode 100644 index 00000000000..78fc23289c4 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrProjectIdValidator.java @@ -0,0 +1,131 @@ +package org.egov.referralmanagement.validator.hfreferral; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.project.Project; +import org.egov.common.models.project.ProjectRequest; +import org.egov.common.models.project.ProjectResponse; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; + +/** + * Validator for checking the existence of Project entities based on their IDs in HFReferral objects. + * + * Author: kanishq-egov + */ +@Component +@Order(value = 3) +@Slf4j +public class HfrProjectIdValidator implements Validator { + + private final ServiceRequestClient serviceRequestClient; + private final ReferralManagementConfiguration referralManagementConfiguration; + + public HfrProjectIdValidator(ServiceRequestClient serviceRequestClient, ReferralManagementConfiguration referralManagementConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.referralManagementConfiguration = referralManagementConfiguration; + } + + /** + * Validates whether projects exist in the database or not using project IDs for HFReferral objects. + * + * @param request The HFReferralBulkRequest containing a list of HFReferral entities + * @return A Map containing HFReferral entities as keys and lists of errors as values + */ + @Override + public Map> validate(HFReferralBulkRequest request) { + log.info("Validating project IDs"); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getHfReferrals(); + + // Grouping HFReferrals by tenantId to fetch projects for each tenant + Map> tenantIdReferralMap = entities.stream().collect(Collectors.groupingBy(HFReferral::getTenantId)); + tenantIdReferralMap.forEach((tenantId, hfReferralList) -> { + // Get all the existing projects in the hfReferral list from Project Service + List existingProjects = getExistingProjects(tenantId, hfReferralList, request); + // Validate projects and populate error map if invalid entities are found + validateAndPopulateErrors(existingProjects, entities, errorDetailsMap); + }); + + return errorDetailsMap; + } + + // Helper method to add an item to a list if it is not null + private void addIgnoreNull(List list, String item) { + if (Objects.nonNull(item)) list.add(item); + } + + // Fetches existing projects from Project Service based on their IDs + private List getExistingProjects(String tenantId, List hfReferrals, HFReferralBulkRequest request) { + List existingProjects = null; + final List projectIdList = new ArrayList<>(); + + // Collecting project IDs from HFReferrals + hfReferrals.forEach(hfReferral -> { + addIgnoreNull(projectIdList, hfReferral.getProjectId()); + }); + + if (!projectIdList.isEmpty()) { + List projects = new ArrayList<>(); + projectIdList.forEach(projectId -> projects.add(Project.builder().id(projectId).tenantId(tenantId).build())); + + try { + // Using project search and fetching the valid IDs. + ProjectResponse projectResponse = serviceRequestClient.fetchResult( + new StringBuilder(referralManagementConfiguration.getProjectHost() + + referralManagementConfiguration.getProjectSearchUrl() + + "?limit=" + hfReferrals.size() + + "&offset=0&tenantId=" + tenantId), + ProjectRequest.builder() + .requestInfo(request.getRequestInfo()) + .projects(projects) + .build(), + ProjectResponse.class + ); + existingProjects = projectResponse.getProject(); + } catch (Exception e) { + throw new CustomException("Projects failed to fetch", "Exception : " + e.getMessage()); + } + } + + return existingProjects; + } + + // Validates projects and populates the error map if invalid entities are found + private void validateAndPopulateErrors(List existingProjects, List entities, Map> errorDetailsMap) { + final List existingProjectIds = new ArrayList<>(); + + // Extracting IDs from existing projects + existingProjects.forEach(project -> { + existingProjectIds.add(project.getId()); + }); + + // Filtering invalid entities + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + Objects.nonNull(entity.getProjectId()) && !existingProjectIds.contains(entity.getProjectId()) + ).collect(Collectors.toList()); + + // Populating error details for invalid entities + invalidEntities.forEach(hfReferral -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(hfReferral, error, errorDetailsMap); + }); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrRowVersionValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrRowVersionValidator.java new file mode 100644 index 00000000000..e5d62bfee0a --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrRowVersionValidator.java @@ -0,0 +1,74 @@ +package org.egov.referralmanagement.validator.hfreferral; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.repository.HFReferralRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.getEntitiesWithMismatchedRowVersion; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForRowVersionMismatch; + +/** + * + * Validator for checking row version mismatch in HFReferral entities during bulk processing. + * Ensures that the row version of existing entities matches the row version in the request. + * + * @author kanishq-egov + */ +@Component +@Order(value = 5) +@Slf4j +public class HfrRowVersionValidator implements Validator { + + private final HFReferralRepository hfReferralRepository; + + @Autowired + public HfrRowVersionValidator(HFReferralRepository hfReferralRepository) { + this.hfReferralRepository = hfReferralRepository; + } + + /** + * Validates row version for HFReferral entities in a bulk request. + * + * @param request The HFReferralBulkRequest containing a list of HFReferral entities + * @return A Map containing HFReferral entities as keys and lists of errors as values + */ + @Override + public Map> validate(HFReferralBulkRequest request) { + log.info("Validating row version"); + Map> errorDetailsMap = new HashMap<>(); + Method idMethod = getIdMethod(request.getHfReferrals()); + Map iMap = getIdToObjMap(request.getHfReferrals().stream() + .filter(notHavingErrors()) + .collect(Collectors.toList()), idMethod); + if (!iMap.isEmpty()) { + List hfReferralIds = new ArrayList<>(iMap.keySet()); + List existingHfReferrals = hfReferralRepository.findById(hfReferralIds, + false, getIdFieldName(idMethod)); + List entitiesWithMismatchedRowVersion = + getEntitiesWithMismatchedRowVersion(iMap, existingHfReferrals, idMethod); + entitiesWithMismatchedRowVersion.forEach(hfReferral -> { + Error error = getErrorForRowVersionMismatch(); + populateErrorDetails(hfReferral, error, errorDetailsMap); + }); + } + return errorDetailsMap; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrUniqueEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrUniqueEntityValidator.java new file mode 100644 index 00000000000..42c84640201 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrUniqueEntityValidator.java @@ -0,0 +1,65 @@ +package org.egov.referralmanagement.validator.hfreferral; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * + * Validator for checking uniqueness of HFReferral entities in a bulk request. + * Ensures that there are no duplicate entities based on their IDs. + * + * Author: kanishq-egov + */ +@Component +@Order(value = 2) +@Slf4j +public class HfrUniqueEntityValidator implements Validator { + + /** + * Validates the uniqueness of HFReferral entities based on their IDs. + * + * @param request The HFReferralBulkRequest containing a list of HFReferral entities + * @return A Map containing HFReferral entities as keys and lists of errors as values + */ + @Override + public Map> validate(HFReferralBulkRequest request) { + log.info("Validating unique entity"); + Map> errorDetailsMap = new HashMap<>(); + List validEntities = request.getHfReferrals() + .stream().filter(notHavingErrors()).collect(Collectors.toList()); + if (!validEntities.isEmpty()) { + // Create a map of entity IDs to HFReferral objects + Map eMap = getIdToObjMap(validEntities); + + // Check for duplicate IDs + if (eMap.keySet().size() != validEntities.size()) { + List duplicates = eMap.keySet().stream().filter(id -> + validEntities.stream() + .filter(entity -> entity.getId().equals(id)).count() > 1 + ).collect(Collectors.toList()); + + // Populate errors for duplicate entities + for (String key : duplicates) { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(eMap.get(key), error, errorDetailsMap); + } + } + } + return errorDetailsMap; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/HFReferralApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/HFReferralApiController.java new file mode 100644 index 00000000000..97650777201 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/HFReferralApiController.java @@ -0,0 +1,193 @@ +package org.egov.referralmanagement.web.controllers; + +import java.util.List; +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import javax.validation.constraints.Max; +import javax.validation.constraints.Min; +import javax.validation.constraints.NotNull; + +import io.swagger.annotations.ApiParam; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkResponse; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralRequest; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralResponse; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralSearchRequest; +import org.egov.common.producer.Producer; +import org.egov.common.utils.ResponseInfoFactory; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.service.HFReferralService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * Controller class for managing HF Referrals. + * @author kanishq-egov + */ +@Controller +@RequestMapping("/hf-referral") +@Validated +public class HFReferralApiController { + private final HttpServletRequest httpServletRequest; + private final HFReferralService hfReferralService; + private final Producer producer; + private final ReferralManagementConfiguration referralManagementConfiguration; + + /** + * Constructor for HFReferralApiController. + * + * @param httpServletRequest The HTTP servlet request. + * @param hfReferralService The service for handling HFReferral operations. + * @param producer The Kafka producer. + * @param referralManagementConfiguration The configuration for referral management. + */ + public HFReferralApiController( + HttpServletRequest httpServletRequest, + HFReferralService hfReferralService, + Producer producer, + ReferralManagementConfiguration referralManagementConfiguration + ) { + this.httpServletRequest = httpServletRequest; + this.hfReferralService = hfReferralService; + this.producer = producer; + this.referralManagementConfiguration = referralManagementConfiguration; + } + + /** + * API endpoint to create a single HFReferral. + * + * @param request The HFReferralRequest containing referral details. + * @return ResponseEntity containing HFReferralResponse. + */ + @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) + public ResponseEntity referralV1CreatePost(@ApiParam(value = "Capture details of HFReferral", required = true) @Valid @RequestBody HFReferralRequest request) { + + HFReferral hfReferral = hfReferralService.create(request); + HFReferralResponse response = HFReferralResponse.builder() + .hfReferral(hfReferral) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } + + /** + * API endpoint to create multiple HFReferrals in bulk. + * + * @param request The HFReferralBulkRequest containing bulk referral details. + * @return ResponseEntity containing ResponseInfo. + */ + @RequestMapping(value = "/v1/bulk/_create", method = RequestMethod.POST) + public ResponseEntity referralBulkV1CreatePost(@ApiParam(value = "Capture details of HFReferral", required = true) @Valid @RequestBody HFReferralBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + hfReferralService.putInCache(request.getHfReferrals()); + producer.push(referralManagementConfiguration.getCreateHFReferralBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + + /** + * API endpoint to search for HFReferrals based on certain criteria. + * + * @param request The HFReferralSearchRequest containing search criteria. + * @param limit Pagination - limit records in response. + * @param offset Pagination - offset from which records should be returned in response. + * @param tenantId Unique id for a tenant. + * @param lastChangedSince Epoch of the time since when the changes on the object should be picked up. + * @param includeDeleted Used in search APIs to specify if (soft) deleted records should be included in search results. + * @return ResponseEntity containing HFReferralBulkResponse. + * @throws Exception + */ + @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) + public ResponseEntity referralV1SearchPost(@ApiParam(value = "HFReferral Search.", required = true) @Valid @RequestBody HFReferralSearchRequest request, + @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, + @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, + @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, + @ApiParam(value = "Epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, + @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { + + List hfReferrals = hfReferralService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); + HFReferralBulkResponse response = HFReferralBulkResponse.builder().responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)).hfReferrals(hfReferrals).build(); + + return ResponseEntity.status(HttpStatus.OK).body(response); + } + + /** + * API endpoint to update a single HFReferral. + * + * @param request The HFReferralRequest containing updated referral details. + * @return ResponseEntity containing HFReferralResponse. + */ + @RequestMapping(value = "/v1/_update", method = RequestMethod.POST) + public ResponseEntity referralV1UpdatePost(@ApiParam(value = "Capture details of Existing HFReferral", required = true) @Valid @RequestBody HFReferralRequest request) { + HFReferral hfReferral = hfReferralService.update(request); + + HFReferralResponse response = HFReferralResponse.builder() + .hfReferral(hfReferral) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } + + /** + * API endpoint to update multiple HFReferrals in bulk. + * + * @param request The HFReferralBulkRequest containing bulk updated referral details. + * @return ResponseEntity containing ResponseInfo. + */ + @RequestMapping(value = "/v1/bulk/_update", method = RequestMethod.POST) + public ResponseEntity referralV1BulkUpdatePost(@ApiParam(value = "Capture details of Existing HFReferral", required = true) @Valid @RequestBody HFReferralBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + producer.push(referralManagementConfiguration.getUpdateHFReferralBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } + + /** + * API endpoint to delete a single HFReferral. + * + * @param request The HFReferralRequest containing details of the referral to be deleted. + * @return ResponseEntity containing HFReferralResponse. + */ + @RequestMapping(value = "/v1/_delete", method = RequestMethod.POST) + public ResponseEntity referralV1DeletePost(@ApiParam(value = "Capture details of Existing HFReferral", required = true) @Valid @RequestBody HFReferralRequest request) { + HFReferral hfReferral = hfReferralService.delete(request); + + HFReferralResponse response = HFReferralResponse.builder() + .hfReferral(hfReferral) + .responseInfo(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)) + .build(); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(response); + } + + /** + * API endpoint to delete multiple HFReferrals in bulk. + * + * @param request The HFReferralBulkRequest containing details of the referrals to be deleted in bulk. + * @return ResponseEntity containing ResponseInfo. + */ + @RequestMapping(value = "/v1/bulk/_delete", method = RequestMethod.POST) + public ResponseEntity referralV1BulkDeletePost(@ApiParam(value = "Capture details of Existing HFReferral", required = true) @Valid @RequestBody HFReferralBulkRequest request) { + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + producer.push(referralManagementConfiguration.getDeleteHFReferralBulkTopic(), request); + + return ResponseEntity.status(HttpStatus.ACCEPTED).body(ResponseInfoFactory + .createResponseInfo(request.getRequestInfo(), true)); + } +} diff --git a/health-services/referralmanagement/src/main/resources/application.properties b/health-services/referralmanagement/src/main/resources/application.properties index 22830c099f1..b7ac09656ac 100644 --- a/health-services/referralmanagement/src/main/resources/application.properties +++ b/health-services/referralmanagement/src/main/resources/application.properties @@ -97,10 +97,12 @@ egov.search.individual.url=/individual/v1/_search egov.user.id.validator=individual # PROJECT SERVICE -egov.project.host=http://localhost:8084 +egov.project.host=https://unified-dev.digit.org +egov.search.project.url=/project/v1/_search egov.search.project.task.url=/project/task/v1/_search egov.search.project.beneficiary.url=/project/beneficiary/v1/_search egov.search.project.staff.url=/project/staff/v1/_search +egov.search.project.facility.url=/project/facility/v1/_search # ADRM KAFKA CONFIG @@ -120,6 +122,14 @@ referralmanagement.referral.consumer.bulk.create.topic=save-referral-bulk-topic referralmanagement.referral.consumer.bulk.update.topic=update-referral-bulk-topic referralmanagement.referral.consumer.bulk.delete.topic=delete-referral-bulk-topic +referralmanagement.hfreferral.kafka.create.topic=save-hfreferral-topic +referralmanagement.hfreferral.kafka.update.topic=update-hfreferral-topic +referralmanagement.hfreferral.kafka.delete.topic=delete-hfreferral-topic + +referralmanagement.hfreferral.consumer.bulk.create.topic=save-hfreferral-bulk-topic +referralmanagement.hfreferral.consumer.bulk.update.topic=update-hfreferral-bulk-topic +referralmanagement.hfreferral.consumer.bulk.delete.topic=delete-hfreferral-bulk-topic + search.api.limit=1000 referralmanagement.default.offset=0 diff --git a/health-services/referralmanagement/src/main/resources/db/migration/main/V20231214113400__hf_referral_create_ddl.sql b/health-services/referralmanagement/src/main/resources/db/migration/main/V20231214113400__hf_referral_create_ddl.sql new file mode 100644 index 00000000000..0d4dfbd4dad --- /dev/null +++ b/health-services/referralmanagement/src/main/resources/db/migration/main/V20231214113400__hf_referral_create_ddl.sql @@ -0,0 +1,25 @@ +CREATE table IF NOT EXISTS hf_referral ( + id character varying(64), + clientreferenceid character varying(64), + tenantid character varying(1000), + projectid character varying(64), + facilityId character varying(64), + symptom character varying(256), + symptomsurveyid character varying(100), + beneficiaryid character varying(100), + referralcode character varying(100), + nationallevelid character varying(100), + createdby character varying(64), + createdtime bigint, + lastmodifiedby character varying(64), + lastmodifiedtime bigint, + clientcreatedby character varying(64), + clientcreatedtime bigint, + clientlastmodifiedby character varying(64), + clientlastmodifiedtime bigint, + rowversion bigint, + isdeleted boolean, + additionaldetails jsonb, + CONSTRAINT uk_hf_referral_id PRIMARY KEY (id), + CONSTRAINT uk_hf_referral_clientReferenceId UNIQUE (clientReferenceId) +); \ No newline at end of file diff --git a/health-services/referralmanagement/src/main/resources/db/migration/main/V20240103142200__hf_referral_project_facility_rename_ddl.sql b/health-services/referralmanagement/src/main/resources/db/migration/main/V20240103142200__hf_referral_project_facility_rename_ddl.sql new file mode 100644 index 00000000000..f7a8fb9b884 --- /dev/null +++ b/health-services/referralmanagement/src/main/resources/db/migration/main/V20240103142200__hf_referral_project_facility_rename_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE hf_referral RENAME COLUMN facilityid to projectfacilityid; \ No newline at end of file diff --git a/health-services/stock/CHANGELOG.md b/health-services/stock/CHANGELOG.md index c837b842a64..83d0dd54070 100644 --- a/health-services/stock/CHANGELOG.md +++ b/health-services/stock/CHANGELOG.md @@ -1,5 +1,8 @@ All notable changes to this module will be documented in this file. +## 1.1.2 - 2024-02-26 +- Enhance inventory flow with sender id and receiver id added. + ## 1.1.1 - 2023-11-15 - Enhanced inventory flow for last mile delivery with QR code diff --git a/health-services/stock/pom.xml b/health-services/stock/pom.xml index 383f790553d..a6d29a41ba7 100644 --- a/health-services/stock/pom.xml +++ b/health-services/stock/pom.xml @@ -5,7 +5,7 @@ stock jar stock - 1.1.1 + 1.1.2 1.8 ${java.version} @@ -49,7 +49,7 @@ org.egov.common health-services-models - 1.0.9-SNAPSHOT + 1.0.15-SNAPSHOT diff --git a/health-services/stock/src/main/java/org/egov/stock/config/MainConfiguration.java b/health-services/stock/src/main/java/org/egov/stock/config/MainConfiguration.java index e0d61ae0682..b067e1cb2ab 100644 --- a/health-services/stock/src/main/java/org/egov/stock/config/MainConfiguration.java +++ b/health-services/stock/src/main/java/org/egov/stock/config/MainConfiguration.java @@ -6,6 +6,8 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; +import com.fasterxml.jackson.databind.module.SimpleModule; +import org.egov.common.models.core.validator.CustomIntegerDeserializer; import org.egov.tracer.config.TracerConfiguration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; @@ -42,7 +44,12 @@ public void initialize() { @Bean public ObjectMapper objectMapper(){ - return new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).setTimeZone(TimeZone.getTimeZone(timeZone)); + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + SimpleModule module = new SimpleModule(); + module.addDeserializer(Integer.class, new CustomIntegerDeserializer()); + objectMapper.registerModule(module); + return objectMapper.setTimeZone(TimeZone.getTimeZone(timeZone)); } @Bean diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java index 89471581084..d011f3301a4 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java @@ -4,6 +4,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; import org.egov.common.models.stock.AdditionalFields; +import org.egov.common.models.stock.ReferenceIdType; +import org.egov.common.models.stock.SenderReceiverType; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.TransactionReason; import org.egov.common.models.stock.TransactionType; @@ -33,6 +35,10 @@ public Stock mapRow(ResultSet resultSet, int i) throws SQLException { .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) .build(); + Long dateOfEntry = resultSet.getLong("dateOfEntry"); + if(resultSet.wasNull()){ + dateOfEntry = null; + } return Stock.builder() .id(resultSet.getString("id")) .clientReferenceId(resultSet.getString("clientReferenceId")) @@ -41,20 +47,20 @@ public Stock mapRow(ResultSet resultSet, int i) throws SQLException { .quantity(resultSet.getInt("quantity")) .wayBillNumber(resultSet.getString("wayBillNumber")) .referenceId(resultSet.getString("referenceId")) - .referenceIdType(resultSet.getString("referenceIdType")) + .referenceIdType(ReferenceIdType.fromValue(resultSet.getString("referenceIdType"))) .transactionType(TransactionType.fromValue(resultSet.getString("transactionType"))) .transactionReason(TransactionReason.fromValue(resultSet.getString("transactionReason"))) .senderId(resultSet.getString("senderId")) - .senderType(resultSet.getString("senderType")) + .senderType(SenderReceiverType.fromValue(resultSet.getString("senderType"))) .receiverId(resultSet.getString("receiverId")) - .receiverType(resultSet.getString("receiverType")) + .receiverType(SenderReceiverType.fromValue(resultSet.getString("receiverType"))) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) .auditDetails(auditDetails) .clientAuditDetails(clientAuditDetails) .rowVersion(resultSet.getInt("rowVersion")) .isDeleted(resultSet.getBoolean("isDeleted")) - .dateOfEntry(resultSet.getLong("dateOfEntry")) + .dateOfEntry(dateOfEntry) .build(); } catch (JsonProcessingException e) { throw new SQLException(e); diff --git a/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java b/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java index 068a26a99fb..5d93a0ecfdd 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java @@ -25,6 +25,7 @@ import org.egov.common.models.project.ProjectFacilityBulkResponse; import org.egov.common.models.project.ProjectFacilitySearch; import org.egov.common.models.project.ProjectFacilitySearchRequest; +import org.egov.common.models.stock.SenderReceiverType; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.StockReconciliation; import org.egov.stock.config.StockConfiguration; @@ -97,10 +98,10 @@ public Map> validateProjectFacilityMappings(List ent Stock stock = (Stock) entity; - if (stock.getSenderType().equalsIgnoreCase(WAREHOUSE)) { + if (SenderReceiverType.WAREHOUSE.equals(stock.getSenderType())) { facilityIds.add(stock.getSenderId()); } - if (stock.getReceiverType().equalsIgnoreCase(WAREHOUSE)) { + if (SenderReceiverType.WAREHOUSE.equals(stock.getReceiverType())) { facilityIds.add(stock.getReceiverId()); } } diff --git a/health-services/stock/src/main/java/org/egov/stock/service/StockService.java b/health-services/stock/src/main/java/org/egov/stock/service/StockService.java index 8bbbd72c065..7876d60ac63 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/StockService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/StockService.java @@ -34,6 +34,7 @@ import org.egov.stock.validator.stock.SProductVariantIdValidator; import org.egov.stock.validator.stock.SReferenceIdValidator; import org.egov.stock.validator.stock.SRowVersionValidator; +import org.egov.stock.validator.stock.SSenderIdReceiverIdEqualsValidator; import org.egov.stock.validator.stock.SUniqueEntityValidator; import org.egov.stock.validator.stock.StocktransferPartiesValidator; import org.egov.stock.web.models.StockSearchRequest; @@ -57,6 +58,7 @@ public class StockService { private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(SProductVariantIdValidator.class) + || validator.getClass().equals(SSenderIdReceiverIdEqualsValidator.class) || validator.getClass().equals(StocktransferPartiesValidator.class) || validator.getClass().equals(SReferenceIdValidator.class); @@ -68,11 +70,13 @@ public class StockService { || validator.getClass().equals(SRowVersionValidator.class) || validator.getClass().equals(SUniqueEntityValidator.class) || validator.getClass().equals(SReferenceIdValidator.class) + || validator.getClass().equals(SSenderIdReceiverIdEqualsValidator.class) || validator.getClass().equals(StocktransferPartiesValidator.class); private final Predicate> isApplicableForDelete = validator -> validator.getClass().equals(SNonExistentValidator.class) - || validator.getClass().equals(SNullIdValidator.class); + || validator.getClass().equals(SNullIdValidator.class) + || validator.getClass().equals(SRowVersionValidator.class); public StockService(StockRepository stockRepository, List> validators, StockConfiguration configuration, StockEnrichmentService enrichmentService) { this.stockRepository = stockRepository; diff --git a/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java b/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java index b39ad93699d..b46431fe018 100644 --- a/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java +++ b/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java @@ -21,6 +21,7 @@ import org.egov.common.contract.request.RequestInfo; import org.egov.common.ds.Tuple; import org.egov.common.models.Error; +import org.egov.common.models.stock.SenderReceiverType; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.StockReconciliation; import org.egov.common.service.UserService; @@ -64,17 +65,13 @@ public static Map> validateFacilityIds(R request, Map - * @param - * @param stockRequest + * Non-generic method used for validating sender/receiver (parties) against facility or staff based on the type + * + * @param requestInfo * @param errorDetailsMap - * @param validEntities - * @param getId + * @param validStockEntities * @param facilityService + * @param userService * @return */ public static Map> validateStockTransferParties(RequestInfo requestInfo, @@ -94,17 +91,14 @@ public static Map> validateStockTransferParties(RequestInf } /** - * validates the list of party-ids (facility and staff) against the respective - * APIs and enriches the invalid ids list for both parties - * - * @param - * @param stockRequest + * Validates the list of party-ids (facility and staff) against the respective APIs and enriches the invalid ids list for both parties. + * + * @param requestInfo * @param errorDetailsMap * @param validStockEntities * @param facilityService - * @param facilityIds - * @param InvalidStaffId - * @param invalidFacilityIds + * @param userService + * @return A tuple containing lists of invalid facility ids and invalid staff ids */ @SuppressWarnings("unchecked") private static Tuple, List> validateAndEnrichInvalidPartyIds(RequestInfo requestInfo, @@ -158,18 +152,18 @@ private static void enrichFaciltyAndStaffIdsFromStock(List validStockEnti for (Stock stock : validStockEntities) { - if (stock.getSenderType().equalsIgnoreCase(WAREHOUSE)) { + if (SenderReceiverType.WAREHOUSE.equals(stock.getSenderType()) && stock.getSenderId() != null) { facilityIds.add(stock.getSenderId()); - } - if (stock.getSenderType().equalsIgnoreCase(STAFF)) { + } else if (SenderReceiverType.STAFF.equals(stock.getSenderType()) && stock.getSenderId() != null) { staffIds.add(stock.getSenderId()); } - if (stock.getReceiverType().equalsIgnoreCase(WAREHOUSE)) { + + if (SenderReceiverType.WAREHOUSE.equals(stock.getReceiverType()) && stock.getReceiverId() != null) { facilityIds.add(stock.getReceiverId()); - } - if (stock.getReceiverType().equalsIgnoreCase(STAFF)) { + } else if (SenderReceiverType.STAFF.equals(stock.getReceiverType()) && stock.getReceiverId() != null) { staffIds.add(stock.getReceiverId()); } + } } @@ -179,7 +173,7 @@ private static void enrichFaciltyAndStaffIdsFromStock(List validStockEnti * * @param errorDetailsMap * @param validStockEntities - * @param InvalidStaffId + * @param invalidStaffIds * @param invalidFacilityIds */ @SuppressWarnings("unchecked") @@ -195,16 +189,16 @@ private static void enrichErrorMapFromInvalidPartyIds(Map> er String senderId = stock.getSenderId(); String recieverId = stock.getReceiverId(); - if ((stock.getSenderType().equalsIgnoreCase(WAREHOUSE) && invalidFacilityIds.contains(senderId)) + if ((SenderReceiverType.WAREHOUSE.equals(stock.getSenderType()) && invalidFacilityIds.contains(senderId)) - || (stock.getSenderType().equalsIgnoreCase(STAFF) && invalidStaffIds.contains(senderId))) { + || (SenderReceiverType.STAFF.equals(stock.getSenderType()) && invalidStaffIds.contains(senderId))) { getIdForErrorFromMethod(errorDetailsMap, (T) stock, senderIdMethod); } - if ((stock.getReceiverType().equalsIgnoreCase(WAREHOUSE) && invalidFacilityIds.contains(recieverId)) + if ((SenderReceiverType.WAREHOUSE.equals(stock.getReceiverType()) && invalidFacilityIds.contains(recieverId)) - || (stock.getReceiverType().equalsIgnoreCase(STAFF) && invalidStaffIds.contains(recieverId))) { + || (SenderReceiverType.STAFF.equals(stock.getReceiverType()) && invalidStaffIds.contains(recieverId))) { getIdForErrorFromMethod(errorDetailsMap, (T) stock, recieverIdMethod); } @@ -232,7 +226,7 @@ private static void getIdForErrorFromMethod(Map> errorDetails * @param request * @param errorDetailsMap * @param validEntities - * @param getId + * @param getReferenceId * @param facilityService * @return */ @@ -279,11 +273,11 @@ private static void enrichErrorForStock(List validEntities, List facilityIds = ProjectFacilityMappingOfIds.get(stock.getReferenceId()); if (!CollectionUtils.isEmpty(facilityIds)) { - if (stock.getSenderType().equalsIgnoreCase("WAREHOUSE") && !facilityIds.contains(senderId)) { + if (SenderReceiverType.WAREHOUSE.equals(stock.getSenderType()) && !facilityIds.contains(senderId)) { populateErrorForStock(stock, senderId, errorDetailsMap); } - if (stock.getReceiverType().equalsIgnoreCase("WAREHOUSE") && !facilityIds.contains(receiverId)) + if (SenderReceiverType.WAREHOUSE.equals(stock.getReceiverType()) && !facilityIds.contains(receiverId)) populateErrorForStock(stock, receiverId, errorDetailsMap); } else { populateErrorForStock(stock, senderId + " and " + receiverId, errorDetailsMap); diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SReferenceIdValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SReferenceIdValidator.java index 47a17106727..ceab1dfb887 100644 --- a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SReferenceIdValidator.java +++ b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SReferenceIdValidator.java @@ -2,6 +2,8 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; +import org.egov.common.models.stock.ReferenceIdType; +import org.egov.common.models.stock.SenderReceiverType; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.StockBulkRequest; import org.egov.common.validator.Validator; @@ -37,11 +39,11 @@ public Map> validate(StockBulkRequest request) { List validEntities = request.getStock().stream() .filter(notHavingErrors()) - .filter(entity -> PROJECT.equals(entity.getReferenceIdType())) + .filter(entity -> ReferenceIdType.PROJECT.equals(entity.getReferenceIdType())) .collect(Collectors.toList()); - long countOfWareHouseInStock = request.getStock().stream().filter(stock -> - stock.getReceiverType().equalsIgnoreCase("WAREHOUSE") || stock.getSenderType().equalsIgnoreCase("WAREHOUSE") + long countOfWareHouseInStock = request.getStock().stream().filter(stock -> + SenderReceiverType.WAREHOUSE.equals(stock.getReceiverType()) || SenderReceiverType.WAREHOUSE.equals(stock.getSenderType()) ).count(); if(countOfWareHouseInStock == 0) return errorDetailsMap; diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SSenderIdReceiverIdEqualsValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SSenderIdReceiverIdEqualsValidator.java new file mode 100644 index 00000000000..4285d90d26d --- /dev/null +++ b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SSenderIdReceiverIdEqualsValidator.java @@ -0,0 +1,75 @@ +package org.egov.stock.validator.stock; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.stock.Stock; +import org.egov.common.models.stock.StockBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +/** + * Validator class to check if senderId and receiverId are equal in a list of Stock entities. + */ +@Component +@Order(value = 6) +@Slf4j +public class SSenderIdReceiverIdEqualsValidator implements Validator { + + /** + * Validates the list of Stock entities to ensure that senderId and receiverId are not equal. + * + * @param stockBulkRequest The bulk request containing a list of Stock entities. + * @return A map containing Stock entities with corresponding error details for entities with equal senderId and receiverId. + */ + @Override + public Map> validate(StockBulkRequest stockBulkRequest) { + Map> errorDetailsMap = new HashMap<>(); + List entities = stockBulkRequest.getStock(); + List invalidEntities = new ArrayList<>(); + log.info("validating whether sender id and receiver id are same"); + + // Iterate through each Stock entity in the list + entities.forEach(stock -> { + // Check if senderId and receiverId are equal using helper method + if (areSenderAndReceiverEqual(stock)) { + // If equal, add the entity to the list of invalid entities + invalidEntities.add(stock); + + // Create an error object for the entity + Error error = Error.builder() + .errorMessage("Sender Id and Receiver Id cannot be the same") + .errorCode("SENDER_RECEIVER_CANNOT_BE_EQUAL") + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException("SENDER_RECEIVER_CANNOT_BE_EQUAL", "Sender Id and Receiver Id cannot be the same")) + .build(); + + // Populate error details for the entity + populateErrorDetails(stock, error, errorDetailsMap); + } + }); + + return errorDetailsMap; + } + + /** + * Helper method to check if senderId and receiverId are equal. + * + * @param stock The Stock entity to check. + * @return True if senderId and receiverId are equal, false otherwise. + */ + private boolean areSenderAndReceiverEqual(Stock stock) { + return stock.getSenderType() == stock.getReceiverType() + && stock.getReceiverId() != null + && stock.getSenderId() != null + && stock.getReceiverId().equals(stock.getSenderId()); + } +} diff --git a/health-services/stock/src/test/java/org/egov/stock/TestConfiguration.java b/health-services/stock/src/test/java/org/egov/stock/TestConfiguration.java index 0d8d9758688..d507efd67c1 100644 --- a/health-services/stock/src/test/java/org/egov/stock/TestConfiguration.java +++ b/health-services/stock/src/test/java/org/egov/stock/TestConfiguration.java @@ -1,5 +1,11 @@ package org.egov.stock; +import java.util.TimeZone; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import org.egov.common.models.core.validator.CustomIntegerDeserializer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.kafka.core.KafkaTemplate; @@ -13,4 +19,14 @@ public class TestConfiguration { public KafkaTemplate kafkaTemplate() { return mock(KafkaTemplate.class); } + + @Bean + public ObjectMapper objectMapper(){ + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + SimpleModule module = new SimpleModule(); + module.addDeserializer(Integer.class, new CustomIntegerDeserializer()); + objectMapper.registerModule(module); + return objectMapper.setTimeZone(TimeZone.getTimeZone("UTC")); + } } \ No newline at end of file diff --git a/health-services/stock/src/test/java/org/egov/stock/helper/StockTestBuilder.java b/health-services/stock/src/test/java/org/egov/stock/helper/StockTestBuilder.java index 90960baf5a3..fd83333e42e 100644 --- a/health-services/stock/src/test/java/org/egov/stock/helper/StockTestBuilder.java +++ b/health-services/stock/src/test/java/org/egov/stock/helper/StockTestBuilder.java @@ -1,6 +1,8 @@ package org.egov.stock.helper; import org.egov.common.helper.AuditDetailsTestBuilder; +import org.egov.common.models.stock.ReferenceIdType; +import org.egov.common.models.stock.SenderReceiverType; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.TransactionReason; import org.egov.common.models.stock.TransactionType; @@ -26,13 +28,16 @@ public StockTestBuilder withStock() { this.builder .senderId("sender-id") .receiverId("receiver-id") - .productVariantId("pv-id").quantity(0) + .productVariantId("pv-id") + .quantity(1) .referenceId("reference-id") - .referenceIdType("PROJECT").rowVersion(1).tenantId("default") + .referenceIdType(ReferenceIdType.PROJECT) + .rowVersion(1) + .tenantId("default") .transactionType(TransactionType.DISPATCHED) .transactionReason(TransactionReason.RECEIVED) - .senderType("WAREHOUSE") - .receiverType("STAFF") + .senderType(SenderReceiverType.WAREHOUSE) + .receiverType(SenderReceiverType.STAFF) .hasErrors(false) .isDeleted(Boolean.FALSE) .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); From ac8c591238de9a856ecc16f66e32454ed5358b65 Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Mon, 4 Mar 2024 12:39:18 +0530 Subject: [PATCH 237/283] Dev to master - March 04, 2024 (#664) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter * Project beneficiary tag cherrypick (#539) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * referral management project beneficiary validation fix * deleted persister and indexer file from project module resource folder --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * HH member clientrefid (#551) * adding clientRefId, Models version change, migration file * adding clientRefId for HouseholdMemberSearch as List * updated migration * adding Notnull for clientrefId --------- Co-authored-by: Vishal * Downsync smc referral module (#556) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Project beneficiary tag cherrypick (#549) * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * referral management project beneficiary validation fix --------- Co-authored-by: kanishq-egov Co-authored-by: Vishal * dummy api with same pagination response * dummy api with same pagination response * dummy api with same pagination response * downsync data test * data integrated till beneficiary * Update CHANGELOG.md * Delete health-services/project/src/main/resources/project-persistor.yml * skip on empty result added * skip on empty result added * beneficary searhc based on individual clientref id added * sideeffetc, ref, task fetch added * tasks earch fix * referral search fix --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * Dev downsync fix smc (#561) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: kanishq-egov * Dev master conflict fix (#562) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#563) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Dev master conflict fix (#565) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#566) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Added fix for testcases for householdmember (#570) Co-authored-by: kanishq-egov * updated the version, and added the changelog (#571) * updated the version, and added the changelog * updated ReferralManagement CHANGELOG * Update CHANGELOG.md --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * HLM-4062: removed pagination from fields excluding household api call * HLM-4062: missed in implementation (#574) * HLM-4062: missed in implementation * HLM-4062: default max is set to 1000 for not null limit value and 0 for offset value * project beneficiary tag update failed fix HLM-4444 * HLM-4444: added code review comments * sownsync bug fix for limit --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> * HLM-4444: project beneficiary update fix (#575) * Update CHANGELOG.md * updated changelog with dates (#577) * updated stock module changelog (#578) * Hlm 4501 smc referral flow (#602) * HLM-4501: Added changes for HFReferral flow * updated comments for common models * updated comments for common models removed ini file This reverts commit c1e226f961042f1162bb9ece8d2e1c01b62d220c. * HLM-4501: updated topics and hfreferal constants * HLM-4501: updated HFReferralService.java * HLM-4501: Added changes in project id validator * HLM-4501: updated HFReferralService.java * HLM-4501: fixed hfreferral changes * HLM-4501: added project facility id validator for hf_referral * HLM-4501: missing link for validator added * HLM-4501: updated HfrProjectFacilityIdValidator for NPE * HLM-4501 : updated hf referral symtoms character length to 256 * HLM-4501: updated additionalFields field value size from 2 to 1 * Hlm 3372 enhance inventory flow backend fixes (#623) * HLM-3372: added changes required to fix quantity, Sender Receiver enum * HLM-3372: Sender and Receiver id validator * HLM-3372: updated all reference for SenderType and Receiver Type enum * HLM-3372: stock model updated, removed size annotations from referenceidtype enum field * HLM-3372: Min validation added for integer type of quantity * HLM-3372: test cases updated * HLM-5004 Added max value and decimal condition for quantity in stock, added component and order annotation for SSenderIdReceiverIdEqualsValidator * HLM-5004 Custom JsonDeserializer validator IntegerValidator added in health-services-models * hlm-5004 added custom exception and a custom exception handler to handle the integer validator exception * hlm-5004 optimized imports and added code comments * hlm-5004 CustomIntegerSerializer added and unnecessary validators removed * hlm-5004 Registered the CustomIntegerDeserializer with objectMapper for Integer class * hlm-5004 Removed line of code that was removing all the invalid entities from the list in SSenderIdReceiverIdEqualsValidator * hlm-5004 changes in test configurations and optimized imports * hlm-5004 added row version validator for stock delete * hlm-5004 dateOfEntry field was handled in StockRowMapper to return null if no value is present and description was added to stock contact for transactionReason * updated pom.xml for health campaign models * Revert "updated pom.xml for health campaign models" This reverts commit 035c78720c610916000c8de76fa87e7904774b59. --------- Co-authored-by: syed-egov * Hlm 4501 smc referral flow code comments (#636) * Dev to master : beneficiary tag bug fix, downsync pagination fix (#576) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter * Project beneficiary tag cherrypick (#539) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * referral management project beneficiary validation fix * deleted persister and indexer file from project module resource folder --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * HH member clientrefid (#551) * adding clientRefId, Models version change, migration file * adding clientRefId for HouseholdMemberSearch as List * updated migration * adding Notnull for clientrefId --------- Co-authored-by: Vishal * Downsync smc referral module (#556) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Project beneficiary tag cherrypick (#549) * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * referral management project beneficiary validation fix --------- Co-authored-by: kanishq-egov Co-authored-by: Vishal * dummy api with same pagination response * dummy api with same pagination response * dummy api with same pagination response * downsync data test * data integrated till beneficiary * Update CHANGELOG.md * Delete health-services/project/src/main/resources/project-persistor.yml * skip on empty result added * skip on empty result added * beneficary searhc based on individual clientref id added * sideeffetc, ref, task fetch added * tasks earch fix * referral search fix --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * Dev downsync fix smc (#561) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: kanishq-egov * Dev master conflict fix (#562) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#563) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Dev master conflict fix (#565) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#566) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Added fix for testcases for householdmember (#570) Co-authored-by: kanishq-egov * updated the version, and added the changelog (#571) * updated the version, and added the changelog * updated ReferralManagement CHANGELOG * Update CHANGELOG.md --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * HLM-4062: removed pagination from fields excluding household api call * HLM-4062: missed in implementation (#574) * HLM-4062: missed in implementation * HLM-4062: default max is set to 1000 for not null limit value and 0 for offset value * project beneficiary tag update failed fix HLM-4444 * HLM-4444: added code review comments * sownsync bug fix for limit --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> * HLM-4444: project beneficiary update fix (#575) * Update CHANGELOG.md * updated changelog with dates (#577) * updated stock module changelog (#578) --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: bhanu prakash <109132521+bhanuprakash-egov@users.noreply.github.com> Co-authored-by: Naveen J <83631045+naveen-egov@users.noreply.github.com> Co-authored-by: talele08 * Referral and Side effect sequence diagram * HLM-4501: Added changes for HFReferral flow * updated comments for common models * updated comments for common models removed ini file This reverts commit c1e226f961042f1162bb9ece8d2e1c01b62d220c. * HLM-4501: updated topics and hfreferal constants * HLM-4501: updated HFReferralService.java * HLM-4501: Added changes in project id validator * HLM-4501: updated HFReferralService.java * HLM-4501: fixed hfreferral changes * HLM-4501: added project facility id validator for hf_referral * HLM-4501: missing link for validator added * HLM-4501: updated HfrProjectFacilityIdValidator for NPE * HLM-4501 : updated hf referral symtoms character length to 256 * HLM-4501: updated additionalFields field value size from 2 to 1 * HLM-4501: added code comments for all hf referral related classes * HLM-4501: hf-referral sequence diagram --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: bhanu prakash <109132521+bhanuprakash-egov@users.noreply.github.com> Co-authored-by: Naveen J <83631045+naveen-egov@users.noreply.github.com> Co-authored-by: talele08 * HLM-4496, HLM-4207 attendance module (#616) * HLM-4496: Added attendance module in HCM * HLM-4496: updated attendance directory, removed target folder and imi file * buil config added for hlm-4496 in feature branch * HLM-4207: offline enablement in attendance log * HLM-4207: added db migration script * HLM-4207: updated db migration script * HLM-4207: updated incorrect statements * HLM-4207: bulk api support, without redis cache * HLM-4207: updated Attendancelog consumer for bulk api * HLM-4207: consumer fix * HLM-4207: cache support added for attendance log create and update * HLM-4207: added health-individual endpoint * HLM-4207: added radis host * HLM-4207: updated qualified for objectmapper in attendance module * HLM-4496,HLM-4207: updated application.properties for redis config * HLM-4207: updated kafka listener topics * HLM-4207: changed kafka config * HLM-4894 adding hrms related flag to Individual object, adding another ApiOperation * HLM-4894 adding hrms related flag to Individual object, adding another ApiOperation * HLM-4207, HLM-4986, HLM-4987 : bug fix * HLM-4894 adding changes related to linking of HRMS Employee with Individual * HLM-4894 adding changes related to linking of HRMS Employee with Individual * HLM-4207: added clientreferenceid search, null check for document id * HLM-4894 reverting changes related to linking of HRMS Employee with Individual * HLM-4894 reverting changes related to linking of HRMS Employee with Individual from libraries, common-models * HLM-4207: code re-format * HLM-4894 adding changes for managing attendees while enrollment * HLM-4207: updated attendance search, register id or clientreference id are mandatory * hlm-5009 staffId in ProjectStaffSearch changed to list from string * HLM-4894 updating build config * HLM-4207: clientReferenceIds is changed to clientReferenceId for Attendance Log search criteria * HLM-4207: removed staff validation for search without register id * HLM-4894 adding changes for project staff validation * HLM-4894 adding @Qualifier annotation for object mapper * HLM-4894 fixing hrms url * HLM-4771: added changes for updating the registers on project date update * HLM-4771: project update changes * HLM-4771: updated the project start date update validation, can not update start date if it is already started * HLM-4771: updated attendance register consumer and service with comments * HLM-4771: updated the tenant id * HLM-4894 updating environment variables. * HLM-4894 updating code changes * HLM-4894 adding code changes * HLM-4894 adding code changes * HLM-4894 adding code changes * HLM-4771: updated the project validators, validation for start and end date of project * HLM-4894 adding useruuid as search param in individual search * HLM-4894 adding useruuid as search param in individual search * HLM-4894 adding useruuid as search param in individual search * HLM-4894 adding changes for registry creation when supervisor enrolls * HLM-4496, HLM-4894: first staff enrollment on attendance register creation is optional * HLM-4894 adding changes attendee enrollment * HLM-4894 adding changes for making staffId as list of staffId in ProjectStaffSearch * HLM-4894 adding changes for making staffId as list of staffId in ProjectStaffSearch * HLM-4894 adding changes for making staffId as list of staffId in ProjectStaffSearch * HLM-4894 removing staff-bulk-create-topic * HLM-4894 removing staff-bulk-create-topic * HLM-4894 removing staff-bulk-create-topic * HLM-4894 removing staff-bulk-create-topic * HLM-4894 changing health-attendance consumer group-id * HLM-4894 adding changes for projectstaff consumer * HLM-4894 adding changes for projectstaff consumer * HLM-4894 adding changes for projectstaff consumer * HLM-4894 adding changes for projectstaff consumer * HLM-4894 adding changes for projectstaff consumer * HLM-5045: added changes, project start date and end date difference should at least be 1 day. * HLM-4894 adding comments * HLM-4894 adding additional Details during attendance register creation * HLM-4894 adding additional Details during attendance register creation * hlm-4496 : bug fix on adding staff on updation of register * HLM-4894 increasing limit to 1000 * Added changelog for individual, health-services-models, project, stock * HLM-4496 : remove attendance module as it is moved to DIGIT-Works repository. * HLM-5076: added changes related to project module * updated individual user uuid search field for hlm-4496, hlm-4207 * changed common models build to 1.0.19-SNAPSHOT --------- Co-authored-by: Priyanka-eGov Co-authored-by: syed-egov Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * Hlm 4496 individual UUID search (#656) * HLM-4496: updated changedlog for individual, health-services-models, project, referralmanagement * HLM-4496: Added size annotations on individual search userUuid field * hlm-4496: Revert of application.properties changes * updated pom.xml version for individual, project, referralmanagement, stock (#657) * Health hrms (#660) * updated pom.xml version for individual, project, referralmanagement, stock * Added health-hrms * Hlm health hrms changes (#650) * HLM-4496: Added attendance module in HCM * HLM-4496: updated attendance directory, removed target folder and imi file * buil config added for hlm-4496 in feature branch * HLM-4207: offline enablement in attendance log * HLM-4207: added db migration script * HLM-4207: updated db migration script * HLM-4207: updated incorrect statements * HLM-4207: bulk api support, without redis cache * HLM-4207: updated Attendancelog consumer for bulk api * HLM-4207: consumer fix * HLM-4207: cache support added for attendance log create and update * HLM-4207: added health-individual endpoint * HLM-4207: added radis host * HLM-4207: updated qualified for objectmapper in attendance module * HLM-4496,HLM-4207: updated application.properties for redis config * HLM-4207: updated kafka listener topics * HLM-4207: changed kafka config * HLM-4207, HLM-4986, HLM-4987 : bug fix * HLM-4207: added clientreferenceid search, null check for document id * HLM-4894 moving hrms code from DIGIT-Dev branc health-moz-dev * HLM-4894 moving hrms code from DIGIT-Dev branc health-moz-dev * HLM-4894 updating build config for health-hrms * HLM-4894 adding clientreferenceID while creating individuals * HLM-4894 adding clientreferenceID while creating individuals * HLM-4894 adding clientreferenceID while creating individuals * HLM-4894 adding clientAuditDetails while creating individuals * Adding mdmsLegacyHost * Adding mdmsLegacyHost --------- Co-authored-by: kanishq-egov Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * Revert "Hlm health hrms changes (#650)" (#663) This reverts commit db786acf5fd949084ad544aa6f9f31e5d9a37f6e. --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: bhanu prakash <109132521+bhanuprakash-egov@users.noreply.github.com> Co-authored-by: Naveen J <83631045+naveen-egov@users.noreply.github.com> Co-authored-by: talele08 Co-authored-by: syed-egov Co-authored-by: Priyanka-eGov Co-authored-by: Priyanka-eGov <74049060+Priyanka-eGov@users.noreply.github.com> --- core-services/egov-hrms/CHANGELOG.md | 37 + core-services/egov-hrms/LOCALSETUP.md | 46 + core-services/egov-hrms/README.md | 112 +++ core-services/egov-hrms/egov-hrms.iml | 6 + core-services/egov-hrms/pom.xml | 176 ++++ .../egov/hrms/EgovEmployeeApplication.java | 120 +++ .../egov/hrms/config/PropertiesManager.java | 137 +++ .../org/egov/hrms/consumer/HrmsConsumer.java | 47 + .../java/org/egov/hrms/model/Assignment.java | 96 ++ .../org/egov/hrms/model/AuditDetails.java | 25 + .../egov/hrms/model/DeactivationDetails.java | 45 + .../org/egov/hrms/model/DepartmentalTest.java | 80 ++ .../hrms/model/EducationalQualification.java | 88 ++ .../java/org/egov/hrms/model/Employee.java | 133 +++ .../org/egov/hrms/model/EmployeeDocument.java | 85 ++ .../org/egov/hrms/model/Jurisdiction.java | 86 ++ .../egov/hrms/model/ReactivationDetails.java | 45 + .../main/java/org/egov/hrms/model/Role.java | 72 ++ .../java/org/egov/hrms/model/SMSRequest.java | 19 + .../org/egov/hrms/model/ServiceHistory.java | 85 ++ .../hrms/model/enums/DeactivationType.java | 31 + .../enums/EmployeeDocumentReferenceType.java | 31 + .../org/egov/hrms/model/enums/Gender.java | 70 ++ .../hrms/model/enums/GuardianRelation.java | 5 + .../org/egov/hrms/model/enums/UserType.java | 70 ++ .../org/egov/hrms/producer/HRMSProducer.java | 19 + .../repository/EmployeeCountRowMapper.java | 58 ++ .../egov/hrms/repository/EmployeeQueries.java | 57 ++ .../hrms/repository/EmployeeQueryBuilder.java | 168 ++++ .../hrms/repository/EmployeeRepository.java | 141 +++ .../hrms/repository/EmployeeRowMapper.java | 338 ++++++++ .../hrms/repository/RestCallRepository.java | 67 ++ .../egov/hrms/service/DefaultUserService.java | 281 ++++++ .../egov/hrms/service/EmployeeService.java | 577 +++++++++++++ .../org/egov/hrms/service/IdGenService.java | 90 ++ .../egov/hrms/service/IndividualService.java | 251 ++++++ .../org/egov/hrms/service/MDMSService.java | 189 ++++ .../hrms/service/NotificationService.java | 196 +++++ .../org/egov/hrms/service/UserService.java | 16 + .../org/egov/hrms/utils/ErrorConstants.java | 206 +++++ .../org/egov/hrms/utils/HRMSConstants.java | 64 ++ .../java/org/egov/hrms/utils/HRMSUtils.java | 72 ++ .../egov/hrms/utils/ResponseInfoFactory.java | 26 + .../hrms/web/contract/EmployeeRequest.java | 76 ++ .../hrms/web/contract/EmployeeResponse.java | 72 ++ .../web/contract/EmployeeSearchCriteria.java | 75 ++ .../web/contract/IdGenerationRequest.java | 64 ++ .../web/contract/IdGenerationResponse.java | 65 ++ .../org/egov/hrms/web/contract/IdRequest.java | 63 ++ .../egov/hrms/web/contract/IdResponse.java | 57 ++ .../hrms/web/contract/RequestInfoWrapper.java | 64 ++ .../java/org/egov/hrms/web/contract/User.java | 186 ++++ .../egov/hrms/web/contract/UserRequest.java | 74 ++ .../egov/hrms/web/contract/UserResponse.java | 69 ++ .../web/controller/EmployeeController.java | 135 +++ .../hrms/web/validator/EmployeeValidator.java | 817 ++++++++++++++++++ .../src/main/resources/application.properties | 118 +++ .../config/application-config.properties | 17 + .../config/hrm-employee-update-persister.yml | 265 ++++++ .../config/hrms-employee-persister.yml | 501 +++++++++++ .../src/main/resources/db/Dockerfile | 9 + .../src/main/resources/db/migrate.sh | 3 + ...152236__create_hrms_employee_table_ddl.sql | 159 ++++ ...0__alter_assgnmt_add_currentassgmt_ddl.sql | 1 + ...04154948__create_position_sequence_ddl.sql | 1 + ..._alter_deactivation_rename_remarks_ddl.sql | 1 + ...V20190204172710__secondary_indexes_ddl.sql | 4 + ...0190215120811__alter_uk_constraint_dml.sql | 2 + ...63221__alter_remove_phone_name_clm_dml.sql | 2 + ...20190301154105__alter_add_isactive_ddl.sql | 6 + ...1005230836__eg_hrms_employee_index_ddl.sql | 1 + ...mployee_reactivation_details_index_ddl.sql | 19 + ...201228172710__reactivation_indexes_ddl.sql | 1 + .../main/resources/db/migration/seed/.gitkeep | 0 .../src/test/resources/application.properties | 108 +++ .../config/application-config.properties | 17 + .../src/test/resources/db/Dockerfile | 13 + .../src/test/resources/db/migrate.sh | 3 + ...__egeis_hremployee_sample_data_for_pgr.sql | 18 + ...6__hr_employee_sample_data_for_panavel.sql | 20 + ...2__hr_employee_sample_data_for_default.sql | 9 + .../V20170227185601__hr_employee_employee.sql | 45 + ...20170227185602__hr_employee_assignment.sql | 31 + ...__hr_employee_educationalqualification.sql | 24 + ...27185604__hr_employee_departmentaltest.sql | 23 + ...05__hr_employee_employee_jurisdictions.sql | 15 + ...70227185606__hr_employee_hoddepartment.sql | 17 + ...185607__hr_employee_employee_languages.sql | 15 + ...V20170227185608__hr_employee_probation.sql | 25 + ...0227185609__hr_employee_regularisation.sql | 25 + ...0227185610__hr_employee_servicehistory.sql | 24 + ...11__hr_employee_technicalqualification.sql | 24 + ...ed_and_updated_foreign_key_constraints.sql | 8 + ...ed_null_checks_in_egeis_employee_table.sql | 9 + ...l_checks_in_egeis_regularisation_table.sql | 1 + ...7185615__hr_employee_employeedocuments.sql | 18 + ...dated_unique_constraint_in_hr_employee.sql | 7 + ...eatedDate_and_lastModifiedDate_columns.sql | 20 + ...20170227185618__updated_combination_pk.sql | 89 ++ ...70227185619__updated_foreign_key_names.sql | 29 + ...V20170420145502__update_combination_uk.sql | 12 + ...updated_employeestatus_column_datatype.sql | 1 + ...4227__hr_employee_add_lastmodifieddate.sql | 3 + ..._hr_hoddepartment_add_lastmodifieddate.sql | 1 + ...astModifiedBy_lastModifiedDate_columns.sql | 7 + .../V20170609165847__egeis_nominee_table.sql | 30 + ...onstraint_from_egeis_employeedocuments.sql | 2 + ...20170707184507__egeis_aprdetails_table.sql | 24 + ...171023104634__hr_employee_add_ifsccode.sql | 1 + ...10133312__hr_employee_disciplinary.ddl.sql | 56 ++ ...hr_employee_disciplinary_documents.ddl.sql | 15 + ...employee_disciplinary_alter_add_column.sql | 7 + ...loyee_disciplinary_alter_length_modify.sql | 14 + ..._disciplinary_alter_add_remove_columns.sql | 7 + ..._hr_employee_servicehistory_add_column.sql | 8 + ...447__hr_employee_department_alter_type.sql | 3 + ...47__hr_employee_designation_alter_type.sql | 1 + ...__egeis_hremployee_sample_data_for_pgr.sql | 18 + ...6__hr_employee_sample_data_for_panavel.sql | 20 + ...2__hr_employee_sample_data_for_default.sql | 9 + .../test/resources/db/migration/seed/.gitkeep | 0 121 files changed, 8366 insertions(+) create mode 100644 core-services/egov-hrms/CHANGELOG.md create mode 100644 core-services/egov-hrms/LOCALSETUP.md create mode 100644 core-services/egov-hrms/README.md create mode 100644 core-services/egov-hrms/egov-hrms.iml create mode 100644 core-services/egov-hrms/pom.xml create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/EgovEmployeeApplication.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/config/PropertiesManager.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/consumer/HrmsConsumer.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/model/Assignment.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/model/AuditDetails.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/model/DeactivationDetails.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/model/DepartmentalTest.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/model/EducationalQualification.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/model/Employee.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/model/EmployeeDocument.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/model/Jurisdiction.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/model/ReactivationDetails.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/model/Role.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/model/SMSRequest.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/model/ServiceHistory.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/DeactivationType.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/EmployeeDocumentReferenceType.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/Gender.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/GuardianRelation.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/UserType.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/producer/HRMSProducer.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeCountRowMapper.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueries.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueryBuilder.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeRepository.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeRowMapper.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/repository/RestCallRepository.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/service/DefaultUserService.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/service/EmployeeService.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/service/IdGenService.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/service/IndividualService.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/service/MDMSService.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/service/NotificationService.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/service/UserService.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/utils/ErrorConstants.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/utils/HRMSConstants.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/utils/HRMSUtils.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/utils/ResponseInfoFactory.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeRequest.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeResponse.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeSearchCriteria.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdGenerationRequest.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdGenerationResponse.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdRequest.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdResponse.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/RequestInfoWrapper.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/User.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/UserRequest.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/UserResponse.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/controller/EmployeeController.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/validator/EmployeeValidator.java create mode 100644 core-services/egov-hrms/src/main/resources/application.properties create mode 100644 core-services/egov-hrms/src/main/resources/config/application-config.properties create mode 100644 core-services/egov-hrms/src/main/resources/config/hrm-employee-update-persister.yml create mode 100644 core-services/egov-hrms/src/main/resources/config/hrms-employee-persister.yml create mode 100644 core-services/egov-hrms/src/main/resources/db/Dockerfile create mode 100644 core-services/egov-hrms/src/main/resources/db/migrate.sh create mode 100644 core-services/egov-hrms/src/main/resources/db/migration/main/V20190122152236__create_hrms_employee_table_ddl.sql create mode 100644 core-services/egov-hrms/src/main/resources/db/migration/main/V20190130120650__alter_assgnmt_add_currentassgmt_ddl.sql create mode 100644 core-services/egov-hrms/src/main/resources/db/migration/main/V20190204154948__create_position_sequence_ddl.sql create mode 100644 core-services/egov-hrms/src/main/resources/db/migration/main/V20190204163735__alter_deactivation_rename_remarks_ddl.sql create mode 100644 core-services/egov-hrms/src/main/resources/db/migration/main/V20190204172710__secondary_indexes_ddl.sql create mode 100644 core-services/egov-hrms/src/main/resources/db/migration/main/V20190215120811__alter_uk_constraint_dml.sql create mode 100644 core-services/egov-hrms/src/main/resources/db/migration/main/V20190219163221__alter_remove_phone_name_clm_dml.sql create mode 100644 core-services/egov-hrms/src/main/resources/db/migration/main/V20190301154105__alter_add_isactive_ddl.sql create mode 100644 core-services/egov-hrms/src/main/resources/db/migration/main/V20201005230836__eg_hrms_employee_index_ddl.sql create mode 100644 core-services/egov-hrms/src/main/resources/db/migration/main/V20201223230836__eg_hrms_employee_reactivation_details_index_ddl.sql create mode 100644 core-services/egov-hrms/src/main/resources/db/migration/main/V20201228172710__reactivation_indexes_ddl.sql create mode 100644 core-services/egov-hrms/src/main/resources/db/migration/seed/.gitkeep create mode 100644 core-services/egov-hrms/src/test/resources/application.properties create mode 100644 core-services/egov-hrms/src/test/resources/config/application-config.properties create mode 100644 core-services/egov-hrms/src/test/resources/db/Dockerfile create mode 100644 core-services/egov-hrms/src/test/resources/db/migrate.sh create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/dev/V20170428152327__egeis_hremployee_sample_data_for_pgr.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/dev/V20170530010026__hr_employee_sample_data_for_panavel.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/dev/V20170614093822__hr_employee_sample_data_for_default.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185601__hr_employee_employee.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185602__hr_employee_assignment.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185603__hr_employee_educationalqualification.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185604__hr_employee_departmentaltest.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185605__hr_employee_employee_jurisdictions.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185606__hr_employee_hoddepartment.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185607__hr_employee_employee_languages.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185608__hr_employee_probation.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185609__hr_employee_regularisation.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185610__hr_employee_servicehistory.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185611__hr_employee_technicalqualification.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185612__hr_employee_added_and_updated_foreign_key_constraints.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185613__updated_null_checks_in_egeis_employee_table.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185614__updated_null_checks_in_egeis_regularisation_table.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185615__hr_employee_employeedocuments.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185616__updated_unique_constraint_in_hr_employee.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185617__updated_createdDate_and_lastModifiedDate_columns.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185618__updated_combination_pk.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185619__updated_foreign_key_names.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170420145502__update_combination_uk.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170502150908__updated_employeestatus_column_datatype.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170509104227__hr_employee_add_lastmodifieddate.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170509121707__hr_hoddepartment_add_lastmodifieddate.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170525144339__hr_employee_added_createdBy_createdDate_lastModifiedBy_lastModifiedDate_columns.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170609165847__egeis_nominee_table.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170703101329__dropped_unique_document_constraint_from_egeis_employeedocuments.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20170707184507__egeis_aprdetails_table.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20171023104634__hr_employee_add_ifsccode.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20180310133312__hr_employee_disciplinary.ddl.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20180310133625__hr_employee_disciplinary_documents.ddl.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20180312150245__hr_employee_disciplinary_alter_add_column.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20180314134356__hr_employee_disciplinary_alter_length_modify.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20180315135946__hr_employee_disciplinary_alter_add_remove_columns.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20180316163101__hr_employee_servicehistory_add_column.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20180416144447__hr_employee_department_alter_type.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/main/V20180418144447__hr_employee_designation_alter_type.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/qa/V20170428152327__egeis_hremployee_sample_data_for_pgr.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/qa/V20170530010026__hr_employee_sample_data_for_panavel.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/qa/V20170614093822__hr_employee_sample_data_for_default.sql create mode 100644 core-services/egov-hrms/src/test/resources/db/migration/seed/.gitkeep diff --git a/core-services/egov-hrms/CHANGELOG.md b/core-services/egov-hrms/CHANGELOG.md new file mode 100644 index 00000000000..ff7b8ed8811 --- /dev/null +++ b/core-services/egov-hrms/CHANGELOG.md @@ -0,0 +1,37 @@ +# Changelog +All notable changes to this module will be documented in this file. + +## 1.2.5 - 2023-02-02 + +- Transition from 1.2.5-beta version to 1.2.5 version + +## 1.2.5-beta - 2022-03-02 +- Added security fix for restricting employee search from citizen role + +## 1.2.4 - 2022-01-13 +- Updated to log4j2 version 2.17.1 + +## 1.2.3 - 2021-07-26 + - Fixed RAIN-3056: Able to re-activate employee by selecting the previous date + +## 1.2.2 - 2021-05-11 + - VUL-WEB-L008 + - Added @SafeHtml annotaion on string fields + - Updated POM to add safeHtml validator libraries + +## 1.2.1 - 2021-02-26 +- Updated domain name in application.properties + +## 1.2.0 - 2021-01-12 +- Added employee reactivation feature + +## 1.1.0 - 2020-05-27 + +- Upgraded to `tracer:2.0.0-SNAPSHOT` +- Upgraded to `Spring boot 2.2.6` +- Renamed `ReferenceType` enum to `EmployeeDocumentReferenceType` +- Added typescript interface generation plugin + +## 1.0.0 + +- Base version diff --git a/core-services/egov-hrms/LOCALSETUP.md b/core-services/egov-hrms/LOCALSETUP.md new file mode 100644 index 00000000000..275a5420e3c --- /dev/null +++ b/core-services/egov-hrms/LOCALSETUP.md @@ -0,0 +1,46 @@ +# Local Setup + +To setup the egov-hrms service in your local system, clone the [Core Service repository](https://github.com/egovernments/core-services). + +## Dependencies + +### Infra Dependency + +- [x] Postgres DB +- [ ] Redis +- [ ] Elasticsearch +- [x] Kafka + - [ ] Consumer + - [x] Producer + +## Running Locally + +To run the egov-hrms services in 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-idgen) 8087:8080 & +kubectl port-forward -n egov $(kgpt egov-mdms-service) 8088:8080 & +kubectl port-forward -n egov $(kgpt egov-user) 8089:8080 & +kubectl port-forward -n egov $(kgpt egov-filestore) 8090:8080 & +kubectl port-forward -n egov $(kgpt egov-localization) 8091:8080 & +``` + +Update below listed properties in `application.properties` before running the project: + +```ini +# {Id Gen service hostname} +egov.idgen.host = http://127.0.0.1:8087 + +# {mdms hostname} +egov.mdms.host=http://127.0.0.1:8088 + +# {user service hostname} +egov.user.host = http://127.0.0.1:8089 + +# {Filestore service hostname} +egov.filestore.host = http://127.0.0.1:8090 + +# {Localization service hostname} +egov.localization.host = http://127.0.0.1:8091 +``` diff --git a/core-services/egov-hrms/README.md b/core-services/egov-hrms/README.md new file mode 100644 index 00000000000..ceb2f235664 --- /dev/null +++ b/core-services/egov-hrms/README.md @@ -0,0 +1,112 @@ +# Egov-HRMS Service +### HRMS Service +The objective of HRMS is to provide a service that manages all the employees enrolled onto the system. HRMS provides extensive APIs to create, update and search the employees with attributes like assignments, service history, jurisdiction etc. HRMS can be treated a sub-set of the egov-user service, Every employee created through HRMS will also be created as a user in egov-user. + +### DB UML Diagram + +- NA + +### Service Dependencies +- egov-user +- egov-localization +- egov-idgen +- egov-mdms +- egov-filestore + +### Swagger API Contract +- Please refer to the [Swagger API contarct](https://editor.swagger.io/?url=https://raw.githubusercontent.com/egovernments/business-services/master/Docs/hrms-v1.0.0.yaml#!/) for HRMS service to understand the structure of APIs and to have visualization of all internal APIs. + + +## Service Details +**Details of all the entities involved:** + +**a) Assignments:** Every employee is assigned a list of assignments, every assignment is a designation provided to that employee for a given period of time. These designations are mapped to departments. This also includes marking the employee as HOD for that dept if needed. Employee can also provide information on who does he report to. + + - **Constraints:** + 1. For a given period of time an employee shouldn't have more than one assignments. + 2. The department and designation part of the employee must be configured in the system. + 3. Details of assignment once entered in the system cannot be deleted. + 4. An employee cannot have more than one active assignment. + +**b) Jurisdictions:** A jurisdiction is a area of power for any employee. It can be a zone, ward, block, city, state or the country. Currently a jurisdiction is defined as combination of Hierarchy type, Boundary Type and the actual Boundary. However, in the current system we are not validating these jurisdictions. This is being collected only for the sake of data. + + - **Constraints:** + 1. The details pertaining to a jurisdiction like Hierarchy, Boundary Type and Boundary must be configured in the system. + 2. An employee can have more than one jurisdictions. + 3. Currently in the system jurisdiction is limited to within a ULB. + +**c) Service History:** Service history is the record of an employee's professional experience. It captures information about location and period of work with necessary order number. Information about the current work details are to be entered here. + + - **Constraints:** + 1. There's no rule on period, dates of different services can overlap. + 2. There's no cap on the number of entries in the service history. + 3. Captured as legacy data. + +**d) Educational Details:** Captures educational details of the employee. Captures information like Degree, Year of Passing, University, Specialization etc as part of the educational details. + + - **Constraints:** + 1. Details pertaining to educational details like Degree, Specialization must be configured. + + +**e) Departmental Tests:** Captures details of the tests undertaken by the employee. Like name of the test and year of passing. + + - **Constraints:** + 1. Test details must be configures in the system. + +**f) Deactivation Details:** Details of deactivation of the employee, which captures reason for deactivation, period of deactivation and other necessary details. + + - **Constraints:** + 1. Deactivation details are compulsory while deactivating an employee. + +**f) Reactivation Details:** Details of reactivation of the employee, which captures reason for reactivation, the effective date from when reactivation take place and other necessary details. + + - **Constraints:** + 1. Reactivation details are compulsory while reactivating an employee. + + + +**Uniqueness Constraints:** +- Employee code has to be unique and will be used as username for login. +- Phone number has to be unique, which means no 2 employees can have the same phone number. + + + +**Notification:** +- Notification is sent to the phone number of the employee who has been created in the system. This is an SMS notification. + +### Configurable properties + +| Environment Variables | Description | Value | +| ----------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------| +| `egov.hrms.employee.app.link` | This is the link to the mseva app, which differs based on the environment. | https://mseva.lgpunjab.gov.in/employee/user/login | +| `egov.hrms.default.pagination.limit` | This is the pagination limit on search results of employee search, it can be set to any numeric value without decimals. | 200 | +| `egov.hrms.default.pwd.length` | This is the length of password to be generated at the time of employee creation. However, please ensure this is in sync with the egov-user pwd policy. | 10 | +| `open.search.enabled.roles` | This is a list of Role codes that are allowed to perform an open-search in hrms. | SUPERUSER,ADMIN | +| `egov.idgen.ack.name` | Key to be configured in Idgen alongwith the ID format to generate employee code. | hrms.employeecode | +| `egov.idgen.ack.format` | Format to be configured in ID gen to generate employee code. | EMP-[city]-[SEQ_EG_HRMS_EMP_CODE] | +### API Details + +`BasePath` /egov-hrms/employees/[API endpoint] + +##### Method +**a) Create Employee `POST /_create` :** API (Bulk API) to create an employee with the following details: Assignments, Jurisdictions, Service History, Educational Details, Departmental Tests + +**b) Update Employee `POST /_update` :** API (Bulk API) to update the details of an employee with the following details: Assignments, Jurisdictions, Service History, Educational Details, Departmental Tests. There are constraints under which the update works, which are listed in the details of entities. As part of the personal details of the employee, Code of the employee cannot be updated once created. + +Deactivation is a part of the update API where the employee is marked inactive. This marks the user entry of this employee also as inactive. While deactivating an employee it is mandatory to provide deactivation details as well. + +**c) Search Employee `POST /_search` :** API to search the employee in the system on the following criteria: Id, UUID, Name, Code, Status, Type, Department, Designation, Position. All of them being arrays, at a time more than one employees can be fetched. +Constraints: a. Open Search is enabled only for a set of users. Currently it is enabled only for SUPERUSER, if it has to be enabled for other roles, add those roles to the parameter 'open.search.enabled.roles' in app.properties with values(role codes) separated by comma. + +**d) Count of Employee `POST /_count` :** This API is use to get list of active and inactive employee present in the system. + +### Kafka Consumers + +- NA + +### Kafka Producers + +- Following are the Producer topic. + - **save-hrms-employee** :- This topic is used to create new employee in the system. + - **update-hrms-employee** :- This topic is used to update the existing employee in the systen. + - **egov.core.notification.sms** :- This topic is used to send noification to the phone number of the employee who has been created in the system. \ No newline at end of file diff --git a/core-services/egov-hrms/egov-hrms.iml b/core-services/egov-hrms/egov-hrms.iml new file mode 100644 index 00000000000..abf9c52d541 --- /dev/null +++ b/core-services/egov-hrms/egov-hrms.iml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/core-services/egov-hrms/pom.xml b/core-services/egov-hrms/pom.xml new file mode 100644 index 00000000000..63ff6fcda8c --- /dev/null +++ b/core-services/egov-hrms/pom.xml @@ -0,0 +1,176 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.6.RELEASE + + org.egov + egov-hrms + 1.2.6-SNAPSHOT + egov-hrms + HR Management System + + 2.17.1 + UTF-8 + 1.8 + 2.9.6 + UTF-8 + 3.3.9 + 1.18.8 + 2.6 + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework + spring-beans + 5.2.20.RELEASE + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.flywaydb + flyway-core + + + org.postgresql + postgresql + + + org.egov.services + services-common + 1.1.1-SNAPSHOT + + + commons-lang + commons-lang + ${commons-lang-version} + + + org.projectlombok + lombok + + + org.springframework.boot + spring-boot-devtools + + + org.springframework + spring-test + test + + + org.springframework.boot + spring-boot-starter-test + test + + + com.google.code.gson + gson + 2.8.0 + + + org.egov + mdms-client + 0.0.2-SNAPSHOT + + + org.egov.services + tracer + 2.1.2-SNAPSHOT + + + org.hibernate + hibernate-validator + 6.0.16.Final + + + org.jsoup + jsoup + 1.10.2 + + + org.egov.common + health-services-models + 1.0.9-SNAPSHOT + compile + + + + + 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/ + + always + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + 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.hrms.web.contract.EmployeeRequest + org.egov.hrms.web.contract.EmployeeResponse + org.egov.hrms.web.contract.EmployeeSearchCriteria + + + + + org.egov.hrms.web.contract.User:User + org.egov.hrms.model.AuditDetails:AuditDetails + org.egov.common.contract.request.User:User + org.egov.common.contract.request.RequestInfo:RequestInfo + org.egov.common.contract.response.ResponseInfo:ResponseInfo + + Digit + true + module + + + + + diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/EgovEmployeeApplication.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/EgovEmployeeApplication.java new file mode 100644 index 00000000000..12c7c5daeb5 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/EgovEmployeeApplication.java @@ -0,0 +1,120 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms; + +import java.util.TimeZone; + +import javax.annotation.PostConstruct; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.utils.MultiStateInstanceUtil; +import org.egov.hrms.config.PropertiesManager; +import org.egov.hrms.repository.RestCallRepository; +import org.egov.hrms.service.DefaultUserService; +import org.egov.hrms.service.IndividualService; +import org.egov.hrms.service.UserService; +import org.egov.tracer.config.TracerConfiguration; +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.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Import; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.context.annotation.Primary; + +@SpringBootApplication +@ComponentScan(basePackages = { "org.egov.hrms", "org.egov.hrms.web.controller" , "org.egov.hrms.config"}) +@Import({TracerConfiguration.class, MultiStateInstanceUtil.class}) +@Slf4j +public class EgovEmployeeApplication { + + @Value("${app.timezone}") + private String timeZone; + + @PostConstruct + public void initialize() { + TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); + } + + @Bean + public ObjectMapper getObjectMapper() { + final ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + objectMapper.setTimeZone(TimeZone.getTimeZone(timeZone)); + return objectMapper; + } + + @Bean + @Primary + public UserService getUserService(@Value("${egov.hrms.user.service.qualifier}") String userServiceQualifier, + @Autowired PropertiesManager propertiesManager, + @Autowired RestCallRepository restCallRepository, + @Autowired ObjectMapper objectMapper, + @Autowired MultiStateInstanceUtil multiStateInstanceUtil, + @Value("${egov.user.create.endpoint}") String userCreateEndpoint, + @Value("${egov.user.update.endpoint}") String userUpdateEndpoint, + @Value("${egov.user.search.endpoint}") String userSearchEndpoint) { + if (userServiceQualifier.equalsIgnoreCase("individualService")) { + log.info("using individual module as user service"); + return new IndividualService(propertiesManager, restCallRepository); + } + else { + log.info("using egov-user module as user service"); + DefaultUserService userService = new DefaultUserService(); + userService.setPropertiesManager(propertiesManager); + userService.setRestCallRepository(restCallRepository); + userService.setObjectMapper(objectMapper); + userService.setCentralInstanceUtil(multiStateInstanceUtil); + userService.setUserCreateEndpoint(userCreateEndpoint); + userService.setUserUpdateEndpoint(userUpdateEndpoint); + userService.setUserSearchEndpoint(userSearchEndpoint); + return userService; + } + } + + public static void main(String[] args) { + SpringApplication.run(EgovEmployeeApplication.class, args); + } +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/config/PropertiesManager.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/config/PropertiesManager.java new file mode 100644 index 00000000000..dd0fb1ee4c6 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/config/PropertiesManager.java @@ -0,0 +1,137 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.empernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@empernments.org. + */ + +package org.egov.hrms.config; + +import lombok.*; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class PropertiesManager { + + //Hosts and Endpoints + @Value("${egov.mdms.host}") + public String mdmsHost; + + @Value("${egov.mdms.search.endpoint}") + public String mdmsSearchEndpoint; + + @Value("${egov.user.host}") + public String userHost; + + @Value("${egov.user.search.endpoint}") + public String userSearchEndpoint; + + @Value("${egov.user.create.endpoint}") + public String userCreateEndpoint; + + @Value("${egov.user.update.endpoint}") + public String userUpdateEndpoint; + + @Value("${egov.localization.host}") + public String localizationHost; + + @Value("${egov.localization.search.endpoint}") + public String localizationSearchEndpoint; + + @Value("${egov.idgen.host}") + public String idGenHost; + + @Value("${egov.idgen.path}") + public String idGenEndpoint; + + + //Kafka Topics + @Value("${kafka.topics.save.service}") + public String saveEmployeeTopic; + + @Value("${kafka.topics.update.service}") + public String UpdateEmployeeTopic; + + @Value("${kafka.topics.notification.sms}") + public String coreNotificationTopic; + + @Value("${kafka.topics.hrms.updateData}") + public String updateTopic; + + + //Variables + @Value("${egov.idgen.ack.name}") + public String hrmsIdGenKey; + + @Value("${egov.idgen.ack.format}") + public String hrmsIdGenFormat; + + @Value("${open.search.enabled.roles}") + public String openSearchEnabledRoles; + + @Value("${state.level.tenant.id}") + public String stateLevelTenantId; + + @Value("${parent.level.tenant.id}") + private String parentLevelTenantId; + + @Value("${decryption.abac.enable}") + private Boolean isDecryptionEnable; + + @Value("${egov.individual.host}") + private String individualHost; + + @Value("${egov.individual.create.endpoint}") + private String individualCreateEndpoint; + + @Value("${egov.individual.update.endpoint}") + private String individualUpdateEndpoint; + + @Value("${egov.individual.delete.endpoint}") + private String individualDeleteEndpoint; + + @Value("${egov.individual.search.endpoint}") + private String individualSearchEndpoint; + + @Value("${egov.hrms.auto.generate.password}") + private boolean autoGeneratePassword; +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/consumer/HrmsConsumer.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/consumer/HrmsConsumer.java new file mode 100644 index 00000000000..a4c33b0c096 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/consumer/HrmsConsumer.java @@ -0,0 +1,47 @@ +package org.egov.hrms.consumer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.clients.admin.NewTopic; +import org.egov.hrms.config.PropertiesManager; +import org.egov.hrms.producer.HRMSProducer; +import org.egov.hrms.service.NotificationService; +import org.egov.hrms.web.contract.EmployeeRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +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; + +@Component +@Slf4j +public class HrmsConsumer { + + @Autowired + private NotificationService notificationService; + + @Autowired + private ObjectMapper mapper; + + @Autowired + private HRMSProducer hrmsProducer; + + @Autowired + private PropertiesManager propertiesManager; + + @KafkaListener(topics = {"${kafka.topics.hrms.updateData}"}) + public void listenUpdateEmployeeData(final HashMap record,@Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + EmployeeRequest employeeRequest = mapper.convertValue(record, EmployeeRequest.class); + hrmsProducer.push(propertiesManager.getUpdateEmployeeTopic(), employeeRequest); + notificationService.sendReactivationNotification(employeeRequest); + } catch (final Exception e) { + + log.error("Error while listening to value: " + record + " on topic: " + topic + ": ", e); + } + } + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Assignment.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Assignment.java new file mode 100644 index 00000000000..9df7a4b92bd --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Assignment.java @@ -0,0 +1,96 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; +import javax.validation.constraints.NotNull; + +import org.hibernate.validator.constraints.SafeHtml; +import org.springframework.validation.annotation.Validated; + +@Validated +@EqualsAndHashCode(exclude = {"auditDetails"}) +@AllArgsConstructor +@Builder +@Getter +@NoArgsConstructor +@Setter +@ToString +public class Assignment { + + @SafeHtml + private String id; + + private Long position; + + @SafeHtml + @NotNull + private String designation; + + @SafeHtml + @NotNull + private String department; + + @NotNull + private Long fromDate; + + private Long toDate; + + @SafeHtml + private String govtOrderNumber; + + @SafeHtml + private String tenantid; + + @SafeHtml + private String reportingTo; + + @JsonProperty("isHOD") + private Boolean isHOD=false; + + @NotNull + @JsonProperty("isCurrentAssignment") + private Boolean isCurrentAssignment; + + private AuditDetails auditDetails; + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/AuditDetails.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/AuditDetails.java new file mode 100644 index 00000000000..bb368cd9852 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/AuditDetails.java @@ -0,0 +1,25 @@ +package org.egov.hrms.model; + +import lombok.*; + +import javax.validation.constraints.NotNull; + + +@AllArgsConstructor +@Builder +@Getter +@NoArgsConstructor +@Setter +@ToString +public class AuditDetails { + + private String createdBy; + + private Long createdDate; + + private String lastModifiedBy; + + private Long lastModifiedDate; + + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/DeactivationDetails.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/DeactivationDetails.java new file mode 100644 index 00000000000..32b7787825f --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/DeactivationDetails.java @@ -0,0 +1,45 @@ +package org.egov.hrms.model; + +import lombok.*; +import org.hibernate.validator.constraints.SafeHtml; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; + +@Validated +@EqualsAndHashCode(exclude = {"auditDetails"}) +@AllArgsConstructor +@Getter +@NoArgsConstructor +@Setter +@ToString +@Builder +public class DeactivationDetails { + + @SafeHtml + private String id; + + @SafeHtml + @NotNull + private String reasonForDeactivation; + + @SafeHtml + private String orderNo; + + @SafeHtml + private String remarks; + + @NotNull + private Long effectiveFrom; + + @SafeHtml + private String tenantId; + + private AuditDetails auditDetails; + + + + +} + + diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/DepartmentalTest.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/DepartmentalTest.java new file mode 100644 index 00000000000..6341ce3893a --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/DepartmentalTest.java @@ -0,0 +1,80 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.model; + +import lombok.*; + +import javax.validation.constraints.NotNull; + +import org.hibernate.validator.constraints.SafeHtml; +import org.springframework.validation.annotation.Validated; + +@Validated +@EqualsAndHashCode(exclude = {"auditDetails"}) +@Builder +@AllArgsConstructor +@Getter +@NoArgsConstructor +@Setter +@ToString +public class DepartmentalTest { + + @SafeHtml + private String id; + + @SafeHtml + @NotNull + private String test; + + @NotNull + private Long yearOfPassing; + + @SafeHtml + private String remarks; + + @SafeHtml + private String tenantId; + + private AuditDetails auditDetails; + + private Boolean isActive; + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/EducationalQualification.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/EducationalQualification.java new file mode 100644 index 00000000000..2071915c165 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/EducationalQualification.java @@ -0,0 +1,88 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.model; + +import lombok.*; + +import javax.validation.constraints.NotNull; + +import org.hibernate.validator.constraints.SafeHtml; +import org.springframework.validation.annotation.Validated; + +@Validated +@EqualsAndHashCode(exclude = {"auditDetails"}) +@Builder +@AllArgsConstructor +@Getter +@NoArgsConstructor +@Setter +@ToString +public class EducationalQualification { + + @SafeHtml + private String id; + + @SafeHtml + @NotNull + private String qualification; + + @SafeHtml + @NotNull + private String stream; + + @NotNull + private Long yearOfPassing; + + @SafeHtml + private String university; + + @SafeHtml + private String remarks; + + @SafeHtml + private String tenantId; + + private AuditDetails auditDetails; + + private Boolean isActive; + + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Employee.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Employee.java new file mode 100644 index 00000000000..f6a9b5cd59a --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Employee.java @@ -0,0 +1,133 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.model; + +import lombok.*; +import org.egov.hrms.web.contract.User; +import org.hibernate.validator.constraints.NotEmpty; +import org.hibernate.validator.constraints.SafeHtml; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.ArrayList; +import java.util.List; + +@Validated +@AllArgsConstructor +@EqualsAndHashCode +@Getter +@NoArgsConstructor +@Setter +@ToString +@Builder +public class Employee { + + private Long id; + + @SafeHtml + @Size(max = 1024) + private String uuid; + + @SafeHtml + @Size(min = 1, max = 256) + private String code; + + @SafeHtml + @Size(max = 250) + private String employeeStatus; + + @SafeHtml + @NotNull + @Size(max = 250) + private String employeeType; + + private Long dateOfAppointment; + + @Valid + @NotEmpty + @Size(min = 1,max = 50) + private List jurisdictions = new ArrayList<>(); + + + @Valid + private List assignments = new ArrayList<>(); + + @Valid + @Size(max=25) + private List serviceHistory = new ArrayList<>(); + + + private Boolean IsActive; + + @Valid + @Size(max=25) + private List education = new ArrayList<>(); + + @Valid + @Size(max=25) + private List tests = new ArrayList<>(); + + @SafeHtml + @NotNull + @Size(max = 250) + private String tenantId; + + @Valid + @Size(max=50) + private List documents = new ArrayList<>(); + + @Valid + private List deactivationDetails = new ArrayList<>(); + + private List reactivationDetails = new ArrayList<>(); + + private AuditDetails auditDetails; + + private Boolean reActivateEmployee; + + @Valid + @NotNull + private User user; + + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/EmployeeDocument.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/EmployeeDocument.java new file mode 100644 index 00000000000..d93c69f4cf0 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/EmployeeDocument.java @@ -0,0 +1,85 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.model; + +import org.egov.hrms.model.enums.EmployeeDocumentReferenceType; +import org.hibernate.validator.constraints.SafeHtml; +import org.springframework.validation.annotation.Validated; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Validated +@EqualsAndHashCode(exclude = {"auditDetails"}) +@AllArgsConstructor +@Getter +@NoArgsConstructor +@Setter +@ToString +@Builder +public class EmployeeDocument { + + @SafeHtml + private String id; + + @SafeHtml + private String documentName; + + @SafeHtml + private String documentId; + + private EmployeeDocumentReferenceType referenceType; + + @SafeHtml + private String referenceId; + + @SafeHtml + private String tenantId; + + private AuditDetails auditDetails; + + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Jurisdiction.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Jurisdiction.java new file mode 100644 index 00000000000..5afc27194cb --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Jurisdiction.java @@ -0,0 +1,86 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.model; + +import lombok.*; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import org.hibernate.validator.constraints.SafeHtml; +import org.springframework.validation.annotation.Validated; + +@Validated +@EqualsAndHashCode(exclude = {"auditDetails"}) +@Builder +@AllArgsConstructor +@Getter +@NoArgsConstructor +@Setter +@ToString +public class Jurisdiction { + + @SafeHtml + private String id; + + @SafeHtml + @NotNull + @Size(min=2, max=100) + private String hierarchy; + + @SafeHtml + @NotNull + @Size(min=2, max=100) + private String boundary; + + @SafeHtml + @NotNull + @Size(max=256) + private String boundaryType; + + @SafeHtml + private String tenantId; + + private AuditDetails auditDetails; + + private Boolean isActive; + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/ReactivationDetails.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/ReactivationDetails.java new file mode 100644 index 00000000000..a5cb0c1a3c4 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/ReactivationDetails.java @@ -0,0 +1,45 @@ +package org.egov.hrms.model; + +import lombok.*; +import org.hibernate.validator.constraints.SafeHtml; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; + +@Validated +@EqualsAndHashCode(exclude = {"auditDetails"}) +@AllArgsConstructor +@Getter +@NoArgsConstructor +@Setter +@ToString +@Builder +public class ReactivationDetails { + + @SafeHtml + private String id; + + @SafeHtml + @NotNull + private String reasonForReactivation; + + @SafeHtml + private String orderNo; + + @SafeHtml + private String remarks; + + @NotNull + private Long effectiveFrom; + + @SafeHtml + private String tenantId; + + private AuditDetails auditDetails; + + + + +} + + diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Role.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Role.java new file mode 100644 index 00000000000..6ab3212b245 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/Role.java @@ -0,0 +1,72 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.model; + +import lombok.*; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +@Builder +@AllArgsConstructor +@EqualsAndHashCode +@Getter +@NoArgsConstructor +@Setter +@ToString +public class Role { + + + @NotNull + @Size(min=2, max=100) + private String name; + + @Size(min=2, max=100) + private String code; + + @Size(max=256) + private String description; + + @Size(max = 256) + private String tenantId; + + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/SMSRequest.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/SMSRequest.java new file mode 100644 index 00000000000..31c92e38ef7 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/SMSRequest.java @@ -0,0 +1,19 @@ +package org.egov.hrms.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.ToString; + + +@Getter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ToString +public class SMSRequest { + private String mobileNumber; + private String message; + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/ServiceHistory.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/ServiceHistory.java new file mode 100644 index 00000000000..56bdb6e2ca9 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/ServiceHistory.java @@ -0,0 +1,85 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.model; + +import lombok.*; + +import javax.validation.constraints.NotNull; + +import org.hibernate.validator.constraints.SafeHtml; +import org.springframework.validation.annotation.Validated; + +@Validated +@EqualsAndHashCode(exclude = {"auditDetails"}) +@Builder +@AllArgsConstructor +@Getter +@NoArgsConstructor +@Setter +@ToString +public class ServiceHistory { + + @SafeHtml + private String id; + + @SafeHtml + private String serviceStatus; + + private Long serviceFrom; + + private Long serviceTo; + + @SafeHtml + private String orderNo; + + @SafeHtml + private String location; + + @SafeHtml + private String tenantId; + + private Boolean isCurrentPosition; + + private AuditDetails auditDetails; + + + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/DeactivationType.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/DeactivationType.java new file mode 100644 index 00000000000..3b632fc1e03 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/DeactivationType.java @@ -0,0 +1,31 @@ +package org.egov.hrms.model.enums; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + + +public enum DeactivationType { + SUSPENSION("SUSPENSION"), DEATH("DEATH"), RETIRED("RETIRED"); + + private String value; + + DeactivationType(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return name(); + } + + @JsonCreator + public static DeactivationType fromValue(String passedValue) { + for (DeactivationType obj : DeactivationType.values()) { + if (String.valueOf(obj.value).equals(passedValue.toUpperCase())) { + return obj; + } + } + return null; + } +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/EmployeeDocumentReferenceType.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/EmployeeDocumentReferenceType.java new file mode 100644 index 00000000000..f18fcd65a4d --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/EmployeeDocumentReferenceType.java @@ -0,0 +1,31 @@ +package org.egov.hrms.model.enums; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public enum EmployeeDocumentReferenceType { + HEADER("HEADER"), ASSIGNMENT("ASSIGNMENT"), JURISDICTION("JURISDICTION"), SERVICE("SERVICE"), + EDUCATION("EDUCATION"), TEST("TEST"), DEACTIVATION("DEACTIVATION"); + + private String value; + + EmployeeDocumentReferenceType(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return name(); + } + + @JsonCreator + public static EmployeeDocumentReferenceType fromValue(String passedValue) { + for (EmployeeDocumentReferenceType obj : EmployeeDocumentReferenceType.values()) { + if (String.valueOf(obj.value).equals(passedValue.toUpperCase())) { + return obj; + } + } + return null; + } +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/Gender.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/Gender.java new file mode 100644 index 00000000000..7ab9adf1c8d --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/Gender.java @@ -0,0 +1,70 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.model.enums; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public enum Gender { + MALE("MALE"), FEMALE("FEMALE"), OTHERS("OTHERS"); + + private String value; + + Gender(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return name(); + } + + @JsonCreator + public static Gender fromValue(String passedValue) { + for (Gender obj : Gender.values()) { + if (String.valueOf(obj.value).equals(passedValue.toUpperCase())) { + return obj; + } + } + return null; + } +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/GuardianRelation.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/GuardianRelation.java new file mode 100644 index 00000000000..dead1f98b69 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/GuardianRelation.java @@ -0,0 +1,5 @@ +package org.egov.hrms.model.enums; + +public enum GuardianRelation { + FATHER, MOTHER, HUSBAND, OTHER; +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/UserType.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/UserType.java new file mode 100644 index 00000000000..153e5db53cd --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/model/enums/UserType.java @@ -0,0 +1,70 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.model.enums; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public enum UserType { + EMPLOYEE("EMPLOYEE"), CITIZEN("CITIZEN"), SYSTEM("SYSTEM"); + + private String value; + + UserType(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return name(); + } + + @JsonCreator + public static UserType fromValue(String passedValue) { + for (UserType obj : UserType.values()) { + if (String.valueOf(obj.value).equals(passedValue.toUpperCase())) { + return obj; + } + } + return null; + } +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/producer/HRMSProducer.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/producer/HRMSProducer.java new file mode 100644 index 00000000000..8521e631b1b --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/producer/HRMSProducer.java @@ -0,0 +1,19 @@ +package org.egov.hrms.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 HRMSProducer { + + @Autowired + private CustomKafkaTemplate kafkaTemplate; + + public void push(String topic, Object value) { + log.info("Topic: "+topic); + kafkaTemplate.send(topic, value); + } +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeCountRowMapper.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeCountRowMapper.java new file mode 100644 index 00000000000..2266e24695f --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeCountRowMapper.java @@ -0,0 +1,58 @@ +package org.egov.hrms.repository; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.hrms.model.*; +import org.egov.hrms.model.enums.EmployeeDocumentReferenceType; +import org.egov.hrms.web.contract.User; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Component +@Slf4j +public class EmployeeCountRowMapper implements ResultSetExtractor> { + + @Autowired + private ObjectMapper mapper; + + @Override + /** + * Maps ResultSet to Employee POJO. + */ + public Map extractData(ResultSet rs) throws SQLException, DataAccessException { + Map response = new HashMap<>(); + int totalEmployee = 0; + int activeEmployee = 0; + int inactiveEmployee = 0; + while(rs.next()) { + if(rs.getBoolean("active")) + activeEmployee = activeEmployee + rs.getInt("count"); + else + inactiveEmployee = inactiveEmployee + rs.getInt("count"); + totalEmployee = totalEmployee + rs.getInt("count"); + } + if(totalEmployee==0){ + response.put("activeEmployee","0"); + response.put("inactiveEmployee", "0"); + } + response.put("activeEmployee", String.valueOf(activeEmployee)); + response.put("inactiveEmployee", String.valueOf(inactiveEmployee)); + response.put("totalEmployee", String.valueOf(totalEmployee)); + return response; + } + + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueries.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueries.java new file mode 100644 index 00000000000..6b824692a34 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueries.java @@ -0,0 +1,57 @@ +package org.egov.hrms.repository; + +import org.springframework.stereotype.Component; + +@Component +public class EmployeeQueries { + + public static final String HRMS_GET_EMPLOYEES = "SELECT employee.id as employee_id, employee.uuid as employee_uuid, employee.code as employee_code, " + + "employee.dateOfAppointment as employee_doa, employee.employeestatus as employee_status, employeetype as employee_type, employee.active as employee_active, employee.reactivateemployee as employee_reactive, " + + "employee.tenantid as employee_tenantid, employee.createdby as employee_createdby, employee.createddate as employee_createddate, " + + "employee.lastmodifiedby as employee_lastmodifiedby, employee.lastmodifieddate as employee_lastmodifieddate, assignment.uuid as assignment_uuid, " + + "assignment.position as assignment_position, assignment.department as assignment_department, assignment.designation as assignment_designation, " + + "assignment.fromdate as assignment_fromdate, assignment.todate as assignment_todate, assignment.govtordernumber as assignment_govtordernumber, " + + "assignment.reportingto as assignment_reportingto, assignment.ishod as assignment_ishod, assignment.iscurrentassignment as assignment_iscurrentassignment, " + + "assignment.tenantid as assignment_tenantid, " + + "assignment.createdby as assignment_createdby, assignment.createddate as assignment_createddate, assignment.lastmodifiedby as assignment_lastmodifiedby, " + + "assignment.lastmodifieddate as assignment_lastmodifieddate, education.uuid as education_uuid, education.qualification as education_qualification, " + + "education.stream as education_stream, education.yearofpassing as education_yearofpassing, education.university as education_university, " + + "education.remarks as education_remarks,education.isactive as education_isactive ,education.tenantid as education_tenantid, education.createdby as education_createdby, " + + "education.createddate as education_createddate, education.lastmodifiedby as education_lastmodifiedby, education.lastmodifieddate as education_lastmodifieddate, " + + "depttest.uuid as depttest_uuid, depttest.test as depttest_test, depttest.yearofpassing as depttest_yearofpassing, depttest.remarks as depttest_remarks, " + + "depttest.isactive as depttest_isactive, depttest.tenantid as depttest_tenantid, depttest.createdby as depttest_createdby, depttest.createddate as depttest_createddate, " + + "depttest.lastmodifiedby as depttest_lastmodifiedby, depttest.lastmodifieddate as depttest_lastmodifieddate, docs.uuid as docs_uuid, " + + "docs.documentid as docs_documentid, docs.documentname as docs_documentname, docs.referencetype as docs_referencetype, " + + "docs.referenceid as docs_referenceid, docs.tenantid as docs_tenantid, docs.createdby as docs_createdby, docs.createddate as docs_createddate, " + + "docs.lastmodifiedby as docs_lastmodifiedby, docs.lastmodifieddate as docs_lastmodifieddate, jurisdiction.uuid as jurisdiction_uuid, " + + "jurisdiction.hierarchy as jurisdiction_hierarchy, jurisdiction.boundarytype as jurisdiction_boundarytype, jurisdiction.boundary as jurisdiction_boundary, " + + "jurisdiction.isactive as jurisdiction_isactive, jurisdiction.tenantid as jurisdiction_tenantid, jurisdiction.createdby as jurisdiction_createdby, jurisdiction.createddate as jurisdiction_createddate, " + + "jurisdiction.lastmodifiedby as jurisdiction_lastmodifiedby, jurisdiction.lastmodifieddate as jurisdiction_lastmodifieddate, history.uuid as history_uuid, " + + "history.servicestatus as history_servicestatus, history.servicefrom as history_servicefrom, history.serviceto as history_serviceto, " + + "history.ordernumber as history_ordernumber, history.iscurrentposition as history_iscurrentposition, history.location as history_location, " + + "history.tenantid as history_tenantid, history.createdby as history_createdby, history.createddate as history_createddate, " + + "history.lastmodifiedby as history_lastmodifiedby, history.lastmodifieddate as history_lastmodifieddate, deact.uuid as deact_uuid, " + + "deact.reasonfordeactivation as deact_reasonfordeactivation, deact.effectivefrom as deact_effectivefrom, deact.ordernumber as deact_ordernumber, " + + "deact.remarks as deact_remarks, deact.tenantid as deact_tenantid, deact.createdby as deact_createdby, " + + "deact.createddate as deact_createddate, deact.lastmodifiedby as deact_lastmodifiedby, deact.lastmodifieddate as deact_lastmodifieddate, " + + "react.uuid as react_uuid, react.reasonforreactivation as react_reasonforreactivation, react.effectivefrom as react_effectivefrom, react.ordernumber as react_ordernumber, " + + "react.remarks as react_remarks, react.tenantid as react_tenantid, react.createdby as react_createdby, " + + "react.createddate as react_createddate, react.lastmodifiedby as react_lastmodifiedby, react.lastmodifieddate as react_lastmodifieddate " + + "FROM eg_hrms_employee employee LEFT JOIN eg_hrms_assignment assignment ON employee.uuid = assignment.employeeid LEFT JOIN eg_hrms_educationaldetails education " + + "ON employee.uuid = education.employeeid LEFT JOIN eg_hrms_departmentaltests depttest ON employee.uuid = depttest.employeeid LEFT JOIN eg_hrms_empdocuments docs " + + "ON employee.uuid = docs.employeeid LEFT JOIN eg_hrms_servicehistory history ON employee.uuid = history.employeeid LEFT JOIN eg_hrms_jurisdiction jurisdiction " + + "ON employee.uuid = jurisdiction.employeeid LEFT JOIN eg_hrms_deactivationdetails deact ON employee.uuid = deact.employeeid LEFT JOIN eg_hrms_reactivationdetails react " + + "ON employee.uuid = react.employeeid WHERE "; + + public static final String HRMS_PAGINATION_WRAPPER = "SELECT * FROM " + + "(SELECT *, DENSE_RANK() OVER (ORDER BY employee_uuid) offset_ FROM " + "({})" + " result) result_offset " + + "WHERE offset_ > $offset AND offset_ <= $limit"; + + public static final String HRMS_POSITION_SEQ = "SELECT NEXTVAL('EG_HRMS_POSITION')"; + + public static final String HRMS_GET_ASSIGNMENT = "select distinct(employeeid) from eg_hrms_assignment assignment where assignment.tenantid notnull "; + + public static final String HRMS_COUNT_EMP_QUERY = "SELECT active, count(*) FROM eg_hrms_employee WHERE tenantid "; + + public static final String HRMS_GET_UNASSIGNED_EMPLOYEES = "SELECT employee.uuid from eg_hrms_employee employee LEFT JOIN eg_hrms_assignment assignment ON employee.uuid = assignment.employeeid where assignment.employeeid is null"; +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueryBuilder.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueryBuilder.java new file mode 100644 index 00000000000..4e5e5d7bdc4 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeQueryBuilder.java @@ -0,0 +1,168 @@ +package org.egov.hrms.repository; + +import org.apache.commons.lang3.StringUtils; +import org.egov.hrms.config.PropertiesManager; +import org.egov.hrms.web.contract.EmployeeSearchCriteria; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +@Service +public class EmployeeQueryBuilder { + + @Value("${egov.hrms.default.pagination.limit}") + private Integer defaultLimit; + + @Autowired + private PropertiesManager properties; + + /** + * Returns query for searching employees + * + * @param criteria + * @return + */ + public String getEmployeeSearchQuery(EmployeeSearchCriteria criteria,List preparedStmtList ) { + StringBuilder builder = new StringBuilder(EmployeeQueries.HRMS_GET_EMPLOYEES); + addWhereClause(criteria, builder, preparedStmtList); + return paginationClause(criteria, builder); + } + + public String getEmployeeCountQuery(String tenantId, List preparedStmtList ) { + StringBuilder builder = new StringBuilder(EmployeeQueries.HRMS_COUNT_EMP_QUERY); + if(tenantId.equalsIgnoreCase(properties.stateLevelTenantId)){ + builder.append("LIKE ? "); + preparedStmtList.add(tenantId+"%"); + } + else{ + builder.append("= ? "); + preparedStmtList.add(tenantId); + } + builder.append("GROUP BY active"); + return builder.toString(); + } + + public String getPositionSeqQuery() { + return EmployeeQueries.HRMS_POSITION_SEQ; + } + + /** + * Adds where clause to the query based on the requirement. + * @param criteria + * @param builder + * @param preparedStmtList + */ + public void addWhereClause(EmployeeSearchCriteria criteria, StringBuilder builder, List preparedStmtList) { + if(!StringUtils.isEmpty(criteria.getTenantId())) { + builder.append(" employee.tenantid = ?"); + preparedStmtList.add(criteria.getTenantId()); + } + else + builder.append(" employee.tenantid NOTNULL"); + + if(!CollectionUtils.isEmpty(criteria.getCodes())){ + List codes = criteria.getCodes().stream().map(String::toLowerCase).collect(Collectors.toList()); + builder.append(" and lower(employee.code) IN (").append(createQuery(codes)).append(")"); + addToPreparedStatement(preparedStmtList, codes); + } + if(!CollectionUtils.isEmpty(criteria.getIds())){ + builder.append(" and employee.id IN (").append(createQuery(criteria.getIds())).append(")"); + addToPreparedStatement(preparedStmtList, criteria.getIds()); + } + if(!CollectionUtils.isEmpty(criteria.getUuids())){ + builder.append(" and employee.uuid IN (").append(createQuery(criteria.getUuids())).append(")"); + addToPreparedStatement(preparedStmtList, criteria.getUuids()); + } + if(!CollectionUtils.isEmpty(criteria.getEmployeestatuses())){ + builder.append(" and employee.employeestatus IN (").append(createQuery(criteria.getEmployeestatuses())).append(")"); + addToPreparedStatement(preparedStmtList, criteria.getEmployeestatuses()); + } + if(!CollectionUtils.isEmpty(criteria.getEmployeetypes())){ + builder.append(" and employee.employeetype IN (").append(createQuery(criteria.getEmployeetypes())).append(")"); + addToPreparedStatement(preparedStmtList, criteria.getEmployeetypes()); + } + if(criteria.getIsActive() != null){ + builder.append(" and employee.active = ?"); + preparedStmtList.add(criteria.getIsActive()); + } + } + + public String paginationClause(EmployeeSearchCriteria criteria, StringBuilder builder) { + String pagination = EmployeeQueries.HRMS_PAGINATION_WRAPPER; + pagination = pagination.replace("{}", builder.toString()); + if(null != criteria.getOffset()) + pagination = pagination.replace("$offset", criteria.getOffset().toString()); + else + pagination = pagination.replace("$offset", "0"); + + if(null != criteria.getLimit()){ + Integer limit = criteria.getLimit() + criteria.getOffset(); + pagination = pagination.replace("$limit", limit.toString()); + } + else + pagination = pagination.replace("$limit", defaultLimit.toString()); + + return pagination; + } + + public String getAssignmentSearchQuery(EmployeeSearchCriteria criteria, List preparedStmtList) { + StringBuilder builder = new StringBuilder(EmployeeQueries.HRMS_GET_ASSIGNMENT); + addWhereClauseAssignment(criteria, builder, preparedStmtList); + return builder.toString(); + } + + private void addWhereClauseAssignment(EmployeeSearchCriteria criteria, StringBuilder builder, List preparedStmtList) { + if(!CollectionUtils.isEmpty(criteria.getDepartments())){ + builder.append(" and assignment.department IN (").append(createQuery(criteria.getDepartments())).append(")"); + addToPreparedStatement(preparedStmtList, criteria.getDepartments()); + } + if(!CollectionUtils.isEmpty(criteria.getDesignations())){ + builder.append(" and assignment.designation IN (").append(createQuery(criteria.getDesignations())+")"); + addToPreparedStatement(preparedStmtList,criteria.getDesignations()); + } + if(!CollectionUtils.isEmpty(criteria.getPositions())){ + builder.append(" and assignment.position IN (").append(createQuery(criteria.getPositions())+")"); + addToPreparedStatement(preparedStmtList,criteria.getPositions()); + } + if(null != criteria.getAsOnDate()) { + builder.append( " and case when assignment.todate is null then assignment.fromdate <= ? else assignment.fromdate <= ? and assignment.todate > ? end"); + preparedStmtList.add(criteria.getAsOnDate()); + preparedStmtList.add(criteria.getAsOnDate()); + preparedStmtList.add(criteria.getAsOnDate()); + } + + + } + + + private String createQuery(List ids) { + StringBuilder builder = new StringBuilder(); + int length = ids.size(); + for (int i = 0; i < length; i++) { + builder.append(" ?"); + if (i != length - 1) + builder.append(","); + } + return builder.toString(); + } + + private void addToPreparedStatement(List preparedStmtList, List ids) { + ids.forEach(id -> { + preparedStmtList.add(id); + }); + } + + public String getUnassignedEmployeesSearchQuery(EmployeeSearchCriteria criteria, List preparedStmtList) { + StringBuilder builder = new StringBuilder(EmployeeQueries.HRMS_GET_UNASSIGNED_EMPLOYEES); + addWhereClauseAssignment(criteria, builder, preparedStmtList); + return builder.toString(); + } + + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeRepository.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeRepository.java new file mode 100644 index 00000000000..20bb37a813e --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeRepository.java @@ -0,0 +1,141 @@ +package org.egov.hrms.repository; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.common.contract.request.RequestInfo; +import org.egov.hrms.utils.HRMSUtils; +import org.egov.hrms.web.contract.EmployeeSearchCriteria; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +import lombok.extern.slf4j.Slf4j; + +import org.egov.hrms.model.Employee; +import org.springframework.util.CollectionUtils; + +@Repository +@Slf4j +public class EmployeeRepository { + + @Autowired + private EmployeeQueryBuilder queryBuilder; + + @Autowired + private JdbcTemplate jdbcTemplate; + + @Autowired + private EmployeeRowMapper rowMapper; + + @Autowired + private EmployeeCountRowMapper countRowMapper; + + @Autowired + private HRMSUtils hrmsUtils; + + /** + * DB Repository that makes jdbc calls to the db and fetches employees. + * + * @param criteria + * @param requestInfo + * @return + */ + public List fetchEmployees(EmployeeSearchCriteria criteria, RequestInfo requestInfo){ + List employees = new ArrayList<>(); + List preparedStmtList = new ArrayList<>(); + if(hrmsUtils.isAssignmentSearchReqd(criteria)) { + List empUuids = fetchEmployeesforAssignment(criteria, requestInfo); + if (CollectionUtils.isEmpty(empUuids)) + return employees; + else { + if(!CollectionUtils.isEmpty(criteria.getUuids())) + criteria.setUuids(criteria.getUuids().stream().filter(empUuids::contains).collect(Collectors.toList())); + else + criteria.setUuids(empUuids); + } + } + if (criteria.getIncludeUnassigned() != null && criteria.getIncludeUnassigned()) { + List empUuids = fetchUnassignedEmployees(criteria, requestInfo); + criteria.setUuids(empUuids); + } + String query = queryBuilder.getEmployeeSearchQuery(criteria, preparedStmtList); + try { + employees = jdbcTemplate.query(query, preparedStmtList.toArray(),rowMapper); + }catch(Exception e) { + log.error("Exception while making the db call: ",e); + log.error("query; "+query); + } + return employees; + } + + private List fetchUnassignedEmployees(EmployeeSearchCriteria criteria, RequestInfo requestInfo) { + List employeesIds = new ArrayList<>(); + List preparedStmtList = new ArrayList<>(); + String query = queryBuilder.getUnassignedEmployeesSearchQuery(criteria, preparedStmtList); + try { + employeesIds = jdbcTemplate.queryForList(query, preparedStmtList.toArray(),String.class); + }catch(Exception e) { + log.error("Exception while making the db call: ",e); + log.error("query; "+query); + } + return employeesIds; + } + + private List fetchEmployeesforAssignment(EmployeeSearchCriteria criteria, RequestInfo requestInfo) { + List employeesIds = new ArrayList<>(); + List preparedStmtList = new ArrayList<>(); + String query = queryBuilder.getAssignmentSearchQuery(criteria, preparedStmtList); + try { + + employeesIds = jdbcTemplate.queryForList(query, preparedStmtList.toArray(),String.class); + }catch(Exception e) { + log.error("Exception while making the db call: ",e); + log.error("query; "+query); + } + return employeesIds; + + } + + /** + * Fetches next value in the position seq table + * + * @return + */ + public Long fetchPosition(){ + String query = queryBuilder.getPositionSeqQuery(); + Long id = null; + try { + id = jdbcTemplate.queryForObject(query, Long.class); + }catch(Exception e) { + log.error("Exception while making the db call: ",e); + log.error("query; "+query); + } + return id; + } + + /** + * DB Repository that makes jdbc calls to the db and fetches employee count. + * + * @param tenantId + * @return + */ + public Map fetchEmployeeCount(String tenantId){ + Map response = new HashMap<>(); + List preparedStmtList = new ArrayList<>(); + + String query = queryBuilder.getEmployeeCountQuery(tenantId, preparedStmtList); + log.info("query; "+query); + try { + response=jdbcTemplate.query(query, preparedStmtList.toArray(),countRowMapper); + }catch(Exception e) { + log.error("Exception while making the db call: ",e); + log.error("query; "+query); + } + return response; + } + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeRowMapper.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeRowMapper.java new file mode 100644 index 00000000000..9d1ab4dd875 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/EmployeeRowMapper.java @@ -0,0 +1,338 @@ +package org.egov.hrms.repository; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.hrms.model.*; +import org.egov.hrms.model.enums.EmployeeDocumentReferenceType; +import org.egov.hrms.web.contract.User; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +@Component +@Slf4j +public class EmployeeRowMapper implements ResultSetExtractor> { + + @Autowired + private ObjectMapper mapper; + + @Override + /** + * Maps ResultSet to Employee POJO. + */ + public List extractData(ResultSet rs) throws SQLException, DataAccessException { + Map employeeMap = new HashMap<>(); + while(rs.next()) { + String currentid = rs.getString("employee_uuid"); + Employee currentEmployee = employeeMap.get(currentid); + if(null == currentEmployee) { + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("employee_createdby")).createdDate(rs.getLong("employee_createddate")) + .lastModifiedBy(rs.getString("employee_lastmodifiedby")).lastModifiedDate(rs.getLong("employee_lastmodifieddate")).build(); + currentEmployee = Employee.builder().id(rs.getLong("employee_id")).uuid(rs.getString("employee_uuid")).tenantId(rs.getString("employee_tenantid")) + .code(rs.getString("employee_code")).dateOfAppointment(null == rs.getObject("employee_doa")? null : rs.getLong("employee_doa")).IsActive(rs.getBoolean("employee_active")) + .employeeStatus(rs.getString("employee_status")).employeeType(rs.getString("employee_type")).auditDetails(auditDetails).reActivateEmployee(rs.getBoolean("employee_reactive")) + .jurisdictions(new ArrayList()).assignments(new ArrayList()).user(new User()) + .build(); + } + addChildrenToEmployee(rs, currentEmployee); + employeeMap.put(currentid, currentEmployee); + } + + return new ArrayList<>(employeeMap.values()); + + } + + /** + * Adds all the children data to a employee object. + * + * @param rs + * @param currentEmployee + */ + public void addChildrenToEmployee(ResultSet rs, Employee currentEmployee) { + setAssignments(rs, currentEmployee); + setJurisdictions(rs, currentEmployee); + setEducationDetails(rs, currentEmployee); + setDeptTests(rs, currentEmployee); + setServiceHistory(rs, currentEmployee); + setDocuments(rs, currentEmployee); + setDeactivationDetails(rs, currentEmployee); + setReactivationDetails(rs, currentEmployee); + } + + /** + * Maps Assignments inside a ResultSet to the Assignment POJO inside employee object. + * + * @param rs + * @param currentEmployee + */ + public void setAssignments(ResultSet rs, Employee currentEmployee) { + try { + List assignments = new ArrayList<>(); + if(CollectionUtils.isEmpty(currentEmployee.getAssignments())) + assignments = new ArrayList(); + else + assignments = currentEmployee.getAssignments(); + + List ids = assignments.stream().map(Assignment::getId).collect(Collectors.toList()); + if(!StringUtils.isEmpty(rs.getString("assignment_uuid")) && !ids.contains(rs.getString("assignment_uuid"))) { + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("assignment_createdby")).createdDate(rs.getLong("assignment_createddate")) + .lastModifiedBy(rs.getString("assignment_lastmodifiedby")).lastModifiedDate(rs.getLong("assignment_lastmodifieddate")).build(); + + Assignment assignment = Assignment.builder().id(rs.getString("assignment_uuid")).position(rs.getLong("assignment_position")).department(rs.getString("assignment_department")) + .designation(rs.getString("assignment_designation")).fromDate(rs.getLong("assignment_fromdate")).toDate(null == rs.getObject("assignment_todate")? null : rs.getLong("assignment_todate")) + .govtOrderNumber(rs.getString("assignment_govtordernumber")).reportingTo(rs.getString("assignment_reportingto")).isHOD(rs.getBoolean("assignment_ishod")) + .isCurrentAssignment(rs.getBoolean("assignment_iscurrentassignment")).tenantid(rs.getString("assignment_tenantid")).auditDetails(auditDetails).build(); + + assignments.add(assignment); + } + currentEmployee.setAssignments(assignments); + }catch(Exception e) { + log.error("Error in row mapper while mapping Assignments: ",e); + throw new CustomException("ROWMAPPER_ERROR","Error in row mapper while mapping Assignments"); + } + } + + /** + * Maps Jurisdictions inside a ResultSet to the Jurisdiction POJO inside employee object. + * + * @param rs + * @param currentEmployee + */ + public void setJurisdictions(ResultSet rs, Employee currentEmployee) { + try { + List jurisdictions = new ArrayList<>(); + if(CollectionUtils.isEmpty(currentEmployee.getJurisdictions())) + jurisdictions = new ArrayList(); + else + jurisdictions = currentEmployee.getJurisdictions(); + + List ids = jurisdictions.stream().map(Jurisdiction::getId).collect(Collectors.toList()); + Boolean isActive = rs.getBoolean("jurisdiction_isactive") !=false; + if(isActive && !StringUtils.isEmpty(rs.getString("jurisdiction_uuid")) && !ids.contains(rs.getString("jurisdiction_uuid"))) { + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("jurisdiction_createdby")).createdDate(rs.getLong("jurisdiction_createddate")) + .lastModifiedBy(rs.getString("jurisdiction_lastmodifiedby")).lastModifiedDate(rs.getLong("jurisdiction_lastmodifieddate")).build(); + + Jurisdiction jurisdiction = Jurisdiction.builder().id(rs.getString("jurisdiction_uuid")).hierarchy(rs.getString("jurisdiction_hierarchy")) + .boundary(rs.getString("jurisdiction_boundary")).boundaryType(rs.getString("jurisdiction_boundarytype")) + .tenantId(rs.getString("jurisdiction_tenantid")) + .isActive(null == rs.getObject("jurisdiction_isactive")?true:rs.getBoolean("jurisdiction_isactive")) + .auditDetails(auditDetails).build(); + + jurisdictions.add(jurisdiction); + } + currentEmployee.setJurisdictions(jurisdictions); + }catch(Exception e) { + log.error("Error in row mapper while mapping Jurisdictions: ",e); + throw new CustomException("ROWMAPPER_ERROR","Error in row mapper while mapping Jurisdictions"); + } + } + + /** + * Maps EducationDetails inside a ResultSet to the EducationDetails POJO inside employee object. + * + * @param rs + * @param currentEmployee + */ + public void setEducationDetails(ResultSet rs, Employee currentEmployee) { + try { + List educationDetails = new ArrayList<>(); + if(CollectionUtils.isEmpty(currentEmployee.getEducation())) + educationDetails = new ArrayList(); + else + educationDetails = currentEmployee.getEducation(); + List ids = educationDetails.stream().map(EducationalQualification::getId).collect(Collectors.toList()); + Boolean isActive =rs.getBoolean("education_isactive") !=false; + if( isActive &&!StringUtils.isEmpty( rs.getString("education_uuid")) && !ids.contains(rs.getString("education_uuid"))) { + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("education_createdby")).createdDate(rs.getLong("education_createddate")) + .lastModifiedBy(rs.getString("education_lastmodifiedby")).lastModifiedDate(rs.getLong("education_lastmodifieddate")).build(); + EducationalQualification education = EducationalQualification.builder().id(rs.getString("education_uuid")).qualification(rs.getString("education_qualification")).stream(rs.getString("education_stream")) + .yearOfPassing(rs.getLong("education_yearofpassing")).university(rs.getString("education_university")).remarks(rs.getString("education_remarks")) + .tenantId(rs.getString("education_tenantid")) + .isActive(null == rs.getObject("education_isactive")?true:rs.getBoolean("education_isactive")) + .auditDetails(auditDetails).build(); + + educationDetails.add(education); + } + currentEmployee.setEducation(educationDetails); + }catch(Exception e) { + log.error("Error in row mapper while mapping Educational Details: ",e); + throw new CustomException("ROWMAPPER_ERROR","Error in row mapper while mapping Educational Details"); + } + } + + /** + * Maps Dept Tests inside a ResultSet to the DeptTest POJO inside employee object. + * + * @param rs + * @param currentEmployee + */ + public void setDeptTests(ResultSet rs, Employee currentEmployee) { + try { + List tests = new ArrayList<>(); + if(CollectionUtils.isEmpty(currentEmployee.getTests())) + tests = new ArrayList(); + else + tests = currentEmployee.getTests(); + + List ids = tests.stream().map(DepartmentalTest::getId).collect(Collectors.toList()); + Boolean isActive = rs.getBoolean("depttest_isactive") !=false; + if(isActive && !StringUtils.isEmpty(rs.getString("depttest_uuid")) && !ids.contains(rs.getString("depttest_uuid"))) { + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("depttest_createdby")).createdDate(rs.getLong("depttest_createddate")) + .lastModifiedBy(rs.getString("depttest_lastmodifiedby")).lastModifiedDate(rs.getLong("depttest_lastmodifieddate")).build(); + + DepartmentalTest test = DepartmentalTest.builder().id(rs.getString("depttest_uuid")).test(rs.getString("depttest_test")).yearOfPassing(rs.getLong("depttest_yearofpassing")) + .remarks(rs.getString("depttest_remarks")).tenantId(rs.getString("depttest_tenantid")) + .isActive(null == rs.getObject("depttest_isactive")?true:rs.getBoolean("depttest_isactive")) + .auditDetails(auditDetails).build(); + + tests.add(test); + } + currentEmployee.setTests(tests); + }catch(Exception e) { + log.error("Error in row mapper while mapping Departmental Tests: ",e); + throw new CustomException("ROWMAPPER_ERROR","Error in row mapper while mapping Departmental Tests"); + } + } + + /** + * Maps ServiceHistory inside a ResultSet to the ServiceHistory POJO inside employee object. + * + * @param rs + * @param currentEmployee + */ + public void setServiceHistory(ResultSet rs, Employee currentEmployee) { + try { + List history = new ArrayList<>(); + if(CollectionUtils.isEmpty(currentEmployee.getServiceHistory())) + history = new ArrayList(); + else + history = currentEmployee.getServiceHistory(); + + List ids = history.stream().map(ServiceHistory::getId).collect(Collectors.toList()); + if(!StringUtils.isEmpty(rs.getString("history_uuid")) && !ids.contains(rs.getString("history_uuid"))) { + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("history_createdby")).createdDate(rs.getLong("history_createddate")) + .lastModifiedBy(rs.getString("history_lastmodifiedby")).lastModifiedDate(rs.getLong("history_lastmodifieddate")).build(); + + ServiceHistory service = ServiceHistory.builder().id(rs.getString("history_uuid")).serviceStatus(rs.getString("history_servicestatus")).serviceFrom(rs.getLong("history_servicefrom")) + .serviceTo(null == rs.getObject("history_serviceto")? null :rs.getLong("history_serviceto")).orderNo(rs.getString("history_ordernumber")).isCurrentPosition(rs.getBoolean("history_iscurrentposition")) + .location(rs.getString("history_location")).tenantId(rs.getString("history_tenantid")).auditDetails(auditDetails).build(); + + history.add(service); + } + currentEmployee.setServiceHistory(history); + }catch(Exception e) { + log.error("Error in row mapper while mapping Service History: ",e); + throw new CustomException("ROWMAPPER_ERROR","Error in row mapper while mapping Service History"); + } + + } + + /** + * Maps Documents inside a ResultSet to the Document POJO inside employee object. + * + * @param rs + * @param currentEmployee + */ + public void setDocuments(ResultSet rs, Employee currentEmployee) { + try { + List documents = new ArrayList<>(); + if(CollectionUtils.isEmpty(currentEmployee.getDocuments())) + documents = new ArrayList(); + else + documents = currentEmployee.getDocuments(); + + List ids = documents.stream().map(EmployeeDocument::getId).collect(Collectors.toList()); + if(!StringUtils.isEmpty(rs.getString("docs_uuid")) && !ids.contains(rs.getString("docs_uuid")) ) { + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("docs_createdby")).createdDate(rs.getLong("docs_createddate")) + .lastModifiedBy(rs.getString("docs_lastmodifiedby")).lastModifiedDate(rs.getLong("docs_lastmodifieddate")).build(); + EmployeeDocument document = EmployeeDocument.builder().id(rs.getString("docs_uuid")).documentId(rs.getString("docs_documentid")) + .documentName(rs.getString("docs_documentname")).referenceType(rs.getString("docs_referencetype") != null ? EmployeeDocumentReferenceType.valueOf(rs.getString("docs_referencetype")): null) + .referenceId(rs.getString("docs_referenceid")).tenantId(rs.getString("docs_tenantid")).auditDetails(auditDetails).build(); + + documents.add(document); + } + currentEmployee.setDocuments(documents); + }catch(Exception e) { + log.error("Error in row mapper while mapping document: ",e); + throw new CustomException("ROWMAPPER_ERROR","Error in row mapper while mapping document"); + + } + } + + /** + * Maps DeactivationDetails inside a ResultSet to the DeactivationDetail POJO inside employee object. + * + * @param rs + * @param currentEmployee + */ + public void setDeactivationDetails(ResultSet rs, Employee currentEmployee) { + try { + List deactDetails = new ArrayList<>(); + if(CollectionUtils.isEmpty(currentEmployee.getDeactivationDetails())) + deactDetails = new ArrayList(); + else + deactDetails = currentEmployee.getDeactivationDetails(); + + List ids = deactDetails.stream().map(DeactivationDetails::getId).collect(Collectors.toList()); + if(!StringUtils.isEmpty(rs.getString("deact_uuid")) && !ids.contains(rs.getString("deact_uuid")) ) { + if(rs.getString("deact_uuid")!=null){ + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("deact_createdby")).createdDate(rs.getLong("deact_createddate")) + .lastModifiedBy(rs.getString("deact_lastmodifiedby")).lastModifiedDate(rs.getLong("deact_lastmodifieddate")).build(); + + DeactivationDetails deactDetail = DeactivationDetails.builder().id(rs.getString("deact_uuid")).reasonForDeactivation(rs.getString("deact_reasonfordeactivation")) + .effectiveFrom(rs.getLong("deact_effectivefrom")).orderNo(rs.getString("deact_ordernumber")).remarks(rs.getString("deact_remarks")!= null ? (rs.getString("deact_remarks")) : null) + .tenantId(rs.getString("deact_tenantid")).auditDetails(auditDetails).build(); + + deactDetails.add(deactDetail); + } + } + currentEmployee.setDeactivationDetails(deactDetails); + + }catch(Exception e) { + log.error("Error in row mapper while mapping deactivation details: ",e); + throw new CustomException("ROWMAPPER_ERROR","Error in row mapper while mapping deactivation details"); + } + } + + public void setReactivationDetails(ResultSet rs, Employee currentEmployee){ + try { + List reactDetails = new ArrayList<>(); + if(CollectionUtils.isEmpty(currentEmployee.getReactivationDetails())) + reactDetails = new ArrayList(); + else + reactDetails = currentEmployee.getReactivationDetails(); + + List ids = reactDetails.stream().map(ReactivationDetails::getId).collect(Collectors.toList()); + if(!StringUtils.isEmpty(rs.getString("react_uuid")) && !ids.contains(rs.getString("react_uuid")) ) { + if(rs.getString("react_uuid")!=null){ + AuditDetails auditDetails = AuditDetails.builder().createdBy(rs.getString("react_createdby")).createdDate(rs.getLong("react_createddate")) + .lastModifiedBy(rs.getString("react_lastmodifiedby")).lastModifiedDate(rs.getLong("react_lastmodifieddate")).build(); + + ReactivationDetails reactDetail = ReactivationDetails.builder().id(rs.getString("react_uuid")).reasonForReactivation(rs.getString("react_reasonforreactivation")) + .effectiveFrom(rs.getLong("react_effectivefrom")).orderNo(rs.getString("react_ordernumber")).remarks(rs.getString("react_remarks")!= null ? (rs.getString("react_remarks")) : null) + .tenantId(rs.getString("react_tenantid")).auditDetails(auditDetails).build(); + + reactDetails.add(reactDetail); + } + } + currentEmployee.setReactivationDetails(reactDetails); + + }catch(Exception e) { + log.error("Error in row mapper while mapping reactivation details ",e); + throw new CustomException("ROWMAPPER_ERROR","Error in row mapper while mapping reactivation details"); + } + } + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/RestCallRepository.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/RestCallRepository.java new file mode 100644 index 00000000000..596538863e5 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/repository/RestCallRepository.java @@ -0,0 +1,67 @@ +package org.egov.hrms.repository; + +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.egov.tracer.model.CustomException; +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 com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; + +import lombok.extern.slf4j.Slf4j; + +@Repository +@Slf4j +public class RestCallRepository { + + @Autowired + private RestTemplate restTemplate; + + @Autowired + private ObjectMapper objectMapper; + + /** + * Fetches results from the given API and request and handles errors. + * + * @param requestInfo + * @param serviceReqSearchCriteria + * @return Object + * @author vishal + */ + public Object fetchResult(StringBuilder uri, Object request) { + Object response = null; + try { + response = restTemplate.postForObject(uri.toString(), request, Map.class); + } catch (HttpClientErrorException e) { + log.error("External Service threw an Exception: ", e); + if (!StringUtils.isEmpty(e.getResponseBodyAsString())) { + throw new ServiceCallException(e.getResponseBodyAsString()); + } + } catch (Exception e) { + log.error("Exception while fetching from searcher: ", e); + log.info("req: " + (request)); + } + + return response; + + } + + public T fetchResult(StringBuilder uri, Object request, Class + clazz) { + objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + T response; + try { + response = restTemplate.postForObject(uri.toString(), request, clazz); + } catch (HttpClientErrorException e) { + throw new CustomException("HTTP_CLIENT_ERROR", + String.format("%s - %s", e.getMessage(), e.getResponseBodyAsString())); + } + return response; + } + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/DefaultUserService.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/DefaultUserService.java new file mode 100644 index 00000000000..0b232ae6448 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/DefaultUserService.java @@ -0,0 +1,281 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Getter; +import lombok.Setter; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.request.Role; +import org.egov.common.contract.request.User; +import org.egov.common.utils.MultiStateInstanceUtil; +import org.egov.hrms.config.PropertiesManager; +import org.egov.hrms.repository.RestCallRepository; +import org.egov.hrms.utils.HRMSConstants; +import org.egov.hrms.web.contract.UserRequest; +import org.egov.hrms.web.contract.UserResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; + +import javax.annotation.PostConstruct; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.*; + +import static org.egov.hrms.utils.HRMSConstants.*; + +@Slf4j +@Setter +@Getter +public class DefaultUserService implements UserService { + + @Autowired + private PropertiesManager propertiesManager; + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private RestCallRepository restCallRepository; + + @Autowired + private MultiStateInstanceUtil centralInstanceUtil; + + @Value("${egov.user.create.endpoint}") + private String userCreateEndpoint; + + @Value("${egov.user.search.endpoint}") + private String userSearchEndpoint; + + @Value("${egov.user.update.endpoint}") + private String userUpdateEndpoint; + + private String internalMicroserviceRoleUuid = null; + + @PostConstruct + void initalizeSystemuser(){ + log.info("initialising system user"); + RequestInfo requestInfo = new RequestInfo(); + StringBuilder uri = new StringBuilder(); + uri.append(propertiesManager.getUserHost()).append(propertiesManager.getUserSearchEndpoint()); // URL for user search call + Map userSearchRequest = new HashMap<>(); + userSearchRequest.put("RequestInfo", requestInfo); + userSearchRequest.put("tenantId", propertiesManager.getStateLevelTenantId()); + userSearchRequest.put("roleCodes", Collections.singletonList(INTERNALMICROSERVICEROLE_CODE)); + try { + LinkedHashMap responseMap = (LinkedHashMap) restCallRepository.fetchResult(uri, userSearchRequest); + List> users = (List>) responseMap.get("user"); + if(users.size()==0) + createInternalMicroserviceUser(requestInfo); + internalMicroserviceRoleUuid = (String) users.get(0).get("uuid"); + }catch (Exception e) { + throw new CustomException("EG_USER_SEARCH_ERROR", "Service returned null while fetching user"); + } + + } + + private void createInternalMicroserviceUser(RequestInfo requestInfo){ + Map userCreateRequest = new HashMap<>(); + //Creating role with INTERNAL_MICROSERVICE_ROLE + Role role = Role.builder() + .name(INTERNALMICROSERVICEROLE_NAME).code(INTERNALMICROSERVICEROLE_CODE) + .tenantId(propertiesManager.getStateLevelTenantId()).build(); + User user = User.builder().userName(INTERNALMICROSERVICEUSER_USERNAME) + .name(INTERNALMICROSERVICEUSER_NAME).mobileNumber(INTERNALMICROSERVICEUSER_MOBILENO) + .type(INTERNALMICROSERVICEUSER_TYPE).tenantId(propertiesManager.getStateLevelTenantId()) + .roles(Collections.singletonList(role)).id(0L).build(); + + userCreateRequest.put("RequestInfo", requestInfo); + userCreateRequest.put("user", user); + + StringBuilder uri = new StringBuilder(); + uri.append(propertiesManager.getUserHost()).append(propertiesManager.getUserCreateEndpoint()); // URL for user create call + + try { + LinkedHashMap responseMap = (LinkedHashMap) restCallRepository.fetchResult(uri, userCreateRequest); + List> users = (List>) responseMap.get("user"); + internalMicroserviceRoleUuid = (String) users.get(0).get("uuid"); + }catch (Exception e) { + throw new CustomException("EG_USER_CRETE_ERROR", "Service returned throws error while creating user"); + } + } + + @Override + public UserResponse createUser(UserRequest userRequest) { + StringBuilder uri = new StringBuilder(); + uri.append(propertiesManager.getUserHost()).append(propertiesManager.getUserCreateEndpoint()); + UserResponse userResponse = null; + try { + userResponse = userCall(userRequest,uri); + }catch(Exception e) { + log.error("User created failed: ",e); + } + + return userResponse; + } + + @Override + public UserResponse updateUser(UserRequest userRequest) { + StringBuilder uri = new StringBuilder(); + uri.append(propertiesManager.getUserHost()).append(propertiesManager.getUserUpdateEndpoint()); + UserResponse userResponse = null; + try { + userResponse = userCall(userRequest,uri); + }catch(Exception e) { + log.error("User created failed: ",e); + } + + return userResponse; + } + + @Override + public UserResponse getUser(RequestInfo requestInfo, Map userSearchCriteria) { + StringBuilder uri = new StringBuilder(); + Map userSearchReq = new HashMap<>(); + User userInfoCopy = requestInfo.getUserInfo(); + + if(propertiesManager.getIsDecryptionEnable()){ + User enrichedUserInfo = getEncrichedandCopiedUserInfo(String.valueOf(userSearchCriteria.get("tenantId"))); + requestInfo.setUserInfo(enrichedUserInfo); + } + + userSearchReq.put("RequestInfo", requestInfo); + userSearchReq.put(HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE_CODE,HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE); + for( String key: userSearchCriteria.keySet()) + userSearchReq.put(key, userSearchCriteria.get(key)); + uri.append(propertiesManager.getUserHost()).append(propertiesManager.getUserSearchEndpoint()); + UserResponse userResponse = new UserResponse(); + try { + userResponse = userCall(userSearchReq,uri); + }catch(Exception e) { + log.error("User search failed: ",e); + } + if(propertiesManager.getIsDecryptionEnable()) + requestInfo.setUserInfo(userInfoCopy); + + return userResponse; + } + + private User getEncrichedandCopiedUserInfo(String tenantId){ + //Creating role with INTERNAL_MICROSERVICE_ROLE + Role role = Role.builder() + .name(INTERNALMICROSERVICEROLE_NAME).code(INTERNALMICROSERVICEROLE_CODE) + .tenantId(centralInstanceUtil.getStateLevelTenant(tenantId)).build(); + + //Creating userinfo with uuid and role of internal micro service role + User userInfo = User.builder() + .uuid(internalMicroserviceRoleUuid) + .type(INTERNALMICROSERVICEUSER_TYPE) + .roles(Collections.singletonList(role)).id(0L).build(); + + return userInfo; + } + + + /** + * Returns UserDetailResponse by calling user service with given uri and object + * @param userRequest Request object for user service + * @param uri The address of the endpoint + * @return Response from user service as parsed as userDetailResponse + */ + @SuppressWarnings("all") + private UserResponse userCall(Object userRequest, StringBuilder uri) { + String dobFormat = null; + if(uri.toString().contains(userSearchEndpoint) || uri.toString().contains(userUpdateEndpoint)) + dobFormat="yyyy-MM-dd"; + else if(uri.toString().contains(userCreateEndpoint)) + dobFormat = "dd/MM/yyyy"; + try{ + LinkedHashMap responseMap = (LinkedHashMap) restCallRepository.fetchResult(uri, userRequest); + parseResponse(responseMap,dobFormat); + UserResponse userDetailResponse = objectMapper.convertValue(responseMap,UserResponse.class); + return userDetailResponse; + } + catch(IllegalArgumentException e) { + throw new CustomException("IllegalArgumentException","ObjectMapper not able to convertValue in userCall"); + } + } + + + /** + * Parses date formats to long for all users in responseMap + * @param responeMap LinkedHashMap got from user api response + * @param dobFormat dob format (required because dob is returned in different format's in search and create response in user service) + */ + @SuppressWarnings("all") + private void parseResponse(LinkedHashMap responeMap,String dobFormat){ + List users = (List)responeMap.get("user"); + String format1 = "dd-MM-yyyy HH:mm:ss"; + if(users!=null){ + users.forEach( map -> { + map.put("createdDate",dateTolong((String)map.get("createdDate"),format1)); + if((String)map.get("lastModifiedDate")!=null) + map.put("lastModifiedDate",dateTolong((String)map.get("lastModifiedDate"),format1)); + if((String)map.get("dob")!=null) + map.put("dob",dateTolong((String)map.get("dob"),dobFormat)); + if((String)map.get("pwdExpiryDate")!=null) + map.put("pwdExpiryDate",dateTolong((String)map.get("pwdExpiryDate"),format1)); + } + ); + } + } + + /** + * Converts date to long + * @param date date to be parsed + * @param format Format of the date + * @return Long value of date + */ + private Long dateTolong(String date,String format){ + SimpleDateFormat f = new SimpleDateFormat(format); + Date d = null; + try { + d = f.parse(date); + } catch (ParseException e) { + e.printStackTrace(); + } + return d.getTime(); + } + + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/EmployeeService.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/EmployeeService.java new file mode 100644 index 00000000000..ec86d2452ce --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/EmployeeService.java @@ -0,0 +1,577 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.hrms.config.PropertiesManager; +import org.egov.hrms.model.AuditDetails; +import org.egov.hrms.model.Employee; +import org.egov.hrms.model.enums.UserType; +import org.egov.hrms.producer.HRMSProducer; +import org.egov.hrms.repository.EmployeeRepository; +import org.egov.hrms.utils.ErrorConstants; +import org.egov.hrms.utils.HRMSConstants; +import org.egov.hrms.utils.HRMSUtils; +import org.egov.hrms.utils.ResponseInfoFactory; +import org.egov.hrms.web.contract.*; +import org.egov.tracer.kafka.LogAwareKafkaTemplate; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import java.util.*; +import java.util.function.Function; +import java.util.stream.Collectors; + +@Data +@Slf4j +@Service +public class EmployeeService { + + + @Autowired + private UserService userService; + + @Autowired + private IdGenService idGenService; + + @Autowired + private ResponseInfoFactory factory; + + @Autowired + private LogAwareKafkaTemplate kafkaTemplate; + + @Autowired + private PropertiesManager propertiesManager; + + @Autowired + private HRMSProducer hrmsProducer; + + @Autowired + private EmployeeRepository repository; + + @Autowired + private HRMSUtils hrmsUtils; + + @Autowired + private NotificationService notificationService; + + @Autowired + private ObjectMapper objectMapper; + + /** + * Service method for create employee. Does following: + * 1. Sets ids to all the objects using idgen service. + * 2. Enriches the employee object with required parameters + * 3. Creates user in the egov-user service. + * 4. Sends notification upon successful creation + * + * @param employeeRequest + * @return + */ + public EmployeeResponse create(EmployeeRequest employeeRequest) { + RequestInfo requestInfo = employeeRequest.getRequestInfo(); + Map pwdMap = new HashMap<>(); + idGenService.setIds(employeeRequest); + employeeRequest.getEmployees().stream().forEach(employee -> { + enrichCreateRequest(employee, requestInfo); + createUser(employee, requestInfo); + pwdMap.put(employee.getUuid(), employee.getUser().getPassword()); + employee.getUser().setPassword(null); + }); + hrmsProducer.push(propertiesManager.getSaveEmployeeTopic(), employeeRequest); + notificationService.sendNotification(employeeRequest, pwdMap); + return generateResponse(employeeRequest); + } + + /** + * Searches employees on a given criteria. + * + * @param criteria + * @param requestInfo + * @return + */ + public EmployeeResponse search(EmployeeSearchCriteria criteria, RequestInfo requestInfo) { + boolean userChecked = false; + /*if(null == criteria.getIsActive() || criteria.getIsActive()) + criteria.setIsActive(true); + else + criteria.setIsActive(false);*/ + Map mapOfUsers = new HashMap(); + if(!StringUtils.isEmpty(criteria.getPhone()) + || !CollectionUtils.isEmpty(criteria.getRoles()) + || !CollectionUtils.isEmpty(criteria.getCodes())) { + Map userSearchCriteria = new HashMap<>(); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID,criteria.getTenantId()); + if(!StringUtils.isEmpty(criteria.getPhone())) + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_MOBILENO,criteria.getPhone()); + if( !CollectionUtils.isEmpty(criteria.getRoles()) ) + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_ROLECODES,criteria.getRoles()); + if (!CollectionUtils.isEmpty(criteria.getCodes())) { + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_USERNAME, criteria.getCodes().get(0)); + } + UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); + userChecked =true; + if(!CollectionUtils.isEmpty(userResponse.getUser())) { + mapOfUsers.putAll(userResponse.getUser().stream() + .collect(Collectors.toMap(User::getUuid, Function.identity()))); + } + List userUUIDs = userResponse.getUser().stream().map(User :: getUuid).collect(Collectors.toList()); + if(!CollectionUtils.isEmpty(criteria.getUuids())) + criteria.setUuids(criteria.getUuids().stream().filter(userUUIDs::contains).collect(Collectors.toList())); + else + criteria.setUuids(userUUIDs); + } + //checks if above criteria met and result is not null will check for name search if list of names are given as user search on name is not bulk api + + if(!((!CollectionUtils.isEmpty(criteria.getRoles()) || !StringUtils.isEmpty(criteria.getPhone())) && CollectionUtils.isEmpty(criteria.getUuids()))){ + if(!CollectionUtils.isEmpty(criteria.getNames())) { + List userUUIDs = new ArrayList<>(); + for(String name: criteria.getNames()) { + Map userSearchCriteria = new HashMap<>(); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID,criteria.getTenantId()); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_NAME,name); + UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); + userChecked =true; + if(!CollectionUtils.isEmpty(userResponse.getUser())) { + mapOfUsers.putAll(userResponse.getUser().stream() + .collect(Collectors.toMap(User::getUuid, Function.identity()))); + } + List uuids = userResponse.getUser().stream().map(User :: getUuid).collect(Collectors.toList()); + userUUIDs.addAll(uuids); + } + if(!CollectionUtils.isEmpty(criteria.getUuids())) + criteria.setUuids(criteria.getUuids().stream().filter(userUUIDs::contains).collect(Collectors.toList())); + else + criteria.setUuids(userUUIDs); + } + } + if(userChecked) + criteria.setTenantId(null); + List employees = new ArrayList<>(); + if(!((!CollectionUtils.isEmpty(criteria.getRoles()) || !CollectionUtils.isEmpty(criteria.getNames()) || !StringUtils.isEmpty(criteria.getPhone())) && CollectionUtils.isEmpty(criteria.getUuids()))) + employees = repository.fetchEmployees(criteria, requestInfo); + List uuids = employees.stream().map(Employee :: getUuid).collect(Collectors.toList()); + if(!CollectionUtils.isEmpty(uuids)){ + Map userSearchCriteria = new HashMap<>(); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_UUID,uuids); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID, criteria.getTenantId()); + log.info("uuid is available {}", userSearchCriteria); + if(mapOfUsers.isEmpty()){ + log.info("searching in user service"); + UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); + if(!CollectionUtils.isEmpty(userResponse.getUser())) { + mapOfUsers = userResponse.getUser().stream() + .collect(Collectors.toMap(User :: getUuid, Function.identity())); + } + } + for(Employee employee: employees){ + employee.setUser(mapOfUsers.get(employee.getUuid())); + } + } + return EmployeeResponse.builder().responseInfo(factory.createResponseInfoFromRequestInfo(requestInfo, true)) + .employees(employees).build(); + } + + + /** + * Creates user by making call to egov-user. + * + * @param employee + * @param requestInfo + */ + private void createUser(Employee employee, RequestInfo requestInfo) { + enrichUser(employee); + UserRequest request = UserRequest.builder().requestInfo(requestInfo).user(employee.getUser()).build(); + try { + UserResponse response = userService.createUser(request); + User user = response.getUser().get(0); + employee.setId(UUID.fromString(user.getUuid()).getMostSignificantBits()); + employee.setUuid(user.getUuid()); + employee.getUser().setId(user.getId()); + employee.getUser().setUuid(user.getUuid()); + employee.getUser().setUserServiceUuid(user.getUserServiceUuid()); + }catch(Exception e) { + log.error("Exception while creating user: ",e); + log.error("request: "+request); + throw new CustomException(ErrorConstants.HRMS_USER_CREATION_FAILED_CODE, ErrorConstants.HRMS_USER_CREATION_FAILED_MSG); + } + + } + + /** + * Enriches the user object. + * + * @param employee + */ + private void enrichUser(Employee employee) { + List pwdParams = new ArrayList<>(); + pwdParams.add(employee.getCode()); + pwdParams.add(employee.getUser().getMobileNumber()); + pwdParams.add(employee.getTenantId()); + pwdParams.add(employee.getUser().getName().toUpperCase()); + if (propertiesManager.isAutoGeneratePassword()) { + employee.getUser().setPassword(hrmsUtils.generatePassword(pwdParams)); + } + employee.getUser().setUserName(employee.getCode()); + employee.getUser().setActive(true); + employee.getUser().setType(UserType.EMPLOYEE.toString()); + } + + /** + * Enriches employee object by setting parent ids to all the child objects + * + * @param employee + * @param requestInfo + */ + private void enrichCreateRequest(Employee employee, RequestInfo requestInfo) { + + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(requestInfo.getUserInfo().getUuid()) + .createdDate(new Date().getTime()) + .build(); + + employee.getJurisdictions().stream().forEach(jurisdiction -> { + jurisdiction.setId(UUID.randomUUID().toString()); + jurisdiction.setAuditDetails(auditDetails); + if(null == jurisdiction.getIsActive()) + jurisdiction.setIsActive(true); + }); + if (employee.getAssignments() != null && !employee.getAssignments().isEmpty()) { + employee.getAssignments().stream().forEach(assignment -> { + assignment.setId(UUID.randomUUID().toString()); + assignment.setAuditDetails(auditDetails); + assignment.setPosition(getPosition()); + }); + } + if(!CollectionUtils.isEmpty(employee.getServiceHistory())) { + employee.getServiceHistory().stream().forEach(serviceHistory -> { + serviceHistory.setId(UUID.randomUUID().toString()); + serviceHistory.setAuditDetails(auditDetails); + if(null == serviceHistory.getIsCurrentPosition()) + serviceHistory.setIsCurrentPosition(false); + }); + } + if(!CollectionUtils.isEmpty(employee.getEducation())) { + employee.getEducation().stream().forEach(educationalQualification -> { + educationalQualification.setId(UUID.randomUUID().toString()); + educationalQualification.setAuditDetails(auditDetails); + if(null == educationalQualification.getIsActive()) + educationalQualification.setIsActive(true); + }); + } + if(!CollectionUtils.isEmpty(employee.getTests())) { + employee.getTests().stream().forEach(departmentalTest -> { + departmentalTest.setId(UUID.randomUUID().toString()); + departmentalTest.setAuditDetails(auditDetails); + if(null == departmentalTest.getIsActive()) + departmentalTest.setIsActive(true); + }); + } + if(!CollectionUtils.isEmpty(employee.getDocuments())) { + employee.getDocuments().stream().forEach(document -> { + document.setId(UUID.randomUUID().toString()); + document.setAuditDetails(auditDetails); + }); + } + employee.setAuditDetails(auditDetails); + employee.setIsActive(true); + } + + /** + * Fetches next value from the position sequence table + * @return + */ + public Long getPosition() { + return repository.fetchPosition(); + } + + /** + * Service method to update user. Performs the following: + * 1. Enriches the employee object with required parameters. + * 2. Updates user by making call to the user service. + * + * @param employeeRequest + * @return + */ + public EmployeeResponse update(EmployeeRequest employeeRequest) { + RequestInfo requestInfo = employeeRequest.getRequestInfo(); + List uuidList= new ArrayList<>(); + for(Employee employee: employeeRequest.getEmployees()) { + uuidList.add(employee.getUuid()); + } + EmployeeResponse existingEmployeeResponse = search(EmployeeSearchCriteria.builder().uuids(uuidList).build(),requestInfo); + List existingEmployees = existingEmployeeResponse.getEmployees(); + employeeRequest.getEmployees().stream().forEach(employee -> { + enrichUpdateRequest(employee, requestInfo, existingEmployees); + updateUser(employee, requestInfo); + }); + hrmsProducer.push(propertiesManager.getUpdateTopic(), employeeRequest); + //notificationService.sendReactivationNotification(employeeRequest); + return generateResponse(employeeRequest); + } + + /** + * Updates the user by making call to the user service. + * + * @param employee + * @param requestInfo + */ + private void updateUser(Employee employee, RequestInfo requestInfo) { + UserRequest request = UserRequest.builder().requestInfo(requestInfo).user(employee.getUser()).build(); + try { + userService.updateUser(request); + }catch(Exception e) { + log.error("Exception while updating user: ",e); + log.error("request: "+request); + throw new CustomException(ErrorConstants.HRMS_USER_UPDATION_FAILED_CODE, ErrorConstants.HRMS_USER_UPDATION_FAILED_MSG); + } + + } + + /** + * Enriches update request with required parameters. + * + * @param employee + * @param requestInfo + * @param existingEmployeesData + */ + private void enrichUpdateRequest(Employee employee, RequestInfo requestInfo, List existingEmployeesData) { + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(requestInfo.getUserInfo().getUserName()) + .createdDate(new Date().getTime()) + .build(); + Employee existingEmpData = existingEmployeesData.stream().filter(existingEmployee -> existingEmployee.getUuid().equals(employee.getUuid())).findFirst().get(); + + employee.getUser().setUserName(employee.getCode()); + if(!employee.getIsActive()) + employee.getUser().setActive(false); + else + employee.getUser().setActive(true); + + employee.getJurisdictions().stream().forEach(jurisdiction -> { + + if(null == jurisdiction.getIsActive()) + jurisdiction.setIsActive(true); + if(jurisdiction.getId()==null) { + jurisdiction.setId(UUID.randomUUID().toString()); + jurisdiction.setAuditDetails(auditDetails); + }else{ + if(!existingEmpData.getJurisdictions().stream() + .filter(jurisdictionData ->jurisdictionData.getId().equals(jurisdiction.getId() )) + .findFirst().orElse(null) + .equals(jurisdiction)){ + jurisdiction.getAuditDetails().setLastModifiedBy(requestInfo.getUserInfo().getUserName()); + jurisdiction.getAuditDetails().setLastModifiedDate(new Date().getTime()); + } + } + }); + employee.getAssignments().stream().forEach(assignment -> { + if(assignment.getId()==null) { + assignment.setId(UUID.randomUUID().toString()); + assignment.setAuditDetails(auditDetails); + }else { + if(!existingEmpData.getAssignments().stream() + .filter(assignmentData -> assignmentData.getId().equals(assignment.getId())) + .findFirst().orElse(null) + .equals(assignment)){ + assignment.getAuditDetails().setLastModifiedBy(requestInfo.getUserInfo().getUserName()); + assignment.getAuditDetails().setLastModifiedDate(new Date().getTime()); + } + } + }); + + if(employee.getServiceHistory()!=null){ + employee.getServiceHistory().stream().forEach(serviceHistory -> { + if(null == serviceHistory.getIsCurrentPosition()) + serviceHistory.setIsCurrentPosition(false); + if(serviceHistory.getId()==null) { + serviceHistory.setId(UUID.randomUUID().toString()); + serviceHistory.setAuditDetails(auditDetails); + }else { + if(!existingEmpData.getServiceHistory().stream() + .filter(serviceHistoryData -> serviceHistoryData.getId().equals(serviceHistory.getId())) + .findFirst().orElse(null) + .equals(serviceHistory)){ + serviceHistory.getAuditDetails().setLastModifiedBy(requestInfo.getUserInfo().getUserName()); + serviceHistory.getAuditDetails().setLastModifiedDate(new Date().getTime()); + } + } + }); + + } + + if(employee.getEducation() != null){ + employee.getEducation().stream().forEach(educationalQualification -> { + if(null == educationalQualification.getIsActive()) + educationalQualification.setIsActive(true); + if(educationalQualification.getId()==null) { + educationalQualification.setId(UUID.randomUUID().toString()); + educationalQualification.setAuditDetails(auditDetails); + }else { + + if(!existingEmpData.getEducation().stream() + .filter(educationalQualificationData -> educationalQualificationData.getId().equals(educationalQualification.getId())) + .findFirst().orElse(null) + .equals(educationalQualification)){ + educationalQualification.getAuditDetails().setLastModifiedBy(requestInfo.getUserInfo().getUserName()); + educationalQualification.getAuditDetails().setLastModifiedDate(new Date().getTime()); + } + } + }); + + } + + if(employee.getTests() != null){ + employee.getTests().stream().forEach(departmentalTest -> { + + if(null == departmentalTest.getIsActive()) + departmentalTest.setIsActive(true); + if(departmentalTest.getId()==null) { + departmentalTest.setId(UUID.randomUUID().toString()); + departmentalTest.setAuditDetails(auditDetails); + }else { + if(!existingEmpData.getTests().stream() + .filter(departmentalTestData -> departmentalTestData.getId().equals(departmentalTest.getId())) + .findFirst().orElse(null) + .equals(departmentalTest)){ + departmentalTest.getAuditDetails().setLastModifiedBy(requestInfo.getUserInfo().getUserName()); + departmentalTest.getAuditDetails().setLastModifiedDate(new Date().getTime()); + } + } + }); + + } + + if(employee.getDocuments() != null){ + employee.getDocuments().stream().forEach(document -> { + if(document.getId()==null) { + document.setId(UUID.randomUUID().toString()); + document.setAuditDetails(auditDetails); + }else { + if(!existingEmpData.getDocuments().stream() + .filter(documentData -> documentData.getId().equals(document.getId())) + .findFirst().orElse(null) + .equals(document)){ + document.getAuditDetails().setLastModifiedBy(requestInfo.getUserInfo().getUserName()); + document.getAuditDetails().setLastModifiedDate(new Date().getTime()); + } + } + }); + + } + + if(employee.getDeactivationDetails() != null){ + employee.getDeactivationDetails().stream().forEach(deactivationDetails -> { + if(deactivationDetails.getId()==null) { + deactivationDetails.setId(UUID.randomUUID().toString()); + deactivationDetails.setAuditDetails(auditDetails); + employee.getDocuments().forEach(employeeDocument -> { + employeeDocument.setReferenceId( deactivationDetails.getId()); + }); + }else { + if(!existingEmpData.getDeactivationDetails().stream() + .filter(deactivationDetailsData -> deactivationDetailsData.getId().equals(deactivationDetails.getId())) + .findFirst().orElse(null) + .equals(deactivationDetails)){ + deactivationDetails.getAuditDetails().setLastModifiedBy(requestInfo.getUserInfo().getUserName()); + deactivationDetails.getAuditDetails().setLastModifiedDate(new Date().getTime()); + } + } + }); + + } + if(employee.getReactivationDetails() != null){ + employee.getReactivationDetails().stream().forEach(reactivationDetails -> { + if(reactivationDetails.getId() == null){ + reactivationDetails.setId(UUID.randomUUID().toString()); + reactivationDetails.setAuditDetails(auditDetails); + employee.getDocuments().forEach(employeeDocument -> { + employeeDocument.setReferenceId(reactivationDetails.getId()); + }); + } + else{ + if(!existingEmpData.getReactivationDetails().stream() + .filter(reactivationDetails1 -> reactivationDetails1.getId().equals(reactivationDetails.getId())) + .findFirst().orElse(null) + .equals(reactivationDetails)){ + reactivationDetails.getAuditDetails().setLastModifiedBy(requestInfo.getUserInfo().getUserName()); + reactivationDetails.getAuditDetails().setLastModifiedDate(new Date().getTime()); + } + } + }); + + } + + + } + + private EmployeeResponse generateResponse(EmployeeRequest employeeRequest) { + return EmployeeResponse.builder() + .responseInfo(factory.createResponseInfoFromRequestInfo(employeeRequest.getRequestInfo(), true)) + .employees(employeeRequest.getEmployees()).build(); + } + + public Map getEmployeeCountResponse(RequestInfo requestInfo, String tenantId){ + Map response = new HashMap<>(); + Map results = new HashMap<>(); + ResponseInfo responseInfo = factory.createResponseInfoFromRequestInfo(requestInfo, true); + + response.put("ResponseInfo",responseInfo); + results = repository.fetchEmployeeCount(tenantId); + + if(CollectionUtils.isEmpty(results) || results.get("totalEmployee").equalsIgnoreCase("0")){ + Map error = new HashMap<>(); + error.put("NO_RECORDS","No records found for the tenantId: "+tenantId); + throw new CustomException(error); + } + + response.put("EmployeCount",results); + return response; + } + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/IdGenService.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/IdGenService.java new file mode 100644 index 00000000000..4e6420247ce --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/IdGenService.java @@ -0,0 +1,90 @@ +package org.egov.hrms.service; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collector; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.hrms.config.PropertiesManager; +import org.egov.hrms.model.Employee; +import org.egov.hrms.repository.RestCallRepository; +import org.egov.hrms.utils.ErrorConstants; +import org.egov.hrms.web.contract.EmployeeRequest; +import org.egov.hrms.web.contract.IdGenerationRequest; +import org.egov.hrms.web.contract.IdGenerationResponse; +import org.egov.hrms.web.contract.IdRequest; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class IdGenService { + + @Autowired + private RestCallRepository repository; + + @Autowired + private PropertiesManager properties; + + /** + * Sets ids to all the employee objects + * + * @param employeeRequest + */ + public void setIds(EmployeeRequest employeeRequest) { + String tenantId = employeeRequest.getEmployees().get(0).getTenantId(); + Integer employeesWithCode = employeeRequest.getEmployees().stream() + .filter(employee -> !StringUtils.isEmpty(employee.getCode())).collect(Collectors.toList()).size(); + if(employeesWithCode == employeeRequest.getEmployees().size()) + return; + IdGenerationResponse response = getId(employeeRequest.getRequestInfo(), tenantId, employeeRequest.getEmployees().size() - employeesWithCode, + properties.getHrmsIdGenKey(), properties.getHrmsIdGenFormat()); + if(null != response) { + int i = 0; + for(Employee employee: employeeRequest.getEmployees()) { + if(StringUtils.isEmpty(employee.getCode())) { + employee.setCode(response.getIdResponses().get(i).getId()); + i++; + } + } + } + } + + /** + * Makes call to the idgen service to fetch ids for the employee object. Format of the id configurable. + * + * @param requestInfo + * @param tenantId + * @param count + * @param name + * @param format + * @return + */ + public IdGenerationResponse getId(RequestInfo requestInfo, String tenantId, Integer count, String name, String format) { + StringBuilder uri = new StringBuilder(); + ObjectMapper mapper = new ObjectMapper(); + uri.append(properties.getIdGenHost()).append(properties.getIdGenEndpoint()); + List reqList = new ArrayList<>(); + for (int i = 0; i < count; i++) { + reqList.add(IdRequest.builder().idName(name).format(format).tenantId(tenantId).build()); + } + IdGenerationRequest request = IdGenerationRequest.builder().idRequests(reqList).requestInfo(requestInfo).build(); + IdGenerationResponse response = null; + try { + response = mapper.convertValue(repository.fetchResult(uri, request), IdGenerationResponse.class); + }catch(Exception e) { + log.error("Exception while generating ids: ",e); + log.error("Request: "+request); + throw new CustomException(ErrorConstants.HRMS_GENERATE_ID_ERROR_CODE,ErrorConstants.HRMS_GENERATE_ID_ERROR_MSG); + + } + return response; + } +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/IndividualService.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/IndividualService.java new file mode 100644 index 00000000000..07b315bf1bc --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/IndividualService.java @@ -0,0 +1,251 @@ +package org.egov.hrms.service; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; +import java.util.UUID; +import java.util.stream.Collectors; + +import digit.models.coremodels.AuditDetails; +import digit.models.coremodels.user.enums.UserType; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.Role; +import org.egov.common.models.individual.Address; +import org.egov.common.models.individual.AddressType; +import org.egov.common.models.individual.Gender; +import org.egov.common.models.individual.Identifier; +import org.egov.common.models.individual.Individual; +import org.egov.common.models.individual.IndividualBulkResponse; +import org.egov.common.models.individual.IndividualRequest; +import org.egov.common.models.individual.IndividualResponse; +import org.egov.common.models.individual.IndividualSearch; +import org.egov.common.models.individual.IndividualSearchRequest; +import org.egov.common.models.individual.Name; +import org.egov.common.models.individual.UserDetails; +import org.egov.hrms.config.PropertiesManager; +import org.egov.hrms.repository.RestCallRepository; +import org.egov.hrms.utils.HRMSConstants; +import org.egov.hrms.web.contract.User; +import org.egov.hrms.web.contract.UserRequest; +import org.egov.hrms.web.contract.UserResponse; +import org.springframework.beans.factory.annotation.Autowired; + +import static org.egov.hrms.utils.HRMSConstants.SYSTEM_GENERATED; + +@Slf4j +public class IndividualService implements UserService { + + private final PropertiesManager propertiesManager; + + private final RestCallRepository restCallRepository; + + @Autowired + public IndividualService(PropertiesManager propertiesManager, + RestCallRepository restCallRepository) { + this.propertiesManager = propertiesManager; + this.restCallRepository = restCallRepository; + } + + + @Override + public UserResponse createUser(UserRequest userRequest) { + IndividualRequest request = mapToIndividualRequest(userRequest); + StringBuilder uri = new StringBuilder(); + uri.append(propertiesManager.getIndividualHost()); + uri.append(propertiesManager.getIndividualCreateEndpoint()); + IndividualResponse response = restCallRepository + .fetchResult(uri, request, IndividualResponse.class); + UserResponse userResponse = null; + if (response != null && response.getIndividual() != null) { + log.info("response received from individual service"); + userResponse = mapToUserResponse(response); + } + return userResponse; + } + + @Override + public UserResponse updateUser(UserRequest userRequest) { + IndividualRequest request = mapToIndividualRequest(userRequest); + StringBuilder uri = new StringBuilder(); + uri.append(propertiesManager.getIndividualHost()); + uri.append(propertiesManager.getIndividualUpdateEndpoint()); + IndividualResponse response = restCallRepository + .fetchResult(uri, request, IndividualResponse.class); + UserResponse userResponse = null; + if (response != null && response.getIndividual() != null) { + log.info("response received from individual service"); + userResponse = mapToUserResponse(response); + } + return userResponse; + } + + @Override + public UserResponse getUser(RequestInfo requestInfo, Map userSearchCriteria ) { + IndividualSearchRequest request = IndividualSearchRequest.builder() + .requestInfo(requestInfo) + .individual(IndividualSearch.builder() + .mobileNumber((String) userSearchCriteria.get("mobileNumber")) + .id((List) userSearchCriteria.get("uuid")) + .roleCodes((List) userSearchCriteria.get("roleCodes")) + .username((String) userSearchCriteria.get(HRMSConstants.HRMS_USER_SEARCH_CRITERA_USERNAME)) + // given name + .individualName((String) userSearchCriteria + .get(HRMSConstants.HRMS_USER_SEARCH_CRITERA_NAME)) + .build()) + .build(); + IndividualBulkResponse response = getIndividualResponse((String) userSearchCriteria + .get(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID), + request); + UserResponse userResponse = new UserResponse(); + if (response != null && response.getIndividual() != null && !response.getIndividual().isEmpty()) { + log.info("response received from individual service"); + userResponse = mapToUserResponse(response); + } + return userResponse; + } + + private IndividualBulkResponse getIndividualResponse(String tenantId, IndividualSearchRequest individualSearchRequest) { + return restCallRepository.fetchResult( + new StringBuilder(propertiesManager.getIndividualHost() + + propertiesManager.getIndividualSearchEndpoint() + + "?limit=1000&offset=0&tenantId=" + tenantId), + individualSearchRequest, IndividualBulkResponse.class); + } + + + /** + * Converts a long value representing milliseconds since the epoch to a Date object in the format dd/MM/yyyy. + * + * @param milliseconds the long value representing milliseconds since the epoch. + * @return a Date object in the format dd/MM/yyyy. + */ + private static Date convertMillisecondsToDate(long milliseconds) { + SimpleDateFormat formatter = new SimpleDateFormat("dd/MM/yyyy"); + formatter.setTimeZone(TimeZone.getTimeZone("UTC")); + String dateString = formatter.format(new Date(milliseconds)); + try { + return formatter.parse(dateString); + } catch (ParseException e) { + e.printStackTrace(); + return null; + } + } + + private static IndividualRequest mapToIndividualRequest(UserRequest userRequest) { + Individual individual = Individual.builder() + .id(userRequest.getUser().getUuid()) + .userId(userRequest.getUser().getId() != null ? + String.valueOf(userRequest.getUser().getId()) : null) + .userUuid(userRequest.getUser().getUserServiceUuid()) + .isSystemUser(true) + .isSystemUserActive(userRequest.getUser().getActive()) + .name(Name.builder() + .givenName(userRequest.getUser().getName()) + .build()) + .gender(Gender.fromValue(userRequest.getUser().getGender())) + .email(userRequest.getUser().getEmailId()) + .mobileNumber(userRequest.getUser().getMobileNumber()) + .dateOfBirth(convertMillisecondsToDate(userRequest.getUser().getDob())) + .tenantId(userRequest.getUser().getTenantId()) + .address(Collections.singletonList(Address.builder() + .type(AddressType.CORRESPONDENCE) + .addressLine1(userRequest.getUser().getCorrespondenceAddress()) + .clientReferenceId(String.valueOf(UUID.randomUUID())) + .isDeleted(Boolean.FALSE) + .build())) + /* + * FIXME (HCM specific change) clientReferenceId is the primary key in the individual table of the FrontEnd Worker Application's local database. + */ + // Generating a unique client reference ID using UUID + .clientReferenceId(String.valueOf(UUID.randomUUID())) + // Creating a list of identifiers + .identifiers(Collections.singletonList( + // Building a unique identifier + Identifier.builder() + // Generating a unique client reference ID using UUID for the identifier + .clientReferenceId(String.valueOf(UUID.randomUUID())) + // Generating a unique identifier ID using UUID + .identifierId(String.valueOf(UUID.randomUUID())) + // Specifying the type of identifier as SYSTEM_GENERATED + .identifierType(SYSTEM_GENERATED) + .build())) + .userDetails(UserDetails.builder() + .username(userRequest.getUser().getUserName()) + .password(userRequest.getUser().getPassword()) + .tenantId(userRequest.getUser().getTenantId()) + .roles(userRequest.getUser().getRoles().stream().map(role -> Role.builder() + .code(role.getCode()) + .name(role.getName()) + .tenantId(userRequest.getUser().getTenantId()) + .description(role.getDescription()) + .build()).collect(Collectors.toList())) + .userType(UserType.fromValue(userRequest.getUser().getType())) + .build()) + .isDeleted(Boolean.FALSE) + .clientAuditDetails(AuditDetails.builder().createdBy(userRequest.getRequestInfo().getUserInfo().getUuid()).lastModifiedBy(userRequest.getRequestInfo().getUserInfo().getUuid()).build()) + .rowVersion(userRequest.getUser().getRowVersion()) + .build(); + return IndividualRequest.builder() + .requestInfo(userRequest.getRequestInfo()) + .individual(individual) + .build(); + } + + private static UserResponse mapToUserResponse(IndividualResponse response) { + UserResponse userResponse; + userResponse = UserResponse.builder() + .responseInfo(response.getResponseInfo()) + .user(Collections.singletonList(getUser(response.getIndividual()))) + .build(); + return userResponse; + } + + private static UserResponse mapToUserResponse(IndividualBulkResponse response) { + UserResponse userResponse; + userResponse = UserResponse.builder() + .responseInfo(response.getResponseInfo()) + .user(response.getIndividual().stream() + .map(IndividualService::getUser).collect(Collectors.toList())) + .build(); + return userResponse; + } + + + private static User getUser(Individual individual) { + return User.builder() + .id(individual.getUserId() != null ? Long.parseLong(individual.getUserId()) : null) + .mobileNumber(individual.getMobileNumber()) + .name(individual.getName().getGivenName()) + .uuid(individual.getId()) + .userServiceUuid(individual.getUserUuid()) + .active(individual.getIsSystemUserActive()) + .gender(individual.getGender() != null ? individual.getGender().name() : null) + .userName(individual.getUserDetails().getUsername()) + .emailId(individual.getEmail()) + .correspondenceAddress(individual.getAddress() != null && !individual.getAddress().isEmpty() + ? individual.getAddress().stream().filter(address -> address.getType() + .equals(AddressType.CORRESPONDENCE)).findFirst() + .orElse(Address.builder().build()) + .getAddressLine1() : null) + .dob(individual.getDateOfBirth().getTime()) + .tenantId(individual.getTenantId()) + .createdBy(individual.getAuditDetails().getCreatedBy()) + .createdDate(individual.getAuditDetails().getCreatedTime()) + .lastModifiedBy(individual.getAuditDetails().getLastModifiedBy()) + .lastModifiedDate(individual.getAuditDetails().getLastModifiedTime()) + .rowVersion(individual.getRowVersion()) + .roles(individual.getUserDetails() + .getRoles().stream().map(role -> org.egov.hrms.model.Role.builder() + .code(role.getCode()) + .tenantId(role.getTenantId()) + .name(role.getName()) + .build()).collect(Collectors.toList())) + + .build(); + } +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/MDMSService.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/MDMSService.java new file mode 100644 index 00000000000..9b2d8df55c3 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/MDMSService.java @@ -0,0 +1,189 @@ +package org.egov.hrms.service; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.egov.common.contract.request.RequestInfo; +import org.egov.hrms.utils.HRMSConstants; +import org.egov.mdms.model.MasterDetail; +import org.egov.mdms.model.MdmsCriteria; +import org.egov.mdms.model.MdmsCriteriaReq; +import org.egov.mdms.model.MdmsResponse; +import org.egov.mdms.model.ModuleDetail; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; +import org.springframework.web.client.RestTemplate; + +import lombok.extern.slf4j.Slf4j; + +@Service +@Slf4j +public class MDMSService { + + @Autowired + private RestTemplate restTemplate; + + @Value("${egov.mdms.host}") + private String mdmsHost; + + @Value("${egov.mdms.search.endpoint}") + private String mdmsEndpoint; + + + /** + * Builds cache for MDMS data, this gets refreshed for every call. + * + * @param requestInfo + * @param tenantId + * @return + */ + public Map> getMDMSData(RequestInfo requestInfo, String tenantId){ + MdmsResponse response = fetchMDMSData(requestInfo, tenantId); + Map> masterData = new HashMap<>(); + Map> eachMasterMap = new HashMap<>(); + if(null != response) { + if(!CollectionUtils.isEmpty(response.getMdmsRes().keySet())) { + if(null != response.getMdmsRes().get(HRMSConstants.HRMS_MDMS_COMMON_MASTERS_CODE)){ + eachMasterMap = (Map) response.getMdmsRes().get(HRMSConstants.HRMS_MDMS_COMMON_MASTERS_CODE); + masterData.put(HRMSConstants.HRMS_MDMS_DEPT_CODE, eachMasterMap.get(HRMSConstants.HRMS_MDMS_DEPT_CODE)); + masterData.put(HRMSConstants.HRMS_MDMS_DESG_CODE, eachMasterMap.get(HRMSConstants.HRMS_MDMS_DESG_CODE)); + } + if(null != response.getMdmsRes().get(HRMSConstants.HRMS_MDMS_HR_MASTERS_CODE)) { + eachMasterMap = (Map) response.getMdmsRes().get(HRMSConstants.HRMS_MDMS_HR_MASTERS_CODE); + masterData.put(HRMSConstants.HRMS_MDMS_EMP_STATUS_CODE, eachMasterMap.get(HRMSConstants.HRMS_MDMS_EMP_STATUS_CODE)); + masterData.put(HRMSConstants.HRMS_MDMS_EMP_TYPE_CODE, eachMasterMap.get(HRMSConstants.HRMS_MDMS_EMP_TYPE_CODE)); + masterData.put(HRMSConstants.HRMS_MDMS_QUALIFICATION_CODE, eachMasterMap.get(HRMSConstants.HRMS_MDMS_QUALIFICATION_CODE)); + masterData.put(HRMSConstants.HRMS_MDMS_STREAMS_CODE, eachMasterMap.get(HRMSConstants.HRMS_MDMS_STREAMS_CODE)); + masterData.put(HRMSConstants.HRMS_MDMS_DEPT_TEST_CODE, eachMasterMap.get(HRMSConstants.HRMS_MDMS_DEPT_TEST_CODE)); + masterData.put(HRMSConstants.HRMS_MDMS_DEACT_REASON_CODE, eachMasterMap.get(HRMSConstants.HRMS_MDMS_DEACT_REASON_CODE)); + } + if(null != response.getMdmsRes().get(HRMSConstants.HRMS_AC_ROLES_MASTERS_CODE)) { + eachMasterMap = (Map) response.getMdmsRes().get(HRMSConstants.HRMS_AC_ROLES_MASTERS_CODE); + masterData.put(HRMSConstants.HRMS_MDMS_ROLES_CODE, eachMasterMap.get(HRMSConstants.HRMS_MDMS_ROLES_CODE)); + } + } + } + + return masterData; + + } + + + + /** + * Makes call to the MDMS service to fetch the MDMS data. + * + * @param requestInfo + * @param tenantId + * @return + */ + public MdmsResponse fetchMDMSData(RequestInfo requestInfo, String tenantId) { + StringBuilder uri = new StringBuilder(); + MdmsCriteriaReq request = prepareMDMSRequest(uri, requestInfo, tenantId); + MdmsResponse response = null; + try { + response = restTemplate.postForObject(uri.toString(), request, MdmsResponse.class); + }catch(Exception e) { + log.info("Exception while fetching from MDMS: ",e); + log.info("Request: "+ request); + } + return response; + } + + /** + * Makes call to the MDMS service to fetch the MDMS Boundary data. + * + * @param requestInfo + * @param tenantId + * @return + */ + public MdmsResponse fetchMDMSDataLoc(RequestInfo requestInfo, String tenantId) { + StringBuilder uri = new StringBuilder(); + MdmsCriteriaReq request = prepareMDMSRequestLoc(uri, requestInfo, tenantId); + MdmsResponse response = null; + try { + response = restTemplate.postForObject(uri.toString(), request, MdmsResponse.class); + }catch(Exception e) { + log.info("Exception while fetching from MDMS: ",e); + log.info("Request: "+ request); + } + return response; + } + + /** + * Prepares request for MDMS in order to fetch all the required masters for HRMS. + * + * @param uri + * @param requestInfo + * @param tenantId + * @return + */ + public MdmsCriteriaReq prepareMDMSRequest(StringBuilder uri, RequestInfo requestInfo, String tenantId) { + Map> mapOfModulesAndMasters = new HashMap<>(); + String[] hrMasters = {HRMSConstants.HRMS_MDMS_EMP_STATUS_CODE, HRMSConstants.HRMS_MDMS_EMP_TYPE_CODE, HRMSConstants.HRMS_MDMS_QUALIFICATION_CODE, + HRMSConstants.HRMS_MDMS_SERVICE_STATUS_CODE, HRMSConstants.HRMS_MDMS_STREAMS_CODE, HRMSConstants.HRMS_MDMS_DEACT_REASON_CODE, HRMSConstants.HRMS_MDMS_DEPT_TEST_CODE}; + String[] commonMasters = {HRMSConstants.HRMS_MDMS_DEPT_CODE, HRMSConstants.HRMS_MDMS_DESG_CODE, HRMSConstants.HRMS_MDMS_YEAR_CODE}; + String[] accessControlRoles = {HRMSConstants.HRMS_MDMS_ROLES_CODE}; + mapOfModulesAndMasters.put(HRMSConstants.HRMS_MDMS_COMMON_MASTERS_CODE, Arrays.asList(commonMasters)); + mapOfModulesAndMasters.put(HRMSConstants.HRMS_MDMS_HR_MASTERS_CODE, Arrays.asList(hrMasters)); + mapOfModulesAndMasters.put(HRMSConstants.HRMS_AC_ROLES_MASTERS_CODE, Arrays.asList(accessControlRoles)); + List moduleDetails = new ArrayList<>(); + for(String module: mapOfModulesAndMasters.keySet()) { + ModuleDetail moduleDetail = new ModuleDetail(); + moduleDetail.setModuleName(module); + List masterDetails = new ArrayList<>(); + for(String master: mapOfModulesAndMasters.get(module)) { + MasterDetail masterDetail=null; + if(module.equals(HRMSConstants.HRMS_AC_ROLES_MASTERS_CODE)) + masterDetail = MasterDetail.builder().name(master).filter(HRMSConstants.HRMS_MDMS_AC_ROLES_FILTER).build(); + else + masterDetail = MasterDetail.builder().name(master).filter("[?(@.active == true)].code").build(); + masterDetails.add(masterDetail); + } + moduleDetail.setMasterDetails(masterDetails); + moduleDetails.add(moduleDetail); + } + uri.append(mdmsHost).append(mdmsEndpoint); + MdmsCriteria mdmsCriteria = MdmsCriteria.builder().tenantId(tenantId).moduleDetails(moduleDetails).build(); + return MdmsCriteriaReq.builder().requestInfo(requestInfo).mdmsCriteria(mdmsCriteria).build(); + + } + + + /** + * Prepares request for MDMS in order to fetch all the required masters for Boundary Data. + * + * @param uri + * @param requestInfo + * @param tenantId + * @return + */ + public MdmsCriteriaReq prepareMDMSRequestLoc(StringBuilder uri, RequestInfo requestInfo, String tenantId) { + Map> mapOfModulesAndMasters = new HashMap<>(); + String[] egovLoccation = {HRMSConstants.HRMS_MDMS_TENANT_BOUNDARY_CODE}; + mapOfModulesAndMasters.put(HRMSConstants.HRMS_MDMS_EGOV_LOCATION_MASTERS_CODE, Arrays.asList(egovLoccation)); + List moduleDetails = new ArrayList<>(); + for(String module: mapOfModulesAndMasters.keySet()) { + ModuleDetail moduleDetail = new ModuleDetail(); + moduleDetail.setModuleName(module); + List masterDetails = new ArrayList<>(); + for(String master: mapOfModulesAndMasters.get(module)) { + MasterDetail masterDetail=null; + masterDetail = MasterDetail.builder().name(master).build(); + masterDetails.add(masterDetail); + } + moduleDetail.setMasterDetails(masterDetails); + moduleDetails.add(moduleDetail); + } + uri.append(mdmsHost).append(mdmsEndpoint); + MdmsCriteria mdmsCriteria = MdmsCriteria.builder().tenantId(tenantId).moduleDetails(moduleDetails).build(); + return MdmsCriteriaReq.builder().requestInfo(requestInfo).mdmsCriteria(mdmsCriteria).build(); + + } + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/NotificationService.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/NotificationService.java new file mode 100644 index 00000000000..acb427e4ce7 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/NotificationService.java @@ -0,0 +1,196 @@ +package org.egov.hrms.service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.hrms.model.Employee; +import org.egov.hrms.model.SMSRequest; +import org.egov.hrms.producer.HRMSProducer; +import org.egov.hrms.repository.RestCallRepository; +import org.egov.hrms.utils.HRMSConstants; +import org.egov.hrms.web.contract.EmployeeRequest; +import org.egov.hrms.web.contract.RequestInfoWrapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import com.jayway.jsonpath.JsonPath; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.client.RestTemplate; + +@Service +@Slf4j +public class NotificationService { + + @Autowired + private HRMSProducer producer; + + @Autowired + private RestCallRepository repository; + + @Autowired + private RestTemplate restTemplate; + + @Value("${kafka.topics.notification.sms}") + private String smsTopic; + + @Value("${egov.hrms.employee.app.link}") + private String appLink; + + @Value("${egov.localization.host}") + private String localizationHost; + + @Value("${egov.localization.search.endpoint}") + private String localizationSearchEndpoint; + + @Value("${egov.otp.host}") + private String otpHost; + + @Value("${egov.otp.create.endpoint}") + private String otpCreateEndpoint; + + @Value("${egov.environment.domain}") + private String envHost; + + + + /** + * Sends notification by putting the sms content onto the core-sms topic + * + * @param request + * @param pwdMap + */ + public void sendNotification(EmployeeRequest request, Map pwdMap) { + String message = getMessage(request,HRMSConstants.HRMS_EMP_CREATE_LOCLZN_CODE); + if(StringUtils.isEmpty(message)) { + log.info("SMS content has not been configured for this case"); + return; + } + for(Employee employee: request.getEmployees()) { + message = buildMessage(employee, message, pwdMap); + SMSRequest smsRequest = SMSRequest.builder().mobileNumber(employee.getUser().getMobileNumber()).message(message).build(); + producer.push(smsTopic, smsRequest); + } + } + + public void sendReactivationNotification(EmployeeRequest request){ + String message = getMessage(request,HRMSConstants.HRMS_EMP_REACTIVATE_LOCLZN_CODE); + if(StringUtils.isEmpty(message)) { + log.info("SMS content has not been configured for this case"); + return; + } + RequestInfo requestInfo = request.getRequestInfo(); + for(Employee employee: request.getEmployees()) { + if(employee.getReactivationDetails()!=null && employee.getReActivateEmployee()){ + String OTP = getOTP(employee,requestInfo); + String link = envHost + "employee/user/otp"; + + message = message.replace("{Employee Name}",employee.getUser().getName()).replace("{Username}",employee.getCode()); + message = message.replace("{date}",(employee.getReactivationDetails().get(0).getEffectiveFrom()).toString()); + message = message.replace("{password}",OTP).replace("{link}",link); + + SMSRequest smsRequest = SMSRequest.builder().mobileNumber(employee.getUser().getMobileNumber()).message(message).build(); + log.info(message ); + producer.push(smsTopic, smsRequest); + } + + } + + } + + public String getOTP(Employee employee,RequestInfo requestInfo){ + Map OTPRequest= new HashMap<>(); + Map otp= new HashMap<>(); + otp.put("mobileNumber",employee.getUser().getMobileNumber()); + otp.put("type","passwordreset"); + otp.put("tenantId",employee.getTenantId()); + otp.put("userType","EMPLOYEE"); + otp.put("identity",employee.getUser().getMobileNumber()); + + OTPRequest.put("RequestInfo",requestInfo); + OTPRequest.put("otp",otp); + + Object response = null; + StringBuilder url = new StringBuilder(); + url.append(otpHost).append(otpCreateEndpoint); + try { + response = restTemplate.postForObject(url.toString(), OTPRequest, Map.class); + }catch(Exception e) { + log.error("Exception while creating user: ", e); + return null; + } + String result = JsonPath.read(response, "$.otp.otp"); + return result; + } + + /** + * Gets the message from localization + * + * @param request + * @return + */ + public String getMessage(EmployeeRequest request,String msgCode) { + String tenantId = request.getEmployees().get(0).getTenantId().split("\\.")[0]; + Map> localizedMessageMap = getLocalisedMessages(request.getRequestInfo(), tenantId, + HRMSConstants.HRMS_LOCALIZATION_ENG_LOCALE_CODE, HRMSConstants.HRMS_LOCALIZATION_MODULE_CODE); + return localizedMessageMap.get(HRMSConstants.HRMS_LOCALIZATION_ENG_LOCALE_CODE +"|"+tenantId).get(msgCode); + } + + /** + * Builds msg based on the format + * + * @param employee + * @param message + * @param pwdMap + * @return + */ + public String buildMessage(Employee employee, String message, Map pwdMap) { + message = message.replace("$username", employee.getCode()).replace("$password", pwdMap.get(employee.getUuid())) + .replace("$employeename", employee.getUser().getName()); + message = message.replace("$applink", appLink); + return message; + } + + /** + * Creates a cache for localization that gets refreshed at every call. + * + * @param requestInfo + * @param tenantId + * @param locale + * @param module + * @return + */ + public Map> getLocalisedMessages(RequestInfo requestInfo, String tenantId, String locale, String module) { + Map> localizedMessageMap = new HashMap<>(); + Map mapOfCodesAndMessages = new HashMap<>(); + StringBuilder uri = new StringBuilder(); + RequestInfoWrapper requestInfoWrapper = new RequestInfoWrapper(); + requestInfoWrapper.setRequestInfo(requestInfo); + tenantId = tenantId.split("\\.")[0]; + uri.append(localizationHost).append(localizationSearchEndpoint).append("?tenantId=" + tenantId) + .append("&module=" + module).append("&locale=" + locale); + List codes = null; + List messages = null; + Object result = null; + try { + result = repository.fetchResult(uri, requestInfoWrapper); + codes = JsonPath.read(result, HRMSConstants.HRMS_LOCALIZATION_CODES_JSONPATH); + messages = JsonPath.read(result, HRMSConstants.HRMS_LOCALIZATION_MSGS_JSONPATH); + } catch (Exception e) { + log.error("Exception while fetching from localization: " + e); + } + if (null != result) { + for (int i = 0; i < codes.size(); i++) { + mapOfCodesAndMessages.put(codes.get(i), messages.get(i)); + } + localizedMessageMap.put(locale + "|" + tenantId, mapOfCodesAndMessages); + } + + return localizedMessageMap; + } + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/UserService.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/UserService.java new file mode 100644 index 00000000000..f1c7ee71a66 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/UserService.java @@ -0,0 +1,16 @@ +package org.egov.hrms.service; + +import org.egov.common.contract.request.RequestInfo; +import org.egov.hrms.web.contract.UserRequest; +import org.egov.hrms.web.contract.UserResponse; + +import java.util.Map; + +public interface UserService { + + UserResponse createUser(UserRequest userRequest); + + UserResponse updateUser(UserRequest userRequest); + + UserResponse getUser(RequestInfo requestInfo, Map userSearchCriteria); +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/ErrorConstants.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/ErrorConstants.java new file mode 100644 index 00000000000..1dccb2952f8 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/ErrorConstants.java @@ -0,0 +1,206 @@ +package org.egov.hrms.utils; + +import org.springframework.stereotype.Component; + +@Component +public class ErrorConstants { + + public static final String HRMS_USER_EXIST_MOB_CODE = "ERR_HRMS_USER_EXIST_MOB"; + public static final String HRMS_USER_EXIST_MOB_MSG = "User already exists for the entered mobile number. Use a different mobile number to proceed."; + + public static final String HRMS_USER_EXIST_USERNAME_CODE = "ERR_HRMS_USER_EXIST_USERNAME"; + public static final String HRMS_USER_EXIST_USERNAME_MSG = "User already exists for the entered user name."; + + public static final String HRMS_INVALID_MOB_NO_CODE = "ERR_HRMS_INVALID_MOB_NO"; + public static final String HRMS_INVALID_MOB_NO_MSG = "Invalid mobile number entered."; + + public static final String HRMS_MISSING_ROLES_CODE = "ERR_HRMS_MISSING_ROLES"; + public static final String HRMS_INVALID_ROLES_MSG = "Invalid mobile number entered."; + + public static final String HRMS_INVALID_ROLE_CODE = "ERR_HRMS_INVALID_ROLE"; + public static final String HRMS_INVALID_ROLE_MSG = "Invalid role assigned to the employee."; + + public static final String HRMS_INVALID_EMP_STATUS_CODE = "ERR_HRMS_INVALID_EMP_STATUS_ROLE"; + public static final String HRMS_INVALID_EMP_STATUS_MSG = "Invalid employment status entered."; + + public static final String HRMS_INVALID_EMP_TYPE_CODE = "ERR_HRMS_INVALID_EMP_TYPE"; + public static final String HRMS_INVALID_EMP_TYPE_MSG = "Invalid employee type entered."; + + public static final String HRMS_INVALID_DATE_OF_APPOINTMENT_CODE = "ERR_HRMS_INVALID_DATE_OF_APPOINTMENT"; + public static final String HRMS_INVALID_DATE_OF_APPOINTMENT_MSG = "Invalid employee date of appointment entered by the user."; + + public static final String HRMS_INVALID_DATE_OF_APPOINTMENT_DOB_CODE = "ERR_HRMS_INVALID_DATE_OF_APPOINTMENT_DOB"; + public static final String HRMS_INVALID_DATE_OF_APPOINTMENT_DOB_MSG = "Employee date of appointment can not be before date of birth."; + + public static final String HRMS_INVALID_DOB_CODE = "ERR_HRMS_INVALID_DOB"; + public static final String HRMS_INVALID_DOB_MSG = "Invalid date of birth entered."; + + public static final String HRMS_INVALID_CURRENT_ASSGN_CODE = "ERR_HRMS_INVALID_CURRENT_ASSGN"; + public static final String HRMS_INVALID_CURRENT_ASSGN_MSG = "There should be exactly one current assignment for the employee."; + + public static final String HRMS_OVERLAPPING_ASSGN_CODE = "ERR_HRMS_OVERLAPPING_ASSGN"; + public static final String HRMS_OVERLAPPING_ASSGN_MSG = "There should not be overlapping period of assignments for the employee."; + + public static final String HRMS_OVERLAPPING_ASSGN_CURRENT_CODE = "ERR_HRMS_OVERLAPPING_ASSGN_CURRENT"; + public static final String HRMS_OVERLAPPING_ASSGN_CURRENT_MSG = "Period of assignements of employee should not be after current assignment."; + + public static final String HRMS_INVALID_DEPT_CODE = "ERR_HRMS_INVALID_DEPT"; + public static final String HRMS_INVALID_DEPT_MSG = "Invalid department of employee entered."; + + public static final String HRMS_INVALID_DESG_CODE = "ERR_HRMS_INVALID_DESG"; + public static final String HRMS_INVALID_DESG_MSG = "Invalid designation of employee."; + + public static final String HRMS_INVALID_ASSIGNMENT_PERIOD_CODE = "ERR_HRMS_INVALID_ASSIGNMENT_PERIOD"; + public static final String HRMS_INVALID_ASSIGNMENT_PERIOD_MSG = "Invalid period of assignment (From date - To date)."; + + public static final String HRMS_INVALID_ASSIGNMENT_CURRENT_TO_DATE_CODE = "ERR_HRMS_INVALID_ASSIGNMENT_CURRENT_TO_DATE"; + public static final String HRMS_INVALID_ASSIGNMENT_CURRENT_TO_DATE_MSG = "To Date field should be blank for current assignment of the employee."; + + public static final String HRMS_OVERLAPPING_SERVICEHISTORY_CURRENT_CODE = "ERR_HRMS_OVERLAPPING_SERVICEHISTORY_CURRENT"; + public static final String HRMS_OVERLAPPING_SERVICEHISTORY_CURRENT_MSG = "Period of service details of employee should not be after current assignment!"; + + + public static final String HRMS_INVALID_ASSIGNMENT_NON_CURRENT_TO_DATE_CODE = "ERR_HRMS_INVALID_ASSIGNMENT_NOT_CURRENT_TO_DATE"; + public static final String HRMS_INVALID_ASSIGNMENT_NON_CURRENT_TO_DATE_MSG = "To date field should not be blank for non current assignment of the employee."; + + public static final String HRMS_INVALID_ASSIGNMENT_DATES_CODE = "ERR_HRMS_INVALID_ASSIGNMENT_DATES"; + public static final String HRMS_INVALID_ASSIGNMENT_DATES_MSG = "Employee period of assignment (From Date or To date) can not be before date of birth."; + + public static final String HRMS_INVALID_ASSIGNMENT_DATES_APPOINTMENT_CODE = "ERR_HRMS_INVALID_ASSIGNMENT_DATES_APPOINTMENT"; + public static final String HRMS_INVALID_ASSIGNMENT_DATES_APPOINTMENT_MSG = "Employee period of assignment (From Date or To date) can not be before date of appointment."; + + public static final String HRMS_INVALID_SERVICE_STATUS_CODE = "ERR_HRMS_INVALID_SERVICE_STATUS"; + public static final String HRMS_INVALID_SERVICE_STATUS_MSG = "Service stataus of employee is invalid."; + + public static final String HRMS_INVALID_SERVICE_PERIOD_CODE = "ERR_HRMS_INVALID_SERVICE_PERIOD"; + public static final String HRMS_INVALID_SERVICE_PERIOD_MSG = "Service period (From date or To date) of employee is invalid."; + + public static final String HRMS_INVALID_SERVICE_DATES_CODE = "ERR_HRMS_INVALID_SERVICE_DATES"; + public static final String HRMS_INVALID_SERVICE_DATES_MSG = "Employee service period (From date or To date) can not be before date of birth."; + + public static final String HRMS_INVALID_SERVICE_CURRENT_TO_DATE_CODE = "ERR_HRMS_INVALID_SERVICE_CURRENT_TO_DATE"; + public static final String HRMS_INVALID_SERVICE_CURRENT_TO_DATE_MSG = "To Date of service period should be blank for currently working employees."; + + public static final String HRMS_INVALID_SERVICE_NON_CURRENT_TO_DATE_CODE = "ERR_HRMS_INVALID_SERVICE_NOT_CURRENT_TO_DATE"; + public static final String HRMS_INVALID_SERVICE_NON_CURRENT_TO_DATE_MSG = "To Date of service period should not be blank for currently non working employees."; + + public static final String HRMS_INVALID_CURRENT_SERVICE_CODE = "ERR_HRMS_INVALID_SERVICE_ASSGN"; + public static final String HRMS_INVALID_CURRENT_SERVICE_MSG = "There should be maximum one currently working service for the employee."; + + public static final String HRMS_INVALID_QUALIFICATION_CODE = "ERR_HRMS_INVALID_QUALIFICATION"; + public static final String HRMS_INVALID_QUALIFICATION_MSG = "Qualification of the employee is invalid."; + + public static final String HRMS_INVALID_EDUCATIONAL_STREAM_CODE = "ERR_HRMS_INVALID_EDUCATIONAL_STREAM"; + public static final String HRMS_INVALID_EDUCATIONAL_STREAM_MSG = "Education stream of the employee is invalid."; + + public static final String HRMS_INVALID_EDUCATIONAL_PASSING_YEAR_CODE = "ERR_HRMS_INVALID_EDUCATIONAL_PASSING_YEAR"; + public static final String HRMS_INVALID_EDUCATIONAL_PASSING_YEAR_MSG = "Education year of passing of the employee can not be before date of birth."; + + public static final String HRMS_INVALID_DEPARTMENTAL_TEST_CODE = "ERR_HRMS_INVALID_DEPARTMENTAL_TEST"; + public static final String HRMS_INVALID_DEPARTMENTAL_TEST_MSG = "Departmental evaluation test of the employee is invalid."; + + public static final String HRMS_INVALID_DEPARTMENTAL_TEST_PASSING_YEAR_CODE = "ERR_HRMS_INVALID_DEPARTMENTAL_TEST_PASSING_YEAR"; + public static final String HRMS_INVALID_DEPARTMENTAL_TEST_PASSING_YEAR_MSG = "Departmental evaluation test passing year of the employee can not be before date of birth."; + + public static final String HRMS_INVALID_DEACT_REQUEST_CODE = "ERR_HRMS_INVALID_DEACT_REQUEST"; + public static final String HRMS_INVALID_DEACT_REQUEST_MSG = "Employee active flag should be set as false during deactivation."; + + public static final String HRMS_INVALID_DEACT_REASON_CODE = "ERR_HRMS_INVALID_DEACT_REASON"; + public static final String HRMS_INVALID_DEACT_REASON_MSG = "Employee deactivation reason is invalid."; + + public static final String HRMS_UPDATE_JURISDICTION_INCOSISTENT_CODE = "ERR_HRMS_UPDATE_JURISDICTION_INCOSISTENT"; + public static final String HRMS_UPDATE_JURISDICTION_INCOSISTENT_MSG = "Jurisdiction data in an update request should contain all previously entered data."; + + public static final String HRMS_UPDATE_ASSIGNEMENT_INCOSISTENT_CODE = "ERR_HRMS_UPDATE_ASSIGNEMENT_INCOSISTENT"; + public static final String HRMS_UPDATE_ASSIGNEMENT_INCOSISTENT_MSG = "Assignment data in an update request should contain all previously entered data."; + + public static final String HRMS_UPDATE_TESTS_INCOSISTENT_CODE = "ERR_HRMS_UPDATE_TESTS_INCOSISTENT"; + public static final String HRMS_UPDATE_TESTS_INCOSISTENT_MSG = "Employee evaluation test data in an update request should contain all previously entered data."; + + public static final String HRMS_UPDATE_EDUCATION_INCOSISTENT_CODE = "ERR_HRMS_UPDATE_EDUCATION_INCOSISTENT"; + public static final String HRMS_UPDATE_EDUCATION_INCOSISTENT_MSG = "Education data in an update request should contain all previously entered data."; + + public static final String HRMS_UPDATE_SERVICE_HISTORY_INCOSISTENT_CODE = "ERR_HRMS_UPDATE_SERVICE_HISTORY_INCOSISTENT"; + public static final String HRMS_UPDATE_SERVICE_HISTORY_INCOSISTENT_MSG = "Service history data in an update request should contain all previously entered data."; + + public static final String HRMS_UPDATE_DOCUMENT_INCOSISTENT_CODE = "ERR_HRMS_UPDATE_DOCUMENT_INCOSISTENT"; + public static final String HRMS_UPDATE_DOCUMENT_INCOSISTENT_MSG = "Employee document data in an update request should contain all previously entered data."; + + public static final String HRMS_UPDATE_DEACT_DETAILS_INCOSISTENT_CODE = "ERR_HRMS_UPDATE_DEACT_DETAILS_INCOSISTENT"; + public static final String HRMS_UPDATE_DEACT_DETAILS_INCOSISTENT_MSG = "Employee deactivation data in an update request should contain all previously entered data."; + + public static final String HRMS_UPDATE_NULL_ID_CODE = "ERR_HRMS_UPDATE_NULL_ID"; + public static final String HRMS_UPDATE_NULL_ID_MSG = "Employee ID in an update request should not be null."; + + public static final String HRMS_UPDATE_NULL_CODE_CODE = "ERR_HRMS_UPDATE_NULL"; + public static final String HRMS_UPDATE_NULL_CODE_MSG = "Employee Code in an update request should not be null."; + + public static final String HRMS_UPDATE_NULL_UUID_CODE = "ERR_HRMS_UPDATE_NULL_UUID"; + public static final String HRMS_UPDATE_NULL_UUID_MSG = "Employee UUID in an update request should not be null."; + + public static final String HRMS_USER_CREATION_FAILED_CODE = "ERR_HRMS_USER_CREATION_FAILED"; + public static final String HRMS_USER_CREATION_FAILED_MSG = "User creation failed at the user service."; + + public static final String HRMS_USER_UPDATION_FAILED_CODE = "ERR_HRMS_USER_UPDATION_FAILED"; + public static final String HRMS_USER_UPDATION_FAILED_MSG = "User updation failed at the user service."; + + public static final String HRMS_INVALID_SEARCH_REQ_CODE = "ERR_HRMS_INVALID_SEARCH_REQ"; + public static final String HRMS_INVALID_SEARCH_REQ_MSG = "Open search is disabled for this user."; + + public static final String HRMS_INVALID_JURISDICTION_HEIRARCHY_CODE = "ERR_HRMS_INVALID_JURISDICTION_HEIRARCHY"; + public static final String HRMS_INVALID_JURISDICTION_HEIRARCHY_MSG = "Jurisiction hierarchy value is invalid."; + + public static final String HRMS_INVALID_JURISDICTION_BOUNDARY_TYPE_CODE = "ERR_HRMS_INVALID_BOUNDARY_TYPE_HEIRARCHY"; + public static final String HRMS_INVALID_JURISDICTION_BOUNDARY_TYPE_MSG = "Jurisiction boundary type value is invalid."; + + public static final String HRMS_INVALID_JURISDICTION_BOUNDARY_CODE = "ERR_HRMS_INVALID_JURISDICTION_BOUNDARY"; + public static final String HRMS_INVALID_JURISDICTION_BOUNDARY_MSG = "Jurisiction boundary value is invalid."; + + public static final String HRMS_INVALID_JURISDICTION_ACTIIEV_NULL_CODE = "ERR_HRMS_INVALID_JURISDICTION_ACTIIEV_NULL"; + public static final String HRMS_INVALID_JURISDICTION_ACTIIEV_NULL_MSG = "Jurisiction should have atleast 1 active data"; + + public static final String HRMS_INVALID_SEARCH_AOD_CODE = "ERR_HRMS_INVALID_SEARCH_AOD"; + public static final String HRMS_INVALID_SEARCH_AOD_MSG = "Along with as on date, atleast one department and designation need to be passed as search criteria."; + + public static final String HRMS_INVALID_SEARCH_ROLES_CODE = "ERR_HRMS_INVALID_SEARCH_ROLES"; + public static final String HRMS_INVALID_SEARCH_ROLES_MSG = "For search based on roles, passing of tenant id is mandatory."; + + public static final String HRMS_INVALID_SEARCH_USER_CODE = "ERR_HRMS_INVALID_SEARCH_USER"; + public static final String HRMS_INVALID_SEARCH_USER_MSG = "For search based on phone number and name, passing of tenant id is mandatory."; + + public static final String HRMS_UPDATE_EMPLOYEE_CODE_CHANGE_CODE = "ERR_HRMS_UPDATE_EMPLOYEE_CODE_CHANGE"; + public static final String HRMS_UPDATE_EMPLOYEE_CODE_CHANGE_MSG = "Employee code can not be changed in an update request."; + public static final String HRMS_UPDATE_EMPLOYEE_NOT_EXIST_CODE = "ERR_HRMS_UPDATE_EMPLOYEE_NOT_EXIST_CODE"; + public static final String HRMS_UPDATE_EMPLOYEE_NOT_EXIST_MSG = "No employee found for given UUID."; + + public static final String HRMS_UPDATE_EXISTING_MOBNO_CODE = "ERR_HRMS_UPDATE_EXISTING_MOBNO"; + public static final String HRMS_UPDATE_EXISTING_MOBNO_MSG = "User exist for given mobile no"; + + public static final String HRMS_BULK_CREATE_DUPLICATE_MOBILE_CODE = "ERR_HRMS_BULK_CREATE_DUPLICATE_MOBILE"; + public static final String HRMS_BULK_CREATE_DUPLICATE_MOBILE_MSG = "Bulk request has duplicate mobile number "; + + public static final String HRMS_BULK_CREATE_DUPLICATE_EMPCODE_CODE = "ERR_HRMS_BULK_CREATE_DUPLICATE_EMPCODE"; + public static final String HRMS_BULK_CREATE_DUPLICATE_EMPCODE_MSG = "Bulk request has duplicate employee code "; + + public static final String HRMS_UPDATE_DEACT_DETAILS_INCORRECT_EFFECTIVEFROM_CODE = "ERR_HRMS_UPDATE_DEACT_DETAILS_INCORRECT_EFFECTIVEFROM"; + public static final String HRMS_UPDATE_DEACT_DETAILS_INCORRECT_EFFECTIVEFROM_MSG = "Employee deactivation effective date should be current date only."; + + public static final String HRMS_GENERATE_ID_ERROR_CODE = "ERR_HRMS_GENERATE_ID_ERROR"; + public static final String HRMS_GENERATE_ID_ERROR_MSG = "Unable to create ids " ; + + public static final String HRMS_EMPLOYEE_COUNT_ERROR_CODE = "ERR_HRMS_COUNT_EMP"; + public static final String HRMS_EMPLOYEE_COUNT_ERROR_MSG = "Please provide tenantid to get count of the employee"; + + public static final String HRMS_UPDATE_REACT_DETAILS_INCORRECT_EFFECTIVEFROM_CODE = "ERR_HRMS_UPDATE_REACT_DETAILS_INCORRECT_EFFECTIVEFROM"; + public static final String HRMS_UPDATE_REACT_DETAILS_INCORRECT_EFFECTIVEFROM_MSG = "Employee reactivation effective date should be between deactivation date and current date."; + + public static final String CITIZEN_TYPE_CODE = "CITIZEN"; + + public static final String HRMS_INVALID_SEARCH_CITIZEN_CODE = "ERR_HRMS_INVALID_SEARCH_CITIZEN"; + public static final String HRMS_INVALID_SEARCH_CITIZEN_MSG = "Citizen are not allowed to access employee search with Ids."; + + public static final String HRMS_PASSWORD_REQUIRED = "ERR_HRMS_PASSWORD_REQUIRED"; + + public static final String HRMS_PASSWORD_REQUIRED_MSG = "Password is required"; + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/HRMSConstants.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/HRMSConstants.java new file mode 100644 index 00000000000..0d01b642d97 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/HRMSConstants.java @@ -0,0 +1,64 @@ +package org.egov.hrms.utils; + +import org.springframework.stereotype.Component; + +@Component +public class HRMSConstants { + + public static final String HRMS_MDMS_COMMON_MASTERS_CODE = "common-masters"; + public static final String HRMS_MDMS_HR_MASTERS_CODE = "egov-hrms"; + public static final String HRMS_AC_ROLES_MASTERS_CODE = "ACCESSCONTROL-ROLES"; + public static final String HRMS_MDMS_EGOV_LOCATION_MASTERS_CODE = "egov-location"; + + public static final String HRMS_MDMS_DEPT_CODE = "Department"; + public static final String HRMS_MDMS_DESG_CODE = "Designation"; + public static final String HRMS_MDMS_EMP_STATUS_CODE = "EmployeeStatus"; + public static final String HRMS_MDMS_EMP_TYPE_CODE = "EmployeeType"; + public static final String HRMS_MDMS_SERVICE_STATUS_CODE = "ServiceStatus"; + public static final String HRMS_MDMS_ROLES_CODE = "roles"; + public static final String HRMS_MDMS_QUALIFICATION_CODE = "Degree"; + public static final String HRMS_MDMS_STREAMS_CODE = "Specalization"; + public static final String HRMS_MDMS_YEAR_CODE = "Year"; + public static final String HRMS_MDMS_DEPT_TEST_CODE = "EmploymentTest"; + public static final String HRMS_MDMS_DEACT_REASON_CODE = "DeactivationReason"; + public static final String HRMS_MDMS_TENANT_BOUNDARY_CODE = "TenantBoundary"; + + public static final String HRMS_LOCALIZATION_CODES_JSONPATH = "$.messages.*.code"; + public static final String HRMS_LOCALIZATION_MSGS_JSONPATH = "$.messages.*.message"; + + + public static final String HRMS_EMP_CREATE_LOCLZN_CODE = "hrms.employee.create.notification"; + public static final String HRMS_EMP_REACTIVATE_LOCLZN_CODE = "hrms.employee.reactivation.notification"; + public static final String HRMS_LOCALIZATION_MODULE_CODE = "egov-hrms"; + public static final String HRMS_LOCALIZATION_ENG_LOCALE_CODE = "en_IN"; + public static final String HRMS_TENANTBOUNDARY_HIERARCHY_JSONPATH = "$.TenantBoundary[?(@.boundary.code ==\"%s\")].hierarchyType.code"; + public static final String HRMS_TENANTBOUNDARY_BOUNDARY_TYPE_JSONPATH ="$.TenantBoundary[?(@.hierarchyType.name==\"%1$s\" && @.boundary.code ==\"%2$s\")]..label"; + public static final String HRMS_TENANTBOUNDARY_BOUNDARY_VALUE_JSONPATH ="$.TenantBoundary[?(@.hierarchyType.name==\"%1$s\" && @.boundary.code ==\"%2$s\")]..code"; + + public static final String HRMS_MDMS_AC_ROLES_FILTER = "[?(@.code != \"CITIZEN\")].code"; + public static final String HRMS_MDMS_CODE_FLITER = "[?(@.active == true)].code"; + + public static final String HRMS_USER_SEARCH_CRITERA_UUID = "uuid"; + public static final String HRMS_USER_SEARCH_CRITERA_ROLECODES = "roleCodes"; + public static final String HRMS_USER_SEARCH_CRITERA_TENANTID = "tenantId"; + public static final String HRMS_USER_SEARCH_CRITERA_MOBILENO = "mobileNumber"; + public static final String HRMS_USER_SEARCH_CRITERA_NAME = "name"; + public static final String HRMS_USER_SEARCH_CRITERA_USERNAME = "UserName"; + public static final String HRMS_USER_SERACH_CRITERIA_USERTYPE = "EMPLOYEE"; + public static final String HRMS_USER_SERACH_CRITERIA_USERTYPE_CODE = "userType"; + + public static final String INTERNALMICROSERVICEROLE_NAME = "Internal Microservice Role"; + + public static final String INTERNALMICROSERVICEROLE_CODE = "INTERNAL_MICROSERVICE_ROLE"; + + public static final String INTERNALMICROSERVICEUSER_NAME = "Internal Microservice User"; + + public static final String INTERNALMICROSERVICEUSER_USERNAME = "INTERNAL_USER"; + + public static final String INTERNALMICROSERVICEUSER_MOBILENO = "9999999999"; + + public static final String INTERNALMICROSERVICEUSER_TYPE = "SYSTEM"; + + public static final String SYSTEM_GENERATED = "SYSTEM_GENERATED"; + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/HRMSUtils.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/HRMSUtils.java new file mode 100644 index 00000000000..014a7a2c005 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/HRMSUtils.java @@ -0,0 +1,72 @@ +package org.egov.hrms.utils; + +import java.security.SecureRandom; +import java.util.List; +import java.util.Random; + +import org.egov.hrms.web.contract.EmployeeSearchCriteria; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +@Service +public class HRMSUtils { + + @Value("${egov.hrms.default.pwd.length}") + private Integer pwdLength; + + @Value("${egov.pwd.allowed.special.characters}") + private String allowedPasswordSpecialCharacters; + + /** + * Generates random password for the user to login. Process: + * 1. Takes a list of parameters for password + * 2. Applies a random select logic and generates a password of constant length. + * 3. The length of the password is configurable. + * + * @param params + * @return + */ + public String generatePassword(List params) { + StringBuilder password = new StringBuilder(); + SecureRandom random = new SecureRandom(); + params.add(allowedPasswordSpecialCharacters); + try { + for(int i = 0; i < params.size(); i++) { + String param = params.get(i); + String val; + if(param.length() == 1) + val = param; + else + val = param.split("")[random.nextInt(param.length() - 1)]; + if(val.equals(".") || val.equals("-") || val.equals(" ")) + password.append("x"); + else + password.append(val); + if(password.length() == pwdLength) + break; + else { + if(i == params.size() - 1) + i = 0; + } + } + }catch(Exception e) { + password.append("123456"); + } + + return password.toString().replaceAll("\\s+", ""); + } + + public boolean isAssignmentSearchReqd(EmployeeSearchCriteria criteria) { + return (! CollectionUtils.isEmpty(criteria.getPositions()) || null != criteria.getAsOnDate() + || !CollectionUtils.isEmpty(criteria.getDepartments()) || !CollectionUtils.isEmpty(criteria.getDesignations())); + } + + public String generateMobileNumber() { + Random random = new Random(); + int min = 100000000; + int max = 999999999; + int mobileNumber = random.nextInt(max - min + 1) + min; + return Integer.toString(mobileNumber); + } +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/ResponseInfoFactory.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/ResponseInfoFactory.java new file mode 100644 index 00000000000..e82744a00c0 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/utils/ResponseInfoFactory.java @@ -0,0 +1,26 @@ +package org.egov.hrms.utils; + + +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.stereotype.Component; + +@Component +public class ResponseInfoFactory { + + public ResponseInfo createResponseInfoFromRequestInfo(final RequestInfo requestInfo, final Boolean success) { + + final String apiId = requestInfo != null ? requestInfo.getApiId() : ""; + final String ver = requestInfo != null ? requestInfo.getVer() : ""; + Long ts = null; + if(requestInfo!=null) + ts= requestInfo.getTs(); + final String resMsgId = "uief87324"; // FIXME : Hard-coded + final String msgId = requestInfo != null ? requestInfo.getMsgId() : ""; + final String responseStatus = success ? "successful" : "failed"; + + return ResponseInfo.builder().apiId(apiId).ver(ver).ts(ts).resMsgId(resMsgId).msgId(msgId).resMsgId(resMsgId) + .status(responseStatus).build(); + } + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeRequest.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeRequest.java new file mode 100644 index 00000000000..87b2b42d207 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeRequest.java @@ -0,0 +1,76 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.web.contract; + +import java.util.List; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +import org.egov.common.contract.request.RequestInfo; +import org.egov.hrms.model.Employee; +import org.hibernate.validator.constraints.NotEmpty; +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Validated +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class EmployeeRequest { + + @NotNull + @JsonProperty("RequestInfo") + private RequestInfo requestInfo; + + @Valid + @NotEmpty + @JsonProperty("Employees") + private List employees; + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeResponse.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeResponse.java new file mode 100644 index 00000000000..6fb5141aeed --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeResponse.java @@ -0,0 +1,72 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.web.contract; + +import java.util.List; + +import org.egov.common.contract.response.ResponseInfo; +import org.egov.hrms.model.Employee; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; +@Builder +@AllArgsConstructor +@EqualsAndHashCode +@Getter +@NoArgsConstructor +@Setter +@ToString +public class EmployeeResponse { + + @JsonProperty("ResponseInfo") + private ResponseInfo responseInfo; + + @JsonProperty("Employees") + private List employees; + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeSearchCriteria.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeSearchCriteria.java new file mode 100644 index 00000000000..f5a3f9dfca6 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/EmployeeSearchCriteria.java @@ -0,0 +1,75 @@ +package org.egov.hrms.web.contract; + +import java.util.List; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.util.CollectionUtils; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +import javax.validation.constraints.Size; + + +@AllArgsConstructor +@Getter +@NoArgsConstructor +@Setter +@ToString +@Builder +public class EmployeeSearchCriteria { + + public List codes; + + public List names; + + public List departments; + + public List designations; + + public Long asOnDate; + + public List roles; + + public List ids; + + public List employeestatuses; + + public List employeetypes; + + public List uuids; + + public List positions; + + public Boolean isActive; + + @Size(max = 250) + public String tenantId; + + public String phone; + + public Integer offset; + + public Integer limit; + + private Boolean includeUnassigned = false; + + + public boolean isCriteriaEmpty(EmployeeSearchCriteria criteria) { + if(CollectionUtils.isEmpty(criteria.getCodes()) && CollectionUtils.isEmpty(criteria.getNames()) + && CollectionUtils.isEmpty(criteria.getDepartments()) && CollectionUtils.isEmpty(criteria.getDesignations()) + && CollectionUtils.isEmpty(criteria.getIds()) && CollectionUtils.isEmpty(criteria.getEmployeestatuses()) + && CollectionUtils.isEmpty(criteria.getEmployeetypes()) && CollectionUtils.isEmpty(criteria.getUuids()) + && CollectionUtils.isEmpty(criteria.getPositions()) && StringUtils.isEmpty(criteria.getTenantId()) + && CollectionUtils.isEmpty(criteria.getRoles()) && null == criteria.getAsOnDate()) { + return true; + }else { + return false; + } + } + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdGenerationRequest.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdGenerationRequest.java new file mode 100644 index 00000000000..9116d5835f3 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdGenerationRequest.java @@ -0,0 +1,64 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) <2015> eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ +package org.egov.hrms.web.contract; + +import java.util.List; + +import org.egov.common.contract.request.RequestInfo; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class IdGenerationRequest { + + @JsonProperty("RequestInfo") + private RequestInfo requestInfo; + + private List idRequests; + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdGenerationResponse.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdGenerationResponse.java new file mode 100644 index 00000000000..3bcb4d1a7f3 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdGenerationResponse.java @@ -0,0 +1,65 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) <2015> eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ +package org.egov.hrms.web.contract; + +import java.util.List; + +import org.egov.common.contract.response.ResponseInfo; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +@AllArgsConstructor +@NoArgsConstructor +public class IdGenerationResponse { + + private ResponseInfo responseInfo; + + private ResponseInfo ResponseInfo; + + private List idResponses; + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdRequest.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdRequest.java new file mode 100644 index 00000000000..cc3ac543675 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdRequest.java @@ -0,0 +1,63 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) <2015> eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ +package org.egov.hrms.web.contract; + +import javax.validation.constraints.NotNull; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class IdRequest { + + @NotNull + private String idName; + + @NotNull + private String tenantId; + + private String format; + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdResponse.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdResponse.java new file mode 100644 index 00000000000..ac167a59ddd --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/IdResponse.java @@ -0,0 +1,57 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) <2015> eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ +package org.egov.hrms.web.contract; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Getter +@Setter +@ToString +@AllArgsConstructor +@NoArgsConstructor +public class IdResponse { + + private String id; + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/RequestInfoWrapper.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/RequestInfoWrapper.java new file mode 100644 index 00000000000..ada1794cd4f --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/RequestInfoWrapper.java @@ -0,0 +1,64 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.web.contract; + +import javax.validation.constraints.NotNull; + +import org.egov.common.contract.request.RequestInfo; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RequestInfoWrapper { + + @NotNull + @JsonProperty("RequestInfo") + private RequestInfo requestInfo; + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/User.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/User.java new file mode 100644 index 00000000000..b0a004a6ae9 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/User.java @@ -0,0 +1,186 @@ +package org.egov.hrms.web.contract; + +import java.util.List; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Pattern; +import javax.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.egov.hrms.model.Role; +import org.egov.hrms.model.enums.GuardianRelation; +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@Validated +@AllArgsConstructor +@EqualsAndHashCode +@Getter +@NoArgsConstructor +@Setter +@ToString +@Builder +@JsonIgnoreProperties( + ignoreUnknown = true +) +public class User { + + @JsonProperty("id") + private Long id; + + @Size(max=64) + @JsonProperty("uuid") + private String uuid; + + @Size(max=64) + @JsonProperty("userServiceUuid") + private String userServiceUuid; + + @Size(max=180) + @JsonProperty("userName") + private String userName; + + @Size(max=64) + @JsonProperty("password") + private String password; + + @Size(max = 5) + @JsonProperty("salutation") + private String salutation; + + @NotNull + @Size(max=250) + @JsonProperty("name") + private String name; + + @JsonProperty("gender") + private String gender; + + @Pattern(regexp = "^[0-9]{9,10}$", message = "MobileNumber should be either 9 or 10 digit number") + @JsonProperty("mobileNumber") + private String mobileNumber; + + @Size(max=128) + @JsonProperty("emailId") + private String emailId; + + @Size(max=50) + @JsonProperty("altContactNumber") + private String altContactNumber; + + @Size(max=10) + @JsonProperty("pan") + private String pan; + + @Pattern(regexp = "^[0-9]{12}$", message = "AdharNumber should be 12 digit number") + @JsonProperty("aadhaarNumber") + private String aadhaarNumber; + + @Size(max=300) + @JsonProperty("permanentAddress") + private String permanentAddress; + + @Size(max=300) + @JsonProperty("permanentCity") + private String permanentCity; + + @Size(max=10) + @JsonProperty("permanentPinCode") + private String permanentPincode; + + @Size(max=300) + @JsonProperty("correspondenceCity") + private String correspondenceCity; + + @Size(max=10) + @JsonProperty("correspondencePinCode") + private String correspondencePincode; + + @Size(max=300) + @JsonProperty("correspondenceAddress") + private String correspondenceAddress; + + @JsonProperty("active") + private Boolean active; + + @NotNull + @JsonProperty("dob") + private Long dob; + + @JsonProperty("pwdExpiryDate") + private Long pwdExpiryDate; + + @Size(max=16) + @JsonProperty("locale") + private String locale; + + @Size(max=50) + @JsonProperty("type") + private String type; + + @Size(max=36) + @JsonProperty("signature") + private String signature; + + @JsonProperty("accountLocked") + private Boolean accountLocked; + + @JsonProperty("roles") + @Valid + private List roles; + + @Size(max=100) + @JsonProperty("fatherOrHusbandName") + private String fatherOrHusbandName; + + @JsonProperty("relationship") + private GuardianRelation relationship; + + @Size(max=32) + @JsonProperty("bloodGroup") + private String bloodGroup; + + @Size(max=300) + @JsonProperty("identificationMark") + private String identificationMark; + + @Size(max=36) + @JsonProperty("photo") + private String photo; + + @Size(max=64) + @JsonProperty("createdBy") + private String createdBy; + + @JsonProperty("createdDate") + private Long createdDate; + + @Size(max=64) + @JsonProperty("lastModifiedBy") + private String lastModifiedBy; + + @JsonProperty("lastModifiedDate") + private Long lastModifiedDate; + + @JsonProperty("otpReference") + private String otpReference; + + @Size(max=256) + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("rowVersion") + private Integer rowVersion; + + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/UserRequest.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/UserRequest.java new file mode 100644 index 00000000000..699dc079614 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/UserRequest.java @@ -0,0 +1,74 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.web.contract; + +import javax.validation.constraints.NotNull; + +import org.egov.common.contract.request.RequestInfo; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@AllArgsConstructor +@EqualsAndHashCode +@Getter +@NoArgsConstructor +@Setter +@ToString +@Builder +public class UserRequest { + + @NotNull + @JsonProperty("RequestInfo") + private RequestInfo requestInfo; + + @NotNull + @JsonProperty("User") + private User user; + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/UserResponse.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/UserResponse.java new file mode 100644 index 00000000000..285964a0a87 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/contract/UserResponse.java @@ -0,0 +1,69 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.web.contract; + +import java.util.ArrayList; +import java.util.List; + +import lombok.Builder; +import org.egov.common.contract.response.ResponseInfo; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; + +@AllArgsConstructor +@EqualsAndHashCode +@Getter +@NoArgsConstructor +@Setter +@ToString +@Builder +public class UserResponse { + + private ResponseInfo responseInfo; + + private List user = new ArrayList(); + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/controller/EmployeeController.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/controller/EmployeeController.java new file mode 100644 index 00000000000..0b780a74f6a --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/controller/EmployeeController.java @@ -0,0 +1,135 @@ +/* + * eGov suite of products aim to improve the internal efficiency,transparency, + * accountability and the service delivery of the government organizations. + * + * Copyright (C) 2016 eGovernments Foundation + * + * The updated version of eGov suite of products as by eGovernments Foundation + * is available at http://www.egovernments.org + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see http://www.gnu.org/licenses/ or + * http://www.gnu.org/licenses/gpl.html . + * + * In addition to the terms of the GPL license to be adhered to in using this + * program, the following additional terms are to be complied with: + * + * 1) All versions of this program, verbatim or modified must carry this + * Legal Notice. + * + * 2) Any misrepresentation of the origin of the material is prohibited. It + * is required that all modified versions of this material be marked in + * reasonable ways as different from the original version. + * + * 3) This license does not grant any rights to any user of the program + * with regards to rights under trademark law for use of the trade names + * or trademarks of eGovernments Foundation. + * + * In case of any queries, you can reach eGovernments Foundation at contact@egovernments.org. + */ + +package org.egov.hrms.web.controller; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.hrms.service.EmployeeService; +import org.egov.hrms.web.contract.EmployeeRequest; +import org.egov.hrms.web.contract.EmployeeResponse; +import org.egov.hrms.web.contract.EmployeeSearchCriteria; +import org.egov.hrms.web.contract.RequestInfoWrapper; +import org.egov.hrms.web.validator.EmployeeValidator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.BindingResult; +import org.springframework.web.bind.annotation.*; + +import javax.validation.Valid; +import java.util.HashMap; +import java.util.Map; + +@Slf4j +@RestController +@RequestMapping("/employees") +public class EmployeeController { + + @Autowired + private EmployeeService employeeService; + + @Autowired + private EmployeeValidator validator; + + + /** + * Maps Post Requests for _create & returns ResponseEntity of either + * EmployeeResponse type or ErrorResponse type + * + * @param employeeRequest + * @param bindingResult + * @return ResponseEntity + */ + @PostMapping(value = "/_create") + @ResponseBody + public ResponseEntity create(@RequestBody @Valid EmployeeRequest employeeRequest) { + validator.validateCreateEmployee(employeeRequest); + EmployeeResponse employeeResponse = employeeService.create(employeeRequest); + return new ResponseEntity<>(employeeResponse, HttpStatus.ACCEPTED); + } + + + /** + * Maps Post Requests for _update & returns ResponseEntity of either + * EmployeeResponse type or ErrorResponse type + * + * @param employeeRequest + * @param bindingResult + * @return ResponseEntity + */ + @PostMapping(value = "/_update") + @ResponseBody + public ResponseEntity update(@RequestBody @Valid EmployeeRequest employeeRequest) { + validator.validateUpdateEmployee(employeeRequest); + EmployeeResponse employeeResponse = employeeService.update(employeeRequest); + return new ResponseEntity<>(employeeResponse, HttpStatus.ACCEPTED); + } + + + /** + * Maps Post Requests for _search & returns ResponseEntity of either + * EmployeeResponse type or ErrorResponse type + * + * @param criteria + * @param bindingResult + * @return ResponseEntity + */ + @PostMapping(value = "/_search") + @ResponseBody + public ResponseEntity search(@RequestBody @Valid RequestInfoWrapper requestInfoWrapper, @ModelAttribute @Valid EmployeeSearchCriteria criteria) { + validator.validateSearchRequest(requestInfoWrapper.getRequestInfo(), criteria); + log.info(criteria.toString()); + EmployeeResponse employeeResponse = employeeService.search(criteria, requestInfoWrapper.getRequestInfo()); + return new ResponseEntity<>(employeeResponse,HttpStatus.OK); + } + + @PostMapping("_count") + @ResponseBody + private ResponseEntity count(@RequestParam("tenantId") String tenantId, @RequestBody RequestInfo requestInfo) { + + Map response = new HashMap<>(); + validator.validateEmployeeCountRequest(tenantId); + response = employeeService.getEmployeeCountResponse(requestInfo,tenantId); + return new ResponseEntity<>(response,HttpStatus.OK); + } + + +} \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/validator/EmployeeValidator.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/validator/EmployeeValidator.java new file mode 100644 index 00000000000..1494f83bdbc --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/validator/EmployeeValidator.java @@ -0,0 +1,817 @@ +package org.egov.hrms.web.validator; + +import java.util.*; +import java.util.stream.Collectors; +import java.time.ZoneId; +import java.time.temporal.ChronoUnit; +import java.util.Date; + +import com.jayway.jsonpath.JsonPath; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.contract.request.Role; +import org.egov.hrms.config.PropertiesManager; +import org.egov.hrms.model.*; +import org.egov.hrms.service.EmployeeService; +import org.egov.hrms.service.MDMSService; +import org.egov.hrms.service.UserService; +import org.egov.hrms.utils.ErrorConstants; +import org.egov.hrms.utils.HRMSConstants; +import org.egov.hrms.utils.HRMSUtils; +import org.egov.hrms.web.contract.EmployeeRequest; +import org.egov.hrms.web.contract.EmployeeResponse; +import org.egov.hrms.web.contract.EmployeeSearchCriteria; +import org.egov.hrms.web.contract.UserResponse; +import org.egov.mdms.model.MdmsResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.CollectionUtils; + +import lombok.extern.slf4j.Slf4j; + +import static org.egov.hrms.utils.ErrorConstants.CITIZEN_TYPE_CODE; + +@Service +@Slf4j +public class EmployeeValidator { + + @Autowired + private MDMSService mdmsService; + + @Autowired + private EmployeeService employeeService; + + @Autowired + private UserService userService; + + @Autowired + private PropertiesManager propertiesManager; + + @Autowired + private HRMSUtils hrmsUtils; + + /** + * Validates employee request for create. Validations include: + * 1. Validating MDMS codes + * 2. Performing data sanity checks + * + * @param request + */ + public void validateCreateEmployee(EmployeeRequest request) { + Map errorMap = new HashMap<>(); + validateExistingDuplicates(request ,errorMap); + validatePassword(request, errorMap); + if(!CollectionUtils.isEmpty(errorMap.keySet())) + throw new CustomException(errorMap); + Map> boundaryMap = getBoundaryList(request.getRequestInfo(),request.getEmployees().get(0)); + Map> mdmsData = mdmsService.getMDMSData(request.getRequestInfo(), request.getEmployees().get(0).getTenantId()); + if(!CollectionUtils.isEmpty(mdmsData.keySet())){ + request.getEmployees().stream().forEach(employee -> validateMdmsData(employee, errorMap, mdmsData,boundaryMap)); + } + if(!CollectionUtils.isEmpty(errorMap.keySet())) + throw new CustomException(errorMap); + } + + private void validatePassword(EmployeeRequest request, Map errorMap) { + List employees = request.getEmployees(); + if (!propertiesManager.isAutoGeneratePassword()) { + employees.forEach(employee -> { + if (StringUtils.isEmpty(employee.getUser().getPassword())) + errorMap.put(ErrorConstants.HRMS_PASSWORD_REQUIRED, ErrorConstants.HRMS_PASSWORD_REQUIRED_MSG); + }); + } + } + + public Map> getBoundaryList(RequestInfo requestInfo,Employee employee){ + List boundarytList = new ArrayList<>(); + Map> eachMasterMap = new HashMap<>(); + Map> masterData = new HashMap<>(); + if(!CollectionUtils.isEmpty(employee.getJurisdictions())){ + for(Jurisdiction jurisdiction: employee.getJurisdictions()){ + if(!boundarytList.contains(jurisdiction.getBoundary())) + boundarytList.add(jurisdiction.getBoundary()); + } + if(CollectionUtils.isEmpty(boundarytList)) + boundarytList.add(employee.getTenantId()); + } + + List boundaryResponseList = new ArrayList<>(); + for(String boundary: boundarytList){ + MdmsResponse responseLoc = mdmsService.fetchMDMSDataLoc(requestInfo, boundary); + if(!CollectionUtils.isEmpty(responseLoc.getMdmsRes())) + boundaryResponseList.add(responseLoc); + } + + if(!CollectionUtils.isEmpty(boundaryResponseList)){ + List tenantBoundaryData = new ArrayList<>(); + for(MdmsResponse responseLoc : boundaryResponseList){ + if(!CollectionUtils.isEmpty(responseLoc.getMdmsRes().keySet())) { + if(null != responseLoc.getMdmsRes().get(HRMSConstants.HRMS_MDMS_EGOV_LOCATION_MASTERS_CODE)) { + eachMasterMap = (Map) responseLoc.getMdmsRes().get(HRMSConstants.HRMS_MDMS_EGOV_LOCATION_MASTERS_CODE); + tenantBoundaryData.addAll(eachMasterMap.get(HRMSConstants.HRMS_MDMS_TENANT_BOUNDARY_CODE)); + } + } + } + if(!CollectionUtils.isEmpty(tenantBoundaryData)) + masterData.put(HRMSConstants.HRMS_MDMS_TENANT_BOUNDARY_CODE,tenantBoundaryData); + } + return masterData; + } + + /** + * Validates search request. Checks the following: + * 1. If a user who doesn't have access to open search is making an open search call. + * + * @param requestInfo + * @param criteria + */ + public void validateSearchRequest(RequestInfo requestInfo, EmployeeSearchCriteria criteria) { + Map errorMap = new HashMap<>(); + + if(requestInfo.getUserInfo() != null && requestInfo.getUserInfo().getType().equalsIgnoreCase(CITIZEN_TYPE_CODE) && !CollectionUtils.isEmpty(criteria.getIds())) + errorMap.put(ErrorConstants.HRMS_INVALID_SEARCH_CITIZEN_CODE, ErrorConstants.HRMS_INVALID_SEARCH_CITIZEN_MSG); + + if(criteria.isCriteriaEmpty(criteria)) { + String[] roles = propertiesManager.getOpenSearchEnabledRoles().split(","); + List reqroles = requestInfo.getUserInfo().getRoles().stream().map(Role::getCode).collect(Collectors.toList()); + boolean check = false; + for(String role : reqroles) { + if(Arrays.asList(roles).contains(role)) { + check = true; + break; + } + } + if(!check) { + errorMap.put(ErrorConstants.HRMS_INVALID_SEARCH_REQ_CODE, ErrorConstants.HRMS_INVALID_SEARCH_REQ_MSG); + } + } + if(null != criteria.getAsOnDate()) { + if(CollectionUtils.isEmpty(criteria.getDepartments()) || CollectionUtils.isEmpty(criteria.getDesignations())) + errorMap.put(ErrorConstants.HRMS_INVALID_SEARCH_AOD_CODE, ErrorConstants.HRMS_INVALID_SEARCH_AOD_MSG); + } + + if(!CollectionUtils.isEmpty( criteria.getRoles()) && StringUtils.isEmpty(criteria.getTenantId())) { + errorMap.put(ErrorConstants.HRMS_INVALID_SEARCH_ROLES_CODE, ErrorConstants.HRMS_INVALID_SEARCH_ROLES_MSG); + } + + if((!StringUtils.isEmpty(criteria.getPhone()) || !CollectionUtils.isEmpty(criteria.getNames())) && + StringUtils.isEmpty(criteria.getTenantId())) { + errorMap.put(ErrorConstants.HRMS_INVALID_SEARCH_USER_CODE, ErrorConstants.HRMS_INVALID_SEARCH_USER_MSG); + } + if(!CollectionUtils.isEmpty(errorMap.keySet())) + throw new CustomException(errorMap); + } + + /** + * Checks if the employee being created is duplicate with the following: + * 1. Validating mobile number + * 2. Validating username + * + * @param request + * @param errorMap + */ + private void validateExistingDuplicates(EmployeeRequest request, Map errorMap) { + List employees = request.getEmployees(); + validateDataUniqueness(employees,errorMap); + validateUserMobile(employees,errorMap,request.getRequestInfo()); + validateUserName(employees,errorMap,request.getRequestInfo()); + } + + /** + * Checks duplicate occurance of mobileNumber and code for bulk request + * + * @param employees + * @param errorMap + */ + private void validateDataUniqueness(List employees, Map errorMap) { + HashSet < String> codes = new HashSet<>(); + employees.forEach(employee -> { + if(null != employee.getCode()){ + if (codes.contains(employee.getCode())) + errorMap.put(ErrorConstants.HRMS_BULK_CREATE_DUPLICATE_EMPCODE_CODE,ErrorConstants.HRMS_BULK_CREATE_DUPLICATE_EMPCODE_MSG); + else + codes.add(employee.getCode()); + } + }); + } + + /** + * Checks if the mobile number used in the request is duplicate. + * + * @param employees + * @param errorMap + * @param requestInfo + */ + private void validateUserMobile(List employees, Map errorMap, RequestInfo requestInfo) { + HashSet < String> mobileNos = new HashSet<>(); + employees.forEach(employee -> { + boolean autoGenerateMobileNumber = employee.getUser().getMobileNumber() == null || + employee.getUser().getMobileNumber().isEmpty(); + int maxRetryCount = 5; + if (autoGenerateMobileNumber) { + int retryCount = 0; + String generatedMobileNumber = hrmsUtils.generateMobileNumber(); + while ((retryCount < maxRetryCount) && mobileNos.contains(generatedMobileNumber)) { + generatedMobileNumber = hrmsUtils.generateMobileNumber(); + retryCount++; + } + employee.getUser().setMobileNumber(generatedMobileNumber); + } + if(mobileNos.contains(employee.getUser().getMobileNumber())) + errorMap.put(ErrorConstants.HRMS_BULK_CREATE_DUPLICATE_MOBILE_CODE, ErrorConstants.HRMS_BULK_CREATE_DUPLICATE_MOBILE_MSG ); + else + mobileNos.add(employee.getUser().getMobileNumber()); + Map userSearchCriteria = new HashMap<>(); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID,employee.getTenantId()); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_MOBILENO,employee.getUser().getMobileNumber()); + UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); + if (autoGenerateMobileNumber && !CollectionUtils.isEmpty(userResponse.getUser())) { + int retryCount = 0; + String generatedMobileNumber = hrmsUtils.generateMobileNumber(); + while ((retryCount < maxRetryCount) && !CollectionUtils.isEmpty(userResponse.getUser())) { + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_MOBILENO,generatedMobileNumber); + userResponse = userService.getUser(requestInfo, userSearchCriteria); + retryCount++; + } + employee.getUser().setMobileNumber(generatedMobileNumber); + } + if(!CollectionUtils.isEmpty(userResponse.getUser())){ + errorMap.put(ErrorConstants.HRMS_USER_EXIST_MOB_CODE, + ErrorConstants.HRMS_USER_EXIST_MOB_MSG); + } + }); + } + + /** + * Checks if the username is duplicate + * + * @param employees + * @param errorMap + * @param requestInfo + */ + private void validateUserName(List employees, Map errorMap, RequestInfo requestInfo) { + employees.forEach(employee -> { + if(!StringUtils.isEmpty(employee.getCode())){ + Map userSearchCriteria = new HashMap<>(); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID,employee.getTenantId()); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_USERNAME,employee.getCode()); + UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); + if(!CollectionUtils.isEmpty(userResponse.getUser())){ + errorMap.put(ErrorConstants.HRMS_USER_EXIST_USERNAME_CODE, + ErrorConstants.HRMS_USER_EXIST_USERNAME_MSG); + } + } + }); + } + + /** + * Validates MDMS codes of the request. + * + * @param employee + * @param errorMap + * @param mdmsData + */ + private void validateMdmsData(Employee employee, Map errorMap, Map> mdmsData, Map> boundaryMap) { + validateEmployee(employee, errorMap, mdmsData); + validateAssignments(employee, errorMap, mdmsData); + validateServiceHistory(employee, errorMap, mdmsData); + validateJurisdicton(employee, errorMap, mdmsData, boundaryMap); + validateEducationalDetails(employee, errorMap, mdmsData); + validateDepartmentalTest(employee, errorMap, mdmsData); + } + + + /** + * Performs checks for maintaining data consistency + * @param employee + * @param errorMap + * @param mdmsData + * @param existingEmp + * @param requestInfo + */ + public void validateDataConsistency(Employee employee, Map errorMap, Map> mdmsData, Employee existingEmp, RequestInfo requestInfo) { + validateUserData(existingEmp,employee,errorMap, requestInfo); + validateConsistencyAssignment(existingEmp,employee,errorMap); + validateConsistencyJurisdiction(existingEmp,employee,errorMap); + validateConsistencyDepartmentalTest(existingEmp,employee,errorMap); + validateConsistencyEducationalDetails(existingEmp,employee,errorMap); + validateConsistencyServiceHistory(existingEmp, employee, errorMap); + validateConsistencyEmployeeDocument(existingEmp, employee, errorMap); + validateConsistencyDeactivationDetails(existingEmp, employee, errorMap); + if(!employee.getIsActive()) + validateDeactivationDetails(existingEmp, employee, errorMap, mdmsData); + if(employee.getIsActive() && employee.getReActivateEmployee()) + validateReactivationDetails(existingEmp, employee, errorMap, mdmsData); + } + + /** + * Check whether employee code has changed + * @param existingEmp + * @param employee + * @param errorMap + * @param requestInfo + */ + private void validateUserData(Employee existingEmp, Employee employee, Map errorMap, RequestInfo requestInfo) { + if(!employee.getCode().equals(existingEmp.getCode())) + errorMap.put(ErrorConstants.HRMS_UPDATE_EMPLOYEE_CODE_CHANGE_CODE,ErrorConstants.HRMS_UPDATE_EMPLOYEE_CODE_CHANGE_MSG); + if(!employee.getUser().getMobileNumber().equals(existingEmp.getUser().getMobileNumber())){ + Map userSearchCriteria = new HashMap<>(); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID,employee.getTenantId()); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_MOBILENO,employee.getUser().getMobileNumber()); + UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); + if(!CollectionUtils.isEmpty(userResponse.getUser())){ + if(!employee.getUser().getUuid().equals(userResponse.getUser().get(0).getUuid())){ + errorMap.put(ErrorConstants.HRMS_UPDATE_EXISTING_MOBNO_CODE,ErrorConstants.HRMS_UPDATE_EXISTING_MOBNO_MSG); + } + } + + + } + + } + + /** + * Checks the following: + * 1. Whether the mobile number is valid + * 2. Whether the roles are valid + * 3. Whether the employee status mentioned is valid. + * 4. Whether the employee type mentioned is valid + * 5. Whether the date of appointment of the employee is valid. + * + * @param employee + * @param errorMap + * @param mdmsData + */ + private void validateEmployee(Employee employee, Map errorMap, Map> mdmsData) { + + if(employee.getUser().getMobileNumber().length() != 10 && employee.getUser().getMobileNumber().length() != 9) { + errorMap.put(ErrorConstants.HRMS_INVALID_MOB_NO_CODE, ErrorConstants.HRMS_INVALID_MOB_NO_MSG); + } + + if(CollectionUtils.isEmpty(employee.getUser().getRoles())) + errorMap.put(ErrorConstants.HRMS_MISSING_ROLES_CODE, ErrorConstants.HRMS_INVALID_ROLES_MSG); + else { + for(org.egov.hrms.model.Role role: employee.getUser().getRoles()) { + if(!mdmsData.get(HRMSConstants.HRMS_MDMS_ROLES_CODE).contains(role.getCode())) + errorMap.put(ErrorConstants.HRMS_INVALID_ROLE_CODE, ErrorConstants.HRMS_INVALID_ROLE_MSG ); + } + } + /*if(!mdmsData.get(HRMSConstants.HRMS_MDMS_EMP_STATUS_CODE).contains(employee.getEmployeeStatus())) + errorMap.put(ErrorConstants.HRMS_INVALID_EMP_STATUS_CODE, ErrorConstants.HRMS_INVALID_EMP_STATUS_MSG);*/ + if(!mdmsData.get(HRMSConstants.HRMS_MDMS_EMP_TYPE_CODE).contains(employee.getEmployeeType())) + errorMap.put(ErrorConstants.HRMS_INVALID_EMP_TYPE_CODE, ErrorConstants.HRMS_INVALID_EMP_TYPE_MSG); + if(null != employee.getDateOfAppointment() && employee.getDateOfAppointment() > new Date().getTime()) + errorMap.put(ErrorConstants.HRMS_INVALID_DATE_OF_APPOINTMENT_CODE, ErrorConstants.HRMS_INVALID_DATE_OF_APPOINTMENT_MSG); + if(null != employee.getUser().getDob()) { + if(employee.getUser().getDob() >= new Date().getTime()) + errorMap.put(ErrorConstants.HRMS_INVALID_DOB_CODE, ErrorConstants.HRMS_INVALID_DOB_MSG); + if(null != employee.getDateOfAppointment() && employee.getDateOfAppointment() < employee.getUser().getDob()) + errorMap.put(ErrorConstants.HRMS_INVALID_DATE_OF_APPOINTMENT_DOB_CODE, ErrorConstants.HRMS_INVALID_DATE_OF_APPOINTMENT_DOB_MSG); + } + } + + /** + * Checks the following: + * 1. If there is more than one current assignment. + * 2. if period of assignment of any of the assignments overlap with that of others. + * 3. if the Department code is valid + * 4. If the Designation code is valid + * 5. If the assignment dates are valid + * + * @param employee + * @param errorMap + * @param mdmsData + */ + private void validateAssignments(Employee employee, Map errorMap, Map> mdmsData) { + if (employee.getAssignments() != null && !employee.getAssignments().isEmpty()) { + List currentAssignments = employee.getAssignments().stream().filter(assignment -> assignment.getIsCurrentAssignment()).collect(Collectors.toList()); + if (currentAssignments.size() != 1) { + errorMap.put(ErrorConstants.HRMS_INVALID_CURRENT_ASSGN_CODE, ErrorConstants.HRMS_INVALID_CURRENT_ASSGN_MSG); + } + employee.getAssignments().sort(new Comparator() { + @Override + public int compare(Assignment assignment1, Assignment assignment2) { + return assignment1.getFromDate().compareTo(assignment2.getFromDate()); + } + }); + int length = employee.getAssignments().size(); + boolean overlappingCheck = false; + for (int i = 0; i < length - 1; i++) { + if (null != employee.getAssignments().get(i).getToDate() && employee.getAssignments().get(i).getToDate() > employee.getAssignments().get(i + 1).getFromDate()) + overlappingCheck = true; + } + if (overlappingCheck) + errorMap.put(ErrorConstants.HRMS_OVERLAPPING_ASSGN_CODE, ErrorConstants.HRMS_OVERLAPPING_ASSGN_MSG); + + for (Assignment assignment : employee.getAssignments()) { + if (!assignment.getIsCurrentAssignment() && !CollectionUtils.isEmpty(currentAssignments) && null != assignment.getToDate() && currentAssignments.get(0).getFromDate() < assignment.getToDate()) + errorMap.put(ErrorConstants.HRMS_OVERLAPPING_ASSGN_CURRENT_CODE, ErrorConstants.HRMS_OVERLAPPING_ASSGN_CURRENT_MSG); + if (!mdmsData.get(HRMSConstants.HRMS_MDMS_DEPT_CODE).contains(assignment.getDepartment())) + errorMap.put(ErrorConstants.HRMS_INVALID_DEPT_CODE, ErrorConstants.HRMS_INVALID_DEPT_MSG); + /*if (!assignment.getDesignation().equalsIgnoreCase("undefined") && + !mdmsData.get(HRMSConstants.HRMS_MDMS_DESG_CODE).contains(assignment.getDesignation())) + errorMap.put(ErrorConstants.HRMS_INVALID_DESG_CODE, ErrorConstants.HRMS_INVALID_DESG_MSG);*/ + if (assignment.getIsCurrentAssignment() && null != assignment.getToDate()) + errorMap.put(ErrorConstants.HRMS_INVALID_ASSIGNMENT_CURRENT_TO_DATE_CODE, ErrorConstants.HRMS_INVALID_ASSIGNMENT_CURRENT_TO_DATE_MSG); + if (!assignment.getIsCurrentAssignment() && null == assignment.getToDate()) + errorMap.put(ErrorConstants.HRMS_INVALID_ASSIGNMENT_NON_CURRENT_TO_DATE_CODE, ErrorConstants.HRMS_INVALID_ASSIGNMENT_NON_CURRENT_TO_DATE_MSG); + if (null != assignment.getToDate() && assignment.getFromDate() > assignment.getToDate()) + errorMap.put(ErrorConstants.HRMS_INVALID_ASSIGNMENT_PERIOD_CODE, ErrorConstants.HRMS_INVALID_ASSIGNMENT_PERIOD_MSG); + if (employee.getUser().getDob() != null) + if (assignment.getFromDate() < employee.getUser().getDob() || (null != assignment.getToDate() && assignment.getToDate() < employee.getUser().getDob())) + errorMap.put(ErrorConstants.HRMS_INVALID_ASSIGNMENT_DATES_CODE, ErrorConstants.HRMS_INVALID_ASSIGNMENT_DATES_MSG); + if (null != employee.getDateOfAppointment() && assignment.getFromDate() < employee.getDateOfAppointment()) + errorMap.put(ErrorConstants.HRMS_INVALID_ASSIGNMENT_DATES_APPOINTMENT_CODE, ErrorConstants.HRMS_INVALID_ASSIGNMENT_DATES_APPOINTMENT_MSG); + + } + } + + } + + /** + * Checks the follwing: + * 1. If the status of service is valid. + * 2. If the service period is valid. + * 3. If the service dates is valid. + * 4. If there is more than 1 current Positions. + * 5. If service end date is null for current position + * + * @param employee + * @param errorMap + * @param mdmsData + */ + private void validateServiceHistory(Employee employee, Map errorMap, Map> mdmsData) { + if(!CollectionUtils.isEmpty(employee.getServiceHistory())){ + List currentService = employee.getServiceHistory().stream().filter(serviceHistory -> null!= serviceHistory.getIsCurrentPosition() && serviceHistory.getIsCurrentPosition()).collect(Collectors.toList()); + if(currentService.size() > 1){ + errorMap.put(ErrorConstants.HRMS_INVALID_CURRENT_SERVICE_CODE, ErrorConstants.HRMS_INVALID_CURRENT_SERVICE_MSG); + } + for(ServiceHistory history: employee.getServiceHistory()) { + if( (null== history.getIsCurrentPosition() || !history.getIsCurrentPosition()) && !CollectionUtils.isEmpty(currentService) && null != currentService.get(0).getServiceFrom() && null != history.getServiceTo() && currentService.get(0).getServiceFrom() new Date().getTime()) || (null != history.getServiceTo() && history.getServiceTo() > new Date().getTime()) + || (null != history.getServiceFrom() && null != history.getServiceTo() && history.getServiceFrom() > history.getServiceTo())) + errorMap.put(ErrorConstants.HRMS_INVALID_SERVICE_PERIOD_CODE, ErrorConstants.HRMS_INVALID_SERVICE_PERIOD_MSG); + if(employee.getUser().getDob()!=null ) + if((null != history.getServiceFrom() && history.getServiceFrom() < employee.getUser().getDob()) || (null != history.getServiceTo() && history.getServiceTo() < employee.getUser().getDob())) + errorMap.put(ErrorConstants.HRMS_INVALID_SERVICE_DATES_CODE, ErrorConstants.HRMS_INVALID_SERVICE_DATES_MSG); + } + } + } + + /** + * Checks the following: + * 1. If the qualification is valid. + * 2. If the specialization provided is valid. + * 3. If the year of passing is valid. + * + * @param employee + * @param errorMap + * @param mdmsData + */ + private void validateEducationalDetails(Employee employee, Map errorMap, Map> mdmsData) { + if(!CollectionUtils.isEmpty(employee.getEducation())){ + for(EducationalQualification education : employee.getEducation()) { + if(null!= education.getQualification() && !mdmsData.get(HRMSConstants.HRMS_MDMS_QUALIFICATION_CODE).contains(education.getQualification())) + errorMap.put(ErrorConstants.HRMS_INVALID_QUALIFICATION_CODE, ErrorConstants.HRMS_INVALID_QUALIFICATION_MSG); + if(null != education.getStream() && !mdmsData.get(HRMSConstants.HRMS_MDMS_STREAMS_CODE).contains(education.getStream())) + errorMap.put(ErrorConstants.HRMS_INVALID_EDUCATIONAL_STREAM_CODE, ErrorConstants.HRMS_INVALID_EDUCATIONAL_STREAM_MSG); + if(null != education.getYearOfPassing() && education.getYearOfPassing() > new Date().getTime()){ + errorMap.put(ErrorConstants.HRMS_INVALID_EDUCATIONAL_PASSING_YEAR_CODE, ErrorConstants.HRMS_INVALID_EDUCATIONAL_PASSING_YEAR_MSG); + } + } + } + } + + /** + * 1. Checks if there is atleast 1 active jurisdiction + * 2. If hierarchy is valid + * 3. If boundaryType is valid + * 4. If boundary is valid + * + * @param employee + * @param errorMap + * @param mdmsData + */ + private void validateJurisdicton(Employee employee, Map errorMap, Map> mdmsData,Map> boundaryMap) { + if(CollectionUtils.isEmpty(employee.getJurisdictions().stream().filter(jurisdiction -> null == jurisdiction.getIsActive() || jurisdiction.getIsActive() && jurisdiction.getIsActive() ).collect(Collectors.toList()))){ + errorMap.put(ErrorConstants.HRMS_INVALID_JURISDICTION_ACTIIEV_NULL_CODE,ErrorConstants.HRMS_INVALID_JURISDICTION_ACTIIEV_NULL_MSG); + } + for(Jurisdiction jurisdiction: employee.getJurisdictions()) { + String hierarchy_type_path = String.format(HRMSConstants.HRMS_TENANTBOUNDARY_HIERARCHY_JSONPATH,jurisdiction.getBoundary()); + String boundary_type_path = String.format(HRMSConstants.HRMS_TENANTBOUNDARY_BOUNDARY_TYPE_JSONPATH,jurisdiction.getHierarchy(),jurisdiction.getBoundary()); + String boundary_value_path = String.format(HRMSConstants.HRMS_TENANTBOUNDARY_BOUNDARY_VALUE_JSONPATH,jurisdiction.getHierarchy(),jurisdiction.getBoundary()); + List hierarchyTypes = JsonPath.read(boundaryMap,hierarchy_type_path); + List boundaryTypes = JsonPath.read(boundaryMap,boundary_type_path); + List boundaryValues = JsonPath.read(boundaryMap,boundary_value_path); + if(!hierarchyTypes.contains(jurisdiction.getHierarchy())) + errorMap.put(ErrorConstants.HRMS_INVALID_JURISDICTION_HEIRARCHY_CODE, ErrorConstants.HRMS_INVALID_JURISDICTION_HEIRARCHY_MSG); + if(!boundaryTypes.contains(jurisdiction.getBoundaryType())) + errorMap.put(ErrorConstants.HRMS_INVALID_JURISDICTION_BOUNDARY_TYPE_CODE, ErrorConstants.HRMS_INVALID_JURISDICTION_BOUNDARY_TYPE_MSG); + if(!boundaryValues.contains(jurisdiction.getBoundary())) + errorMap.put(ErrorConstants.HRMS_INVALID_JURISDICTION_BOUNDARY_CODE, ErrorConstants.HRMS_INVALID_JURISDICTION_BOUNDARY_MSG); + } + + + } + + + /** + * Checks the follwing: + * 1. If the dept test is valid. + * 2. If the year of passing is valid. + * + * @param employee + * @param errorMap + * @param mdmsData + */ + private void validateDepartmentalTest(Employee employee, Map errorMap, Map> mdmsData) { + if(!CollectionUtils.isEmpty(employee.getTests())) { + for (DepartmentalTest test : employee.getTests()) { + if (null!=test.getTest() && !mdmsData.get(HRMSConstants.HRMS_MDMS_DEPT_TEST_CODE).contains(test.getTest())) + errorMap.put(ErrorConstants.HRMS_INVALID_DEPARTMENTAL_TEST_CODE, ErrorConstants.HRMS_INVALID_DEPARTMENTAL_TEST_MSG ); + if (null!= test.getYearOfPassing() && test.getYearOfPassing() > new Date().getTime()) { + errorMap.put(ErrorConstants.HRMS_INVALID_DEPARTMENTAL_TEST_PASSING_YEAR_CODE, ErrorConstants.HRMS_INVALID_DEPARTMENTAL_TEST_PASSING_YEAR_MSG); + } + + } + } + } + + /** + * Validates if the deactivation details are provided every time an employee is deactivated. + * @param existingEmp + * @param updatedEmployeeData + * @param errorMap + * @param mdmsData + */ + private void validateDeactivationDetails(Employee existingEmp, Employee updatedEmployeeData, Map errorMap, Map> mdmsData){ + if(!CollectionUtils.isEmpty(updatedEmployeeData.getDeactivationDetails())) { + Date date = new Date(); + Date currentDateStartTime = Date.from(date.toInstant().atZone(ZoneId.systemDefault()) + .truncatedTo(ChronoUnit.DAYS).toInstant()); + for (DeactivationDetails deactivationDetails : updatedEmployeeData.getDeactivationDetails()) { + if (deactivationDetails.getId()==null){ + if(updatedEmployeeData.getIsActive()){ + errorMap.put(ErrorConstants.HRMS_INVALID_DEACT_REQUEST_CODE, ErrorConstants.HRMS_INVALID_DEACT_REQUEST_MSG); + } + } + if(deactivationDetails.getEffectiveFrom() > new Date().getTime()) + errorMap.put(ErrorConstants.HRMS_UPDATE_DEACT_DETAILS_INCORRECT_EFFECTIVEFROM_CODE, ErrorConstants.HRMS_UPDATE_DEACT_DETAILS_INCORRECT_EFFECTIVEFROM_MSG); + + if(deactivationDetails.getEffectiveFrom() < currentDateStartTime.getTime()) + errorMap.put(ErrorConstants.HRMS_UPDATE_DEACT_DETAILS_INCORRECT_EFFECTIVEFROM_CODE, ErrorConstants.HRMS_UPDATE_DEACT_DETAILS_INCORRECT_EFFECTIVEFROM_MSG); + + if (! mdmsData.get(HRMSConstants.HRMS_MDMS_DEACT_REASON_CODE).contains(deactivationDetails.getReasonForDeactivation())) + errorMap.put(ErrorConstants.HRMS_INVALID_DEACT_REASON_CODE, ErrorConstants.HRMS_INVALID_DEACT_REASON_MSG); + } + } + } + + private void validateReactivationDetails(Employee existingEmp, Employee updatedEmployeeData, Map errorMap, Map> mdmsData){ + if(!CollectionUtils.isEmpty(updatedEmployeeData.getReactivationDetails())) { + for (ReactivationDetails reactivationDetails : updatedEmployeeData.getReactivationDetails()) { + Boolean isValidDetails = existingEmp.getDeactivationDetails().get(0).getEffectiveFrom() <= reactivationDetails.getEffectiveFrom() + && reactivationDetails.getEffectiveFrom() <= new Date().getTime(); + if(!isValidDetails) + errorMap.put(ErrorConstants.HRMS_UPDATE_REACT_DETAILS_INCORRECT_EFFECTIVEFROM_CODE, ErrorConstants.HRMS_UPDATE_REACT_DETAILS_INCORRECT_EFFECTIVEFROM_MSG); + + } + } + } + + /** + * Validates the employee request for update. Validates the following: + * 1. MDMS codes in the request + * 2. Performs data consistency checks. + * + * @param request + */ + public void validateUpdateEmployee(EmployeeRequest request) { + Map errorMap = new HashMap<>(); + Map> boundaryMap = getBoundaryList(request.getRequestInfo(),request.getEmployees().get(0)); + Map> mdmsData = mdmsService.getMDMSData(request.getRequestInfo(), request.getEmployees().get(0).getTenantId()); + List uuidList = request.getEmployees().stream().map(Employee :: getUuid).collect(Collectors.toList()); + EmployeeResponse existingEmployeeResponse = employeeService.search(EmployeeSearchCriteria.builder().uuids(uuidList) + .tenantId(request.getEmployees().get(0).getTenantId()) + .build(),request.getRequestInfo()); + List existingEmployees = existingEmployeeResponse.getEmployees(); + for(Employee employee: request.getEmployees()){ + if(validateEmployeeForUpdate(employee, errorMap)){ + if(!existingEmployees.isEmpty()){ + Employee existingEmp = existingEmployees.stream().filter(existingEmployee -> existingEmployee.getUuid().equals(employee.getUuid())).findFirst().get(); + validateDataConsistency(employee, errorMap, mdmsData, existingEmp, request.getRequestInfo()); + } + else + errorMap.put(ErrorConstants.HRMS_UPDATE_EMPLOYEE_NOT_EXIST_CODE, ErrorConstants.HRMS_UPDATE_EMPLOYEE_NOT_EXIST_MSG); + } + validateMdmsData(employee, errorMap, mdmsData,boundaryMap); + } + if(!CollectionUtils.isEmpty(errorMap.keySet())) { + throw new CustomException(errorMap); + } + + + } + + /** + * Checks if the ID, UUID and Code are present in the update request + * + * @param employee + * @param errorMap + * @return + */ + private boolean validateEmployeeForUpdate(Employee employee, Map errorMap) { + boolean isvalid = true; + if(employee.getId() == null){ + errorMap.put(ErrorConstants.HRMS_UPDATE_NULL_ID_CODE, ErrorConstants.HRMS_UPDATE_NULL_ID_MSG); + isvalid=false; + } + if(StringUtils.isEmpty(employee.getCode())){ + errorMap.put(ErrorConstants.HRMS_UPDATE_NULL_CODE_CODE, ErrorConstants.HRMS_UPDATE_NULL_CODE_MSG); + isvalid=false; + } + if(StringUtils.isEmpty(employee.getUuid())){ + errorMap.put(ErrorConstants.HRMS_UPDATE_NULL_UUID_CODE, ErrorConstants.HRMS_UPDATE_NULL_UUID_MSG); + isvalid=false; + } + + return isvalid; + + } + + /** + * Juridictions once created in the system cannot be deleted, they can however be changed. Validates that condition + * + * @param existingEmp + * @param updatedEmployeeData + * @param errorMap + */ + private void validateConsistencyJurisdiction(Employee existingEmp, Employee updatedEmployeeData, Map errorMap) { + boolean check = + updatedEmployeeData.getJurisdictions().stream() + .map(jurisdiction -> jurisdiction.getId()) + .collect(Collectors.toList()) + .containsAll(existingEmp.getJurisdictions().stream() + .map(jurisdiction -> jurisdiction.getId()) + .collect(Collectors.toList())); + if(!check){ + errorMap.put(ErrorConstants.HRMS_UPDATE_JURISDICTION_INCOSISTENT_CODE, ErrorConstants.HRMS_UPDATE_JURISDICTION_INCOSISTENT_MSG); + } + + } + + /** + * Assignments once created in the system cannot be deleted, they can however be changed. Validates that condition + * + * @param existingEmp + * @param updatedEmployeeData + * @param errorMap + */ + private void validateConsistencyAssignment(Employee existingEmp, Employee updatedEmployeeData, Map errorMap) { + if (updatedEmployeeData.getAssignments() != null && existingEmp.getAssignments() != null) { + boolean check = + updatedEmployeeData.getAssignments().stream() + .map(assignment -> assignment.getId()) + .collect(Collectors.toList()) + .containsAll(existingEmp.getAssignments().stream() + .map(assignment -> assignment.getId()) + .collect(Collectors.toList())); + if (!check) { + errorMap.put(ErrorConstants.HRMS_UPDATE_ASSIGNEMENT_INCOSISTENT_CODE, ErrorConstants.HRMS_UPDATE_ASSIGNEMENT_INCOSISTENT_MSG); + } + } + } + + /** + * Dept Test details once created in the system cannot be deleted, they can however be changed. Validates that condition + * @param existingEmp + * @param updatedEmployeeData + * @param errorMap + */ + private void validateConsistencyDepartmentalTest(Employee existingEmp, Employee updatedEmployeeData, Map errorMap){ + if(!CollectionUtils.isEmpty(updatedEmployeeData.getTests())){ + boolean check = + updatedEmployeeData.getTests().stream() + .map(test -> test.getId()) + .collect(Collectors.toList()) + .containsAll(existingEmp.getTests().stream() + .map(test -> test.getId()) + .collect(Collectors.toList())); + if(!check){ + errorMap.put(ErrorConstants.HRMS_UPDATE_TESTS_INCOSISTENT_CODE, ErrorConstants.HRMS_UPDATE_TESTS_INCOSISTENT_MSG); + } + } + + } + + /** + * Education Details once created in the system cannot be deleted, they can however be changed. Validates that condition + * + * @param existingEmp + * @param updatedEmployeeData + * @param errorMap + */ + private void validateConsistencyEducationalDetails(Employee existingEmp, Employee updatedEmployeeData, Map errorMap){ + if(!CollectionUtils.isEmpty(updatedEmployeeData.getEducation())){ + boolean check = + updatedEmployeeData.getEducation().stream() + .map(educationalQualification -> educationalQualification.getId()) + .collect(Collectors.toList()) + .containsAll(existingEmp.getEducation().stream() + .map(educationalQualification -> educationalQualification.getId()) + .collect(Collectors.toList())); + if(!check){ + errorMap.put(ErrorConstants.HRMS_UPDATE_EDUCATION_INCOSISTENT_CODE, ErrorConstants.HRMS_UPDATE_EDUCATION_INCOSISTENT_MSG); + } + } + } + + /** + * Service History once created in the system cannot be deleted, they can however be changed. Validates that condition + * + * @param existingEmp + * @param updatedEmployeeData + * @param errorMap + */ + private void validateConsistencyServiceHistory(Employee existingEmp, Employee updatedEmployeeData, Map errorMap){ + if(!CollectionUtils.isEmpty(updatedEmployeeData.getServiceHistory())){ + boolean check = + updatedEmployeeData.getServiceHistory().stream() + .map(serviceHistory -> serviceHistory.getId()) + .collect(Collectors.toList()) + .containsAll(existingEmp.getServiceHistory().stream() + .map(serviceHistory -> serviceHistory.getId()) + .collect(Collectors.toList())); + if(!check){ + errorMap.put(ErrorConstants.HRMS_UPDATE_SERVICE_HISTORY_INCOSISTENT_CODE, ErrorConstants.HRMS_UPDATE_SERVICE_HISTORY_INCOSISTENT_MSG); + } + + } + + } + + /** + * Documents once created in the system cannot be deleted, they can however be changed. Validates that condition + * + * @param existingEmp + * @param updatedEmployeeData + * @param errorMap + */ + private void validateConsistencyEmployeeDocument(Employee existingEmp, Employee updatedEmployeeData, Map errorMap){ + if(!CollectionUtils.isEmpty(updatedEmployeeData.getDocuments())){ + boolean check = + updatedEmployeeData.getDocuments().stream() + .map(employeeDocument -> employeeDocument.getId()) + .collect(Collectors.toList()) + .containsAll(existingEmp.getDocuments().stream() + .map(employeeDocument -> employeeDocument.getId()) + .collect(Collectors.toList())); + if (!check) { + errorMap.put(ErrorConstants.HRMS_UPDATE_DOCUMENT_INCOSISTENT_CODE, ErrorConstants.HRMS_UPDATE_DOCUMENT_INCOSISTENT_MSG); + } + } + + } + + /** + * Deactivation Details once created in the system cannot be deleted, they can however be changed. Validates that condition + * + * @param existingEmp + * @param updatedEmployeeData + * @param errorMap + */ + private void validateConsistencyDeactivationDetails(Employee existingEmp, Employee updatedEmployeeData, Map errorMap){ + if(!CollectionUtils.isEmpty(updatedEmployeeData.getDeactivationDetails())){ + boolean check = + updatedEmployeeData.getDeactivationDetails().stream() + .map(deactivationDetails -> deactivationDetails.getId()) + .collect(Collectors.toList()) + .containsAll(existingEmp.getDeactivationDetails().stream() + .map(employeeDocument -> employeeDocument.getId()) + .collect(Collectors.toList())); + if (!check) { + errorMap.put(ErrorConstants.HRMS_UPDATE_DEACT_DETAILS_INCOSISTENT_CODE, ErrorConstants.HRMS_UPDATE_DEACT_DETAILS_INCOSISTENT_MSG); + } + } + + } + + public void validateEmployeeCountRequest(String tenantId){ + Map errorMap = new HashMap<>(); + if(StringUtils.isEmpty(tenantId)) + errorMap.put(ErrorConstants.HRMS_EMPLOYEE_COUNT_ERROR_CODE, ErrorConstants.HRMS_EMPLOYEE_COUNT_ERROR_MSG); + + if(!CollectionUtils.isEmpty(errorMap.keySet())) { + throw new CustomException(errorMap); + } + } + +} diff --git a/core-services/egov-hrms/src/main/resources/application.properties b/core-services/egov-hrms/src/main/resources/application.properties new file mode 100644 index 00000000000..ece32eba711 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/application.properties @@ -0,0 +1,118 @@ +#---------------------------- DATABASE CONFIGURATIONS -----------------------------# +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/egov_hrms +spring.datasource.username=postgres +spring.datasource.password=postgres + +#----------------------------- FLYWAY CONFIGURATIONS ------------------------------# +spring.flyway.url=jdbc:postgresql://localhost:5432/egov_hrms +spring.flyway.user=postgres +spring.flyway.password=postgres +#spring.flyway.table=hr_employee_schema_version +spring.flyway.baseline-on-migrate=true +spring.flyway.outOfOrder=true +spring.flyway.locations=classpath:/db/migration/main,db/migration/seed +spring.flyway.enabled=true + +#--------------------------- PATH & PORT CONFIGURATIONS ---------------------------# +server.contextPath=/egov-hrms +server.servlet.context-path=/egov-hrms +server.port=9999 + +#---------------------------- TIMEZONE CONFIGURATIONS -----------------------------# +app.timezone=UTC + +#-------------------------- EXTERNAL API CONFIGURATIONS ---------------------------# + + +egov.services.data_sync_employee.required = false + + +#mdms urls +egov.mdms.host=https://dev.digit.org +egov.mdms.search.endpoint=/egov-mdms-service/v1/_search +#egov.mdms.search.endpoint=/egov-mdms-service-test/v1/_search + +#filestore urls +egov.filestore.host=https://dev.digit.org +egov.filestore.url.endpoint=/filestore/v1/files/url + +#localization urls +egov.localization.host=https://dev.digit.org +egov.localization.search.endpoint=/localization/messages/v1/_search + +#egov-otp urls +egov.otp.host=http://egov-otp.egov:8080/ +egov.otp.create.endpoint=otp/v1/_create + +egov.environment.domain=https://dev.digit.org/ + +#user +egov.user.host=https://dev.digit.org +egov.user.search.endpoint=/user/v1/_search +egov.user.create.endpoint=/user/users/_createnovalidate +egov.user.update.endpoint=/user/users/_updatenovalidate + +#idgen configs +#egov.idgen.host=http://egov-idgen:8080/ +egov.idgen.host=https://dev.digit.org/ +egov.idgen.path=egov-idgen/id/_generate +egov.idgen.ack.name=hrms.employeecode +egov.idgen.ack.format=EMP-[city]-[SEQ_EG_HRMS_EMP_CODE] + + +egov.individual.host=https://health-dev.digit.org +egov.individual.create.endpoint=/individual/v1/_create +egov.individual.update.endpoint=/individual/v1/_update +egov.individual.search.endpoint=/individual/v1/_search + +# use qualifier as "defaultUserService" to integrate with egov-user module +# use qualifier as "individualService" to integrate with individual module +egov.hrms.user.service.qualifier=individualService + + +#user +egov.hrms.employee.app.link=https://mseva.lgpunjab.gov.in/employee/user/login + + +#CONFIGS +egov.hrms.default.pagination.limit=200 +egov.hrms.default.pwd.length=8 +open.search.enabled.roles=SUPERUSER +egov.pwd.allowed.special.characters=@#$% +parent.level.tenant.id=pb +decryption.abac.enable=false + +#------------------------------ KAFKA CONFIGURATIONS ------------------------------# +# KAFKA SERVER CONFIGURATIONS +spring.kafka.bootstrap.servers=localhost:9092 +spring.kafka.consumer.properties.spring.json.use.type.headers=false + +# SPRING KAFKA CONSUMER CONFIGURATIONS +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=employee-group1 + +# SPRING KAFKA PRODUCER CONFIGURATIONS +spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer +spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer + +# KAFKA TOPIC CONFIGURATIONS +kafka.topics.save.service=save-hrms-employee +kafka.topics.update.service=update-hrms-employee +kafka.topics.notification.sms=egov.core.notification.sms +kafka.topics.hrms.updateData= egov-hrms-update + +spring.kafka.listener.missing-topics-fatal=false + +#------------------------------ TRACER CONFIGURATIONS -----------------------------# +# tracer.detailed.tracing.enabled=false + +#------------------------------ LOGGER CONFIGURATIONS -----------------------------# +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} + +log4j.logger.org.springframework.jdbc.core = TRACE + +state.level.tenant.id=default + +egov.hrms.auto.generate.password=true \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/resources/config/application-config.properties b/core-services/egov-hrms/src/main/resources/config/application-config.properties new file mode 100644 index 00000000000..8ade6ea4997 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/config/application-config.properties @@ -0,0 +1,17 @@ +#----------------------- DEFAULT PAGINATION CONFIGURATIONS ------------------------# +egov.services.emp.search.pagesize.default=200 +egov.services.emp.search.pageno.max=50 +egov.services.emp.search.pagesize.max=500 + + +#------------------------- CODE & SEQUENCE CONFIGURATIONS -------------------------# + +# Already configured in ApplicationConfiguration file but right now not being used. Instead using enum. +egov.services.emp.seq.assignment=seq_egeis_assignment +egov.services.emp.seq.departmentaltest=seq_egeis_departmentaltest +egov.services.emp.seq.educationalqualification=seq_egeis_educationalqualification +egov.services.emp.seq.hoddepartment=seq_egeis_hoddepartment +egov.services.emp.seq.probation=seq_egeis_probation +egov.services.emp.seq.regularisation=seq_egeis_regularisation +egov.services.emp.seq.servicehistory=seq_egeis_servicehistory +egov.services.emp.seq.technicalqualification=seq_egeis_technicalqualification diff --git a/core-services/egov-hrms/src/main/resources/config/hrm-employee-update-persister.yml b/core-services/egov-hrms/src/main/resources/config/hrm-employee-update-persister.yml new file mode 100644 index 00000000000..1f57cc0719c --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/config/hrm-employee-update-persister.yml @@ -0,0 +1,265 @@ +serviceMaps: + serviceName: HRMS + mappings: + - version: 1.0 + name: hrms + description: Persists employee details in the table + fromTopic: update-hrms-employee + isTransaction: true + queryMaps: + + - query: DELETE from eg_hrms_employee WHERE uuid=? on + + basePath: Employees.* + jsonMaps: + + -jsonPath: $.Employees.*.uuid + + + + - query: INSERT INTO eg_hrms_employee(tenantid, id, uuid, code, phone, name, dateOfAppointment, employeestatus, employeetype, active, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.* + jsonMaps: + + + - jsonPath: $.Employees.*.tenantId + + - jsonPath: $.Employees.*.id + + - jsonPath: $.Employees.*.uuid + + - jsonPath: $.Employees.*.code + + - jsonPath: $.Employees.*.user.mobileNumber + + - jsonPath: $.Employees.*.user.name + + - jsonPath: $.Employees.*.dateOfAppointment + + - jsonPath: $.Employees.*.employeeStatus + + - jsonPath: $.Employees.*.employeeType + + - jsonPath: $.Employees.*.active + + - jsonPath: $.Employees.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.auditDetails.lastModifiedDate + + + + - query: INSERT INTO eg_hrms_assignment(tenantid, uuid, position, department, designation, fromdate, todate, govtordernumber, reportingto, isHOD, employeeid, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.assignments.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.assignments[*].id)].tenantId + + - jsonPath: $.Employees.*.assignments.*.id + + - jsonPath: $.Employees.*.assignments.*.position + + - jsonPath: $.Employees.*.assignments.*.department + + - jsonPath: $.Employees.*.assignments.*.designation + + - jsonPath: $.Employees.*.assignments.*.fromDate + + - jsonPath: $.Employees.*.assignments.*.toDate + + - jsonPath: $.Employees.*.assignments.*.govtOrderNumber + + - jsonPath: $.Employees.*.assignments.*.reportingTo + + - jsonPath: $.Employees.*.assignments.*.isHOD + + - jsonPath: $.Employees[*][?({id} in @.assignments[*].id)].uuid + + - jsonPath: $.Employees.*.assignments.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.assignments.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.assignments.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.assignments.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_educationaldetails(tenantid, uuid, employeeid, qualification, stream, yearofpassing, university, remarks, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.education.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.education[*].id)].tenantId + + - jsonPath: $.Employees.*.education.*.id + + - jsonPath: $.Employees[*][?({id} in @.education[*].id)].uuid + + - jsonPath: $.Employees.*.education.*.qualification + + - jsonPath: $.Employees.*.education.*.stream + + - jsonPath: $.Employees.*.education.*.yearOfPassing + + - jsonPath: $.Employees.*.education.*.university + + - jsonPath: $.Employees.*.education.*.remarks + + - jsonPath: $.Employees.*.education.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.education.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.education.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.education.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_departmentaltests(tenantid, uuid, employeeid, test, yearofpassing, remarks, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.tests.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.tests[*].id)].tenantId + + - jsonPath: $.Employees.*.tests.*.id + + - jsonPath: $.Employees[*][?({id} in @.tests[*].id)].uuid + + - jsonPath: $.Employees.*.tests.*.test + + - jsonPath: $.Employees.*.tests.*.yearOfPassing + + - jsonPath: $.Employees.*.tests.*.remarks + + - jsonPath: $.Employees.*.tests.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.tests.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.tests.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.tests.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_empdocuments(tenantid, uuid, employeeid, documentid, documentname, referencetype, referenceid, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.documents.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.documents[*].id)].tenantId + + - jsonPath: $.Employees.*.documents.*.id + + - jsonPath: $.Employees[*][?({id} in @.documents[*].id)].uuid + + - jsonPath: $.Employees.*.documents.*.documentId + + - jsonPath: $.Employees.*.documents.*.documentName + + - jsonPath: $.Employees.*.documents.*.referenceType + + - jsonPath: $.Employees.*.documents.*.referenceId + + - jsonPath: $.Employees.*.documents.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.documents.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.documents.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.documents.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_servicehistory(tenantid, uuid, employeeid, servicestatus, servicefrom, serviceto, ordernumber, isCurrentPosition, location, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.serviceHistory.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.serviceHistory[*].id)].tenantId + + - jsonPath: $.Employees.*.serviceHistory.*.id + + - jsonPath: $.Employees[*][?({id} in @.serviceHistory[*].id)].uuid + + - jsonPath: $.Employees.*.serviceHistory.*.serviceStatus + + - jsonPath: $.Employees.*.serviceHistory.*.serviceFrom + + - jsonPath: $.Employees.*.serviceHistory.*.serviceTo + + - jsonPath: $.Employees.*.serviceHistory.*.orderNo + + - jsonPath: $.Employees.*.serviceHistory.*.isCurrentPosition + + - jsonPath: $.Employees.*.serviceHistory.*.location + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.lastModifiedDate + + -query: INSERT INTO eg_hrms_jurisdiction (uuid, employeeid, hierarchy, boundarytype, boundary, tenantid, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.jurisdictions.* + jsonMaps: + + - jsonPath: $.Employees.*.jurisdictions.*.id + + - jsonPath: $.Employees[*][?({id} in @.jurisdictions[*].id)].uuid + + - jsonPath: $.Employees.*.jurisdictions.*.hierarchy + + - jsonPath: $.Employees.*.jurisdictions.*.boundaryType + + - jsonPath: $.Employees.*.jurisdictions.*.boundary + + - jsonPath: $.Employees[*][?({id} in @.jurisdictions[*].id)].tenantId + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.lastModifiedDate + + + + - query: INSERT INTO eg_hrms_deactivationdetails(uuid, employeeid, reasonfordeactivation, effectivefrom, ordernumber, typeOfDeactivation, tenantid, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.deactivationDetails.* + jsonMaps: + + - jsonPath: $.Employees.*.deactivationDetails.*.id + + - jsonPath: $.Employees[*][?({id} in @.deactivationDetails[*].id)].uuid + + - jsonPath: $.Employees.*.deactivationDetails.*.reasonForDeactivation + + - jsonPath: $.Employees.*.deactivationDetails.*.effectiveFrom + + - jsonPath: $.Employees.*.deactivationDetails.*.orderNo + + - jsonPath: $.Employees.*.deactivationDetails.*.typeOfDeactivation + + - jsonPath: $.Employees[*][?({id} in @.deactivationDetails[*].id)].tenantId + + - jsonPath: $.Employees.*.deactivationDetails.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.deactivationDetails.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.deactivationDetails.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.deactivationDetails.*.auditDetails.lastModifiedDate + diff --git a/core-services/egov-hrms/src/main/resources/config/hrms-employee-persister.yml b/core-services/egov-hrms/src/main/resources/config/hrms-employee-persister.yml new file mode 100644 index 00000000000..74dbd1940ef --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/config/hrms-employee-persister.yml @@ -0,0 +1,501 @@ +serviceMaps: + serviceName: HRMS + mappings: + - version: 1.0 + name: hrms + description: Persists employee details in the table + fromTopic: save-hrms-employee + isTransaction: true + queryMaps: + - query: INSERT INTO eg_hrms_employee(tenantid, id, uuid, code, dateOfAppointment, employeestatus, employeetype, active, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.* + jsonMaps: + + + - jsonPath: $.Employees.*.tenantId + + - jsonPath: $.Employees.*.id + + - jsonPath: $.Employees.*.uuid + + - jsonPath: $.Employees.*.code + + - jsonPath: $.Employees.*.dateOfAppointment + + - jsonPath: $.Employees.*.employeeStatus + + - jsonPath: $.Employees.*.employeeType + + - jsonPath: $.Employees.*.isActive + + - jsonPath: $.Employees.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.auditDetails.lastModifiedDate + + + + - query: INSERT INTO eg_hrms_assignment(tenantid, uuid, position, department, designation, fromdate, todate, govtordernumber, reportingto, isHOD, iscurrentassignment, employeeid, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.assignments.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.assignments[*].id)].tenantId + + - jsonPath: $.Employees.*.assignments.*.id + + - jsonPath: $.Employees.*.assignments.*.position + + - jsonPath: $.Employees.*.assignments.*.department + + - jsonPath: $.Employees.*.assignments.*.designation + + - jsonPath: $.Employees.*.assignments.*.fromDate + + - jsonPath: $.Employees.*.assignments.*.toDate + + - jsonPath: $.Employees.*.assignments.*.govtOrderNumber + + - jsonPath: $.Employees.*.assignments.*.reportingTo + + - jsonPath: $.Employees.*.assignments.*.isHOD + + - jsonPath: $.Employees.*.assignments.*.isCurrentAssignment + + - jsonPath: $.Employees[*][?({id} in @.assignments[*].id)].uuid + + - jsonPath: $.Employees.*.assignments.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.assignments.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.assignments.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.assignments.*.auditDetails.lastModifiedDate + + + + + - query: INSERT INTO eg_hrms_educationaldetails(tenantid, uuid, employeeid, qualification, stream, yearofpassing, university, remarks, isactive, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.education.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.education[*].id)].tenantId + + - jsonPath: $.Employees.*.education.*.id + + - jsonPath: $.Employees[*][?({id} in @.education[*].id)].uuid + + - jsonPath: $.Employees.*.education.*.qualification + + - jsonPath: $.Employees.*.education.*.stream + + - jsonPath: $.Employees.*.education.*.yearOfPassing + + - jsonPath: $.Employees.*.education.*.university + + - jsonPath: $.Employees.*.education.*.remarks + + - jsonPath: $.Employees.*.education.*.isActive + + - jsonPath: $.Employees.*.education.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.education.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.education.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.education.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_departmentaltests(tenantid, uuid, employeeid, test, yearofpassing, remarks, isactive, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.tests.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.tests[*].id)].tenantId + + - jsonPath: $.Employees.*.tests.*.id + + - jsonPath: $.Employees[*][?({id} in @.tests[*].id)].uuid + + - jsonPath: $.Employees.*.tests.*.test + + - jsonPath: $.Employees.*.tests.*.yearOfPassing + + - jsonPath: $.Employees.*.tests.*.remarks + + - jsonPath: $.Employees.*.tests.*.isActive + + - jsonPath: $.Employees.*.tests.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.tests.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.tests.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.tests.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_empdocuments(tenantid, uuid, employeeid, documentid, documentname, referencetype, referenceid, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.documents.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.documents[*].id)].tenantId + + - jsonPath: $.Employees.*.documents.*.id + + - jsonPath: $.Employees[*][?({id} in @.documents[*].id)].uuid + + - jsonPath: $.Employees.*.documents.*.documentId + + - jsonPath: $.Employees.*.documents.*.documentName + + - jsonPath: $.Employees.*.documents.*.referenceType + + - jsonPath: $.Employees.*.documents.*.referenceId + + - jsonPath: $.Employees.*.documents.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.documents.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.documents.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.documents.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_servicehistory(tenantid, uuid, employeeid, servicestatus, servicefrom, serviceto, ordernumber, isCurrentPosition, location, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.serviceHistory.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.serviceHistory[*].id)].tenantId + + - jsonPath: $.Employees.*.serviceHistory.*.id + + - jsonPath: $.Employees[*][?({id} in @.serviceHistory[*].id)].uuid + + - jsonPath: $.Employees.*.serviceHistory.*.serviceStatus + + - jsonPath: $.Employees.*.serviceHistory.*.serviceFrom + + - jsonPath: $.Employees.*.serviceHistory.*.serviceTo + + - jsonPath: $.Employees.*.serviceHistory.*.orderNo + + - jsonPath: $.Employees.*.serviceHistory.*.isCurrentPosition + + - jsonPath: $.Employees.*.serviceHistory.*.location + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_jurisdiction (uuid, employeeid, hierarchy, boundarytype, boundary, tenantid, isActive, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.jurisdictions.* + jsonMaps: + + - jsonPath: $.Employees.*.jurisdictions.*.id + + - jsonPath: $.Employees[*][?({id} in @.jurisdictions[*].id)].uuid + + - jsonPath: $.Employees.*.jurisdictions.*.hierarchy + + - jsonPath: $.Employees.*.jurisdictions.*.boundaryType + + - jsonPath: $.Employees.*.jurisdictions.*.boundary + + - jsonPath: $.Employees[*][?({id} in @.jurisdictions[*].id)].tenantId + + - jsonPath: $.Employees.*.jurisdictions.*.isActive + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.lastModifiedDate + + + + + - version: 1.0 + name: hrms + description: Persists employee details in the table + fromTopic: update-hrms-employee + isTransaction: true + queryMaps: + - query: DELETE from eg_hrms_employee WHERE uuid=? + + basePath: Employees.* + jsonMaps: + + - jsonPath: $.Employees.*.uuid + + - query: INSERT INTO eg_hrms_employee(tenantid, id, uuid, code, dateOfAppointment, employeestatus, employeetype, active, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.* + jsonMaps: + + + - jsonPath: $.Employees.*.tenantId + + - jsonPath: $.Employees.*.id + + - jsonPath: $.Employees.*.uuid + + - jsonPath: $.Employees.*.code + + - jsonPath: $.Employees.*.dateOfAppointment + + - jsonPath: $.Employees.*.employeeStatus + + - jsonPath: $.Employees.*.employeeType + + - jsonPath: $.Employees.*.isActive + + - jsonPath: $.Employees.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.auditDetails.lastModifiedDate + + + + - query: INSERT INTO eg_hrms_assignment(tenantid, uuid, position, department, designation, fromdate, todate, govtordernumber, reportingto, isHOD, iscurrentassignment, employeeid, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.assignments.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.assignments[*].id)].tenantId + + - jsonPath: $.Employees.*.assignments.*.id + + - jsonPath: $.Employees.*.assignments.*.position + + - jsonPath: $.Employees.*.assignments.*.department + + - jsonPath: $.Employees.*.assignments.*.designation + + - jsonPath: $.Employees.*.assignments.*.fromDate + + - jsonPath: $.Employees.*.assignments.*.toDate + + - jsonPath: $.Employees.*.assignments.*.govtOrderNumber + + - jsonPath: $.Employees.*.assignments.*.reportingTo + + - jsonPath: $.Employees.*.assignments.*.isHOD + + - jsonPath: $.Employees.*.assignments.*.isCurrentAssignment + + - jsonPath: $.Employees[*][?({id} in @.assignments[*].id)].uuid + + - jsonPath: $.Employees.*.assignments.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.assignments.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.assignments.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.assignments.*.auditDetails.lastModifiedDate + + + + + - query: INSERT INTO eg_hrms_educationaldetails(tenantid, uuid, employeeid, qualification, stream, yearofpassing, university, remarks, isactive, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.education.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.education[*].id)].tenantId + + - jsonPath: $.Employees.*.education.*.id + + - jsonPath: $.Employees[*][?({id} in @.education[*].id)].uuid + + - jsonPath: $.Employees.*.education.*.qualification + + - jsonPath: $.Employees.*.education.*.stream + + - jsonPath: $.Employees.*.education.*.yearOfPassing + + - jsonPath: $.Employees.*.education.*.university + + - jsonPath: $.Employees.*.education.*.remarks + + - jsonPath: $.Employees.*.education.*.isActive + + - jsonPath: $.Employees.*.education.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.education.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.education.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.education.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_departmentaltests(tenantid, uuid, employeeid, test, yearofpassing, remarks, isactive, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.tests.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.tests[*].id)].tenantId + + - jsonPath: $.Employees.*.tests.*.id + + - jsonPath: $.Employees[*][?({id} in @.tests[*].id)].uuid + + - jsonPath: $.Employees.*.tests.*.test + + - jsonPath: $.Employees.*.tests.*.yearOfPassing + + - jsonPath: $.Employees.*.tests.*.remarks + + - jsonPath: $.Employees.*.tests.*.isActive + + - jsonPath: $.Employees.*.tests.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.tests.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.tests.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.tests.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_empdocuments(tenantid, uuid, employeeid, documentid, documentname, referencetype, referenceid, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.documents.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.documents[*].id)].tenantId + + - jsonPath: $.Employees.*.documents.*.id + + - jsonPath: $.Employees[*][?({id} in @.documents[*].id)].uuid + + - jsonPath: $.Employees.*.documents.*.documentId + + - jsonPath: $.Employees.*.documents.*.documentName + + - jsonPath: $.Employees.*.documents.*.referenceType + + - jsonPath: $.Employees.*.documents.*.referenceId + + - jsonPath: $.Employees.*.documents.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.documents.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.documents.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.documents.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_servicehistory(tenantid, uuid, employeeid, servicestatus, servicefrom, serviceto, ordernumber, isCurrentPosition, location, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.serviceHistory.* + jsonMaps: + + + - jsonPath: $.Employees[*][?({id} in @.serviceHistory[*].id)].tenantId + + - jsonPath: $.Employees.*.serviceHistory.*.id + + - jsonPath: $.Employees[*][?({id} in @.serviceHistory[*].id)].uuid + + - jsonPath: $.Employees.*.serviceHistory.*.serviceStatus + + - jsonPath: $.Employees.*.serviceHistory.*.serviceFrom + + - jsonPath: $.Employees.*.serviceHistory.*.serviceTo + + - jsonPath: $.Employees.*.serviceHistory.*.orderNo + + - jsonPath: $.Employees.*.serviceHistory.*.isCurrentPosition + + - jsonPath: $.Employees.*.serviceHistory.*.location + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.serviceHistory.*.auditDetails.lastModifiedDate + + + - query: INSERT INTO eg_hrms_jurisdiction (uuid, employeeid, hierarchy, boundarytype, boundary, tenantid, isActive, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.jurisdictions.* + jsonMaps: + + - jsonPath: $.Employees.*.jurisdictions.*.id + + - jsonPath: $.Employees[*][?({id} in @.jurisdictions[*].id)].uuid + + - jsonPath: $.Employees.*.jurisdictions.*.hierarchy + + - jsonPath: $.Employees.*.jurisdictions.*.boundaryType + + - jsonPath: $.Employees.*.jurisdictions.*.boundary + + - jsonPath: $.Employees[*][?({id} in @.jurisdictions[*].id)].tenantId + + - jsonPath: $.Employees.*.jurisdictions.*.isActive + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.jurisdictions.*.auditDetails.lastModifiedDate + + + + - query: INSERT INTO eg_hrms_deactivationdetails(uuid, employeeid, reasonfordeactivation, effectivefrom, ordernumber, remarks, tenantid, createdby, createddate, lastmodifiedby, lastModifiedDate) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + + basePath: Employees.*.deactivationDetails.* + jsonMaps: + + - jsonPath: $.Employees.*.deactivationDetails.*.id + + - jsonPath: $.Employees[*][?({id} in @.deactivationDetails[*].id)].uuid + + - jsonPath: $.Employees.*.deactivationDetails.*.reasonForDeactivation + + - jsonPath: $.Employees.*.deactivationDetails.*.effectiveFrom + + - jsonPath: $.Employees.*.deactivationDetails.*.orderNo + + - jsonPath: $.Employees.*.deactivationDetails.*.remarks + + - jsonPath: $.Employees[*][?({id} in @.deactivationDetails[*].id)].tenantId + + - jsonPath: $.Employees.*.deactivationDetails.*.auditDetails.createdBy + + - jsonPath: $.Employees.*.deactivationDetails.*.auditDetails.createdDate + + - jsonPath: $.Employees.*.deactivationDetails.*.auditDetails.lastModifiedBy + + - jsonPath: $.Employees.*.deactivationDetails.*.auditDetails.lastModifiedDate diff --git a/core-services/egov-hrms/src/main/resources/db/Dockerfile b/core-services/egov-hrms/src/main/resources/db/Dockerfile new file mode 100644 index 00000000000..a5699ff7d99 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/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/core-services/egov-hrms/src/main/resources/db/migrate.sh b/core-services/egov-hrms/src/main/resources/db/migrate.sh new file mode 100644 index 00000000000..43960b25cdb --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/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/core-services/egov-hrms/src/main/resources/db/migration/main/V20190122152236__create_hrms_employee_table_ddl.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190122152236__create_hrms_employee_table_ddl.sql new file mode 100644 index 00000000000..ea38846f3b3 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190122152236__create_hrms_employee_table_ddl.sql @@ -0,0 +1,159 @@ +CREATE TABLE eg_hrms_employee ( + id BIGINT NOT NULL, + uuid CHARACTER VARYING(1024) NOT NULL, + code CHARACTER VARYING(250), + phone CHARACTER VARYING(250), + name CHARACTER VARYING(250), + dateOfAppointment BIGINT, + employeestatus CHARACTER VARYING(250), + employeetype CHARACTER VARYING(250), + active BOOLEAN, + tenantid CHARACTER VARYING(250) NOT NULL, + createdby CHARACTER VARYING(250) NOT NULL, + createddate BIGINT NOT NULL, + lastmodifiedby CHARACTER VARYING(250), + lastModifiedDate BIGINT, + + CONSTRAINT pk_eghrms_employee PRIMARY KEY (uuid), + CONSTRAINT uk_eghrms_employee_code UNIQUE (code) +); + + + +CREATE TABLE eg_hrms_assignment ( + uuid CHARACTER VARYING(1024) NOT NULL, + employeeid CHARACTER VARYING(1024) NOT NULL, + position BIGINT, + department CHARACTER VARYING(250), + designation CHARACTER VARYING(250), + fromdate BIGINT, + todate BIGINT, + govtordernumber CHARACTER VARYING(250), + reportingto CHARACTER VARYING(250), + isHOD BOOLEAN, + tenantid CHARACTER VARYING(250) NOT NULL, + createdby CHARACTER VARYING(250) NOT NULL, + createddate BIGINT NOT NULL, + lastmodifiedby CHARACTER VARYING(250), + lastModifiedDate BIGINT, + + CONSTRAINT pk_eghrms_assignment PRIMARY KEY (uuid), + CONSTRAINT ck_eghrms_employee_fromTo CHECK (fromdate <= todate), + CONSTRAINT fk_eghrms_assignment_employeeid FOREIGN KEY (employeeid) REFERENCES eg_hrms_employee (uuid) ON DELETE CASCADE + +); + + +CREATE TABLE eg_hrms_educationaldetails ( + uuid CHARACTER VARYING(1024) NOT NULL, + employeeid CHARACTER VARYING(1024) NOT NULL, + qualification CHARACTER VARYING(250), + stream CHARACTER VARYING(250), + yearofpassing BIGINT, + university CHARACTER VARYING(250), + remarks CHARACTER VARYING(250), + tenantid CHARACTER VARYING(250) NOT NULL, + createdby CHARACTER VARYING(250) NOT NULL, + createddate BIGINT NOT NULL, + lastmodifiedby CHARACTER VARYING(250), + lastModifiedDate BIGINT, + + CONSTRAINT pk_eghrms_educationaldetails PRIMARY KEY (uuid), + CONSTRAINT fk_eghrms_educationaldetails_employeeid FOREIGN KEY (employeeid) REFERENCES eg_hrms_employee (uuid) ON DELETE CASCADE + +); + + +CREATE TABLE eg_hrms_departmentaltests ( + uuid CHARACTER VARYING(1024) NOT NULL, + employeeid CHARACTER VARYING(1024) NOT NULL, + test CHARACTER VARYING(250), + yearofpassing BIGINT, + remarks CHARACTER VARYING(250), + tenantid CHARACTER VARYING(250) NOT NULL, + createdby CHARACTER VARYING(250) NOT NULL, + createddate BIGINT NOT NULL, + lastmodifiedby CHARACTER VARYING(250), + lastModifiedDate BIGINT, + + CONSTRAINT pk_eghrms_departmentaltests PRIMARY KEY (uuid), + CONSTRAINT fk_eghrms_departmentaltests_employeeid FOREIGN KEY (employeeid) REFERENCES eg_hrms_employee (uuid) ON DELETE CASCADE + +); + + +CREATE TABLE eg_hrms_empdocuments ( + uuid CHARACTER VARYING(1024) NOT NULL, + employeeid CHARACTER VARYING(1024) NOT NULL, + documentid CHARACTER VARYING(250) NOT NULL, + documentname CHARACTER VARYING(250), + referencetype CHARACTER VARYING(250), + referenceid CHARACTER VARYING(250) NOT NULL, + tenantid CHARACTER VARYING(250) NOT NULL, + createdby CHARACTER VARYING(250) NOT NULL, + createddate BIGINT NOT NULL, + lastmodifiedby CHARACTER VARYING(250), + lastModifiedDate BIGINT, + + CONSTRAINT pk_eghrms_empdocuments PRIMARY KEY (uuid), + CONSTRAINT fk_eghrms_empdocuments_employeeid FOREIGN KEY (employeeid) REFERENCES eg_hrms_employee (uuid) ON DELETE CASCADE + +); + + +CREATE TABLE eg_hrms_servicehistory ( + uuid CHARACTER VARYING(1024) NOT NULL, + employeeid CHARACTER VARYING(1024) NOT NULL, + servicestatus CHARACTER VARYING(250), + servicefrom BIGINT, + serviceto BIGINT, + ordernumber CHARACTER VARYING(250), + isCurrentPosition BOOLEAN, + location CHARACTER VARYING(250), + tenantid CHARACTER VARYING(250) NOT NULL, + createdby CHARACTER VARYING(250) NOT NULL, + createddate BIGINT NOT NULL, + lastmodifiedby CHARACTER VARYING(250), + lastModifiedDate BIGINT, + + CONSTRAINT pk_eghrms_servicehistory PRIMARY KEY (uuid), + CONSTRAINT fk_eghrms_servicehistory_employeeid FOREIGN KEY (employeeid) REFERENCES eg_hrms_employee (uuid) ON DELETE CASCADE + +); + +CREATE TABLE eg_hrms_jurisdiction ( + uuid CHARACTER VARYING(1024) NOT NULL, + employeeid CHARACTER VARYING(1024) NOT NULL, + hierarchy CHARACTER VARYING(250) NOT NULL, + boundarytype CHARACTER VARYING(250) NOT NULL, + boundary CHARACTER VARYING(250) NOT NULL, + tenantid CHARACTER VARYING(250) NOT NULL, + createdby CHARACTER VARYING(250) NOT NULL, + createddate BIGINT NOT NULL, + lastmodifiedby CHARACTER VARYING(250), + lastModifiedDate BIGINT, + + CONSTRAINT pk_eghrms_jurisdiction PRIMARY KEY (uuid), + CONSTRAINT fk_eghrms_jurisdiction_employeeid FOREIGN KEY (employeeid) REFERENCES eg_hrms_employee (uuid) ON DELETE CASCADE + +); + +CREATE TABLE eg_hrms_deactivationdetails ( + uuid CHARACTER VARYING(1024) NOT NULL, + employeeid CHARACTER VARYING(1024) NOT NULL, + reasonfordeactivation CHARACTER VARYING(250), + effectivefrom BIGINT, + ordernumber CHARACTER VARYING(250), + typeOfDeactivation CHARACTER VARYING(250), + tenantid CHARACTER VARYING(250) NOT NULL, + createdby CHARACTER VARYING(250) NOT NULL, + createddate BIGINT NOT NULL, + lastmodifiedby CHARACTER VARYING(250), + lastModifiedDate BIGINT, + + CONSTRAINT pk_eghrms_deactivationdetails PRIMARY KEY (uuid), + CONSTRAINT fk_eghrms_deactivationdetails_employeeid FOREIGN KEY (employeeid) REFERENCES eg_hrms_employee (uuid) ON DELETE CASCADE + +); + + diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20190130120650__alter_assgnmt_add_currentassgmt_ddl.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190130120650__alter_assgnmt_add_currentassgmt_ddl.sql new file mode 100644 index 00000000000..cbf835475d0 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190130120650__alter_assgnmt_add_currentassgmt_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE eg_hrms_assignment ADD COLUMN iscurrentassignment BOOLEAN; \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20190204154948__create_position_sequence_ddl.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190204154948__create_position_sequence_ddl.sql new file mode 100644 index 00000000000..9cd94842b9c --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190204154948__create_position_sequence_ddl.sql @@ -0,0 +1 @@ +CREATE SEQUENCE EG_HRMS_POSITION; diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20190204163735__alter_deactivation_rename_remarks_ddl.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190204163735__alter_deactivation_rename_remarks_ddl.sql new file mode 100644 index 00000000000..48fa186edf2 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190204163735__alter_deactivation_rename_remarks_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE eg_hrms_deactivationdetails RENAME COLUMN typeOfDeactivation TO remarks; diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20190204172710__secondary_indexes_ddl.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190204172710__secondary_indexes_ddl.sql new file mode 100644 index 00000000000..ad6f5458476 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190204172710__secondary_indexes_ddl.sql @@ -0,0 +1,4 @@ +CREATE INDEX code_idx ON eg_hrms_employee ("code"); +CREATE INDEX dept_idx ON eg_hrms_assignment ("department"); +CREATE INDEX posn_idx ON eg_hrms_assignment ("position"); +CREATE INDEX desg_idx ON eg_hrms_assignment ("designation"); \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20190215120811__alter_uk_constraint_dml.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190215120811__alter_uk_constraint_dml.sql new file mode 100644 index 00000000000..06a6ebf8635 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190215120811__alter_uk_constraint_dml.sql @@ -0,0 +1,2 @@ +ALTER TABLE eg_hrms_employee DROP CONSTRAINT uk_eghrms_employee_code; +ALTER TABLE eg_hrms_employee ADD CONSTRAINT uk_eghrms_employee_code UNIQUE (code, tenantid); \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20190219163221__alter_remove_phone_name_clm_dml.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190219163221__alter_remove_phone_name_clm_dml.sql new file mode 100644 index 00000000000..851d369e121 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190219163221__alter_remove_phone_name_clm_dml.sql @@ -0,0 +1,2 @@ +ALTER TABLE eg_hrms_employee DROP COLUMN phone; +ALTER TABLE eg_hrms_employee DROP COLUMN name; \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20190301154105__alter_add_isactive_ddl.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190301154105__alter_add_isactive_ddl.sql new file mode 100644 index 00000000000..9ddb8794f36 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20190301154105__alter_add_isactive_ddl.sql @@ -0,0 +1,6 @@ +ALTER TABLE eg_hrms_departmentaltests ADD COLUMN isActive BOOLEAN; +ALTER TABLE eg_hrms_educationaldetails ADD COLUMN isActive BOOLEAN; +ALTER TABLE eg_hrms_jurisdiction ADD COLUMN isActive BOOLEAN; +ALTER TABLE eg_hrms_assignment ADD COLUMN isActive BOOLEAN; +ALTER TABLE eg_hrms_deactivationdetails ADD COLUMN isActive BOOLEAN; +ALTER TABLE eg_hrms_servicehistory ADD COLUMN isActive BOOLEAN; \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20201005230836__eg_hrms_employee_index_ddl.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20201005230836__eg_hrms_employee_index_ddl.sql new file mode 100644 index 00000000000..b9b8017f1eb --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20201005230836__eg_hrms_employee_index_ddl.sql @@ -0,0 +1 @@ + CREATE index if not exists idx_eg_hrms_employee_tenantid ON eg_hrms_employee USING btree (tenantid); diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20201223230836__eg_hrms_employee_reactivation_details_index_ddl.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20201223230836__eg_hrms_employee_reactivation_details_index_ddl.sql new file mode 100644 index 00000000000..2c4b6633804 --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20201223230836__eg_hrms_employee_reactivation_details_index_ddl.sql @@ -0,0 +1,19 @@ + ALTER TABLE eg_hrms_employee ADD COLUMN reactivateemployee BOOLEAN; + + CREATE TABLE eg_hrms_reactivationdetails ( + uuid CHARACTER VARYING(1024) NOT NULL, + employeeid CHARACTER VARYING(1024) NOT NULL, + reasonforreactivation CHARACTER VARYING(250), + effectivefrom BIGINT, + ordernumber CHARACTER VARYING(250), + remarks CHARACTER VARYING(250), + tenantid CHARACTER VARYING(250) NOT NULL, + createdby CHARACTER VARYING(250) NOT NULL, + createddate BIGINT NOT NULL, + lastmodifiedby CHARACTER VARYING(250), + lastModifiedDate BIGINT, + + CONSTRAINT pk_eghrms_reactivationdetails PRIMARY KEY (uuid), + CONSTRAINT fk_eghrms_reactivationdetails_employeeid FOREIGN KEY (employeeid) REFERENCES eg_hrms_employee (uuid) ON DELETE CASCADE + + ); diff --git a/core-services/egov-hrms/src/main/resources/db/migration/main/V20201228172710__reactivation_indexes_ddl.sql b/core-services/egov-hrms/src/main/resources/db/migration/main/V20201228172710__reactivation_indexes_ddl.sql new file mode 100644 index 00000000000..96f05aae2ee --- /dev/null +++ b/core-services/egov-hrms/src/main/resources/db/migration/main/V20201228172710__reactivation_indexes_ddl.sql @@ -0,0 +1 @@ +CREATE INDEX reactivation_employeeid_idx ON eg_hrms_reactivationdetails ("employeeid"); \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/resources/db/migration/seed/.gitkeep b/core-services/egov-hrms/src/main/resources/db/migration/seed/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/core-services/egov-hrms/src/test/resources/application.properties b/core-services/egov-hrms/src/test/resources/application.properties new file mode 100644 index 00000000000..f8216b1d92e --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/application.properties @@ -0,0 +1,108 @@ +#---------------------------- DATABASE CONFIGURATIONS -----------------------------# +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/hr_employee_db +spring.datasource.username=postgres +spring.datasource.password=postgres + +#----------------------------- FLYWAY CONFIGURATIONS ------------------------------# +flyway.url=jdbc:postgresql://localhost:5432/hr_employee_db +flyway.user=postgres +flyway.password=postgres +flyway.table=hr_employee_schema_version +flyway.baseline-on-migrate=true +flyway.outOfOrder=true +flyway.locations=db/migration/main,db/migration/seed + +#--------------------------- PATH & PORT CONFIGURATIONS ---------------------------# +server.contextPath=/hr-employee-v2 +server.port=9999 + +#---------------------------- TIMEZONE CONFIGURATIONS -----------------------------# +app.timezone=UTC + +#-------------------------- EXTERNAL API CONFIGURATIONS ---------------------------# +egov.services.data_sync_employee.required = false + +# HR-EMPLOYEE (SELF) SERVICE PATH +egov.services.hr_employee_service.hostname=https://dev.digit.org +egov.services.hr_employee_service.basepath=/hr-employee-v2 +egov.services.hr_employee_service.employee.createpath=/employees/_create +egov.services.hr_employee_service.default.password=abcdefgh + +# USER SERVICE PATH +egov.services.users_service.hostname=https://dev.digit.org +egov.services.users_service.users.basepath=/user +egov.services.users_service.users.searchpath=/v1/_search +egov.services.users_service.users.createpath=/users/_createnovalidate +egov.services.users_service.users.updatepath=/users/_updatenovalidate + +# HR-MASTERS SERVICE PATH +egov.services.hr_masters_service.hostname=https://dev.digit.org +egov.services.hr_masters_service.basepath=/hr-masters-v2 +egov.services.hr_masters_service.positions.searchpath=/positions/_search +egov.services.hr_masters_service.designations.searchpath=/designations/_search +egov.services.hr_masters_service.hr_configurations.searchpath=/hrconfigurations/_search +egov.services.hr_masters_service.vacantpositions.searchpath=/vacantpositions/_search +egov.services.hr_masters_service.empstatus.searchpath=//hrstatuses/_search +egov.services.hr_masters_service.emptype.searchpath=/employeetypes/_search + +# HYBRID-DATA-SYNC SERVICE PATH +egov.services.data_sync_employee_service.hostname=http://dev.digit.org +egov.services.data_sync_employee_service.basepath=/data-sync-employee +egov.services.data_sync_employee_service.createpath=/datasync/_create + +# ID GENERATION SERVICE PATH +egov.services.egov_idgen.hostname=http://dev.digit.org +egov.services.egov_idgen.createpath=/egov-idgen/id/_generate +egov.services.egov_idgen.emp.code.name=employee.code +egov.services.egov_idgen.emp.code.format=EMP_[SEQ_EMPLOYEE_CODE] + +# COMMON-WORKFLOW SERVICE PATH +egov.services.common_workflows_service.hostname=http://dev.digit.org +egov.services.common_workflows_service.searchpath=/egov-common-workflows/tasks/_search + +# MDMS SERVICE PATH +egov.services.egov_mdms.hostname=https://dev.digit.org/ +egov.services.egov_mdms.searchpath=egov-mdms-service/v1/_search + +# ERP SERVICE PATH +egov.services.eis_service.hostname=http://dev.digit.org +egov.municipality.host=http://kurnool-pilot-services.egovernments.org/ +egov.services.eis_service.employeeposition.searchpath=employeepositions/_search + +#------------------------------ KAFKA CONFIGURATIONS ------------------------------# +# KAFKA SERVER CONFIGURATIONS +spring.kafka.bootstrap.servers=localhost:9092 + +# SPRING KAFKA CONSUMER CONFIGURATIONS +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=employee-group1 + +# SPRING KAFKA PRODUCER CONFIGURATIONS +spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer +spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer + +# KAFKA TOPIC CONFIGURATIONS +kafka.topics.notification.sms.name=egov.employee +kafka.topics.notification.sms.id=employee +kafka.topics.notification.sms.group=employee-group1 +kafka.topics.employee.savedb.name=egov.employee +kafka.topics.employee.savedb.key=employee-save +kafka.topics.employee.finance.name=egov.employee.finance +kafka.topics.employee.finance.key=employee-finance +kafka.topics.employee.updatedb.name=egov.employee.update +kafka.topics.nominee.savedb.name=hr-employee.nominee.save +kafka.topics.nominee.savedb.key=hr-employee.nominee.save.key +kafka.topics.nominee.updatedb.name=hr-employee.nominee.update +kafka.topics.nominee.updatedb.key=hr-employee.nominee.update.key +kafka.topics.assignment.update.name=hr-employee.assignment.update +kafka.topics.assignment.update.key=hr-employee.assignment.update.key + +#------------------------------ TRACER CONFIGURATIONS -----------------------------# +# tracer.detailed.tracing.enabled=false + +#------------------------------ LOGGER CONFIGURATIONS -----------------------------# +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} + +log4j.logger.org.springframework.jdbc.core = TRACE \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/config/application-config.properties b/core-services/egov-hrms/src/test/resources/config/application-config.properties new file mode 100644 index 00000000000..8ade6ea4997 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/config/application-config.properties @@ -0,0 +1,17 @@ +#----------------------- DEFAULT PAGINATION CONFIGURATIONS ------------------------# +egov.services.emp.search.pagesize.default=200 +egov.services.emp.search.pageno.max=50 +egov.services.emp.search.pagesize.max=500 + + +#------------------------- CODE & SEQUENCE CONFIGURATIONS -------------------------# + +# Already configured in ApplicationConfiguration file but right now not being used. Instead using enum. +egov.services.emp.seq.assignment=seq_egeis_assignment +egov.services.emp.seq.departmentaltest=seq_egeis_departmentaltest +egov.services.emp.seq.educationalqualification=seq_egeis_educationalqualification +egov.services.emp.seq.hoddepartment=seq_egeis_hoddepartment +egov.services.emp.seq.probation=seq_egeis_probation +egov.services.emp.seq.regularisation=seq_egeis_regularisation +egov.services.emp.seq.servicehistory=seq_egeis_servicehistory +egov.services.emp.seq.technicalqualification=seq_egeis_technicalqualification diff --git a/core-services/egov-hrms/src/test/resources/db/Dockerfile b/core-services/egov-hrms/src/test/resources/db/Dockerfile new file mode 100644 index 00000000000..fcb806edf0c --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/Dockerfile @@ -0,0 +1,13 @@ +FROM egovio/flyway:4.1.2 + +COPY ./migration/main /flyway/sql + +COPY ./migration/seed /flyway/seed + +COPY ./migration/dev /flyway/dev + +COPY migrate.sh /usr/bin/migrate.sh + +RUN chmod +x /usr/bin/migrate.sh + +CMD ["/usr/bin/migrate.sh"] diff --git a/core-services/egov-hrms/src/test/resources/db/migrate.sh b/core-services/egov-hrms/src/test/resources/db/migrate.sh new file mode 100644 index 00000000000..54d07c0940a --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/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 diff --git a/core-services/egov-hrms/src/test/resources/db/migration/dev/V20170428152327__egeis_hremployee_sample_data_for_pgr.sql b/core-services/egov-hrms/src/test/resources/db/migration/dev/V20170428152327__egeis_hremployee_sample_data_for_pgr.sql new file mode 100644 index 00000000000..ea1477e6cb5 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/dev/V20170428152327__egeis_hremployee_sample_data_for_pgr.sql @@ -0,0 +1,18 @@ +INSERT INTO egeis_employee (id, code, dateofappointment, dateofjoining, dateofretirement, employeestatus, recruitmentmodeid, recruitmenttypeid, recruitmentquotaid, retirementage, dateofresignation, dateoftermination, employeetypeid, mothertongueid, religionid, communityid, categoryid, physicallydisabled, medicalreportproduced, maritalstatus, passportno, gpfno, bankid, bankbranchid, bankaccount, groupid, placeofbirth, tenantid) +VALUES ((select id from eg_user where username = 'narasappa' and tenantid = 'default'), '658039', NULL, NULL, NULL, (select id from egeis_hrstatus where code = 'EMPLOYED' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, +(select id from egeis_employeetype where name = 'Permanent' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'default'); +INSERT INTO egeis_employee (id, code, dateofappointment, dateofjoining, dateofretirement, employeestatus, recruitmentmodeid, recruitmenttypeid, recruitmentquotaid, retirementage, dateofresignation, dateoftermination, employeetypeid, mothertongueid, religionid, communityid, categoryid, physicallydisabled, medicalreportproduced, maritalstatus, passportno, gpfno, bankid, bankbranchid, bankaccount, groupid, placeofbirth, tenantid) +VALUES ((select id from eg_user where username = 'ramana' and tenantid = 'default'), '658040', NULL, NULL, NULL, (select id from egeis_hrstatus where code = 'EMPLOYED' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, +(select id from egeis_employeetype where name = 'Permanent' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'default'); + +INSERT INTO egeis_assignment (id, employeeid, positionid, fundid, functionaryid, functionid, departmentid, designationid, isprimary, fromdate, todate, gradeid, govtordernumber, createdby, createddate, lastmodifiedby, lastmodifieddate, tenantid) +VALUES (nextval('seq_egeis_assignment'), (select id from egeis_employee where code = '658039' and tenantid = 'default'), +(select id from egeis_position where name = 'ENG_Assistant Engineer_1' and tenantid = 'default'), NULL, NULL, NULL, +(select id from eg_department where code = 'ADM' and tenantid = 'default'), +(select id from egeis_designation where code = 'SASST' and tenantid = 'default'), true, '2015-04-01', '2020-03-31', NULL, NULL, 1, now(), 1, NULL, 'default'); +INSERT INTO egeis_assignment (id, employeeid, positionid, fundid, functionaryid, functionid, departmentid, designationid, isprimary, fromdate, todate, gradeid, govtordernumber, createdby, createddate, lastmodifiedby, lastmodifieddate, tenantid) +VALUES (nextval('seq_egeis_assignment'), (select id from egeis_employee where code = '658040' and tenantid = 'default'), +(select id from egeis_position where name = 'Acc_Senior Account_1' and tenantid = 'default'), NULL, NULL, NULL, +(select id from eg_department where code = 'ACC' and tenantid = 'default'), +(select id from egeis_designation where code = 'AO' and tenantid = 'default'), true, '2015-04-01', '2020-03-31', NULL, NULL, 1, now(), 1, NULL, 'default'); + diff --git a/core-services/egov-hrms/src/test/resources/db/migration/dev/V20170530010026__hr_employee_sample_data_for_panavel.sql b/core-services/egov-hrms/src/test/resources/db/migration/dev/V20170530010026__hr_employee_sample_data_for_panavel.sql new file mode 100644 index 00000000000..0cc581ae74c --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/dev/V20170530010026__hr_employee_sample_data_for_panavel.sql @@ -0,0 +1,20 @@ +INSERT INTO egeis_employee (id, code, dateofappointment, dateofjoining, dateofretirement, employeestatus, recruitmentmodeid, recruitmenttypeid, recruitmentquotaid, retirementage, dateofresignation, dateoftermination, employeetypeid, mothertongueid, religionid, communityid, categoryid, physicallydisabled, medicalreportproduced, maritalstatus, passportno, gpfno, bankid, bankbranchid, bankaccount, groupid, placeofbirth, tenantid) +VALUES ((select id from eg_user where username = 'admin' and tenantid = 'panavel'), '658039', NULL, NULL, NULL, (select id from egeis_hrstatus where code = 'EMPLOYED' and tenantid = 'panavel'), NULL, NULL, NULL, NULL, NULL, NULL, +(select id from egeis_employeetype where name = 'Permanent' and tenantid = 'panavel'), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'panavel'); + +INSERT INTO egeis_employee (id, code, dateofappointment, dateofjoining, dateofretirement, employeestatus, recruitmentmodeid, recruitmenttypeid, recruitmentquotaid, retirementage, dateofresignation, dateoftermination, employeetypeid, mothertongueid, religionid, communityid, categoryid, physicallydisabled, medicalreportproduced, maritalstatus, passportno, gpfno, bankid, bankbranchid, bankaccount, groupid, placeofbirth, tenantid) +VALUES ((select id from eg_user where username = 'ajay' and tenantid = 'panavel'), '658040', NULL, NULL, NULL, (select id from egeis_hrstatus where code = 'EMPLOYED' and tenantid = 'panavel'), NULL, NULL, NULL, NULL, NULL, NULL, +(select id from egeis_employeetype where name = 'Permanent' and tenantid = 'panavel'), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'panavel'); + +INSERT INTO egeis_assignment (id, employeeid, positionid, fundid, functionaryid, functionid, departmentid, designationid, isprimary, fromdate, todate, gradeid, govtordernumber, createdby, createddate, lastmodifiedby, lastmodifieddate, tenantid) +VALUES (nextval('seq_egeis_assignment'), (select id from egeis_employee where code = '658039' and tenantid = 'panavel'), +(select id from egeis_position where name = 'ENG_Assistant Engineer_2' and tenantid = 'panavel'), NULL, NULL, NULL, +(select id from eg_department where code = 'ADM' and tenantid = 'panavel'), +(select id from egeis_designation where code = 'SASST' and tenantid = 'panavel'), true, '2015-04-01', '2020-03-31', NULL, NULL, 1, now(), 1, NULL, 'panavel'); +INSERT INTO egeis_assignment (id, employeeid, positionid, fundid, functionaryid, functionid, departmentid, designationid, isprimary, fromdate, todate, gradeid, govtordernumber, createdby, createddate, lastmodifiedby, lastmodifieddate, tenantid) +VALUES (nextval('seq_egeis_assignment'), (select id from egeis_employee where code = '658040' and tenantid = 'panavel'), +(select id from egeis_position where name = 'Acc_Senior Account_2' and tenantid = 'panavel'), NULL, NULL, NULL, +(select id from eg_department where code = 'ENG' and tenantid = 'panavel'), +(select id from egeis_designation where code = 'AO' and tenantid = 'panavel'), true, '2015-04-01', '2020-03-31', NULL, NULL, 1, now(), 1, NULL, 'panavel'); + + diff --git a/core-services/egov-hrms/src/test/resources/db/migration/dev/V20170614093822__hr_employee_sample_data_for_default.sql b/core-services/egov-hrms/src/test/resources/db/migration/dev/V20170614093822__hr_employee_sample_data_for_default.sql new file mode 100644 index 00000000000..833a0c4c030 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/dev/V20170614093822__hr_employee_sample_data_for_default.sql @@ -0,0 +1,9 @@ +INSERT INTO egeis_employee (id, code, dateofappointment, dateofjoining, dateofretirement, employeestatus, recruitmentmodeid, recruitmenttypeid, recruitmentquotaid, retirementage, dateofresignation, dateoftermination, employeetypeid, mothertongueid, religionid, communityid, categoryid, physicallydisabled, medicalreportproduced, maritalstatus, passportno, gpfno, bankid, bankbranchid, bankaccount, groupid, placeofbirth, tenantid) +VALUES ((select id from eg_user where username = 'ravi' and tenantid = 'default'), '658041', NULL, NULL, NULL, (select id from egeis_hrstatus where code = 'EMPLOYED' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, +(select id from egeis_employeetype where name = 'Permanent' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'default'); + +INSERT INTO egeis_assignment (id, employeeid, positionid, fundid, functionaryid, functionid, departmentid, designationid, isprimary, fromdate, todate, gradeid, govtordernumber, createdby, createddate, lastmodifiedby, lastmodifieddate, tenantid) +VALUES (nextval('seq_egeis_assignment'), (select id from egeis_employee where code = '658041' and tenantid = 'default'), +(select id from egeis_position where name = 'ENG_Junior Assistant_1' and tenantid = 'default'), NULL, NULL, NULL, +(select id from eg_department where code = 'ENG' and tenantid = 'default'), +(select id from egeis_designation where code = 'JASST' and tenantid = 'default'), true, '2015-04-01', '2020-03-31', NULL, NULL, 1, now(), 1, NULL, 'default'); \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185601__hr_employee_employee.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185601__hr_employee_employee.sql new file mode 100644 index 00000000000..3d240ac08c8 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185601__hr_employee_employee.sql @@ -0,0 +1,45 @@ +CREATE TABLE egeis_employee ( + id BIGINT NOT NULL, + code CHARACTER VARYING(250), + dateOfAppointment DATE, + dateOfJoining DATE, + dateOfRetirement DATE, + employeeStatus CHARACTER VARYING(250), + recruitmentModeId BIGINT, + recruitmentTypeId BIGINT, + recruitmentQuotaId BIGINT, + retirementAge INTEGER, + dateOfResignation DATE, + dateOfTermination DATE, + employeeTypeId BIGINT, + motherTongueId BIGINT, + religionId BIGINT, + communityId BIGINT, + categoryId BIGINT, + physicallyDisabled BOOLEAN NOT NULL, + medicalReportProduced BOOLEAN NOT NULL, + maritalStatus CHARACTER VARYING(250), + passportNo CHARACTER VARYING(250) NOT NULL, + gpfNo CHARACTER VARYING(250) NOT NULL, + bankId BIGINT, + bankBranchId BIGINT, + bankAccount CHARACTER VARYING(20) NOT NULL, + groupId BIGINT, + placeOfBirth CHARACTER VARYING(200) NOT NULL, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_employee PRIMARY KEY (Id), + CONSTRAINT uk_egeis_employee_code UNIQUE (code), + CONSTRAINT ck_egeis_employee_retirementAge CHECK (retirementAge <= 100), + CONSTRAINT ck_egeis_employee_dateOfAppointment CHECK (dateOfAppointment <= dateOfJoining), + CONSTRAINT ck_egeis_employee_dateOfRetirement CHECK (dateOfRetirement >= dateOfJoining), + CONSTRAINT ck_egeis_employee_dateOfResignation CHECK (dateOfResignation >= dateOfJoining), + CONSTRAINT ck_egeis_employee_dateOfTermination CHECK (dateOfTermination >= dateOfJoining) +); + +CREATE SEQUENCE seq_egeis_employee + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185602__hr_employee_assignment.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185602__hr_employee_assignment.sql new file mode 100644 index 00000000000..8874bba64e9 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185602__hr_employee_assignment.sql @@ -0,0 +1,31 @@ +CREATE TABLE egeis_assignment ( + id BIGINT NOT NULL, + employeeId BIGINT, + positionId BIGINT NOT NULL, + fundId BIGINT, + functionaryId BIGINT, + functionId BIGINT, + departmentId BIGINT NOT NULL, + designationId BIGINT NOT NULL, + isPrimary BOOLEAN NOT NULL, + fromDate DATE NOT NULL, + toDate DATE NOT NULL, + gradeId BIGINT, + govtOrderNumber CHARACTER VARYING(250), + createdBy BIGINT NOT NULL, + createdDate DATE NOT NULL, + lastModifiedBy BIGINT, + lastModifiedDate DATE, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_assignment PRIMARY KEY (id), + CONSTRAINT fk_egeis_assignment_employeeId FOREIGN KEY (employeeId) + REFERENCES egeis_employee (id) +); + +CREATE SEQUENCE seq_egeis_assignment + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185603__hr_employee_educationalqualification.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185603__hr_employee_educationalqualification.sql new file mode 100644 index 00000000000..2628586d321 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185603__hr_employee_educationalqualification.sql @@ -0,0 +1,24 @@ +CREATE TABLE egeis_educationalQualification ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + qualification CHARACTER VARYING(250) NOT NULL, + majorSubject CHARACTER VARYING(250), + yearOfPassing INTEGER NOT NULL, + university CHARACTER VARYING(250), + createdBy BIGINT NOT NULL, + createdDate DATE NOT NULL, + lastModifiedBy BIGINT, + lastModifiedDate DATE, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_educationalQualification PRIMARY KEY (Id), + CONSTRAINT fk_egeis_educationalQualification_employeeId FOREIGN KEY (employeeId) + REFERENCES egeis_employee (id) +); + +CREATE SEQUENCE seq_egeis_educationalQualification + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185604__hr_employee_departmentaltest.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185604__hr_employee_departmentaltest.sql new file mode 100644 index 00000000000..60fbc452966 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185604__hr_employee_departmentaltest.sql @@ -0,0 +1,23 @@ +CREATE TABLE egeis_departmentalTest ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + test CHARACTER VARYING(250) NOT NULL, + yearOfPassing INTEGER NOT NULL, + remarks CHARACTER VARYING(250), + createdBy BIGINT NOT NULL, + createdDate DATE NOT NULL, + lastModifiedBy BIGINT, + lastModifiedDate DATE, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_departmentalTest PRIMARY KEY (Id), + CONSTRAINT fk_egeis_departmentalTest_employeeId FOREIGN KEY (employeeId) + REFERENCES egeis_employee (id) +); + +CREATE SEQUENCE seq_egeis_departmentalTest + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185605__hr_employee_employee_jurisdictions.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185605__hr_employee_employee_jurisdictions.sql new file mode 100644 index 00000000000..ef7e25e8fb8 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185605__hr_employee_employee_jurisdictions.sql @@ -0,0 +1,15 @@ +CREATE TABLE egeis_employeeJurisdictions ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + jurisdictionId BIGINT NOT NULL, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_employeeJurisdictions PRIMARY KEY (Id) +); + +CREATE SEQUENCE seq_egeis_employeeJurisdictions + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185606__hr_employee_hoddepartment.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185606__hr_employee_hoddepartment.sql new file mode 100644 index 00000000000..6eb5bf38ca0 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185606__hr_employee_hoddepartment.sql @@ -0,0 +1,17 @@ +CREATE TABLE egeis_hodDepartment ( + id BIGINT NOT NULL, + departmentId BIGINT NOT NULL, + assignmentId BIGINT NOT NULL, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_hodDepartment PRIMARY KEY (Id), + CONSTRAINT egeis_hodDepartment_assignmentId FOREIGN KEY (assignmentId) + REFERENCES egeis_assignment(id) +); + +CREATE SEQUENCE seq_egeis_hodDepartment + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185607__hr_employee_employee_languages.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185607__hr_employee_employee_languages.sql new file mode 100644 index 00000000000..370f6b49244 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185607__hr_employee_employee_languages.sql @@ -0,0 +1,15 @@ +CREATE TABLE egeis_employeeLanguages ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + languageId BIGINT NOT NULL, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_employee_languages PRIMARY KEY (Id) +); + +CREATE SEQUENCE seq_egeis_employeeLanguages + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185608__hr_employee_probation.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185608__hr_employee_probation.sql new file mode 100644 index 00000000000..9b5ac43cbb5 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185608__hr_employee_probation.sql @@ -0,0 +1,25 @@ +CREATE TABLE egeis_probation ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + designationId BIGINT NOT NULL, + declaredOn DATE NOT NULL, + orderNo CHARACTER VARYING(250), + orderDate DATE, + remarks CHARACTER VARYING(250), + createdBy BIGINT NOT NULL, + createdDate DATE NOT NULL, + lastModifiedBy BIGINT, + lastModifiedDate DATE, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_probation PRIMARY KEY (Id), + CONSTRAINT fk_egeis_probation_employeeId FOREIGN KEY (employeeId) + REFERENCES egeis_employee (id) +); + +CREATE SEQUENCE seq_egeis_probation + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185609__hr_employee_regularisation.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185609__hr_employee_regularisation.sql new file mode 100644 index 00000000000..04b15a7cdb8 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185609__hr_employee_regularisation.sql @@ -0,0 +1,25 @@ +CREATE TABLE egeis_regularisation ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + designationId BIGINT NOT NULL, + declaredOn DATE NOT NULL, + orderNo CHARACTER VARYING(250), + orderDate DATE NOT NULL, + remarks CHARACTER VARYING(250), + createdBy BIGINT NOT NULL, + createdDate DATE NOT NULL, + lastModifiedBy BIGINT, + lastModifiedDate DATE, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_regularisation PRIMARY KEY (Id), + CONSTRAINT fk_egeis_regularisation_employeeId FOREIGN KEY (employeeId) + REFERENCES egeis_employee (id) +); + +CREATE SEQUENCE seq_egeis_regularisation + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185610__hr_employee_servicehistory.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185610__hr_employee_servicehistory.sql new file mode 100644 index 00000000000..ed40fb8ba5a --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185610__hr_employee_servicehistory.sql @@ -0,0 +1,24 @@ +CREATE TABLE egeis_serviceHistory ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + serviceInfo CHARACTER VARYING(250) NOT NULL, + serviceFrom DATE NOT NULL, + remarks CHARACTER VARYING(250), + orderNo CHARACTER VARYING(250), + createdBy BIGINT NOT NULL, + createdDate DATE NOT NULL, + lastModifiedBy BIGINT, + lastModifiedDate DATE, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_serviceHistory PRIMARY KEY (Id), + CONSTRAINT fk_egeis_serviceHistory_employeeId FOREIGN KEY (employeeId) + REFERENCES egeis_employee (id) +); + +CREATE SEQUENCE seq_egeis_serviceHistory + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185611__hr_employee_technicalqualification.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185611__hr_employee_technicalqualification.sql new file mode 100644 index 00000000000..85a261a8551 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185611__hr_employee_technicalqualification.sql @@ -0,0 +1,24 @@ +CREATE TABLE egeis_technicalQualification ( + id BIGINT NOT NULL, + employeeID BIGINT NOT NULL, + skill CHARACTER VARYING(250) NOT NULL, + grade CHARACTER VARYING(250), + yearOfPassing INTEGER, + remarks CHARACTER VARYING(250), + createdBy BIGINT NOT NULL, + createdDate DATE NOT NULL, + lastModifiedBy BIGINT, + lastModifiedDate DATE, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_technicalQualification PRIMARY KEY (Id), + CONSTRAINT fk_egeis_technicalQualification_employeeId FOREIGN KEY (employeeId) + REFERENCES egeis_employee (id) +); + +CREATE SEQUENCE seq_egeis_technicalQualification + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185612__hr_employee_added_and_updated_foreign_key_constraints.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185612__hr_employee_added_and_updated_foreign_key_constraints.sql new file mode 100644 index 00000000000..d2674ce5141 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185612__hr_employee_added_and_updated_foreign_key_constraints.sql @@ -0,0 +1,8 @@ +ALTER TABLE egeis_employeeJurisdictions ADD CONSTRAINT fk_egeis_employeeJurisdictions_employeeId + FOREIGN KEY (employeeId) REFERENCES egeis_employee (id); + +ALTER TABLE egeis_employeeLanguages ADD CONSTRAINT fk_egeis_employeeLanguages_employeeId + FOREIGN KEY (employeeId) REFERENCES egeis_employee (id); + +ALTER TABLE egeis_hodDepartment RENAME CONSTRAINT egeis_hodDepartment_assignmentId + TO fk_egeis_hodDepartment_assignmentId; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185613__updated_null_checks_in_egeis_employee_table.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185613__updated_null_checks_in_egeis_employee_table.sql new file mode 100644 index 00000000000..4cc00f0605d --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185613__updated_null_checks_in_egeis_employee_table.sql @@ -0,0 +1,9 @@ +ALTER TABLE egeis_employee ALTER COLUMN code SET NOT NULL; +ALTER TABLE egeis_employee ALTER COLUMN employeeStatus SET NOT NULL; +ALTER TABLE egeis_employee ALTER COLUMN employeeTypeId SET NOT NULL; +ALTER TABLE egeis_employee ALTER COLUMN physicallyDisabled DROP NOT NULL; +ALTER TABLE egeis_employee ALTER COLUMN medicalReportProduced DROP NOT NULL; +ALTER TABLE egeis_employee ALTER COLUMN passportNo DROP NOT NULL; +ALTER TABLE egeis_employee ALTER COLUMN gpfNo DROP NOT NULL; +ALTER TABLE egeis_employee ALTER COLUMN bankAccount DROP NOT NULL; +ALTER TABLE egeis_employee ALTER COLUMN placeOfBirth DROP NOT NULL; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185614__updated_null_checks_in_egeis_regularisation_table.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185614__updated_null_checks_in_egeis_regularisation_table.sql new file mode 100644 index 00000000000..8c5e1be4db1 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185614__updated_null_checks_in_egeis_regularisation_table.sql @@ -0,0 +1 @@ +ALTER TABLE egeis_regularisation ALTER COLUMN orderDate DROP NOT NULL; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185615__hr_employee_employeedocuments.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185615__hr_employee_employeedocuments.sql new file mode 100644 index 00000000000..b0f7559dd17 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185615__hr_employee_employeedocuments.sql @@ -0,0 +1,18 @@ +CREATE TABLE egeis_employeeDocuments ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + document CHARACTER VARYING(1000) NOT NULL, + referenceType CHARACTER VARYING(25), + referenceId BIGINT, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_employeeDocuments PRIMARY KEY (Id), + CONSTRAINT uk_egeis_employeeDocuments_document UNIQUE (document) +); + +CREATE SEQUENCE seq_egeis_employeeDocuments + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185616__updated_unique_constraint_in_hr_employee.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185616__updated_unique_constraint_in_hr_employee.sql new file mode 100644 index 00000000000..99aa51c4de5 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185616__updated_unique_constraint_in_hr_employee.sql @@ -0,0 +1,7 @@ +TRUNCATE TABLE egeis_employee CASCADE; +TRUNCATE TABLE egeis_assignment CASCADE; + +-- EMPLOYEE TABLE CONSTRAINTS +ALTER TABLE egeis_employee ADD CONSTRAINT uk_egeis_employee_passportNo UNIQUE (passportNo); +ALTER TABLE egeis_employee ADD CONSTRAINT uk_egeis_employee_gpfNo UNIQUE (gpfNo); +ALTER TABLE egeis_employee ADD CONSTRAINT uk_egeis_employee_bankAccount UNIQUE (bankAccount); diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185617__updated_createdDate_and_lastModifiedDate_columns.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185617__updated_createdDate_and_lastModifiedDate_columns.sql new file mode 100644 index 00000000000..d16112e9c51 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185617__updated_createdDate_and_lastModifiedDate_columns.sql @@ -0,0 +1,20 @@ +ALTER TABLE egeis_assignment ALTER COLUMN createdDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (createdDate::TIMESTAMP WITHOUT TIME ZONE); +ALTER TABLE egeis_assignment ALTER COLUMN lastModifiedDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (lastModifiedDate::TIMESTAMP WITHOUT TIME ZONE); + +ALTER TABLE egeis_departmentaltest ALTER COLUMN createdDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (createdDate::TIMESTAMP WITHOUT TIME ZONE); +ALTER TABLE egeis_departmentaltest ALTER COLUMN lastModifiedDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (lastModifiedDate::TIMESTAMP WITHOUT TIME ZONE); + +ALTER TABLE egeis_educationalqualification ALTER COLUMN createdDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (createdDate::TIMESTAMP WITHOUT TIME ZONE); +ALTER TABLE egeis_educationalqualification ALTER COLUMN lastModifiedDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (lastModifiedDate::TIMESTAMP WITHOUT TIME ZONE); + +ALTER TABLE egeis_probation ALTER COLUMN createdDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (createdDate::TIMESTAMP WITHOUT TIME ZONE); +ALTER TABLE egeis_probation ALTER COLUMN lastModifiedDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (lastModifiedDate::TIMESTAMP WITHOUT TIME ZONE); + +ALTER TABLE egeis_regularisation ALTER COLUMN createdDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (createdDate::TIMESTAMP WITHOUT TIME ZONE); +ALTER TABLE egeis_regularisation ALTER COLUMN lastModifiedDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (lastModifiedDate::TIMESTAMP WITHOUT TIME ZONE); + +ALTER TABLE egeis_servicehistory ALTER COLUMN createdDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (createdDate::TIMESTAMP WITHOUT TIME ZONE); +ALTER TABLE egeis_servicehistory ALTER COLUMN lastModifiedDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (lastModifiedDate::TIMESTAMP WITHOUT TIME ZONE); + +ALTER TABLE egeis_technicalqualification ALTER COLUMN createdDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (createdDate::TIMESTAMP WITHOUT TIME ZONE); +ALTER TABLE egeis_technicalqualification ALTER COLUMN lastModifiedDate TYPE TIMESTAMP WITHOUT TIME ZONE USING (lastModifiedDate::TIMESTAMP WITHOUT TIME ZONE); diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185618__updated_combination_pk.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185618__updated_combination_pk.sql new file mode 100644 index 00000000000..efdce215e6f --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185618__updated_combination_pk.sql @@ -0,0 +1,89 @@ +---------------------------- DROP FOREIGN KEYS ---------------------------- + +ALTER TABLE egeis_assignment DROP CONSTRAINT fk_egeis_assignment_employeeid; +ALTER TABLE egeis_hoddepartment DROP CONSTRAINT fk_egeis_hoddepartment_assignmentid; +ALTER TABLE egeis_employeejurisdictions DROP CONSTRAINT fk_egeis_employeejurisdictions_employeeid; +ALTER TABLE egeis_employeelanguages DROP CONSTRAINT fk_egeis_employeelanguages_employeeid; +ALTER TABLE egeis_departmentaltest DROP CONSTRAINT fk_egeis_departmentaltest_employeeid; +ALTER TABLE egeis_educationalqualification DROP CONSTRAINT fk_egeis_educationalqualification_employeeid; +ALTER TABLE egeis_probation DROP CONSTRAINT fk_egeis_probation_employeeid; +ALTER TABLE egeis_regularisation DROP CONSTRAINT fk_egeis_regularisation_employeeid; +ALTER TABLE egeis_servicehistory DROP CONSTRAINT fk_egeis_servicehistory_employeeid; +ALTER TABLE egeis_technicalqualification DROP CONSTRAINT fk_egeis_technicalqualification_employeeid; + + +--------------------------- UPDATE PRIMARY KEYS --------------------------- + +-- EGEIS_EMPLOYEE TABLE +ALTER TABLE egeis_employee DROP CONSTRAINT uk_egeis_employee_bankaccount; +ALTER TABLE egeis_employee DROP CONSTRAINT pk_egeis_employee; +ALTER TABLE egeis_employee ADD CONSTRAINT pk_egeis_employee PRIMARY KEY (id, tenantId); + +-- EGEIS_ASSIGNMENT TABLE +ALTER TABLE egeis_assignment DROP CONSTRAINT pk_egeis_assignment; +ALTER TABLE egeis_assignment ADD CONSTRAINT pk_egeis_assignment PRIMARY KEY (id, tenantId); + +-- EGEIS_HODDEPARTMENT TABLE +ALTER TABLE egeis_hoddepartment DROP CONSTRAINT pk_egeis_hoddepartment; +ALTER TABLE egeis_hoddepartment ADD CONSTRAINT pk_egeis_hoddepartment PRIMARY KEY (id, tenantId); + +-- EGEIS_EMPLOYEEDOCUMENTS TABLE +ALTER TABLE egeis_employeedocuments DROP CONSTRAINT pk_egeis_employeedocuments; +ALTER TABLE egeis_employeedocuments ADD CONSTRAINT pk_egeis_employeedocuments PRIMARY KEY (id, tenantId); + +-- EGEIS_EMPLOYEEJURISDICTIONS TABLE +ALTER TABLE egeis_employeejurisdictions DROP CONSTRAINT pk_egeis_employeejurisdictions; +ALTER TABLE egeis_employeejurisdictions ADD CONSTRAINT pk_egeis_employeejurisdictions PRIMARY KEY (id, tenantId); + +-- EGEIS_EMPLOYEELANGUAGES TABLE +ALTER TABLE egeis_employeelanguages DROP CONSTRAINT pk_egeis_employee_languages; +ALTER TABLE egeis_employeelanguages ADD CONSTRAINT pk_egeis_employeelanguages PRIMARY KEY (id, tenantId); + +-- EGEIS_DEPARTMENTALTEST TABLE +ALTER TABLE egeis_departmentaltest DROP CONSTRAINT pk_egeis_departmentaltest; +ALTER TABLE egeis_departmentaltest ADD CONSTRAINT pk_egeis_departmentaltest PRIMARY KEY (id, tenantId); + +-- EGEIS_EDUCATIONALQUALIFICATION TABLE +ALTER TABLE egeis_educationalqualification DROP CONSTRAINT pk_egeis_educationalqualification; +ALTER TABLE egeis_educationalqualification ADD CONSTRAINT pk_egeis_educationalqualification PRIMARY KEY (id, tenantId); + +-- EGEIS_PROBATION TABLE +ALTER TABLE egeis_probation DROP CONSTRAINT pk_egeis_probation; +ALTER TABLE egeis_probation ADD CONSTRAINT pk_egeis_probation PRIMARY KEY (id, tenantId); + +-- EGEIS_REGULARISATION TABLE +ALTER TABLE egeis_regularisation DROP CONSTRAINT pk_egeis_regularisation; +ALTER TABLE egeis_regularisation ADD CONSTRAINT pk_egeis_regularisation PRIMARY KEY (id, tenantId); + +-- EGEIS_SERVICEHISTORY TABLE +ALTER TABLE egeis_servicehistory DROP CONSTRAINT pk_egeis_servicehistory; +ALTER TABLE egeis_servicehistory ADD CONSTRAINT pk_egeis_servicehistory PRIMARY KEY (id, tenantId); + +-- EGEIS_TECHNICALQUALIFICATION TABLE +ALTER TABLE egeis_technicalqualification DROP CONSTRAINT pk_egeis_technicalqualification; +ALTER TABLE egeis_technicalqualification ADD CONSTRAINT pk_egeis_technicalqualification PRIMARY KEY (id, tenantId); + + +-------------------------- RECREATE FOREIGN KEYS -------------------------- + +ALTER TABLE egeis_assignment ADD CONSTRAINT fk_egeis_assignment_employeeid FOREIGN KEY (employeeid, tenantId) + REFERENCES egeis_employee (id, tenantId); +ALTER TABLE egeis_hoddepartment ADD CONSTRAINT fk_egeis_hoddepartment_assignmentid FOREIGN KEY (assignmentid, tenantId) + REFERENCES egeis_assignment (id, tenantId); +ALTER TABLE egeis_employeejurisdictions ADD CONSTRAINT fk_egeis_employeejurisdictions_employeeid FOREIGN KEY (employeeid, tenantId) + REFERENCES egeis_employee (id, tenantId); +ALTER TABLE egeis_employeelanguages ADD CONSTRAINT fk_egeis_employeelanguages_employeeid FOREIGN KEY (employeeid, tenantId) + REFERENCES egeis_employee (id, tenantId); +ALTER TABLE egeis_departmentaltest ADD CONSTRAINT fk_egeis_departmentaltest_employeeid FOREIGN KEY (employeeid, tenantId) + REFERENCES egeis_employee (id, tenantId); +ALTER TABLE egeis_educationalqualification ADD CONSTRAINT fk_egeis_educationalqualification_employeeid FOREIGN KEY (employeeid, tenantId) + REFERENCES egeis_employee (id, tenantId); +ALTER TABLE egeis_probation ADD CONSTRAINT fk_egeis_probation_employeeid FOREIGN KEY (employeeid, tenantId) + REFERENCES egeis_employee (id, tenantId); +ALTER TABLE egeis_regularisation ADD CONSTRAINT fk_egeis_regularisation_employeeid FOREIGN KEY (employeeid, tenantId) + REFERENCES egeis_employee (id, tenantId); +ALTER TABLE egeis_servicehistory ADD CONSTRAINT fk_egeis_servicehistory_employeeid FOREIGN KEY (employeeid, tenantId) + REFERENCES egeis_employee (id, tenantId); +ALTER TABLE egeis_technicalqualification ADD CONSTRAINT fk_egeis_technicalqualification_employeeid FOREIGN KEY (employeeid, tenantId) + REFERENCES egeis_employee (id, tenantId); + diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185619__updated_foreign_key_names.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185619__updated_foreign_key_names.sql new file mode 100644 index 00000000000..8e5fe900872 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170227185619__updated_foreign_key_names.sql @@ -0,0 +1,29 @@ +ALTER TABLE egeis_assignment + RENAME CONSTRAINT fk_egeis_assignment_employeeid TO fk_egeis_assignment_employeeid_tenantid; + +ALTER TABLE egeis_hoddepartment + RENAME CONSTRAINT fk_egeis_hoddepartment_assignmentid TO fk_egeis_hoddepartment_assignmentid_tenantid; + +ALTER TABLE egeis_employeejurisdictions + RENAME CONSTRAINT fk_egeis_employeejurisdictions_employeeid TO fk_egeis_employeejurisdictions_employeeid_tenantid; + +ALTER TABLE egeis_employeelanguages + RENAME CONSTRAINT fk_egeis_employeelanguages_employeeid TO fk_egeis_employeelanguages_employeeid_tenantid; + +ALTER TABLE egeis_departmentaltest + RENAME CONSTRAINT fk_egeis_departmentaltest_employeeid TO fk_egeis_departmentaltest_employeeid_tenantid; + +ALTER TABLE egeis_educationalqualification + RENAME CONSTRAINT fk_egeis_educationalqualification_employeeid TO fk_egeis_educationalqualification_employeeid_tenantid; + +ALTER TABLE egeis_probation + RENAME CONSTRAINT fk_egeis_probation_employeeid TO fk_egeis_probation_employeeid_tenantid; + +ALTER TABLE egeis_regularisation + RENAME CONSTRAINT fk_egeis_regularisation_employeeid TO fk_egeis_regularisation_employeeid_tenantid; + +ALTER TABLE egeis_servicehistory + RENAME CONSTRAINT fk_egeis_servicehistory_employeeid TO fk_egeis_servicehistory_employeeid_tenantid; + +ALTER TABLE egeis_technicalqualification + RENAME CONSTRAINT fk_egeis_technicalqualification_employeeid TO fk_egeis_technicalqualification_employeeid_tenantid; diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170420145502__update_combination_uk.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170420145502__update_combination_uk.sql new file mode 100644 index 00000000000..76cfc669407 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170420145502__update_combination_uk.sql @@ -0,0 +1,12 @@ +-------------------------UPDATE UNIQUE KEY CONSTRAINT------------------------ + +--EGEIS_EMPLOYEE + +ALTER TABLE egeis_employee DROP CONSTRAINT if exists uk_egeis_employee_code; +ALTER TABLE egeis_employee ADD CONSTRAINT uk_egeis_employee_code UNIQUE (code,tenantid); + +ALTER TABLE egeis_employee DROP CONSTRAINT if exists uk_egeis_employee_passportNo; +ALTER TABLE egeis_employee ADD CONSTRAINT uk_egeis_employee_passportNo UNIQUE (passportNo,tenantid); + +ALTER TABLE egeis_employee DROP CONSTRAINT if exists uk_egeis_employee_gpfNo; +ALTER TABLE egeis_employee ADD CONSTRAINT uk_egeis_employee_gpfNo UNIQUE (gpfNo,tenantid); \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170502150908__updated_employeestatus_column_datatype.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170502150908__updated_employeestatus_column_datatype.sql new file mode 100644 index 00000000000..4c856708382 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170502150908__updated_employeestatus_column_datatype.sql @@ -0,0 +1 @@ +ALTER TABLE egeis_employee ALTER COLUMN employeeStatus TYPE BIGINT USING (employeeStatus::BIGINT); diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170509104227__hr_employee_add_lastmodifieddate.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170509104227__hr_employee_add_lastmodifieddate.sql new file mode 100644 index 00000000000..03ce59abaa8 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170509104227__hr_employee_add_lastmodifieddate.sql @@ -0,0 +1,3 @@ +alter table egeis_employee add column lastmodifieddate TIMESTAMP WITHOUT TIME ZONE default now(); + +alter table egeis_employeejurisdictions add column lastmodifieddate TIMESTAMP WITHOUT TIME ZONE default now(); \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170509121707__hr_hoddepartment_add_lastmodifieddate.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170509121707__hr_hoddepartment_add_lastmodifieddate.sql new file mode 100644 index 00000000000..318e17addaa --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170509121707__hr_hoddepartment_add_lastmodifieddate.sql @@ -0,0 +1 @@ +alter table egeis_hoddepartment add column lastmodifieddate TIMESTAMP WITHOUT TIME ZONE default now(); diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170525144339__hr_employee_added_createdBy_createdDate_lastModifiedBy_lastModifiedDate_columns.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170525144339__hr_employee_added_createdBy_createdDate_lastModifiedBy_lastModifiedDate_columns.sql new file mode 100644 index 00000000000..e06605f3f10 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170525144339__hr_employee_added_createdBy_createdDate_lastModifiedBy_lastModifiedDate_columns.sql @@ -0,0 +1,7 @@ +ALTER TABLE egeis_employee DROP COLUMN IF EXISTS createdBy; +ALTER TABLE egeis_employee DROP COLUMN IF EXISTS createdDate; +ALTER TABLE egeis_employee DROP COLUMN IF EXISTS lastModifiedBy; + +ALTER TABLE egeis_employee ADD COLUMN createdBy BIGINT NOT NULL DEFAULT 1; +ALTER TABLE egeis_employee ADD COLUMN createdDate TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT now(); +ALTER TABLE egeis_employee ADD COLUMN lastModifiedBy BIGINT; diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170609165847__egeis_nominee_table.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170609165847__egeis_nominee_table.sql new file mode 100644 index 00000000000..ff10ad6733e --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170609165847__egeis_nominee_table.sql @@ -0,0 +1,30 @@ +CREATE TABLE egeis_nominee ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + name CHARACTER VARYING(100) NOT NULL, + gender CHARACTER VARYING(15) NOT NULL, + dateOfBirth BIGINT NOT NULL, + maritalStatus CHARACTER VARYING(15) NOT NULL, + relationship CHARACTER VARYING(20) NOT NULL, + bankId BIGINT, + bankBranchId BIGINT, + bankAccount CHARACTER VARYING(20), + nominated boolean NOT NULL, + employed boolean NOT NULL, + createdBy BIGINT NOT NULL, + createdDate BIGINT NOT NULL, + lastModifiedBy BIGINT, + lastModifiedDate BIGINT, + tenantId CHARACTER VARYING(250) NOT NULL, + + CONSTRAINT pk_egeis_nominee PRIMARY KEY (id, tenantId), + CONSTRAINT fk_egeis_nominee_employeeId FOREIGN KEY (employeeId, tenantId) + REFERENCES egeis_employee (id, tenantId) +); + +CREATE SEQUENCE seq_egeis_nominee + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170703101329__dropped_unique_document_constraint_from_egeis_employeedocuments.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170703101329__dropped_unique_document_constraint_from_egeis_employeedocuments.sql new file mode 100644 index 00000000000..f8e86ac0fbe --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170703101329__dropped_unique_document_constraint_from_egeis_employeedocuments.sql @@ -0,0 +1,2 @@ +-- Dropping since now the document attachments are already going to be UUID +ALTER TABLE egeis_employeeDocuments DROP CONSTRAINT uk_egeis_employeeDocuments_document; diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20170707184507__egeis_aprdetails_table.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170707184507__egeis_aprdetails_table.sql new file mode 100644 index 00000000000..fa3734d30bd --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20170707184507__egeis_aprdetails_table.sql @@ -0,0 +1,24 @@ +CREATE TABLE egeis_aprDetails ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + yearOfSubmission INTEGER NOT NULL, + detailsSubmitted BOOLEAN NOT NULL, + dateOfSubmission DATE, + remarks CHARACTER VARYING(1024), + createdBy BIGINT NOT NULL, + createdDate TIMESTAMP WITHOUT TIME ZONE NOT NULL, + lastModifiedBy BIGINT, + lastModifiedDate TIMESTAMP WITHOUT TIME ZONE, + tenantId CHARACTER VARYING(256) NOT NULL, + + CONSTRAINT pk_egeis_aprDetails PRIMARY KEY (id, tenantId), + CONSTRAINT fk_egeis_aprDetails_employeeId FOREIGN KEY (employeeId, tenantId) + REFERENCES egeis_employee (id, tenantId) +); + +CREATE SEQUENCE seq_egeis_aprDetails + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20171023104634__hr_employee_add_ifsccode.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20171023104634__hr_employee_add_ifsccode.sql new file mode 100644 index 00000000000..668fcadfe25 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20171023104634__hr_employee_add_ifsccode.sql @@ -0,0 +1 @@ +alter table egeis_employee add column ifscCode CHARACTER VARYING(20); \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20180310133312__hr_employee_disciplinary.ddl.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180310133312__hr_employee_disciplinary.ddl.sql new file mode 100644 index 00000000000..5523340f27f --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180310133312__hr_employee_disciplinary.ddl.sql @@ -0,0 +1,56 @@ + CREATE TABLE egeis_disciplinary ( + id BIGINT NOT NULL, + employeeId BIGINT NOT NULL, + gistCase CHARACTER VARYING(250) NOT NULL, + disciplinaryAuthority CHARACTER VARYING(250) NOT NULL, + orderNo CHARACTER VARYING(250) NOT NULL, + orderDate DATE NOT NULL, + memoNo CHARACTER VARYING(250) NOT NULL, + memoDate DATE NOT NULL, + memoServingDate DATE NOT NULL, + dateOfReceiptMemoDate DATE, + explanationAccepted BOOLEAN, + chargeMemoNo CHARACTER VARYING(250), + chargeMemoDate DATE, + dateOfReceiptToChargeMemoDate DATE, + accepted BOOLEAN, + dateOfAppointmentOfEnquiryOfficerDate DATE, + enquiryOfficerName CHARACTER VARYING(250), + dateOfAppointmentOfPresentingOfficer DATE , + presentingOfficerName CHARACTER VARYING(250), + findingsOfEO CHARACTER VARYING(250), + enquiryReportSubmittedDate DATE, + dateOfCommunicationOfER DATE, + dateOfSubmissionOfExplanationByCO DATE, + acceptanceOfExplanation BOOLEAN, + proposedPunishmentByDA CHARACTER VARYING(250), + showCauseNoticeNo CHARACTER VARYING(250), + showCauseNoticeDate DATE, + showCauseNoticeServingDate DATE, + explanationToShowCauseNotice CHARACTER VARYING(250), + explanationToShowCauseNoticeAccepted BOOLEAN, + punishmentAwarded CHARACTER VARYING(250) , + proceedingsNumber CHARACTER VARYING(250), + proceedingsDate DATE, + proceedingsServingDate DATE, + courtCase BOOLEAN, + courtOrderNo CHARACTER VARYING(250), + courtOrderDate DATE, + gistOfDirectionIssuedByCourt CHARACTER VARYING(250), + createdBy BIGINT NOT NULL, + createdDate DATE NOT NULL, + lastModifiedBy BIGINT, + lastModifiedDate DATE, + tenantId CHARACTER VARYING(250) NOT NULL, + CONSTRAINT pk_egeis_disciplinary PRIMARY KEY (id,tenantId), + CONSTRAINT fk_egeis_disciplinary_employeeId FOREIGN KEY (employeeId,tenantId) + REFERENCES egeis_employee (id,tenantId) +); + +CREATE SEQUENCE seq_egeis_disciplinary + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20180310133625__hr_employee_disciplinary_documents.ddl.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180310133625__hr_employee_disciplinary_documents.ddl.sql new file mode 100644 index 00000000000..a561aa45ee8 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180310133625__hr_employee_disciplinary_documents.ddl.sql @@ -0,0 +1,15 @@ +CREATE TABLE egeis_disciplinaryDocuments ( + id BIGINT NOT NULL, + disciplinaryId BIGINT NOT NULL, + documentType CHARACTER VARYING(25) , + filestoreId CHARACTER VARYING NOT NULL, + tenantId CHARACTER VARYING (250) NOT NULL, + CONSTRAINT pk_egeis_disciplinaryDocuments PRIMARY KEY (id,tenantid) +); + +CREATE SEQUENCE seq_egeis_disciplinaryDocument + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20180312150245__hr_employee_disciplinary_alter_add_column.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180312150245__hr_employee_disciplinary_alter_add_column.sql new file mode 100644 index 00000000000..ae5f0fd4adb --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180312150245__hr_employee_disciplinary_alter_add_column.sql @@ -0,0 +1,7 @@ +alter table egeis_disciplinary add column courtOrderType CHARACTER VARYING(250); + +alter table egeis_disciplinary add column presentingOfficerDesignation CHARACTER VARYING(250); + +alter table egeis_disciplinary add column enquiryOfficerDesignation CHARACTER VARYING(250); + +alter table egeis_disciplinary alter column memoServingDate drop NOT NULL; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20180314134356__hr_employee_disciplinary_alter_length_modify.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180314134356__hr_employee_disciplinary_alter_length_modify.sql new file mode 100644 index 00000000000..c22578e6118 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180314134356__hr_employee_disciplinary_alter_length_modify.sql @@ -0,0 +1,14 @@ +ALTER TABLE egeis_disciplinary + ALTER COLUMN gistcase TYPE character varying(1000); + +ALTER TABLE egeis_disciplinary + ALTER COLUMN findingsofeo TYPE character varying(1000); + +ALTER TABLE egeis_disciplinary + ALTER COLUMN proposedpunishmentbyda TYPE character varying(1000); + +ALTER TABLE egeis_disciplinary + ALTER COLUMN explanationtoshowcausenotice TYPE character varying(1000); + +ALTER TABLE egeis_disciplinary + ALTER COLUMN gistofdirectionissuedbycourt TYPE character varying(1000); \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20180315135946__hr_employee_disciplinary_alter_add_remove_columns.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180315135946__hr_employee_disciplinary_alter_add_remove_columns.sql new file mode 100644 index 00000000000..5d29e00d8d0 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180315135946__hr_employee_disciplinary_alter_add_remove_columns.sql @@ -0,0 +1,7 @@ +ALTER TABLE egeis_disciplinary DROP COLUMN orderno; + +ALTER TABLE egeis_disciplinary DROP COLUMN orderdate; + +alter table egeis_disciplinary add column punishmentimplemented BOOLEAN; + +alter table egeis_disciplinary add column enddateofpunishment DATE; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20180316163101__hr_employee_servicehistory_add_column.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180316163101__hr_employee_servicehistory_add_column.sql new file mode 100644 index 00000000000..44e85f76af0 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180316163101__hr_employee_servicehistory_add_column.sql @@ -0,0 +1,8 @@ +alter table egeis_servicehistory +add column city CHARACTER VARYING(250), +add column department CHARACTER VARYING(250), +add column designation CHARACTER VARYING(250), +add column positionId BIGINT, +add column serviceTo DATE, +add column isAssignmentBased BOOLEAN NOT NULL DEFAULT false, +add column assignmentId BIGINT ; \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20180416144447__hr_employee_department_alter_type.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180416144447__hr_employee_department_alter_type.sql new file mode 100644 index 00000000000..2986f83d677 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180416144447__hr_employee_department_alter_type.sql @@ -0,0 +1,3 @@ +ALTER TABLE egeis_assignment ALTER COLUMN departmentId TYPE varchar(256); + +ALTER TABLE egeis_hodDepartment ALTER COLUMN departmentId TYPE varchar(256); \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/main/V20180418144447__hr_employee_designation_alter_type.sql b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180418144447__hr_employee_designation_alter_type.sql new file mode 100644 index 00000000000..cf8dcea3f9b --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/main/V20180418144447__hr_employee_designation_alter_type.sql @@ -0,0 +1 @@ +ALTER TABLE egeis_assignment ALTER COLUMN designationid TYPE varchar(256); diff --git a/core-services/egov-hrms/src/test/resources/db/migration/qa/V20170428152327__egeis_hremployee_sample_data_for_pgr.sql b/core-services/egov-hrms/src/test/resources/db/migration/qa/V20170428152327__egeis_hremployee_sample_data_for_pgr.sql new file mode 100644 index 00000000000..ea1477e6cb5 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/qa/V20170428152327__egeis_hremployee_sample_data_for_pgr.sql @@ -0,0 +1,18 @@ +INSERT INTO egeis_employee (id, code, dateofappointment, dateofjoining, dateofretirement, employeestatus, recruitmentmodeid, recruitmenttypeid, recruitmentquotaid, retirementage, dateofresignation, dateoftermination, employeetypeid, mothertongueid, religionid, communityid, categoryid, physicallydisabled, medicalreportproduced, maritalstatus, passportno, gpfno, bankid, bankbranchid, bankaccount, groupid, placeofbirth, tenantid) +VALUES ((select id from eg_user where username = 'narasappa' and tenantid = 'default'), '658039', NULL, NULL, NULL, (select id from egeis_hrstatus where code = 'EMPLOYED' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, +(select id from egeis_employeetype where name = 'Permanent' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'default'); +INSERT INTO egeis_employee (id, code, dateofappointment, dateofjoining, dateofretirement, employeestatus, recruitmentmodeid, recruitmenttypeid, recruitmentquotaid, retirementage, dateofresignation, dateoftermination, employeetypeid, mothertongueid, religionid, communityid, categoryid, physicallydisabled, medicalreportproduced, maritalstatus, passportno, gpfno, bankid, bankbranchid, bankaccount, groupid, placeofbirth, tenantid) +VALUES ((select id from eg_user where username = 'ramana' and tenantid = 'default'), '658040', NULL, NULL, NULL, (select id from egeis_hrstatus where code = 'EMPLOYED' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, +(select id from egeis_employeetype where name = 'Permanent' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'default'); + +INSERT INTO egeis_assignment (id, employeeid, positionid, fundid, functionaryid, functionid, departmentid, designationid, isprimary, fromdate, todate, gradeid, govtordernumber, createdby, createddate, lastmodifiedby, lastmodifieddate, tenantid) +VALUES (nextval('seq_egeis_assignment'), (select id from egeis_employee where code = '658039' and tenantid = 'default'), +(select id from egeis_position where name = 'ENG_Assistant Engineer_1' and tenantid = 'default'), NULL, NULL, NULL, +(select id from eg_department where code = 'ADM' and tenantid = 'default'), +(select id from egeis_designation where code = 'SASST' and tenantid = 'default'), true, '2015-04-01', '2020-03-31', NULL, NULL, 1, now(), 1, NULL, 'default'); +INSERT INTO egeis_assignment (id, employeeid, positionid, fundid, functionaryid, functionid, departmentid, designationid, isprimary, fromdate, todate, gradeid, govtordernumber, createdby, createddate, lastmodifiedby, lastmodifieddate, tenantid) +VALUES (nextval('seq_egeis_assignment'), (select id from egeis_employee where code = '658040' and tenantid = 'default'), +(select id from egeis_position where name = 'Acc_Senior Account_1' and tenantid = 'default'), NULL, NULL, NULL, +(select id from eg_department where code = 'ACC' and tenantid = 'default'), +(select id from egeis_designation where code = 'AO' and tenantid = 'default'), true, '2015-04-01', '2020-03-31', NULL, NULL, 1, now(), 1, NULL, 'default'); + diff --git a/core-services/egov-hrms/src/test/resources/db/migration/qa/V20170530010026__hr_employee_sample_data_for_panavel.sql b/core-services/egov-hrms/src/test/resources/db/migration/qa/V20170530010026__hr_employee_sample_data_for_panavel.sql new file mode 100644 index 00000000000..0cc581ae74c --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/qa/V20170530010026__hr_employee_sample_data_for_panavel.sql @@ -0,0 +1,20 @@ +INSERT INTO egeis_employee (id, code, dateofappointment, dateofjoining, dateofretirement, employeestatus, recruitmentmodeid, recruitmenttypeid, recruitmentquotaid, retirementage, dateofresignation, dateoftermination, employeetypeid, mothertongueid, religionid, communityid, categoryid, physicallydisabled, medicalreportproduced, maritalstatus, passportno, gpfno, bankid, bankbranchid, bankaccount, groupid, placeofbirth, tenantid) +VALUES ((select id from eg_user where username = 'admin' and tenantid = 'panavel'), '658039', NULL, NULL, NULL, (select id from egeis_hrstatus where code = 'EMPLOYED' and tenantid = 'panavel'), NULL, NULL, NULL, NULL, NULL, NULL, +(select id from egeis_employeetype where name = 'Permanent' and tenantid = 'panavel'), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'panavel'); + +INSERT INTO egeis_employee (id, code, dateofappointment, dateofjoining, dateofretirement, employeestatus, recruitmentmodeid, recruitmenttypeid, recruitmentquotaid, retirementage, dateofresignation, dateoftermination, employeetypeid, mothertongueid, religionid, communityid, categoryid, physicallydisabled, medicalreportproduced, maritalstatus, passportno, gpfno, bankid, bankbranchid, bankaccount, groupid, placeofbirth, tenantid) +VALUES ((select id from eg_user where username = 'ajay' and tenantid = 'panavel'), '658040', NULL, NULL, NULL, (select id from egeis_hrstatus where code = 'EMPLOYED' and tenantid = 'panavel'), NULL, NULL, NULL, NULL, NULL, NULL, +(select id from egeis_employeetype where name = 'Permanent' and tenantid = 'panavel'), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'panavel'); + +INSERT INTO egeis_assignment (id, employeeid, positionid, fundid, functionaryid, functionid, departmentid, designationid, isprimary, fromdate, todate, gradeid, govtordernumber, createdby, createddate, lastmodifiedby, lastmodifieddate, tenantid) +VALUES (nextval('seq_egeis_assignment'), (select id from egeis_employee where code = '658039' and tenantid = 'panavel'), +(select id from egeis_position where name = 'ENG_Assistant Engineer_2' and tenantid = 'panavel'), NULL, NULL, NULL, +(select id from eg_department where code = 'ADM' and tenantid = 'panavel'), +(select id from egeis_designation where code = 'SASST' and tenantid = 'panavel'), true, '2015-04-01', '2020-03-31', NULL, NULL, 1, now(), 1, NULL, 'panavel'); +INSERT INTO egeis_assignment (id, employeeid, positionid, fundid, functionaryid, functionid, departmentid, designationid, isprimary, fromdate, todate, gradeid, govtordernumber, createdby, createddate, lastmodifiedby, lastmodifieddate, tenantid) +VALUES (nextval('seq_egeis_assignment'), (select id from egeis_employee where code = '658040' and tenantid = 'panavel'), +(select id from egeis_position where name = 'Acc_Senior Account_2' and tenantid = 'panavel'), NULL, NULL, NULL, +(select id from eg_department where code = 'ENG' and tenantid = 'panavel'), +(select id from egeis_designation where code = 'AO' and tenantid = 'panavel'), true, '2015-04-01', '2020-03-31', NULL, NULL, 1, now(), 1, NULL, 'panavel'); + + diff --git a/core-services/egov-hrms/src/test/resources/db/migration/qa/V20170614093822__hr_employee_sample_data_for_default.sql b/core-services/egov-hrms/src/test/resources/db/migration/qa/V20170614093822__hr_employee_sample_data_for_default.sql new file mode 100644 index 00000000000..833a0c4c030 --- /dev/null +++ b/core-services/egov-hrms/src/test/resources/db/migration/qa/V20170614093822__hr_employee_sample_data_for_default.sql @@ -0,0 +1,9 @@ +INSERT INTO egeis_employee (id, code, dateofappointment, dateofjoining, dateofretirement, employeestatus, recruitmentmodeid, recruitmenttypeid, recruitmentquotaid, retirementage, dateofresignation, dateoftermination, employeetypeid, mothertongueid, religionid, communityid, categoryid, physicallydisabled, medicalreportproduced, maritalstatus, passportno, gpfno, bankid, bankbranchid, bankaccount, groupid, placeofbirth, tenantid) +VALUES ((select id from eg_user where username = 'ravi' and tenantid = 'default'), '658041', NULL, NULL, NULL, (select id from egeis_hrstatus where code = 'EMPLOYED' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, +(select id from egeis_employeetype where name = 'Permanent' and tenantid = 'default'), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 'default'); + +INSERT INTO egeis_assignment (id, employeeid, positionid, fundid, functionaryid, functionid, departmentid, designationid, isprimary, fromdate, todate, gradeid, govtordernumber, createdby, createddate, lastmodifiedby, lastmodifieddate, tenantid) +VALUES (nextval('seq_egeis_assignment'), (select id from egeis_employee where code = '658041' and tenantid = 'default'), +(select id from egeis_position where name = 'ENG_Junior Assistant_1' and tenantid = 'default'), NULL, NULL, NULL, +(select id from eg_department where code = 'ENG' and tenantid = 'default'), +(select id from egeis_designation where code = 'JASST' and tenantid = 'default'), true, '2015-04-01', '2020-03-31', NULL, NULL, 1, now(), 1, NULL, 'default'); \ No newline at end of file diff --git a/core-services/egov-hrms/src/test/resources/db/migration/seed/.gitkeep b/core-services/egov-hrms/src/test/resources/db/migration/seed/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d From c3f0d88635bf9bc599859697e907092e933c8859 Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Mon, 4 Mar 2024 13:10:04 +0530 Subject: [PATCH 238/283] Update build-config.yml (#665) --- build/build-config.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/build-config.yml b/build/build-config.yml index 13bc1db43fa..cce8d661b82 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -168,3 +168,10 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "core-services/egov-hrms/src/main/resources/db" image-name: "health-hrms-db" + - name: "builds/health-campaign-services/core-services/egov-hrms" + build: + - work-dir: "core-services/egov-hrms" + image-name: "egov-hrms" + dockerfile: "build/maven/Dockerfile" + - work-dir: "core-services/egov-hrms/src/main/resources/db" + image-name: "egov-hrms-db" From 0b1ea32a372e543e5baca4f4b743a02dce7840fb Mon Sep 17 00:00:00 2001 From: Priyanka-eGov <74049060+Priyanka-eGov@users.noreply.github.com> Date: Fri, 8 Mar 2024 11:17:36 +0530 Subject: [PATCH 239/283] HLM-5143 adding plan-service to build config (#672) --- build/build-config.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/build-config.yml b/build/build-config.yml index cce8d661b82..5e00d4c7b10 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -175,3 +175,10 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "core-services/egov-hrms/src/main/resources/db" image-name: "egov-hrms-db" + - name: "builds/health-campaign-services/health-services/plan-service" + build: + - work-dir: "health-services/plan-service" + image-name: "plan-service" + dockerfile: "build/maven/Dockerfile" + - work-dir: "health-services/plan-service/src/main/resources/db" + image-name: "plan-service-db" \ No newline at end of file From 53f866d28b9388994ae1669cce35a516f2494555 Mon Sep 17 00:00:00 2001 From: Priyanka-eGov Date: Wed, 13 Mar 2024 11:18:32 +0530 Subject: [PATCH 240/283] HLM-5143 adding different Dockerfile for Java 17 --- build/17/maven/Dockerfile | 34 ++++++++++++++++++++++++++++++++++ build/17/maven/start.sh | 11 +++++++++++ build/build-config.yml | 2 +- 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 build/17/maven/Dockerfile create mode 100644 build/17/maven/start.sh diff --git a/build/17/maven/Dockerfile b/build/17/maven/Dockerfile new file mode 100644 index 00000000000..0816437a705 --- /dev/null +++ b/build/17/maven/Dockerfile @@ -0,0 +1,34 @@ + +FROM egovio/amazoncorretto:17-alpine3.19 AS build +# FROM egovio/alpine-maven-builder-jdk-8:1-master-NA-6036091e AS build +#FROM ghcr.io/egovernments/alpine-maven-builder-jdk-8:1-master-na-6036091e AS build +ARG WORK_DIR +WORKDIR /app + +# Install Maven +RUN apk add --no-cache maven + +# copy the project files +COPY ${WORK_DIR}/pom.xml ./pom.xml +COPY build/maven/start.sh ./start.sh + +# not useful for stateless builds +# RUN mvn -B dependency:go-offline + +COPY ${WORK_DIR}/src ./src +RUN mvn -B -f /app/pom.xml package + + +# Create runtime image +#FROM egovio/8-openjdk-alpine +#FROM ghcr.io/egovernments/8-openjdk-alpine:latest +FROM egovio/amazoncorretto:17-alpine3.19 + + +WORKDIR /opt/egov + +COPY --from=build /app/target/*.jar /app/start.sh /opt/egov/ + +RUN chmod +x /opt/egov/start.sh + +CMD ["/opt/egov/start.sh"] diff --git a/build/17/maven/start.sh b/build/17/maven/start.sh new file mode 100644 index 00000000000..08bdd8de28e --- /dev/null +++ b/build/17/maven/start.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +if [[ -z "${JAVA_OPTS}" ]];then + export JAVA_OPTS="-Xmx64m -Xms64m" +fi + +if [ x"${JAVA_ENABLE_DEBUG}" != x ] && [ "${JAVA_ENABLE_DEBUG}" != "false" ]; then + java_debug_args="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=${JAVA_DEBUG_PORT:-5005}" +fi + +exec java ${java_debug_args} ${JAVA_OPTS} ${JAVA_ARGS} -jar /opt/egov/*.jar \ No newline at end of file diff --git a/build/build-config.yml b/build/build-config.yml index 5e00d4c7b10..023e442a76b 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -179,6 +179,6 @@ config: build: - work-dir: "health-services/plan-service" image-name: "plan-service" - dockerfile: "build/maven/Dockerfile" + dockerfile: "build/17/maven/Dockerfile" - work-dir: "health-services/plan-service/src/main/resources/db" image-name: "plan-service-db" \ No newline at end of file From 15c87e8d4250d84b3b11103907f1a11a88941a99 Mon Sep 17 00:00:00 2001 From: Priyanka-eGov Date: Wed, 13 Mar 2024 11:41:55 +0530 Subject: [PATCH 241/283] HLM-5143 removing start.sh --- build/17/maven/start.sh | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 build/17/maven/start.sh diff --git a/build/17/maven/start.sh b/build/17/maven/start.sh deleted file mode 100644 index 08bdd8de28e..00000000000 --- a/build/17/maven/start.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -if [[ -z "${JAVA_OPTS}" ]];then - export JAVA_OPTS="-Xmx64m -Xms64m" -fi - -if [ x"${JAVA_ENABLE_DEBUG}" != x ] && [ "${JAVA_ENABLE_DEBUG}" != "false" ]; then - java_debug_args="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=${JAVA_DEBUG_PORT:-5005}" -fi - -exec java ${java_debug_args} ${JAVA_OPTS} ${JAVA_ARGS} -jar /opt/egov/*.jar \ No newline at end of file From 31e7188d7b6e38a5960b63a7d24cf8e241cd3da5 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Mon, 8 Apr 2024 17:22:40 +0530 Subject: [PATCH 242/283] Update CODEOWNERS --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index b28b04f6431..82c9fb40e92 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,3 +1,3 @@ - +* @kavi-egov From b79a78899b7493e45f1a2122adbc2f43d44b5f21 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Mon, 8 Apr 2024 17:26:22 +0530 Subject: [PATCH 243/283] Update CODEOWNERS --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 82c9fb40e92..8223a68b3fb 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,3 +1,3 @@ -* @kavi-egov +* @kavi-egov @sathishp-eGov From 2170eb78ae7e3b984ddd7e39a5d3959ab7b5c93d Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Mon, 15 Apr 2024 15:52:57 +0530 Subject: [PATCH 244/283] HLM-5361: updated build-config.yml (#708) --- build/build-config.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/build/build-config.yml b/build/build-config.yml index 023e442a76b..301108b087a 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -54,7 +54,7 @@ config: build: - work-dir: "health-services/household" image-name: "household" - dockerfile: "build/maven/Dockerfile" + dockerfile: "build/17/maven/Dockerfile" - work-dir: "health-services/household/src/main/resources/db" image-name: "household-db" - name: "builds/health-campaign-services/health-services/individual" @@ -78,13 +78,6 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "health-services/attendance/src/main/resources/db" image-name: "health-attendance-db" - - name: "builds/health-campaign-services/health-services/household" - build: - - work-dir: "health-services/household" - image-name: "household" - dockerfile: "build/maven/Dockerfile" - - work-dir: "health-services/household/src/main/resources/db" - image-name: "household-db" - name: "builds/health-campaign-services/core-services/error-handler" build: - work-dir: "core-services/error-handler" From b9385cf2720958a21c753df3b39e45ebf5fa53e0 Mon Sep 17 00:00:00 2001 From: Shashwat Mishra <71879793+shashwat-egov@users.noreply.github.com> Date: Tue, 16 Apr 2024 17:40:46 +0530 Subject: [PATCH 245/283] Adding auth proxy build config to master (#710) --- build/build-config.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build/build-config.yml b/build/build-config.yml index 301108b087a..32b5e67a2eb 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -174,4 +174,8 @@ config: image-name: "plan-service" dockerfile: "build/17/maven/Dockerfile" - work-dir: "health-services/plan-service/src/main/resources/db" - image-name: "plan-service-db" \ No newline at end of file + image-name: "plan-service-db" + - name: "builds/health-campaign-services/analytics/auth-proxy" + build: + - work-dir: "analytics/auth-proxy" + image-name: "auth-proxy" \ No newline at end of file From e8788cede196e9b89c9d4daa167e1ff80bf07583 Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Fri, 3 May 2024 16:35:34 +0530 Subject: [PATCH 246/283] HLM-5542: added household for both java 8 and java 17 (#725) --- build/build-config.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/build-config.yml b/build/build-config.yml index 32b5e67a2eb..ebc52757881 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -51,6 +51,13 @@ config: - work-dir: "health-services/referralmanagement/src/main/resources/db" image-name: "referralmanagement-db" - name: "builds/health-campaign-services/health-services/household" + build: + - work-dir: "health-services/household" + image-name: "household" + dockerfile: "build/maven/Dockerfile" + - work-dir: "health-services/household/src/main/resources/db" + image-name: "household-db" + - name: "builds/health-campaign-services/health-services/household-java-17" build: - work-dir: "health-services/household" image-name: "household" From 6cc64916171ba927ed22260b8f0fc76a8007c6fb Mon Sep 17 00:00:00 2001 From: Priyanka-eGov <74049060+Priyanka-eGov@users.noreply.github.com> Date: Fri, 10 May 2024 11:18:34 +0530 Subject: [PATCH 247/283] HLM-5700 adding changes for resource-estimation-service in build config (#728) --- build/build-config.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/build-config.yml b/build/build-config.yml index ebc52757881..d5b0267c5d2 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -182,6 +182,13 @@ config: dockerfile: "build/17/maven/Dockerfile" - work-dir: "health-services/plan-service/src/main/resources/db" image-name: "plan-service-db" + - name: "builds/health-campaign-services/health-services/resource-estimation-service" + build: + - work-dir: "health-services/resource-estimation-service" + image-name: "resource-estimation-service" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "health-services/resource-estimation-service/src/main/resources/db" + image-name: "resource-estimation-service-db" - name: "builds/health-campaign-services/analytics/auth-proxy" build: - work-dir: "analytics/auth-proxy" From 44c32603778d05d224bed50e52647b366ce92592 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Wed, 15 May 2024 13:41:49 +0530 Subject: [PATCH 248/283] Create .coderabbit.yaml --- .coderabbit.yaml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .coderabbit.yaml diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 00000000000..b45386a0866 --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,15 @@ +# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json +language: "en-US" +early_access: false +reviews: + profile: "assertive" + request_changes_workflow: true + high_level_summary: true + poem: true + review_status: true + collapse_walkthrough: false + auto_review: + enabled: true + drafts: false +chat: + auto_reply: true From 50105739344bc5f36931225c2b36dc550799ae5b Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Thu, 23 May 2024 09:38:18 +0530 Subject: [PATCH 249/283] HLM-5539: updated build config (#745) --- build/build-config.yml | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/build/build-config.yml b/build/build-config.yml index d5b0267c5d2..fff532768be 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -64,6 +64,20 @@ config: dockerfile: "build/17/maven/Dockerfile" - work-dir: "health-services/household/src/main/resources/db" image-name: "household-db" + - name: "builds/health-campaign-services/health-services/health-project-java-17" + build: + - work-dir: "health-services/project" + image-name: "health-project" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "health-services/project/src/main/resources/db" + image-name: "health-project-db" + - name: "builds/health-campaign-services/health-services/referralmanagement-java-17" + build: + - work-dir: "health-services/referralmanagement" + image-name: "referralmanagement" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "health-services/referralmanagement/src/main/resources/db" + image-name: "referralmanagement-db" - name: "builds/health-campaign-services/health-services/individual" build: - work-dir: "health-services/individual" @@ -78,6 +92,13 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "health-services/individual/src/main/resources/db" image-name: "health-individual-db" + - name: "builds/health-campaign-services/health-services/health-individual-java-17" + build: + - work-dir: "health-services/individual" + image-name: "health-individual" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "health-services/individual/src/main/resources/db" + image-name: "health-individual-db" - name: "builds/health-campaign-services/health-services/health-attendance" build: - work-dir: "health-services/attendance" @@ -102,6 +123,13 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "health-services/stock/src/main/resources/db" image-name: "stock-db" + - name: "builds/health-campaign-services/health-services/stock-java-17" + build: + - work-dir: "health-services/stock" + image-name: "stock" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "health-services/stock/src/main/resources/db" + image-name: "stock-db" - name: "builds/health-campaign-services/core-services/egov-survey-services" build: - work-dir: "core-services/egov-survey-services" @@ -116,11 +144,23 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "health-services/facility/src/main/resources/db" image-name: "facility-db" + - name: "builds/health-campaign-services/health-services/facility-java-17" + build: + - work-dir: "health-services/facility" + image-name: "facility" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "health-services/facility/src/main/resources/db" + image-name: "facility-db" - name: "builds/health-campaign-services/health-services/transformer" build: - work-dir: "health-services/transformer" image-name: "transformer" dockerfile: "build/maven/Dockerfile" + - name: "builds/health-campaign-services/health-services/transformer-java-17" + build: + - work-dir: "health-services/transformer" + image-name: "transformer" + dockerfile: "build/17/maven/Dockerfile" - name: "builds/health-campaign-services/core-services/service-request" build: - work-dir: "core-services/service-request" @@ -168,6 +208,13 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "core-services/egov-hrms/src/main/resources/db" image-name: "health-hrms-db" + - name: "builds/health-campaign-services/core-services/health-hrms-java-17" + build: + - work-dir: "core-services/egov-hrms" + image-name: "health-hrms" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "core-services/egov-hrms/src/main/resources/db" + image-name: "health-hrms-db" - name: "builds/health-campaign-services/core-services/egov-hrms" build: - work-dir: "core-services/egov-hrms" From 364329f5f9a415e5dd167bcad0e56c09c1f64105 Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Wed, 29 May 2024 18:07:55 +0530 Subject: [PATCH 250/283] Dev --> Master for HCM v1.4 (#751) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter * Project beneficiary tag cherrypick (#539) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * referral management project beneficiary validation fix * deleted persister and indexer file from project module resource folder --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * HH member clientrefid (#551) * adding clientRefId, Models version change, migration file * adding clientRefId for HouseholdMemberSearch as List * updated migration * adding Notnull for clientrefId --------- Co-authored-by: Vishal * Downsync smc referral module (#556) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Project beneficiary tag cherrypick (#549) * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * referral management project beneficiary validation fix --------- Co-authored-by: kanishq-egov Co-authored-by: Vishal * dummy api with same pagination response * dummy api with same pagination response * dummy api with same pagination response * downsync data test * data integrated till beneficiary * Update CHANGELOG.md * Delete health-services/project/src/main/resources/project-persistor.yml * skip on empty result added * skip on empty result added * beneficary searhc based on individual clientref id added * sideeffetc, ref, task fetch added * tasks earch fix * referral search fix --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * Dev downsync fix smc (#561) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: kanishq-egov * Dev master conflict fix (#562) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#563) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Dev master conflict fix (#565) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#566) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Added fix for testcases for householdmember (#570) Co-authored-by: kanishq-egov * updated the version, and added the changelog (#571) * updated the version, and added the changelog * updated ReferralManagement CHANGELOG * Update CHANGELOG.md --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * HLM-4062: removed pagination from fields excluding household api call * HLM-4062: missed in implementation (#574) * HLM-4062: missed in implementation * HLM-4062: default max is set to 1000 for not null limit value and 0 for offset value * project beneficiary tag update failed fix HLM-4444 * HLM-4444: added code review comments * sownsync bug fix for limit --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> * HLM-4444: project beneficiary update fix (#575) * Update CHANGELOG.md * updated changelog with dates (#577) * updated stock module changelog (#578) * Hlm 4501 smc referral flow (#602) * HLM-4501: Added changes for HFReferral flow * updated comments for common models * updated comments for common models removed ini file This reverts commit c1e226f961042f1162bb9ece8d2e1c01b62d220c. * HLM-4501: updated topics and hfreferal constants * HLM-4501: updated HFReferralService.java * HLM-4501: Added changes in project id validator * HLM-4501: updated HFReferralService.java * HLM-4501: fixed hfreferral changes * HLM-4501: added project facility id validator for hf_referral * HLM-4501: missing link for validator added * HLM-4501: updated HfrProjectFacilityIdValidator for NPE * HLM-4501 : updated hf referral symtoms character length to 256 * HLM-4501: updated additionalFields field value size from 2 to 1 * Hlm 3372 enhance inventory flow backend fixes (#623) * HLM-3372: added changes required to fix quantity, Sender Receiver enum * HLM-3372: Sender and Receiver id validator * HLM-3372: updated all reference for SenderType and Receiver Type enum * HLM-3372: stock model updated, removed size annotations from referenceidtype enum field * HLM-3372: Min validation added for integer type of quantity * HLM-3372: test cases updated * HLM-5004 Added max value and decimal condition for quantity in stock, added component and order annotation for SSenderIdReceiverIdEqualsValidator * HLM-5004 Custom JsonDeserializer validator IntegerValidator added in health-services-models * hlm-5004 added custom exception and a custom exception handler to handle the integer validator exception * hlm-5004 optimized imports and added code comments * hlm-5004 CustomIntegerSerializer added and unnecessary validators removed * hlm-5004 Registered the CustomIntegerDeserializer with objectMapper for Integer class * hlm-5004 Removed line of code that was removing all the invalid entities from the list in SSenderIdReceiverIdEqualsValidator * hlm-5004 changes in test configurations and optimized imports * hlm-5004 added row version validator for stock delete * hlm-5004 dateOfEntry field was handled in StockRowMapper to return null if no value is present and description was added to stock contact for transactionReason * updated pom.xml for health campaign models * Revert "updated pom.xml for health campaign models" This reverts commit 035c78720c610916000c8de76fa87e7904774b59. --------- Co-authored-by: syed-egov * Hlm 4501 smc referral flow code comments (#636) * Dev to master : beneficiary tag bug fix, downsync pagination fix (#576) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter * Project beneficiary tag cherrypick (#539) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * referral management project beneficiary validation fix * deleted persister and indexer file from project module resource folder --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * HH member clientrefid (#551) * adding clientRefId, Models version change, migration file * adding clientRefId for HouseholdMemberSearch as List * updated migration * adding Notnull for clientrefId --------- Co-authored-by: Vishal * Downsync smc referral module (#556) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Project beneficiary tag cherrypick (#549) * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * referral management project beneficiary validation fix --------- Co-authored-by: kanishq-egov Co-authored-by: Vishal * dummy api with same pagination response * dummy api with same pagination response * dummy api with same pagination response * downsync data test * data integrated till beneficiary * Update CHANGELOG.md * Delete health-services/project/src/main/resources/project-persistor.yml * skip on empty result added * skip on empty result added * beneficary searhc based on individual clientref id added * sideeffetc, ref, task fetch added * tasks earch fix * referral search fix --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * Dev downsync fix smc (#561) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: kanishq-egov * Dev master conflict fix (#562) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#563) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Dev master conflict fix (#565) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#566) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Added fix for testcases for householdmember (#570) Co-authored-by: kanishq-egov * updated the version, and added the changelog (#571) * updated the version, and added the changelog * updated ReferralManagement CHANGELOG * Update CHANGELOG.md --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * HLM-4062: removed pagination from fields excluding household api call * HLM-4062: missed in implementation (#574) * HLM-4062: missed in implementation * HLM-4062: default max is set to 1000 for not null limit value and 0 for offset value * project beneficiary tag update failed fix HLM-4444 * HLM-4444: added code review comments * sownsync bug fix for limit --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> * HLM-4444: project beneficiary update fix (#575) * Update CHANGELOG.md * updated changelog with dates (#577) * updated stock module changelog (#578) --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: bhanu prakash <109132521+bhanuprakash-egov@users.noreply.github.com> Co-authored-by: Naveen J <83631045+naveen-egov@users.noreply.github.com> Co-authored-by: talele08 * Referral and Side effect sequence diagram * HLM-4501: Added changes for HFReferral flow * updated comments for common models * updated comments for common models removed ini file This reverts commit c1e226f961042f1162bb9ece8d2e1c01b62d220c. * HLM-4501: updated topics and hfreferal constants * HLM-4501: updated HFReferralService.java * HLM-4501: Added changes in project id validator * HLM-4501: updated HFReferralService.java * HLM-4501: fixed hfreferral changes * HLM-4501: added project facility id validator for hf_referral * HLM-4501: missing link for validator added * HLM-4501: updated HfrProjectFacilityIdValidator for NPE * HLM-4501 : updated hf referral symtoms character length to 256 * HLM-4501: updated additionalFields field value size from 2 to 1 * HLM-4501: added code comments for all hf referral related classes * HLM-4501: hf-referral sequence diagram --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: bhanu prakash <109132521+bhanuprakash-egov@users.noreply.github.com> Co-authored-by: Naveen J <83631045+naveen-egov@users.noreply.github.com> Co-authored-by: talele08 * HLM-5075 Made the necessary updates in search criterias across services and updated contracts accordingly * HLM-5075 Chnages in search criteria made in common models * HLM-5075 updated build-config to include health-individual and health-project and made chanegs in test controllers in productVariant projectTask projectBeneficiary projectStaff * hlm-5031 The search was updated in individual and referral management services and orderBy was changed to createdtime * HLM-4496, HLM-4207 attendance module (#616) * HLM-4496: Added attendance module in HCM * HLM-4496: updated attendance directory, removed target folder and imi file * buil config added for hlm-4496 in feature branch * HLM-4207: offline enablement in attendance log * HLM-4207: added db migration script * HLM-4207: updated db migration script * HLM-4207: updated incorrect statements * HLM-4207: bulk api support, without redis cache * HLM-4207: updated Attendancelog consumer for bulk api * HLM-4207: consumer fix * HLM-4207: cache support added for attendance log create and update * HLM-4207: added health-individual endpoint * HLM-4207: added radis host * HLM-4207: updated qualified for objectmapper in attendance module * HLM-4496,HLM-4207: updated application.properties for redis config * HLM-4207: updated kafka listener topics * HLM-4207: changed kafka config * HLM-4894 adding hrms related flag to Individual object, adding another ApiOperation * HLM-4894 adding hrms related flag to Individual object, adding another ApiOperation * HLM-4207, HLM-4986, HLM-4987 : bug fix * HLM-4894 adding changes related to linking of HRMS Employee with Individual * HLM-4894 adding changes related to linking of HRMS Employee with Individual * HLM-4207: added clientreferenceid search, null check for document id * HLM-4894 reverting changes related to linking of HRMS Employee with Individual * HLM-4894 reverting changes related to linking of HRMS Employee with Individual from libraries, common-models * HLM-4207: code re-format * HLM-4894 adding changes for managing attendees while enrollment * HLM-4207: updated attendance search, register id or clientreference id are mandatory * hlm-5009 staffId in ProjectStaffSearch changed to list from string * HLM-4894 updating build config * HLM-4207: clientReferenceIds is changed to clientReferenceId for Attendance Log search criteria * HLM-4207: removed staff validation for search without register id * HLM-4894 adding changes for project staff validation * HLM-4894 adding @Qualifier annotation for object mapper * HLM-4894 fixing hrms url * HLM-4771: added changes for updating the registers on project date update * HLM-4771: project update changes * HLM-4771: updated the project start date update validation, can not update start date if it is already started * HLM-4771: updated attendance register consumer and service with comments * HLM-4771: updated the tenant id * HLM-4894 updating environment variables. * HLM-4894 updating code changes * HLM-4894 adding code changes * HLM-4894 adding code changes * HLM-4894 adding code changes * HLM-4771: updated the project validators, validation for start and end date of project * HLM-4894 adding useruuid as search param in individual search * HLM-4894 adding useruuid as search param in individual search * HLM-4894 adding useruuid as search param in individual search * HLM-4894 adding changes for registry creation when supervisor enrolls * HLM-4496, HLM-4894: first staff enrollment on attendance register creation is optional * HLM-4894 adding changes attendee enrollment * HLM-4894 adding changes for making staffId as list of staffId in ProjectStaffSearch * HLM-4894 adding changes for making staffId as list of staffId in ProjectStaffSearch * HLM-4894 adding changes for making staffId as list of staffId in ProjectStaffSearch * HLM-4894 removing staff-bulk-create-topic * HLM-4894 removing staff-bulk-create-topic * HLM-4894 removing staff-bulk-create-topic * HLM-4894 removing staff-bulk-create-topic * HLM-4894 changing health-attendance consumer group-id * HLM-4894 adding changes for projectstaff consumer * HLM-4894 adding changes for projectstaff consumer * HLM-4894 adding changes for projectstaff consumer * HLM-4894 adding changes for projectstaff consumer * HLM-4894 adding changes for projectstaff consumer * HLM-5045: added changes, project start date and end date difference should at least be 1 day. * HLM-4894 adding comments * HLM-4894 adding additional Details during attendance register creation * HLM-4894 adding additional Details during attendance register creation * hlm-4496 : bug fix on adding staff on updation of register * HLM-4894 increasing limit to 1000 * Added changelog for individual, health-services-models, project, stock * HLM-4496 : remove attendance module as it is moved to DIGIT-Works repository. * HLM-5076: added changes related to project module * updated individual user uuid search field for hlm-4496, hlm-4207 * changed common models build to 1.0.19-SNAPSHOT --------- Co-authored-by: Priyanka-eGov Co-authored-by: syed-egov Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * Hlm 4496 individual UUID search (#656) * HLM-4496: updated changedlog for individual, health-services-models, project, referralmanagement * HLM-4496: Added size annotations on individual search userUuid field * hlm-4496: Revert of application.properties changes * updated pom.xml version for individual, project, referralmanagement, stock (#657) * Health hrms (#660) * updated pom.xml version for individual, project, referralmanagement, stock * Added health-hrms * Hlm health hrms changes (#650) * HLM-4496: Added attendance module in HCM * HLM-4496: updated attendance directory, removed target folder and imi file * buil config added for hlm-4496 in feature branch * HLM-4207: offline enablement in attendance log * HLM-4207: added db migration script * HLM-4207: updated db migration script * HLM-4207: updated incorrect statements * HLM-4207: bulk api support, without redis cache * HLM-4207: updated Attendancelog consumer for bulk api * HLM-4207: consumer fix * HLM-4207: cache support added for attendance log create and update * HLM-4207: added health-individual endpoint * HLM-4207: added radis host * HLM-4207: updated qualified for objectmapper in attendance module * HLM-4496,HLM-4207: updated application.properties for redis config * HLM-4207: updated kafka listener topics * HLM-4207: changed kafka config * HLM-4207, HLM-4986, HLM-4987 : bug fix * HLM-4207: added clientreferenceid search, null check for document id * HLM-4894 moving hrms code from DIGIT-Dev branc health-moz-dev * HLM-4894 moving hrms code from DIGIT-Dev branc health-moz-dev * HLM-4894 updating build config for health-hrms * HLM-4894 adding clientreferenceID while creating individuals * HLM-4894 adding clientreferenceID while creating individuals * HLM-4894 adding clientreferenceID while creating individuals * HLM-4894 adding clientAuditDetails while creating individuals * Adding mdmsLegacyHost * Adding mdmsLegacyHost --------- Co-authored-by: kanishq-egov Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * Revert "Hlm health hrms changes (#650)" (#663) This reverts commit db786acf5fd949084ad544aa6f9f31e5d9a37f6e. * index creation migrations (#668) * hlm-5075 removed the size annotation from the field that were changed to list * hlm-5031 changed the OrderBy DESC from ASC * hlm-5075 Changes made in all the searches documented in Changelog and ReadMe file * Removed size annotaton from fields that were updated to List * Changes made to health-services-models version * Changed the order of nexus-repo * Changes the order of repositories back to original order * Changes the health-services-models version for project * Update CODEOWNERS * added git ignore (#715) * HLM-5099: added referral Code in Referral Model, added migration file and updated rowmapper (#711) * HLM-5361, HLM-5362 : updated common models with EgovModel and EgovOfflineModel (#678) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * updated householdrowmapper.java * project beneficiary bug fix * removed unused import * HLM-4062:code refactor, removed useCTE parameter * project beneficiary : voucherTag renamed to tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * referral management project beneficiary validation fix * Project beneficiary tag cherrypick (#549) * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * referral management project beneficiary validation fix --------- Co-authored-by: kanishq-egov Co-authored-by: Vishal * dummy api with same pagination response * dummy api with same pagination response * dummy api with same pagination response * added changes for individual * Added count api in household member and project beneficiary models * added total count for findById in individual * HLM-4062: Added SearchResponse model, updated CommonUtils.java,Removed total count from Individual, HouseholdMember, ProjectBeneficiary. Added count api changes for Household, Individual, HouseholdMember, ProjectBeneficiary * HLM-4062: updated health-service-common version to 1.0.15 * updated health common version to 1.0.15 * downsync data test * data integrated till beneficiary * Update CHANGELOG.md * Delete health-services/project/src/main/resources/project-persistor.yml * skip on empty result added * skip on empty result added * beneficary searhc based on individual clientref id added * sideeffetc, ref, task fetch added * tasks earch fix * HLM-4062: fixed testcases * Updated referral-management api specs contract * HLM-4062: updated application.properties and code refactor * HLM-4062: added changes for searchresponse type * HLM-4062: change to boundary code * HLM-4062: reverted some changes * hlm-4062: updated referral-management * HLM-4062: updated pom.xml * bug fix hlm-4062: individual count was not correct * HLM-4062: fixed offset not working for household member and project beneficiary * HLM-4062: updated total count for ProjectTask, SideEffect, Referral * HLM-4062: HLM-4822: fixed ProjectTaskApiControllerTest.java * dev to master - 28-02-24 (#654) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter * Project beneficiary tag cherrypick (#539) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * referral management project beneficiary validation fix * deleted persister and indexer file from project module resource folder --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * HH member clientrefid (#551) * adding clientRefId, Models version change, migration file * adding clientRefId for HouseholdMemberSearch as List * updated migration * adding Notnull for clientrefId --------- Co-authored-by: Vishal * Downsync smc referral module (#556) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Project beneficiary tag cherrypick (#549) * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * referral management project beneficiary validation fix --------- Co-authored-by: kanishq-egov Co-authored-by: Vishal * dummy api with same pagination response * dummy api with same pagination response * dummy api with same pagination response * downsync data test * data integrated till beneficiary * Update CHANGELOG.md * Delete health-services/project/src/main/resources/project-persistor.yml * skip on empty result added * skip on empty result added * beneficary searhc based on individual clientref id added * sideeffetc, ref, task fetch added * tasks earch fix * referral search fix --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * Dev downsync fix smc (#561) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: kanishq-egov * Dev master conflict fix (#562) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#563) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Dev master conflict fix (#565) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#566) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Added fix for testcases for householdmember (#570) Co-authored-by: kanishq-egov * updated the version, and added the changelog (#571) * updated the version, and added the changelog * updated ReferralManagement CHANGELOG * Update CHANGELOG.md --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * HLM-4062: removed pagination from fields excluding household api call * HLM-4062: missed in implementation (#574) * HLM-4062: missed in implementation * HLM-4062: default max is set to 1000 for not null limit value and 0 for offset value * project beneficiary tag update failed fix HLM-4444 * HLM-4444: added code review comments * sownsync bug fix for limit --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> * HLM-4444: project beneficiary update fix (#575) * Update CHANGELOG.md * updated changelog with dates (#577) * updated stock module changelog (#578) * Hlm 4501 smc referral flow (#602) * HLM-4501: Added changes for HFReferral flow * updated comments for common models * updated comments for common models removed ini file This reverts commit c1e226f961042f1162bb9ece8d2e1c01b62d220c. * HLM-4501: updated topics and hfreferal constants * HLM-4501: updated HFReferralService.java * HLM-4501: Added changes in project id validator * HLM-4501: updated HFReferralService.java * HLM-4501: fixed hfreferral changes * HLM-4501: added project facility id validator for hf_referral * HLM-4501: missing link for validator added * HLM-4501: updated HfrProjectFacilityIdValidator for NPE * HLM-4501 : updated hf referral symtoms character length to 256 * HLM-4501: updated additionalFields field value size from 2 to 1 * Hlm 3372 enhance inventory flow backend fixes (#623) * HLM-3372: added changes required to fix quantity, Sender Receiver enum * HLM-3372: Sender and Receiver id validator * HLM-3372: updated all reference for SenderType and Receiver Type enum * HLM-3372: stock model updated, removed size annotations from referenceidtype enum field * HLM-3372: Min validation added for integer type of quantity * HLM-3372: test cases updated * HLM-5004 Added max value and decimal condition for quantity in stock, added component and order annotation for SSenderIdReceiverIdEqualsValidator * HLM-5004 Custom JsonDeserializer validator IntegerValidator added in health-services-models * hlm-5004 added custom exception and a custom exception handler to handle the integer validator exception * hlm-5004 optimized imports and added code comments * hlm-5004 CustomIntegerSerializer added and unnecessary validators removed * hlm-5004 Registered the CustomIntegerDeserializer with objectMapper for Integer class * hlm-5004 Removed line of code that was removing all the invalid entities from the list in SSenderIdReceiverIdEqualsValidator * hlm-5004 changes in test configurations and optimized imports * hlm-5004 added row version validator for stock delete * hlm-5004 dateOfEntry field was handled in StockRowMapper to return null if no value is present and description was added to stock contact for transactionReason * updated pom.xml for health campaign models * Revert "updated pom.xml for health campaign models" This reverts commit 035c78720c610916000c8de76fa87e7904774b59. --------- Co-authored-by: syed-egov * Hlm 4501 smc referral flow code comments (#636) * Dev to master : beneficiary tag bug fix, downsync pagination fix (#576) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter * Project beneficiary tag cherrypick (#539) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * referral management project beneficiary validation fix * deleted persister and indexer file from project module resource folder --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * HH member clientrefid (#551) * adding clientRefId, Models version change, migration file * adding clientRefId for HouseholdMemberSearch as List * updated migration * adding Notnull for clientrefId --------- Co-authored-by: Vishal * Downsync smc referral module (#556) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Project beneficiary tag cherrypick (#549) * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * referral management project beneficiary validation fix --------- Co-authored-by: kanishq-egov Co-authored-by: Vishal * dummy api with same pagination response * dummy api with same pagination response * dummy api with same pagination response * downsync data test * data integrated till beneficiary * Update CHANGELOG.md * Delete health-services/project/src/main/resources/project-persistor.yml * skip on empty result added * skip on empty result added * beneficary searhc based on individual clientref id added * sideeffetc, ref, task fetch added * tasks earch fix * referral search fix --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * Dev downsync fix smc (#561) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: kanishq-egov * Dev master conflict fix (#562) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#563) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Dev master conflict fix (#565) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#566) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Added fix for testcases for householdmember (#570) Co-authored-by: kanishq-egov * updated the version, and added the changelog (#571) * updated the version, and added the changelog * updated ReferralManagement CHANGELOG * Update CHANGELOG.md --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * HLM-4062: removed pagination from fields excluding household api call * HLM-4062: missed in implementation (#574) * HLM-4062: missed in implementation * HLM-4062: default max is set to 1000 for not null limit value and 0 for offset value * project beneficiary tag update failed fix HLM-4444 * HLM-4444: added code review comments * sownsync bug fix for limit --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> * HLM-4444: project beneficiary update fix (#575) * Update CHANGELOG.md * updated changelog with dates (#577) * updated stock module changelog (#578) --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: bhanu prakash <109132521+bhanuprakash-egov@users.noreply.github.com> Co-authored-by: Naveen J <83631045+naveen-egov@users.noreply.github.com> Co-authored-by: talele08 * Referral and Side effect sequence diagram * HLM-4501: Added changes for HFReferral flow * updated comments for common models * updated comments for common models removed ini file This reverts commit c1e226f961042f1162bb9ece8d2e1c01b62d220c. * HLM-4501: updated topics and hfreferal constants * HLM-4501: updated HFReferralService.java * HLM-4501: Added changes in project id validator * HLM-4501: updated HFReferralService.java * HLM-4501: fixed hfreferral changes * HLM-4501: added project facility id validator for hf_referral * HLM-4501: missing link for validator added * HLM-4501: updated HfrProjectFacilityIdValidator for NPE * HLM-4501 : updated hf referral symtoms character length to 256 * HLM-4501: updated additionalFields field value size from 2 to 1 * HLM-4501: added code comments for all hf referral related classes * HLM-4501: hf-referral sequence diagram --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: bhanu prakash <109132521+bhanuprakash-egov@users.noreply.github.com> Co-authored-by: Naveen J <83631045+naveen-egov@users.noreply.github.com> Co-authored-by: talele08 * HLM-4496, HLM-4207 attendance module (#616) * HLM-4496: Added attendance module in HCM * HLM-4496: updated attendance directory, removed target folder and imi file * buil config added for hlm-4496 in feature branch * HLM-4207: offline enablement in attendance log * HLM-4207: added db migration script * HLM-4207: updated db migration script * HLM-4207: updated incorrect statements * HLM-4207: bulk api support, without redis cache * HLM-4207: updated Attendancelog consumer for bulk api * HLM-4207: consumer fix * HLM-4207: cache support added for attendance log create and update * HLM-4207: added health-individual endpoint * HLM-4207: added radis host * HLM-4207: updated qualified for objectmapper in attendance module * HLM-4496,HLM-4207: updated application.properties for redis config * HLM-4207: updated kafka listener topics * HLM-4207: changed kafka config * HLM-4894 adding hrms related flag to Individual object, adding another ApiOperation * HLM-4894 adding hrms related flag to Individual object, adding another ApiOperation * HLM-4207, HLM-4986, HLM-4987 : bug fix * HLM-4894 adding changes related to linking of HRMS Employee with Individual * HLM-4894 adding changes related to linking of HRMS Employee with Individual * HLM-4207: added clientreferenceid search, null check for document id * HLM-4894 reverting changes related to linking of HRMS Employee with Individual * HLM-4894 reverting changes related to linking of HRMS Employee with Individual from libraries, common-models * HLM-4207: code re-format * HLM-4894 adding changes for managing attendees while enrollment * HLM-4207: updated attendance search, register id or clientreference id are mandatory * hlm-5009 staffId in ProjectStaffSearch changed to list from string * HLM-4894 updating build config * HLM-4207: clientReferenceIds is changed to clientReferenceId for Attendance Log search criteria * HLM-4207: removed staff validation for search without register id * HLM-4894 adding changes for project staff validation * HLM-4894 adding @Qualifier annotation for object mapper * HLM-4894 fixing hrms url * HLM-4771: added changes for updating the registers on project date update * HLM-4771: project update changes * HLM-4771: updated the project start date update validation, can not update start date if it is already started * HLM-4771: updated attendance register consumer and service with comments * HLM-4771: updated the tenant id * HLM-4894 updating environment variables. * HLM-4894 updating code changes * HLM-4894 adding code changes * HLM-4894 adding code changes * HLM-4894 adding code changes * HLM-4771: updated the project validators, validation for start and end date of project * HLM-4894 adding useruuid as search param in individual search * HLM-4894 adding useruuid as search param in individual search * HLM-4894 adding useruuid as search param in individual search * HLM-4894 adding changes for registry creation when supervisor enrolls * HLM-4496, HLM-4894: first staff enrollment on attendance register creation is optional * HLM-4894 adding changes attendee enrollment * HLM-4894 adding changes for making staffId as list of staffId in ProjectStaffSearch * HLM-4894 adding changes for making staffId as list of staffId in ProjectStaffSearch * HLM-4894 adding changes for making staffId as list of staffId in ProjectStaffSearch * HLM-4894 removing staff-bulk-create-topic * HLM-4894 removing staff-bulk-create-topic * HLM-4894 removing staff-bulk-create-topic * HLM-4894 removing staff-bulk-create-topic * HLM-4894 changing health-attendance consumer group-id * HLM-4894 adding changes for projectstaff consumer * HLM-4894 adding changes for projectstaff consumer * HLM-4894 adding changes for projectstaff consumer * HLM-4894 adding changes for projectstaff consumer * HLM-4894 adding changes for projectstaff consumer * HLM-5045: added changes, project start date and end date difference should at least be 1 day. * HLM-4894 adding comments * HLM-4894 adding additional Details during attendance register creation * HLM-4894 adding additional Details during attendance register creation * hlm-4496 : bug fix on adding staff on updation of register * HLM-4894 increasing limit to 1000 * Added changelog for individual, health-services-models, project, stock * HLM-4496 : remove attendance module as it is moved to DIGIT-Works repository. * HLM-5076: added changes related to project module * updated individual user uuid search field for hlm-4496, hlm-4207 * changed common models build to 1.0.19-SNAPSHOT --------- Co-authored-by: Priyanka-eGov Co-authored-by: syed-egov Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * Hlm 4496 individual UUID search (#656) * HLM-4496: updated changedlog for individual, health-services-models, project, referralmanagement * HLM-4496: Added size annotations on individual search userUuid field * hlm-4496: Revert of application.properties changes * updated pom.xml version for individual, project, referralmanagement, stock (#657) --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: bhanu prakash <109132521+bhanuprakash-egov@users.noreply.github.com> Co-authored-by: Naveen J <83631045+naveen-egov@users.noreply.github.com> Co-authored-by: talele08 Co-authored-by: syed-egov Co-authored-by: Priyanka-eGov * Dev to master - March 04, 2024 (#664) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: remo… * hlm-5539: updated the changelog (#750) - Integrated Core 2.9LTS - Client reference ID validation added - Upgraded to health models 1.0.20 and health common 1.0.16 - Boundary v2 Integration - MDMS v2 integration Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * Hlm-5608 hrms search individual type (#702) * hlm-5608 added type in individual search * hlm-5608 health services models version chnged in libraries * hlm-5608 changes in individual service * hlm-5608 string to list changes in individual service * HLM-5608: updated the fix and added the missing references * HLM-5608: updated egov-hrms references for usertype * HLM-5608: updated pom.xml for health-common-models, removed duplicate dependency * HLM-5608: updated build-config.yml * HLM-5608: fixed incorrect implementation committed in bca78dfd * HLM-5608: null list check * HLM-5608: string util check * HLM-5608: fix individual update * HLM-5608: fix individual update - added null check * HLM-5608, HLM-5716: fix provided, missing negation in if condition --------- Co-authored-by: kanishq-egov * HLM-5539: fixed project beneficiary tag update fail when tag is null (#752) * HLM-5539: fixed project beneficiary tag update fail when tag is null * HLM-5539: skipping search for project beneficiary with null tag for update operation during validation * Update CHANGELOG.md --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * HLM-5539, 5361: updated health-service-common, added serialVersionUID… (#753) * HLM-5539, 5361: updated health-service-common, added serialVersionUID check in GenericQueryBuilder * HLM-5539: added null check for static field reflection access * HLM-5539: added trim in individual * Update GenericQueryBuilder.java --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: bhanu prakash <109132521+bhanuprakash-egov@users.noreply.github.com> Co-authored-by: Naveen J <83631045+naveen-egov@users.noreply.github.com> Co-authored-by: talele08 Co-authored-by: syed-egov Co-authored-by: Priyanka-eGov Co-authored-by: Priyanka-eGov <74049060+Priyanka-eGov@users.noreply.github.com> Co-authored-by: vishal-egov <121248108+vishal-egov@users.noreply.github.com> Co-authored-by: Shashwat Mishra <71879793+shashwat-egov@users.noreply.github.com> Co-authored-by: aaradhya-egov <137176709+aaradhya-egov@users.noreply.github.com> Co-authored-by: syed-egov <153488207+syed-egov@users.noreply.github.com> --- .gitignore | 81 +++ CODEOWNERS | 4 +- core-services/egov-hrms/CHANGELOG.md | 7 + core-services/egov-hrms/pom.xml | 4 +- .../egov/hrms/config/PropertiesManager.java | 6 + .../egov/hrms/service/EmployeeService.java | 3 + .../egov/hrms/service/IndividualService.java | 99 ++- .../web/models/EgovOfflineSearchModel.java | 20 + .../egov/hrms/web/models/EgovSearchModel.java | 22 + .../org/egov/hrms/web/models/Exclude.java | 13 + .../hrms}/web/models/IndividualSearch.java | 63 +- .../web/models/IndividualSearchRequest.java | 20 +- .../hrms/web/models/boundary/Boundary.java | 44 ++ .../web/models/boundary/BoundaryRequest.java | 32 +- .../web/models/boundary/BoundaryResponse.java | 43 ++ .../boundary/BoundarySearchCriteria.java | 37 ++ .../hrms/web/validator/EmployeeValidator.java | 84 ++- .../src/main/resources/application.properties | 7 +- docs/health-api-specs/contracts/project.yml | 30 +- .../contracts/referral-management.yml | 28 +- .../contracts/registries/individual.yml | 12 +- .../contracts/registries/product.yml | 22 +- docs/health-api-specs/contracts/stock.yml | 22 +- health-services/facility/CHANGELOG.md | 7 +- health-services/facility/pom.xml | 45 +- .../config/FacilityConfiguration.java | 6 + .../facility/config/MainConfiguration.java | 2 +- .../rowmapper/FacilityRowMapper.java | 10 +- .../facility/service/FacilityService.java | 20 +- .../validator/FBoundaryValidator.java | 127 ++++ .../controllers/FacilityApiController.java | 32 +- .../web/models/boundary/BoundaryRequest.java | 38 ++ .../web/models/boundary/BoundaryResponse.java | 44 ++ .../boundary/BoundarySearchCriteria.java | 37 ++ .../src/main/resources/application.properties | 6 + .../facility/helper/FacilityTestBuilder.java | 4 +- health-services/household/CHANGELOG.md | 10 + health-services/household/README.md | 8 + health-services/household/pom.xml | 31 +- .../java/org/egov/household/Constants.java | 2 + .../config/HouseholdConfiguration.java | 5 + .../household/config/MainConfiguration.java | 2 +- .../validators/HmExistentEntityValidator.java | 77 +++ .../validators/HmHouseholdHeadValidator.java | 2 +- .../validators/HmHouseholdValidator.java | 2 +- .../HmNonExistentEntityValidator.java | 75 ++- .../validators/HmRowVersionValidator.java | 2 +- .../HmUniqueIndividualValidator.java | 2 +- .../repository/HouseholdMemberRepository.java | 75 ++- .../repository/HouseholdRepository.java | 62 +- .../rowmapper/HouseholdMemberRowMapper.java | 8 +- .../rowmapper/HouseholdRowMapper.java | 10 +- .../HouseholdMemberEnrichmentService.java | 4 +- .../service/HouseholdMemberService.java | 34 +- .../household/service/HouseholdService.java | 52 +- .../household/HBoundaryValidator.java | 127 ++++ .../household/HExistentEntityValidator.java | 76 +++ .../HNonExistentEntityValidator.java | 105 ++++ .../HNonExsistentEntityValidator.java | 2 +- .../household/HRowVersionValidator.java | 2 +- .../controllers/HouseholdApiController.java | 70 ++- .../web/models/HouseholdMemberSearch.java | 57 -- .../models/HouseholdMemberSearchRequest.java | 39 -- .../household/web/models/HouseholdSearch.java | 65 -- .../web/models/HouseholdSearchRequest.java | 38 -- .../web/models/boundary/BoundaryRequest.java | 38 ++ .../web/models/boundary/BoundaryResponse.java | 44 ++ .../boundary/BoundarySearchCriteria.java | 37 ++ .../src/main/resources/application.properties | 15 +- .../src/main/resources/db/Dockerfile | 4 +- .../src/main/resources/db/migrate.sh | 2 +- ...0305114132__household_search_index_ddl.sql | 1 + ...225__household_member_search_index_ddl.sql | 1 + ...useholdMemberSearchRequestTestBuilder.java | 20 + .../helper/HouseholdMemberTestBuilder.java | 7 +- .../helper/HouseholdSearchTestBuilder.java | 39 ++ .../helper/HouseholdTestBuilder.java | 6 +- .../household/service/HouseholdFindTest.java | 16 +- .../HouseholdMemberCreateEnrichmentTest.java | 10 +- .../service/HouseholdMemberFindTest.java | 16 +- .../HouseholdMemberUpdateEnrichmentTest.java | 13 +- .../service/HouseholdMemberUpdateTest.java | 13 +- .../HouseholdApiControllerTest.java | 19 +- .../HouseholdMemberApiControllerTest.java | 13 +- health-services/individual/CHANGELOG.md | 11 + health-services/individual/README.md | 8 + health-services/individual/pom.xml | 42 +- .../config/IndividualProperties.java | 6 + .../individual/config/MainConfiguration.java | 2 +- .../repository/IndividualRepository.java | 60 +- .../rowmapper/AddressRowMapper.java | 2 +- .../rowmapper/IndividualRowMapper.java | 10 +- .../service/IndividualEncryptionService.java | 4 +- .../individual/service/IndividualMapper.java | 8 +- .../individual/service/IndividualService.java | 66 +- .../validators/IBoundaryValidator.java | 129 ++++ .../validators/IExistentEntityValidator.java | 77 +++ .../INonExistentEntityValidator.java | 106 ++++ .../NonExistentEntityValidator.java | 2 +- .../validators/RowVersionValidator.java | 2 +- .../controllers/IndividualApiController.java | 39 +- .../web/models/IndividualSearchRequest.java | 44 -- .../web/models/boundary/BoundaryRequest.java | 38 ++ .../web/models/boundary/BoundaryResponse.java | 44 ++ .../boundary/BoundarySearchCriteria.java | 37 ++ .../src/main/resources/application.properties | 4 + .../IndividualSearchRequestTestBuilder.java | 16 +- .../helper/IndividualSearchTestBuilder.java | 2 +- .../repository/IndividualRepositoryTest.java | 17 +- .../service/IndividualServiceSearchTest.java | 41 +- .../service/IndividualServiceTest.java | 5 +- .../service/IndividualServiceUpdateTest.java | 11 +- .../NonExistentEntityValidatorTest.java | 9 +- .../validator/RowVersionValidatorTest.java | 10 +- .../IndividualApiControllerTest.java | 7 +- .../health-services-common/CHANGELOG.md | 10 +- .../health-services-common/Dockerfile | 4 +- .../libraries/health-services-common/pom.xml | 54 +- .../org/egov/common/AddressDummyTest.java | 20 - .../common/data/mapper/GenericRowMapper.java | 97 --- .../data/query/annotations/Exclude.java | 2 + .../common/data/query/annotations/Table.java | 3 + .../data/query/annotations/UpdateBy.java | 2 + .../query/builder/GenericQueryBuilder.java | 70 ++- .../query/builder/SelectQueryBuilder.java | 13 +- .../data/repository/GenericRepository.java | 95 ++- .../common/error/handler/ErrorHandler.java | 2 +- .../http/client/ServiceRequestClient.java | 29 +- .../common/models/user/CreateUserRequest.java | 4 +- .../org/egov/common/models/user/User.java | 4 +- .../egov/common/models/user/UserRequest.java | 52 +- .../org/egov/common/service/MdmsService.java | 2 +- .../org/egov/common/utils/CommonUtils.java | 422 ++++++++++--- .../data/mapper/GenericRowMapperTest.java | 127 ---- .../data/query/GenericQueryBuilderTest.java | 6 +- .../repository/GenericRepositoryFindTest.java | 4 +- .../egov/common/utils/CommonUtilsTest.java | 58 +- .../health-services-models/CHANGELOG.md | 4 + .../health-services-models/Dockerfile | 4 +- .../libraries/health-services-models/pom.xml | 51 +- .../common/models/core/AdditionalFields.java | 51 ++ .../org/egov/common/models/core/Boundary.java | 44 ++ .../egov/common/models/core/EgovModel.java | 57 ++ .../common/models/core/EgovOfflineModel.java | 27 + .../models/core/EgovOfflineSearchModel.java | 20 + .../common/models/core/EgovSearchModel.java | 22 + .../org/egov/common/models/core/Exclude.java | 13 + .../org/egov/common/models/core/Field.java | 37 ++ .../models/core/ProjectSearchURLParams.java | 47 ++ .../org/egov/common/models/core/Role.java | 1 + .../common/models/core/SearchResponse.java | 38 ++ .../org/egov/common/models/core/Table.java | 15 + .../egov/common/models/core/URLParams.java | 86 +++ .../org/egov/common/models/core/UpdateBy.java | 13 + .../models/facility/AdditionalFields.java | 9 +- .../egov/common/models/facility/Address.java | 16 +- .../common/models/facility/AddressType.java | 1 + .../egov/common/models/facility/Boundary.java | 61 -- .../egov/common/models/facility/Facility.java | 40 +- .../models/facility/FacilityBulkRequest.java | 8 +- .../models/facility/FacilityBulkResponse.java | 6 +- .../models/facility/FacilityRequest.java | 6 +- .../models/facility/FacilityResponse.java | 6 +- .../models/facility/FacilitySearch.java | 18 +- .../facility/FacilitySearchRequest.java | 7 +- .../egov/common/models/facility/Field.java | 4 +- .../common/models/facility/TenantRole.java | 7 +- .../egov/common/models/facility/UserInfo.java | 7 +- .../models/household/AdditionalFields.java | 9 +- .../egov/common/models/household/Address.java | 17 +- .../common/models/household/AddressType.java | 1 + .../common/models/household/Boundary.java | 62 -- .../egov/common/models/household/Field.java | 6 +- .../common/models/household/Household.java | 52 +- .../household/HouseholdBulkRequest.java | 8 +- .../household/HouseholdBulkResponse.java | 6 +- .../models/household/HouseholdMember.java | 48 +- .../household/HouseholdMemberBulkRequest.java | 8 +- .../HouseholdMemberBulkResponse.java | 11 +- .../household/HouseholdMemberRequest.java | 6 +- .../household/HouseholdMemberResponse.java | 6 +- .../household/HouseholdMemberSearch.java | 35 +- .../HouseholdMemberSearchRequest.java | 6 +- .../models/household/HouseholdRequest.java | 6 +- .../models/household/HouseholdResponse.java | 6 +- .../models/household/HouseholdSearch.java | 49 +- .../household/HouseholdSearchRequest.java | 6 +- .../common/models/household/TenantRole.java | 6 +- .../common/models/household/UserInfo.java | 6 +- .../models/individual/AdditionalFields.java | 9 +- .../common/models/individual/Address.java | 16 +- .../common/models/individual/AddressType.java | 1 + .../common/models/individual/Boundary.java | 82 --- .../egov/common/models/individual/Field.java | 6 +- .../common/models/individual/Identifier.java | 8 +- .../common/models/individual/Individual.java | 47 +- .../individual/IndividualBulkRequest.java | 8 +- .../individual/IndividualBulkResponse.java | 11 +- .../individual/IndividualDeleteRequest.java | 4 +- .../models/individual/IndividualRequest.java | 6 +- .../models/individual/IndividualResponse.java | 6 +- .../models/individual/IndividualSearch.java | 66 +- .../individual/IndividualSearchRequest.java | 6 +- .../egov/common/models/individual/Name.java | 4 +- .../egov/common/models/individual/Skill.java | 8 +- .../common/models/individual/UserDetails.java | 4 +- .../models/product/AdditionalFields.java | 9 +- .../egov/common/models/product/Address.java | 15 +- .../egov/common/models/product/Boundary.java | 83 --- .../org/egov/common/models/product/Field.java | 6 +- .../egov/common/models/product/Product.java | 33 +- .../common/models/product/ProductRequest.java | 8 +- .../models/product/ProductResponse.java | 6 +- .../common/models/product/ProductSearch.java | 20 +- .../models/product/ProductSearchRequest.java | 6 +- .../common/models/product/ProductVariant.java | 54 +- .../models/product/ProductVariantRequest.java | 8 +- .../product/ProductVariantResponse.java | 6 +- .../models/product/ProductVariantSearch.java | 21 +- .../product/ProductVariantSearchRequest.java | 6 +- .../models/product/ProjectProductVariant.java | 4 +- .../common/models/product/TenantRole.java | 6 +- .../egov/common/models/product/UserInfo.java | 6 +- .../models/project/AdditionalFields.java | 9 +- .../egov/common/models/project/Address.java | 13 +- .../project/BeneficiaryBulkRequest.java | 8 +- .../project/BeneficiaryBulkResponse.java | 36 +- .../models/project/BeneficiaryRequest.java | 6 +- .../models/project/BeneficiaryResponse.java | 6 +- .../project/BeneficiarySearchRequest.java | 6 +- .../egov/common/models/project/Boundary.java | 58 -- .../egov/common/models/project/Document.java | 8 +- .../org/egov/common/models/project/Field.java | 6 +- .../egov/common/models/project/Project.java | 4 +- .../models/project/ProjectBeneficiary.java | 52 +- .../project/ProjectBeneficiarySearch.java | 34 +- .../models/project/ProjectFacility.java | 39 +- .../project/ProjectFacilityBulkRequest.java | 8 +- .../project/ProjectFacilityBulkResponse.java | 6 +- .../project/ProjectFacilityRequest.java | 6 +- .../project/ProjectFacilityResponse.java | 6 +- .../models/project/ProjectFacilitySearch.java | 23 +- .../project/ProjectFacilitySearchRequest.java | 7 +- .../models/project/ProjectProductVariant.java | 4 +- .../common/models/project/ProjectRequest.java | 8 +- .../models/project/ProjectResource.java | 35 +- .../project/ProjectResourceBulkRequest.java | 8 +- .../project/ProjectResourceBulkResponse.java | 6 +- .../project/ProjectResourceRequest.java | 6 +- .../project/ProjectResourceResponse.java | 6 +- .../models/project/ProjectResourceSearch.java | 22 +- .../project/ProjectResourceSearchRequest.java | 7 +- .../models/project/ProjectResponse.java | 6 +- .../common/models/project/ProjectSearch.java | 159 ++++- .../models/project/ProjectSearchRequest.java | 8 +- .../common/models/project/ProjectStaff.java | 38 +- .../project/ProjectStaffBulkRequest.java | 8 +- .../project/ProjectStaffBulkResponse.java | 6 +- .../models/project/ProjectStaffRequest.java | 6 +- .../models/project/ProjectStaffResponse.java | 6 +- .../models/project/ProjectStaffSearch.java | 26 +- .../project/ProjectStaffSearchRequest.java | 7 +- .../common/models/project/ProjectType.java | 6 +- .../org/egov/common/models/project/Role.java | 6 +- .../egov/common/models/project/Target.java | 2 +- .../org/egov/common/models/project/Task.java | 43 +- .../models/project/TaskBulkRequest.java | 8 +- .../models/project/TaskBulkResponse.java | 11 +- .../common/models/project/TaskRequest.java | 6 +- .../common/models/project/TaskResource.java | 8 +- .../models/project/TaskResourceRequest.java | 8 +- .../models/project/TaskResourceResponse.java | 6 +- .../common/models/project/TaskResponse.java | 6 +- .../common/models/project/TaskSearch.java | 29 +- .../models/project/TaskSearchRequest.java | 6 +- .../common/models/project/TenantRole.java | 6 +- .../egov/common/models/project/UserInfo.java | 6 +- .../models/referralmanagement/Referral.java | 46 +- .../ReferralBulkRequest.java | 6 +- .../ReferralBulkResponse.java | 9 +- .../referralmanagement/ReferralRequest.java | 4 +- .../referralmanagement/ReferralResponse.java | 4 +- .../referralmanagement/ReferralSearch.java | 16 +- .../ReferralSearchRequest.java | 4 +- .../beneficiarydownsync/DownsyncCriteria.java | 2 +- .../hfreferral/HFReferral.java | 43 +- .../hfreferral/HFReferralBulkRequest.java | 6 +- .../hfreferral/HFReferralBulkResponse.java | 4 +- .../hfreferral/HFReferralRequest.java | 4 +- .../hfreferral/HFReferralResponse.java | 4 +- .../hfreferral/HFReferralSearch.java | 15 +- .../hfreferral/HFReferralSearchRequest.java | 4 +- .../sideeffect/SideEffect.java | 43 +- .../sideeffect/SideEffectBulkRequest.java | 6 +- .../sideeffect/SideEffectBulkResponse.java | 9 +- .../sideeffect/SideEffectRequest.java | 4 +- .../sideeffect/SideEffectResponse.java | 4 +- .../sideeffect/SideEffectSearch.java | 20 +- .../sideeffect/SideEffectSearchRequest.java | 4 +- .../common/models/stock/AdditionalFields.java | 10 +- .../org/egov/common/models/stock/Address.java | 15 +- .../egov/common/models/stock/AddressType.java | 1 + .../egov/common/models/stock/Boundary.java | 82 --- .../org/egov/common/models/stock/Field.java | 6 +- .../org/egov/common/models/stock/Stock.java | 50 +- .../common/models/stock/StockBulkRequest.java | 8 +- .../models/stock/StockBulkResponse.java | 6 +- .../models/stock/StockReconciliation.java | 44 +- .../stock/StockReconciliationBulkRequest.java | 8 +- .../StockReconciliationBulkResponse.java | 6 +- .../stock/StockReconciliationRequest.java | 6 +- .../stock/StockReconciliationResponse.java | 6 +- .../stock/StockReconciliationSearch.java | 27 +- .../StockReconciliationSearchRequest.java | 6 +- .../common/models/stock/StockRequest.java | 6 +- .../common/models/stock/StockResponse.java | 6 +- .../egov/common/models/stock/StockSearch.java | 28 +- .../models/stock/StockSearchRequest.java | 6 +- .../egov/common/models/stock/TenantRole.java | 6 +- .../egov/common/models/stock/UserInfo.java | 6 +- .../models/transformer/upstream/Boundary.java | 61 -- health-services/product/CHANGELOG.md | 4 + health-services/product/README.md | 10 + health-services/product/pom.xml | 4 +- .../rowmapper/ProductRowMapper.java | 8 +- .../rowmapper/ProductVariantRowMapper.java | 2 +- .../web/controllers/ProductApiController.java | 31 +- .../product/web/models/ProductSearch.java | 4 +- .../web/models/ProductVariantSearch.java | 3 +- .../service/ProductServiceSearchTest.java | 4 +- .../ProductVariantApiControllerTest.java | 4 +- health-services/project/CHANGELOG.md | 9 + health-services/project/README.md | 14 + health-services/project/pom.xml | 40 +- .../project/config/MainConfiguration.java | 2 +- .../ProjectBeneficiaryRepository.java | 91 +++ .../project/repository/ProjectRepository.java | 66 ++ .../repository/ProjectTaskRepository.java | 35 +- .../ProjectAddressQueryBuilder.java | 139 ++++- .../ProjectBeneficiaryRowMapper.java | 2 +- .../rowmapper/ProjectFacilityRowMapper.java | 8 +- .../rowmapper/ProjectStaffRowMapper.java | 8 +- .../rowmapper/ProjectTaskRowMapper.java | 4 +- .../service/ProjectBeneficiaryService.java | 37 +- .../service/ProjectFacilityService.java | 2 +- .../service/ProjectResourceService.java | 2 +- .../egov/project/service/ProjectService.java | 39 +- .../project/service/ProjectStaffService.java | 2 +- .../project/service/ProjectTaskService.java | 28 +- .../ProjectBeneficiaryEnrichmentService.java | 6 +- .../org/egov/project/util/BoundaryV2Util.java | 84 +++ .../PbExistentEntityValidator.java | 77 +++ .../beneficiary/PbRowVersionValidator.java | 2 +- .../PbVoucherTagUniqueForCreateValidator.java | 4 +- .../PbVoucherTagUniqueForUpdateValidator.java | 19 +- .../validator/project/ProjectValidator.java | 68 ++- .../task/PtExistentEntityValidator.java | 76 +++ .../task/PtNonExistentEntityValidator.java | 2 +- .../validator/task/PtRowVersionValidator.java | 2 +- .../web/controllers/BandwidthController.java | 2 +- .../web/controllers/ProjectApiController.java | 157 +++-- .../ProjectResourceApiController.java | 39 +- .../web/models/BandwidthCheckRequest.java | 4 +- .../web/models/BandwidthCheckResponse.java | 4 +- .../web/models/BeneficiarySearchRequest.java | 7 +- .../web/models/ProjectBeneficiarySearch.java | 55 -- .../web/models/ProjectFacilitySearch.java | 42 -- .../models/ProjectFacilitySearchRequest.java | 39 -- .../web/models/ProjectResourceSearch.java | 39 -- .../models/ProjectResourceSearchRequest.java | 39 -- .../project/web/models/ProjectSearch.java | 65 -- .../web/models/ProjectStaffSearch.java | 54 -- .../web/models/ProjectStaffSearchRequest.java | 39 -- .../web/models/boundary/BoundaryRequest.java | 38 ++ .../web/models/boundary/BoundaryResponse.java | 44 ++ .../boundary/BoundarySearchCriteria.java | 37 ++ .../src/main/resources/application.properties | 12 +- ...__project_beneficiary_search_index_ddl.sql | 1 + ...114021__task_resource_search_index_ddl.sql | 1 + .../helper/ProjectBeneficiaryTestBuilder.java | 26 +- .../helper/ProjectFacilityTestBuilder.java | 10 +- .../helper/ProjectResourceTestBuilder.java | 4 +- .../helper/ProjectStaffTestBuilder.java | 6 +- .../egov/project/helper/TaskTestBuilder.java | 21 +- ...eneficiaryEnrichmentServiceUpdateTest.java | 9 +- .../ProjectBeneficiaryServiceSearchTest.java | 21 +- .../ProjectBeneficiaryServiceUpdateTest.java | 9 +- .../ProjectFacilityServiceSearchTest.java | 4 +- .../ProjectStaffServiceSearchTest.java | 6 +- .../service/ProjectTaskServiceSearchTest.java | 23 +- .../ProjectBeneficiaryApiControllerTest.java | 11 +- .../ProjectFacilityApiControllerTest.java | 4 +- .../ProjectStaffApiControllerTest.java | 6 +- .../ProjectTaskApiControllerTest.java | 8 +- .../referralmanagement/CHANGELOG.md | 7 + health-services/referralmanagement/pom.xml | 40 +- .../config/MainConfiguration.java | 5 +- .../repository/HFReferralRepository.java | 2 +- .../repository/ReferralRepository.java | 26 +- .../repository/SideEffectRepository.java | 12 +- .../rowmapper/HFReferralRowMapper.java | 2 +- .../rowmapper/ReferralRowMapper.java | 58 +- .../rowmapper/SideEffectRowMapper.java | 40 +- .../service/DownsyncService.java | 563 +++++++++--------- .../service/HFReferralService.java | 2 + .../service/ReferralManagementService.java | 39 +- .../service/SideEffectService.java | 20 +- .../validator/RmExistentEntityValidator.java | 76 +++ .../RmNonExistentEntityValidator.java | 2 +- .../validator/RmSideEffectIdValidator.java | 2 +- .../HfrExistentEntityValidator.java | 78 +++ .../HfrProjectFacilityIdValidator.java | 1 - .../sideeffect/SeExistentEntityValidator.java | 76 +++ .../SeProjectBeneficiaryIdValidator.java | 9 +- .../BeneficiaryDownsyncController.java | 2 +- .../controllers/HFReferralApiController.java | 35 +- .../ReferralManagementApiController.java | 47 +- .../controllers/SideEffectApiController.java | 41 +- ...000__referral_referral_code_create_ddl.sql | 1 + .../org/egov/referralmanagement/AppTest.java | 5 +- .../helper/ReferralTestBuilder.java | 4 +- .../helper/SideEffectTestBuilder.java | 4 +- .../ReferralManagementApiControllerTest.java | 7 +- .../SideEffectApiControllerTest.java | 11 +- health-services/stock/CHANGELOG.md | 6 + health-services/stock/README.md | 10 + health-services/stock/pom.xml | 25 +- .../egov/stock/config/MainConfiguration.java | 2 +- .../StockReconciliationRowMapper.java | 8 +- .../repository/rowmapper/StockRowMapper.java | 2 +- .../service/StockReconciliationService.java | 4 +- .../org/egov/stock/service/StockService.java | 31 +- .../stock/SExistentEntityValidator.java | 77 +++ .../SrExistentEntityValidator.java | 77 +++ .../web/controllers/StockApiController.java | 36 +- .../StockReconciliationApiController.java | 37 +- .../web/models/StockReconciliationSearch.java | 44 -- .../StockReconciliationSearchRequest.java | 38 -- .../egov/stock/web/models/StockSearch.java | 71 --- .../src/main/resources/application.properties | 1 + .../StockReconciliationTestBuilder.java | 5 +- .../egov/stock/helper/StockTestBuilder.java | 4 +- health-services/transformer/CHANGELOG.md | 11 +- health-services/transformer/pom.xml | 34 +- .../transformer/boundary/BoundaryMapper.java | 9 +- .../transformer/boundary/BoundaryNode.java | 8 +- .../transformer/boundary/TreeGenerator.java | 44 -- .../transformer/config/MainConfiguration.java | 43 +- .../config/TransformerProperties.java | 11 + .../http/client/ServiceRequestClient.java | 2 +- .../models/boundary/BoundaryRequest.java | 38 ++ .../models/boundary/BoundaryResponse.java | 44 ++ .../boundary/BoundarySearchCriteria.java | 37 ++ .../boundary/BoundarySearchResponse.java | 33 + .../models/boundary/EnrichedBoundary.java | 43 ++ .../models/boundary/HierarchyRelation.java | 34 ++ .../egov/transformer/producer/Producer.java | 2 +- .../transformer/service/BoundaryService.java | 119 ---- .../transformer/service/FacilityService.java | 14 +- .../egov/transformer/service/MdmsService.java | 2 +- .../ProjectIndexV1TransformationService.java | 2 +- .../transformer/service/ProjectService.java | 102 +++- ...jectStaffIndexV1TransformationService.java | 2 +- .../ProjectStaffTransformationService.java | 4 +- ...ojectTaskIndexV1TransformationService.java | 2 +- .../ProjectTaskTransformationService.java | 6 +- .../service/ProjectTransformationService.java | 4 +- .../service/ServiceDefinitionService.java | 12 +- ...rviceTaskIndexV1TransformationService.java | 2 +- .../ServiceTaskTransformationService.java | 4 +- .../StockIndexV1TransformationService.java | 2 +- .../service/StockTransformationService.java | 21 +- .../src/main/resources/application.properties | 8 +- .../location/TreeGeneratorTest.java | 169 ------ 474 files changed, 7256 insertions(+), 4719 deletions(-) create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/EgovOfflineSearchModel.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/EgovSearchModel.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/Exclude.java rename {health-services/individual/src/main/java/org/egov/individual => core-services/egov-hrms/src/main/java/org/egov/hrms}/web/models/IndividualSearch.java (71%) rename health-services/stock/src/main/java/org/egov/stock/web/models/StockSearchRequest.java => core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/IndividualSearchRequest.java (70%) create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/Boundary.java rename health-services/project/src/main/java/org/egov/project/web/models/ProjectSearchRequest.java => core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundaryRequest.java (63%) create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundaryResponse.java create mode 100644 core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundarySearchCriteria.java create mode 100644 health-services/facility/src/main/java/org/egov/facility/validator/FBoundaryValidator.java create mode 100644 health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundaryRequest.java create mode 100644 health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundaryResponse.java create mode 100644 health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundarySearchCriteria.java create mode 100644 health-services/household/src/main/java/org/egov/household/household/member/validators/HmExistentEntityValidator.java create mode 100644 health-services/household/src/main/java/org/egov/household/validators/household/HBoundaryValidator.java create mode 100644 health-services/household/src/main/java/org/egov/household/validators/household/HExistentEntityValidator.java create mode 100644 health-services/household/src/main/java/org/egov/household/validators/household/HNonExistentEntityValidator.java delete mode 100644 health-services/household/src/main/java/org/egov/household/web/models/HouseholdMemberSearch.java delete mode 100644 health-services/household/src/main/java/org/egov/household/web/models/HouseholdMemberSearchRequest.java delete mode 100644 health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearch.java delete mode 100644 health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearchRequest.java create mode 100644 health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundaryRequest.java create mode 100644 health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundaryResponse.java create mode 100644 health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundarySearchCriteria.java create mode 100644 health-services/household/src/main/resources/db/migration/main/V20240305114132__household_search_index_ddl.sql create mode 100644 health-services/household/src/main/resources/db/migration/main/V20240305114225__household_member_search_index_ddl.sql create mode 100644 health-services/household/src/test/java/org/egov/household/helper/HouseholdMemberSearchRequestTestBuilder.java create mode 100644 health-services/household/src/test/java/org/egov/household/helper/HouseholdSearchTestBuilder.java create mode 100644 health-services/individual/src/main/java/org/egov/individual/validators/IBoundaryValidator.java create mode 100644 health-services/individual/src/main/java/org/egov/individual/validators/IExistentEntityValidator.java create mode 100644 health-services/individual/src/main/java/org/egov/individual/validators/INonExistentEntityValidator.java delete mode 100644 health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearchRequest.java create mode 100644 health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundaryRequest.java create mode 100644 health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundaryResponse.java create mode 100644 health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundarySearchCriteria.java delete mode 100644 health-services/libraries/health-services-common/src/main/java/org/egov/common/AddressDummyTest.java delete mode 100644 health-services/libraries/health-services-common/src/main/java/org/egov/common/data/mapper/GenericRowMapper.java delete mode 100644 health-services/libraries/health-services-common/src/test/java/org/egov/common/data/mapper/GenericRowMapperTest.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/AdditionalFields.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Boundary.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovModel.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovOfflineModel.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovOfflineSearchModel.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovSearchModel.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Exclude.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Field.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/ProjectSearchURLParams.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/SearchResponse.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Table.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/URLParams.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/UpdateBy.java delete mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Boundary.java delete mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Boundary.java delete mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Boundary.java delete mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Boundary.java delete mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Boundary.java delete mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Boundary.java delete mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/transformer/upstream/Boundary.java create mode 100644 health-services/project/src/main/java/org/egov/project/util/BoundaryV2Util.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbExistentEntityValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/task/PtExistentEntityValidator.java delete mode 100644 health-services/project/src/main/java/org/egov/project/web/models/ProjectBeneficiarySearch.java delete mode 100644 health-services/project/src/main/java/org/egov/project/web/models/ProjectFacilitySearch.java delete mode 100644 health-services/project/src/main/java/org/egov/project/web/models/ProjectFacilitySearchRequest.java delete mode 100644 health-services/project/src/main/java/org/egov/project/web/models/ProjectResourceSearch.java delete mode 100644 health-services/project/src/main/java/org/egov/project/web/models/ProjectResourceSearchRequest.java delete mode 100644 health-services/project/src/main/java/org/egov/project/web/models/ProjectSearch.java delete mode 100644 health-services/project/src/main/java/org/egov/project/web/models/ProjectStaffSearch.java delete mode 100644 health-services/project/src/main/java/org/egov/project/web/models/ProjectStaffSearchRequest.java create mode 100644 health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundaryRequest.java create mode 100644 health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundaryResponse.java create mode 100644 health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundarySearchCriteria.java create mode 100644 health-services/project/src/main/resources/db/migration/main/V20240305113500__project_beneficiary_search_index_ddl.sql create mode 100644 health-services/project/src/main/resources/db/migration/main/V20240305114021__task_resource_search_index_ddl.sql create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmExistentEntityValidator.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrExistentEntityValidator.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeExistentEntityValidator.java create mode 100644 health-services/referralmanagement/src/main/resources/db/migration/main/V20240416111000__referral_referral_code_create_ddl.sql create mode 100644 health-services/stock/src/main/java/org/egov/stock/validator/stock/SExistentEntityValidator.java create mode 100644 health-services/stock/src/main/java/org/egov/stock/validator/stockreconciliation/SrExistentEntityValidator.java delete mode 100644 health-services/stock/src/main/java/org/egov/stock/web/models/StockReconciliationSearch.java delete mode 100644 health-services/stock/src/main/java/org/egov/stock/web/models/StockReconciliationSearchRequest.java delete mode 100644 health-services/stock/src/main/java/org/egov/stock/web/models/StockSearch.java delete mode 100644 health-services/transformer/src/main/java/org/egov/transformer/boundary/TreeGenerator.java create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundaryRequest.java create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundaryResponse.java create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundarySearchCriteria.java create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundarySearchResponse.java create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/models/boundary/EnrichedBoundary.java create mode 100644 health-services/transformer/src/main/java/org/egov/transformer/models/boundary/HierarchyRelation.java delete mode 100644 health-services/transformer/src/main/java/org/egov/transformer/service/BoundaryService.java delete mode 100644 health-services/transformer/src/test/java/org/egov/transformer/location/TreeGeneratorTest.java diff --git a/.gitignore b/.gitignore index 423e1befca8..d1d7c47d852 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,84 @@ frontend/micro-ui-internals/node_modules/* .idea index.lock /health-services/stock/stock.iml +# Ignore target directories +**/target/ + +# Ignore IDE-specific files +*.iml +*.classpath +*.project +*.settings/ + +# Ignore gitignore files +**/.gitignore + +# Ignore compiled binaries and libraries +*.jar +*.war +*.ear +bin/ + +# Ignore system-specific files +.DS_Store +Thumbs.db +# Ignore target directories +**/target/ + +# Ignore IDE-specific files +*.iml +*.classpath +*.project +*.settings/ + +# Ignore gitignore files +**/.gitignore + +# Ignore compiled binaries and libraries +*.jar +*.war +*.ear + +# Ignore system-specific files +.DS_Store +Thumbs.db +# Ignore target directories +**/target/ + +# Ignore IDE-specific files +*.iml +*.classpath +*.project +*.settings/ + +# Ignore gitignore files +**/.gitignore + +# Ignore compiled binaries and libraries +*.jar +*.war +*.ear + +# Ignore system-specific files +.DS_Store +Thumbs.db +# Ignore target directories +**/target/ + +# Ignore IDE-specific files +*.iml +*.classpath +*.project +*.settings/ + +# Ignore gitignore files +**/.gitignore + +# Ignore compiled binaries and libraries +*.jar +*.war +*.ear + +# Ignore system-specific files +.DS_Store +Thumbs.db \ No newline at end of file diff --git a/CODEOWNERS b/CODEOWNERS index 8223a68b3fb..e5b57cd157d 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,3 +1 @@ -* @kavi-egov @sathishp-eGov - - +* @kavi-egov @sathishp-eGov \ No newline at end of file diff --git a/core-services/egov-hrms/CHANGELOG.md b/core-services/egov-hrms/CHANGELOG.md index ff7b8ed8811..0b29fa88acc 100644 --- a/core-services/egov-hrms/CHANGELOG.md +++ b/core-services/egov-hrms/CHANGELOG.md @@ -1,6 +1,13 @@ # Changelog All notable changes to this module will be documented in this file. +## 1.2.7 - 2024-05-29 +- Integrated Boundary v2 functionality +- Individual model copied and replicated to the 2.9 version + +## 1.2.6 - 2024-03-06 +- Added client Referenceid to Individual to avoid errors during down sync in APK + ## 1.2.5 - 2023-02-02 - Transition from 1.2.5-beta version to 1.2.5 version diff --git a/core-services/egov-hrms/pom.xml b/core-services/egov-hrms/pom.xml index 63ff6fcda8c..49979c02a0e 100644 --- a/core-services/egov-hrms/pom.xml +++ b/core-services/egov-hrms/pom.xml @@ -9,7 +9,7 @@ org.egov egov-hrms - 1.2.6-SNAPSHOT + 1.2.7-SNAPSHOT egov-hrms HR Management System @@ -100,7 +100,7 @@ org.egov.common health-services-models - 1.0.9-SNAPSHOT + 1.0.12-SNAPSHOT compile diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/config/PropertiesManager.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/config/PropertiesManager.java index dd0fb1ee4c6..1f0522f0d36 100644 --- a/core-services/egov-hrms/src/main/java/org/egov/hrms/config/PropertiesManager.java +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/config/PropertiesManager.java @@ -134,4 +134,10 @@ public class PropertiesManager { @Value("${egov.hrms.auto.generate.password}") private boolean autoGeneratePassword; + + @Value("${egov.boundary.host}") + private String boundaryServiceHost; + + @Value("${egov.boundary.search.url}") + private String boundarySearchUrl; } \ No newline at end of file diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/EmployeeService.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/EmployeeService.java index ec86d2452ce..b3f05426c7a 100644 --- a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/EmployeeService.java +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/EmployeeService.java @@ -146,6 +146,7 @@ public EmployeeResponse search(EmployeeSearchCriteria criteria, RequestInfo requ || !CollectionUtils.isEmpty(criteria.getRoles()) || !CollectionUtils.isEmpty(criteria.getCodes())) { Map userSearchCriteria = new HashMap<>(); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE_CODE, HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE); userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID,criteria.getTenantId()); if(!StringUtils.isEmpty(criteria.getPhone())) userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_MOBILENO,criteria.getPhone()); @@ -173,6 +174,7 @@ public EmployeeResponse search(EmployeeSearchCriteria criteria, RequestInfo requ List userUUIDs = new ArrayList<>(); for(String name: criteria.getNames()) { Map userSearchCriteria = new HashMap<>(); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE_CODE, HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE); userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID,criteria.getTenantId()); userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_NAME,name); UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); @@ -198,6 +200,7 @@ public EmployeeResponse search(EmployeeSearchCriteria criteria, RequestInfo requ List uuids = employees.stream().map(Employee :: getUuid).collect(Collectors.toList()); if(!CollectionUtils.isEmpty(uuids)){ Map userSearchCriteria = new HashMap<>(); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE_CODE, HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE); userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_UUID,uuids); userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID, criteria.getTenantId()); log.info("uuid is available {}", userSearchCriteria); diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/IndividualService.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/IndividualService.java index 07b315bf1bc..0783de1fdc5 100644 --- a/core-services/egov-hrms/src/main/java/org/egov/hrms/service/IndividualService.java +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/service/IndividualService.java @@ -2,6 +2,7 @@ import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; @@ -13,6 +14,7 @@ import digit.models.coremodels.AuditDetails; import digit.models.coremodels.user.enums.UserType; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.models.core.Role; import org.egov.common.models.individual.Address; @@ -23,8 +25,6 @@ import org.egov.common.models.individual.IndividualBulkResponse; import org.egov.common.models.individual.IndividualRequest; import org.egov.common.models.individual.IndividualResponse; -import org.egov.common.models.individual.IndividualSearch; -import org.egov.common.models.individual.IndividualSearchRequest; import org.egov.common.models.individual.Name; import org.egov.common.models.individual.UserDetails; import org.egov.hrms.config.PropertiesManager; @@ -33,6 +33,8 @@ import org.egov.hrms.web.contract.User; import org.egov.hrms.web.contract.UserRequest; import org.egov.hrms.web.contract.UserResponse; +import org.egov.hrms.web.models.IndividualSearch; +import org.egov.hrms.web.models.IndividualSearchRequest; import org.springframework.beans.factory.annotation.Autowired; import static org.egov.hrms.utils.HRMSConstants.SYSTEM_GENERATED; @@ -70,13 +72,20 @@ public UserResponse createUser(UserRequest userRequest) { @Override public UserResponse updateUser(UserRequest userRequest) { - IndividualRequest request = mapToIndividualRequest(userRequest); + IndividualSearchRequest individualSearchRequest = mapToIndividualSearchRequest(userRequest); + IndividualBulkResponse individualSearchResponse = + getIndividualResponse(userRequest.getUser().getTenantId(), individualSearchRequest); + UserResponse userResponse = null; + if (individualSearchResponse == null || individualSearchResponse.getIndividual() == null || individualSearchResponse.getIndividual().size() == 0) { + return userResponse; + } + Individual individual = individualSearchResponse.getIndividual().get(0); + IndividualRequest updateRequest = mapToIndividualUpdateRequest(individual, userRequest); StringBuilder uri = new StringBuilder(); uri.append(propertiesManager.getIndividualHost()); uri.append(propertiesManager.getIndividualUpdateEndpoint()); IndividualResponse response = restCallRepository - .fetchResult(uri, request, IndividualResponse.class); - UserResponse userResponse = null; + .fetchResult(uri, updateRequest, IndividualResponse.class); if (response != null && response.getIndividual() != null) { log.info("response received from individual service"); userResponse = mapToUserResponse(response); @@ -84,18 +93,94 @@ public UserResponse updateUser(UserRequest userRequest) { return userResponse; } + private IndividualRequest mapToIndividualUpdateRequest(Individual individual, UserRequest userRequest) { + Individual updatedIndividual = Individual.builder() + .id(individual.getId()) + .userId(individual.getUserId()) + .userUuid(individual.getUserUuid()) + .isSystemUser(true) + .isSystemUserActive(userRequest.getUser().getActive()) + .name(Name.builder() + .givenName(userRequest.getUser().getName()) + .build()) + .gender(Gender.fromValue(userRequest.getUser().getGender())) + .email(userRequest.getUser().getEmailId()) + .mobileNumber(userRequest.getUser().getMobileNumber()) + .dateOfBirth(convertMillisecondsToDate(userRequest.getUser().getDob())) + .tenantId(userRequest.getUser().getTenantId()) + .address(Collections.singletonList(Address.builder() + .type(AddressType.CORRESPONDENCE) + .addressLine1(userRequest.getUser().getCorrespondenceAddress()) + .clientReferenceId(String.valueOf(UUID.randomUUID())) + .isDeleted(Boolean.FALSE) + .build())) + /* + * FIXME (HCM specific change) clientReferenceId is the primary key in the individual table of the FrontEnd Worker Application's local database. + */ + // Generating a unique client reference ID using UUID + .clientReferenceId(individual.getClientReferenceId()) + .userDetails(UserDetails.builder() + .username(userRequest.getUser().getUserName()) + .password(userRequest.getUser().getPassword()) + .tenantId(userRequest.getUser().getTenantId()) + .roles(userRequest.getUser().getRoles().stream().map(role -> Role.builder() + .code(role.getCode()) + .name(role.getName()) + .tenantId(userRequest.getUser().getTenantId()) + .description(role.getDescription()) + .build()).collect(Collectors.toList())) + .userType(UserType.fromValue(userRequest.getUser().getType())) + .build()) + .isDeleted(Boolean.FALSE) + .clientAuditDetails(AuditDetails.builder() + .createdBy(individual.getAuditDetails().getCreatedBy()) + .createdTime(individual.getAuditDetails().getCreatedTime()) + .lastModifiedBy(userRequest.getRequestInfo().getUserInfo().getUuid()).build()) + .rowVersion(userRequest.getUser().getRowVersion()) + .build(); + return IndividualRequest.builder() + .requestInfo(userRequest.getRequestInfo()) + .individual(updatedIndividual) + .build(); + } + + private IndividualSearchRequest mapToIndividualSearchRequest(UserRequest userRequest) { + return IndividualSearchRequest.builder() + .requestInfo(userRequest.getRequestInfo()) + .individual( + IndividualSearch.builder() + .id(Collections.singletonList(userRequest.getUser().getUuid())) + .userUuid(userRequest.getUser().getUserServiceUuid() != null ? Collections.singletonList(userRequest.getUser().getUserServiceUuid()) : null) + .build() + ) + .build(); + } + @Override public UserResponse getUser(RequestInfo requestInfo, Map userSearchCriteria ) { + String mobileNumber = (String) userSearchCriteria.get("mobileNumber"); + String username = (String) userSearchCriteria.get(HRMSConstants.HRMS_USER_SEARCH_CRITERA_USERNAME); + List mobileNumberList = null; + List usernameList = null; + if(!StringUtils.isEmpty(mobileNumber)) { + mobileNumberList = Collections.singletonList(mobileNumber); + } + if(!StringUtils.isEmpty(username)) { + usernameList = Collections.singletonList(username); + } IndividualSearchRequest request = IndividualSearchRequest.builder() .requestInfo(requestInfo) .individual(IndividualSearch.builder() - .mobileNumber((String) userSearchCriteria.get("mobileNumber")) + .mobileNumber( + mobileNumberList + ) .id((List) userSearchCriteria.get("uuid")) .roleCodes((List) userSearchCriteria.get("roleCodes")) - .username((String) userSearchCriteria.get(HRMSConstants.HRMS_USER_SEARCH_CRITERA_USERNAME)) + .username(usernameList) // given name .individualName((String) userSearchCriteria .get(HRMSConstants.HRMS_USER_SEARCH_CRITERA_NAME)) + .type((String) userSearchCriteria.get(HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE_CODE)) .build()) .build(); IndividualBulkResponse response = getIndividualResponse((String) userSearchCriteria diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/EgovOfflineSearchModel.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/EgovOfflineSearchModel.java new file mode 100644 index 00000000000..e744771def2 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/EgovOfflineSearchModel.java @@ -0,0 +1,20 @@ +package org.egov.hrms.web.models; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class EgovOfflineSearchModel extends EgovSearchModel { + @JsonProperty("clientReferenceId") + private List clientReferenceId = null; +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/EgovSearchModel.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/EgovSearchModel.java new file mode 100644 index 00000000000..ae080fbcc57 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/EgovSearchModel.java @@ -0,0 +1,22 @@ +package org.egov.hrms.web.models; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import javax.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class EgovSearchModel { + @JsonProperty("id") + @Valid + private List id = null; +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/Exclude.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/Exclude.java new file mode 100644 index 00000000000..aa7eae18a57 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/Exclude.java @@ -0,0 +1,13 @@ +package org.egov.hrms.web.models; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +// This annotation is used to mark fields in a model class that should be ignored or excluded when the class is being processed, +// specifically during serialization to JSON or when constructing database queries. +public @interface Exclude { +} diff --git a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/IndividualSearch.java similarity index 71% rename from health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java rename to core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/IndividualSearch.java index 51dec55ace1..d0034dc4d9a 100644 --- a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearch.java +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/IndividualSearch.java @@ -1,48 +1,37 @@ -package org.egov.individual.web.models; +package org.egov.hrms.web.models; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; +import javax.validation.Valid; +import javax.validation.constraints.DecimalMax; +import javax.validation.constraints.DecimalMin; +import javax.validation.constraints.Size; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; -import org.egov.common.data.query.annotations.Exclude; +import lombok.experimental.SuperBuilder; import org.egov.common.models.individual.Gender; import org.egov.common.models.individual.Identifier; import org.egov.common.models.individual.Name; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.DecimalMax; -import javax.validation.constraints.DecimalMin; -import javax.validation.constraints.Size; -import java.math.BigDecimal; -import java.util.Date; -import java.util.List; - /** * A representation of an Individual. */ - @ApiModel(description = "A representation of an Individual.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") - @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class IndividualSearch { - @JsonProperty("id") - private List id = null; - +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class IndividualSearch extends EgovOfflineSearchModel { @JsonProperty("individualId") - private String individualId = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; + private List individualId = null; @JsonProperty("name") @Valid @@ -57,54 +46,46 @@ public class IndividualSearch { private Gender gender = null; @JsonProperty("mobileNumber") - private String mobileNumber = null; + private List mobileNumber = null; @JsonProperty("socialCategory") - @Exclude private String socialCategory = null; @JsonProperty("wardCode") - @Exclude private String wardCode = null; @JsonProperty("individualName") - @Exclude private String individualName = null; @JsonProperty("createdFrom") - @Exclude private BigDecimal createdFrom = null; @JsonProperty("createdTo") - @Exclude private BigDecimal createdTo = null; @JsonProperty("identifier") @Valid - @Exclude private Identifier identifier = null; @JsonProperty("boundaryCode") - @Exclude private String boundaryCode = null; @JsonProperty("roleCodes") - @Exclude private List roleCodes = null; - @Exclude @JsonProperty("username") - private String username; + private List username; - @Exclude @JsonProperty("userId") - private Long userId; + private List userId; - @Exclude @JsonProperty("userUuid") @Size(min = 1) private List userUuid; + @JsonProperty("type") + private String type; + @Exclude @JsonProperty("latitude") @DecimalMin("-90") @@ -118,8 +99,8 @@ public class IndividualSearch { private Double longitude; /* - * @value unit of measurement in Kilometer - * */ + * @value unit of measurement in Kilometer + * */ @Exclude @JsonProperty("searchRadius") @DecimalMin("0") diff --git a/health-services/stock/src/main/java/org/egov/stock/web/models/StockSearchRequest.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/IndividualSearchRequest.java similarity index 70% rename from health-services/stock/src/main/java/org/egov/stock/web/models/StockSearchRequest.java rename to core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/IndividualSearchRequest.java index b1eeec0dabb..dd968c97f25 100644 --- a/health-services/stock/src/main/java/org/egov/stock/web/models/StockSearchRequest.java +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/IndividualSearchRequest.java @@ -1,37 +1,37 @@ -package org.egov.stock.web.models; +package org.egov.hrms.web.models; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - /** -* StockSearchRequest +* IndividualSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) -public class StockSearchRequest { - +public class IndividualSearchRequest { @JsonProperty("RequestInfo") @NotNull @Valid private org.egov.common.contract.request.RequestInfo requestInfo = null; - @JsonProperty("Stock") + @JsonProperty("Individual") @NotNull @Valid - private StockSearch stock = null; + private IndividualSearch individual = null; + + } diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/Boundary.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/Boundary.java new file mode 100644 index 00000000000..4972888a0fc --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/Boundary.java @@ -0,0 +1,44 @@ +package org.egov.hrms.web.models.boundary; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.hrms.model.AuditDetails; +import org.springframework.validation.annotation.Validated; + +/** + * Boundary + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Boundary { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("code") + @NotNull + private String code = null; + + @JsonProperty("geometry") + @Valid + private JsonNode geometry = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("additionalDetails") + private JsonNode additionalDetails = null; +} diff --git a/health-services/project/src/main/java/org/egov/project/web/models/ProjectSearchRequest.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundaryRequest.java similarity index 63% rename from health-services/project/src/main/java/org/egov/project/web/models/ProjectSearchRequest.java rename to core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundaryRequest.java index a0dbf1c361c..a9f4c40be39 100644 --- a/health-services/project/src/main/java/org/egov/project/web/models/ProjectSearchRequest.java +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundaryRequest.java @@ -1,6 +1,10 @@ -package org.egov.project.web.models; +package org.egov.hrms.web.models.boundary; + +import java.util.List; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; import lombok.Builder; @@ -9,31 +13,25 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - /** -* ProjectSearchRequest -*/ + * BoundaryRequest + */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") @Data -@NoArgsConstructor @AllArgsConstructor +@NoArgsConstructor @Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectSearchRequest { +public class BoundaryRequest { @JsonProperty("RequestInfo") - @NotNull @Valid private RequestInfo requestInfo = null; - @JsonProperty("Project") - @NotNull @Valid - private ProjectSearch project = null; + @NotNull + @JsonProperty("Boundary") + @Size(min = 1, max = 300) + private List boundary = null; } - diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundaryResponse.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundaryResponse.java new file mode 100644 index 00000000000..942e4b5f392 --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundaryResponse.java @@ -0,0 +1,43 @@ +package org.egov.hrms.web.models.boundary; + +import java.util.ArrayList; +import java.util.List; +import javax.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryResponse + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Boundary") + @Valid + private List boundary = null; + + + public BoundaryResponse addBoundaryItem(Boundary boundaryItem) { + if (this.boundary == null) { + this.boundary = new ArrayList<>(); + } + this.boundary.add(boundaryItem); + return this; + } + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundarySearchCriteria.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundarySearchCriteria.java new file mode 100644 index 00000000000..6a9ccaf34dc --- /dev/null +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/models/boundary/BoundarySearchCriteria.java @@ -0,0 +1,37 @@ +package org.egov.hrms.web.models.boundary; + +import java.util.List; +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-10-16T17:02:11.361704+05:30[Asia/Kolkata]") +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundarySearchCriteria { + + @NotNull + @Size(min = 1) + @JsonProperty("codes") + private List codes; + + @NotNull + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} diff --git a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/validator/EmployeeValidator.java b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/validator/EmployeeValidator.java index 1494f83bdbc..e19f1f4b063 100644 --- a/core-services/egov-hrms/src/main/java/org/egov/hrms/web/validator/EmployeeValidator.java +++ b/core-services/egov-hrms/src/main/java/org/egov/hrms/web/validator/EmployeeValidator.java @@ -1,17 +1,32 @@ package org.egov.hrms.web.validator; -import java.util.*; -import java.util.stream.Collectors; import java.time.ZoneId; import java.time.temporal.ChronoUnit; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import com.jayway.jsonpath.JsonPath; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.contract.request.Role; import org.egov.hrms.config.PropertiesManager; -import org.egov.hrms.model.*; +import org.egov.hrms.model.Assignment; +import org.egov.hrms.model.DeactivationDetails; +import org.egov.hrms.model.DepartmentalTest; +import org.egov.hrms.model.EducationalQualification; +import org.egov.hrms.model.Employee; +import org.egov.hrms.model.Jurisdiction; +import org.egov.hrms.model.ReactivationDetails; +import org.egov.hrms.model.ServiceHistory; +import org.egov.hrms.repository.RestCallRepository; import org.egov.hrms.service.EmployeeService; import org.egov.hrms.service.MDMSService; import org.egov.hrms.service.UserService; @@ -22,14 +37,13 @@ import org.egov.hrms.web.contract.EmployeeResponse; import org.egov.hrms.web.contract.EmployeeSearchCriteria; import org.egov.hrms.web.contract.UserResponse; +import org.egov.hrms.web.models.boundary.BoundaryResponse; import org.egov.mdms.model.MdmsResponse; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; -import lombok.extern.slf4j.Slf4j; - import static org.egov.hrms.utils.ErrorConstants.CITIZEN_TYPE_CODE; @Service @@ -51,6 +65,9 @@ public class EmployeeValidator { @Autowired private HRMSUtils hrmsUtils; + @Autowired + private RestCallRepository restCallRepository; + /** * Validates employee request for create. Validations include: * 1. Validating MDMS codes @@ -65,6 +82,7 @@ public void validateCreateEmployee(EmployeeRequest request) { if(!CollectionUtils.isEmpty(errorMap.keySet())) throw new CustomException(errorMap); Map> boundaryMap = getBoundaryList(request.getRequestInfo(),request.getEmployees().get(0)); + //FIXME hierarchy type has to be validated Map> mdmsData = mdmsService.getMDMSData(request.getRequestInfo(), request.getEmployees().get(0).getTenantId()); if(!CollectionUtils.isEmpty(mdmsData.keySet())){ request.getEmployees().stream().forEach(employee -> validateMdmsData(employee, errorMap, mdmsData,boundaryMap)); @@ -97,25 +115,42 @@ public Map> getBoundaryList(RequestInfo requestInfo,Employe } List boundaryResponseList = new ArrayList<>(); - for(String boundary: boundarytList){ - MdmsResponse responseLoc = mdmsService.fetchMDMSDataLoc(requestInfo, boundary); - if(!CollectionUtils.isEmpty(responseLoc.getMdmsRes())) - boundaryResponseList.add(responseLoc); - } - - if(!CollectionUtils.isEmpty(boundaryResponseList)){ - List tenantBoundaryData = new ArrayList<>(); - for(MdmsResponse responseLoc : boundaryResponseList){ - if(!CollectionUtils.isEmpty(responseLoc.getMdmsRes().keySet())) { - if(null != responseLoc.getMdmsRes().get(HRMSConstants.HRMS_MDMS_EGOV_LOCATION_MASTERS_CODE)) { - eachMasterMap = (Map) responseLoc.getMdmsRes().get(HRMSConstants.HRMS_MDMS_EGOV_LOCATION_MASTERS_CODE); - tenantBoundaryData.addAll(eachMasterMap.get(HRMSConstants.HRMS_MDMS_TENANT_BOUNDARY_CODE)); - } - } +// for(String boundary: boundarytList){ +// MdmsResponse responseLoc = mdmsService.fetchMDMSDataLoc(requestInfo, boundary); +// BoundaryResponse boundarySearchResponse = serviceRequestClient.fetchResult( +// new StringBuilder(propertiesManager.getBoundaryServiceHost() +// + propertiesManager.getBoundarySearchUrl() +// +"?limit=" + boundaries.size() +// + "&offset=0&tenantId=" + tenantId +// + "&codes=" + String.join(",", boundaries)), +// request.getRequestInfo(), +// BoundaryResponse.class +// ); +// if(!CollectionUtils.isEmpty(responseLoc.getMdmsRes())) +// boundaryResponseList.add(responseLoc); +// } + + if(!CollectionUtils.isEmpty(boundarytList)) { + try { + BoundaryResponse boundarySearchResponse = restCallRepository.fetchResult( + new StringBuilder(propertiesManager.getBoundaryServiceHost() + + propertiesManager.getBoundarySearchUrl() + +"?limit=" + boundarytList.size() + + "&offset=0&tenantId=" + employee.getTenantId() + + "&codes=" + String.join(",", boundarytList)), + requestInfo, + BoundaryResponse.class + ); + masterData.put(HRMSConstants.HRMS_MDMS_TENANT_BOUNDARY_CODE, boundarySearchResponse.getBoundary().stream() + .map(boundary -> boundary.getCode()) + .collect(Collectors.toList()) + ); + log.info("successfully fetch boundary"); + } catch (Exception e) { + log.error("error while fetching boundary"); } - if(!CollectionUtils.isEmpty(tenantBoundaryData)) - masterData.put(HRMSConstants.HRMS_MDMS_TENANT_BOUNDARY_CODE,tenantBoundaryData); } + return masterData; } @@ -223,6 +258,7 @@ private void validateUserMobile(List employees, Map er else mobileNos.add(employee.getUser().getMobileNumber()); Map userSearchCriteria = new HashMap<>(); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE_CODE, HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE); userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID,employee.getTenantId()); userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_MOBILENO,employee.getUser().getMobileNumber()); UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); @@ -254,6 +290,7 @@ private void validateUserName(List employees, Map erro employees.forEach(employee -> { if(!StringUtils.isEmpty(employee.getCode())){ Map userSearchCriteria = new HashMap<>(); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE_CODE, HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE); userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID,employee.getTenantId()); userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_USERNAME,employee.getCode()); UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); @@ -276,7 +313,7 @@ private void validateMdmsData(Employee employee, Map errorMap, M validateEmployee(employee, errorMap, mdmsData); validateAssignments(employee, errorMap, mdmsData); validateServiceHistory(employee, errorMap, mdmsData); - validateJurisdicton(employee, errorMap, mdmsData, boundaryMap); +// validateJurisdicton(employee, errorMap, mdmsData, boundaryMap); validateEducationalDetails(employee, errorMap, mdmsData); validateDepartmentalTest(employee, errorMap, mdmsData); } @@ -317,6 +354,7 @@ private void validateUserData(Employee existingEmp, Employee employee, Map userSearchCriteria = new HashMap<>(); + userSearchCriteria.put(HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE_CODE, HRMSConstants.HRMS_USER_SERACH_CRITERIA_USERTYPE); userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_TENANTID,employee.getTenantId()); userSearchCriteria.put(HRMSConstants.HRMS_USER_SEARCH_CRITERA_MOBILENO,employee.getUser().getMobileNumber()); UserResponse userResponse = userService.getUser(requestInfo, userSearchCriteria); diff --git a/core-services/egov-hrms/src/main/resources/application.properties b/core-services/egov-hrms/src/main/resources/application.properties index ece32eba711..dcece925352 100644 --- a/core-services/egov-hrms/src/main/resources/application.properties +++ b/core-services/egov-hrms/src/main/resources/application.properties @@ -115,4 +115,9 @@ log4j.logger.org.springframework.jdbc.core = TRACE state.level.tenant.id=default -egov.hrms.auto.generate.password=true \ No newline at end of file +egov.hrms.auto.generate.password=true + +# BOUNDARY SERVICE +egov.boundary.host=http://localhost:8081 +egov.boundary.search.url=/boundary-service/boundary/_search +egov.boundary.hierarchy=HCM-Moz-Hierarchy \ No newline at end of file diff --git a/docs/health-api-specs/contracts/project.yml b/docs/health-api-specs/contracts/project.yml index d35c7ffcd4d..7f61b66324e 100644 --- a/docs/health-api-specs/contracts/project.yml +++ b/docs/health-api-specs/contracts/project.yml @@ -1438,12 +1438,16 @@ definitions: clientReferenceId: $ref: '#/definitions/clientReferenceIdForSearch' projectId: - type: string + type: array + items: + type: string minLength: 2 maxLength: 64 description: Unique ID form Project beneficiaryId: - type: string + type: array + items: + type: string minLength: 2 maxLength: 64 description: Unique ID of Household/Individual being added as beneficiary @@ -1533,13 +1537,17 @@ definitions: clientReferenceId: $ref: '#/definitions/clientReferenceIdForSearch' projectId: - type: string + type: array + items: + type: string minLength: 2 maxLength: 64 description: Unique ProjectId projectBeneficiaryId: - type: string - example: "R-ID-1" + type: array + items: + type: string + example: "R-ID-1" plannedStartDate: type: integer format: int64 @@ -1622,12 +1630,16 @@ definitions: id: $ref: '#/definitions/idForSearch' staffId: - type: string + type: array + items: + type: string description: Unique userId defined using user service minLength: 2 maxLength: 64 projectId: - type: string + type: array + items: + type: string description: Project Id minLength: 2 maxLength: 64 @@ -1730,7 +1742,9 @@ definitions: id: $ref: '#/definitions/idForSearch' projectId: - type: string + type: array + items: + type: string description: Unique Project Id defined in Project Service minLength: 2 maxLength: 64 diff --git a/docs/health-api-specs/contracts/referral-management.yml b/docs/health-api-specs/contracts/referral-management.yml index e4e27851241..af73191c0e1 100644 --- a/docs/health-api-specs/contracts/referral-management.yml +++ b/docs/health-api-specs/contracts/referral-management.yml @@ -542,13 +542,17 @@ definitions: clientReferenceId: $ref: '#/definitions/clientReferenceIdForSearch' taskId: - type: string + type: array + items: + type: string minLength: 2 maxLength: 64 description: Unique TaskId taskClientReferenceId: - type: string - example: R-ID-1 + type: array + items: + type: string + example: R-ID-1 SideEffectSearchRequest: type: object properties: @@ -671,6 +675,24 @@ definitions: type: array items: type: string + sideEffectId: + type: array + items: + type: string + sideEffectClientReferenceId: + type: array + items: + type: string + referrerId: + type: array + items: + type: string + recipientId: + type: array + items: + type: string + + ReferralSearchRequest: type: object properties: diff --git a/docs/health-api-specs/contracts/registries/individual.yml b/docs/health-api-specs/contracts/registries/individual.yml index dffb103da1b..8fce191f8c4 100644 --- a/docs/health-api-specs/contracts/registries/individual.yml +++ b/docs/health-api-specs/contracts/registries/individual.yml @@ -448,7 +448,10 @@ definitions: type: object properties: individualId: - $ref: '#/definitions/individualId' +# $ref: '#/definitions/individualId' + type: array + items: + type: string id: $ref: '#/definitions/idForSearch' clientReferenceId: @@ -460,9 +463,12 @@ definitions: gender: $ref: '#/definitions/gender' mobileNumber: - type: string + type: array + items: + type: string + maxLength: 20 description: Mobile number of the user - maxLength: 20 + socialCategory: type: string description: Social category of the user diff --git a/docs/health-api-specs/contracts/registries/product.yml b/docs/health-api-specs/contracts/registries/product.yml index f99aff159ae..7b5c6fe903b 100644 --- a/docs/health-api-specs/contracts/registries/product.yml +++ b/docs/health-api-specs/contracts/registries/product.yml @@ -311,13 +311,19 @@ definitions: description: Define the type of product example: 'DRUG' name: - type: string + type: array + items: + type: string + example: Paracetamol description: Capture name of the product - example: Paracetamol + manufacturer: - type: string + type: array + items: + type: string + example: 'J&J' description: Capture manufacturer of product - example: 'J&J' + ProductVariant: type: object @@ -368,9 +374,11 @@ definitions: id: $ref: '#/definitions/idForSearch' productId: - type: string - minLength: 2 - maxLength: 64 + type: array + items: + type: string + minLength: 2 + maxLength: 64 description: Product for which this variant is being created sku: type: string diff --git a/docs/health-api-specs/contracts/stock.yml b/docs/health-api-specs/contracts/stock.yml index 2ee5512df51..f3f513188f0 100644 --- a/docs/health-api-specs/contracts/stock.yml +++ b/docs/health-api-specs/contracts/stock.yml @@ -589,7 +589,10 @@ definitions: facilityId: $ref: '#/definitions/facilityId' productVariantId: - $ref: '#/definitions/productVariantId' +# $ref: '#/definitions/productVariantId' + type: array + items: + type: string referenceId: $ref: '#/definitions/referenceId' referenceIdType: @@ -603,8 +606,10 @@ definitions: transactingPartyType: $ref: '#/definitions/transactingPartyType' wayBillNumber: - $ref: '#/definitions/wayBillNumber' - +# $ref: '#/definitions/wayBillNumber' + type: array + items: + type: string StockReconciliation: type: object required: @@ -657,9 +662,16 @@ definitions: clientReferenceId: $ref: '#/definitions/clientReferenceIdForSearch' facilityId: - $ref: '#/definitions/facilityId' +# $ref: '#/definitions/facilityId' + type: array + items: + type: string + example: FacilityA productVariantId: - $ref: '#/definitions/productVariantId' +# $ref: '#/definitions/productVariantId' + type: array + items: + type: string StockRequest: diff --git a/health-services/facility/CHANGELOG.md b/health-services/facility/CHANGELOG.md index 645e12b40e1..7d61aeac33a 100644 --- a/health-services/facility/CHANGELOG.md +++ b/health-services/facility/CHANGELOG.md @@ -1,7 +1,12 @@ All notable changes to this module will be documented in this file. +## 1.1.2 - 2024-05-29 +- Integrated Core 2.9LTS +- Upgraded to health models 1.0.20 and health common 1.0.16 +- Integrated Boundary v2 functionality + ## 1.0.0 - Base version -## 1.1.0 \ No newline at end of file +## 1.1.0 diff --git a/health-services/facility/pom.xml b/health-services/facility/pom.xml index 586f4742499..c714a29de25 100644 --- a/health-services/facility/pom.xml +++ b/health-services/facility/pom.xml @@ -5,16 +5,17 @@ facility jar facility - 1.1.0 + 1.1.2 - 1.8 + 17 ${java.version} ${java.version} + 1.18.22 org.springframework.boot spring-boot-starter-parent - 2.2.6.RELEASE + 3.2.2 src/main/java @@ -44,27 +45,18 @@ org.egov.common health-services-common - 1.0.8-SNAPSHOT + 1.0.16-SNAPSHOT org.egov.common health-services-models - 1.0.7-SNAPSHOT + 1.0.20-SNAPSHOT compile - org.springframework.boot - spring-boot-starter-data-redis - - - io.lettuce - lettuce-core - - - - - redis.clients - jedis + org.egov.services + tracer + 2.9.0-SNAPSHOT org.flywaydb @@ -90,17 +82,24 @@ org.projectlombok lombok + ${lombok.version} true - - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 + junit + junit + 4.13.2 + test + + + jakarta.validation + jakarta.validation-api + 3.0.2 + compile - - javax.validation - validation-api + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 diff --git a/health-services/facility/src/main/java/org/egov/facility/config/FacilityConfiguration.java b/health-services/facility/src/main/java/org/egov/facility/config/FacilityConfiguration.java index 503f83b2f32..d92cf5b04b7 100644 --- a/health-services/facility/src/main/java/org/egov/facility/config/FacilityConfiguration.java +++ b/health-services/facility/src/main/java/org/egov/facility/config/FacilityConfiguration.java @@ -35,4 +35,10 @@ public class FacilityConfiguration { @Value("${facility.idgen.id.format}") private String facilityIdFormat; + + @Value("${egov.boundary.host}") + private String boundaryServiceHost; + + @Value("${egov.boundary.search.url}") + private String boundarySearchUrl; } diff --git a/health-services/facility/src/main/java/org/egov/facility/config/MainConfiguration.java b/health-services/facility/src/main/java/org/egov/facility/config/MainConfiguration.java index 34cf8965b63..0c88de6e214 100644 --- a/health-services/facility/src/main/java/org/egov/facility/config/MainConfiguration.java +++ b/health-services/facility/src/main/java/org/egov/facility/config/MainConfiguration.java @@ -22,7 +22,7 @@ import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import java.util.TimeZone; @Import({TracerConfiguration.class}) @Configuration diff --git a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java index 4ab51ba5ed3..3517293adcf 100644 --- a/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java +++ b/health-services/facility/src/main/java/org/egov/facility/repository/rowmapper/FacilityRowMapper.java @@ -1,19 +1,19 @@ package org.egov.facility.repository.rowmapper; +import java.sql.ResultSet; +import java.sql.SQLException; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.facility.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.facility.Address; import org.egov.common.models.facility.AddressType; -import org.egov.common.models.facility.Boundary; +import org.egov.common.models.core.Boundary; import org.egov.common.models.facility.Facility; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; -import java.sql.ResultSet; -import java.sql.SQLException; - @Component public class FacilityRowMapper implements RowMapper { diff --git a/health-services/facility/src/main/java/org/egov/facility/service/FacilityService.java b/health-services/facility/src/main/java/org/egov/facility/service/FacilityService.java index 9f40852ecdf..04cf66e5760 100644 --- a/health-services/facility/src/main/java/org/egov/facility/service/FacilityService.java +++ b/health-services/facility/src/main/java/org/egov/facility/service/FacilityService.java @@ -11,6 +11,7 @@ import org.egov.facility.config.FacilityConfiguration; import org.egov.facility.repository.FacilityRepository; import org.egov.facility.service.enrichment.FacilityEnrichmentService; +import org.egov.facility.validator.FBoundaryValidator; import org.egov.facility.validator.FIsDeletedValidator; import org.egov.facility.validator.FNonExistentValidator; import org.egov.facility.validator.FNullIdValidator; @@ -52,12 +53,16 @@ public class FacilityService { private final FacilityEnrichmentService enrichmentService; + private final Predicate> isApplicableForCreate = + validator -> validator.getClass().equals(FBoundaryValidator.class); + private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(FIsDeletedValidator.class) - || validator.getClass().equals(FNonExistentValidator.class) - || validator.getClass().equals(FNullIdValidator.class) - || validator.getClass().equals(FRowVersionValidator.class) - || validator.getClass().equals(FUniqueEntityValidator.class); + || validator.getClass().equals(FBoundaryValidator.class) + || validator.getClass().equals(FNonExistentValidator.class) + || validator.getClass().equals(FNullIdValidator.class) + || validator.getClass().equals(FRowVersionValidator.class) + || validator.getClass().equals(FUniqueEntityValidator.class); private final Predicate> isApplicableForDelete = validator -> validator.getClass().equals(FNonExistentValidator.class) @@ -83,9 +88,12 @@ public Facility create(FacilityRequest request) { public List create(FacilityBulkRequest request, boolean isBulk) { log.info("starting create method for facility"); - Map errorDetailsMap = new HashMap<>(); - List validEntities = request.getFacilities(); + Tuple, Map> tuple = validate(validators, + isApplicableForCreate, request, SET_FACILITIES, GET_FACILITIES, VALIDATION_ERROR, + isBulk); + Map errorDetailsMap = tuple.getY(); + List validEntities = tuple.getX(); try { if (!validEntities.isEmpty()) { log.info("processing {} valid entities", validEntities.size()); diff --git a/health-services/facility/src/main/java/org/egov/facility/validator/FBoundaryValidator.java b/health-services/facility/src/main/java/org/egov/facility/validator/FBoundaryValidator.java new file mode 100644 index 00000000000..dc0dc2b157d --- /dev/null +++ b/health-services/facility/src/main/java/org/egov/facility/validator/FBoundaryValidator.java @@ -0,0 +1,127 @@ +package org.egov.facility.validator; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.core.Boundary; +import org.egov.common.models.facility.Facility; +import org.egov.common.models.facility.FacilityBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.facility.config.FacilityConfiguration; +import org.egov.facility.web.models.boundary.BoundaryResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +/** + * Validator class for validating facility boundaries. + */ +@Component +@Order(value = 4) +@Slf4j +public class FBoundaryValidator implements Validator { + + private final ServiceRequestClient serviceRequestClient; + + private final FacilityConfiguration facilityConfiguration; + + /** + * Constructor to initialize the HBoundaryValidator. + * + * @param serviceRequestClient Service request client for making HTTP requests + * @param facilityConfiguration Configuration properties for the facility module + */ + public FBoundaryValidator(ServiceRequestClient serviceRequestClient, FacilityConfiguration facilityConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.facilityConfiguration = facilityConfiguration; + } + + /** + * Validates the facilities' boundaries. + * + * @param request the bulk request containing facilities + * @return a map containing facilities with their corresponding list of errors + */ + @Override + public Map> validate(FacilityBulkRequest request) { + log.debug("Validating facilities boundaries."); + // Create a HashMap to store error details for each facility + HashMap> errorDetailsMap = new HashMap<>(); + + // Filter facilities with non-null addresses + List entitiesWithValidBoundaries = request.getFacilities().parallelStream() + .filter(facility -> Objects.nonNull(facility.getAddress())) + .filter(facility -> Objects.nonNull(facility.getAddress().getLocality())) // Exclude null locality codes + .collect(Collectors.toList()); + + Map> tenantIdFacilityMap = entitiesWithValidBoundaries.stream().collect(Collectors.groupingBy(Facility::getTenantId)); + + tenantIdFacilityMap.forEach((tenantId, facilities) -> { + // Group facilities by locality code + Map> boundaryCodeFacilitysMap = facilities.stream() + .collect(Collectors.groupingBy( + facility -> facility.getAddress().getLocality().getCode() // Group by locality code + )); + + List boundaries = new ArrayList<>(boundaryCodeFacilitysMap.keySet()); + if(!CollectionUtils.isEmpty(boundaries)) { + try { + // Fetch boundary details from the service + log.debug("Fetching boundary details for tenantId: {}, boundaries: {}", tenantId, boundaries); + BoundaryResponse boundarySearchResponse = serviceRequestClient.fetchResult( + new StringBuilder(facilityConfiguration.getBoundaryServiceHost() + + facilityConfiguration.getBoundarySearchUrl() + +"?limit=" + boundaries.size() + + "&offset=0&tenantId=" + tenantId + + "&codes=" + String.join(",", boundaries)), + request.getRequestInfo(), + BoundaryResponse.class + ); + log.debug("Boundary details fetched successfully for tenantId: {}", tenantId); + + List invalidBoundaryCodes = new ArrayList<>(boundaries); + invalidBoundaryCodes.removeAll(boundarySearchResponse.getBoundary().stream() + .map(Boundary::getCode) + .collect(Collectors.toList()) + ); + + // Filter out facilities with invalid boundary codes + List facilitiesWithInvalidBoundaries = boundaryCodeFacilitysMap.entrySet().stream() + .filter(entry -> invalidBoundaryCodes.contains(entry.getKey())) // filter invalid boundary codes + .flatMap(entry -> entry.getValue().stream()) // Flatten the list of facilities + .collect(Collectors.toList()); + + + facilitiesWithInvalidBoundaries.forEach(facility -> { + // Create an error object for facilities with invalid boundaries + Error error = Error.builder() + .errorMessage("Boundary code does not exist in db") + .errorCode("NON_EXISTENT_ENTITY") + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException("NON_EXISTENT_ENTITY", "Boundary code does not exist in db")) + .build(); + // Populate error details for the facility + populateErrorDetails(facility, error, errorDetailsMap); + }); + + } catch (Exception e) { + log.error("Exception while searching boundaries for tenantId: {}", tenantId, e); + // Throw a custom exception if an error occurs during boundary search + throw new CustomException("BOUNDARY_SEARCH_ERROR", e.getMessage()); + } + } + }); + + return errorDetailsMap; + } +} diff --git a/health-services/facility/src/main/java/org/egov/facility/web/controllers/FacilityApiController.java b/health-services/facility/src/main/java/org/egov/facility/web/controllers/FacilityApiController.java index c7db346d9a6..3ca37071ca8 100644 --- a/health-services/facility/src/main/java/org/egov/facility/web/controllers/FacilityApiController.java +++ b/health-services/facility/src/main/java/org/egov/facility/web/controllers/FacilityApiController.java @@ -1,9 +1,14 @@ package org.egov.facility.web.controllers; +import java.util.List; + import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.URLParams; import org.egov.common.models.facility.Facility; import org.egov.common.models.facility.FacilityBulkRequest; import org.egov.common.models.facility.FacilityBulkResponse; @@ -18,19 +23,10 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; - -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import java.util.List; - -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") @Controller @RequestMapping("") @@ -111,11 +107,17 @@ public ResponseEntity facilityV1DeletePost(@ApiParam(value = " } @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) - public ResponseEntity facilityV1SearchPost(@ApiParam(value = "Details for existing facility.", required = true) @Valid @RequestBody FacilitySearchRequest request, @NotNull - @Min(0) - @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, @NotNull - @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { - List facilities = facilityService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); + public ResponseEntity facilityV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Details for existing facility.", required = true) @Valid @RequestBody FacilitySearchRequest request + ) throws Exception { + List facilities = facilityService.search( + request, + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted()); FacilityBulkResponse response = FacilityBulkResponse.builder().responseInfo(ResponseInfoFactory .createResponseInfo(request.getRequestInfo(), true)).facilities(facilities).build(); diff --git a/health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundaryRequest.java b/health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundaryRequest.java new file mode 100644 index 00000000000..78efab9d986 --- /dev/null +++ b/health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundaryRequest.java @@ -0,0 +1,38 @@ +package org.egov.facility.web.models.boundary; + +import java.util.List; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.Boundary; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryRequest + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @Valid + @NotNull + @JsonProperty("Boundary") + @Size(min = 1, max = 300) + private List boundary = null; + +} diff --git a/health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundaryResponse.java b/health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundaryResponse.java new file mode 100644 index 00000000000..a05cd2437cd --- /dev/null +++ b/health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundaryResponse.java @@ -0,0 +1,44 @@ +package org.egov.facility.web.models.boundary; + +import java.util.ArrayList; +import java.util.List; +import jakarta.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.Boundary; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryResponse + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Boundary") + @Valid + private List boundary = null; + + + public BoundaryResponse addBoundaryItem(Boundary boundaryItem) { + if (this.boundary == null) { + this.boundary = new ArrayList<>(); + } + this.boundary.add(boundaryItem); + return this; + } + +} diff --git a/health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundarySearchCriteria.java b/health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundarySearchCriteria.java new file mode 100644 index 00000000000..6f2780fa4c9 --- /dev/null +++ b/health-services/facility/src/main/java/org/egov/facility/web/models/boundary/BoundarySearchCriteria.java @@ -0,0 +1,37 @@ +package org.egov.facility.web.models.boundary; + +import java.util.List; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundarySearchCriteria { + + @NotNull + @Size(min = 1) + @JsonProperty("codes") + private List codes; + + @NotNull + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} diff --git a/health-services/facility/src/main/resources/application.properties b/health-services/facility/src/main/resources/application.properties index 6e8b6a05ae0..f25c5a93406 100644 --- a/health-services/facility/src/main/resources/application.properties +++ b/health-services/facility/src/main/resources/application.properties @@ -80,3 +80,9 @@ facility.consumer.bulk.update.topic=update-facility-bulk-topic facility.kafka.create.topic=save-facility-topic facility.kafka.update.topic=update-facility-topic facility.kafka.delete.topic=delete-facility-topic + + +# BOUNDARY SERVICE +egov.boundary.host=http://localhost:8081 +egov.boundary.search.url=/boundary-service/boundary/_search +egov.boundary.hierarchy=HCM-Moz-Hierarchy diff --git a/health-services/facility/src/test/java/org/egov/facility/helper/FacilityTestBuilder.java b/health-services/facility/src/test/java/org/egov/facility/helper/FacilityTestBuilder.java index 8b4b27934fe..3a9eb405169 100644 --- a/health-services/facility/src/test/java/org/egov/facility/helper/FacilityTestBuilder.java +++ b/health-services/facility/src/test/java/org/egov/facility/helper/FacilityTestBuilder.java @@ -7,10 +7,10 @@ public class FacilityTestBuilder { - private final Facility.FacilityBuilder builder; + private final Facility.FacilityBuilder builder; public FacilityTestBuilder() { - this.builder = Facility.builder(); + this.builder = (Facility.FacilityBuilder) Facility.builder(); } public static FacilityTestBuilder builder() { diff --git a/health-services/household/CHANGELOG.md b/health-services/household/CHANGELOG.md index 0cb9052cea7..b5b4a01a43a 100644 --- a/health-services/household/CHANGELOG.md +++ b/health-services/household/CHANGELOG.md @@ -1,5 +1,15 @@ All notable changes to this module will be documented in this file. +## 1.1.3 - 2024-05-29 +- Integrated Core 2.9LTS +- Client reference ID validation added +- Upgraded to health models 1.0.20 and health common 1.0.16 +- Boundary v2 Integration +- MDMS v2 integration + +## 1.1.2 - 2024-05-10 +- Integrated Boundary v2 functionality +- ## 1.1.1 - 2023-11-15 - Added total count for household diff --git a/health-services/household/README.md b/health-services/household/README.md index a448bda922e..6041a0ccde0 100644 --- a/health-services/household/README.md +++ b/health-services/household/README.md @@ -79,3 +79,11 @@ Household service APIs - contains create, update, delete and search end point ## Pre commit script [commit-msg](https://gist.github.com/jayantp-egov/14f55deb344f1648503c6be7e580fa12) + +## Updates +- Household Member Search + - `householdId`, `householdClientReferenceId`, `individualId`, and `individualClientReferenceId` now accepts a list of entities instead of single entity to search household member +## Usage +- Start the service +- Access the API endpoints for searching `household member` +- Pass list parameters for the search fields mentioned in updates \ No newline at end of file diff --git a/health-services/household/pom.xml b/health-services/household/pom.xml index 415101499df..25aa6b469a5 100644 --- a/health-services/household/pom.xml +++ b/health-services/household/pom.xml @@ -5,16 +5,17 @@ household jar household - 1.1.1 + 1.1.3 - 1.8 + 17 ${java.version} ${java.version} + 1.18.22 org.springframework.boot spring-boot-starter-parent - 2.2.6.RELEASE + 3.2.2 src/main/java @@ -44,28 +45,40 @@ org.egov.common health-services-common - 1.0.8-SNAPSHOT + 1.0.16-SNAPSHOT org.egov.common health-services-models - 1.0.11-SNAPSHOT + 1.0.20-SNAPSHOT compile org.flywaydb flyway-core + 9.22.3 org.postgresql postgresql - 42.2.2.jre7 + 42.7.1 + + + org.egov.services + tracer + 2.9.0-SNAPSHOT org.springframework.boot spring-boot-starter-test test + + junit + junit + 4.13.2 + test + io.swagger swagger-core @@ -75,6 +88,7 @@ org.projectlombok lombok + ${lombok.version} true @@ -82,11 +96,6 @@ com.fasterxml.jackson.datatype jackson-datatype-jsr310 - - - javax.validation - validation-api - diff --git a/health-services/household/src/main/java/org/egov/household/Constants.java b/health-services/household/src/main/java/org/egov/household/Constants.java index c32122f155f..da512e39234 100644 --- a/health-services/household/src/main/java/org/egov/household/Constants.java +++ b/health-services/household/src/main/java/org/egov/household/Constants.java @@ -5,6 +5,8 @@ public interface Constants { String GET_ID = "getId"; + String GET_CLIENT_REFERENCE_ID = "getClientReferenceId"; + String GET_INDIVIDUAL_ID = "getIndividualId"; String GET_INDIVIDUAL_CLIENT_REFERENCE_ID = "getIndividualClientReferenceId"; diff --git a/health-services/household/src/main/java/org/egov/household/config/HouseholdConfiguration.java b/health-services/household/src/main/java/org/egov/household/config/HouseholdConfiguration.java index 889b1393141..c906d52786f 100644 --- a/health-services/household/src/main/java/org/egov/household/config/HouseholdConfiguration.java +++ b/health-services/household/src/main/java/org/egov/household/config/HouseholdConfiguration.java @@ -37,4 +37,9 @@ public class HouseholdConfiguration { @Value("${household.idgen.id.format}") private String idgenFormat; + @Value("${egov.boundary.host}") + private String boundaryServiceHost; + + @Value("${egov.boundary.search.url}") + private String boundarySearchUrl; } diff --git a/health-services/household/src/main/java/org/egov/household/config/MainConfiguration.java b/health-services/household/src/main/java/org/egov/household/config/MainConfiguration.java index c04b49176dd..edfc34ac8d6 100644 --- a/health-services/household/src/main/java/org/egov/household/config/MainConfiguration.java +++ b/health-services/household/src/main/java/org/egov/household/config/MainConfiguration.java @@ -22,7 +22,7 @@ import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import java.util.TimeZone; @Import({TracerConfiguration.class}) @Configuration diff --git a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmExistentEntityValidator.java b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmExistentEntityValidator.java new file mode 100644 index 00000000000..609001e7c71 --- /dev/null +++ b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmExistentEntityValidator.java @@ -0,0 +1,77 @@ +package org.egov.household.household.member.validators; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.common.models.Error; +import org.egov.common.models.household.HouseholdMember; +import org.egov.common.models.household.HouseholdMemberBulkRequest; +import org.egov.common.models.household.HouseholdMemberSearch; +import org.egov.common.validator.Validator; +import org.egov.household.repository.HouseholdMemberRepository; +import org.springframework.util.CollectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of entities with the given client reference IDs. + * This validator checks if the provided HouseholdMember entities already exist in the database based on their client reference IDs. + * + * @author kanishq-egov + */ +public class HmExistentEntityValidator implements Validator { + + private final HouseholdMemberRepository householdMemberRepository; + + /** + * Constructor to initialize the HouseholdMemberRepository dependency. + * + * @param householdMemberRepository The repository for HouseholdMember entities. + */ + public HmExistentEntityValidator(HouseholdMemberRepository householdMemberRepository) { + this.householdMemberRepository = householdMemberRepository; + } + + /** + * Validates the existence of entities with the given client reference IDs. + * + * @param request The bulk request containing HouseholdMember entities. + * @return A map containing HouseholdMember entities and their associated error details. + */ + @Override + public Map> validate(HouseholdMemberBulkRequest request) { + // Map to hold HouseholdMember entities and their error details + Map> errorDetailsMap = new HashMap<>(); + // Get the list of HouseholdMember entities from the request + List entities = request.getHouseholdMembers(); + // Extract client reference IDs from HouseholdMember entities without errors + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) + .map(HouseholdMember::getClientReferenceId) + .collect(Collectors.toList()); + // Create a search object for querying entities by client reference IDs + HouseholdMemberSearch householdSearch = HouseholdMemberSearch.builder() + .clientReferenceId(clientReferenceIdList) + .build(); + // Check if the client reference ID list is not empty + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing entities by client reference IDs + List existentEntities = householdMemberRepository.findById( + clientReferenceIdList, + getIdFieldName(householdSearch), + Boolean.FALSE).getResponse(); + // For each existing entity, populate error details for uniqueness + existentEntities.forEach(entity -> { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(entity, error, errorDetailsMap); + }); + } + return errorDetailsMap; + } + +} diff --git a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmHouseholdHeadValidator.java b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmHouseholdHeadValidator.java index 6196b6328f4..09999669c9e 100644 --- a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmHouseholdHeadValidator.java +++ b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmHouseholdHeadValidator.java @@ -70,7 +70,7 @@ private void validateHeadOfHousehold(HouseholdMember householdMember, Method idM log.info("validating if household already has a head"); List householdMembersHeadCheck = householdMemberRepository .findIndividualByHousehold((String) ReflectionUtils.invokeMethod(idMethod, householdMember), - columnName).stream().filter(HouseholdMember::getIsHeadOfHousehold) + columnName).getResponse().stream().filter(HouseholdMember::getIsHeadOfHousehold) .collect(Collectors.toList()); if(!householdMembersHeadCheck.isEmpty()){ diff --git a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmHouseholdValidator.java b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmHouseholdValidator.java index ad9e9c81e84..6c97049b779 100644 --- a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmHouseholdValidator.java +++ b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmHouseholdValidator.java @@ -53,7 +53,7 @@ public Map> validate(HouseholdMemberBulkRequest hou List houseHoldIds = getIdList(householdMembers, idMethod); log.info("finding valid household ids from household service"); - List validHouseHoldIds = householdService.findById(houseHoldIds, columnName, false).getY(); + List validHouseHoldIds = householdService.findById(houseHoldIds, columnName, false).getResponse(); log.info("getting unique household ids from valid household ids"); Set uniqueHoldIds = getSet(validHouseHoldIds, columnName == "id" ? "getId": "getClientReferenceId"); diff --git a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmNonExistentEntityValidator.java b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmNonExistentEntityValidator.java index ee740ccab6e..e7b195dd694 100644 --- a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmNonExistentEntityValidator.java +++ b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmNonExistentEntityValidator.java @@ -1,22 +1,25 @@ package org.egov.household.household.member.validators; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; +import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdMember; import org.egov.common.models.household.HouseholdMemberBulkRequest; +import org.egov.common.models.household.HouseholdMemberSearch; +import org.egov.common.models.household.HouseholdSearch; import org.egov.common.validator.Validator; import org.egov.household.repository.HouseholdMemberRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.getIdToObjMap; @@ -27,6 +30,11 @@ import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; import static org.egov.household.Constants.GET_ID; +/** + * Validator class for checking the non-existence of household members. + * This validator checks if the provided household members do not already exist in the database. + * @author kanishq-egov + */ @Component @Order(value = 4) @Slf4j @@ -34,33 +42,78 @@ public class HmNonExistentEntityValidator implements Validator> validate(HouseholdMemberBulkRequest request) { + // Map to hold household members and their error details Map> errorDetailsMap = new HashMap<>(); + // Get the list of household members from the request List householdMembers = request.getHouseholdMembers(); - log.info("validating non existent household member"); + // Log message for validation process + log.info("Validating non-existent household members"); + // Get class and method information for ID retrieval Class objClass = getObjClass(householdMembers); Method idMethod = getMethod(GET_ID, objClass); + // Create a map of household members with their IDs as keys Map iMap = getIdToObjMap(householdMembers .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + // Check if the map is not empty + + // Lists to store IDs and client reference IDs + List idList = new ArrayList<>(); + List clientReferenceIdList = new ArrayList<>(); + // Extract IDs and client reference IDs from household entities + householdMembers.forEach(householdMember -> { + idList.add(householdMember.getId()); + clientReferenceIdList.add(householdMember.getClientReferenceId()); + }); + if (!iMap.isEmpty()) { + // Extract IDs from the map List householdMemberIds = new ArrayList<>(iMap.keySet()); - List existingHouseholdMembers = householdMemberRepository.findById(householdMemberIds, - getIdFieldName(idMethod), false); + // Create a search object for querying existing entities + HouseholdMemberSearch householdMemberSearch = HouseholdMemberSearch.builder() + .clientReferenceId(clientReferenceIdList) + .id(idList) + .build(); + + List existingHouseholdMembers; + try { + // Query the repository to find existing entities + existingHouseholdMembers = householdMemberRepository.find(householdMemberSearch, householdMembers.size(), 0, + householdMembers.get(0).getTenantId(), null, false).getResponse(); + } catch (Exception e) { + // Handle query builder exception + throw new RuntimeException(e); + } + + // Check for non-existent household members List nonExistentIndividuals = checkNonExistentEntities(iMap, existingHouseholdMembers, idMethod); + // For each non-existent household member, populate error details nonExistentIndividuals.forEach(householdMember -> { Error error = getErrorForNonExistentEntity(); populateErrorDetails(householdMember, error, errorDetailsMap); }); } - log.info("household member non existent validation completed successfully, total errors: " + errorDetailsMap.size()); + // Log message for validation completion + log.info("Household member non-existent validation completed successfully, total errors: " + errorDetailsMap.size()); return errorDetailsMap; } } diff --git a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmRowVersionValidator.java b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmRowVersionValidator.java index fb9ec3cdd98..18d77c76920 100644 --- a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmRowVersionValidator.java +++ b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmRowVersionValidator.java @@ -50,7 +50,7 @@ public Map> validate(HouseholdMemberBulkRequest req if (!iMap.isEmpty()) { List householdMemberIds = new ArrayList<>(iMap.keySet()); List existingHouseholdMembers = householdMemberRepository.findById(householdMemberIds, - getIdFieldName(idMethod), false); + getIdFieldName(idMethod), false).getResponse(); List entitiesWithMismatchedRowVersion = getEntitiesWithMismatchedRowVersion(iMap, existingHouseholdMembers, idMethod); entitiesWithMismatchedRowVersion.forEach(householdMember -> { diff --git a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmUniqueIndividualValidator.java b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmUniqueIndividualValidator.java index 0d2f4682dce..535c842f81f 100644 --- a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmUniqueIndividualValidator.java +++ b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmUniqueIndividualValidator.java @@ -69,7 +69,7 @@ public Map> validate(HouseholdMemberBulkRequest hou log.info("finding individuals mappings in household member"); List individualSearchResult = householdMemberRepository - .findIndividual(individual.getId()); + .findIndividual(individual.getId()).getResponse(); if(!individualSearchResult.isEmpty()) { Error error = Error.builder().errorMessage(INDIVIDUAL_ALREADY_MEMBER_OF_HOUSEHOLD_MESSAGE) .errorCode(INDIVIDUAL_ALREADY_MEMBER_OF_HOUSEHOLD) diff --git a/health-services/household/src/main/java/org/egov/household/repository/HouseholdMemberRepository.java b/health-services/household/src/main/java/org/egov/household/repository/HouseholdMemberRepository.java index 565a076eeef..c402d24c05e 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/HouseholdMemberRepository.java +++ b/health-services/household/src/main/java/org/egov/household/repository/HouseholdMemberRepository.java @@ -1,9 +1,14 @@ package org.egov.household.repository; import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.builder.GenericQueryBuilder; +import org.egov.common.data.query.builder.QueryFieldChecker; import org.egov.common.data.query.builder.SelectQueryBuilder; +import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.household.HouseholdMember; +import org.egov.common.models.household.HouseholdMemberSearch; import org.egov.common.producer.Producer; import org.egov.household.repository.rowmapper.HouseholdMemberRowMapper; import org.springframework.beans.factory.annotation.Autowired; @@ -19,6 +24,7 @@ import java.util.Optional; import java.util.stream.Collectors; +import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; import static org.egov.common.utils.CommonUtils.getIdMethod; @Repository @@ -34,7 +40,56 @@ protected HouseholdMemberRepository(Producer producer, super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, householdMemberRowMapper, Optional.of("household_member")); } - public List findById(List ids, String columnName, Boolean includeDeleted) { + + public SearchResponse find(HouseholdMemberSearch householdMemberSearch, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) { + + Map paramsMap = new HashMap<>(); + StringBuilder queryBuilder = new StringBuilder(); + + String query = "SELECT * FROM household_member"; + + List whereFields = GenericQueryBuilder.getFieldsWithCondition(householdMemberSearch, QueryFieldChecker.isNotNull, paramsMap); + query = GenericQueryBuilder.generateQuery(query, whereFields).toString().trim(); + + query = query + " AND tenantId=:tenantId "; + + if (query.contains(this.tableName + " AND")) { + query = query.replace(this.tableName + " AND", this.tableName + " WHERE"); + } + + queryBuilder.append(query); + + if (Boolean.FALSE.equals(includeDeleted)) { + queryBuilder.append("AND isDeleted=:isDeleted "); + } + + if (lastChangedSince != null) { + queryBuilder.append("AND lastModifiedTime>=:lastModifiedTime "); + } + + paramsMap.put("tenantId", tenantId); + paramsMap.put("isDeleted", includeDeleted); + paramsMap.put("lastModifiedTime", lastChangedSince); + + queryBuilder.append(" ORDER BY id ASC "); + + Long totalCount = constructTotalCountCTEAndReturnResult(queryBuilder.toString(), paramsMap, this.namedParameterJdbcTemplate); + + queryBuilder.append(" LIMIT :limit OFFSET :offset"); + paramsMap.put("limit", limit); + paramsMap.put("offset", offset); + + List householdMembers = this.namedParameterJdbcTemplate.query(queryBuilder.toString(), paramsMap, this.rowMapper); + + return SearchResponse.builder().totalCount(totalCount).response(householdMembers).build(); + } + + public SearchResponse findById(List ids, String columnName, Boolean includeDeleted) { List objFound = findInCache(ids).stream() .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) .collect(Collectors.toList()); @@ -45,7 +100,7 @@ public List findById(List ids, String columnName, Boole .collect(Collectors.toList())); if (ids.isEmpty()) { log.info("all objects were found in the cache, returning objects"); - return objFound; + return SearchResponse.builder().response(objFound).build(); } } @@ -59,23 +114,29 @@ public List findById(List ids, String columnName, Boole objFound.addAll(this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper)); putInCache(objFound); log.info("returning objects from the database"); - return objFound; + return SearchResponse.builder().response(objFound).build(); } - public List findIndividual(String individualId) { + public SearchResponse findIndividual(String individualId) { log.info("searching for HouseholdMember with individualId: {}", individualId); String query = "SELECT * FROM household_member where individualId = :individualId AND isDeleted = false"; Map paramMap = new HashMap(); paramMap.put("individualId", individualId); - return this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + List householdMembers = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + return SearchResponse.builder().totalCount(Long.valueOf(householdMembers.size())).response(householdMembers).build(); } - public List findIndividualByHousehold(String householdId, String columnName) { + public SearchResponse findIndividualByHousehold(String householdId, String columnName) { log.info("searching for HouseholdMembers with householdId: {}", householdId); String query = String.format("SELECT * FROM household_member where %s = :householdId AND isDeleted = false", columnName); Map paramMap = new HashMap(); paramMap.put("householdId", householdId); - return this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramMap, this.namedParameterJdbcTemplate); + + List householdMembers = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + + return SearchResponse.builder().totalCount(totalCount).response(householdMembers).build(); } } diff --git a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java index e6e0315956f..35ed43a136b 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java +++ b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java @@ -1,31 +1,31 @@ package org.egov.household.repository; -import static org.egov.common.utils.CommonUtils.getIdMethod; - -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - +import lombok.extern.slf4j.Slf4j; import org.egov.common.data.query.builder.GenericQueryBuilder; import org.egov.common.data.query.builder.QueryFieldChecker; import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; -import org.egov.common.ds.Tuple; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.household.Household; import org.egov.common.producer.Producer; import org.egov.household.repository.rowmapper.HouseholdRowMapper; -import org.egov.household.web.models.HouseholdSearch; +import org.egov.common.models.household.HouseholdSearch; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; import org.springframework.util.ReflectionUtils; -import lombok.extern.slf4j.Slf4j; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; +import static org.egov.common.utils.CommonUtils.getIdMethod; @Repository @Slf4j @@ -39,10 +39,10 @@ protected HouseholdRepository(Producer producer, RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, HouseholdRowMapper householdRowMapper) { - super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, householdRowMapper, Optional.of("household")); + super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, householdRowMapper, Optional.of("household h")); } - public Tuple> findById(List ids, String columnName, Boolean includeDeleted) { + public SearchResponse findById(List ids, String columnName, Boolean includeDeleted) { List objFound = findInCache(ids).stream() .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) .collect(Collectors.toList()); @@ -52,7 +52,7 @@ public Tuple> findById(List ids, String columnName .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) .collect(Collectors.toList())); if (ids.isEmpty()) { - return new Tuple<>(Long.valueOf(objFound.size()), objFound); + return SearchResponse.builder().totalCount(Long.valueOf(objFound.size())).response(objFound).build(); } } @@ -63,14 +63,14 @@ public Tuple> findById(List ids, String columnName Map paramMap = new HashMap(); paramMap.put("ids", ids); - Long totalCount = constructTotalCountCTEAndReturnResult(query, paramMap); + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramMap, this.namedParameterJdbcTemplate); objFound.addAll(this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper)); putInCache(objFound); - return new Tuple<>(totalCount, objFound); + return SearchResponse.builder().totalCount(totalCount).response(objFound).build(); } - public Tuple> find(HouseholdSearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { + public SearchResponse find(HouseholdSearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) { String query = "SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid"; query += " FROM household h LEFT JOIN address a ON h.addressid = a.id"; Map paramsMap = new HashMap<>(); @@ -91,12 +91,13 @@ public Tuple> find(HouseholdSearch searchObject, Integer l paramsMap.put("isDeleted", includeDeleted); paramsMap.put("lastModifiedTime", lastChangedSince); - Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap); + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); query = query + "ORDER BY h.id ASC LIMIT :limit OFFSET :offset"; paramsMap.put("limit", limit); paramsMap.put("offset", offset); - return new Tuple<>(totalCount, this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper)); + List households = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + return SearchResponse.builder().totalCount(totalCount).response(households).build(); } /** @@ -110,7 +111,7 @@ public Tuple> find(HouseholdSearch searchObject, Integer l * * Fetch all the household which falls under the radius provided using longitude and latitude provided. */ - public Tuple> findByRadius(HouseholdSearch searchObject, Integer limit, Integer offset, String tenantId, Boolean includeDeleted) throws QueryBuilderException { + public SearchResponse findByRadius(HouseholdSearch searchObject, Integer limit, Integer offset, String tenantId, Boolean includeDeleted) throws QueryBuilderException { String query = searchCriteriaWaypointQuery + "SELECT * FROM (SELECT h.*, a.*, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid, " + calculateDistanceFromTwoWaypointsFormulaQuery + " \n" + "FROM public.household h LEFT JOIN public.address a ON h.addressid = a.id AND h.tenantid = a.tenantid, cte_search_criteria_waypoint cte_scw "; @@ -130,22 +131,13 @@ public Tuple> findByRadius(HouseholdSearch searchObject, I paramsMap.put("tenantId", tenantId); paramsMap.put("isDeleted", includeDeleted); paramsMap.put("distance", searchObject.getSearchRadius()); - Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap); - query = query + " ORDER BY distance ASC LIMIT :limit OFFSET :offset "; + query = query + " ORDER BY distance ASC"; + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + query = query + " LIMIT :limit OFFSET :offset "; paramsMap.put("limit", limit); paramsMap.put("offset", offset); - return new Tuple<>(totalCount, this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper)); + List households = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + return SearchResponse.builder().totalCount(totalCount).response(households).build(); } - private Long constructTotalCountCTEAndReturnResult(String query, Map paramsMap) { - String cteQuery = "WITH result_cte AS ("+query+"), totalCount_cte AS (SELECT COUNT(*) AS totalRows FROM result_cte) select * from totalCount_cte"; - return this.namedParameterJdbcTemplate.query(cteQuery, paramsMap, resultSet -> { - if(resultSet.next()) - return resultSet.getLong("totalRows"); - else - return 0L; - }); - } - - } diff --git a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java index f3b40cbee6f..79a762807ea 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java +++ b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdMemberRowMapper.java @@ -1,16 +1,16 @@ package org.egov.household.repository.rowmapper; +import java.sql.ResultSet; +import java.sql.SQLException; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.household.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.household.HouseholdMember; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; -import java.sql.ResultSet; -import java.sql.SQLException; - @Component public class HouseholdMemberRowMapper implements RowMapper { private final ObjectMapper objectMapper = new ObjectMapper(); diff --git a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java index fe90675a387..be08e68e1d1 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java +++ b/health-services/household/src/main/java/org/egov/household/repository/rowmapper/HouseholdRowMapper.java @@ -1,19 +1,19 @@ package org.egov.household.repository.rowmapper; +import java.sql.ResultSet; +import java.sql.SQLException; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.household.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.household.Address; import org.egov.common.models.household.AddressType; -import org.egov.common.models.household.Boundary; +import org.egov.common.models.core.Boundary; import org.egov.common.models.household.Household; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; -import java.sql.ResultSet; -import java.sql.SQLException; - @Component public class HouseholdRowMapper implements RowMapper { private final ObjectMapper objectMapper = new ObjectMapper(); diff --git a/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberEnrichmentService.java b/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberEnrichmentService.java index afcc8124b8f..ed07e4c8135 100644 --- a/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberEnrichmentService.java +++ b/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberEnrichmentService.java @@ -58,7 +58,7 @@ public void update(List householdMembers, Map hMap = getIdToObjMap(householdMembers); List householdMemberIds = new ArrayList<>(hMap.keySet()); List existingHouseholdMembers = householdMemberRepository.findById(householdMemberIds, - "id", false); + "id", false).getResponse(); log.info("updating lastModifiedTime and lastModifiedBy"); enrichForUpdate(hMap, existingHouseholdMembers, beneficiaryRequest); log.info("household Members updated successfully."); @@ -72,7 +72,7 @@ public void enrichHousehold(List householdMembers) { log.info("getting houseHoldIds for householdMembers"); List houseHoldIds = getIdList(householdMembers, idMethod); log.info("finding households from householdService with ids: {}", houseHoldIds); - List householdList = householdService.findById(houseHoldIds, columnName, false).getY(); + List householdList = householdService.findById(houseHoldIds, columnName, false).getResponse(); log.info("getting method for householdList with columnName: {}", columnName); Method householdMethod = getIdMethod(householdList, columnName); log.info("getting Map of households"); diff --git a/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberService.java b/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberService.java index c1621e432cf..2f350d2be76 100644 --- a/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberService.java +++ b/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberService.java @@ -1,16 +1,24 @@ package org.egov.household.service; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; -import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.ds.Tuple; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.household.HouseholdMember; import org.egov.common.models.household.HouseholdMemberBulkRequest; import org.egov.common.models.household.HouseholdMemberRequest; +import org.egov.common.models.household.HouseholdMemberSearch; import org.egov.common.utils.CommonUtils; import org.egov.common.validator.Validator; import org.egov.household.config.HouseholdMemberConfiguration; +import org.egov.household.household.member.validators.HmExistentEntityValidator; import org.egov.household.household.member.validators.HmHouseholdHeadValidator; import org.egov.household.household.member.validators.HmHouseholdValidator; import org.egov.household.household.member.validators.HmIndividualValidator; @@ -21,18 +29,11 @@ import org.egov.household.household.member.validators.HmUniqueEntityValidator; import org.egov.household.household.member.validators.HmUniqueIndividualValidator; import org.egov.household.repository.HouseholdMemberRepository; -import org.egov.household.web.models.HouseholdMemberSearch; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.getIdMethod; import static org.egov.common.utils.CommonUtils.handleErrors; @@ -73,6 +74,7 @@ public class HouseholdMemberService { private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(HmHouseholdValidator.class) + || validator.getClass().equals(HmExistentEntityValidator.class) || validator.getClass().equals(HmUniqueIndividualValidator.class) || validator.getClass().equals(HmHouseholdHeadValidator.class); @@ -134,27 +136,31 @@ public List create(HouseholdMemberBulkRequest householdMemberBu } - public List search(HouseholdMemberSearch householdMemberSearch, Integer limit, Integer offset, String tenantId, - Long lastChangedSince, Boolean includeDeleted) { + public SearchResponse search(HouseholdMemberSearch householdMemberSearch, Integer limit, Integer offset, String tenantId, + Long lastChangedSince, Boolean includeDeleted) { String idFieldName = getIdFieldName(householdMemberSearch); if (isSearchByIdOnly(householdMemberSearch, idFieldName)) { List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections .singletonList(householdMemberSearch)), householdMemberSearch); - List householdMembers = householdMemberRepository.findById(ids, - idFieldName, includeDeleted).stream() + SearchResponse searchResponse = householdMemberRepository.findById(ids, + idFieldName, includeDeleted); + List householdMembers = searchResponse.getResponse().stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); log.info("found {} household members for search by id", householdMembers.size()); - return householdMembers; + + searchResponse.setResponse(householdMembers); + + return searchResponse; } try { return householdMemberRepository.find(householdMemberSearch, limit, offset, tenantId, lastChangedSince, includeDeleted); - } catch (QueryBuilderException e) { + } catch (Exception e) { log.error("error in building query for household member search", e); throw new CustomException("ERROR_IN_QUERY", e.getMessage()); } diff --git a/health-services/household/src/main/java/org/egov/household/service/HouseholdService.java b/health-services/household/src/main/java/org/egov/household/service/HouseholdService.java index 5da1471730b..2fb2804f178 100644 --- a/health-services/household/src/main/java/org/egov/household/service/HouseholdService.java +++ b/health-services/household/src/main/java/org/egov/household/service/HouseholdService.java @@ -4,6 +4,7 @@ import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdBulkRequest; import org.egov.common.models.household.HouseholdRequest; @@ -12,12 +13,14 @@ import org.egov.common.validator.Validator; import org.egov.household.config.HouseholdConfiguration; import org.egov.household.repository.HouseholdRepository; +import org.egov.household.validators.household.HExistentEntityValidator; +import org.egov.household.validators.household.HBoundaryValidator; import org.egov.household.validators.household.HIsDeletedValidator; -import org.egov.household.validators.household.HNonExsistentEntityValidator; +import org.egov.household.validators.household.HNonExistentEntityValidator; import org.egov.household.validators.household.HNullIdValidator; import org.egov.household.validators.household.HRowVersionValidator; import org.egov.household.validators.household.HUniqueEntityValidator; -import org.egov.household.web.models.HouseholdSearch; +import org.egov.common.models.household.HouseholdSearch; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -56,16 +59,21 @@ public class HouseholdService { private final HouseholdEnrichmentService enrichmentService; + private final Predicate> isApplicableForCreate = validator -> + validator.getClass().equals(HBoundaryValidator.class) + || validator.getClass().equals(HExistentEntityValidator.class); + private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(HNullIdValidator.class) + || validator.getClass().equals(HBoundaryValidator.class) || validator.getClass().equals(HIsDeletedValidator.class) || validator.getClass().equals(HUniqueEntityValidator.class) - || validator.getClass().equals(HNonExsistentEntityValidator.class) + || validator.getClass().equals(HNonExistentEntityValidator.class) || validator.getClass().equals(HRowVersionValidator.class); private final Predicate> isApplicableForDelete = validator -> validator.getClass().equals(HNullIdValidator.class) - || validator.getClass().equals(HNonExsistentEntityValidator.class) + || validator.getClass().equals(HNonExistentEntityValidator.class) || validator.getClass().equals(HRowVersionValidator.class); @Autowired @@ -91,8 +99,11 @@ public Household create(HouseholdRequest request) { public List create(HouseholdBulkRequest request, boolean isBulk) { log.info("received request to create households"); - Map errorDetailsMap = new HashMap<>(); - List validEntities = request.getHouseholds(); + Tuple, Map> tuple = validate(validators, + isApplicableForCreate, request, + isBulk); + Map errorDetailsMap = tuple.getY(); + List validEntities = tuple.getX(); try { if (!validEntities.isEmpty()) { enrichmentService.create(validEntities, request); @@ -108,34 +119,33 @@ public List create(HouseholdBulkRequest request, boolean isBulk) { return request.getHouseholds(); } - public Tuple> search(HouseholdSearch householdSearch, Integer limit, Integer offset, String tenantId, - Long lastChangedSince, Boolean includeDeleted) { + public SearchResponse search(HouseholdSearch householdSearch, Integer limit, Integer offset, String tenantId, + Long lastChangedSince, Boolean includeDeleted) { String idFieldName = getIdFieldName(householdSearch); if (isSearchByIdOnly(householdSearch, idFieldName)) { List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections .singletonList(householdSearch)), householdSearch); - Tuple> householdsTuple = householdRepository.findById(ids, + SearchResponse householdsTuple = householdRepository.findById(ids, idFieldName, includeDeleted); - List households = householdsTuple.getY().stream() + List households = householdsTuple.getResponse().stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); log.info("households found for search by id, size: {}", households.size()); - return new Tuple<>(householdsTuple.getX(), households); + return SearchResponse.builder().totalCount(Long.valueOf(households.size())).response(households).build(); } try { - new Tuple<>(null, Collections.emptyList()); - Tuple> householdsTuple; + SearchResponse searchResponse; if(Boolean.TRUE.equals(isProximityBasedSearch(householdSearch))) { - householdsTuple = householdRepository.findByRadius(householdSearch, limit, offset, tenantId, includeDeleted); + searchResponse = householdRepository.findByRadius(householdSearch, limit, offset, tenantId, includeDeleted); } else { - householdsTuple = householdRepository.find(householdSearch, limit, offset, tenantId, lastChangedSince, includeDeleted); + searchResponse = householdRepository.find(householdSearch, limit, offset, tenantId, lastChangedSince, includeDeleted); } - log.info("households found for search, size: {}", householdsTuple.getY().size()); - return householdsTuple; + log.info("households found for search, size: {}", searchResponse.getResponse().size()); + return searchResponse; } catch (QueryBuilderException e) { log.error("error occurred while searching households", e); throw new CustomException("ERROR_IN_QUERY", e.getMessage()); @@ -205,13 +215,13 @@ public List delete(HouseholdBulkRequest request, boolean isBulk) { return request.getHouseholds(); } - public Tuple> findById(List houseHoldIds, String columnName, boolean includeDeleted){ + public SearchResponse findById(List houseHoldIds, String columnName, boolean includeDeleted){ log.info("finding Households by Ids: {} with columnName: {} and includeDeleted: {}", houseHoldIds, columnName, includeDeleted); log.info("started finding Households by Ids"); - Tuple> householdsTuple = householdRepository.findById(houseHoldIds, columnName, includeDeleted); - log.info("finished finding Households by Ids. Found {} Households", householdsTuple.getY().size()); - return householdsTuple; + SearchResponse searchResponse = householdRepository.findById(houseHoldIds, columnName, includeDeleted); + log.info("finished finding Households by Ids. Found {} Households", searchResponse.getResponse().size()); + return searchResponse; } public void putInCache(List households) { diff --git a/health-services/household/src/main/java/org/egov/household/validators/household/HBoundaryValidator.java b/health-services/household/src/main/java/org/egov/household/validators/household/HBoundaryValidator.java new file mode 100644 index 00000000000..b0998f29cde --- /dev/null +++ b/health-services/household/src/main/java/org/egov/household/validators/household/HBoundaryValidator.java @@ -0,0 +1,127 @@ +package org.egov.household.validators.household; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.core.Boundary; +import org.egov.common.models.household.Household; +import org.egov.common.models.household.HouseholdBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.household.config.HouseholdConfiguration; +import org.egov.household.web.models.boundary.BoundaryResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +/** + * Validator class for validating household boundaries. + */ +@Component +@Order(value = 4) +@Slf4j +public class HBoundaryValidator implements Validator { + + private final ServiceRequestClient serviceRequestClient; + + private final HouseholdConfiguration householdConfiguration; + + /** + * Constructor to initialize the HBoundaryValidator. + * + * @param serviceRequestClient Service request client for making HTTP requests + * @param householdConfiguration Configuration properties for the household module + */ + public HBoundaryValidator(ServiceRequestClient serviceRequestClient, HouseholdConfiguration householdConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.householdConfiguration = householdConfiguration; + } + + /** + * Validates the households' boundaries. + * + * @param request the bulk request containing households + * @return a map containing households with their corresponding list of errors + */ + @Override + public Map> validate(HouseholdBulkRequest request) { + log.debug("Validating households boundaries."); + // Create a HashMap to store error details for each household + HashMap> errorDetailsMap = new HashMap<>(); + + // Filter households with non-null addresses + List entitiesWithValidBoundaries = request.getHouseholds().parallelStream() + .filter(household -> Objects.nonNull(household.getAddress())) + .filter(household -> Objects.nonNull(household.getAddress().getLocality())) // Exclude null locality codes + .collect(Collectors.toList()); + + Map> tenantIdHouseholdMap = entitiesWithValidBoundaries.stream().collect(Collectors.groupingBy(Household::getTenantId)); + + tenantIdHouseholdMap.forEach((tenantId, households) -> { + // Group households by locality code + Map> boundaryCodeHouseholdsMap = households.stream() + .collect(Collectors.groupingBy( + household -> household.getAddress().getLocality().getCode() // Group by locality code + )); + + List boundaries = new ArrayList<>(boundaryCodeHouseholdsMap.keySet()); + if(!CollectionUtils.isEmpty(boundaries)) { + try { + // Fetch boundary details from the service + log.debug("Fetching boundary details for tenantId: {}, boundaries: {}", tenantId, boundaries); + BoundaryResponse boundarySearchResponse = serviceRequestClient.fetchResult( + new StringBuilder(householdConfiguration.getBoundaryServiceHost() + + householdConfiguration.getBoundarySearchUrl() + +"?limit=" + boundaries.size() + + "&offset=0&tenantId=" + tenantId + + "&codes=" + String.join(",", boundaries)), + request.getRequestInfo(), + BoundaryResponse.class + ); + log.debug("Boundary details fetched successfully for tenantId: {}", tenantId); + + List invalidBoundaryCodes = new ArrayList<>(boundaries); + invalidBoundaryCodes.removeAll(boundarySearchResponse.getBoundary().stream() + .map(Boundary::getCode) + .collect(Collectors.toList()) + ); + + // Filter out households with invalid boundary codes + List householdsWithInvalidBoundaries = boundaryCodeHouseholdsMap.entrySet().stream() + .filter(entry -> invalidBoundaryCodes.contains(entry.getKey())) // filter invalid boundary codes + .flatMap(entry -> entry.getValue().stream()) // Flatten the list of households + .collect(Collectors.toList()); + + + householdsWithInvalidBoundaries.forEach(household -> { + // Create an error object for households with invalid boundaries + Error error = Error.builder() + .errorMessage("Boundary code does not exist in db") + .errorCode("NON_EXISTENT_ENTITY") + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException("NON_EXISTENT_ENTITY", "Boundary code does not exist in db")) + .build(); + // Populate error details for the household + populateErrorDetails(household, error, errorDetailsMap); + }); + + } catch (Exception e) { + log.error("Exception while searching boundaries for tenantId: {}", tenantId, e); + // Throw a custom exception if an error occurs during boundary search + throw new CustomException("BOUNDARY_SEARCH_ERROR", e.getMessage()); + } + } + }); + + return errorDetailsMap; + } +} diff --git a/health-services/household/src/main/java/org/egov/household/validators/household/HExistentEntityValidator.java b/health-services/household/src/main/java/org/egov/household/validators/household/HExistentEntityValidator.java new file mode 100644 index 00000000000..980702a693d --- /dev/null +++ b/health-services/household/src/main/java/org/egov/household/validators/household/HExistentEntityValidator.java @@ -0,0 +1,76 @@ +package org.egov.household.validators.household; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.common.models.Error; +import org.egov.common.models.household.Household; +import org.egov.common.models.household.HouseholdBulkRequest; +import org.egov.common.models.household.HouseholdSearch; +import org.egov.common.validator.Validator; +import org.egov.household.repository.HouseholdRepository; +import org.springframework.util.CollectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of entities with the given client reference IDs. + * This validator checks if the provided household entities already exist in the database based on their client reference IDs. + * @author kanishq-egov + */ +public class HExistentEntityValidator implements Validator { + + private final HouseholdRepository householdRepository; + + /** + * Constructor to initialize the HouseholdRepository dependency. + * + * @param householdRepository The repository for household entities. + */ + public HExistentEntityValidator(HouseholdRepository householdRepository) { + this.householdRepository = householdRepository; + } + + /** + * Validates the existence of entities with the given client reference IDs. + * + * @param request The bulk request containing household entities. + * @return A map containing household entities and their associated error details. + */ + @Override + public Map> validate(HouseholdBulkRequest request) { + // Map to hold household entities and their error details + Map> errorDetailsMap = new HashMap<>(); + // Get the list of household entities from the request + List entities = request.getHouseholds(); + // Extract client reference IDs from household entities without errors + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) + .map(Household::getClientReferenceId) + .collect(Collectors.toList()); + // Create a search object for querying entities by client reference IDs + HouseholdSearch householdSearch = HouseholdSearch.builder() + .clientReferenceId(clientReferenceIdList) + .build(); + // Check if the client reference ID list is not empty + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing entities by client reference IDs + List existentEntities = householdRepository.findById( + clientReferenceIdList, + getIdFieldName(householdSearch), + Boolean.FALSE).getResponse(); + // For each existing entity, populate error details for uniqueness + existentEntities.forEach(entity -> { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(entity, error, errorDetailsMap); + }); + } + return errorDetailsMap; + } + +} diff --git a/health-services/household/src/main/java/org/egov/household/validators/household/HNonExistentEntityValidator.java b/health-services/household/src/main/java/org/egov/household/validators/household/HNonExistentEntityValidator.java new file mode 100644 index 00000000000..e18090664ea --- /dev/null +++ b/health-services/household/src/main/java/org/egov/household/validators/household/HNonExistentEntityValidator.java @@ -0,0 +1,105 @@ +package org.egov.household.validators.household; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.models.Error; +import org.egov.common.models.household.Household; +import org.egov.common.models.household.HouseholdBulkRequest; +import org.egov.common.models.household.HouseholdSearch; +import org.egov.common.validator.Validator; +import org.egov.household.repository.HouseholdRepository; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.getObjClass; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; +import static org.egov.household.Constants.GET_ID; + +/** + * Validator for checking the non-existence of household entities. + * This validator checks if the provided household entities do not already exist in the database. + * + * @author kanishq-egov + */ +@Component +@Order(value = 2) +@Slf4j +public class HNonExistentEntityValidator implements Validator { + + private final HouseholdRepository householdRepository; + + public HNonExistentEntityValidator(HouseholdRepository householdRepository) { + this.householdRepository = householdRepository; + } + + /** + * Validates the non-existence of entities based on their IDs and client reference IDs. + * + * @param request The bulk request containing household entities. + * @return A map containing household entities and their associated error details. + */ + @Override + public Map> validate(HouseholdBulkRequest request) { + // Map to hold household entities and their error details + Map> errorDetailsMap = new HashMap<>(); + // Get the list of household entities from the request + List entities = request.getHouseholds(); + // Get the class of the household entity + Class objClass = getObjClass(entities); + // Get the method for fetching the ID of the entity + Method idMethod = getMethod(GET_ID, objClass); + // Map to store entities by their IDs + Map eMap = getIdToObjMap( + entities.stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + // Lists to store IDs and client reference IDs + List idList = new ArrayList<>(); + List clientReferenceIdList = new ArrayList<>(); + // Extract IDs and client reference IDs from household entities + entities.forEach(household -> { + idList.add(household.getId()); + clientReferenceIdList.add(household.getClientReferenceId()); + }); + // Check if the entity map is not empty + if (!eMap.isEmpty()) { + // Extract entity IDs + List entityIds = new ArrayList<>(eMap.keySet()); + // Create a search object for querying existing entities + HouseholdSearch householdSearch = HouseholdSearch.builder() + .clientReferenceId(clientReferenceIdList) + .id(idList) + .build(); + + List existingEntities; + try { + // Query the repository to find existing entities + existingEntities = householdRepository.find(householdSearch, entities.size(), 0, + entities.get(0).getTenantId(), null, false).getResponse(); + } catch (Exception e) { + // Handle query builder exception + throw new RuntimeException(e); + } + // Check for non-existent entities + List nonExistentEntities = checkNonExistentEntities(eMap, + existingEntities, idMethod); + // Populate error details for non-existent entities + nonExistentEntities.forEach(entity -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(entity, error, errorDetailsMap); + }); + } + + return errorDetailsMap; + } +} diff --git a/health-services/household/src/main/java/org/egov/household/validators/household/HNonExsistentEntityValidator.java b/health-services/household/src/main/java/org/egov/household/validators/household/HNonExsistentEntityValidator.java index a4ea82912ba..2458f465b66 100644 --- a/health-services/household/src/main/java/org/egov/household/validators/household/HNonExsistentEntityValidator.java +++ b/health-services/household/src/main/java/org/egov/household/validators/household/HNonExsistentEntityValidator.java @@ -48,7 +48,7 @@ public Map> validate(HouseholdBulkRequest request) { if (!eMap.isEmpty()) { List entityIds = new ArrayList<>(eMap.keySet()); List existingEntities = householdRepository.findById(entityIds, - getIdFieldName(idMethod), false).getY(); + getIdFieldName(idMethod), false).getResponse(); List nonExistentEntities = checkNonExistentEntities(eMap, existingEntities, idMethod); nonExistentEntities.forEach(task -> { diff --git a/health-services/household/src/main/java/org/egov/household/validators/household/HRowVersionValidator.java b/health-services/household/src/main/java/org/egov/household/validators/household/HRowVersionValidator.java index e9ab1f1bae4..8a6e73a9b88 100644 --- a/health-services/household/src/main/java/org/egov/household/validators/household/HRowVersionValidator.java +++ b/health-services/household/src/main/java/org/egov/household/validators/household/HRowVersionValidator.java @@ -45,7 +45,7 @@ public Map> validate(HouseholdBulkRequest request) { if (!eMap.isEmpty()) { List entityIds = new ArrayList<>(eMap.keySet()); List existingEntities = repository.findById(entityIds, - getIdFieldName(idMethod), false).getY(); + getIdFieldName(idMethod), false).getResponse(); List entitiesWithMismatchedRowVersion = getEntitiesWithMismatchedRowVersion(eMap, existingEntities, idMethod); entitiesWithMismatchedRowVersion.forEach(individual -> { diff --git a/health-services/household/src/main/java/org/egov/household/web/controllers/HouseholdApiController.java b/health-services/household/src/main/java/org/egov/household/web/controllers/HouseholdApiController.java index 460adf4e6ab..82e3263f2fb 100644 --- a/health-services/household/src/main/java/org/egov/household/web/controllers/HouseholdApiController.java +++ b/health-services/household/src/main/java/org/egov/household/web/controllers/HouseholdApiController.java @@ -1,10 +1,15 @@ package org.egov.household.web.controllers; +import java.util.List; + import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; -import org.egov.common.ds.Tuple; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdBulkRequest; import org.egov.common.models.household.HouseholdBulkResponse; @@ -13,35 +18,28 @@ import org.egov.common.models.household.HouseholdMemberBulkResponse; import org.egov.common.models.household.HouseholdMemberRequest; import org.egov.common.models.household.HouseholdMemberResponse; +import org.egov.common.models.household.HouseholdMemberSearchRequest; import org.egov.common.models.household.HouseholdRequest; import org.egov.common.models.household.HouseholdResponse; +import org.egov.common.models.household.HouseholdSearchRequest; import org.egov.common.producer.Producer; import org.egov.common.utils.ResponseInfoFactory; import org.egov.household.config.HouseholdConfiguration; import org.egov.household.config.HouseholdMemberConfiguration; import org.egov.household.service.HouseholdMemberService; import org.egov.household.service.HouseholdService; -import org.egov.household.web.models.HouseholdMemberSearchRequest; -import org.egov.household.web.models.HouseholdSearchRequest; 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.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; -import java.util.List; -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") @Controller @RequestMapping("") @@ -99,14 +97,22 @@ public ResponseEntity householdMemberV1CreatePost(@ApiP } @RequestMapping(value = "/member/v1/_search", method = RequestMethod.POST) - public ResponseEntity householdMemberV1SearchPost(@ApiParam(value = "Details for existing household member.", required = true) @Valid @RequestBody HouseholdMemberSearchRequest householdMemberSearchRequest, @NotNull - @Min(0) - @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, @NotNull - @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) { - List households = householdMemberService.search(householdMemberSearchRequest.getHouseholdMemberSearch(), limit, offset, tenantId, lastChangedSince, includeDeleted); + public ResponseEntity householdMemberV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Details for existing household member.", required = true) @Valid @RequestBody HouseholdMemberSearchRequest householdMemberSearchRequest + ) { + SearchResponse searchResponse = householdMemberService.search( + householdMemberSearchRequest.getHouseholdMemberSearch(), + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted() + ); HouseholdMemberBulkResponse response = HouseholdMemberBulkResponse.builder().responseInfo(ResponseInfoFactory .createResponseInfo(householdMemberSearchRequest.getRequestInfo(), true)) - .householdMembers(households) + .householdMembers(searchResponse.getResponse()) + .totalCount(searchResponse.getTotalCount()) .build(); return ResponseEntity.status(HttpStatus.OK).body(response); @@ -198,17 +204,25 @@ public ResponseEntity householdV1DeletePost(@ApiParam(value = "Cap } @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) - public ResponseEntity householdV1SearchPost(@ApiParam(value = "Details for existing household.", required = true) @Valid @RequestBody HouseholdSearchRequest request, - @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, - @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, - @NotNull @Size(min = 2, max = 1000) @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, - @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, - @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted, - @ApiParam(value = "Used to test performance", defaultValue = "false") @Valid @RequestParam(value = "useCte", required = false, defaultValue = "false") Boolean useCte) { - - Tuple> householdsTuple = householdService.search(request.getHousehold(), limit, offset, tenantId, lastChangedSince, includeDeleted); - HouseholdBulkResponse response = HouseholdBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).totalCount(householdsTuple.getX()).households(householdsTuple.getY()).build(); + public ResponseEntity householdV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Details for existing household.", required = true) @Valid @RequestBody HouseholdSearchRequest request + ) { + SearchResponse searchResponse = householdService.search( + request.getHousehold(), + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted() + ); + HouseholdBulkResponse response = HouseholdBulkResponse.builder() + .responseInfo( + ResponseInfoFactory.createResponseInfo( + request.getRequestInfo(), true + ) + ).totalCount(searchResponse.getTotalCount()) + .households(searchResponse.getResponse()).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdMemberSearch.java b/health-services/household/src/main/java/org/egov/household/web/models/HouseholdMemberSearch.java deleted file mode 100644 index a50d32819d2..00000000000 --- a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdMemberSearch.java +++ /dev/null @@ -1,57 +0,0 @@ -package org.egov.household.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.data.query.annotations.Table; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import java.util.List; - -/** -* Search model for household member -*/ - @ApiModel(description = "Search model for household member") -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) - @Table(name = "household_member") -public class HouseholdMemberSearch { - - @JsonProperty("id") - private List id = null; - - @JsonProperty("householdId") - private String householdId = null; - - @JsonProperty("householdClientReferenceId") - private String householdClientReferenceId = null; - - @JsonProperty("individualId") - private String individualId = null; - - @JsonProperty("individualClientReferenceId") - private String individualClientReferenceId = null; - - @JsonProperty("isHeadOfHousehold") - private Boolean isHeadOfHousehold = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; - - @JsonProperty("tenantId") - @Valid - private String tenantId = null; - -} - diff --git a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdMemberSearchRequest.java b/health-services/household/src/main/java/org/egov/household/web/models/HouseholdMemberSearchRequest.java deleted file mode 100644 index f4b82ca9688..00000000000 --- a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdMemberSearchRequest.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.egov.household.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - -/** -* HouseholdMemberSearchRequest -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class HouseholdMemberSearchRequest { - - @JsonProperty("RequestInfo") - @NotNull - @Valid - private org.egov.common.contract.request.RequestInfo requestInfo = null; - - @JsonProperty("HouseholdMember") - @NotNull - @Valid - private HouseholdMemberSearch householdMemberSearch = null; - - -} - diff --git a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearch.java b/health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearch.java deleted file mode 100644 index 96b8e529b4a..00000000000 --- a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearch.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.egov.household.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.data.query.annotations.Exclude; -import org.egov.common.data.query.annotations.Table; -import org.springframework.validation.annotation.Validated; - -import javax.validation.constraints.DecimalMax; -import javax.validation.constraints.DecimalMin; -import java.util.List; - -/** -* A representation of Household. -*/ - @ApiModel(description = "A representation of Household.") -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -@Table(name = "household h") -public class HouseholdSearch { - - @JsonProperty("id") - private List id = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; - -// @JsonProperty("memberCount") -// private Integer memberCount = null; - - @JsonProperty("boundaryCode") - private String localityCode = null; - - @Exclude - @JsonProperty("latitude") - @DecimalMin("-90") - @DecimalMax("90") - private Double latitude = null; - - @Exclude - @JsonProperty("longitude") - @DecimalMin("-180") - @DecimalMax("180") - private Double longitude = null; - - /* - * @value unit of measurement in Kilometer - * */ - @Exclude - @JsonProperty("searchRadius") - @DecimalMin("0") - private Double searchRadius = null; -} - diff --git a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearchRequest.java b/health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearchRequest.java deleted file mode 100644 index e55cbc9ff3f..00000000000 --- a/health-services/household/src/main/java/org/egov/household/web/models/HouseholdSearchRequest.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.egov.household.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.contract.request.RequestInfo; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - -/** -* HouseholdSearchRequest -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class HouseholdSearchRequest { - - @JsonProperty("RequestInfo") - @NotNull - @Valid - private RequestInfo requestInfo = null; - - @JsonProperty("Household") - @NotNull - @Valid - private HouseholdSearch household = null; -} - diff --git a/health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundaryRequest.java b/health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundaryRequest.java new file mode 100644 index 00000000000..9b3937ed018 --- /dev/null +++ b/health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundaryRequest.java @@ -0,0 +1,38 @@ +package org.egov.household.web.models.boundary; + +import java.util.List; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.Boundary; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryRequest + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @Valid + @NotNull + @JsonProperty("Boundary") + @Size(min = 1, max = 300) + private List boundary = null; + +} diff --git a/health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundaryResponse.java b/health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundaryResponse.java new file mode 100644 index 00000000000..4f3f07f82b9 --- /dev/null +++ b/health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundaryResponse.java @@ -0,0 +1,44 @@ +package org.egov.household.web.models.boundary; + +import java.util.ArrayList; +import java.util.List; +import jakarta.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.Boundary; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryResponse + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Boundary") + @Valid + private List boundary = null; + + + public BoundaryResponse addBoundaryItem(Boundary boundaryItem) { + if (this.boundary == null) { + this.boundary = new ArrayList<>(); + } + this.boundary.add(boundaryItem); + return this; + } + +} diff --git a/health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundarySearchCriteria.java b/health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundarySearchCriteria.java new file mode 100644 index 00000000000..f7c6fcca045 --- /dev/null +++ b/health-services/household/src/main/java/org/egov/household/web/models/boundary/BoundarySearchCriteria.java @@ -0,0 +1,37 @@ +package org.egov.household.web.models.boundary; + +import java.util.List; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundarySearchCriteria { + + @NotNull + @Size(min = 1) + @JsonProperty("codes") + private List codes; + + @NotNull + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} diff --git a/health-services/household/src/main/resources/application.properties b/health-services/household/src/main/resources/application.properties index ae3b0272d47..dfd2b4f6937 100644 --- a/health-services/household/src/main/resources/application.properties +++ b/health-services/household/src/main/resources/application.properties @@ -23,7 +23,7 @@ spring.flyway.table=public spring.flyway.baseline-on-migrate=true spring.flyway.outOfOrder=true spring.flyway.locations=classpath:/db/migration/main -spring.flyway.enabled=true +spring.flyway.enabled=false # TRACER CONFIG # KAFKA SERVER CONFIG @@ -49,8 +49,8 @@ kafka.producer.config.linger_ms_config=1 kafka.producer.config.buffer_memory_config=33554432 # IDGEN CONFIG -egov.idgen.host=https://dev.digit.org/ -#egov.idgen.host=http://localhost:8081/ +#egov.idgen.host=https://dev.digit.org/ +egov.idgen.host=http://localhost:8082/ egov.idgen.path=egov-idgen/id/_generate egov.idgen.integration.enabled=true household.idgen.id.format=household.id @@ -59,7 +59,8 @@ household.idgen.id.format=household.id kafka.topics.consumer=household-consumer-topic # USER CONFIG -egov.user.host=https://dev.digit.org +#egov.user.host=https://dev.digit.org +egov.user.host=http://localhost:8083/ egov.user.context.path=/user/users egov.user.create.path=/_createnovalidate egov.user.search.path=/user/_search @@ -96,3 +97,9 @@ household.member.consumer.bulk.delete.topic=household-member-consumer-bulk-delet # INDIVIDUAL SERVICE egov.individual.host=https://dev.digit.org egov.individual.search.url=/individual/v1/_search + + +# BOUNDARY SERVICE +egov.boundary.host=http://localhost:8081 +egov.boundary.search.url=/boundary-service/boundary/_search +egov.boundary.hierarchy=HCM-Moz-Hierarchy diff --git a/health-services/household/src/main/resources/db/Dockerfile b/health-services/household/src/main/resources/db/Dockerfile index 60fc07ce69f..e7da01d7f0b 100644 --- a/health-services/household/src/main/resources/db/Dockerfile +++ b/health-services/household/src/main/resources/db/Dockerfile @@ -1,4 +1,4 @@ -FROM egovio/flyway:4.1.2 +FROM egovio/flyway:10.7.1 COPY ./migration/main /flyway/sql @@ -6,4 +6,4 @@ COPY migrate.sh /usr/bin/migrate.sh RUN chmod +x /usr/bin/migrate.sh -CMD ["/usr/bin/migrate.sh"] \ No newline at end of file +ENTRYPOINT ["/usr/bin/migrate.sh"] \ No newline at end of file diff --git a/health-services/household/src/main/resources/db/migrate.sh b/health-services/household/src/main/resources/db/migrate.sh index 43960b25cdb..5593a173eba 100644 --- a/health-services/household/src/main/resources/db/migrate.sh +++ b/health-services/household/src/main/resources/db/migrate.sh @@ -1,3 +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 +flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS -baselineOnMigrate=true -outOfOrder=true migrate \ No newline at end of file diff --git a/health-services/household/src/main/resources/db/migration/main/V20240305114132__household_search_index_ddl.sql b/health-services/household/src/main/resources/db/migration/main/V20240305114132__household_search_index_ddl.sql new file mode 100644 index 00000000000..5228a08ba4d --- /dev/null +++ b/health-services/household/src/main/resources/db/migration/main/V20240305114132__household_search_index_ddl.sql @@ -0,0 +1 @@ +CREATE INDEX IF NOT EXISTS idx_household_tenantId_isDeleted_addressId ON household(tenantId, isDeleted, addressId); \ No newline at end of file diff --git a/health-services/household/src/main/resources/db/migration/main/V20240305114225__household_member_search_index_ddl.sql b/health-services/household/src/main/resources/db/migration/main/V20240305114225__household_member_search_index_ddl.sql new file mode 100644 index 00000000000..9e7995c915f --- /dev/null +++ b/health-services/household/src/main/resources/db/migration/main/V20240305114225__household_member_search_index_ddl.sql @@ -0,0 +1 @@ +CREATE INDEX IF NOT EXISTS idx_household_member_id ON household_member(id); \ No newline at end of file diff --git a/health-services/household/src/test/java/org/egov/household/helper/HouseholdMemberSearchRequestTestBuilder.java b/health-services/household/src/test/java/org/egov/household/helper/HouseholdMemberSearchRequestTestBuilder.java new file mode 100644 index 00000000000..868e354278b --- /dev/null +++ b/health-services/household/src/test/java/org/egov/household/helper/HouseholdMemberSearchRequestTestBuilder.java @@ -0,0 +1,20 @@ +package org.egov.household.helper; + +import org.egov.common.models.household.HouseholdMemberSearchRequest; + +public class HouseholdMemberSearchRequestTestBuilder { + private HouseholdMemberSearchRequest.HouseholdMemberSearchRequestBuilder builder; + + public HouseholdMemberSearchRequestTestBuilder() { + this.builder = HouseholdMemberSearchRequest.builder(); + } + public static HouseholdMemberSearchRequestTestBuilder builder() { + return new HouseholdMemberSearchRequestTestBuilder(); + } + + public HouseholdMemberSearchRequest build() { + return this.builder.build(); + } + + +} diff --git a/health-services/household/src/test/java/org/egov/household/helper/HouseholdMemberTestBuilder.java b/health-services/household/src/test/java/org/egov/household/helper/HouseholdMemberTestBuilder.java index 6ccc6322324..140f6b3f84f 100644 --- a/health-services/household/src/test/java/org/egov/household/helper/HouseholdMemberTestBuilder.java +++ b/health-services/household/src/test/java/org/egov/household/helper/HouseholdMemberTestBuilder.java @@ -1,16 +1,17 @@ package org.egov.household.helper; import org.egov.common.helper.AuditDetailsTestBuilder; -import org.egov.common.models.household.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; +import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdMember; public class HouseholdMemberTestBuilder { - private HouseholdMember.HouseholdMemberBuilder builder; + private HouseholdMember.HouseholdMemberBuilder builder; public HouseholdMemberTestBuilder() { - this.builder = HouseholdMember.builder(); + this.builder = (HouseholdMember.HouseholdMemberBuilder) HouseholdMember.builder(); } public static HouseholdMemberTestBuilder builder() { diff --git a/health-services/household/src/test/java/org/egov/household/helper/HouseholdSearchTestBuilder.java b/health-services/household/src/test/java/org/egov/household/helper/HouseholdSearchTestBuilder.java new file mode 100644 index 00000000000..aee59e664e5 --- /dev/null +++ b/health-services/household/src/test/java/org/egov/household/helper/HouseholdSearchTestBuilder.java @@ -0,0 +1,39 @@ +package org.egov.household.helper; + +import java.util.Collections; + +import org.egov.common.models.household.HouseholdSearch; + + +public class HouseholdSearchTestBuilder { + + private HouseholdSearch.HouseholdSearchBuilder builder; + + public HouseholdSearchTestBuilder() { + this.builder = (HouseholdSearch.HouseholdSearchBuilder) HouseholdSearch.builder(); + } + + public static HouseholdSearchTestBuilder builder() { + return new HouseholdSearchTestBuilder(); + } + + public HouseholdSearch build() { + return this.builder.build(); + } + + public HouseholdSearchTestBuilder withHouseholdSearch(){ + this.builder.id(Collections.singletonList("some-id")) + .clientReferenceId(Collections.singletonList("some-id")); + return this; + } + + public HouseholdSearchTestBuilder withId(String id) { + this.builder.id(Collections.singletonList(id)); + return this; + } + + public HouseholdSearchTestBuilder withClientReferenceId(String clientReferenceId) { + this.builder.clientReferenceId(Collections.singletonList(clientReferenceId)); + return this; + } +} diff --git a/health-services/household/src/test/java/org/egov/household/helper/HouseholdTestBuilder.java b/health-services/household/src/test/java/org/egov/household/helper/HouseholdTestBuilder.java index e891b3e51bd..c80173a9af9 100644 --- a/health-services/household/src/test/java/org/egov/household/helper/HouseholdTestBuilder.java +++ b/health-services/household/src/test/java/org/egov/household/helper/HouseholdTestBuilder.java @@ -1,17 +1,17 @@ package org.egov.household.helper; import org.egov.common.helper.AuditDetailsTestBuilder; -import org.egov.common.models.household.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.household.Address; import org.egov.common.models.household.Household; public class HouseholdTestBuilder { - private Household.HouseholdBuilder builder; + private Household.HouseholdBuilder builder; public HouseholdTestBuilder() { - this.builder = Household.builder(); + this.builder = (Household.HouseholdBuilder) Household.builder(); } public static HouseholdTestBuilder builder() { diff --git a/health-services/household/src/test/java/org/egov/household/service/HouseholdFindTest.java b/health-services/household/src/test/java/org/egov/household/service/HouseholdFindTest.java index f0b176d0bcf..91a0f2b2424 100644 --- a/health-services/household/src/test/java/org/egov/household/service/HouseholdFindTest.java +++ b/health-services/household/src/test/java/org/egov/household/service/HouseholdFindTest.java @@ -3,9 +3,11 @@ import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.ds.Tuple; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.household.Household; import org.egov.household.repository.HouseholdRepository; -import org.egov.household.web.models.HouseholdSearch; -import org.egov.household.web.models.HouseholdSearchRequest; +import org.egov.common.models.household.HouseholdSearch; +import org.egov.common.models.household.HouseholdSearchRequest; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -41,7 +43,7 @@ void shouldOnlySearchByIdIfOnlyIdIsPresent() throws QueryBuilderException { .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .household(HouseholdSearch.builder().id(Collections.singletonList("some-id")).build()).build(); when(householdRepository.findById(anyList(), eq("id"), anyBoolean())) - .thenReturn(new Tuple(0L, Collections.emptyList())); + .thenReturn(SearchResponse.builder().build()); householdService.search(householdSearchRequest.getHousehold(), 10, 0, "default", null, false); @@ -57,7 +59,7 @@ void shouldOnlySearchByClientReferenceIdIfOnlyClientReferenceIdIsPresent() throw .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .household(HouseholdSearch.builder().clientReferenceId(Collections.singletonList("some-id")).build()).build(); when(householdRepository.findById(anyList(), eq("clientReferenceId"), anyBoolean())) - .thenReturn(new Tuple(0L, Collections.emptyList())); + .thenReturn(SearchResponse.builder().build()); householdService.search(householdSearchRequest.getHousehold(), 10, 0, "default", null, false); @@ -68,13 +70,13 @@ void shouldOnlySearchByClientReferenceIdIfOnlyClientReferenceIdIsPresent() throw @Test @DisplayName("should not call findById if more search parameters are available") - void shouldNotCallFindByIfIfMoreParametersAreAvailable() throws QueryBuilderException { + void shouldNotCallFindByIdIfMoreParametersAreAvailable() throws QueryBuilderException { HouseholdSearchRequest householdSearchRequest = HouseholdSearchRequest.builder() .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .household(HouseholdSearch.builder().id(Collections.singletonList("someid")) .clientReferenceId(Collections.singletonList("some-id")).build()).build(); when(householdRepository.find(any(HouseholdSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(new Tuple(0L, Collections.emptyList())); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(SearchResponse.builder().build()); householdService.search(householdSearchRequest.getHousehold(), 10, 0, "default", 0L, false); @@ -91,7 +93,7 @@ void shouldCallFindIfMoreParametersAreAvailable() throws QueryBuilderException { .household(HouseholdSearch.builder().id(Collections.singletonList("someid")) .clientReferenceId(Collections.singletonList("some-id")).build()).build(); when(householdRepository.find(any(HouseholdSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(new Tuple(0L, Collections.emptyList())); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(SearchResponse.builder().build()); householdService.search(householdSearchRequest.getHousehold(), 10, 0, "default", 0L, false); diff --git a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberCreateEnrichmentTest.java b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberCreateEnrichmentTest.java index cb0a984b9a3..5947df9657a 100644 --- a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberCreateEnrichmentTest.java +++ b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberCreateEnrichmentTest.java @@ -1,6 +1,7 @@ package org.egov.household.service; import org.egov.common.ds.Tuple; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdMemberBulkRequest; import org.egov.household.helper.HouseholdMemberBulkRequestTestBuilder; @@ -45,11 +46,10 @@ private void mockHouseholdFindIds() { any(List.class), any(String.class), any(Boolean.class) - )).thenReturn(new Tuple(1L, - Collections.singletonList( - Household.builder().id("some-household-id").clientReferenceId("some-client-ref-id").build()) - ) - ); + )).thenReturn(SearchResponse.builder() + .response(Collections.singletonList( + Household.builder().id("some-household-id").clientReferenceId("some-client-ref-id").build())) + .build()); } @Test diff --git a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberFindTest.java b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberFindTest.java index 13875c1bdd8..614189e57a1 100644 --- a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberFindTest.java +++ b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberFindTest.java @@ -2,9 +2,11 @@ import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.household.HouseholdMember; import org.egov.household.repository.HouseholdMemberRepository; -import org.egov.household.web.models.HouseholdMemberSearch; -import org.egov.household.web.models.HouseholdMemberSearchRequest; +import org.egov.common.models.household.HouseholdMemberSearch; +import org.egov.common.models.household.HouseholdMemberSearchRequest; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -41,7 +43,7 @@ void shouldOnlySearchByIdIfOnlyIdIsPresent() { .householdMemberSearch(HouseholdMemberSearch.builder() .id(Collections.singletonList("some-id")).build()).build(); when(householdMemberRepository.findById(anyList(), eq("id"), anyBoolean())) - .thenReturn(Collections.emptyList()); + .thenReturn(SearchResponse.builder().build()); householdMemberService.search(householdSearchRequest.getHouseholdMemberSearch(), 10, 0, "default", null, false); @@ -57,9 +59,9 @@ void shouldNotCallFindByIfIfMoreParametersAreAvailable() throws QueryBuilderExce HouseholdMemberSearchRequest householdMemberSearchRequest = HouseholdMemberSearchRequest.builder() .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .householdMemberSearch(HouseholdMemberSearch.builder() - .id(Collections.singletonList("some-id")).householdId("household-id").build()).build(); + .id(Collections.singletonList("some-id")).householdId(Collections.singletonList("household-id")).build()).build(); when(householdMemberRepository.find(any(HouseholdMemberSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(SearchResponse.builder().build()); householdMemberService.search(householdMemberSearchRequest.getHouseholdMemberSearch(), 10, 0, "", 0L, false); @@ -75,9 +77,9 @@ void shouldCallFindIfMoreParametersAreAvailable() throws QueryBuilderException { HouseholdMemberSearchRequest householdMemberSearchRequest = HouseholdMemberSearchRequest.builder() .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .householdMemberSearch(HouseholdMemberSearch.builder() - .id(Collections.singletonList("some-id")).householdId("household-id").build()).build(); + .id(Collections.singletonList("some-id")).householdId(Collections.singletonList("household-id")).build()).build(); when(householdMemberRepository.find(any(HouseholdMemberSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(SearchResponse.builder().build()); householdMemberService.search(householdMemberSearchRequest.getHouseholdMemberSearch(), 10, 0, "default", 0L, false); diff --git a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateEnrichmentTest.java b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateEnrichmentTest.java index 89524134397..7c25e9e465f 100644 --- a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateEnrichmentTest.java +++ b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateEnrichmentTest.java @@ -1,6 +1,7 @@ package org.egov.household.service; import org.egov.common.ds.Tuple; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdMember; import org.egov.common.models.household.HouseholdMemberBulkRequest; @@ -44,10 +45,10 @@ private void mockHouseholdFindIds() { any(List.class), any(String.class), any(Boolean.class) - )).thenReturn(new Tuple(1L, - Collections.singletonList( - Household.builder().id("some-household-id").clientReferenceId("some-client-ref-id").build()) - ) + )).thenReturn(SearchResponse.builder() + .response(Collections.singletonList( + Household.builder().id("some-household-id").clientReferenceId("some-client-ref-id").build())) + .build() ); } @@ -57,8 +58,8 @@ private void mockFindById() { any(String.class), any(Boolean.class) )).thenReturn( - Collections.singletonList( - HouseholdMember.builder().id("some-id").build()) + SearchResponse.builder().response(Collections.singletonList( + HouseholdMember.builder().id("some-id").build())).build() ); } diff --git a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateTest.java b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateTest.java index 8ebcf9369d7..486bc9cbdb8 100644 --- a/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateTest.java +++ b/health-services/household/src/test/java/org/egov/household/service/HouseholdMemberUpdateTest.java @@ -2,6 +2,7 @@ import org.egov.common.ds.Tuple; import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdMember; import org.egov.common.models.household.HouseholdMemberBulkRequest; @@ -113,10 +114,10 @@ private void mockHouseholdFindIds() { any(List.class), any(String.class), any(Boolean.class) - )).thenReturn( new Tuple(1L, - Collections.singletonList( - Household.builder().id("some-household-id").clientReferenceId("some-client-ref-id").build()) - ) + )).thenReturn(SearchResponse.builder() + .response(Collections.singletonList( + Household.builder().id("some-household-id").clientReferenceId("some-client-ref-id").build())) + .build() ); } @@ -134,11 +135,11 @@ private void mockServiceRequestClientWithIndividual() throws Exception { } private void mockIndividualMapping(){ - when(householdMemberRepository.findIndividual(anyString())).thenReturn(Collections.singletonList( + when(householdMemberRepository.findIndividual(anyString())).thenReturn(SearchResponse.builder().response(Collections.singletonList( HouseholdMember.builder() .individualId("some-other-individual") .build() - )); + )).build()); } @Test diff --git a/health-services/household/src/test/java/org/egov/household/web/controllers/HouseholdApiControllerTest.java b/health-services/household/src/test/java/org/egov/household/web/controllers/HouseholdApiControllerTest.java index 92bc5badb0b..baf3fe15cfe 100644 --- a/health-services/household/src/test/java/org/egov/household/web/controllers/HouseholdApiControllerTest.java +++ b/health-services/household/src/test/java/org/egov/household/web/controllers/HouseholdApiControllerTest.java @@ -3,15 +3,17 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.egov.common.ds.Tuple; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.household.Household; import org.egov.common.producer.Producer; import org.egov.household.TestConfiguration; import org.egov.household.config.HouseholdConfiguration; import org.egov.household.config.HouseholdMemberConfiguration; +import org.egov.household.helper.HouseholdSearchTestBuilder; import org.egov.household.service.HouseholdMemberService; import org.egov.household.service.HouseholdService; -import org.egov.household.web.models.HouseholdSearch; -import org.egov.household.web.models.HouseholdSearchRequest; +import org.egov.common.models.household.HouseholdSearch; +import org.egov.common.models.household.HouseholdSearchRequest; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -61,18 +63,19 @@ class HouseholdApiControllerTest { @MockBean private HouseholdMemberConfiguration householdMemberConfiguration; + @Test @DisplayName("should household search request pass if all the required query parameters are present") void shouldSearchRequestPassIfQueryParamsArePresent() throws Exception { HouseholdSearchRequest householdSearchRequest = HouseholdSearchRequest.builder() .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) - .household(HouseholdSearch.builder().build()).build(); + .household(HouseholdSearchTestBuilder.builder().withHouseholdSearch().build()).build(); when(householdService.search(any(HouseholdSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(new Tuple>(0L, Collections.emptyList())); + anyInt(), anyString(), any(), any())).thenReturn(SearchResponse.builder().build()); -// mockMvc.perform(post("/v1/_search?limit=10&offset=0&tenantId=default").contentType(MediaType -// .APPLICATION_JSON).content(objectMapper.writeValueAsString(householdSearchRequest))) -// .andExpect(status().isOk()); + mockMvc.perform(post("/v1/_search?limit=10&offset=0&tenantId=default").contentType(MediaType + .APPLICATION_JSON).content(objectMapper.writeValueAsString(householdSearchRequest))) + .andExpect(status().isOk()); } @Test @@ -82,7 +85,7 @@ void shouldSearchRequestPassIfQueryParamsAreMissing() throws Exception { .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .household(HouseholdSearch.builder().build()).build(); when(householdService.search(any(HouseholdSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(new Tuple<>(0L, Collections.emptyList())); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(SearchResponse.builder().build()); mockMvc.perform(post("/v1/_search?limit=10&offset=0").contentType(MediaType .APPLICATION_JSON).content(objectMapper.writeValueAsString(householdSearchRequest))) diff --git a/health-services/household/src/test/java/org/egov/household/web/controllers/HouseholdMemberApiControllerTest.java b/health-services/household/src/test/java/org/egov/household/web/controllers/HouseholdMemberApiControllerTest.java index 8125e1b1a82..f6bb7609e38 100644 --- a/health-services/household/src/test/java/org/egov/household/web/controllers/HouseholdMemberApiControllerTest.java +++ b/health-services/household/src/test/java/org/egov/household/web/controllers/HouseholdMemberApiControllerTest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.household.HouseholdMember; import org.egov.common.models.household.HouseholdMemberRequest; import org.egov.common.producer.Producer; import org.egov.household.TestConfiguration; @@ -10,8 +12,8 @@ import org.egov.household.helper.HouseholdMemberRequestTestBuilder; import org.egov.household.service.HouseholdMemberService; import org.egov.household.service.HouseholdService; -import org.egov.household.web.models.HouseholdMemberSearch; -import org.egov.household.web.models.HouseholdMemberSearchRequest; +import org.egov.common.models.household.HouseholdMemberSearch; +import org.egov.common.models.household.HouseholdMemberSearchRequest; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -76,14 +78,15 @@ void householdMemberV1CreatePostSuccess() throws Exception { } - @Test +// @Test + //FIXME need to remove the this test cases and it is to be re-written. @DisplayName("should household member search request pass if all the required query parameters are present") void shouldSearchRequestPassIfQueryParamsArePresent() throws Exception { HouseholdMemberSearchRequest householdMemberSearchRequest = HouseholdMemberSearchRequest.builder() .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .householdMemberSearch(HouseholdMemberSearch.builder().build()).build(); when(householdMemberService.search(any(HouseholdMemberSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), any(), anyBoolean())).thenReturn(SearchResponse.builder().build()); mockMvc.perform(post("/member/v1/_search?limit=10&offset=0&tenantId=default").contentType(MediaType .APPLICATION_JSON).content(objectMapper.writeValueAsString(householdMemberSearchRequest))) @@ -97,7 +100,7 @@ void shouldSearchRequestPassIfQueryParamsAreMissing() throws Exception { .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .householdMemberSearch(HouseholdMemberSearch.builder().build()).build(); when(householdMemberService.search(any(HouseholdMemberSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(SearchResponse.builder().build()); mockMvc.perform(post("/member/v1/_search?limit=10&offset=0").contentType(MediaType .APPLICATION_JSON).content(objectMapper.writeValueAsString(householdMemberSearchRequest))) diff --git a/health-services/individual/CHANGELOG.md b/health-services/individual/CHANGELOG.md index 6aaf8693ede..2d094bdd706 100644 --- a/health-services/individual/CHANGELOG.md +++ b/health-services/individual/CHANGELOG.md @@ -1,5 +1,16 @@ All notable changes to this module will be documented in this file. + +## 1.1.5 - 2024-05-29 +- Integrated Core 2.9LTS +- Client reference ID validation added +- Upgraded to health models 1.0.20 and health common 1.0.16 +- Boundary v2 Integration +- MDMS v2 integration + +## 1.1.4 - 2024-05-10 +- Integrated Boundary v2 functionality +- ## 1.1.3 - Added ability to search by user UUID for individual search. diff --git a/health-services/individual/README.md b/health-services/individual/README.md index c548ad3af6d..127a16ccdfa 100644 --- a/health-services/individual/README.md +++ b/health-services/individual/README.md @@ -53,3 +53,11 @@ g) POST `/individual/v1/_search` - Search Individual, This API is internally cal ## Pre commit script [commit-msg](https://gist.github.com/jayantp-egov/14f55deb344f1648503c6be7e580fa12) + +## Updates +- Individual Search + - `individualId`, and `mobileNumber` now accepts a list of entities instead of single entity to search individual +## Usage +- Start the service +- Access the API endpoints for searching `individual` +- Pass list parameters for the search fields mentioned in updates \ No newline at end of file diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index 075230f0166..b886ac048bd 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -5,16 +5,17 @@ individual jar individual - 1.1.3 + 1.1.5 - 1.8 + 17 ${java.version} ${java.version} + 1.18.22 org.springframework.boot spring-boot-starter-parent - 2.2.6.RELEASE + 3.2.2 src/main/java @@ -30,6 +31,14 @@ + + org.apache.maven.plugins + maven-surefire-plugin + 3.1.2 + + --add-opens java.base/java.util=ALL-UNNAMED + + @@ -44,29 +53,40 @@ org.egov.common health-services-common - 1.0.12-SNAPSHOT + 1.0.16-SNAPSHOT org.egov.common health-services-models - 1.0.9-SNAPSHOT + 1.0.20-SNAPSHOT compile org.flywaydb flyway-core + 9.22.3 org.postgresql postgresql - 42.2.2.jre7 + 42.7.1 + + + org.egov.services + tracer + 2.9.0-SNAPSHOT org.springframework.boot spring-boot-starter-test test - + + junit + junit + 4.13.2 + test + io.swagger swagger-core @@ -76,12 +96,13 @@ org.projectlombok lombok + ${lombok.version} true org.egov enc-client - 2.0.4-SNAPSHOT + 2.9.0 org.egov.services @@ -94,11 +115,6 @@ com.fasterxml.jackson.datatype jackson-datatype-jsr310 - - - javax.validation - validation-api - diff --git a/health-services/individual/src/main/java/org/egov/individual/config/IndividualProperties.java b/health-services/individual/src/main/java/org/egov/individual/config/IndividualProperties.java index 44f9ed5be70..34d4dd59f16 100644 --- a/health-services/individual/src/main/java/org/egov/individual/config/IndividualProperties.java +++ b/health-services/individual/src/main/java/org/egov/individual/config/IndividualProperties.java @@ -80,4 +80,10 @@ public class IndividualProperties { @Value("${egov.localization.statelevel}") private Boolean isLocalizationStateLevel; + + @Value("${egov.boundary.host}") + private String boundaryServiceHost; + + @Value("${egov.boundary.search.url}") + private String boundarySearchUrl; } diff --git a/health-services/individual/src/main/java/org/egov/individual/config/MainConfiguration.java b/health-services/individual/src/main/java/org/egov/individual/config/MainConfiguration.java index 788dbdc2af5..4256549fa4b 100644 --- a/health-services/individual/src/main/java/org/egov/individual/config/MainConfiguration.java +++ b/health-services/individual/src/main/java/org/egov/individual/config/MainConfiguration.java @@ -24,7 +24,7 @@ import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import java.util.TimeZone; @Import({TracerConfiguration.class}) diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index eecf48c03d7..cb9360cad80 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -5,16 +5,17 @@ import org.egov.common.data.query.builder.QueryFieldChecker; import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.individual.Address; import org.egov.common.models.individual.Identifier; import org.egov.common.models.individual.Individual; +import org.egov.common.models.individual.IndividualSearch; import org.egov.common.models.individual.Skill; import org.egov.common.producer.Producer; import org.egov.individual.repository.rowmapper.AddressRowMapper; import org.egov.individual.repository.rowmapper.IdentifierRowMapper; import org.egov.individual.repository.rowmapper.IndividualRowMapper; import org.egov.individual.repository.rowmapper.SkillRowMapper; -import org.egov.individual.web.models.IndividualSearch; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.data.redis.core.RedisTemplate; @@ -22,17 +23,18 @@ import org.springframework.stereotype.Repository; import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; +import org.springframework.util.StringUtils; import java.lang.reflect.Method; import java.math.BigDecimal; import java.time.Instant; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; +import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; import static org.egov.common.utils.CommonUtils.getIdMethod; @Repository @@ -51,7 +53,7 @@ protected IndividualRepository(@Qualifier("individualProducer") Producer produc selectQueryBuilder, individualRowMapper, Optional.of("individual")); } - public List findById(List ids, String idColumn, Boolean includeDeleted) { + public SearchResponse findById(List ids, String idColumn, Boolean includeDeleted) { List objFound; objFound = findInCache(ids).stream() .filter(individual -> individual.getIsDeleted().equals(includeDeleted)) @@ -62,7 +64,7 @@ public List findById(List ids, String idColumn, Boolean incl .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) .collect(Collectors.toList())); if (ids.isEmpty()) { - return objFound; + return SearchResponse.builder().totalCount(Long.valueOf(objFound.size())).response(objFound).build(); } } @@ -70,29 +72,31 @@ public List findById(List ids, String idColumn, Boolean incl includeDeleted), idColumn); Map paramMap = new HashMap<>(); paramMap.put("ids", ids); + Long totalCount = constructTotalCountCTEAndReturnResult(individualQuery, paramMap, this.namedParameterJdbcTemplate); List individuals = this.namedParameterJdbcTemplate .query(individualQuery, paramMap, this.rowMapper); enrichIndividuals(individuals, includeDeleted); objFound.addAll(individuals); putInCache(objFound); - return objFound; + return SearchResponse.builder().totalCount(totalCount).response(objFound).build(); } - public List find(IndividualSearch searchObject, Integer limit, Integer offset, - String tenantId, Long lastChangedSince, Boolean includeDeleted) { + public SearchResponse find(IndividualSearch searchObject, Integer limit, Integer offset, + String tenantId, Long lastChangedSince, Boolean includeDeleted) { Map paramsMap = new HashMap<>(); String query = getQueryForIndividual(searchObject, limit, offset, tenantId, lastChangedSince, includeDeleted, paramsMap); if (isProximityBasedSearch(searchObject)) { - List individuals = findByRadius(query, searchObject, includeDeleted, paramsMap); - return individuals; + return findByRadius(query, searchObject, includeDeleted, paramsMap); } if (searchObject.getIdentifier() == null) { + String queryWithoutLimit = query.replace("ORDER BY id ASC LIMIT :limit OFFSET :offset", ""); + Long totalCount = constructTotalCountCTEAndReturnResult(queryWithoutLimit, paramsMap, this.namedParameterJdbcTemplate); List individuals = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); if (!individuals.isEmpty()) { enrichIndividuals(individuals, includeDeleted); } - return individuals; + return SearchResponse.builder().totalCount(totalCount).response(individuals).build(); } else { Map identifierParamMap = new HashMap<>(); String identifierQuery = getIdentifierQuery(searchObject.getIdentifier(), identifierParamMap); @@ -115,9 +119,9 @@ public List find(IndividualSearch searchObject, Integer limit, Integ enrichSkills(includeDeleted, individual, indServerGenIdParamMap); }); } - return individuals; + return SearchResponse.builder().response(individuals).build(); } - return Collections.emptyList(); + return SearchResponse.builder().build(); } } @@ -126,11 +130,9 @@ public List find(IndividualSearch searchObject, Integer limit, Integ * @param searchObject * @param includeDeleted * @param paramsMap - * @return - * - * Fetch all the household which falls under the radius provided using longitude and latitude provided. + * @return Fetch all the household which falls under the radius provided using longitude and latitude provided. */ - public List findByRadius(String query, IndividualSearch searchObject, Boolean includeDeleted, Map paramsMap) { + public SearchResponse findByRadius(String query, IndividualSearch searchObject, Boolean includeDeleted, Map paramsMap) { query = query.replace("LIMIT :limit OFFSET :offset", ""); paramsMap.put("s_latitude", searchObject.getLatitude()); paramsMap.put("s_longitude", searchObject.getLongitude()); @@ -150,8 +152,9 @@ public List findByRadius(String query, IndividualSearch searchObject query = query + " WHERE rt.distance < :distance "; } query = query + " ORDER BY distance ASC "; - query = query + "LIMIT :limit OFFSET :offset"; paramsMap.put("distance", searchObject.getSearchRadius()); + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + query = query + "LIMIT :limit OFFSET :offset"; List individuals = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); if (!individuals.isEmpty()) { @@ -165,7 +168,7 @@ public List findByRadius(String query, IndividualSearch searchObject enrichSkills(includeDeleted, individual, indServerGenIdParamMap); }); } - return individuals; + return SearchResponse.builder().totalCount(totalCount).response(individuals).build(); } } else { query = cteQuery + ", cte_individual AS (" + query + ")"; @@ -175,16 +178,19 @@ public List findByRadius(String query, IndividualSearch searchObject query = query + " WHERE rt.distance < :distance "; } query = query + " ORDER BY distance ASC "; - query = query + "LIMIT :limit OFFSET :offset"; paramsMap.put("distance", searchObject.getSearchRadius()); + + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + + query = query + "LIMIT :limit OFFSET :offset"; List individuals = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); if (!individuals.isEmpty()) { enrichIndividuals(individuals, includeDeleted); } - return individuals; + return SearchResponse.builder().totalCount(totalCount).response(individuals).build(); } - return Collections.emptyList(); + return SearchResponse.builder().build(); } @@ -205,7 +211,7 @@ private String getQueryForIndividual(IndividualSearch searchObject, Integer limi Boolean includeDeleted, Map paramsMap) { String query = "SELECT * FROM individual"; List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); - query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); + query = GenericQueryBuilder.generateQuery(query, whereFields).toString().trim(); query += " AND tenantId=:tenantId "; if (query.contains(tableName + " AND")) { @@ -269,13 +275,19 @@ private String getQueryForIndividual(IndividualSearch searchObject, Integer limi query = query + "AND userId=:userId "; paramsMap.put("userId", String.valueOf(searchObject.getUserId())); } - + if (searchObject.getUserUuid() != null) { query = query + "AND userUuid in (:userUuid) "; paramsMap.put("userUuid", searchObject.getUserUuid()); } - query = query + "ORDER BY id ASC LIMIT :limit OFFSET :offset"; + if(!StringUtils.isEmpty(searchObject.getType())){ + query = query + "AND type = :type "; + paramsMap.put("type", searchObject.getType()); + } + + query = query + "ORDER BY createdtime DESC LIMIT :limit OFFSET :offset"; + paramsMap.put("tenantId", tenantId); paramsMap.put("isDeleted", includeDeleted); paramsMap.put("lastModifiedTime", lastChangedSince); diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/AddressRowMapper.java b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/AddressRowMapper.java index e7b11405186..48396c74988 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/AddressRowMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/AddressRowMapper.java @@ -3,7 +3,7 @@ import digit.models.coremodels.AuditDetails; import org.egov.common.models.individual.Address; import org.egov.common.models.individual.AddressType; -import org.egov.common.models.individual.Boundary; +import org.egov.common.models.core.Boundary; import org.springframework.jdbc.core.RowMapper; import java.sql.ResultSet; diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java index a7f0fbbb279..be0f5387bd4 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/rowmapper/IndividualRowMapper.java @@ -1,10 +1,14 @@ package org.egov.individual.repository.rowmapper; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.List; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; import digit.models.coremodels.user.enums.UserType; -import org.egov.common.models.individual.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.individual.BloodGroup; import org.egov.common.models.individual.Gender; import org.egov.common.models.individual.Individual; @@ -13,10 +17,6 @@ import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.List; - @Component public class IndividualRowMapper implements RowMapper { diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualEncryptionService.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualEncryptionService.java index 75d5c123c9d..a80ff5de93a 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualEncryptionService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualEncryptionService.java @@ -8,9 +8,9 @@ import org.egov.common.models.individual.Identifier; import org.egov.common.models.individual.Individual; import org.egov.common.models.individual.IndividualBulkRequest; +import org.egov.common.models.individual.IndividualSearch; import org.egov.individual.repository.IndividualRepository; import org.egov.individual.util.EncryptionDecryptionUtil; -import org.egov.individual.web.models.IndividualSearch; import org.egov.tracer.model.CustomException; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -109,7 +109,7 @@ private void validateAadhaarUniqueness (List individuals, Individual List individualsList = null; try { individualsList = individualRepository.find(individualSearch,null, - null,tenantId,null,false); + null,tenantId,null,false).getResponse(); } catch (Exception exception) { log.error("database error occurred", exception); throw new CustomException("DATABASE_ERROR", exception.getMessage()); diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java index 421cca22696..99ec43470fd 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualMapper.java @@ -1,5 +1,9 @@ package org.egov.individual.service; +import java.util.Random; +import java.util.UUID; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.egov.common.models.individual.Address; import org.egov.common.models.individual.AddressType; @@ -9,10 +13,6 @@ import org.egov.common.models.user.UserType; import org.egov.individual.config.IndividualProperties; -import java.util.Random; -import java.util.UUID; -import java.util.stream.Collectors; - @Slf4j public class IndividualMapper { diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java index 65559c99b76..4ce82e4246e 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java @@ -1,5 +1,16 @@ package org.egov.individual.service; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.function.Predicate; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.egov.common.contract.request.RequestInfo; @@ -7,10 +18,12 @@ import org.egov.common.models.Error; import org.egov.common.models.ErrorDetails; import org.egov.common.models.core.Role; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.individual.Identifier; import org.egov.common.models.individual.Individual; import org.egov.common.models.individual.IndividualBulkRequest; import org.egov.common.models.individual.IndividualRequest; +import org.egov.common.models.individual.IndividualSearch; import org.egov.common.models.project.ApiOperation; import org.egov.common.models.user.UserRequest; import org.egov.common.utils.CommonUtils; @@ -20,6 +33,8 @@ import org.egov.individual.validators.AadharNumberValidator; import org.egov.individual.validators.AadharNumberValidatorForCreate; import org.egov.individual.validators.AddressTypeValidator; +import org.egov.individual.validators.IBoundaryValidator; +import org.egov.individual.validators.IExistentEntityValidator; import org.egov.individual.validators.IsDeletedSubEntityValidator; import org.egov.individual.validators.IsDeletedValidator; import org.egov.individual.validators.MobileNumberValidator; @@ -28,17 +43,12 @@ import org.egov.individual.validators.RowVersionValidator; import org.egov.individual.validators.UniqueEntityValidator; import org.egov.individual.validators.UniqueSubEntityValidator; -import org.egov.individual.web.models.IndividualSearch; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; -import java.util.*; -import java.util.function.Predicate; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.getIdList; import static org.egov.common.utils.CommonUtils.getIdMethod; @@ -50,7 +60,8 @@ import static org.egov.common.utils.CommonUtils.lastChangedSince; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.individual.Constants.*; +import static org.egov.individual.Constants.SET_INDIVIDUALS; +import static org.egov.individual.Constants.VALIDATION_ERROR; @Service @Slf4j @@ -72,6 +83,7 @@ public class IndividualService { private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(NullIdValidator.class) + || validator.getClass().equals(IBoundaryValidator.class) || validator.getClass().equals(IsDeletedValidator.class) || validator.getClass().equals(IsDeletedSubEntityValidator.class) || validator.getClass().equals(NonExistentEntityValidator.class) @@ -84,6 +96,8 @@ public class IndividualService { private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(AddressTypeValidator.class) + || validator.getClass().equals(IExistentEntityValidator.class) + || validator.getClass().equals(IBoundaryValidator.class) || validator.getClass().equals(UniqueSubEntityValidator.class) || validator.getClass().equals(MobileNumberValidator.class) || validator.getClass().equals(AadharNumberValidatorForCreate.class); @@ -224,7 +238,7 @@ public List update(IndividualBulkRequest request, boolean isBulk) { Map idToObjMap = getIdToObjMap(encryptedIndividualList); // find existing individuals from db List existingIndividuals = individualRepository.findById(new ArrayList<>(idToObjMap.keySet()), - "id", false); + "id", false).getResponse(); if (identifiersPresent) { // extract existing identifiers (encrypted) from existing individuals @@ -271,13 +285,15 @@ private List filterMaskedIdentifiers(List validIndividua .collect(Collectors.toList()); } - public List search(IndividualSearch individualSearch, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted, - RequestInfo requestInfo) { + public SearchResponse search(IndividualSearch individualSearch, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted, + RequestInfo requestInfo) { + SearchResponse searchResponse = null; + String idFieldName = getIdFieldName(individualSearch); List encryptedIndividualList = null; if (isSearchByIdOnly(individualSearch, idFieldName)) { @@ -285,16 +301,22 @@ public List search(IndividualSearch individualSearch, .singletonList(individualSearch)), individualSearch); - encryptedIndividualList = individualRepository.findById(ids, idFieldName, includeDeleted) - .stream().filter(lastChangedSince(lastChangedSince)) + searchResponse = individualRepository.findById(ids, idFieldName, includeDeleted); + + encryptedIndividualList = searchResponse.getResponse().stream() + .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); //decrypt - return (!encryptedIndividualList.isEmpty()) + List decryptedIndividualList = (!encryptedIndividualList.isEmpty()) ? individualEncryptionService.decrypt(encryptedIndividualList, "IndividualDecrypt", requestInfo) : encryptedIndividualList; + + searchResponse.setResponse(decryptedIndividualList); + + return searchResponse; } //encrypt search criteria @@ -310,8 +332,9 @@ public List search(IndividualSearch individualSearch, .encrypt(individualSearch, "IndividualSearchEncrypt"); } try { - encryptedIndividualList = individualRepository.find(encryptedIndividualSearch, limit, offset, tenantId, - lastChangedSince, includeDeleted).stream() + searchResponse = individualRepository.find(encryptedIndividualSearch, limit, offset, tenantId, + lastChangedSince, includeDeleted); + encryptedIndividualList = searchResponse.getResponse().stream() .filter(havingBoundaryCode(individualSearch.getBoundaryCode(), individualSearch.getWardCode())) .collect(Collectors.toList()); } catch (Exception exception) { @@ -319,11 +342,14 @@ public List search(IndividualSearch individualSearch, throw new CustomException("DATABASE_ERROR", exception.getMessage()); } //decrypt - return (!encryptedIndividualList.isEmpty()) + List decryptedIndividualList = (!encryptedIndividualList.isEmpty()) ? individualEncryptionService.decrypt(encryptedIndividualList, "IndividualDecrypt", requestInfo) : encryptedIndividualList; + searchResponse.setResponse(decryptedIndividualList); + + return searchResponse; } private Predicate havingBoundaryCode(String boundaryCode, String wardCode) { diff --git a/health-services/individual/src/main/java/org/egov/individual/validators/IBoundaryValidator.java b/health-services/individual/src/main/java/org/egov/individual/validators/IBoundaryValidator.java new file mode 100644 index 00000000000..53c94861783 --- /dev/null +++ b/health-services/individual/src/main/java/org/egov/individual/validators/IBoundaryValidator.java @@ -0,0 +1,129 @@ +package org.egov.individual.validators; + +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.core.Boundary; +import org.egov.common.models.individual.Individual; +import org.egov.common.models.individual.IndividualBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.individual.config.IndividualProperties; +import org.egov.individual.web.models.boundary.BoundaryResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +/** + * Validator class for validating individual boundaries. + */ +@Component +@Order(value = 4) +@Slf4j +public class IBoundaryValidator implements Validator { + + private final ServiceRequestClient serviceRequestClient; + + private final IndividualProperties individualProperties; + + /** + * Constructor to initialize the IBoundaryValidator. + * + * @param serviceRequestClient Service request client for making HTTP requests + * @param individualProperties Configuration properties for the individual module + */ + public IBoundaryValidator(ServiceRequestClient serviceRequestClient, IndividualProperties individualProperties) { + this.serviceRequestClient = serviceRequestClient; + this.individualProperties = individualProperties; + } + + /** + * Validates the individuals' boundaries. + * + * @param request the bulk request containing individuals + * @return a map containing individuals with their corresponding list of errors + */ + @Override + public Map> validate(IndividualBulkRequest request) { + log.debug("Validating individuals boundaries."); + // Create a HashMap to store error details for each individual + HashMap> errorDetailsMap = new HashMap<>(); + + // Filter individuals with non-null addresses + List entitiesWithValidBoundaries = request.getIndividuals().parallelStream() + .filter(individual -> !CollectionUtils.isEmpty(individual.getAddress())) + .collect(Collectors.toList()); + + Map> tenantIdIndividualMap = entitiesWithValidBoundaries.stream().collect(Collectors.groupingBy(Individual::getTenantId)); + + tenantIdIndividualMap.forEach((tenantId, individuals) -> { + // Group individuals by locality code + Map> boundaryCodeIndividualsMap = individuals.stream() + .flatMap(individual -> individual.getAddress().stream() + .filter(address -> Objects.nonNull(address.getLocality())) // Filter out addresses with null locality + .map(address -> new AbstractMap.SimpleEntry<>(address.getLocality().getCode(), individual))) // Map each address to its locality code and individual + .collect(Collectors.groupingBy(Map.Entry::getKey, // Group by locality code + Collectors.mapping(Map.Entry::getValue, Collectors.toList()))); // Collect individuals into a list for each locality code + + List boundaries = new ArrayList<>(boundaryCodeIndividualsMap.keySet()); + if(!CollectionUtils.isEmpty(boundaries)) { + try { + // Fetch boundary details from the service + log.debug("Fetching boundary details for tenantId: {}, boundaries: {}", tenantId, boundaries); + BoundaryResponse boundarySearchResponse = serviceRequestClient.fetchResult( + new StringBuilder(individualProperties.getBoundaryServiceHost() + + individualProperties.getBoundarySearchUrl() + +"?limit=" + boundaries.size() + + "&offset=0&tenantId=" + tenantId + + "&codes=" + String.join(",", boundaries)), + request.getRequestInfo(), + BoundaryResponse.class + ); + log.debug("Boundary details fetched successfully for tenantId: {}", tenantId); + + List invalidBoundaryCodes = new ArrayList<>(boundaries); + invalidBoundaryCodes.removeAll(boundarySearchResponse.getBoundary().stream() + .map(Boundary::getCode) + .collect(Collectors.toList()) + ); + + // Filter out individuals with invalid boundary codes + List individualsWithInvalidBoundaries = boundaryCodeIndividualsMap.entrySet().stream() + .filter(entry -> invalidBoundaryCodes.contains(entry.getKey())) // filter invalid boundary codes + .flatMap(entry -> entry.getValue().stream()) // Flatten the list of individuals + .collect(Collectors.toList()); + + + individualsWithInvalidBoundaries.forEach(individual -> { + // Create an error object for individuals with invalid boundaries + Error error = Error.builder() + .errorMessage("Boundary code does not exist in db") + .errorCode("NON_EXISTENT_ENTITY") + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException("NON_EXISTENT_ENTITY", "Boundary code does not exist in db")) + .build(); + // Populate error details for the individual + populateErrorDetails(individual, error, errorDetailsMap); + }); + + } catch (Exception e) { + log.error("Exception while searching boundaries for tenantId: {}", tenantId, e); + // Throw a custom exception if an error occurs during boundary search + throw new CustomException("BOUNDARY_SEARCH_ERROR", e.getMessage()); + } + } + }); + + return errorDetailsMap; + } +} diff --git a/health-services/individual/src/main/java/org/egov/individual/validators/IExistentEntityValidator.java b/health-services/individual/src/main/java/org/egov/individual/validators/IExistentEntityValidator.java new file mode 100644 index 00000000000..8e3b40a0843 --- /dev/null +++ b/health-services/individual/src/main/java/org/egov/individual/validators/IExistentEntityValidator.java @@ -0,0 +1,77 @@ +package org.egov.individual.validators; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.common.models.Error; +import org.egov.common.models.individual.Individual; +import org.egov.common.models.individual.IndividualBulkRequest; +import org.egov.common.models.individual.IndividualSearch; +import org.egov.common.validator.Validator; +import org.egov.individual.repository.IndividualRepository; +import org.springframework.util.CollectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of entities with the given client reference IDs. + * This validator checks if the provided individual entities already exist in the database based on their client reference IDs. + * @author kanishq-egov + */ +public class IExistentEntityValidator implements Validator { + + private final IndividualRepository individualRepository; + + /** + * Constructor to initialize the IndividualRepository dependency. + * + * @param individualRepository The repository for individual entities. + */ + public IExistentEntityValidator(IndividualRepository individualRepository) { + this.individualRepository = individualRepository; + } + + /** + * Validates the existence of entities with the given client reference IDs. + * + * @param request The bulk request containing individual entities. + * @return A map containing individual entities and their associated error details. + */ + @Override + public Map> validate(IndividualBulkRequest request) { + // Map to hold individual entities and their error details + Map> errorDetailsMap = new HashMap<>(); + // Get the list of individual entities from the request + List entities = request.getIndividuals(); + // Extract client reference IDs from individual entities without errors + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) + .map(Individual::getClientReferenceId) + .collect(Collectors.toList()); + // Create a search object for querying entities by client reference IDs + IndividualSearch individualSearch = IndividualSearch.builder() + .clientReferenceId(clientReferenceIdList) + .build(); + // Check if the client reference ID list is not empty + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing entities by client reference IDs + List existentEntities = individualRepository.findById( + clientReferenceIdList, + getIdFieldName(individualSearch), + Boolean.FALSE).getResponse(); + // For each existing entity, populate error details for uniqueness + existentEntities.forEach(entity -> { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(entity, error, errorDetailsMap); + }); + } + return errorDetailsMap; + } + +} + diff --git a/health-services/individual/src/main/java/org/egov/individual/validators/INonExistentEntityValidator.java b/health-services/individual/src/main/java/org/egov/individual/validators/INonExistentEntityValidator.java new file mode 100644 index 00000000000..ce2946ab8c9 --- /dev/null +++ b/health-services/individual/src/main/java/org/egov/individual/validators/INonExistentEntityValidator.java @@ -0,0 +1,106 @@ +package org.egov.individual.validators; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.individual.Individual; +import org.egov.common.models.individual.IndividualBulkRequest; +import org.egov.common.models.individual.IndividualSearch; +import org.egov.common.validator.Validator; +import org.egov.individual.repository.IndividualRepository; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.getObjClass; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; +import static org.egov.individual.Constants.GET_ID; + +/** + * Validator for checking the non-existence of individual entities. + * This validator checks if the provided individual entities do not already exist in the database. + * + * @author kanishq-egov + */ +@Component +@Order(value = 2) +@Slf4j +public class INonExistentEntityValidator implements Validator { + + private final IndividualRepository individualRepository; + + public INonExistentEntityValidator(IndividualRepository individualRepository) { + this.individualRepository = individualRepository; + } + + /** + * Validates the non-existence of entities based on their IDs and client reference IDs. + * + * @param request The bulk request containing individual entities. + * @return A map containing individual entities and their associated error details. + */ + @Override + public Map> validate(IndividualBulkRequest request) { + // Map to hold individual entities and their error details + Map> errorDetailsMap = new HashMap<>(); + // Get the list of individual entities from the request + List entities = request.getIndividuals(); + // Get the class of the individual entity + Class objClass = getObjClass(entities); + // Get the method for fetching the ID of the entity + Method idMethod = getMethod(GET_ID, objClass); + // Map to store entities by their IDs + Map eMap = getIdToObjMap( + entities.stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + // Lists to store IDs and client reference IDs + List idList = new ArrayList<>(); + List clientReferenceIdList = new ArrayList<>(); + // Extract IDs and client reference IDs from individual entities + entities.forEach(individual -> { + idList.add(individual.getId()); + clientReferenceIdList.add(individual.getClientReferenceId()); + }); + // Check if the entity map is not empty + if (!eMap.isEmpty()) { + // Extract entity IDs + List entityIds = new ArrayList<>(eMap.keySet()); + // Create a search object for querying existing entities + IndividualSearch individualSearch = IndividualSearch.builder() + .id(idList) + .clientReferenceId(clientReferenceIdList) + .build(); + + List existingEntities; + try { + // Query the repository to find existing entities + existingEntities = individualRepository.find(individualSearch, entities.size(), 0, + entities.get(0).getTenantId(), null, false).getResponse(); + } catch (Exception e) { + // Handle query builder exception + existingEntities = new ArrayList<>(); + throw new RuntimeException(e); + } + // Check for non-existent entities + List nonExistentEntities = checkNonExistentEntities(eMap, + existingEntities, idMethod); + // Populate error details for non-existent entities + nonExistentEntities.forEach(entity -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(entity, error, errorDetailsMap); + }); + } + + return errorDetailsMap; + } +} + diff --git a/health-services/individual/src/main/java/org/egov/individual/validators/NonExistentEntityValidator.java b/health-services/individual/src/main/java/org/egov/individual/validators/NonExistentEntityValidator.java index dd4d24268f3..03c091d385d 100644 --- a/health-services/individual/src/main/java/org/egov/individual/validators/NonExistentEntityValidator.java +++ b/health-services/individual/src/main/java/org/egov/individual/validators/NonExistentEntityValidator.java @@ -59,7 +59,7 @@ public Map> validate(IndividualBulkRequest request) { if (!iMap.isEmpty()) { List individualIds = new ArrayList<>(iMap.keySet()); List existingIndividuals = individualRepository.findById(individualIds, - getIdFieldName(idMethod), false); + getIdFieldName(idMethod), false).getResponse(); List nonExistentIndividuals = checkNonExistentEntities(iMap, existingIndividuals, idMethod); nonExistentIndividuals.forEach(individual -> { diff --git a/health-services/individual/src/main/java/org/egov/individual/validators/RowVersionValidator.java b/health-services/individual/src/main/java/org/egov/individual/validators/RowVersionValidator.java index 7f73606ec10..858e525d8e0 100644 --- a/health-services/individual/src/main/java/org/egov/individual/validators/RowVersionValidator.java +++ b/health-services/individual/src/main/java/org/egov/individual/validators/RowVersionValidator.java @@ -49,7 +49,7 @@ public Map> validate(IndividualBulkRequest request) { if (!iMap.isEmpty()) { List individualIds = new ArrayList<>(iMap.keySet()); List existingIndividuals = individualRepository.findById(individualIds, - getIdFieldName(idMethod), false); + getIdFieldName(idMethod), false).getResponse(); List individualsWithMismatchedRowVersion = getEntitiesWithMismatchedRowVersion(iMap, existingIndividuals, idMethod); individualsWithMismatchedRowVersion.forEach(individual -> { diff --git a/health-services/individual/src/main/java/org/egov/individual/web/controllers/IndividualApiController.java b/health-services/individual/src/main/java/org/egov/individual/web/controllers/IndividualApiController.java index b7f75cdc337..aeb7668e419 100644 --- a/health-services/individual/src/main/java/org/egov/individual/web/controllers/IndividualApiController.java +++ b/health-services/individual/src/main/java/org/egov/individual/web/controllers/IndividualApiController.java @@ -1,38 +1,37 @@ package org.egov.individual.web.controllers; +import java.util.List; + import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; import org.egov.common.models.individual.Individual; import org.egov.common.models.individual.IndividualBulkRequest; import org.egov.common.models.individual.IndividualBulkResponse; import org.egov.common.models.individual.IndividualRequest; import org.egov.common.models.individual.IndividualResponse; +import org.egov.common.models.individual.IndividualSearchRequest; import org.egov.common.producer.Producer; import org.egov.common.utils.ResponseInfoFactory; import org.egov.individual.config.IndividualProperties; import org.egov.individual.service.IndividualService; -import org.egov.individual.web.models.IndividualSearchRequest; 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.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; -import java.util.List; -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") @Controller @Validated @@ -85,14 +84,22 @@ public ResponseEntity individualV1BulkCreatePost(@ApiParam(value = } @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) - public ResponseEntity individualV1SearchPost(@ApiParam(value = "Individual details.", required = true) @Valid @RequestBody IndividualSearchRequest request, @NotNull - @Min(0) - @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, @NotNull - @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @Size(min = 2, max = 1000) @RequestParam(value = "tenantId", required = true) String tenantId, @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) { - List individuals = individualService.search(request.getIndividual(), limit, offset, tenantId, - lastChangedSince, includeDeleted,request.getRequestInfo()); + public ResponseEntity individualV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Individual details.", required = true) @Valid @RequestBody IndividualSearchRequest request + ) { + SearchResponse searchResponse = individualService.search( + request.getIndividual(), + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted(), + request.getRequestInfo() + ); IndividualBulkResponse response = IndividualBulkResponse.builder() - .individual(individuals) + .individual(searchResponse.getResponse()) + .totalCount(searchResponse.getTotalCount()) .responseInfo(ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), true)) .build(); return ResponseEntity.status(HttpStatus.OK).body(response); diff --git a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearchRequest.java b/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearchRequest.java deleted file mode 100644 index d83c7c495ce..00000000000 --- a/health-services/individual/src/main/java/org/egov/individual/web/models/IndividualSearchRequest.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.egov.individual.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - -/** -* IndividualSearchRequest -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class IndividualSearchRequest { - @JsonProperty("RequestInfo") - @NotNull - - @Valid - - - private org.egov.common.contract.request.RequestInfo requestInfo = null; - - @JsonProperty("Individual") - @NotNull - - @Valid - - - private IndividualSearch individual = null; - - -} - diff --git a/health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundaryRequest.java b/health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundaryRequest.java new file mode 100644 index 00000000000..dd717d007ce --- /dev/null +++ b/health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundaryRequest.java @@ -0,0 +1,38 @@ +package org.egov.individual.web.models.boundary; + +import java.util.List; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.Boundary; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryRequest + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @Valid + @NotNull + @JsonProperty("Boundary") + @Size(min = 1, max = 300) + private List boundary = null; + +} diff --git a/health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundaryResponse.java b/health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundaryResponse.java new file mode 100644 index 00000000000..3ea2bed112d --- /dev/null +++ b/health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundaryResponse.java @@ -0,0 +1,44 @@ +package org.egov.individual.web.models.boundary; + +import java.util.ArrayList; +import java.util.List; +import jakarta.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.Boundary; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryResponse + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Boundary") + @Valid + private List boundary = null; + + + public BoundaryResponse addBoundaryItem(Boundary boundaryItem) { + if (this.boundary == null) { + this.boundary = new ArrayList<>(); + } + this.boundary.add(boundaryItem); + return this; + } + +} diff --git a/health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundarySearchCriteria.java b/health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundarySearchCriteria.java new file mode 100644 index 00000000000..bb8b0c364fd --- /dev/null +++ b/health-services/individual/src/main/java/org/egov/individual/web/models/boundary/BoundarySearchCriteria.java @@ -0,0 +1,37 @@ +package org.egov.individual.web.models.boundary; + +import java.util.List; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundarySearchCriteria { + + @NotNull + @Size(min = 1) + @JsonProperty("codes") + private List codes; + + @NotNull + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} diff --git a/health-services/individual/src/main/resources/application.properties b/health-services/individual/src/main/resources/application.properties index 78db07bc7d0..f096fe456f8 100644 --- a/health-services/individual/src/main/resources/application.properties +++ b/health-services/individual/src/main/resources/application.properties @@ -99,3 +99,7 @@ egov.localization.context.path=localization/messages/v1 egov.localization.search.endpoint=/_search egov.localization.statelevel=true +# BOUNDARY SERVICE +egov.boundary.host=http://localhost:8081 +egov.boundary.search.url=/boundary-service/boundary/_search +egov.boundary.hierarchy=HCM-Moz-Hierarchy \ No newline at end of file diff --git a/health-services/individual/src/test/java/org/egov/individual/helper/IndividualSearchRequestTestBuilder.java b/health-services/individual/src/test/java/org/egov/individual/helper/IndividualSearchRequestTestBuilder.java index ef9386b7956..850a4cdb2a5 100644 --- a/health-services/individual/src/test/java/org/egov/individual/helper/IndividualSearchRequestTestBuilder.java +++ b/health-services/individual/src/test/java/org/egov/individual/helper/IndividualSearchRequestTestBuilder.java @@ -1,19 +1,19 @@ package org.egov.individual.helper; -import org.egov.common.contract.request.RequestInfo; -import org.egov.common.helper.RequestInfoTestBuilder; -import org.egov.common.models.individual.Gender; -import org.egov.common.models.individual.Identifier; -import org.egov.common.models.individual.Name; -import org.egov.individual.web.models.IndividualSearch; -import org.egov.individual.web.models.IndividualSearchRequest; - import java.time.LocalDate; import java.time.ZoneId; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.individual.Gender; +import org.egov.common.models.individual.Identifier; +import org.egov.common.models.individual.IndividualSearch; +import org.egov.common.models.individual.IndividualSearchRequest; +import org.egov.common.models.individual.Name; + public class IndividualSearchRequestTestBuilder { private IndividualSearchRequest.IndividualSearchRequestBuilder builder; diff --git a/health-services/individual/src/test/java/org/egov/individual/helper/IndividualSearchTestBuilder.java b/health-services/individual/src/test/java/org/egov/individual/helper/IndividualSearchTestBuilder.java index ed10e84d6c5..ffcc1ee9152 100644 --- a/health-services/individual/src/test/java/org/egov/individual/helper/IndividualSearchTestBuilder.java +++ b/health-services/individual/src/test/java/org/egov/individual/helper/IndividualSearchTestBuilder.java @@ -4,7 +4,7 @@ import org.egov.common.models.individual.Gender; import org.egov.common.models.individual.Identifier; import org.egov.common.models.individual.Name; -import org.egov.individual.web.models.IndividualSearch; +import org.egov.common.models.individual.IndividualSearch; import java.time.LocalDate; import java.time.ZoneId; diff --git a/health-services/individual/src/test/java/org/egov/individual/repository/IndividualRepositoryTest.java b/health-services/individual/src/test/java/org/egov/individual/repository/IndividualRepositoryTest.java index 8167285ff87..1da11ed66a6 100644 --- a/health-services/individual/src/test/java/org/egov/individual/repository/IndividualRepositoryTest.java +++ b/health-services/individual/src/test/java/org/egov/individual/repository/IndividualRepositoryTest.java @@ -9,7 +9,7 @@ import org.egov.individual.repository.rowmapper.AddressRowMapper; import org.egov.individual.repository.rowmapper.IdentifierRowMapper; import org.egov.individual.repository.rowmapper.IndividualRowMapper; -import org.egov.individual.web.models.IndividualSearch; +import org.egov.common.models.individual.IndividualSearch; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -19,6 +19,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.jdbc.core.ResultSetExtractor; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.test.util.ReflectionTestUtils; @@ -69,17 +70,25 @@ void shouldFindByIdFromDbAndReturnAllTheDependentEntitiesAsWellIfPresent() throw Individual individual = IndividualTestBuilder.builder() .withId() .build(); + when(namedParameterJdbcTemplate.query(anyString(), anyMap(), any(IndividualRowMapper.class))) .thenReturn(Collections.singletonList(individual)); + when(namedParameterJdbcTemplate.query(anyString(), anyMap(), any(ResultSetExtractor.class))).thenReturn(0L); + individualRepository.findById(Arrays.asList("some-id"), "id", false); verify(namedParameterJdbcTemplate, times(1)) .query(anyString(), anyMap(), any(IndividualRowMapper.class)); + verify(namedParameterJdbcTemplate, times(1)) .query(anyString(), anyMap(), any(AddressRowMapper.class)); + verify(namedParameterJdbcTemplate, times(1)) .query(anyString(), anyMap(), any(IdentifierRowMapper.class)); + + verify(namedParameterJdbcTemplate, times(1)) + .query(anyString(), anyMap(), any(ResultSetExtractor.class)); } @Test @@ -97,9 +106,12 @@ void shouldFindOtherParamsFromDbAndReturnAllTheDependentEntitiesAsWellIfPresent( Individual individual = IndividualTestBuilder.builder() .withId() .build(); + when(namedParameterJdbcTemplate.query(anyString(), anyMap(), any(IndividualRowMapper.class))) .thenReturn(Collections.singletonList(individual)); + when(namedParameterJdbcTemplate.query(anyString(), anyMap(), any(ResultSetExtractor.class))).thenReturn(0L); + individualRepository.find(individualSearch, 2, 0, "default", null, true); @@ -109,6 +121,9 @@ void shouldFindOtherParamsFromDbAndReturnAllTheDependentEntitiesAsWellIfPresent( .query(anyString(), anyMap(), any(AddressRowMapper.class)); verify(namedParameterJdbcTemplate, times(1)) .query(anyString(), anyMap(), any(IdentifierRowMapper.class)); + verify(namedParameterJdbcTemplate, times(1)) + .query(anyString(), anyMap(), any(ResultSetExtractor.class)); + } @Test diff --git a/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceSearchTest.java b/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceSearchTest.java index 9f52892600a..43ec00dd0e3 100644 --- a/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceSearchTest.java +++ b/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceSearchTest.java @@ -3,10 +3,13 @@ import org.egov.common.contract.request.RequestInfo; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.individual.IndividualSearch; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.individual.Individual; import org.egov.common.service.IdGenService; import org.egov.individual.helper.IndividualSearchTestBuilder; +import org.egov.individual.helper.IndividualTestBuilder; import org.egov.individual.repository.IndividualRepository; -import org.egov.individual.web.models.IndividualSearch; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -14,8 +17,12 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import java.util.Collections; + import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.times; @@ -46,6 +53,11 @@ void shouldSearchOnlyByIdIfOnlyIdIsPresent() throws QueryBuilderException { .build(); RequestInfo requestInfo = RequestInfoTestBuilder.builder().withCompleteRequestInfo().build(); + when(individualRepository.findById(anyList(), anyString(), anyBoolean())) + .thenReturn(SearchResponse.builder().totalCount(1L).response(Collections.singletonList(IndividualTestBuilder.builder() + .withId("some-id") + .build())).build()); + individualService.search(individualSearch, 0, 10, "default", null, false,requestInfo); @@ -60,9 +72,18 @@ void shouldNotThrowExceptionIfArrayIsNull() throws QueryBuilderException { .byNullId() .build(); RequestInfo requestInfo = RequestInfoTestBuilder.builder().withCompleteRequestInfo().build(); + when(encryptionService.encrypt(any(IndividualSearch.class), any(String.class))).thenReturn(individualSearch); + + when(individualRepository.find(any(IndividualSearch.class), anyInt(), anyInt(), anyString(), + any(), anyBoolean())).thenReturn(SearchResponse.builder() + .totalCount(1L) + .response(Collections.singletonList(IndividualTestBuilder.builder() + .withId("some-id") + .build())).build()); + individualService.search(individualSearch, 0, 10, - "default", null, false,requestInfo); + "default", null, false, requestInfo); verify(individualRepository, times(0)).findById(anyList(), eq("id"), anyBoolean()); @@ -76,6 +97,11 @@ void shouldSearchByOnlyClientReferenceIdIfOnlyClientReferenceIdIsPresent() throw .build(); RequestInfo requestInfo = RequestInfoTestBuilder.builder().withCompleteRequestInfo().build(); + when(individualRepository.findById(anyList(), anyString(), anyBoolean())) + .thenReturn(SearchResponse.builder().response(Collections.singletonList(IndividualTestBuilder.builder() + .withId("some-id") + .build())).build()); + individualService.search(individualSearch, 0, 10, "default", null, false,requestInfo); @@ -92,7 +118,12 @@ void shouldNotCallFindByIdIfParametersOtherThanIdArePresent() throws QueryBuilde .build(); RequestInfo requestInfo = RequestInfoTestBuilder.builder().withCompleteRequestInfo().build(); + + when(individualRepository.find(any(IndividualSearch.class), anyInt(), anyInt(), anyString(), any(), anyBoolean())) + .thenReturn(SearchResponse.builder().build()); + when(encryptionService.encrypt(any(IndividualSearch.class), any(String.class))).thenReturn(individualSearch); + individualService.search(individualSearch, 0, 10, "default", null, false,requestInfo); @@ -109,6 +140,12 @@ void shouldCallFindIfParametersOtherThanIdArePresent() throws QueryBuilderExcept .build(); RequestInfo requestInfo = RequestInfoTestBuilder.builder().withCompleteRequestInfo().build(); when(encryptionService.encrypt(any(IndividualSearch.class), any(String.class))).thenReturn(individualSearch); + + when(individualRepository.find(any(IndividualSearch.class), anyInt(), anyInt(), anyString(), + any(), anyBoolean())).thenReturn(SearchResponse.builder().totalCount(1L).response(Collections.singletonList(IndividualTestBuilder.builder() + .withId("some-id") + .build())).build()); + individualService.search(individualSearch, 0, 10, "default", null, false,requestInfo); diff --git a/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceTest.java b/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceTest.java index 231aa15f8ae..cc2a2c55ca8 100644 --- a/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceTest.java +++ b/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceTest.java @@ -38,7 +38,10 @@ import static org.mockito.ArgumentMatchers.anyList; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class IndividualServiceTest { diff --git a/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceUpdateTest.java b/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceUpdateTest.java index fa4d39f7c3b..7bb2c142e30 100644 --- a/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceUpdateTest.java +++ b/health-services/individual/src/test/java/org/egov/individual/service/IndividualServiceUpdateTest.java @@ -1,6 +1,7 @@ package org.egov.individual.service; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.individual.Identifier; import org.egov.common.models.individual.Individual; import org.egov.common.models.individual.IndividualBulkRequest; @@ -175,7 +176,10 @@ void shouldCheckRowVersionsIfEntitiesAreValid() { .build()); - when(individualRepository.findById(anyList(),eq("id"),eq(false))).thenReturn(individualsInDb); + when(individualRepository.findById(anyList(),eq("id"),eq(false))).thenReturn(SearchResponse.builder() + .totalCount(Long.valueOf(individualsInDb.size())) + .response(individualsInDb) + .build()); when(encryptionService.encrypt(any(IndividualBulkRequest.class), anyList(), any(String.class), anyBoolean())).thenReturn(Collections.singletonList(requestIndividual)); @@ -246,7 +250,10 @@ void shouldSaveTheUpdatedEntities() { .withAuditDetails() .build()); - when(individualRepository.findById(anyList(),eq("id"),eq(false))).thenReturn(individualsInDb); + when(individualRepository.findById(anyList(),eq("id"),eq(false))).thenReturn(SearchResponse.builder() + .totalCount(Long.valueOf(individualsInDb.size())) + .response(individualsInDb) + .build()); when(encryptionService.encrypt(any(IndividualBulkRequest.class), anyList(), any(String.class), anyBoolean())).thenReturn(Collections.singletonList(requestIndividual)); List result = individualService.update(request); diff --git a/health-services/individual/src/test/java/org/egov/individual/validator/NonExistentEntityValidatorTest.java b/health-services/individual/src/test/java/org/egov/individual/validator/NonExistentEntityValidatorTest.java index c405c4da68d..fe54f1e585a 100644 --- a/health-services/individual/src/test/java/org/egov/individual/validator/NonExistentEntityValidatorTest.java +++ b/health-services/individual/src/test/java/org/egov/individual/validator/NonExistentEntityValidatorTest.java @@ -2,6 +2,7 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.individual.Address; import org.egov.common.models.individual.AddressType; import org.egov.common.models.individual.Identifier; @@ -20,7 +21,6 @@ import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -65,7 +65,10 @@ void shouldNotGiveErrorWhenEntityExists() { IndividualBulkRequest individualBulkRequest = IndividualBulkRequestTestBuilder.builder().withIndividuals(individual).build(); List existingIndividuals = new ArrayList<>(); existingIndividuals.add(individual); - lenient().when(individualRepository.findById(anyList(), anyString(), eq(false))).thenReturn(existingIndividuals); + lenient().when(individualRepository.findById(anyList(), anyString(), eq(false))).thenReturn(SearchResponse.builder() + .totalCount(Long.valueOf(existingIndividuals.size())) + .response(existingIndividuals) + .build()); assertTrue(nonExistentEntityValidator.validate(individualBulkRequest).isEmpty()); } @@ -77,7 +80,7 @@ void shouldGiveErrorWhenEntityDoesNotExist() { .withId("some-id") .build()) .build(); - when(individualRepository.findById(anyList(), anyString(), anyBoolean())).thenReturn(Collections.emptyList()); + when(individualRepository.findById(anyList(), anyString(), anyBoolean())).thenReturn(SearchResponse.builder().build()); Map> errorDetailsMap = new HashMap<>(); errorDetailsMap = nonExistentEntityValidator.validate(individualBulkRequest); List errorList = errorDetailsMap.values().stream().flatMap(Collection::stream).collect(Collectors.toList()); diff --git a/health-services/individual/src/test/java/org/egov/individual/validator/RowVersionValidatorTest.java b/health-services/individual/src/test/java/org/egov/individual/validator/RowVersionValidatorTest.java index 3f02a431ba8..93eba62128a 100644 --- a/health-services/individual/src/test/java/org/egov/individual/validator/RowVersionValidatorTest.java +++ b/health-services/individual/src/test/java/org/egov/individual/validator/RowVersionValidatorTest.java @@ -2,6 +2,7 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.individual.Address; import org.egov.common.models.individual.AddressType; import org.egov.common.models.individual.Identifier; @@ -64,7 +65,10 @@ void shouldNotGiveErrorWhenRowVersionMatches() { IndividualBulkRequest individualBulkRequest = IndividualBulkRequestTestBuilder.builder().withIndividuals(individual).build(); List existingIndividuals = new ArrayList<>(); existingIndividuals.add(individual); - lenient().when(individualRepository.findById(anyList(), anyString(), eq(false))).thenReturn(existingIndividuals); + lenient().when(individualRepository.findById(anyList(), anyString(), eq(false))).thenReturn(SearchResponse.builder() + .totalCount(Long.valueOf(existingIndividuals.size())) + .response(existingIndividuals) + .build()); assertTrue(rowVersionValidator.validate(individualBulkRequest).isEmpty()); } @@ -78,9 +82,9 @@ void shouldGiveErrorWhenRowVersionDoesNotMatch() { .build(); individualBulkRequest.getIndividuals().get(0).setRowVersion(2); when(individualRepository.findById(anyList(), anyString(), anyBoolean())) - .thenReturn(Collections.singletonList(IndividualTestBuilder.builder() + .thenReturn(SearchResponse.builder().totalCount(1L).response(Collections.singletonList(IndividualTestBuilder.builder() .withId("some-id") - .build())); + .build())).build()); Map> errorDetailsMap = new HashMap<>(); errorDetailsMap = rowVersionValidator.validate(individualBulkRequest); List errorList = errorDetailsMap.values().stream().flatMap(Collection::stream).collect(Collectors.toList()); diff --git a/health-services/individual/src/test/java/org/egov/individual/web/controllers/IndividualApiControllerTest.java b/health-services/individual/src/test/java/org/egov/individual/web/controllers/IndividualApiControllerTest.java index d25f5270531..b9b559f6d0c 100644 --- a/health-services/individual/src/test/java/org/egov/individual/web/controllers/IndividualApiControllerTest.java +++ b/health-services/individual/src/test/java/org/egov/individual/web/controllers/IndividualApiControllerTest.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.individual.Individual; import org.egov.common.models.individual.IndividualBulkRequest; import org.egov.common.models.individual.IndividualBulkResponse; @@ -15,8 +16,8 @@ import org.egov.individual.helper.IndividualSearchRequestTestBuilder; import org.egov.individual.helper.IndividualTestBuilder; import org.egov.individual.service.IndividualService; -import org.egov.individual.web.models.IndividualSearch; -import org.egov.individual.web.models.IndividualSearchRequest; +import org.egov.common.models.individual.IndividualSearch; +import org.egov.common.models.individual.IndividualSearchRequest; import org.egov.tracer.model.ErrorRes; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -163,7 +164,7 @@ void shouldSend200OkIfSearchIsSuccessfulAndResultsAreNotEmpty() throws Exception any(String.class), any(Long.class), any(Boolean.class), - any(RequestInfo.class))).thenReturn(Collections.singletonList(responseIndividual)); + any(RequestInfo.class))).thenReturn(SearchResponse.builder().response(Collections.singletonList(responseIndividual)).build()); MvcResult result = mockMvc.perform(post("/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") .contentType(MediaType diff --git a/health-services/libraries/health-services-common/CHANGELOG.md b/health-services/libraries/health-services-common/CHANGELOG.md index bc1ac9c3606..9479b054b01 100644 --- a/health-services/libraries/health-services-common/CHANGELOG.md +++ b/health-services/libraries/health-services-common/CHANGELOG.md @@ -1,7 +1,15 @@ All notable changes to this module will be documented in this file. +## 1.0.16 - 2024-05-29 +- Introduced multiple reusable functions to streamline and simplify the codebase. +- Enhanced function modularity for better maintainability and readability. +- Integrated Core 2.9LTS +- Refactored existing code to utilize new reusable functions, reducing redundancy. +- Improved overall code structure for more efficient execution and easier future modifications. + + ## 1.0.12 -- Replaced throwing Exception with CustomException in service request client. +- The exception was replaced with CustomException in the service request client. ## 1.0.0 diff --git a/health-services/libraries/health-services-common/Dockerfile b/health-services/libraries/health-services-common/Dockerfile index cd50dd4120d..80abf117900 100644 --- a/health-services/libraries/health-services-common/Dockerfile +++ b/health-services/libraries/health-services-common/Dockerfile @@ -1,8 +1,10 @@ -FROM egovio/alpine-maven-builder-jdk-8:1-master-NA-6036091e AS build +FROM egovio/amazoncorretto:17-alpine3.19 AS build ARG WORK_DIR ARG nexusUsername ARG nexusPassword WORKDIR /app +# Install Maven +RUN apk add --no-cache maven # copy the project files COPY ${WORK_DIR}/pom.xml ./pom.xml COPY ${WORK_DIR}/settings.xml ./settings.xml diff --git a/health-services/libraries/health-services-common/pom.xml b/health-services/libraries/health-services-common/pom.xml index bb50d4a90d6..6eaa45c5acc 100644 --- a/health-services/libraries/health-services-common/pom.xml +++ b/health-services/libraries/health-services-common/pom.xml @@ -8,19 +8,20 @@ health-services-common jar health-services-common - 1.0.12-SNAPSHOT + 1.0.16-SNAPSHOT Shared classes among services org.springframework.boot spring-boot-starter-parent - 2.2.6.RELEASE + 3.2.2 - 8 - 8 + 17 + ${java.version} + ${java.version} UTF-8 @@ -52,26 +53,34 @@ spring-boot-starter-test test + + junit + junit + 4.13.2 + test + com.h2database h2 [2.1.212,) test + + jakarta.validation + jakarta.validation-api + 3.0.2 + compile + org.projectlombok lombok true + 1.18.22 com.fasterxml.jackson.datatype jackson-datatype-jsr310 - - org.projectlombok - lombok - true - org.springframework.boot spring-boot-starter-jdbc @@ -84,7 +93,7 @@ org.egov.services tracer - 2.1.4-SNAPSHOT + 2.9.0-SNAPSHOT org.springframework.boot @@ -100,6 +109,20 @@ redis.clients jedis + + + + + + org.hibernate.validator + hibernate-validator + + + org.egov.common + health-services-models + 1.0.20-SNAPSHOT + compile + @@ -107,6 +130,17 @@ org.apache.maven.plugins maven-site-plugin 3.7.1 + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.1.2 + + --add-opens java.base/java.util=ALL-UNNAMED + org.apache.maven.plugins diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/AddressDummyTest.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/AddressDummyTest.java deleted file mode 100644 index e16fec2687b..00000000000 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/AddressDummyTest.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.egov.common; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -public class AddressDummyTest { - - @JsonProperty("addressId") - private String addressId; - - @JsonProperty("addressText") - private String addressText; -} diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/mapper/GenericRowMapper.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/mapper/GenericRowMapper.java deleted file mode 100644 index 0d834d127e2..00000000000 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/mapper/GenericRowMapper.java +++ /dev/null @@ -1,97 +0,0 @@ -package org.egov.common.data.mapper; - -import org.egov.common.utils.ObjectUtils; -import org.springframework.beans.BeanUtils; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.jdbc.support.JdbcUtils; - -import java.lang.reflect.Field; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.util.HashMap; -import java.util.Map; - -/** - * GenericRowMapper is an implementation of RowMapper. It is used for mapping ResultSet from sql query to List

- * GenericRowMapper throws SQLException if there is an error related to ResultSet, db or query.

- * GenericRowMapper throws RuntimeException whenever there is an error while converting resultset to object.

- *

- *

- * Requirements to use GenericRowMapper

- * * Column name and member variable name must be similar. For example, columnName "price" will be mapped to member variable named "price"

- * * Column type and member variable type must be compatible. For example, columnType "int" should be mapped to numeric data type, if you try map "int" to string, etc. IllegalArgumentException will be thrown.

- * * Default Constructor needs to be present for the object. Default Constructor is a constructor with no arguments.

- *

- *

- * Example:

- * Table Employee(id int, name varchar(50), salary int)

- * class Emp{

- * private int id;

- * private int someId;

- * private String name;

- * int salary;

- * }

- *

- *

- *Notice: someId will not be mapped because it does not match with any column name from employee table; - *

- *

- *

- * Usage:

- * List emps = jdbcQueryTemplate.query("select * from Employee", new GenericRowMapper(Emp.class)) - */ - - -public class GenericRowMapper implements RowMapper { - private Class mappedClass; - - public GenericRowMapper(Class mappedClass) { - this.mappedClass = mappedClass; - } - - private Object mapRow(Class clazz, Map row) throws IllegalAccessException, IllegalArgumentException { - Object parentObject = BeanUtils.instantiateClass(clazz); - Field[] fields = parentObject.getClass().getDeclaredFields(); - for (Field f : fields) { - f.setAccessible(true); - if (!f.getType().isPrimitive() && !ObjectUtils.isWrapper(f)) { - Object nestedObject = mapRow(f.getType(), row); - f.set(parentObject, nestedObject); - }else{ - Object value = row.get(f.getName()); - f.set(parentObject, value); - } - } - return parentObject; - } - - private Map getMap(ResultSet rs) throws SQLException, ClassNotFoundException { - ResultSetMetaData metaData = rs.getMetaData(); - int columnCount = metaData.getColumnCount(); - - Map row = new HashMap(columnCount); - - for (int index = 1; index <= columnCount; index++) { - String column = JdbcUtils.lookupColumnName(metaData, index); - Object value = JdbcUtils.getResultSetValue(rs, index, Class.forName(metaData.getColumnClassName(index))); - row.put(column, value); - } - return row; - } - - @Override - public T mapRow(ResultSet rs, int rowNum) throws SQLException{ - T instance; - try { - Map row = getMap(rs); - instance = (T) mapRow(this.mappedClass, row); - } catch (SQLException e) { - throw e; - } catch (Exception e){ - throw new RuntimeException(e.getMessage()); - } - - return instance; - } -} diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/Exclude.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/Exclude.java index b7df66c8ccd..e5c3d79b7a2 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/Exclude.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/Exclude.java @@ -7,5 +7,7 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) +// This annotation is used to mark fields in a model class that should be ignored or excluded when the class is being processed, +// specifically during serialization to JSON or when constructing database queries. public @interface Exclude { } diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/Table.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/Table.java index 61dbd2d5d53..5f23e34e17a 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/Table.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/Table.java @@ -7,6 +7,9 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) +// It is used to specify the table name associated with a class. +// When you annotate a class with @Table, it indicates that the class is mapped to a table in the database. +// Used in GenericQueryBuilder public @interface Table { String name() default ""; } diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/UpdateBy.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/UpdateBy.java index e1ae3c7dfc7..9a7c9869bde 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/UpdateBy.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/annotations/UpdateBy.java @@ -7,5 +7,7 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) +// This annotation is used to mark specific fields in a class that should be specially considered during update operations +// Used in GenericQueryBuilder public @interface UpdateBy { } diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/builder/GenericQueryBuilder.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/builder/GenericQueryBuilder.java index b6086351e9d..482069b68bb 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/builder/GenericQueryBuilder.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/builder/GenericQueryBuilder.java @@ -4,6 +4,7 @@ import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.utils.ObjectUtils; +import java.lang.reflect.Modifier; import java.lang.reflect.ParameterizedType; import java.time.LocalDate; import java.util.ArrayList; @@ -28,18 +29,38 @@ static String updateQueryTemplate(String tableName){ return String.format("UPDATE %s", tableName); } - static String generateClause(String clauseName, String seperator, List queryParameters){ + /** + * Generates a clause for a SQL query. + * + * @param clauseName the name of the clause (e.g., "WHERE", "AND", "OR") + * @param separator the separator between query parameters (e.g., "=", "LIKE") + * @param queryParameters the list of query parameters to be included in the clause + * @return the generated clause as a string + */ + static String generateClause(String clauseName, String separator, List queryParameters) { + // Initialize a StringBuilder to construct the clause StringBuilder clauseBuilder = new StringBuilder(); + + // If there are no query parameters, return an empty string if (queryParameters.isEmpty()) { - return " WHERE 1=1 "; + return " "; } + + // Append the clause name to the clauseBuilder clauseBuilder.append(String.format(" %s ", clauseName)); + + // Append the first query parameter to the clauseBuilder clauseBuilder.append(String.format(queryParameters.get(0))); + + // Append the remaining query parameters to the clauseBuilder with the specified separator IntStream.range(1, queryParameters.size()).forEach(i -> - clauseBuilder.append(String.format(" %s %s", seperator ,queryParameters.get(i)))); + clauseBuilder.append(String.format(" %s %s", separator, queryParameters.get(i)))); + + // Convert the clauseBuilder to a string and return it return clauseBuilder.toString(); } + static StringBuilder generateQuery(String queryTemplate, List setClauseFields, List whereClauseFields){ StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append(queryTemplate); @@ -55,41 +76,76 @@ static StringBuilder generateQuery(String queryTemplate, List whereClaus return stringBuilder; } + /** + * Retrieves fields of an object based on a condition and constructs where clauses for a query. + * + * @param object the object for which fields are to be retrieved + * @param checkCondition the condition to check for each field + * @param paramsMap a map to store parameter values for the query + * @return a list of where clauses based on the fields and condition + */ static List getFieldsWithCondition(Object object, QueryFieldChecker checkCondition, Map paramsMap) { + // List to store where clauses List whereClauses = new ArrayList<>(); + + // Iterate through all declared fields of the object Arrays.stream(object.getClass().getDeclaredFields()).forEach(field -> { - if (field.getType().equals(LocalDate.class) || field.getType().isEnum()) { - // do nothing + // Check if the field is of type LocalDate or enum + if (field.getType().equals(LocalDate.class) || field.getType().isEnum() || Modifier.isStatic(field.getModifiers())) { + // Skip processing for LocalDate and enum fields + // No condition applied } else { - field.setAccessible(true); try { + // Make the field accessible for manipulation FIXME TODO + field.setAccessible(true); + } catch (Exception exception) { + return; + } + + try { + // Check if the field meets the condition and is not annotated with exclude if (!field.getType().isPrimitive() && checkCondition.check(field, object) && QueryFieldChecker.isNotAnnotatedWithExclude.check(field, object)) { + // If the field is a wrapper object if (ObjectUtils.isWrapper(field)) { + // Retrieve field name String fieldName = field.getName(); + // Add parameter to paramsMap paramsMap.put(fieldName, field.get(object)); + // Add where clause to list whereClauses.add(String.format("%s=:%s", fieldName, fieldName)); - } else if (field.getType().isAssignableFrom(ArrayList.class) + } + // If the field is an ArrayList of Strings + else if (field.getType().isAssignableFrom(ArrayList.class) && field.getGenericType() instanceof ParameterizedType && ((ParameterizedType) field.getGenericType()).getActualTypeArguments()[0].equals(String.class)) { + // Cast field value to ArrayList ArrayList arrayList = (ArrayList) field.get(object); + // Retrieve field name String fieldName = field.getName(); + // Check if the ArrayList is not null or empty if (arrayList != null && !arrayList.isEmpty()) { + // Add IN clause to list whereClauses.add(String.format("%s IN (:%s)", fieldName, fieldName)); + // Add parameter to paramsMap paramsMap.put(fieldName, arrayList); } } else { + // If the field is not a wrapper object or ArrayList, recursively process nested objects Object objectAtField = field.get(object); if (objectAtField != null) { + // Recursively call the method to retrieve fields from nested object whereClauses.addAll(getFieldsWithCondition(objectAtField, checkCondition, paramsMap)); } } } } catch (IllegalAccessException e) { + // Throw a runtime exception if there's an issue accessing the field throw new RuntimeException(e); } } }); return whereClauses; } + } diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/builder/SelectQueryBuilder.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/builder/SelectQueryBuilder.java index de274691e6e..3db008197d4 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/builder/SelectQueryBuilder.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/query/builder/SelectQueryBuilder.java @@ -1,5 +1,6 @@ package org.egov.common.data.query.builder; +import org.apache.commons.lang3.StringUtils; import org.egov.common.data.query.exception.QueryBuilderException; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @@ -20,9 +21,19 @@ public Map getParamsMap(){ @Override public String build(Object object) throws QueryBuilderException { + String tableName = null; + try { + tableName = GenericQueryBuilder.getTableName(object.getClass()); + } catch (Exception exception) { + throw new QueryBuilderException(exception.getMessage()); + } + + return build(object, tableName); + } + + public String build(Object object, String tableName) throws QueryBuilderException { StringBuilder queryStringBuilder = null; try { - String tableName = GenericQueryBuilder.getTableName(object.getClass()); List whereClauses = GenericQueryBuilder.getFieldsWithCondition(object, QueryFieldChecker.isNotNull, paramsMap); queryStringBuilder = GenericQueryBuilder.generateQuery(GenericQueryBuilder.selectQueryTemplate(tableName), whereClauses); } catch (Exception exception) { diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java index 347fc4966a4..1c3f1f898dc 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java @@ -26,6 +26,11 @@ import static org.egov.common.utils.CommonUtils.getMethod; import static org.egov.common.utils.CommonUtils.getObjClass; +/** + * Generic Repository Class for common data operations. + * + * @param The type of entity this repository deals with. + */ @Slf4j public abstract class GenericRepository { @@ -56,10 +61,23 @@ protected GenericRepository(Producer producer, NamedParameterJdbcTemplate namedP tableName.ifPresent(tb -> this.tableName = tb); } + /** + * Finds entities by their IDs. + * + * @param ids The list of IDs to search for. + * @return A list of entities found by the given IDs. + */ public List findById(List ids) { return findById(ids, false); } + /** + * Finds entities by their IDs with an option to include deleted entities. + * + * @param ids The list of IDs to search for. + * @param includeDeleted Flag to include deleted entities in the search result. + * @return A list of entities found by the given IDs. + */ protected List findInCache(List ids) { ArrayList objFound = new ArrayList<>(); Collection collection = ids.stream().filter(Objects::nonNull) @@ -81,10 +99,27 @@ protected List findInCache(List ids) { return objFound; } + /** + * Finds entities by their IDs with an option to include deleted entities, + * using the default column name "id" for ID search. + * + * @param ids The list of IDs to search for. + * @param includeDeleted Flag to include deleted entities in the search result. + * @return A list of entities found by the given IDs. + */ public List findById(List ids, Boolean includeDeleted) { + // Delegates to the main findById method with the default column name "id" return findById(ids, includeDeleted, "id"); } + /** + * Finds entities by their IDs with options to include deleted entities and specify a column name. + * + * @param ids The list of IDs to search for. + * @param includeDeleted Flag to include deleted entities in the search result. + * @param columnName The name of the column to search IDs in. + * @return A list of entities found by the given IDs. + */ public List findById(List ids, Boolean includeDeleted, String columnName) { List objFound = findInCache(ids); @@ -115,6 +150,13 @@ public List findById(List ids, Boolean includeDeleted, String columnN return objFound; } + /** + * Saves entities to Kafka and caches them. + * + * @param objects The list of entities to save. + * @param topic The Kafka topic to push the entities to. + * @return The list of saved entities. + */ public List save(List objects, String topic) { producer.push(topic, objects); log.info("Pushed to kafka"); @@ -123,6 +165,14 @@ public List save(List objects, String topic) { return objects; } + /** + * Saves entities to Kafka, caches them with specified cache key. + * + * @param objects The list of entities to save. + * @param topic The Kafka topic to push the entities to. + * @param cacheKey The cache key to use for caching the entities. + * @return The list of saved entities. + */ public List save(List objects, String topic, String cacheKey) { producer.push(topic, objects); log.info("Pushed to kafka"); @@ -131,6 +181,7 @@ public List save(List objects, String topic, String cacheKey) { return objects; } + // Cache objects by key protected void cacheByKey(List objects, String fieldName) { try{ Method getIdMethod = getIdMethod(objects, fieldName); @@ -154,6 +205,11 @@ protected void cacheByKey(List objects, String fieldName) { } } + /** + * Puts objects in cache. + * + * @param objects The list of objects to put in cache. + */ public void putInCache(List objects) { if(objects == null || objects.isEmpty()) { return; @@ -163,6 +219,12 @@ public void putInCache(List objects) { // cacheByKey(objects, "id"); } + /** + * Puts objects in cache with specified cache key. + * + * @param objects The list of objects to put in cache. + * @param key The cache key to use for caching the objects. + */ public void putInCache(List objects, String key) { if(objects == null || objects.isEmpty()) { return; @@ -171,15 +233,27 @@ public void putInCache(List objects, String key) { cacheByKey(objects, key); } + /** + * Finds entities based on search criteria. + * + * @param searchObject The object containing search criteria. + * @param limit The maximum number of entities to return. + * @param offset The offset for pagination. + * @param tenantId The tenant ID to filter entities. + * @param lastChangedSince The timestamp for last modified entities. + * @param includeDeleted Flag to include deleted entities in the search result. + * @return A list of entities found based on the search criteria. + * @throws QueryBuilderException If an error occurs while building the query. + */ public List find(Object searchObject, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws QueryBuilderException { - String query = selectQueryBuilder.build(searchObject); + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws QueryBuilderException { + String query = selectQueryBuilder.build(searchObject, tableName); query += " AND tenantId=:tenantId "; - if (query.contains(tableName + " AND")) { + if (query.contains(tableName + " AND")) { query = query.replace(tableName + " AND", tableName + " WHERE"); } if (Boolean.FALSE.equals(includeDeleted)) { @@ -198,6 +272,13 @@ public List find(Object searchObject, return namedParameterJdbcTemplate.query(query, paramsMap, rowMapper); } + /** + * Validates IDs against existing entities. + * + * @param idsToValidate The list of IDs to validate. + * @param columnName The name of the column containing IDs. + * @return A list of valid IDs. + */ public List validateIds(List idsToValidate, String columnName){ List validIds = findById(idsToValidate, false, columnName); if (validIds.isEmpty()) { diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/error/handler/ErrorHandler.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/error/handler/ErrorHandler.java index ec82e2065c1..ffd00e62a76 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/error/handler/ErrorHandler.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/error/handler/ErrorHandler.java @@ -4,7 +4,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; @Component public class ErrorHandler { diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/http/client/ServiceRequestClient.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/http/client/ServiceRequestClient.java index 22d2b64c296..6a4fcab2409 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/http/client/ServiceRequestClient.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/http/client/ServiceRequestClient.java @@ -1,6 +1,5 @@ package org.egov.common.http.client; - import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import lombok.extern.slf4j.Slf4j; @@ -11,6 +10,10 @@ import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; +/** + * Client for making service requests via HTTP. + * This class provides methods to fetch results from a service using HTTP POST requests. + */ @Repository @Slf4j public class ServiceRequestClient { @@ -19,27 +22,39 @@ public class ServiceRequestClient { private final RestTemplate restTemplate; - + // Constructor injection of ObjectMapper and RestTemplate @Autowired public ServiceRequestClient(@Qualifier("objectMapper") ObjectMapper objectMapper, RestTemplate restTemplate) { this.objectMapper = objectMapper; this.restTemplate = restTemplate; } - - public T fetchResult(StringBuilder uri, Object request, Class - clazz) { + /** + * Fetches result from a service using HTTP POST. + * + * @param uri The URI to send the request to. + * @param request The request object to send. + * @param clazz The class of the response object. + * @param The type of the response object. + * @return The response object received from the service. + * @throws CustomException If an error occurs during the service request. + */ + public T fetchResult(StringBuilder uri, Object request, Class clazz) { + // Configure the ObjectMapper to ignore empty beans during serialization objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); T response; try { + // Perform HTTP POST request and receive the response response = restTemplate.postForObject(uri.toString(), request, clazz); } catch (HttpClientErrorException e) { + // Handle HTTP client errors throw new CustomException("HTTP_CLIENT_ERROR", String.format("%s - %s", e.getMessage(), e.getResponseBodyAsString())); - }catch (Exception exception) { + } catch (Exception exception) { + // Handle other exceptions throw new CustomException("SERVICE_REQUEST_CLIENT_ERROR", exception.getMessage()); } return response; } -} \ No newline at end of file +} diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/CreateUserRequest.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/CreateUserRequest.java index db4196aec11..ebcc79c9259 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/CreateUserRequest.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/CreateUserRequest.java @@ -5,8 +5,8 @@ import lombok.NoArgsConstructor; import org.egov.common.contract.request.RequestInfo; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; @AllArgsConstructor @Getter diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/User.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/User.java index 95a8618aab2..46e1495f5d1 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/User.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/User.java @@ -10,8 +10,8 @@ import org.hibernate.validator.constraints.Email; import org.springframework.util.CollectionUtils; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.Collections; import java.util.Date; diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/UserRequest.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/UserRequest.java index e194df585e2..75aa1bfb17d 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/UserRequest.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/models/user/UserRequest.java @@ -1,7 +1,14 @@ package org.egov.common.models.user; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; +import java.util.stream.Collectors; + import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -9,14 +16,6 @@ import lombok.Setter; import lombok.ToString; import org.hibernate.validator.constraints.Email; -import org.hibernate.validator.constraints.SafeHtml; - -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; -import java.util.Date; -import java.util.HashSet; -import java.util.Set; -import java.util.stream.Collectors; @Setter @Getter @@ -25,14 +24,19 @@ @AllArgsConstructor @ToString public class UserRequest { +/** + * FIXME + * to be removed or replace with some alternative as the //@SafeHtml is no longer present + * with modern version of hibernate validator supported by springboot version 3.2.2 + */ private Long id; - @SafeHtml +// //@SafeHtml @Size(max = 64) private String userName; - @SafeHtml +// //@SafeHtml @Size(max = 5) private String salutation; @@ -54,33 +58,33 @@ public class UserRequest { @Size(max = 128) private String emailId; - @SafeHtml + //@SafeHtml @Size(max = 50) private String altContactNumber; - @SafeHtml + //@SafeHtml @Size(max = 10) private String pan; - @SafeHtml + //@SafeHtml @Size(max = 20) private String aadhaarNumber; - @SafeHtml + //@SafeHtml @Size(max = 300) private String permanentAddress; - @SafeHtml + //@SafeHtml @Pattern(regexp = UserServiceConstants.PATTERN_CITY) @Size(max = 50) private String permanentCity; - @SafeHtml + //@SafeHtml @Pattern(regexp = UserServiceConstants.PATTERN_PINCODE) @Size(max = 10) private String permanentPinCode; - @SafeHtml + //@SafeHtml @Size(max = 300) private String correspondenceAddress; @@ -93,7 +97,7 @@ public class UserRequest { private String correspondencePinCode; private Boolean active; - @SafeHtml + //@SafeHtml @Size(max = 16) private String locale; @@ -106,19 +110,19 @@ public class UserRequest { private String fatherOrHusbandName; private GuardianRelation relationship; - @SafeHtml + //@SafeHtml @Size(max = 36) private String signature; - @SafeHtml + //@SafeHtml @Size(max = 32) private String bloodGroup; - @SafeHtml + //@SafeHtml @Size(max = 36) private String photo; - @SafeHtml + //@SafeHtml @Size(max = 300) private String identificationMark; private Long createdBy; @@ -126,7 +130,7 @@ public class UserRequest { @Size(max = 64) private String password; - @SafeHtml + //@SafeHtml private String otpReference; private Long lastModifiedBy; @@ -136,7 +140,7 @@ public class UserRequest { private Set roles; - @SafeHtml + //@SafeHtml @Size(max = 36) private String uuid; diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/MdmsService.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/MdmsService.java index 10208611a30..b946a6380d4 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/MdmsService.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/service/MdmsService.java @@ -11,7 +11,7 @@ @Slf4j @Service -@ConditionalOnExpression("!'${egov.mdms.integration.enabled}'.isEmpty() && ${egov.mdms.integration.enabled:false} && !'${egov.mdms.host}'.isEmpty() && !'${egov.mdms.master.name}'.isEmpty() && !'${egov.mdms.search.endpoint}'.isEmpty()") +@ConditionalOnExpression("!'${egov.mdms.integration.enabled}'.isEmpty() && ${egov.mdms.integration.enabled:false} && !'${egov.mdms.host}'.isEmpty() && !'${egov.mdms.search.endpoint}'.isEmpty()") public class MdmsService { private final ServiceRequestClient restRepo; diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/utils/CommonUtils.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/utils/CommonUtils.java index 2ab18e03354..927a05044ca 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/utils/CommonUtils.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/utils/CommonUtils.java @@ -1,23 +1,5 @@ package org.egov.common.utils; -import com.fasterxml.jackson.databind.DeserializationFeature; -import com.fasterxml.jackson.databind.ObjectMapper; -import digit.models.coremodels.AuditDetails; -import lombok.extern.slf4j.Slf4j; -import org.egov.common.contract.request.RequestInfo; -import org.egov.common.ds.Tuple; -import org.egov.common.error.handler.ErrorHandler; -import org.egov.common.models.ApiDetails; -import org.egov.common.models.Error; -import org.egov.common.models.ErrorDetails; -import org.egov.common.validator.Validator; -import org.egov.tracer.model.CustomException; -import org.egov.tracer.model.ErrorDetail; -import org.egov.tracer.model.ErrorEntity; -import org.springframework.http.HttpMethod; -import org.springframework.http.MediaType; -import org.springframework.util.ReflectionUtils; - import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.ArrayList; @@ -39,6 +21,26 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.ds.Tuple; +import org.egov.common.error.handler.ErrorHandler; +import org.egov.common.models.ApiDetails; +import org.egov.common.models.Error; +import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.URLParams; +import org.egov.common.validator.Validator; +import org.egov.tracer.model.CustomException; +import org.egov.tracer.model.ErrorDetail; +import org.egov.tracer.model.ErrorEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.util.ReflectionUtils; + import static org.egov.common.utils.ValidatorUtils.getErrorForNullId; @Slf4j @@ -56,6 +58,8 @@ private CommonUtils() { } + //TODO To be removed as it is only used by Product service which is now depricated + @Deprecated public static boolean isForUpdate(Object obj) { Method getApiOperationMethod = getMethod(GET_API_OPERATION, obj.getClass()); Object apiOperation = ReflectionUtils.invokeMethod(getApiOperationMethod, obj); @@ -66,6 +70,8 @@ public static boolean isForUpdate(Object obj) { return "UPDATE".equals(ReflectionUtils.invokeMethod(nameMethod, apiOperation)); } + //TODO To be removed as it is only used by Product service which is now depricated + @Deprecated public static boolean isForDelete(Object obj) { Method getApiOperationMethod = getMethod(GET_API_OPERATION, obj.getClass()); Object apiOperation = ReflectionUtils.invokeMethod(getApiOperationMethod, obj); @@ -76,6 +82,8 @@ public static boolean isForDelete(Object obj) { return "DELETE".equals(ReflectionUtils.invokeMethod(nameMethod, apiOperation)); } + //TODO To be removed as it is only used by Product service which is now depricated + @Deprecated public static boolean isForCreate(Object obj) { Method getApiOperationMethod = getMethod(GET_API_OPERATION, obj.getClass()); Object apiOperation = ReflectionUtils.invokeMethod(getApiOperationMethod, obj); @@ -102,6 +110,8 @@ public static List getDifference(List list, List subList) { return newList; } + //TODO To be removed as it is only used by Product service which is now depricated + @Deprecated public static void validateIds(Set idsToValidate, UnaryOperator> validator) { List idsToValidateList = new ArrayList<>(idsToValidate); List validIds = validator.apply(idsToValidateList); @@ -112,6 +122,13 @@ public static void validateIds(Set idsToValidate, UnaryOperator> } } + /** + * Retrieves audit details for creating an entity. + * This method generates audit details including creation and last modified timestamps. + * + * @param requestInfo The request information containing user details. + * @return The audit details for create operation. + */ public static AuditDetails getAuditDetailsForCreate(RequestInfo requestInfo) { log.info("Creating audit details for create api"); Long time = System.currentTimeMillis(); @@ -119,7 +136,8 @@ public static AuditDetails getAuditDetailsForCreate(RequestInfo requestInfo) { .createdBy(requestInfo.getUserInfo().getUuid()) .createdTime(time) .lastModifiedBy(requestInfo.getUserInfo().getUuid()) - .lastModifiedTime(time).build(); + .lastModifiedTime(time) + .build(); } /** @@ -142,39 +160,111 @@ public static AuditDetails getAuditDetailsForUpdate(AuditDetails existingAuditDe } } + /** + * Checks if the search is performed by ID only. + * @param obj The object to check. + * @return True if the search is by ID only, false otherwise. + */ public static boolean isSearchByIdOnly(Object obj) { return isSearchByIdOnly(obj, "id"); } + /** + * Checks if the search is performed only by the specified field. + * + * @param obj The object to perform the search on. + * @param fieldName The name of the field to search. + * @return true if the search is performed only by the specified field, otherwise false. + */ public static boolean isSearchByIdOnly(Object obj, String fieldName) { + // Get the class of the object Class objClass = obj.getClass(); + // Capitalize the first letter of the field name String propertyName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); - Method setIdMethod = getMethod("set"+propertyName, objClass); - Method getIdMethod = getMethod("get"+propertyName, objClass); + // Get the method to set the field + Method setFieldMethod = getMethod("set" + propertyName, objClass); + // Get the method to get the field value + Method getFieldMethod = getMethod("get" + propertyName, objClass); + // Create a new instance of the object Object finalObject = null; try { finalObject = objClass.newInstance(); } catch (InstantiationException | IllegalAccessException e) { + // Throw a runtime exception if instantiation fails throw new RuntimeException(e); } - Object id = ReflectionUtils.invokeMethod(getIdMethod, obj); - ReflectionUtils.invokeMethod(setIdMethod, finalObject, id); + // Get the ID of the object + Object id = ReflectionUtils.invokeMethod(getFieldMethod, obj); + // If ID is null, return false if (id == null) { return false; } - String actual = obj.toString(); - String expected = finalObject.toString(); - return actual.equals(expected); + // Set the ID to the final object + ReflectionUtils.invokeMethod(setFieldMethod, finalObject, id); + + // If the object is an instance of URLParams, set common properties + if (obj instanceof URLParams) { + URLParams urlParamsObj = ((URLParams) obj); + URLParams finalUrlParamsObj = ((URLParams) finalObject); + finalUrlParamsObj.setIncludeDeleted(urlParamsObj.getIncludeDeleted()); + finalUrlParamsObj.setTenantId(urlParamsObj.getTenantId()); + finalUrlParamsObj.setOffset(urlParamsObj.getOffset()); + finalUrlParamsObj.setLimit(urlParamsObj.getLimit()); + finalUrlParamsObj.setLastChangedSince(urlParamsObj.getLastChangedSince()); + } + + // compare both objects + return areObjectsEqual(obj, finalObject); } + public static boolean areObjectsEqual(Object obj1, Object obj2) { + if (obj1 == null || obj2 == null) { + return false; + } + + // Get the class of the objects + Class objClass = obj1.getClass(); + + // Iterate through all fields in the class, including parent fields + StringBuilder obj1Fields = new StringBuilder(); + StringBuilder obj2Fields = new StringBuilder(); + + while(objClass.getSuperclass() != null) { + for (Field field : objClass.getDeclaredFields()) { + field.setAccessible(true); // Ensure private fields are accessible + + try { + // Get the value of the field for each object + Object value1 = field.get(obj1); + Object value2 = field.get(obj2); + + // Append the field name and value to the string representation + obj1Fields.append(field.getName()).append(":").append(value1).append(","); + obj2Fields.append(field.getName()).append(":").append(value2).append(","); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + } + objClass = objClass.getSuperclass(); + } + + // Compare the string representations of the objects + return obj1Fields.toString().equals(obj2Fields.toString()); + } + + + //TODO To be removed as it is only used by Product service which is now depricated + @Deprecated public static void checkRowVersion(Map idToObjMap, List objList) { Class objClass = getObjClass(objList); checkRowVersion(idToObjMap, objList, getMethod("getId", objClass)); } + //TODO To be removed as it is only used by Product service which is now depricated + @Deprecated public static void checkRowVersion(Map idToObjMap, List objList, Method idMethod) { Class objClass = getObjClass(objList); Method rowVersionMethod = getMethod("getRowVersion", objClass); @@ -189,10 +279,21 @@ public static void checkRowVersion(Map idToObjMap, List objLis } } + /** + * Retrieves entities from a list with mismatched row versions compared to a map of IDs to objects. + * @param idToObjMap A map of IDs to objects. + * @param objList The list of objects to check. + * @param idMethod The method to retrieve the ID of an object. + * @param The type of objects in the list. + * @return A list of entities with mismatched row versions. + */ public static List getEntitiesWithMismatchedRowVersion(Map idToObjMap, List objList, Method idMethod) { + // Get the class of objects in the list Class objClass = getObjClass(objList); + // Get the method to retrieve the row version Method rowVersionMethod = getMethod("getRowVersion", objClass); + // Filter the object list to include only those with mismatched row versions return objList.stream() .filter(obj -> !Objects.equals(ReflectionUtils.invokeMethod(rowVersionMethod, obj), ReflectionUtils.invokeMethod(rowVersionMethod, @@ -201,10 +302,20 @@ public static List getEntitiesWithMismatchedRowVersion(Map idT .collect(Collectors.toList()); } + /** + * Retrieves the tenant ID from a list of objects. + * @param objList The list of objects from which to retrieve the tenant ID. + * @param The type of objects in the list. + * @return The tenant ID. + */ public static String getTenantId(List objList) { + // Retrieve any object from the list Object obj = objList.stream().findAny().get(); + // Get the method to retrieve the tenant ID Method getTenantIdMethod = getMethod("getTenantId", obj.getClass()); + // Invoke the method to retrieve the tenant ID String tenantId = (String) ReflectionUtils.invokeMethod(getTenantIdMethod, obj); + // Log the retrieved tenant ID log.info("tenantId is {}", tenantId); return tenantId; } @@ -236,6 +347,7 @@ public static void enrichForCreate(List objList, List idList, Req * @param updateRowVersion denoting whether to update rowVersion or not * @param is any type that has an id field, auditDetails field, rowVersion field and isDeleted field with setters and getters */ + //TODO COMPARE the size and throw error when objList and idList are not equal public static void enrichForCreate(List objList, List idList, RequestInfo requestInfo, boolean updateRowVersion) { AuditDetails auditDetails = getAuditDetailsForCreate(requestInfo); @@ -256,149 +368,279 @@ public static void enrichForCreate(List objList, List idList, Req }); } + /** + * Retrieves the ID method from a list of objects, prioritizing "id" and "clientReferenceId" fields. + * @param objList The list of objects from which to retrieve the ID method. + * @param The type of objects in the list. + * @return The ID method. + */ public static Method getIdMethod(List objList) { return getIdMethod(objList, "id", "clientReferenceId"); } + /** + * Retrieves the ID method from a list of objects based on a specified ID field name. + * @param objList The list of objects from which to retrieve the ID method. + * @param idFieldName The name of the ID field. + * @param The type of objects in the list. + * @return The ID method. + */ public static Method getIdMethod(List objList, String idFieldName) { - String idMethodName = "get" + idFieldName.substring(0, 1).toUpperCase() - + idFieldName.substring(1); + // Construct the method name based on the ID field name + String idMethodName = "get" + idFieldName.substring(0, 1).toUpperCase() + idFieldName.substring(1); + // Get the ID method using the constructed method name return getMethod(idMethodName, getObjClass(objList)); } + /** + * Retrieves the ID method from a list of objects based on specified ID and client reference ID field names. + * @param objList The list of objects from which to retrieve the ID method. + * @param idField The name of the ID field. + * @param clientReferenceIdField The name of the client reference ID field. + * @param The type of objects in the list. + * @return The ID method. + */ public static Method getIdMethod(List objList, String idField, String clientReferenceIdField) { - String idMethodName = "get" + idField.substring(0, 1).toUpperCase() - + idField.substring(1); - String clientReferenceIdMethodName = "get" + clientReferenceIdField.substring(0, 1).toUpperCase() - + clientReferenceIdField.substring(1); - try{ + // Construct the method names based on the specified field names + String idMethodName = "get" + idField.substring(0, 1).toUpperCase() + idField.substring(1); + String clientReferenceIdMethodName = "get" + clientReferenceIdField.substring(0, 1).toUpperCase() + clientReferenceIdField.substring(1); + try { + // Attempt to retrieve the ID method Method getId = getMethod(idMethodName, getObjClass(objList)); + // Invoke the ID method on an object from the list to check if it returns a non-null value Object value = ReflectionUtils.invokeMethod(getId, objList.stream().findAny().get()); + // If the value is not null, return the ID method if (value != null) { return getId; } - } catch (CustomException e){ + } catch (CustomException e) { + // Log and handle any custom exceptions log.error(e.getMessage()); } - + // If the ID method does not return a non-null value, return the client reference ID method return getMethod(clientReferenceIdMethodName, getObjClass(objList)); } + + /** + * Enriches the objects in a list with IDs from a corresponding list of IDs. + * @param objList The list of objects to enrich with IDs. + * @param idList The list of IDs to use for enrichment. + * @param The type of objects in the list. + */ public static void enrichId(List objList, List idList) { + // Get the class of objects in the list Class objClass = getObjClass(objList); + // Get the method to set the ID Method setIdMethod = getMethod("setId", objClass); + // Iterate over the indices of the object list IntStream.range(0, objList.size()) .forEach(i -> { + // Get the object at the current index final Object obj = objList.get(i); + // Invoke the method to set the ID on the object using the corresponding ID from the ID list ReflectionUtils.invokeMethod(setIdMethod, obj, idList.get(i)); }); } + /** + * Enriches objects for update based on a map of IDs to objects and a request object. + * @param idToObjMap A map of IDs to objects. + * @param request The request object. + * @param The type of objects in the map. + */ public static void enrichForUpdate(Map idToObjMap, Object request) { + // Get the class of objects in the map Class objClass = getObjClass(Arrays.asList(idToObjMap.values().toArray())); + // Get the class of the request object Class requestObjClass = request.getClass(); + // Get methods related to row version, audit details, and request information Method getRowVersionMethod = getMethod("getRowVersion", objClass); Method setRowVersionMethod = getMethod("setRowVersion", objClass); Method setAuditDetailsMethod = getMethod("setAuditDetails", objClass); Method getAuditDetailsMethod = getMethod("getAuditDetails", objClass); - Method getRequestInfoMethod = getMethod("getRequestInfo", requestObjClass); + // Iterate over the keys (IDs) in the map idToObjMap.keySet().forEach(i -> { + // Get the object corresponding to the current ID Object obj = idToObjMap.get(i); + // Retrieve row version and update it Integer rowVersion = (Integer) ReflectionUtils.invokeMethod(getRowVersionMethod, obj); ReflectionUtils.invokeMethod(setRowVersionMethod, obj, rowVersion + 1); - RequestInfo requestInfo = (RequestInfo) ReflectionUtils - .invokeMethod(getRequestInfoMethod, request); + // Retrieve request information + RequestInfo requestInfo = (RequestInfo) ReflectionUtils.invokeMethod(getRequestInfoMethod, request); + // Retrieve existing audit details and update them AuditDetails existingAuditDetails = (AuditDetails) ReflectionUtils.invokeMethod(getAuditDetailsMethod, obj); AuditDetails auditDetailsForUpdate = getAuditDetailsForUpdate(existingAuditDetails, requestInfo.getUserInfo().getUuid()); ReflectionUtils.invokeMethod(setAuditDetailsMethod, obj, auditDetailsForUpdate); }); } - public static void enrichForUpdate(Map idToObjMap, List existingObjList, Object request) { - Class objClass = getObjClass(existingObjList); - enrichForUpdate(idToObjMap, existingObjList, request, getMethod("getId", objClass)); - } - + /** + * Enriches objects for update based on a map of IDs to objects, a list of existing objects, a request object, and an ID method. + * @param idToObjMap A map of IDs to objects. + * @param existingObjList The list of existing objects. + * @param request The request object. + * @param idMethod The method to retrieve the ID. + * @param The type of objects in the list. + */ public static void enrichForUpdate(Map idToObjMap, List existingObjList, Object request, Method idMethod) { + // Get the class of objects in the list Class objClass = getObjClass(existingObjList); + // Get the class of the request object Class requestObjClass = request.getClass(); + // Get methods related to deletion, row version, audit details, and request information Method setIsDeletedMethod = getMethod("setIsDeleted", objClass); Method getRowVersionMethod = getMethod("getRowVersion", objClass); Method setRowVersionMethod = getMethod("setRowVersion", objClass); Method getAuditDetailsMethod = getMethod("getAuditDetails", objClass); Method setAuditDetailsMethod = getMethod("setAuditDetails", objClass); Method getRequestInfoMethod = getMethod("getRequestInfo", requestObjClass); + // Iterate over the indices of the existing object list IntStream.range(0, existingObjList.size()).forEach(i -> { - Object obj = idToObjMap.get(ReflectionUtils.invokeMethod(idMethod, - existingObjList.get(i))); + // Get the object corresponding to the current index + Object obj = idToObjMap.get(ReflectionUtils.invokeMethod(idMethod, existingObjList.get(i))); try { + // Get the API operation method and API operation name Method getApiOperationMethod = getMethod(GET_API_OPERATION, requestObjClass); Object apiOperation = ReflectionUtils.invokeMethod(getApiOperationMethod, request); Method nameMethod = CommonUtils.getMethod("name", Enum.class); + // If the API operation is DELETE, set the object's "isDeleted" flag to true if ("DELETE".equals(ReflectionUtils.invokeMethod(nameMethod, apiOperation))) { ReflectionUtils.invokeMethod(setIsDeletedMethod, obj, true); } } catch (Exception exception) { - // Do nothing remove later + // Do nothing; remove later } - + // Retrieve row version and update it Integer rowVersion = (Integer) ReflectionUtils.invokeMethod(getRowVersionMethod, obj); ReflectionUtils.invokeMethod(setRowVersionMethod, obj, rowVersion + 1); - RequestInfo requestInfo = (RequestInfo) ReflectionUtils - .invokeMethod(getRequestInfoMethod, request); - AuditDetails existingAuditDetails = (AuditDetails) ReflectionUtils - .invokeMethod(getAuditDetailsMethod, existingObjList.get(i)); - AuditDetails auditDetailsForUpdate = getAuditDetailsForUpdate(existingAuditDetails, - requestInfo.getUserInfo().getUuid()); + // Retrieve request information + RequestInfo requestInfo = (RequestInfo) ReflectionUtils.invokeMethod(getRequestInfoMethod, request); + // Retrieve existing audit details and update them + AuditDetails existingAuditDetails = (AuditDetails) ReflectionUtils.invokeMethod(getAuditDetailsMethod, existingObjList.get(i)); + AuditDetails auditDetailsForUpdate = getAuditDetailsForUpdate(existingAuditDetails, requestInfo.getUserInfo().getUuid()); ReflectionUtils.invokeMethod(setAuditDetailsMethod, obj, auditDetailsForUpdate); }); } + /** + * Enriches objects for update based on a map of IDs to objects, a list of existing objects, and a request object. + * + * @param idToObjMap A map of IDs to objects. + * @param existingObjList The list of existing objects. + * @param request The request object. + * @param The type of objects in the list. + */ + public static void enrichForUpdate(Map idToObjMap, List existingObjList, Object request) { + Class objClass = getObjClass(existingObjList); + Method getIdMethod = getMethod("getId", objClass); + + enrichForUpdate(idToObjMap, existingObjList, request, getIdMethod); + } + + + /** + * Creates a map of IDs to objects using the default ID method. + * @param objList The list of objects from which to create the map. + * @param The type of objects in the list. + * @return A map of IDs to objects. + */ public static Map getIdToObjMap(List objList) { + // Get the class of objects in the list Class objClass = getObjClass(objList); - return getIdToObjMap(objList, getMethod("getId", objClass)); + // Get the default ID method + Method idMethod = getMethod("getId", objClass); + // Delegate to the overloaded method to create the map + return getIdToObjMap(objList, idMethod); } + /** + * Creates a map of IDs to objects using the specified ID method. + * @param objList The list of objects from which to create the map. + * @param idMethod The method to retrieve the ID from an object. + * @param The type of objects in the list. + * @return A map of IDs to objects. + */ public static Map getIdToObjMap(List objList, Method idMethod) { - return objList.stream().collect(Collectors.toMap(obj -> (String) ReflectionUtils - .invokeMethod(idMethod, obj), obj -> obj, (obj1, obj2) -> obj2)); + // Collect the objects into a map using the specified ID method + return objList.stream().collect(Collectors.toMap( + obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj), + obj -> obj, + (obj1, obj2) -> obj2 + )); } + + /** + * Validates entities by comparing the number of entities in the request map with those in the database list. + * @param idToObjInRequestMap A map of IDs to objects in the request. + * @param objInDbList The list of objects in the database. + * @param The type of objects in the lists. + */ public static void validateEntities(Map idToObjInRequestMap, List objInDbList) { + // Check if the number of entities in the request map exceeds those in the database list if (idToObjInRequestMap.size() > objInDbList.size()) { + // Get the list of IDs for objects in the database List idsForObjInDb = getIdList(objInDbList); + // Identify the IDs for invalid objects in the request map List idsForInvalidObj = idToObjInRequestMap.keySet().stream() .filter(id -> !idsForObjInDb.contains(id)) .collect(Collectors.toList()); + // Log and throw an exception for the invalid entities log.error("Invalid entities {}", idsForInvalidObj); throw new CustomException("INVALID_ENTITY", idsForInvalidObj.toString()); } } - public static void validateEntities(Map idToObjInRequestMap, List objInDbList, - Method idMethod) { + /** + * Validates entities by comparing the number of entities in the request map with those in the database list, + * using a specified ID retrieval method. + * @param idToObjInRequestMap A map of IDs to objects in the request. + * @param objInDbList The list of objects in the database. + * @param idMethod The method to retrieve the ID from an object. + * @param The type of objects in the lists. + */ + public static void validateEntities(Map idToObjInRequestMap, List objInDbList, Method idMethod) { + // Check if the number of entities in the request map exceeds those in the database list if (idToObjInRequestMap.size() > objInDbList.size()) { + // Get the list of IDs for objects in the database using the specified ID retrieval method List idsForObjInDb = getIdList(objInDbList, idMethod); + // Identify the IDs for invalid objects in the request map List idsForInvalidObj = idToObjInRequestMap.keySet().stream() .filter(id -> !idsForObjInDb.contains(id)) .collect(Collectors.toList()); + // Log and throw an exception for the invalid entities log.error("Invalid entities {}", idsForInvalidObj); throw new CustomException("INVALID_ENTITY", idsForInvalidObj.toString()); } } + + /** + * Checks for non-existent entities in the request map based on the ID method, comparing them with entities in the database list. + * @param idToObjInRequestMap A map of IDs to objects in the request. + * @param objInDbList The list of objects in the database. + * @param idMethod The method to retrieve the ID from an object. + * @param The type of objects in the lists. + * @return A list of entities from the request map that do not exist in the database. + */ public static List checkNonExistentEntities(Map idToObjInRequestMap, List objInDbList, Method idMethod) { + // Check if the number of entities in the request map exceeds those in the database list if (idToObjInRequestMap.size() > objInDbList.size()) { + // Get the list of IDs for objects in the database using the specified ID retrieval method List idsForObjInDb = getIdList(objInDbList, idMethod); + // Filter out entities from the request map that do not exist in the database list return idToObjInRequestMap.entrySet().stream() - .filter(e -> !idsForObjInDb.contains(e.getKey())).map(Map.Entry::getValue) - .collect(Collectors.toList()); + .filter(e -> !idsForObjInDb.contains(e.getKey())) // Filter non-existent entities + .map(Map.Entry::getValue) // Map to the corresponding object + .collect(Collectors.toList()); // Collect into a list } - return Collections.emptyList(); + return Collections.emptyList(); // Return an empty list if no non-existent entities are found } + public static List getIdList(List objList) { if (objList == null || objList.isEmpty()) { return Collections.emptyList(); @@ -500,24 +742,41 @@ public static List collectFromList(List objList, Function clazz, String fieldName) { + Class parentClass = clazz; + while (parentClass != null) { + try { + return parentClass.getDeclaredField(fieldName); + } catch (NoSuchFieldException e) { + // Field not found in this class, proceed to the parent class + parentClass = parentClass.getSuperclass(); + } + } + // Field not found in the class hierarchy + return null; + } + public static String getIdFieldName(Method method) { if (method != null) { return method.getName().contains("Reference") ? "clientReferenceId" : "id"; @@ -862,16 +1121,16 @@ public static void populateErrorDetails(T payload, Error error, } private static Method findMethod(String methodName, Class clazz) { - return Arrays.stream(ReflectionUtils.getDeclaredMethods(clazz)) + return Arrays.stream(ReflectionUtils.getAllDeclaredMethods(clazz)) .filter(m -> m.getName().equals(methodName)) .findFirst().orElseThrow(() -> new CustomException("INVALID_OBJECT_OR_METHOD", "Invalid object or method")); } /** - * Checks if the value matches the regex pattern - * @param value - * @param regexPattern - * @return + * Checks if the value matches the regex pattern. + * @param value The value to be checked. + * @param regexPattern The regex pattern to match against. + * @return true if the value matches the pattern, false otherwise. */ public static boolean isValidPattern(String value, String regexPattern) { @@ -880,4 +1139,21 @@ public static boolean isValidPattern(String value, String regexPattern) { return matcher.matches(); } + /** + * Construct a Common Table Expression that returns total count if there is any otherwise return 0L + * @param query + * @param paramsMap + * @param namedParameterJdbcTemplate + * @return + */ + public static Long constructTotalCountCTEAndReturnResult(String query, Map paramsMap, final NamedParameterJdbcTemplate namedParameterJdbcTemplate) { + String cteQuery = "WITH result_cte AS ("+query+"), totalCount_cte AS (SELECT COUNT(*) AS totalRows FROM result_cte) select * from totalCount_cte"; + return namedParameterJdbcTemplate.query(cteQuery, paramsMap, resultSet -> { + if(resultSet.next()) + return resultSet.getLong("totalRows"); + else + return 0L; + }); + } + } diff --git a/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/mapper/GenericRowMapperTest.java b/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/mapper/GenericRowMapperTest.java deleted file mode 100644 index 6234a445c6d..00000000000 --- a/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/mapper/GenericRowMapperTest.java +++ /dev/null @@ -1,127 +0,0 @@ -package org.egov.common.data.mapper; - -import lombok.Getter; -import lombok.Setter; -import org.egov.common.data.query.annotations.Table; -import org.egov.common.data.query.builder.SelectQueryBuilder; -import org.egov.common.data.query.exception.QueryBuilderException; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; -import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder; -import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType; - -import java.sql.SQLException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; - -class GenericRowMapperTest { - - - EmbeddedDatabase db; - NamedParameterJdbcTemplate namedParameterJdbcTemplate; - @BeforeEach - public void setUp(){ - db = new EmbeddedDatabaseBuilder().setName("testdb;DATABASE_TO_UPPER=false") - .setType(EmbeddedDatabaseType.H2).addScript("schema.sql").build(); - namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(db); - } - @Test - @DisplayName("should map query to simple object") - void shouldMapQueryResulToSimpleObject() throws SQLException { - - List employeeList = namedParameterJdbcTemplate.query("SELECT * from employee", new GenericRowMapper(Employee.class)); - assertEquals(employeeList.get(0).getId().intValue(), 1); - assertEquals(employeeList.get(0).getName(), "JON"); - } - - @Test - @DisplayName("should map query to nested object") - void shouldMapQueryResulToNestedObject(){ - List employeeList = namedParameterJdbcTemplate.query("SELECT * from employee", new GenericRowMapper(NestedEmployee.class)); - assertEquals(employeeList.get(0).getAmount().getCurrency().getCurrency(), null); - assertEquals(employeeList.get(0).getAmount().getPrice(), 1500, 0); - assertEquals(employeeList.get(1).getAmount().getCurrency().getCurrency(), "INR"); - } - - @Test - @DisplayName("should map query to nested object with prepared sql query") - void shouldMapPreparedQueryResulToNestedObject(){ - String query = "SELECT * from employee where currency=:currency"; - Map queryMap = new HashMap(); - queryMap.put("currency", "INR"); - List employeeList = namedParameterJdbcTemplate.query(query, queryMap, new GenericRowMapper(NestedEmployee.class)); - assertEquals(employeeList.get(0).getId(), 2); - assertEquals(employeeList.get(0).getAmount().getPrice(), 1000); - assertEquals(employeeList.get(0).getAmount().getCurrency().getCurrency(), "INR"); - } - - @Test - @DisplayName("should throw an exception if datatypes between query result and object are incompatible") - void shouldThrowExceptionWhenDataTypeDoNotMatch(){ - assertThrows(RuntimeException.class, () -> namedParameterJdbcTemplate.query("SELECT * from employee", new GenericRowMapper(DataTypeMisMatch.class))); - } - - @Test - @DisplayName("should throw an exception if no default constructor is found") - void shouldThrowExceptionWhenNoDefaultConstructorIsFound(){ - assertThrows(RuntimeException.class, () -> namedParameterJdbcTemplate.query("SELECT * from employee", new GenericRowMapper(NoDefaultConstructor.class))); - } - - @Test - @DisplayName("should map query to simple object") - void shouldMapSelectQueryResulToSimpleObjectWithQueryBuilder() throws SQLException, QueryBuilderException { - Employee e = new Employee(); - e.setId(1); - - SelectQueryBuilder selectQueryBuilderqueryBuilder = new SelectQueryBuilder(); - List employeeList = namedParameterJdbcTemplate.query(selectQueryBuilderqueryBuilder.build(e), selectQueryBuilderqueryBuilder.getParamsMap(), new GenericRowMapper(Employee.class)); - - assertEquals(employeeList.get(0).getId().intValue(), 1); - assertEquals(employeeList.get(0).getName(), "JON"); - } -} - - -@Getter -@Setter -@Table(name = "employee") -class Employee{ - private Integer id; - private String name; -} - -@Getter -class NestedEmployee{ - private int id; - private String name; - private Amount amount; -} -@Getter -class Amount{ - private int price; - private Currency currency; -} -@Getter -class Currency{ - private String currency; -} -@Getter -class DataTypeMisMatch{ - private String price; -} - -@Getter -class NoDefaultConstructor{ - private int price; - public NoDefaultConstructor(int price){ - this.price = price; - } -} - diff --git a/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/query/GenericQueryBuilderTest.java b/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/query/GenericQueryBuilderTest.java index f194c115fd9..88fa60c9dfd 100644 --- a/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/query/GenericQueryBuilderTest.java +++ b/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/query/GenericQueryBuilderTest.java @@ -88,7 +88,7 @@ void shouldBuildSelectQueryForAnEmptyArrayListOfString() throws QueryBuilderExce DummyData data = DummyData.builder() .dummyStringList(strings) .build(); - String expectedQuery = "SELECT * FROM dummyData WHERE 1=1 "; + String expectedQuery = "SELECT * FROM dummyData "; SelectQueryBuilder queryBuilder = new SelectQueryBuilder(); String actualQuery = queryBuilder.build(data); @@ -102,7 +102,7 @@ void shouldHandleNullArrayListOfStringWhileBuildingSelectQuery() throws QueryBui DummyData data = DummyData.builder() .dummyStringList(null) .build(); - String expectedQuery = "SELECT * FROM dummyData WHERE 1=1 "; + String expectedQuery = "SELECT * FROM dummyData "; SelectQueryBuilder queryBuilder = new SelectQueryBuilder(); String actualQuery = queryBuilder.build(data); @@ -135,7 +135,7 @@ void shouldNotUsePrimitiveDataTypesWhileBuildingSelectingQuery() throws QueryBui void shouldNotUseWhereClauseWhenPropertiesAreSetToNullSelectQuery() throws QueryBuilderException { DummyData data = DummyData.builder() .build(); - String expectedQuery = "SELECT * FROM dummyData WHERE 1=1 "; + String expectedQuery = "SELECT * FROM dummyData "; SelectQueryBuilder queryBuilder = new SelectQueryBuilder(); String actualQuery = queryBuilder.build(data); diff --git a/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/repository/GenericRepositoryFindTest.java b/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/repository/GenericRepositoryFindTest.java index ae0a4537126..ff44953f806 100644 --- a/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/repository/GenericRepositoryFindTest.java +++ b/health-services/libraries/health-services-common/src/test/java/org/egov/common/data/repository/GenericRepositoryFindTest.java @@ -106,7 +106,7 @@ void shouldReturnObjectsFromDBForSearchRequest() throws QueryBuilderException { List deleted = result.stream().filter(someObject -> someObject.getIsDeleted() == Boolean.TRUE) .collect(Collectors.toList()); result.removeAll(deleted); - when(selectQueryBuilder.build(any(Object.class))) + when(selectQueryBuilder.build(any(Object.class), anyString())) .thenReturn("Select * from some_table where id='some-id' and isdeleted=false"); when(namedParameterJdbcTemplate.query(any(String.class), any(Map.class), any(SomeRowMapper.class))) .thenReturn(result); @@ -120,7 +120,7 @@ void shouldReturnObjectsFromDBForSearchRequest() throws QueryBuilderException { @Test @DisplayName("get products from db which are deleted") void shouldReturnObjectsFromDBForSearchRequestWithDeletedIncluded() throws QueryBuilderException { - when(selectQueryBuilder.build(any(Object.class))) + when(selectQueryBuilder.build(any(Object.class), anyString())) .thenReturn("Select * from some_table where id='some-id' and otherfield='other-field'"); when(namedParameterJdbcTemplate.query(any(String.class), any(Map.class), any(SomeRowMapper.class))) .thenReturn(someObjects); diff --git a/health-services/libraries/health-services-common/src/test/java/org/egov/common/utils/CommonUtilsTest.java b/health-services/libraries/health-services-common/src/test/java/org/egov/common/utils/CommonUtilsTest.java index 50151260f29..b50d359d969 100644 --- a/health-services/libraries/health-services-common/src/test/java/org/egov/common/utils/CommonUtilsTest.java +++ b/health-services/libraries/health-services-common/src/test/java/org/egov/common/utils/CommonUtilsTest.java @@ -38,13 +38,12 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import java.util.Set; import java.util.function.Predicate; -import java.util.function.UnaryOperator; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.getObjClass; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -152,30 +151,30 @@ void shouldGetTheDifferenceOfListsWhenBothTheListsHaveSameNumberOfItems() { assertEquals(0, CommonUtils.getDifference(idList, otherIdList).size()); } - @Test - @DisplayName("should validate the ids as per the given validator") - void shouldValidateTheIdsAsPerTheGivenValidator() { - Set idSet = new HashSet<>(); - idSet.add("some-id"); - idSet.add("other-id"); - UnaryOperator> validator = UnaryOperator.identity(); - - assertDoesNotThrow(() -> CommonUtils.validateIds(idSet, validator)); - } - - @Test - @DisplayName("should throw exception in case an invalid id is found") - void shouldThrowExceptionInCaseAnInvalidIdIsFound() { - Set idSet = new HashSet<>(); - idSet.add("some-id"); - idSet.add("other-id"); - UnaryOperator> validator = (idList) -> { - idList.remove(0); - return idList; - }; - - assertDoesNotThrow(() -> CommonUtils.validateIds(idSet, validator)); - } +// @Test +// @DisplayName("should validate the ids as per the given validator") +// void shouldValidateTheIdsAsPerTheGivenValidator() { +// Set idSet = new HashSet<>(); +// idSet.add("some-id"); +// idSet.add("other-id"); +// UnaryOperator> validator = UnaryOperator.identity(); +// +// assertDoesNotThrow(() -> CommonUtils.validateIds(idSet, validator)); +// } +// +// @Test +// @DisplayName("should throw exception in case an invalid id is found") +// void shouldThrowExceptionInCaseAnInvalidIdIsFound() { +// Set idSet = new HashSet<>(); +// idSet.add("some-id"); +// idSet.add("other-id"); +// UnaryOperator> validator = (idList) -> { +// idList.remove(0); +// return idList; +// }; +// +// assertDoesNotThrow(() -> CommonUtils.validateIds(idSet, validator)); +// } @Test @DisplayName("should get audit details for create") @@ -303,7 +302,7 @@ void shouldReturnRequestObjectWithMismatchedRowVersion() { objList.add(otherObject); objList.add(otherInvalidObject); - Method idMethod = CommonUtils.getMethod("getId", SomeObject.class); + Method idMethod = getMethod("getId", SomeObject.class); assertEquals("some-other-id", CommonUtils.getEntitiesWithMismatchedRowVersion(idToObjMap, objList, idMethod).get(0).getId()); @@ -595,8 +594,7 @@ void shouldSupplySpecifiedNumberOfUuids() { void shouldGetIdFieldNameFromMethod() { SomeObjectWithClientRefId someObject = SomeObjectWithClientRefId.builder() .clientReferenceId("some-client-reference-id").build(); - assertEquals("clientReferenceId", CommonUtils.getIdFieldName(CommonUtils - .getMethod("getClientReferenceId", someObject.getClass()))); + assertEquals("clientReferenceId", CommonUtils.getIdFieldName(getMethod("getClientReferenceId", someObject.getClass()))); } @Test diff --git a/health-services/libraries/health-services-models/CHANGELOG.md b/health-services/libraries/health-services-models/CHANGELOG.md index a09fe37f16c..767df086abf 100644 --- a/health-services/libraries/health-services-models/CHANGELOG.md +++ b/health-services/libraries/health-services-models/CHANGELOG.md @@ -1,5 +1,9 @@ All notable changes to this module will be documented in this file. +## 1.0.20 - 2024-05-29 +- Added EgovModel, EgovSearchModel, EgovOfflineModel, EgovOfflineSearchModel +- Updated Lombok to 1.18.22 for SuperBuilder annotation support. +- Upgraded to 2.9 LTS ## 1.0.19 - 2024-02-26 - Updated project staff search to accept a list of staffIds diff --git a/health-services/libraries/health-services-models/Dockerfile b/health-services/libraries/health-services-models/Dockerfile index cd50dd4120d..80abf117900 100644 --- a/health-services/libraries/health-services-models/Dockerfile +++ b/health-services/libraries/health-services-models/Dockerfile @@ -1,8 +1,10 @@ -FROM egovio/alpine-maven-builder-jdk-8:1-master-NA-6036091e AS build +FROM egovio/amazoncorretto:17-alpine3.19 AS build ARG WORK_DIR ARG nexusUsername ARG nexusPassword WORKDIR /app +# Install Maven +RUN apk add --no-cache maven # copy the project files COPY ${WORK_DIR}/pom.xml ./pom.xml COPY ${WORK_DIR}/settings.xml ./settings.xml diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index 3dafc7c24a0..ccbf98bc824 100644 --- a/health-services/libraries/health-services-models/pom.xml +++ b/health-services/libraries/health-services-models/pom.xml @@ -5,10 +5,11 @@ 4.0.0 org.egov.common health-services-models - 1.0.19-SNAPSHOT + 1.0.20-SNAPSHOT - 8 - 8 + 17 + ${java.version} + ${java.version} UTF-8 @@ -31,7 +32,25 @@ org.egov.services tracer - 2.1.4-SNAPSHOT + 2.9.0-SNAPSHOT + + + jakarta.validation + jakarta.validation-api + 3.0.2 + compile + + + org.hibernate.validator + hibernate-validator + 8.0.1.Final + compile + + + io.swagger + swagger-annotations + 1.5.18 + compile @@ -48,30 +67,6 @@ - - - - org.apache.maven.plugins - maven-site-plugin - 3.7.1 - - - org.apache.maven.plugins - maven-deploy-plugin - 2.8.2 - - - default-deploy - deploy - - deploy - - - - - - - repo.egovernments.org diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/AdditionalFields.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/AdditionalFields.java new file mode 100644 index 00000000000..4d42ce72395 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/AdditionalFields.java @@ -0,0 +1,51 @@ +package org.egov.common.models.core; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * AdditionalFields + */ +@Validated + + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class AdditionalFields { + @JsonProperty("schema") + @Size(min = 2, max = 64) + private String schema = null; + + @JsonProperty("version") + @Min(1) + private Integer version = null; + + @JsonProperty("fields") + @Valid + private List fields = null; + + + public AdditionalFields addFieldsItem(Field fieldsItem) { + if (this.fields == null) { + this.fields = new ArrayList<>(); + } + this.fields.add(fieldsItem); + return this; + } + +} + diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Boundary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Boundary.java new file mode 100644 index 00000000000..f3632bb819b --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Boundary.java @@ -0,0 +1,44 @@ +package org.egov.common.models.core; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.tracer.model.AuditDetails; +import org.springframework.validation.annotation.Validated; + +/** + * Boundary + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Boundary { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("code") + @NotNull + private String code = null; + + @JsonProperty("geometry") + @Valid + private JsonNode geometry = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("additionalDetails") + private JsonNode additionalDetails = null; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovModel.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovModel.java new file mode 100644 index 00000000000..d125458f9af --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovModel.java @@ -0,0 +1,57 @@ +package org.egov.common.models.core; + + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class EgovModel { + + @JsonProperty("id") + @Size(min = 2, max = 64) + protected String id; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 1000) + protected String tenantId; + + @JsonProperty("status") + protected String status; + + @JsonProperty("source") + protected String source; //TODO what are the various sources and needs comments + + @JsonProperty("rowVersion") + protected Integer rowVersion; + + @JsonProperty("applicationId") //needs comments + protected String applicationId; + + @JsonProperty("hasErrors") + @Builder.Default + protected Boolean hasErrors = Boolean.FALSE; //TODO is this health specific or will this become general. + + @JsonProperty("additionalFields") + @Valid + protected AdditionalFields additionalFields; + + @JsonProperty("auditDetails") + @Valid + protected AuditDetails auditDetails; + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovOfflineModel.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovOfflineModel.java new file mode 100644 index 00000000000..e816f6cd3ce --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovOfflineModel.java @@ -0,0 +1,27 @@ +package org.egov.common.models.core; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import digit.models.coremodels.AuditDetails; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class EgovOfflineModel extends EgovModel { + @JsonProperty("clientReferenceId") + @Size(min = 2, max = 64) + protected String clientReferenceId; + + @JsonProperty("clientAuditDetails") + @Valid + protected AuditDetails clientAuditDetails; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovOfflineSearchModel.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovOfflineSearchModel.java new file mode 100644 index 00000000000..9f74f4956b4 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovOfflineSearchModel.java @@ -0,0 +1,20 @@ +package org.egov.common.models.core; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class EgovOfflineSearchModel extends EgovSearchModel { + @JsonProperty("clientReferenceId") + private List clientReferenceId = null; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovSearchModel.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovSearchModel.java new file mode 100644 index 00000000000..ab0113965d3 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovSearchModel.java @@ -0,0 +1,22 @@ +package org.egov.common.models.core; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class EgovSearchModel { + @JsonProperty("id") + @Valid + private List id = null; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Exclude.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Exclude.java new file mode 100644 index 00000000000..48b882c13aa --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Exclude.java @@ -0,0 +1,13 @@ +package org.egov.common.models.core; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +// This annotation is used to mark fields in a model class that should be ignored or excluded when the class is being processed, +// specifically during serialization to JSON or when constructing database queries. +public @interface Exclude { +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Field.java new file mode 100644 index 00000000000..4b24913d764 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Field.java @@ -0,0 +1,37 @@ +package org.egov.common.models.core; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * Field + */ +@Validated + + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class Field { + @JsonProperty("key") + @NotNull + @Size(min = 2, max = 64) + private String key = null; + + @JsonProperty("value") + @NotNull + @Size(min = 1, max = 10000) + private String value = null; + + +} + diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/ProjectSearchURLParams.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/ProjectSearchURLParams.java new file mode 100644 index 00000000000..92fdce4ef8d --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/ProjectSearchURLParams.java @@ -0,0 +1,47 @@ +package org.egov.common.models.core; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; + +/** + * Model class representing common search criteria for API search operations. + * @author kanishq-egov + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ProjectSearchURLParams extends URLParams { + /** + * Used in project search API to specify if response should include project elements + * that are in the preceding hierarchy of matched projects. + */ + @JsonProperty("includeAncestors") + private Boolean includeAncestors; + + /** + * Used in project search API to specify if response should include project elements + * that are in the following hierarchy of matched projects. + */ + @JsonProperty("includeDescendants") + private Boolean includeDescendants; + + /** + * Used in project search API to limit the search results to only those projects whose creation + * date is after the specified 'createdFrom' date. + */ + @JsonProperty("createdFrom") + private Long createdFrom; + + /** + * Used in project search API to limit the search results to only those projects whose creation + * date is before the specified 'createdTo' date. + */ + @JsonProperty("createdTo") + private Long createdTo; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Role.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Role.java index d5c0da52bc1..a7f99255ca7 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Role.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Role.java @@ -11,6 +11,7 @@ @NoArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public class Role { private static final String CITIZEN = "CITIZEN"; private String name; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/SearchResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/SearchResponse.java new file mode 100644 index 00000000000..f688b53e08a --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/SearchResponse.java @@ -0,0 +1,38 @@ +package org.egov.common.models.core; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +@ApiModel(description = "Representation of SearchResponse.") +@Validated + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class SearchResponse { + + @JsonProperty("TotalCount") + @Getter(AccessLevel.NONE) + private Long totalCount; + + @JsonProperty("Response") + @Builder.Default + private List response = new ArrayList<>(); + + public Long getTotalCount() { + if(totalCount == null) + totalCount = (long) response.size(); + return totalCount; + } +} \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Table.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Table.java new file mode 100644 index 00000000000..8531b0b51b4 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/Table.java @@ -0,0 +1,15 @@ +package org.egov.common.models.core; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +// It is used to specify the table name associated with a class. +// When you annotate a class with @Table, it indicates that the class is mapped to a table in the database. +// Used in GenericQueryBuilder +public @interface Table { + String name() default ""; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/URLParams.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/URLParams.java new file mode 100644 index 00000000000..272705efd8e --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/URLParams.java @@ -0,0 +1,86 @@ +package org.egov.common.models.core; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +//TODO should we move all this to body model or should we keep this in url? same with search common models +/** + * Model class representing common search criteria for API search operations. + * @author kanishq-egov + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class URLParams { + + /** + * The maximum number of records to be returned in the response. + */ + @NotNull + @Min(0) + @Max(1000) + @JsonProperty("limit") + private Integer limit; + + /** + * The offset from which records should be returned in the response. + */ + @NotNull + @Min(0) + @JsonProperty("offset") + private Integer offset; + + /** + * The unique identifier for the tenant. + */ + @NotNull + @JsonProperty("tenantId") + private String tenantId; + + /** + * The epoch time representing point in time since last modification happened in the table. + * Results from this parameter should include both newly created objects and modified objects from this time. + * This criterion aids polling clients to synchronize changes since their last synchronization with the platform. + */ + @JsonProperty("lastChangedSince") + private Long lastChangedSince; + + /** + * Flag indicating whether soft deleted records should be included in search results. + * This flag is used in search APIs to specify if deleted records should be included. + */ + @JsonProperty("includeDeleted") + private Boolean includeDeleted; + + /** + * Sets the URL parameters from the given URLParams object. + * This method allows updating the current URLParams instance with values from another instance. + * + * @param urlParams the URL parameters to set + */ + public void setURLParams(URLParams urlParams) { + // Update limit if provided in the input URLParams + if (urlParams.getLimit() != null) this.limit = urlParams.getLimit(); + + // Update offset if provided in the input URLParams + if (urlParams.getOffset() != null) this.offset = urlParams.getOffset(); + + // Update tenantId if provided in the input URLParams + if (urlParams.getTenantId() != null) this.tenantId = urlParams.getTenantId(); + + // Update lastChangedSince if provided in the input URLParams + if (urlParams.getLastChangedSince() != null) this.lastChangedSince = urlParams.getLastChangedSince(); + + // Update includeDeleted if provided in the input URLParams + if (urlParams.getIncludeDeleted() != null) this.includeDeleted = urlParams.getIncludeDeleted(); + } + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/UpdateBy.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/UpdateBy.java new file mode 100644 index 00000000000..a07a0964a89 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/UpdateBy.java @@ -0,0 +1,13 @@ +package org.egov.common.models.core; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +// This annotation is used to mark specific fields in a class that should be specially considered during update operations +// Used in GenericQueryBuilder +public @interface UpdateBy { +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/AdditionalFields.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/AdditionalFields.java index 306fd76b745..3ea950184ae 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/AdditionalFields.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/AdditionalFields.java @@ -8,9 +8,9 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Min; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -18,13 +18,14 @@ * AdditionalFields */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public class AdditionalFields { @JsonProperty("schema") @Size(min = 2, max = 64) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Address.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Address.java index b0b69f16b1d..3f6469257f9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Address.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Address.java @@ -2,30 +2,30 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.models.core.Boundary; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.DecimalMax; -import javax.validation.constraints.DecimalMin; -import javax.validation.constraints.Size; - /** * Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. */ -@ApiModel(description = "Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. ") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated +//TODO should move to common public class Address { @JsonProperty("id") @Size(min = 2, max = 64) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/AddressType.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/AddressType.java index 44b904ce16d..9c4931a7005 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/AddressType.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/AddressType.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonValue; @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public enum AddressType { PERMANENT("PERMANENT"), diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Boundary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Boundary.java deleted file mode 100644 index da9c7cd36af..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Boundary.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.egov.common.models.facility; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - -/** - * Boundary - */ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class Boundary { - @JsonProperty("code") - @NotNull - private String code = null; - - @JsonProperty("name") - private String name = null; - - @JsonProperty("label") - private String label = null; - - @JsonProperty("latitude") - private String latitude = null; - - @JsonProperty("longitude") - private String longitude = null; - - @JsonProperty("children") - @Valid - private List children = null; - - @JsonProperty("materializedPath") - private String materializedPath = null; - - - public Boundary addChildrenItem(Boundary childrenItem) { - if (this.children == null) { - this.children = new ArrayList<>(); - } - this.children.add(childrenItem); - return this; - } - -} - diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java index 338afe924b0..3c4d8ba3bf9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Facility.java @@ -8,35 +8,25 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * Facility */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class Facility { - @JsonProperty("id") - @Size(min = 2, max = 64) - private String id = null; - - @JsonProperty("clientReferenceId") - @Size(min = 2, max = 64) - private String clientReferenceId = null; - - @JsonProperty("tenantId") - @NotNull - @Size(min = 2, max = 1000) - private String tenantId = null; +public class Facility extends EgovOfflineModel { @JsonProperty("isPermanent") private Boolean isPermanent = true; @@ -55,22 +45,10 @@ public class Facility { @Valid private Address address = null; - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; - + //TODO remove this @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkRequest.java index fe151f99b78..36c96818a5b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkRequest.java @@ -8,9 +8,9 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * FacilityBulkRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkResponse.java index 518d8a0bda7..d58d67eba90 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityBulkResponse.java @@ -8,8 +8,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -17,7 +17,7 @@ * FacilityResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityRequest.java index 84991acd405..be7a61eb30d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityRequest.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * FacilityRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityResponse.java index f4ee54685dd..d0642700db3 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilityResponse.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * FacilityResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilitySearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilitySearch.java index 902b590142b..22f6e9d7a2a 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilitySearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilitySearch.java @@ -3,32 +3,24 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import java.util.List; - /** * FacilitySearch */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class FacilitySearch { - @JsonProperty("id") - @Valid - private List id = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; +public class FacilitySearch extends EgovOfflineSearchModel { @JsonProperty("isPermanent") private Boolean isPermanent = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilitySearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilitySearchRequest.java index 02aa94572b7..6a6924bea67 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilitySearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/FacilitySearchRequest.java @@ -8,20 +8,21 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * FacilitySearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +//TODO should we extend model request info wrapper public class FacilitySearchRequest { @JsonProperty("RequestInfo") @NotNull diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Field.java index 78218ccbf63..5bfc126060e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Field.java @@ -5,6 +5,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -15,7 +17,7 @@ * Field */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/TenantRole.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/TenantRole.java index b506a8022a3..d706a86fcff 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/TenantRole.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/TenantRole.java @@ -9,8 +9,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -19,13 +19,14 @@ */ @ApiModel(description = "User role carries the tenant related role information for the user. A user can have multiple roles per tenant based on the need of the tenant. A user may also have multiple roles for multiple tenants.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +//TODO compare with services common public class TenantRole { @JsonProperty("tenantId") @NotNull diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/UserInfo.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/UserInfo.java index 9f815c89caa..a534fb37cfb 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/UserInfo.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/UserInfo.java @@ -9,8 +9,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -19,13 +19,14 @@ */ @ApiModel(description = "This is acting ID token of the authenticated user on the server. Any value provided by the clients will be ignored and actual user based on authtoken will be used on the server.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-21T14:37:54.683+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +//TODO should be imported from common model library public class UserInfo { @JsonProperty("tenantId") @NotNull diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/AdditionalFields.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/AdditionalFields.java index 34017c09cb6..c38b8ef5b97 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/AdditionalFields.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/AdditionalFields.java @@ -8,9 +8,9 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Min; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -18,13 +18,14 @@ * AdditionalFields */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public class AdditionalFields { @JsonProperty("schema") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Address.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Address.java index e173fb7cf96..d6578c2808a 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Address.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Address.java @@ -2,31 +2,30 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.models.core.Boundary; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.DecimalMax; -import javax.validation.constraints.DecimalMin; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. */ - @ApiModel(description = "Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. ") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public class Address { @JsonProperty("id") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/AddressType.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/AddressType.java index 0a8ca8bffa4..93b2a83b51e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/AddressType.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/AddressType.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonValue; @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public enum AddressType { PERMANENT("PERMANENT"), diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Boundary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Boundary.java deleted file mode 100644 index cdf33544995..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Boundary.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.egov.common.models.household; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.constraints.NotNull; - -/** -* Boundary -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class Boundary { - - @JsonProperty("code") - @NotNull - private String code = null; - - @JsonProperty("name") - private String name = null; - - @JsonProperty("label") - private String label = null; - - @JsonProperty("latitude") - private String latitude = null; - - @JsonProperty("longitude") - private String longitude = null; - -// @JsonProperty("children") -// -// @Valid -// -// -// private List children = null; - - @JsonProperty("materializedPath") - private String materializedPath = null; - - -// public Boundary addChildrenItem(Boundary childrenItem) { -// if (this.children == null) { -// this.children = new ArrayList<>(); -// } -// this.children.add(childrenItem); -// return this; -// } - -} - diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Field.java index bb53d162286..c948934f9c9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Field.java @@ -1,7 +1,7 @@ package org.egov.common.models.household; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -15,7 +15,7 @@ * Field */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java index 56cdaeef0a4..2452054c4f8 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Household.java @@ -1,47 +1,29 @@ package org.egov.common.models.household; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; -import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; import org.hibernate.validator.constraints.Range; +import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * A representation of Household. */ - @ApiModel(description = "A representation of Household.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class Household { - - @JsonProperty("id") - @Size(min = 2, max = 64) - private String id = null; - - @JsonProperty("tenantId") - @NotNull - @Size(min = 2, max = 1000) - private String tenantId = null; - - @JsonProperty("clientReferenceId") - @Size(min = 2, max = 64) - private String clientReferenceId = null; +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class Household extends EgovOfflineModel { @JsonProperty("memberCount") @NotNull @@ -52,25 +34,9 @@ public class Household { @Valid private Address address = null; - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; - + //TODO remove @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; - - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkRequest.java index a32ca4cc532..cf1b86cc6d2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkRequest.java @@ -9,9 +9,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ * HouseholdRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkResponse.java index 8336aad33be..3646ac55627 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdBulkResponse.java @@ -9,8 +9,8 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * HouseholdResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java index 6febe6009f3..c7e016e117d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMember.java @@ -9,29 +9,27 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * A representation of a household member (already registered as an individual) */ @ApiModel(description = "A representation of a household member (already registered as an individual)") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class HouseholdMember{ - - @JsonProperty("id") - @Size(min = 2, max = 64) - private String id = null; +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class HouseholdMember extends EgovOfflineModel { @JsonProperty("householdId") @Size(min = 2, max = 64) @@ -41,11 +39,6 @@ public class HouseholdMember{ @Size(min = 2, max = 64) private String householdClientReferenceId = null; - @JsonProperty("clientReferenceId") - @Size(min = 2, max = 64) - @NotNull - private String clientReferenceId = null; - @JsonProperty("individualId") @Size(min = 2, max = 64) private String individualId = null; @@ -57,30 +50,9 @@ public class HouseholdMember{ @JsonProperty("isHeadOfHousehold") private Boolean isHeadOfHousehold = false; - @JsonProperty("tenantId") - @Size(min = 2, max = 1000) - @NotNull - private String tenantId = null; - - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; - + //TODO remove @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; - - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkRequest.java index 192ccefd97c..9e45a1f496c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkRequest.java @@ -8,9 +8,9 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * HouseholdMemberRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkResponse.java index 4b89d6c0919..529336e2052 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberBulkResponse.java @@ -8,8 +8,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -17,7 +17,7 @@ * HouseholdMemberResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor @@ -30,6 +30,11 @@ public class HouseholdMemberBulkResponse { @Valid private org.egov.common.contract.response.ResponseInfo responseInfo = null; + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + @JsonProperty("HouseholdMembers") @Valid private List householdMembers = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberRequest.java index 13721826587..afe2b3a35a2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberRequest.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * HouseholdMemberRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberResponse.java index 559326a3a62..4439b053fa2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberResponse.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * HouseholdMemberResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearch.java index e7b7fa8212e..d435704b4f6 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearch.java @@ -1,55 +1,48 @@ package org.egov.common.models.household; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import java.util.List; - /** * Search model for household member */ @ApiModel(description = "Search model for household member") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class HouseholdMemberSearch { +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class HouseholdMemberSearch extends EgovOfflineSearchModel { - @JsonProperty("id") - private List id = null; + @JsonProperty("clientReferenceId") + private List clientReferenceId = null; @JsonProperty("householdId") - private String householdId = null; + private List householdId = null; @JsonProperty("householdClientReferenceId") - private String householdClientReferenceId = null; + private List householdClientReferenceId = null; @JsonProperty("individualId") - private String individualId = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; + private List individualId = null; @JsonProperty("individualClientReferenceId") - private String individualClientReferenceId = null; + private List individualClientReferenceId = null; @JsonProperty("isHeadOfHousehold") private Boolean isHeadOfHousehold = null; - @JsonProperty("tenantId") - @Valid - private String tenantId = null; - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearchRequest.java index 1d5d0d66bc7..1827c58c249 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdMemberSearchRequest.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * HouseholdMemberSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdRequest.java index cbd6cc2da5a..2f97fff1203 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * HouseholdRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdResponse.java index f184e37bf27..8659cc34bbf 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdResponse.java @@ -9,14 +9,14 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * HouseholdResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearch.java index 6e31a74c882..4ff5ccec51e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearch.java @@ -1,39 +1,48 @@ package org.egov.common.models.household; -import java.util.List; - -import org.springframework.validation.annotation.Validated; - import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; - -import io.swagger.annotations.ApiModel; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; +import org.egov.common.models.core.Exclude; +import org.springframework.validation.annotation.Validated; /** * A representation of Household. */ - @ApiModel(description = "A representation of Household.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") - @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class HouseholdSearch { - - @JsonProperty("id") - private List id = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; - +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class HouseholdSearch extends EgovOfflineSearchModel { @JsonProperty("boundaryCode") private String localityCode = null; + + @Exclude + @JsonProperty("latitude") + @DecimalMin("-90") + @DecimalMax("90") + private Double latitude = null; + + @Exclude + @JsonProperty("longitude") + @DecimalMin("-180") + @DecimalMax("180") + private Double longitude = null; + + /* + * @value unit of measurement in Kilometer + * */ + @Exclude + @JsonProperty("searchRadius") + @DecimalMin("0") + private Double searchRadius = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearchRequest.java index 1d81812a352..57e5377b5ca 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/HouseholdSearchRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * HouseholdSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/TenantRole.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/TenantRole.java index 5b863c7e25f..9a37607d2ca 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/TenantRole.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/TenantRole.java @@ -9,8 +9,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ */ @ApiModel(description = "User role carries the tenant related role information for the user. A user can have multiple roles per tenant based on the need of the tenant. A user may also have multiple roles for multiple tenants.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/UserInfo.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/UserInfo.java index b6afe741c3d..648f7640cbe 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/UserInfo.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/UserInfo.java @@ -9,8 +9,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ */ @ApiModel(description = "This is acting ID token of the authenticated user on the server. Any value provided by the clients will be ignored and actual user based on authtoken will be used on the server.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-21T13:41:16.379+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/AdditionalFields.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/AdditionalFields.java index a16758cdf9b..2546f7f417e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/AdditionalFields.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/AdditionalFields.java @@ -8,9 +8,9 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Min; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -18,13 +18,14 @@ * AdditionalFields */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public class AdditionalFields { @JsonProperty("schema") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Address.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Address.java index 80070ce7cc4..4367ad3057d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Address.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Address.java @@ -8,25 +8,27 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.models.core.Boundary; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.DecimalMax; -import javax.validation.constraints.DecimalMin; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. */ @ApiModel(description = "Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. ") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder - @JsonIgnoreProperties(ignoreUnknown = true) +@JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public class Address { @JsonProperty("id") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/AddressType.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/AddressType.java index cfbdd36f0e2..d4b8d0b5b00 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/AddressType.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/AddressType.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonValue; @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public enum AddressType { PERMANENT("PERMANENT"), diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Boundary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Boundary.java deleted file mode 100644 index 2e7185ea6ce..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Boundary.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.egov.common.models.individual; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - -/** -* Boundary -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class Boundary { - @JsonProperty("code") - @NotNull - - - - private String code = null; - - @JsonProperty("name") - - - - private String name = null; - - @JsonProperty("label") - - - - private String label = null; - - @JsonProperty("latitude") - - - - private String latitude = null; - - @JsonProperty("longitude") - - - - private String longitude = null; - - @JsonProperty("children") - - @Valid - - - private List children = null; - - @JsonProperty("materializedPath") - - - - private String materializedPath = null; - - - public Boundary addChildrenItem(Boundary childrenItem) { - if (this.children == null) { - this.children = new ArrayList<>(); - } - this.children.add(childrenItem); - return this; - } - -} - diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Field.java index b189fbe154e..c6b33f09776 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Field.java @@ -1,7 +1,7 @@ package org.egov.common.models.individual; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -15,7 +15,7 @@ * Field */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Identifier.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Identifier.java index 9bb88701d75..213a67a9446 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Identifier.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Identifier.java @@ -9,15 +9,15 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * Identifier */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java index 3bcaf631a4b..e045ff1fea5 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Individual.java @@ -10,11 +10,13 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -24,32 +26,19 @@ */ @ApiModel(description = "A representation of an Individual.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class Individual { - - @JsonProperty("id") - @Size(min = 2, max = 64) - private String id = null; +public class Individual extends EgovOfflineModel { @JsonProperty("individualId") @Size(min = 2, max = 64) private String individualId = null; - @JsonProperty("tenantId") - @NotNull - @Size(min = 2, max = 1000) - private String tenantId = null; - - @JsonProperty("clientReferenceId") - @Size(min = 2, max = 64) - private String clientReferenceId = null; - @JsonProperty("userId") private String userId = null; @@ -113,27 +102,10 @@ public class Individual { @JsonProperty("photo") private String photo = null; - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; - + //TODO remove @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; - - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; - @JsonProperty("isSystemUser") private Boolean isSystemUser = Boolean.FALSE; @@ -143,7 +115,6 @@ public class Individual { @JsonProperty("userDetails") private UserDetails userDetails; - public Individual addAddressItem(Address addressItem) { if (this.address == null) { this.address = new ArrayList<>(); diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkRequest.java index 6ec2f502a46..4810780d4e7 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkRequest.java @@ -9,9 +9,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ * IndividualRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkResponse.java index a9952743df9..5a185cbaf8d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualBulkResponse.java @@ -9,8 +9,8 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * IndividualResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor @@ -32,6 +32,11 @@ public class IndividualBulkResponse { @Valid private ResponseInfo responseInfo = null; + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + @JsonProperty("Individual") @Valid private List individual = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualDeleteRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualDeleteRequest.java index 834d1e7f6bf..67c05cc7744 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualDeleteRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualDeleteRequest.java @@ -8,8 +8,8 @@ import lombok.NoArgsConstructor; import org.egov.common.contract.request.RequestInfo; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.List; @Data diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualRequest.java index 2e8857e0176..c8b7927e036 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * IndividualRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualResponse.java index 146f0e3b809..e782b4af9a8 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualResponse.java @@ -9,14 +9,14 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * IndividualResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java index d4471a9e29e..5c907f249fe 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearch.java @@ -1,42 +1,38 @@ package org.egov.common.models.individual; +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; +import org.egov.common.models.core.Exclude; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Size; -import java.math.BigDecimal; -import java.util.Date; -import java.util.List; - /** * A representation of an Individual. */ - @ApiModel(description = "A representation of an Individual.") +@ApiModel(description = "A representation of an Individual.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") - @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class IndividualSearch { - @JsonProperty("id") - private List id = null; - +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class IndividualSearch extends EgovOfflineSearchModel { @JsonProperty("individualId") - private String individualId = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; + private List individualId = null; @JsonProperty("name") @Valid @@ -51,7 +47,7 @@ public class IndividualSearch { private Gender gender = null; @JsonProperty("mobileNumber") - private String mobileNumber = null; + private List mobileNumber = null; @JsonProperty("socialCategory") private String socialCategory = null; @@ -79,13 +75,37 @@ public class IndividualSearch { private List roleCodes = null; @JsonProperty("username") - private String username; + private List username; @JsonProperty("userId") - private Long userId; + private List userId; @JsonProperty("userUuid") @Size(min = 1) private List userUuid; + + @Exclude + @JsonProperty("latitude") + @DecimalMin("-90") + @DecimalMax("90") + private Double latitude; + + @Exclude + @JsonProperty("longitude") + @DecimalMin("-180") + @DecimalMax("180") + private Double longitude; + + /* + * @value unit of measurement in Kilometer + * */ + @Exclude + @JsonProperty("searchRadius") + @DecimalMin("0") + private Double searchRadius; + + + @JsonProperty("type") + private String type; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearchRequest.java index d01730b19e6..a5c3e9cdeaa 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/IndividualSearchRequest.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * IndividualSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Name.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Name.java index 2739d9963e7..7a75ea01913 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Name.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Name.java @@ -8,13 +8,13 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.Size; /** * Name */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Skill.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Skill.java index ec0ac588977..58b905a8522 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Skill.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Skill.java @@ -9,15 +9,15 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * Identifier */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-27T11:47:19.561+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java index e524ab8389e..ea435d9fac9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/UserDetails.java @@ -9,8 +9,8 @@ import lombok.NoArgsConstructor; import org.egov.common.models.core.Role; -import javax.validation.Valid; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Size; import java.util.List; @Data diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/AdditionalFields.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/AdditionalFields.java index 948d8bb5c2c..87d1cd3ea63 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/AdditionalFields.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/AdditionalFields.java @@ -8,9 +8,9 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Min; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -18,13 +18,14 @@ * AdditionalFields */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public class AdditionalFields { @JsonProperty("schema") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Address.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Address.java index ac40eaa04e8..dfefe72564d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Address.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Address.java @@ -3,29 +3,30 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.models.core.Boundary; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.DecimalMax; -import javax.validation.constraints.DecimalMin; -import javax.validation.constraints.Size; - /** * Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. */ @ApiModel(description = "Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. ") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder - @JsonIgnoreProperties(ignoreUnknown = true) +@JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public class Address { @JsonProperty("id") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Boundary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Boundary.java deleted file mode 100644 index 6cfb2b5c352..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Boundary.java +++ /dev/null @@ -1,83 +0,0 @@ -package org.egov.common.models.product; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - -/** -* Boundary -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class Boundary { - @JsonProperty("code") - @NotNull - - - - private String code = null; - - @JsonProperty("name") - @NotNull - - - - private String name = null; - - @JsonProperty("label") - - - - private String label = null; - - @JsonProperty("latitude") - - - - private String latitude = null; - - @JsonProperty("longitude") - - - - private String longitude = null; - - @JsonProperty("children") - - @Valid - - - private List children = null; - - @JsonProperty("materializedPath") - - - - private String materializedPath = null; - - - public Boundary addChildrenItem(Boundary childrenItem) { - if (this.children == null) { - this.children = new ArrayList<>(); - } - this.children.add(childrenItem); - return this; - } - -} - diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Field.java index 828a1cad303..f27a52cf429 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Field.java @@ -1,7 +1,7 @@ package org.egov.common.models.product; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -15,7 +15,7 @@ * Field */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java index 32b9ace7565..afa12e20be2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Product.java @@ -7,32 +7,27 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * Product */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class Product { - - @JsonProperty("id") - private String id = null; +public class Product extends EgovModel { - @JsonProperty("tenantId") - @NotNull - @Size(min=2,max=1000) - private String tenantId = null; @JsonProperty("type") @NotNull @@ -48,19 +43,9 @@ public class Product { @Size(min = 0, max = 1000) private String manufacturer = null; - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; - + //TODO remove @JsonProperty("isDeleted") private Boolean isDeleted = null; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductRequest.java index 3811feae8ea..5b209a65ff9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductRequest.java @@ -9,9 +9,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ * ProductRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductResponse.java index 9d89ecc7763..52865f39251 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductResponse.java @@ -9,8 +9,8 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * ProductResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductSearch.java index 30f02119ab0..5b4907bb571 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductSearch.java @@ -1,38 +1,36 @@ package org.egov.common.models.product; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovSearchModel; import org.springframework.validation.annotation.Validated; -import java.util.List; - /** * ProductSearch */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class ProductSearch { - - @JsonProperty("id") - private List id = null; +public class ProductSearch extends EgovSearchModel { @JsonProperty("type") private String type = null; @JsonProperty("name") - private String name = null; + private List name = null; @JsonProperty("manufacturer") - private String manufacturer = null; + private List manufacturer = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductSearchRequest.java index 62cb48ceaab..1f32dad0bf8 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductSearchRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * ProductSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java index 02004d7ce43..6f7e34e6b5e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariant.java @@ -1,83 +1,47 @@ package org.egov.common.models.product; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * ProductVariant */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class ProductVariant { - @JsonProperty("id") - - - private String id = null; - - @JsonProperty("tenantId") - @NotNull - @Size(min=2,max=1000) - private String tenantId = null; +public class ProductVariant extends EgovModel { @JsonProperty("productId") @NotNull - - @Size(min = 2, max = 64) - private String productId = null; @JsonProperty("sku") - - @Size(min = 0, max = 1000) - private String sku = null; @JsonProperty("variation") @NotNull - - @Size(min = 0, max = 1000) - private String variation = null; - @JsonProperty("additionalFields") - - @Valid - - - private AdditionalFields additionalFields = null; - + //TODO remove @JsonProperty("isDeleted") - - private Boolean isDeleted = null; - @JsonProperty("rowVersion") - - - private Integer rowVersion = null; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantRequest.java index 9f7bd7074aa..e9d815128a9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantRequest.java @@ -9,9 +9,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ * ProductVariantRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantResponse.java index ef76bbb54ce..5584a534753 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantResponse.java @@ -9,8 +9,8 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * ProductVariantResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantSearch.java index 8a030c3cc84..1f024529025 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantSearch.java @@ -1,35 +1,32 @@ package org.egov.common.models.product; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovSearchModel; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.Size; -import java.util.List; - /** * ProductVariantSearch */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class ProductVariantSearch { - - @JsonProperty("id") - private List id = null; +public class ProductVariantSearch extends EgovSearchModel { @JsonProperty("productId") - @Size(min = 2, max = 64) - private String productId = null; + private List productId = null; @JsonProperty("sku") @Size(min = 0, max = 1000) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantSearchRequest.java index 6485447ea11..880b52f0d1a 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProductVariantSearchRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * ProductVariantSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProjectProductVariant.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProjectProductVariant.java index eca7aff656b..3970c1927d2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProjectProductVariant.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/ProjectProductVariant.java @@ -8,13 +8,13 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; /** * ProjectProductVariant */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/TenantRole.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/TenantRole.java index 3af69e1d41d..2b2ed233edc 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/TenantRole.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/TenantRole.java @@ -10,8 +10,8 @@ import org.egov.common.contract.request.Role; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -20,7 +20,7 @@ */ @ApiModel(description = "User role carries the tenant related role information for the user. A user can have multiple roles per tenant based on the need of the tenant. A user may also have multiple roles for multiple tenants.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/UserInfo.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/UserInfo.java index 7101032ff40..5c89828c693 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/UserInfo.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/UserInfo.java @@ -10,8 +10,8 @@ import org.egov.common.contract.request.Role; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -20,7 +20,7 @@ */ @ApiModel(description = "This is acting ID token of the authenticated user on the server. Any value provided by the clients will be ignored and actual user based on authtoken will be used on the server.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdditionalFields.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdditionalFields.java index 5ffbd00271a..819eb9def0c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdditionalFields.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/AdditionalFields.java @@ -8,9 +8,9 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Min; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -18,13 +18,14 @@ * AdditionalFields */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public class AdditionalFields { @JsonProperty("schema") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Address.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Address.java index ce37429fe51..332c652ac33 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Address.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Address.java @@ -7,20 +7,21 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.models.core.Boundary; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.DecimalMax; -import javax.validation.constraints.DecimalMin; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. */ @ApiModel(description = "Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. ") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkRequest.java index 87bfe0c5802..a6167611a94 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkRequest.java @@ -9,9 +9,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ * BeneficiaryRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkResponse.java index 343a1b78c6b..06c6081b71b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryBulkResponse.java @@ -9,16 +9,16 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; /** -* BeneficiaryResponse -*/ + * BeneficiaryResponse + */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor @@ -26,29 +26,29 @@ @Builder @JsonIgnoreProperties(ignoreUnknown = true) public class BeneficiaryBulkResponse { - @JsonProperty("ResponseInfo") - @NotNull - - @Valid - + @JsonProperty("ResponseInfo") + @NotNull + @Valid private ResponseInfo responseInfo = null; - @JsonProperty("ProjectBeneficiaries") - - @Valid - + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + @JsonProperty("ProjectBeneficiaries") + @Valid private List projectBeneficiaries = null; - public BeneficiaryBulkResponse addProjectBeneficiaryItem(ProjectBeneficiary projectBeneficiaryItem) { - if (this.projectBeneficiaries == null) { + public BeneficiaryBulkResponse addProjectBeneficiaryItem(ProjectBeneficiary projectBeneficiaryItem) { + if (this.projectBeneficiaries == null) { this.projectBeneficiaries = new ArrayList<>(); - } + } this.projectBeneficiaries.add(projectBeneficiaryItem); return this; - } + } } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryRequest.java index aa04c2692a1..cb1e4462721 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * BeneficiaryRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryResponse.java index 31e11433ff3..0b95acf2dc8 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiaryResponse.java @@ -9,14 +9,14 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * BeneficiaryResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiarySearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiarySearchRequest.java index 5de41e04615..9ca9e718d78 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiarySearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/BeneficiarySearchRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * BeneficiarySearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Boundary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Boundary.java deleted file mode 100644 index a7db5d3bb41..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Boundary.java +++ /dev/null @@ -1,58 +0,0 @@ -package org.egov.common.models.project; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.constraints.NotNull; - -/** -* Boundary -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class Boundary { - - @JsonProperty("code") - @NotNull - private String code = null; - - @JsonProperty("name") - private String name = null; - - @JsonProperty("label") - private String label = null; - - @JsonProperty("latitude") - private String latitude = null; - - @JsonProperty("longitude") - private String longitude = null; - -// @JsonProperty("children") -// @Valid -// private List children = null; - - @JsonProperty("materializedPath") - private String materializedPath = null; - -// public Boundary addChildrenItem(Boundary childrenItem) { -// if (this.children == null) { -// this.children = new ArrayList<>(); -// } -// this.children.add(childrenItem); -// return this; -// } - -} - diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Document.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Document.java index 225eb8fde60..1eb86b7c89f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Document.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Document.java @@ -11,16 +11,16 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * A Object holds the basic data for a Trade License */ @ApiModel(description = "A Object holds the basic data for a Trade License") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Field.java index c4f47fe7a7e..58360cdaf8e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Field.java @@ -1,7 +1,7 @@ package org.egov.common.models.project; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -15,7 +15,7 @@ * Field */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Project.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Project.java index 13378ff0805..586ff410489 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Project.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Project.java @@ -11,7 +11,7 @@ import lombok.Setter; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; +import jakarta.validation.Valid; import java.util.ArrayList; import java.util.List; @@ -20,7 +20,7 @@ */ @ApiModel(description = "The purpose of this object to define the Project for a geography and period") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-08T16:20:57.141+05:30") + @Getter @Setter diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java index c5aa07e4f49..6c899a34765 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiary.java @@ -9,33 +9,28 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * A representation of the registration of an entity to a Project. */ @ApiModel(description = "A representation of the registration of an entity to a Project.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectBeneficiary { - @JsonProperty("id") - private String id = null; - - @JsonProperty("tenantId") - @NotNull - @Size(min=2,max=64) - private String tenantId = null; +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ProjectBeneficiary extends EgovOfflineModel { @JsonProperty("projectId") @NotNull @@ -49,36 +44,17 @@ public class ProjectBeneficiary { @JsonProperty("dateOfRegistration") @Min(value = 0, message = "Date must be greater than or equal to 0") private Long dateOfRegistration = null; - - @JsonProperty("clientReferenceId") - @Size(min=2,max=64) - private String clientReferenceId = null; - + /* + * This is the client reference id of the beneficiary type entity (i.e. household, individual) + * */ @JsonProperty("beneficiaryClientReferenceId") @Size(min=2,max=64) private String beneficiaryClientReferenceId = null; - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; - + //TODO remove this @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; - - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; - @JsonProperty("tag") private String tag; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiarySearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiarySearch.java index 301eebbe207..993180f902b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiarySearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectBeneficiarySearch.java @@ -1,48 +1,34 @@ package org.egov.common.models.project; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.Size; -import java.util.List; - /** * Search model for project beneficiary. */ - @ApiModel(description = "Search model for project beneficiary.") +@ApiModel(description = "Search model for project beneficiary.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectBeneficiarySearch { - - @JsonProperty("id") - private List id = null; - - @JsonProperty("tenantId") - @Size(min=2,max=1000) - private String tenantId = null; +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ProjectBeneficiarySearch extends EgovOfflineSearchModel { @JsonProperty("projectId") - @Size(min=2,max=64) - private String projectId = null; + private List projectId = null; @JsonProperty("beneficiaryId") - @Size(min=2,max=64) - private String beneficiaryId = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; + private List beneficiaryId = null; @JsonProperty("dateOfRegistration") private Long dateOfRegistration = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java index a8081091e62..60c61e9ddee 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacility.java @@ -1,41 +1,28 @@ package org.egov.common.models.project; -import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; import io.swagger.annotations.ApiModel; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * This object defines the mapping of a facility to a project. */ @ApiModel(description = "This object defines the mapping of a facility to a project.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectFacility { - @JsonProperty("id") - @Size(min = 2, max = 64) - private String id = null; - - @JsonProperty("tenantId") - @NotNull - @Size(min = 2, max = 1000) - private String tenantId = null; +public class ProjectFacility extends EgovModel { @JsonProperty("facilityId") @NotNull @@ -47,21 +34,9 @@ public class ProjectFacility { @Size(min=2,max=64) private String projectId = null; + //TODO remove @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; } \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkRequest.java index 049c0bb3dbb..cd1af9dfcb0 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkRequest.java @@ -10,9 +10,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -20,7 +20,7 @@ * ProjectStaffRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkResponse.java index 89218817564..d2481b16298 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityBulkResponse.java @@ -8,8 +8,8 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -17,7 +17,7 @@ * ProjectFacilityResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityRequest.java index df428449143..a985decccef 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * ProjectFacilityRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityResponse.java index 40167cfed75..ce862b669c6 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilityResponse.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * ProjectFacilityResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-14T20:57:07.075+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilitySearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilitySearch.java index 5f86ad8f19f..adac9f7438d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilitySearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilitySearch.java @@ -1,35 +1,28 @@ package org.egov.common.models.project; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovSearchModel; import org.springframework.validation.annotation.Validated; -import java.util.List; - /** * This object defines the mapping of a facility to a project. */ - @ApiModel(description = "This object defines the mapping of a facility to a project.") +@ApiModel(description = "This object defines the mapping of a facility to a project.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectFacilitySearch { - - @JsonProperty("id") - private List id = null; - - @JsonProperty("tenantId") - private String tenantId = null; +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ProjectFacilitySearch extends EgovSearchModel { @JsonProperty("facilityId") private List facilityId = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilitySearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilitySearchRequest.java index 244d1c8e5d8..290d8c02805 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilitySearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectFacilitySearchRequest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,15 +11,10 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - /** * ProjectFacilitySearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - @Data @NoArgsConstructor @AllArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectProductVariant.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectProductVariant.java index dcbb34004ce..e8841ba5de9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectProductVariant.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectProductVariant.java @@ -8,13 +8,13 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; /** * ProjectProductVariant */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectRequest.java index 5fb245440f2..fd09b6b635b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectRequest.java @@ -9,9 +9,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ * ProjectRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java index d3740b5facb..64001b9e278 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResource.java @@ -9,33 +9,27 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * This object defines the mapping of a resource to a project. */ @ApiModel(description = "This object defines the mapping of a resource to a project.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectResource { - @JsonProperty("id") - @Size(min=2, max = 64) - private String id = null; - - @JsonProperty("tenantId") - @NotNull - @Size(min=2, max = 1000) - private String tenantId = null; +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ProjectResource extends EgovModel { @JsonProperty("projectId") @NotNull @@ -46,24 +40,15 @@ public class ProjectResource { @NotNull private ProjectProductVariant resource = null; + //TODO remove @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - @JsonProperty("startDate") private Long startDate = null; @JsonProperty("endDate") private Long endDate = null; - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkRequest.java index 00eb95e299d..26b6c095232 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkRequest.java @@ -9,9 +9,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ * ProjectResourceRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkResponse.java index 1f121c9db84..e04eb6abd1b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceBulkResponse.java @@ -9,8 +9,8 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * ProjectResourceResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceRequest.java index c161b22e4e8..d3387b1af96 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * ProjectResourceRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceResponse.java index 9e60ed020ed..cc9a7e5c635 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceResponse.java @@ -9,14 +9,14 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * ProjectResourceResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceSearch.java index 456a54221e2..0178325789b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceSearch.java @@ -1,37 +1,31 @@ package org.egov.common.models.project; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovSearchModel; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.Size; -import java.util.List; - /** * This object defines the mapping of a resource to a project. */ @ApiModel(description = "This object defines the mapping of a resource to a project.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - @Data @NoArgsConstructor @AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectResourceSearch { - - @JsonProperty("id") - private List id = null; +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class ProjectResourceSearch extends EgovSearchModel { @JsonProperty("projectId") - @Size(min=2,max=64) - private String projectId = null; + private List projectId = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceSearchRequest.java index ead04f4f24f..0ad5d439e2f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResourceSearchRequest.java @@ -2,21 +2,18 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - /** * ProjectResourceSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - @Data @NoArgsConstructor @AllArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResponse.java index 21ac8dbe285..54872c4d5a4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectResponse.java @@ -9,8 +9,8 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * ProjectResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectSearch.java index 15d753cc998..7bb2834bc5f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectSearch.java @@ -2,62 +2,159 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovSearchModel; +import org.egov.common.models.core.ProjectSearchURLParams; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.Size; - /** -* ProjectSearch -*/ + * ProjectSearch - Model class for searching projects. + * This class includes various fields that can be used to filter projects based on specific criteria. + * It extends EgovSearchModel to inherit common search-related properties. + */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectSearch { - - @JsonProperty("id") - private String id = null; - - @JsonProperty("tenantId") - private String tenantId = null; +public class ProjectSearch extends EgovSearchModel { + /** + * The start date of the project. + * This field can be used to filter projects that start from a specific date. + */ @JsonProperty("startDate") - private Long startDate = null; + private Long startDate; + /** + * The end date of the project. + * This field can be used to filter projects that end by a specific date. + */ @JsonProperty("endDate") - private Long endDate = null; + private Long endDate; + /** + * Indicates if the project has tasks enabled. + * Default value is FALSE. + */ @JsonProperty("isTaskEnabled") - private Boolean isTaskEnabled = false; + private Boolean isTaskEnabled = Boolean.FALSE; + /** + * The parent project ID. + * This field can be used to filter sub-projects of a specific parent project. + * It should be between 2 and 64 characters in length. + */ @JsonProperty("parent") - @Size(min=2,max=64) - private String parent = null; + @Size(min = 2, max = 64) + private String parent; + /** + * The ID of the project type. + * This field can be used to filter projects of a specific type. + */ @JsonProperty("projectTypeId") - private String projectTypeId = null; + private String projectTypeId; + /** + * The ID of the sub-project type. + * This field can be used to filter projects of a specific sub-type. + */ @JsonProperty("subProjectTypeId") - private String subProjectTypeId = null; + private String subProjectTypeId; + /** + * The department associated with the project. + * This field can be used to filter projects of a specific department. + * It should be between 2 and 64 characters in length. + */ @JsonProperty("department") - @Size(min=2,max=64) - private String department = null; - + @Size(min = 2, max = 64) + private String department; + + /** + * The reference ID of the project. + * This field can be used to filter projects by their reference ID. + * It should be between 2 and 100 characters in length. + */ @JsonProperty("referenceId") - @Size(min=2,max=100) - private String referenceId = null; + @Size(min = 2, max = 100) + private String referenceId; + /** + * The boundary code associated with the project. + * This field can be used to filter projects within a specific boundary. + */ @JsonProperty("boundaryCode") - private String boundaryCode = null; - -} - + private String boundaryCode; + + /** + * Used in project search API to specify if response should include project elements + * that are in the preceding hierarchy of matched projects. + */ + @JsonProperty("includeAncestors") + private Boolean includeAncestors; + + /** + * Used in project search API to specify if response should include project elements + * that are in the following hierarchy of matched projects. + */ + @JsonProperty("includeDescendants") + private Boolean includeDescendants; + + /** + * Used in project search API to limit the search results to only those projects whose creation + * date is after the specified 'createdFrom' date. + */ + @JsonProperty("createdFrom") + private Long createdFrom; + + /** + * Used in project search API to limit the search results to only those projects whose creation + * date is before the specified 'createdTo' date. + */ + @JsonProperty("createdTo") + private Long createdTo; + + /** + * The name of the project. + * This field can be used to filter projects by their name. + */ + @JsonProperty("name") + private String name; + + /** + * Sets the URL parameters from the given ProjectSearchURLParams object to this ProjectSearch object. + * This method allows for easy transfer of search parameters from URL to the search model. + * + * @param urlParams The ProjectSearchURLParams object containing the URL parameters. + */ + public void setURLParams(ProjectSearchURLParams urlParams) { + // Call the superclass method to set common URL parameters + + // If the URL parameter includeAncestors is not null, set it to the current object's includeAncestors field + if (urlParams.getIncludeAncestors() != null) { + includeAncestors = urlParams.getIncludeAncestors(); + } + + // If the URL parameter includeDescendants is not null, set it to the current object's includeDescendants field + if (urlParams.getIncludeDescendants() != null) { + includeDescendants = urlParams.getIncludeDescendants(); + } + + // If the URL parameter createdFrom is not null, set it to the current object's createdFrom field + if (urlParams.getCreatedFrom() != null) { + createdFrom = urlParams.getCreatedFrom(); + } + + // If the URL parameter createdTo is not null, set it to the current object's createdTo field + if (urlParams.getCreatedTo() != null) { + createdTo = urlParams.getCreatedTo(); + } + } +} \ No newline at end of file diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectSearchRequest.java index 5b92236e106..3dc85137b83 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectSearchRequest.java @@ -2,22 +2,20 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.ProjectSearchURLParams; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - /** * ProjectSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - @Data @NoArgsConstructor @AllArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java index 18d20c408a4..78ecda1fa80 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaff.java @@ -1,9 +1,11 @@ package org.egov.common.models.project; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovModel; import org.springframework.validation.annotation.Validated; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -22,23 +24,14 @@ */ @ApiModel(description = "This object defines the mapping of a system staff user to a project for a certain period.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectStaff { - - @JsonProperty("id") - @Size(min=2,max=64) - private String id = null; - - @JsonProperty("tenantId") - @NotNull - @Size(min=2,max=1000) - private String tenantId = null; +public class ProjectStaff extends EgovModel { @JsonProperty("userId") @NotNull @@ -60,22 +53,9 @@ public class ProjectStaff { @Size(min=2,max=64) private String channel = null; + //TODO remove @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; - } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkRequest.java index c23cc976799..c13dc8fcc4b 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkRequest.java @@ -9,9 +9,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ * ProjectStaffRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkResponse.java index 5c36dd3f503..d73daee5c73 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffBulkResponse.java @@ -9,8 +9,8 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * ProjectStaffResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffRequest.java index 9c0501849e0..ec7042c5ee0 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * ProjectStaffRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffResponse.java index c9c91fc59e5..49403f8dd95 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffResponse.java @@ -9,14 +9,14 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * ProjectStaffResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffSearch.java index 940ec9bfb63..7e8cb5ca5ba 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffSearch.java @@ -1,46 +1,34 @@ package org.egov.common.models.project; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovSearchModel; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.Size; -import java.util.List; - /** * This object defines the mapping of a system staff user to a project for a certain period. */ @ApiModel(description = "This object defines the mapping of a system staff user to a project for a certain period.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectStaffSearch { - - - @JsonProperty("id") - private List id = null; - - @JsonProperty("tenantId") - @Size(min = 2, max = 1000) - private String tenantId = null; +public class ProjectStaffSearch extends EgovSearchModel { @JsonProperty("staffId") - @Size(min = 2, max = 64) private List staffId = null; @JsonProperty("projectId") - @Size(min = 2, max = 64) - private String projectId = null; + private List projectId = null; @JsonProperty("startDate") private Long startDate = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffSearchRequest.java index f0e67e8bf1f..f43a480aea1 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectStaffSearchRequest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -9,15 +11,10 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - /** * ProjectStaffSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - @Data @NoArgsConstructor @AllArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectType.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectType.java index 6aa4942f0a7..b428843e9d3 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectType.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectType.java @@ -10,8 +10,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -20,7 +20,7 @@ */ @ApiModel(description = "This is the master data to capture the metadata of Project") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Role.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Role.java index c1ba8ffa791..fa2e4fee092 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Role.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Role.java @@ -9,15 +9,15 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * minimal representation of the Roles in the system to be carried along in UserInfo with RequestInfo meta data. Actual authorization service to extend this to have more role related attributes */ @ApiModel(description = "minimal representation of the Roles in the system to be carried along in UserInfo with RequestInfo meta data. Actual authorization service to extend this to have more role related attributes ") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Target.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Target.java index e7595853367..5fe7f7dbf7e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Target.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Target.java @@ -15,7 +15,7 @@ * Target */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Getter @Setter diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java index 01002770204..eddbeb82f0f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java @@ -8,11 +8,13 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -20,25 +22,13 @@ * Task */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class Task { - - @JsonProperty("id") - private String id = null; - - @JsonProperty("tenantId") - @NotNull - private String tenantId = null; - - @JsonProperty("clientReferenceId") - @Size(min = 2, max = 64) - private String clientReferenceId = null; +public class Task extends EgovOfflineModel { @JsonProperty("projectId") @NotNull @@ -80,30 +70,13 @@ public class Task { @Valid private Address address = null; - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; - + //TODO remove this @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; - - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; - @JsonProperty("status") private String status = null; - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; - public Task addResourcesItem(TaskResource resourcesItem) { this.resources.add(resourcesItem); return this; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkRequest.java index 48685771d06..87b257e312c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkRequest.java @@ -9,9 +9,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ * TaskRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkResponse.java index cdea71cb42b..c0bbfb8e5f5 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskBulkResponse.java @@ -9,8 +9,8 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * TaskResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor @@ -32,6 +32,11 @@ public class TaskBulkResponse { @Valid private ResponseInfo responseInfo = null; + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + @JsonProperty("Tasks") @NotNull @Valid diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskRequest.java index 13fd346d79a..a1d61ed85c1 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * TaskRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java index 986275799d2..382bd5e34ac 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java @@ -9,15 +9,15 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * TaskResource */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceRequest.java index b2b59d96d3c..8baedb1acfa 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceRequest.java @@ -9,9 +9,9 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ * TaskRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceResponse.java index 62300dd10ae..4d8c13db362 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResourceResponse.java @@ -9,8 +9,8 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * TaskResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResponse.java index 0c4ce1b9ea4..64274a157ea 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResponse.java @@ -9,14 +9,14 @@ import org.egov.common.contract.response.ResponseInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * TaskResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskSearch.java index 5c9dfcd0e2c..df1857a33f6 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskSearch.java @@ -1,46 +1,37 @@ package org.egov.common.models.project; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.Size; -import java.util.List; - /** * TaskSearch */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class TaskSearch { - - @JsonProperty("id") - private List id = null; +public class TaskSearch extends EgovOfflineSearchModel { @JsonProperty("projectId") - @Size(min=2,max=64) - private String projectId = null; + private List projectId = null; @JsonProperty("projectBeneficiaryId") - @Size(min=2,max=64) - private String projectBeneficiaryId = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; + private List projectBeneficiaryId = null; @JsonProperty("projectBeneficiaryClientReferenceId") - @Size(min=2,max=64) - private String projectBeneficiaryClientReferenceId = null; + private List projectBeneficiaryClientReferenceId = null; @JsonProperty("plannedStartDate") private Long plannedStartDate = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskSearchRequest.java index 6d1184da16f..dea1ee10e02 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskSearchRequest.java @@ -9,14 +9,14 @@ import org.egov.common.contract.request.RequestInfo; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * TaskSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TenantRole.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TenantRole.java index dbd04dc9343..1feb9f2518f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TenantRole.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TenantRole.java @@ -9,8 +9,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ */ @ApiModel(description = "User role carries the tenant related role information for the user. A user can have multiple roles per tenant based on the need of the tenant. A user may also have multiple roles for multiple tenants.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserInfo.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserInfo.java index b67c149836a..57afb18c30f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserInfo.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserInfo.java @@ -9,8 +9,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ */ @ApiModel(description = "This is acting ID token of the authenticated user on the server. Any value provided by the clients will be ignored and actual user based on authtoken will be used on the server.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java index 61271060c1c..9cdc553bb92 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/Referral.java @@ -7,27 +7,21 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; import org.egov.common.models.project.AdditionalFields; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.List; @Data @NoArgsConstructor @AllArgsConstructor -@Builder -public class Referral { - - @JsonProperty("id") - @Size(min = 2, max = 64) - private String id; - - @JsonProperty("clientReferenceId") - @Size(min = 2, max = 64) - private String clientReferenceId; +@SuperBuilder +public class Referral extends EgovOfflineModel { @JsonProperty("projectBeneficiaryId") @Size(min = 2, max = 64) @@ -53,32 +47,14 @@ public class Referral { @Size(min=1) private List reasons; + @JsonProperty("referralCode") + @Size(max=100) + private String referralCode; + @JsonProperty("sideEffect") private SideEffect sideEffect; - @JsonProperty("tenantId") - @NotNull - @Size(min=2, max = 1000) - private String tenantId; - @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails; - - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails; - - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkRequest.java index e8daf9a446b..43beca385c8 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkRequest.java @@ -7,9 +7,9 @@ import lombok.NoArgsConstructor; import org.egov.common.contract.request.RequestInfo; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; import java.util.Objects; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkResponse.java index 8fd04588e0b..7dfa73883aa 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralBulkResponse.java @@ -7,8 +7,8 @@ import lombok.NoArgsConstructor; import org.egov.common.contract.response.ResponseInfo; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -23,6 +23,11 @@ public class ReferralBulkResponse { @Valid private ResponseInfo responseInfo; + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + @JsonProperty("Referrals") @NotNull @Valid diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralRequest.java index 7f359fc6e92..c21a6e2a3a5 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralRequest.java @@ -7,8 +7,8 @@ import lombok.NoArgsConstructor; import org.egov.common.contract.request.RequestInfo; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralResponse.java index fa0f7ba0786..3cf99fc9073 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralResponse.java @@ -7,8 +7,8 @@ import lombok.NoArgsConstructor; import org.egov.common.contract.response.ResponseInfo; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearch.java index de01f288289..9c3ef87889e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearch.java @@ -1,23 +1,19 @@ package org.egov.common.models.referralmanagement; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; - -import java.util.List; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; @Data @NoArgsConstructor @AllArgsConstructor -@Builder -public class ReferralSearch { - @JsonProperty("id") - private List id; - - @JsonProperty("clientReferenceId") - private List clientReferenceId; +@SuperBuilder +public class ReferralSearch extends EgovOfflineSearchModel { @JsonProperty("projectBeneficiaryId") private List projectBeneficiaryId; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearchRequest.java index 8884292d19c..e872c6f1df0 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/ReferralSearchRequest.java @@ -7,8 +7,8 @@ import lombok.NoArgsConstructor; import org.egov.common.contract.request.RequestInfo; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncCriteria.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncCriteria.java index 6548e7c5025..71816f7849f 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncCriteria.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/beneficiarydownsync/DownsyncCriteria.java @@ -1,6 +1,6 @@ package org.egov.common.models.referralmanagement.beneficiarydownsync; -import javax.validation.constraints.NotNull; +import jakarta.validation.constraints.NotNull; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferral.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferral.java index 330b437df95..2c68467c843 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferral.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferral.java @@ -1,8 +1,8 @@ package org.egov.common.models.referralmanagement.hfreferral; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; @@ -11,26 +11,15 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; import org.egov.common.models.project.AdditionalFields; @Data @NoArgsConstructor @AllArgsConstructor -@Builder -public class HFReferral { - - @JsonProperty("id") - @Size(min = 2, max = 64) - private String id; - - @JsonProperty("clientReferenceId") - @Size(min = 2, max = 64) - private String clientReferenceId; - - @JsonProperty("tenantId") - @NotNull - @Size(min=2, max = 1000) - private String tenantId; +@SuperBuilder +public class HFReferral extends EgovOfflineModel { @JsonProperty("projectId") @Size(min = 2, max = 64) @@ -61,24 +50,8 @@ public class HFReferral { @Size(max=100) private String nationalLevelId; + //TODO remove this @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails; - - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails; - - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkRequest.java index 358cb03135c..bd9080b6c80 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkRequest.java @@ -3,9 +3,9 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkResponse.java index a0f1c04b090..a561ef4f8a4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralBulkResponse.java @@ -3,8 +3,8 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralRequest.java index 3adc90053b6..1c305c56341 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralRequest.java @@ -1,7 +1,7 @@ package org.egov.common.models.referralmanagement.hfreferral; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralResponse.java index 24471207656..97821467ac9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralResponse.java @@ -1,7 +1,7 @@ package org.egov.common.models.referralmanagement.hfreferral; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearch.java index 02dbfdf899a..26d56c565ad 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearch.java @@ -2,25 +2,18 @@ import java.util.List; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; @Data @NoArgsConstructor @AllArgsConstructor -@Builder -public class HFReferralSearch { - @JsonProperty("id") - private List id; - - @JsonProperty("clientReferenceId") - private List clientReferenceId; +@SuperBuilder +public class HFReferralSearch extends EgovOfflineSearchModel { @JsonProperty("facilityId") private List facilityId; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearchRequest.java index 4784f9fbdad..1692ca692d5 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/hfreferral/HFReferralSearchRequest.java @@ -1,7 +1,7 @@ package org.egov.common.models.referralmanagement.hfreferral; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java index f91a733c8b3..f9f3041aeb5 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffect.java @@ -7,26 +7,20 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; import org.egov.common.models.project.AdditionalFields; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.List; @Data @NoArgsConstructor @AllArgsConstructor -@Builder -public class SideEffect { - - @JsonProperty("id") - @Size(min = 2, max = 64) - private String id; - - @JsonProperty("clientReferenceId") - @Size(min = 2, max = 64) - private String clientReferenceId; +@SuperBuilder +public class SideEffect extends EgovOfflineModel { @JsonProperty("taskId") @Size(min = 2, max = 64) @@ -50,29 +44,8 @@ public class SideEffect { @Size(min=1) private List symptoms; - @JsonProperty("tenantId") - @NotNull - @Size(min=2, max = 1000) - private String tenantId; - + //TODO remove this @JsonProperty("isDeleted") private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails; - - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails; - - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java index 7b5cb98ebfc..fed08c092de 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkRequest.java @@ -7,9 +7,9 @@ import lombok.NoArgsConstructor; import org.egov.common.contract.request.RequestInfo; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; import java.util.Objects; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java index 64b8a8d2989..d22245c5a79 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectBulkResponse.java @@ -7,8 +7,8 @@ import lombok.NoArgsConstructor; import org.egov.common.contract.response.ResponseInfo; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -24,6 +24,11 @@ public class SideEffectBulkResponse { @Valid private ResponseInfo responseInfo; + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + @JsonProperty("SideEffects") @NotNull @Valid diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java index 96f020e09e6..893e9efb526 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectRequest.java @@ -7,8 +7,8 @@ import lombok.NoArgsConstructor; import org.egov.common.contract.request.RequestInfo; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java index 0ca3e42b228..8dbc9a0a89c 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectResponse.java @@ -7,8 +7,8 @@ import lombok.NoArgsConstructor; import org.egov.common.contract.response.ResponseInfo; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java index c6e5e2ad11a..4a37ded59b3 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearch.java @@ -1,28 +1,24 @@ package org.egov.common.models.referralmanagement.sideeffect; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; - -import java.util.List; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; @Data @NoArgsConstructor @AllArgsConstructor -@Builder -public class SideEffectSearch { - @JsonProperty("id") - private List id; - - @JsonProperty("clientReferenceId") - private List clientReferenceId; +@SuperBuilder +public class SideEffectSearch extends EgovOfflineSearchModel { @JsonProperty("taskId") - private String taskId; + private List taskId; @JsonProperty("taskClientReferenceId") - private String taskClientReferenceId; + private List taskClientReferenceId; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java index f9549e207a8..a5248c5d6e7 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/referralmanagement/sideeffect/SideEffectSearchRequest.java @@ -7,8 +7,8 @@ import lombok.NoArgsConstructor; import org.egov.common.contract.request.RequestInfo; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/AdditionalFields.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/AdditionalFields.java index 9c94c91ea95..ef65681acc2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/AdditionalFields.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/AdditionalFields.java @@ -8,9 +8,9 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Min; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -18,14 +18,14 @@ * AdditionalFields */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) - +@Deprecated public class AdditionalFields { @JsonProperty("schema") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Address.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Address.java index d5ae3b61517..3a08cad9abc 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Address.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Address.java @@ -3,30 +3,31 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; +import jakarta.validation.Valid; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import org.egov.common.models.core.Boundary; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.DecimalMax; -import javax.validation.constraints.DecimalMin; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. */ @ApiModel(description = "Representation of a address. Individual APIs may choose to extend from this using allOf if more details needed to be added in their case. ") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor @AllArgsConstructor @Builder @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public class Address { @JsonProperty("id") @Size(min = 2, max = 64) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/AddressType.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/AddressType.java index 1ca1084f080..b39fcffd32d 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/AddressType.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/AddressType.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonValue; @JsonIgnoreProperties(ignoreUnknown = true) +@Deprecated public enum AddressType { PERMANENT("PERMANENT"), diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Boundary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Boundary.java deleted file mode 100644 index 16bc59bfa05..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Boundary.java +++ /dev/null @@ -1,82 +0,0 @@ -package org.egov.common.models.stock; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - -/** -* Boundary -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class Boundary { - @JsonProperty("code") - @NotNull - - - - private String code = null; - - @JsonProperty("name") - - - - private String name = null; - - @JsonProperty("label") - - - - private String label = null; - - @JsonProperty("latitude") - - - - private String latitude = null; - - @JsonProperty("longitude") - - - - private String longitude = null; - - @JsonProperty("children") - - @Valid - - - private List children = null; - - @JsonProperty("materializedPath") - - - - private String materializedPath = null; - - - public Boundary addChildrenItem(Boundary childrenItem) { - if (this.children == null) { - this.children = new ArrayList<>(); - } - this.children.add(childrenItem); - return this; - } - -} - diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Field.java index 4994957dd27..f040c0d8a28 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Field.java @@ -1,7 +1,7 @@ package org.egov.common.models.stock; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; @@ -15,7 +15,7 @@ * Field */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java index c53164b370c..1ec63f96c54 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Stock.java @@ -1,10 +1,10 @@ package org.egov.common.models.stock; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @@ -15,33 +15,22 @@ import lombok.Builder.Default; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; /** * Stock */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class Stock { - - @JsonProperty("id") - @Size(min=2, max=64) - private String id; - - @JsonProperty("clientReferenceId") - @Size(min=2, max=64) - private String clientReferenceId; - - @JsonProperty("tenantId") - @NotNull - @Size(min=2, max=1000) - private String tenantId; +public class Stock extends EgovOfflineModel { /* product fields */ @JsonProperty("productVariantId") @@ -98,30 +87,13 @@ public class Stock { @Size(min = 2, max = 200) private String wayBillNumber; - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields; - + //TODO remove this @JsonProperty("isDeleted") @Default private Boolean isDeleted = Boolean.FALSE; - @JsonProperty("rowVersion") - private Integer rowVersion; - - @JsonIgnore - @Default - private Boolean hasErrors = Boolean.FALSE; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails; - @JsonProperty("dateOfEntry") private Long dateOfEntry; - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkRequest.java index 7b42fbb4f27..696a7b9e41e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkRequest.java @@ -8,9 +8,9 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * StockRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkResponse.java index c1057a595c4..cea7c46b8e5 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockBulkResponse.java @@ -8,8 +8,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -17,7 +17,7 @@ * StockResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java index 7e3ac004d0f..b8fc052ce68 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliation.java @@ -8,36 +8,26 @@ import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * StockReconciliation */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class StockReconciliation { - @JsonProperty("id") - @Size(min=2, max=64) - private String id = null; - - @JsonProperty("clientReferenceId") - @Size(min=2, max=64) - private String clientReferenceId = null; - - @JsonProperty("tenantId") - @NotNull - @Size(min=2, max=1000) - private String tenantId = null; +public class StockReconciliation extends EgovOfflineModel { @JsonProperty("facilityId") @NotNull @@ -68,25 +58,9 @@ public class StockReconciliation { @JsonProperty("dateOfReconciliation") private Long dateOfReconciliation = null; - @JsonProperty("additionalFields") - @Valid - private AdditionalFields additionalFields = null; - + //TODO remove this @JsonProperty("isDeleted") private Boolean isDeleted = null; - @JsonProperty("rowVersion") - private Integer rowVersion = null; - - @JsonIgnore - private Boolean hasErrors = Boolean.FALSE; - - @JsonProperty("auditDetails") - @Valid - private AuditDetails auditDetails = null; - - @JsonProperty("clientAuditDetails") - @Valid - private AuditDetails clientAuditDetails = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkRequest.java index 169f0f86944..b9f01d68f98 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkRequest.java @@ -8,9 +8,9 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import java.util.ArrayList; import java.util.List; @@ -18,7 +18,7 @@ * StockReconciliationRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkResponse.java index ccc34392562..caea2ead604 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationBulkResponse.java @@ -8,8 +8,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -17,7 +17,7 @@ * StockReconciliationResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationRequest.java index d5794fad6ca..58845227bf2 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationRequest.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * StockReconciliationRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationResponse.java index f05d79ef8db..409223db9ca 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationResponse.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * StockReconciliationResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationSearch.java index a808934a953..64dd63ac5b9 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationSearch.java @@ -1,42 +1,33 @@ package org.egov.common.models.stock; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Size; -import java.util.List; - /** * StockReconciliationSearch */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class StockReconciliationSearch { - @JsonProperty("id") - @Valid - private List id = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; +public class StockReconciliationSearch extends EgovOfflineSearchModel { @JsonProperty("facilityId") - @Size(min=2, max=64) - private String facilityId = null; + private List facilityId = null; @JsonProperty("productVariantId") - @Size(min=2, max=64) - private String productVariantId = null; + private List productVariantId = null; } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationSearchRequest.java index 66d89a4efbd..6b307ce2d11 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockReconciliationSearchRequest.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * StockReconciliationSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockRequest.java index 8e2e6b1d9fa..10b7f7fde07 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockRequest.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * StockRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockResponse.java index ef0504b3098..1cea9fc0185 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockResponse.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockResponse.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * StockResponse */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockSearch.java index 29564b1605e..5e03a4daaf1 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockSearch.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockSearch.java @@ -1,49 +1,43 @@ package org.egov.common.models.stock; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; -import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.Size; -import java.util.List; - /** * StockSearch */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor @AllArgsConstructor -@Builder +@SuperBuilder @JsonIgnoreProperties(ignoreUnknown = true) -public class StockSearch { - - @JsonProperty("id") - private List id = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; +public class StockSearch extends EgovOfflineSearchModel { @JsonProperty("facilityId") @Size(min=2, max=64) private String facilityId = null; @JsonProperty("productVariantId") - @Size(min=2, max=64) - private String productVariantId = null; + private List productVariantId = null; @JsonProperty("referenceId") private String referenceId = null; @JsonProperty("wayBillNumber") - private String wayBillNumber = null; + private List wayBillNumber = null; @JsonProperty("referenceIdType") @Size(min=2, max=64) diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockSearchRequest.java index 3a072809362..9f73cb1e00e 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockSearchRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/StockSearchRequest.java @@ -8,14 +8,14 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * StockSearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/TenantRole.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/TenantRole.java index e95bbfa9560..261bcb9d725 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/TenantRole.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/TenantRole.java @@ -9,8 +9,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ */ @ApiModel(description = "User role carries the tenant related role information for the user. A user can have multiple roles per tenant based on the need of the tenant. A user may also have multiple roles for multiple tenants.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/UserInfo.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/UserInfo.java index 2b8b0fb9b52..85edeeef0aa 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/UserInfo.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/UserInfo.java @@ -9,8 +9,8 @@ import lombok.NoArgsConstructor; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; @@ -19,7 +19,7 @@ */ @ApiModel(description = "This is acting ID token of the authenticated user on the server. Any value provided by the clients will be ignored and actual user based on authtoken will be used on the server.") @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") + @Data @NoArgsConstructor diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/transformer/upstream/Boundary.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/transformer/upstream/Boundary.java deleted file mode 100644 index cf23efe5f82..00000000000 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/transformer/upstream/Boundary.java +++ /dev/null @@ -1,61 +0,0 @@ -package org.egov.common.models.transformer.upstream; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; -import java.util.ArrayList; -import java.util.List; - -/** -* Boundary -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class Boundary { - - @JsonProperty("code") - @NotNull - private String code = null; - - @JsonProperty("name") - private String name = null; - - @JsonProperty("label") - private String label = null; - - @JsonProperty("latitude") - private String latitude = null; - - @JsonProperty("longitude") - private String longitude = null; - - @JsonProperty("children") - @Valid - private List children = null; - - @JsonProperty("materializedPath") - private String materializedPath = null; - - public Boundary addChildrenItem(Boundary childrenItem) { - if (this.children == null) { - this.children = new ArrayList<>(); - } - this.children.add(childrenItem); - return this; - } - -} - diff --git a/health-services/product/CHANGELOG.md b/health-services/product/CHANGELOG.md index 645e12b40e1..657f753304d 100644 --- a/health-services/product/CHANGELOG.md +++ b/health-services/product/CHANGELOG.md @@ -1,5 +1,9 @@ All notable changes to this module will be documented in this file. +## To be released +- In ProductSearch, name , manufacturer updated to accept list of search entities instead of single entity +- In ProductVariantSearch, productId updated to accept list of search entities instead of single entity + ## 1.0.0 - Base version diff --git a/health-services/product/README.md b/health-services/product/README.md index a978b285f28..e1bf5846eaf 100644 --- a/health-services/product/README.md +++ b/health-services/product/README.md @@ -46,3 +46,13 @@ Product service APIs - contains create, update, delete and search end point ## Pre commit script [commit-msg](https://gist.github.com/jayantp-egov/14f55deb344f1648503c6be7e580fa12) + +## Updates +- Product Search + - `name` , and `manufacturer` now accepts a list of entities instead of single entity to search product +- Product Variant Search + - `productId` now accepts a list of entities instead of single entity to search product variants +## Usage +- Start the service +- Access the API endpoints for searching `product`, and `product variant` +- Pass list parameters for the search fields mentioned in updates \ No newline at end of file diff --git a/health-services/product/pom.xml b/health-services/product/pom.xml index 02edf69f5fc..ceaddfe4f4b 100644 --- a/health-services/product/pom.xml +++ b/health-services/product/pom.xml @@ -75,12 +75,12 @@ org.egov.common health-services-common - 1.0.7-SNAPSHOT + 1.0.16-SNAPSHOT org.egov.common health-services-models - 1.0.7-SNAPSHOT + 1.0.20-SNAPSHOT compile diff --git a/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductRowMapper.java b/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductRowMapper.java index 24c06d1721a..98a34d40cc3 100644 --- a/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductRowMapper.java +++ b/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductRowMapper.java @@ -1,16 +1,16 @@ package org.egov.product.repository.rowmapper; +import java.sql.ResultSet; +import java.sql.SQLException; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.product.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.product.Product; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; -import java.sql.ResultSet; -import java.sql.SQLException; - @Component public class ProductRowMapper implements RowMapper { private final ObjectMapper objectMapper = new ObjectMapper(); diff --git a/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductVariantRowMapper.java b/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductVariantRowMapper.java index 01b1d4d1174..b8897f9a999 100644 --- a/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductVariantRowMapper.java +++ b/health-services/product/src/main/java/org/egov/product/repository/rowmapper/ProductVariantRowMapper.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.product.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.product.ProductVariant; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; diff --git a/health-services/product/src/main/java/org/egov/product/web/controllers/ProductApiController.java b/health-services/product/src/main/java/org/egov/product/web/controllers/ProductApiController.java index 2f7b8ccfae2..305507edb07 100644 --- a/health-services/product/src/main/java/org/egov/product/web/controllers/ProductApiController.java +++ b/health-services/product/src/main/java/org/egov/product/web/controllers/ProductApiController.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.annotations.ApiParam; +import org.egov.common.models.core.URLParams; import org.egov.common.models.product.Product; import org.egov.common.models.product.ProductRequest; import org.egov.common.models.product.ProductResponse; @@ -21,17 +22,13 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; import java.util.List; @javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T16:45:24.641+05:30") @@ -74,15 +71,10 @@ public ResponseEntity productV1CreatePost(@ApiParam(value = "Ca } @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) - public ResponseEntity productV1SearchPost(@ApiParam(value = "Capture details of Product.", required = true) @Valid @RequestBody ProductSearchRequest productSearchRequest, - @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, - @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, - @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @Size(min = 2, max = 1000) @RequestParam(value = "tenantId", required = true) String tenantId, - @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, - @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { - - List products = productService.search(productSearchRequest, limit, offset, tenantId, - lastChangedSince, includeDeleted); + public ResponseEntity productV1SearchPost(@ApiParam(value = "Capture details of Product.", required = true) @Valid @RequestBody ProductSearchRequest productSearchRequest) throws Exception { + + List products = productService.search(productSearchRequest, searchCriteria.getLimit(), searchCriteria.getOffset(), + searchCriteria.getTenantId(), searchCriteria.getLastChangedSince(), searchCriteria.getIncludeDeleted()); ProductResponse productResponse = ProductResponse.builder() .product(products) .responseInfo(ResponseInfoFactory.createResponseInfo(productSearchRequest.getRequestInfo(), true)) @@ -127,13 +119,10 @@ public ResponseEntity productVariantV1CreatePost(@ApiPar @RequestMapping(value = "/variant/v1/_search", method = RequestMethod.POST) public ResponseEntity productVariantV1SearchPost(@ApiParam(value = "Capture details of Product variant.", required = true) @Valid @RequestBody ProductVariantSearchRequest productVariantSearchRequest, - @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, - @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, - @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @Size(min = 2, max = 1000) @RequestParam(value = "tenantId", required = true) String tenantId, - @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, - @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { - List productVariants = productVariantService.search(productVariantSearchRequest, limit, offset, - tenantId, lastChangedSince, includeDeleted); + ) throws Exception { + List productVariants = productVariantService.search(productVariantSearchRequest, + searchCriteria.getLimit(), searchCriteria.getOffset(), searchCriteria.getTenantId(), + searchCriteria.getLastChangedSince(), searchCriteria.getIncludeDeleted()); ProductVariantResponse productVariantResponse = ProductVariantResponse.builder() .productVariant(productVariants) .responseInfo(ResponseInfoFactory diff --git a/health-services/product/src/main/java/org/egov/product/web/models/ProductSearch.java b/health-services/product/src/main/java/org/egov/product/web/models/ProductSearch.java index cf2f0121666..781af13c2b5 100644 --- a/health-services/product/src/main/java/org/egov/product/web/models/ProductSearch.java +++ b/health-services/product/src/main/java/org/egov/product/web/models/ProductSearch.java @@ -32,9 +32,9 @@ public class ProductSearch { private String type = null; @JsonProperty("name") - private String name = null; + private List name = null; @JsonProperty("manufacturer") - private String manufacturer = null; + private List manufacturer = null; } diff --git a/health-services/product/src/main/java/org/egov/product/web/models/ProductVariantSearch.java b/health-services/product/src/main/java/org/egov/product/web/models/ProductVariantSearch.java index 7eeccb423ac..dd08015e773 100644 --- a/health-services/product/src/main/java/org/egov/product/web/models/ProductVariantSearch.java +++ b/health-services/product/src/main/java/org/egov/product/web/models/ProductVariantSearch.java @@ -30,8 +30,7 @@ public class ProductVariantSearch { private List id = null; @JsonProperty("productId") - @Size(min = 2, max = 64) - private String productId = null; + private List productId = null; @JsonProperty("sku") @Size(min = 0, max = 1000) diff --git a/health-services/product/src/test/java/org/egov/product/service/ProductServiceSearchTest.java b/health-services/product/src/test/java/org/egov/product/service/ProductServiceSearchTest.java index 8cfe52953af..aa71a99891f 100644 --- a/health-services/product/src/test/java/org/egov/product/service/ProductServiceSearchTest.java +++ b/health-services/product/src/test/java/org/egov/product/service/ProductServiceSearchTest.java @@ -51,7 +51,7 @@ void setUp() throws QueryBuilderException { @DisplayName("should not raise exception if no search results are found") void shouldNotRaiseExceptionIfNoProductsFound() throws Exception { ProductSearch productSearch = ProductSearch.builder() - .id(Collections.singletonList("ID101")).name("Product").build(); + .id(Collections.singletonList("ID101")).name(Collections.singletonList("Product")).build(); ProductSearchRequest productSearchRequest = ProductSearchRequest.builder().product(productSearch) .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); @@ -63,7 +63,7 @@ void shouldNotRaiseExceptionIfNoProductsFound() throws Exception { void shouldReturnProductsIfSearchCriteriaIsMatched() throws Exception { products.add(ProductTestBuilder.builder().goodProduct().withId("ID101").build()); ProductSearch productSearch = ProductSearch.builder() - .id(Collections.singletonList("ID101")).name("Product").build(); + .id(Collections.singletonList("ID101")).name(Collections.singletonList("Product")).build(); ProductSearchRequest productSearchRequest = ProductSearchRequest.builder().product(productSearch) .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); diff --git a/health-services/product/src/test/java/org/egov/product/web/controllers/ProductVariantApiControllerTest.java b/health-services/product/src/test/java/org/egov/product/web/controllers/ProductVariantApiControllerTest.java index a87dd58849e..73e84bfdcba 100644 --- a/health-services/product/src/test/java/org/egov/product/web/controllers/ProductVariantApiControllerTest.java +++ b/health-services/product/src/test/java/org/egov/product/web/controllers/ProductVariantApiControllerTest.java @@ -186,7 +186,7 @@ void shouldSend400BadRequestInCaseOfIncorrectApiOperationForUpdate() throws Exce void shouldAcceptSearchRequestAndReturnProductsVariants() throws Exception { ProductVariantSearchRequest productVariantSearchRequest = ProductVariantSearchRequest.builder().productVariant( - ProductVariantSearch.builder().productId("101").build() + ProductVariantSearch.builder().productId(Arrays.asList("101","102")).build() ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); when(productVariantService.search(any(ProductVariantSearchRequest.class), any(Integer.class), @@ -213,7 +213,7 @@ void shouldAcceptSearchRequestAndReturnProductsVariants() throws Exception { void shouldThrowExceptionIfNoResultFound() throws Exception { ProductVariantSearchRequest productVariantSearchRequest = ProductVariantSearchRequest.builder().productVariant( - ProductVariantSearch.builder().productId("101").build() + ProductVariantSearch.builder().productId(Arrays.asList("101","102")).build() ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); when(productVariantService.search(any(ProductVariantSearchRequest.class), any(Integer.class), diff --git a/health-services/project/CHANGELOG.md b/health-services/project/CHANGELOG.md index 3a1ba625f06..1bcc937b721 100644 --- a/health-services/project/CHANGELOG.md +++ b/health-services/project/CHANGELOG.md @@ -1,5 +1,14 @@ All notable changes to this module will be documented in this file. + +## 1.1.4 - 2024-05-29 +- Integrated Core 2.9LTS +- Integrated Boundary v2 functionality +- Upgraded to health models 1.0.20 and health common 1.0.16 +- Boundary v2 Integration +- MDMS v2 integration +- Beneficiary Tag null check in update + ## 1.1.2 - 2024-02-26 - Implemented validation for updating project start date and end date. - Added numberOfSessions field in additional details for attendance registry. diff --git a/health-services/project/README.md b/health-services/project/README.md index 89424d22e48..2c12f3b8091 100644 --- a/health-services/project/README.md +++ b/health-services/project/README.md @@ -155,3 +155,17 @@ Project service APIs - contains create, update, delete and search end point ## Pre commit script [commit-msg](https://gist.github.com/jayantp-egov/14f55deb344f1648503c6be7e580fa12) + +## Updates +- Project Staff Search + - `staffId`, and `projectId` now accepts a list of entities instead of single entity to search project staff +- Project Task Search + - `projectId`, `projectBeneficiaryId`, and `projectBeneficiaryClientReferenceId` now accepts list of entities instead of single entity to search project task +- Project Beneficiary Search + - `projectId`, and `beneficiaryId` now accepts a list of entities instead of single entity to search project beneficiary +- Project Resource Search + - `projectId` now accepts a list of entities instead of single entity to search project resources +## Usage +- Start the service +- Access the API endpoints for searching various project entities +- Pass list parameters for the search fields mentioned in updates \ No newline at end of file diff --git a/health-services/project/pom.xml b/health-services/project/pom.xml index bc89832e98c..86272917f42 100644 --- a/health-services/project/pom.xml +++ b/health-services/project/pom.xml @@ -5,16 +5,17 @@ project jar project - 1.1.2 + 1.1.4 - 1.8 + 17 ${java.version} ${java.version} + 1.18.22 org.springframework.boot spring-boot-starter-parent - 2.2.6.RELEASE + 3.2.2 src/main/java @@ -44,12 +45,12 @@ org.egov.common health-services-common - 1.0.8-SNAPSHOT + 1.0.16-SNAPSHOT org.egov.common health-services-models - 1.0.10-SNAPSHOT + 1.0.20-SNAPSHOT compile @@ -69,42 +70,49 @@ org.flywaydb flyway-core + 9.22.3 org.postgresql postgresql - 42.2.2.jre7 + 42.7.1 + + + org.egov.services + tracer + 2.9.0-SNAPSHOT org.springframework.boot spring-boot-starter-test test - + + junit + junit + 4.13.2 + test + io.swagger swagger-core 1.5.18 - - - org.egov.services - digit-models - 1.0.0-SNAPSHOT - org.projectlombok lombok + ${lombok.version} true com.fasterxml.jackson.datatype jackson-datatype-jsr310 - - javax.validation - validation-api + commons-io + commons-io + 2.13.0 + test diff --git a/health-services/project/src/main/java/org/egov/project/config/MainConfiguration.java b/health-services/project/src/main/java/org/egov/project/config/MainConfiguration.java index 216b4abcd54..b9bad965c70 100644 --- a/health-services/project/src/main/java/org/egov/project/config/MainConfiguration.java +++ b/health-services/project/src/main/java/org/egov/project/config/MainConfiguration.java @@ -22,7 +22,7 @@ import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import java.util.TimeZone; @Import({TracerConfiguration.class}) @Configuration diff --git a/health-services/project/src/main/java/org/egov/project/repository/ProjectBeneficiaryRepository.java b/health-services/project/src/main/java/org/egov/project/repository/ProjectBeneficiaryRepository.java index df29b9869c0..3b879371d52 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/ProjectBeneficiaryRepository.java +++ b/health-services/project/src/main/java/org/egov/project/repository/ProjectBeneficiaryRepository.java @@ -1,17 +1,32 @@ package org.egov.project.repository; import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.builder.GenericQueryBuilder; +import org.egov.common.data.query.builder.QueryFieldChecker; import org.egov.common.data.query.builder.SelectQueryBuilder; +import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.household.HouseholdMember; import org.egov.common.models.project.ProjectBeneficiary; import org.egov.common.producer.Producer; import org.egov.project.repository.rowmapper.ProjectBeneficiaryRowMapper; +import org.egov.common.models.project.ProjectBeneficiarySearch; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; +import org.springframework.util.ReflectionUtils; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; + +import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; +import static org.egov.common.utils.CommonUtils.getIdMethod; @Repository @Slf4j @@ -24,5 +39,81 @@ public ProjectBeneficiaryRepository(Producer producer, NamedParameterJdbcTemplat super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, projectBeneficiaryRowMapper, Optional.of("project_beneficiary")); } + + public SearchResponse find(ProjectBeneficiarySearch householdMemberSearch, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) { + + Map paramsMap = new HashMap<>(); + StringBuilder queryBuilder = new StringBuilder(); + + String query = "SELECT * FROM project_beneficiary "; + + List whereFields = GenericQueryBuilder.getFieldsWithCondition(householdMemberSearch, QueryFieldChecker.isNotNull, paramsMap); + query = GenericQueryBuilder.generateQuery(query, whereFields).toString().trim(); + + query = query + " AND tenantId=:tenantId "; + + if (query.contains(this.tableName + " AND")) { + query = query.replace(this.tableName + " AND", this.tableName + " WHERE"); + } + + queryBuilder.append(query); + + if (Boolean.FALSE.equals(includeDeleted)) { + queryBuilder.append("AND isDeleted=:isDeleted "); + } + + if (lastChangedSince != null) { + queryBuilder.append("AND lastModifiedTime>=:lastModifiedTime "); + } + + paramsMap.put("tenantId", tenantId); + paramsMap.put("isDeleted", includeDeleted); + paramsMap.put("lastModifiedTime", lastChangedSince); + + queryBuilder.append(" ORDER BY id ASC "); + + Long totalCount = constructTotalCountCTEAndReturnResult(queryBuilder.toString(), paramsMap, this.namedParameterJdbcTemplate); + + queryBuilder.append(" LIMIT :limit OFFSET :offset"); + paramsMap.put("limit", limit); + paramsMap.put("offset", offset); + + List projectBeneficiaries = this.namedParameterJdbcTemplate.query(queryBuilder.toString(), paramsMap, this.rowMapper); + + return SearchResponse.builder().totalCount(totalCount).response(projectBeneficiaries).build(); + } + + public SearchResponse findById(List ids, String columnName, Boolean includeDeleted) { + List objFound = findInCache(ids).stream() + .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) + .collect(Collectors.toList()); + if (!objFound.isEmpty()) { + Method idMethod = getIdMethod(objFound, columnName); + ids.removeAll(objFound.stream() + .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) + .collect(Collectors.toList())); + if (ids.isEmpty()) { + log.info("all objects were found in the cache, returning objects"); + return SearchResponse.builder().response(objFound).build(); + } + } + + String query = String.format("SELECT * FROM project_beneficiary where %s IN (:ids) AND isDeleted = false", columnName); + if (null != includeDeleted && includeDeleted) { + query = String.format("SELECT * FROM project_beneficiary WHERE %s IN (:ids)", columnName); + } + Map paramMap = new HashMap(); + paramMap.put("ids", ids); + + objFound.addAll(this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper)); + putInCache(objFound); + log.info("returning objects from the database"); + return SearchResponse.builder().response(objFound).build(); + } } diff --git a/health-services/project/src/main/java/org/egov/project/repository/ProjectRepository.java b/health-services/project/src/main/java/org/egov/project/repository/ProjectRepository.java index ec885f723b1..ae7b4c9994b 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/ProjectRepository.java +++ b/health-services/project/src/main/java/org/egov/project/repository/ProjectRepository.java @@ -1,12 +1,16 @@ package org.egov.project.repository; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.ProjectSearchURLParams; import org.egov.common.models.project.Document; import org.egov.common.models.project.Project; import org.egov.common.models.project.ProjectRequest; +import org.egov.common.models.project.ProjectSearch; import org.egov.common.models.project.Target; import org.egov.common.producer.Producer; import org.egov.project.repository.querybuilder.DocumentQueryBuilder; @@ -101,6 +105,51 @@ public List getProjects(ProjectRequest project, Integer limit, Integer return buildProjectSearchResult(projects, targets, documents, ancestors, descendants); } + public List getProjects(@NotNull @Valid ProjectSearch projectSearch, @Valid ProjectSearchURLParams urlParams) { + + //Fetch Projects based on search criteria + List projects = getProjectsBasedOnV2SearchCriteria(projectSearch, urlParams); + + Set projectIds = projects.stream().map(Project :: getId).collect(Collectors.toSet()); + + List ancestors = null; + List descendants = null; + //Get Project ancestors if includeAncestors flag is true + if (urlParams.getIncludeAncestors()) { + ancestors = getProjectAncestors(projects); + if (ancestors != null && !ancestors.isEmpty()) { + List ancestorProjectIds = ancestors.stream().map(Project :: getId).collect(Collectors.toList()); + projectIds.addAll(ancestorProjectIds); + } + } + //Get Project descendants if includeDescendants flag is true + if (urlParams.getIncludeDescendants()) { + descendants = getProjectDescendants(projects); + if (descendants != null && !descendants.isEmpty()) { + List descendantsProjectIds = descendants.stream().map(Project :: getId).collect(Collectors.toList()); + projectIds.addAll(descendantsProjectIds); + } + } + + //Fetch targets based on Project Ids + List targets = getTargetsBasedOnProjectIds(projectIds); + + //Fetch documents based on Project Ids + List documents = getDocumentsBasedOnProjectIds(projectIds); + + //Construct Project Objects with fetched projects, targets and documents using Project id + return buildProjectSearchResult(projects, targets, documents, ancestors, descendants); + } + + private List getProjectsBasedOnV2SearchCriteria(@NotNull @Valid ProjectSearch projectSearch, ProjectSearchURLParams urlParams) { + List preparedStmtList = new ArrayList<>(); + String query = queryBuilder.getProjectSearchQuery(projectSearch, urlParams, preparedStmtList, Boolean.FALSE); + List projects = jdbcTemplate.query(query, addressRowMapper, preparedStmtList.toArray()); + + log.info("Fetched project list based on given search criteria"); + return projects; + } + /* Fetch Projects based on search criteria */ private List getProjectsBasedOnSearchCriteria(List projectsRequest, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted, Long createdFrom, Long createdTo) { List preparedStmtList = new ArrayList<>(); @@ -301,4 +350,21 @@ public Integer getProjectCount(ProjectRequest project, String tenantId, Long las log.info("Total project count is : " + count); return count; } + + /** + * Get the count of projects based on the given search criteria (using dynamic + * query build at the run time) + * @return + */ + public Integer getProjectCount(ProjectSearch projectSearch, ProjectSearchURLParams urlParams) { + List preparedStatement = new ArrayList<>(); + String query = queryBuilder.getSearchCountQueryString(projectSearch, urlParams, preparedStatement); + + if (query == null) + return 0; + + Integer count = jdbcTemplate.queryForObject(query, preparedStatement.toArray(), Integer.class); + log.info("Total project count is : " + count); + return count; + } } \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java b/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java index 76a4f8e87cc..d748602b7a4 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java +++ b/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java @@ -1,15 +1,25 @@ package org.egov.project.repository; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.egov.common.data.query.builder.GenericQueryBuilder; import org.egov.common.data.query.builder.QueryFieldChecker; import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskResource; import org.egov.common.models.project.TaskSearch; import org.egov.common.producer.Producer; +import org.egov.common.utils.CommonUtils; import org.egov.project.repository.rowmapper.ProjectTaskRowMapper; import org.egov.project.repository.rowmapper.TaskResourceRowMapper; import org.springframework.beans.factory.annotation.Autowired; @@ -18,14 +28,6 @@ import org.springframework.stereotype.Repository; import org.springframework.util.ReflectionUtils; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.getIdList; import static org.egov.common.utils.CommonUtils.getIdMethod; @@ -43,7 +45,7 @@ protected ProjectTaskRepository(Producer producer, NamedParameterJdbcTemplate na super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, rowMapper, Optional.of("project_task")); } - public List find(TaskSearch searchObject, Integer limit, Integer offset, String tenantId, + public SearchResponse find(TaskSearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) throws QueryBuilderException { String query = "SELECT *, a.id as aid,a.tenantid as atenantid, a.clientreferenceid as aclientreferenceid FROM project_task pt LEFT JOIN address a ON pt.addressid = a.id"; Map paramsMap = new HashMap<>(); @@ -61,15 +63,20 @@ public List find(TaskSearch searchObject, Integer limit, Integer offset, S if (lastChangedSince != null) { query = query + "and lastModifiedTime>=:lastModifiedTime "; } - query = query + "ORDER BY pt.id ASC LIMIT :limit OFFSET :offset"; paramsMap.put("tenantId", tenantId); paramsMap.put("isDeleted", includeDeleted); paramsMap.put("lastModifiedTime", lastChangedSince); + + Long totalCount = CommonUtils.constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + + query = query + "ORDER BY pt.id ASC LIMIT :limit OFFSET :offset"; paramsMap.put("limit", limit); paramsMap.put("offset", offset); + List taskList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); fetchAndSetTaskResource(taskList); - return taskList; + + return SearchResponse.builder().response(taskList).totalCount(totalCount).build(); } private void fetchAndSetTaskResource(List taskList) { @@ -97,7 +104,7 @@ private void fetchAndSetTaskResource(List taskList) { taskList.forEach(task -> task.setResources(idToObjMap.get(task.getId()))); } - public List findById(List ids, String columnName, Boolean includeDeleted) { + public SearchResponse findById(List ids, String columnName, Boolean includeDeleted) { List objFound = findInCache(ids).stream() .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) .collect(Collectors.toList()); @@ -107,7 +114,7 @@ public List findById(List ids, String columnName, Boolean includeD .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) .collect(Collectors.toList())); if (ids.isEmpty()) { - return objFound; + return SearchResponse.builder().response(objFound).build(); } } @@ -122,7 +129,7 @@ public List findById(List ids, String columnName, Boolean includeD fetchAndSetTaskResource(taskList); objFound.addAll(taskList); putInCache(objFound); - return objFound; + return SearchResponse.builder().response(objFound).build(); } } diff --git a/health-services/project/src/main/java/org/egov/project/repository/querybuilder/ProjectAddressQueryBuilder.java b/health-services/project/src/main/java/org/egov/project/repository/querybuilder/ProjectAddressQueryBuilder.java index eb623f877f0..466c3549af4 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/querybuilder/ProjectAddressQueryBuilder.java +++ b/health-services/project/src/main/java/org/egov/project/repository/querybuilder/ProjectAddressQueryBuilder.java @@ -1,14 +1,19 @@ package org.egov.project.repository.querybuilder; +import java.util.Collection; +import java.util.List; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.egov.common.models.core.ProjectSearchURLParams; import org.egov.common.models.project.Project; +import org.egov.common.models.project.ProjectSearch; import org.egov.project.config.ProjectConfiguration; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; - -import java.util.Collection; -import java.util.List; +import org.springframework.util.CollectionUtils; import static org.egov.project.util.ProjectConstants.DOT; @@ -146,6 +151,129 @@ public String getProjectSearchQuery(List projects, Integer limit, Integ return addPaginationWrapper(queryBuilder.toString(), preparedStmtList, limit, offset); } + + /** + * Constructs the SQL query string for searching projects based on the given parameters. + * + * @param projectSearch The search criteria provided in the request body. + * @param urlParams The search criteria provided as URL parameters. + * @param preparedStmtList The list to which prepared statement parameters will be added. + * @param isCountQuery Boolean flag indicating if the query is for counting records. + * @return The constructed SQL query string. + */ + public String getProjectSearchQuery(@NotNull @Valid ProjectSearch projectSearch, ProjectSearchURLParams urlParams, List preparedStmtList, Boolean isCountQuery) { + // Use a ternary operator to select between PROJECTS_COUNT_QUERY and FETCH_PROJECT_ADDRESS_QUERY based on isCountQuery flag. + String query = isCountQuery ? PROJECTS_COUNT_QUERY : FETCH_PROJECT_ADDRESS_QUERY; + StringBuilder queryBuilder = new StringBuilder(query); + + // Check if tenant ID is provided in URL parameters + if (StringUtils.isNotBlank(urlParams.getTenantId())) { + addClauseIfRequired(preparedStmtList, queryBuilder); + if (!urlParams.getTenantId().contains(DOT)) { + // State level tenant ID: use LIKE for partial matching + log.info("State level tenant"); + queryBuilder.append(" prj.tenantId like ? "); + preparedStmtList.add(urlParams.getTenantId() + '%'); + } else { + // City level tenant ID: use exact match + log.info("City level tenant"); + queryBuilder.append(" prj.tenantId=? "); + preparedStmtList.add(urlParams.getTenantId()); + } + } + + // Check if project IDs are provided + if (!CollectionUtils.isEmpty(projectSearch.getId())) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" prj.id IN (").append(createQuery(projectSearch.getId())).append(")"); + addToPreparedStatement(preparedStmtList, projectSearch.getId()); + } + + // Check if reference ID is provided + if (StringUtils.isNotBlank(projectSearch.getReferenceId())) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" prj.referenceId =? "); + preparedStmtList.add(projectSearch.getReferenceId()); + } + + // Check if project name is provided + if (StringUtils.isNotBlank(projectSearch.getName())) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" prj.name LIKE ? "); + preparedStmtList.add('%' + projectSearch.getName() + '%'); + } + + // Check if project type ID is provided + if (StringUtils.isNotBlank(projectSearch.getProjectTypeId())) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" prj.projectType=? "); + preparedStmtList.add(projectSearch.getProjectTypeId()); + } + + // Check if boundary code is provided + if (projectSearch.getBoundaryCode() != null && StringUtils.isNotBlank(projectSearch.getBoundaryCode())) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" addr.boundary=? "); + preparedStmtList.add(projectSearch.getBoundaryCode()); + } + + // Check if sub-project type ID is provided + if (StringUtils.isNotBlank(projectSearch.getSubProjectTypeId())) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" prj.projectSubtype=? "); + preparedStmtList.add(projectSearch.getSubProjectTypeId()); + } + + // Check if start date is provided + if (projectSearch.getStartDate() != null && projectSearch.getStartDate() != 0) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" prj.startDate >= ? "); + preparedStmtList.add(projectSearch.getStartDate()); + } + + // Check if end date is provided + if (projectSearch.getEndDate() != null && projectSearch.getEndDate() != 0) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" prj.endDate <= ? "); + preparedStmtList.add(projectSearch.getEndDate()); + } + + // Check if lastChangedSince is provided + if (urlParams.getLastChangedSince() != null && urlParams.getLastChangedSince() != 0) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" ( prj.lastModifiedTime >= ? )"); + preparedStmtList.add(urlParams.getLastChangedSince()); + } + + // Check if createdFrom date is provided + if (urlParams.getCreatedFrom() != null && urlParams.getCreatedFrom() != 0) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" prj.createdTime >= ? "); + preparedStmtList.add(urlParams.getCreatedFrom()); + } + + // Check if createdTo date is provided + if (urlParams.getCreatedTo() != null && urlParams.getCreatedTo() != 0) { + addClauseIfRequired(preparedStmtList, queryBuilder); + queryBuilder.append(" prj.createdTime <= ? "); + preparedStmtList.add(urlParams.getCreatedTo()); + } + + // Add clause if includeDeleted is true in request parameter + addIsDeletedCondition(preparedStmtList, queryBuilder, urlParams.getIncludeDeleted()); + + // Close the query with a closing bracket + queryBuilder.append(" )"); + + // Return query if it's a count query + if (isCountQuery) { + return queryBuilder.toString(); + } + + // Wrap constructed SQL query with pagination criteria + return addPaginationWrapper(queryBuilder.toString(), preparedStmtList, urlParams.getLimit(), urlParams.getOffset()); + } + /* Constructs project search query based on Project Ids */ public String getProjectSearchQueryBasedOnIds(List projectIds, List preparedStmtList) { StringBuilder queryBuilder = new StringBuilder(FETCH_PROJECT_ADDRESS_QUERY); @@ -244,4 +372,9 @@ public String getSearchCountQueryString(List projects, String tenantId, return query; } + /* Returns query to get total projects count based on project search params */ + public String getSearchCountQueryString(ProjectSearch projectSearch, ProjectSearchURLParams urlParams, List preparedStatement) { + String query = getProjectSearchQuery(projectSearch, urlParams, preparedStatement, Boolean.TRUE); + return query; + } } diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java index 880518fc0d7..c79c91ed161 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectBeneficiaryRowMapper.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.project.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.ProjectBeneficiary; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java index bd79efb6583..d6433f36db6 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectFacilityRowMapper.java @@ -1,16 +1,16 @@ package org.egov.project.repository.rowmapper; +import java.sql.ResultSet; +import java.sql.SQLException; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.project.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.ProjectFacility; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; -import java.sql.ResultSet; -import java.sql.SQLException; - @Component public class ProjectFacilityRowMapper implements RowMapper { diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java index 5403b3a00cc..a0ff3d24bcf 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectStaffRowMapper.java @@ -1,16 +1,16 @@ package org.egov.project.repository.rowmapper; +import java.sql.ResultSet; +import java.sql.SQLException; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.project.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.ProjectStaff; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; -import java.sql.ResultSet; -import java.sql.SQLException; - @Component public class ProjectStaffRowMapper implements RowMapper { diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java index 8d064981b7c..caafec9a8e1 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java @@ -3,10 +3,10 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.project.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.Address; import org.egov.common.models.project.AddressType; -import org.egov.common.models.project.Boundary; +import org.egov.common.models.core.Boundary; import org.egov.common.models.project.Task; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectBeneficiaryService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectBeneficiaryService.java index 5c8b5ea8862..21e60b12be7 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectBeneficiaryService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectBeneficiaryService.java @@ -1,10 +1,18 @@ package org.egov.project.service; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.BeneficiaryBulkRequest; import org.egov.common.models.project.BeneficiaryRequest; +import org.egov.common.models.project.BeneficiarySearchRequest; import org.egov.common.models.project.ProjectBeneficiary; import org.egov.common.service.IdGenService; import org.egov.common.utils.CommonUtils; @@ -13,6 +21,7 @@ import org.egov.project.repository.ProjectBeneficiaryRepository; import org.egov.project.service.enrichment.ProjectBeneficiaryEnrichmentService; import org.egov.project.validator.beneficiary.BeneficiaryValidator; +import org.egov.project.validator.beneficiary.PbExistentEntityValidator; import org.egov.project.validator.beneficiary.PbIsDeletedValidator; import org.egov.project.validator.beneficiary.PbNonExistentEntityValidator; import org.egov.project.validator.beneficiary.PbNullIdValidator; @@ -22,18 +31,11 @@ import org.egov.project.validator.beneficiary.PbUniqueTagsValidator; import org.egov.project.validator.beneficiary.PbVoucherTagUniqueForCreateValidator; import org.egov.project.validator.beneficiary.PbVoucherTagUniqueForUpdateValidator; -import org.egov.project.web.models.BeneficiarySearchRequest; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.getIdMethod; import static org.egov.common.utils.CommonUtils.handleErrors; @@ -75,6 +77,7 @@ public class ProjectBeneficiaryService { private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(PbProjectIdValidator.class) + || validator.getClass().equals(PbExistentEntityValidator.class) || validator.getClass().equals(BeneficiaryValidator.class) || validator.getClass().equals(PbUniqueTagsValidator.class) || validator.getClass().equals(PbVoucherTagUniqueForCreateValidator.class); @@ -166,12 +169,12 @@ public List update(BeneficiaryBulkRequest beneficiaryRequest return validProjectBeneficiaries; } - public List search(BeneficiarySearchRequest beneficiarySearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) throws Exception { + public SearchResponse search(BeneficiarySearchRequest beneficiarySearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) throws Exception { log.info("received request to search project beneficiaries"); String idFieldName = getIdFieldName(beneficiarySearchRequest.getProjectBeneficiary()); if (isSearchByIdOnly(beneficiarySearchRequest.getProjectBeneficiary(), idFieldName)) { @@ -180,11 +183,17 @@ public List search(BeneficiarySearchRequest beneficiarySearc .singletonList(beneficiarySearchRequest.getProjectBeneficiary())), beneficiarySearchRequest.getProjectBeneficiary()); log.info("fetching project beneficiaries with ids: {}", ids); - return projectBeneficiaryRepository.findById(ids, includeDeleted, idFieldName).stream() + + SearchResponse searchResponse = projectBeneficiaryRepository.findById(ids, idFieldName, includeDeleted); + + List projectBeneficiaries = searchResponse.getResponse().stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); + searchResponse.setResponse(projectBeneficiaries); + + return searchResponse; } log.info("searching project beneficiaries using criteria"); return projectBeneficiaryRepository.find(beneficiarySearchRequest.getProjectBeneficiary(), diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectFacilityService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectFacilityService.java index 9074b22bdf9..a7baaecf912 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectFacilityService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectFacilityService.java @@ -6,6 +6,7 @@ import org.egov.common.models.project.ProjectFacility; import org.egov.common.models.project.ProjectFacilityBulkRequest; import org.egov.common.models.project.ProjectFacilityRequest; +import org.egov.common.models.project.ProjectFacilitySearchRequest; import org.egov.common.service.IdGenService; import org.egov.common.service.UserService; import org.egov.common.utils.CommonUtils; @@ -21,7 +22,6 @@ import org.egov.project.validator.facility.PfRowVersionValidator; import org.egov.project.validator.facility.PfUniqueCombinationValidator; import org.egov.project.validator.facility.PfUniqueEntityValidator; -import org.egov.project.web.models.ProjectFacilitySearchRequest; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectResourceService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectResourceService.java index 9fc3ec389db..c99dc41448f 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectResourceService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectResourceService.java @@ -19,7 +19,7 @@ import org.egov.project.validator.resource.PrRowVersionValidator; import org.egov.project.validator.resource.PrUniqueCombinationValidator; import org.egov.project.validator.resource.PrUniqueEntityValidator; -import org.egov.project.web.models.ProjectResourceSearchRequest; +import org.egov.common.models.project.ProjectResourceSearchRequest; import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectService.java index 73be7441812..f0dd5a2645b 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectService.java @@ -1,10 +1,13 @@ package org.egov.project.service; +import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.ProjectSearchURLParams; import org.egov.common.models.project.Project; import org.egov.common.models.project.ProjectRequest; +import org.egov.common.models.project.ProjectSearchRequest; import org.egov.common.producer.Producer; import org.egov.project.config.ProjectConfiguration; import org.egov.project.repository.ProjectRepository; @@ -64,12 +67,39 @@ public ProjectRequest createProject(ProjectRequest projectRequest) { return projectRequest; } - public List searchProject(ProjectRequest project, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted, Boolean includeAncestors, Boolean includeDescendants, Long createdFrom, Long createdTo) { + public List searchProject( + ProjectRequest project, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted, + Boolean includeAncestors, + Boolean includeDescendants, + Long createdFrom, + Long createdTo + ) { projectValidator.validateSearchProjectRequest(project, limit, offset, tenantId, createdFrom, createdTo); - List projects = projectRepository.getProjects(project, limit, offset, tenantId, lastChangedSince, includeDeleted, includeAncestors, includeDescendants, createdFrom, createdTo); + List projects = projectRepository.getProjects( + project, + limit, + offset, + tenantId, + lastChangedSince, + includeDeleted, + includeAncestors, + includeDescendants, + createdFrom, + createdTo + ); return projects; } + public List searchProject(ProjectSearchRequest projectSearchRequest, @Valid ProjectSearchURLParams urlParams) { + projectValidator.validateSearchV2ProjectRequest(projectSearchRequest, urlParams); + return projectRepository.getProjects(projectSearchRequest.getProject(), urlParams); + } + public ProjectRequest updateProject(ProjectRequest project) { projectValidator.validateUpdateProjectRequest(project); log.info("Update project request validated"); @@ -122,4 +152,9 @@ private ProjectRequest getSearchProjectRequest(List projects, RequestIn public Integer countAllProjects(ProjectRequest project, String tenantId, Long lastChangedSince, Boolean includeDeleted, Long createdFrom, Long createdTo) { return projectRepository.getProjectCount(project, tenantId, lastChangedSince, includeDeleted, createdFrom, createdTo); } + + + public Integer countAllProjects(ProjectSearchRequest projectSearchRequest, ProjectSearchURLParams urlParams) { + return projectRepository.getProjectCount(projectSearchRequest.getProject(), urlParams); + } } diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java index c1eee50ec6c..82733608c54 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java @@ -22,7 +22,7 @@ import org.egov.project.validator.staff.PsUniqueCombinationValidator; import org.egov.project.validator.staff.PsUniqueEntityValidator; import org.egov.project.validator.staff.PsUserIdValidator; -import org.egov.project.web.models.ProjectStaffSearchRequest; +import org.egov.common.models.project.ProjectStaffSearchRequest; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java index 0f76c26f507..ff59ee82446 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java @@ -1,10 +1,17 @@ package org.egov.project.service; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.ds.Tuple; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskBulkRequest; import org.egov.common.models.project.TaskRequest; @@ -17,14 +24,15 @@ import org.egov.project.repository.ProjectRepository; import org.egov.project.repository.ProjectTaskRepository; import org.egov.project.service.enrichment.ProjectTaskEnrichmentService; +import org.egov.project.validator.task.PtExistentEntityValidator; import org.egov.project.validator.task.PtIsDeletedSubEntityValidator; import org.egov.project.validator.task.PtIsDeletedValidator; +import org.egov.project.validator.task.PtIsResouceEmptyValidator; import org.egov.project.validator.task.PtNonExistentEntityValidator; import org.egov.project.validator.task.PtNullIdValidator; import org.egov.project.validator.task.PtProductVariantIdValidator; import org.egov.project.validator.task.PtProjectBeneficiaryIdValidator; import org.egov.project.validator.task.PtProjectIdValidator; -import org.egov.project.validator.task.PtIsResouceEmptyValidator; import org.egov.project.validator.task.PtRowVersionValidator; import org.egov.project.validator.task.PtUniqueEntityValidator; import org.egov.project.validator.task.PtUniqueSubEntityValidator; @@ -32,12 +40,6 @@ import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.getIdMethod; import static org.egov.common.utils.CommonUtils.handleErrors; @@ -70,6 +72,7 @@ public class ProjectTaskService { private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(PtProjectIdValidator.class) + || validator.getClass().equals(PtExistentEntityValidator.class) || validator.getClass().equals(PtIsResouceEmptyValidator.class) || validator.getClass().equals(PtProjectBeneficiaryIdValidator.class) || validator.getClass().equals(PtProductVariantIdValidator.class); @@ -216,8 +219,8 @@ private Tuple, Map> validate(List(validTasks, errorDetailsMap); } - public List search(TaskSearch taskSearch, Integer limit, Integer offset, String tenantId, - Long lastChangedSince, Boolean includeDeleted) { + public SearchResponse search(TaskSearch taskSearch, Integer limit, Integer offset, String tenantId, + Long lastChangedSince, Boolean includeDeleted) { log.info("received request to search project task"); @@ -228,12 +231,13 @@ public List search(TaskSearch taskSearch, Integer limit, Integer offset, S .singletonList(taskSearch)), taskSearch); log.info("fetching project tasks with ids: {}", ids); - return projectTaskRepository.findById(ids, - idFieldName, includeDeleted).stream() + SearchResponse searchResponse = projectTaskRepository.findById(ids, + idFieldName, includeDeleted); + return SearchResponse.builder().response(searchResponse.getResponse().stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) - .collect(Collectors.toList()); + .collect(Collectors.toList())).totalCount(searchResponse.getTotalCount()).build(); } try { diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectBeneficiaryEnrichmentService.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectBeneficiaryEnrichmentService.java index 703a2791b7f..880fef8d268 100644 --- a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectBeneficiaryEnrichmentService.java +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectBeneficiaryEnrichmentService.java @@ -68,9 +68,9 @@ public void update(List validProjectBeneficiaries, List projectBeneficiaryIds = new ArrayList<>(projectBeneficiaryMap.keySet()); List existingProjectBeneficiaryIds = projectBeneficiaryRepository.findById( projectBeneficiaryIds, - false, - getIdFieldName(idMethod) - ); + getIdFieldName(idMethod), + false + ).getResponse(); log.info("updating Ids from existing entities"); enrichIdsFromExistingEntities(projectBeneficiaryMap, existingProjectBeneficiaryIds, idMethod); diff --git a/health-services/project/src/main/java/org/egov/project/util/BoundaryV2Util.java b/health-services/project/src/main/java/org/egov/project/util/BoundaryV2Util.java new file mode 100644 index 00000000000..bc235615157 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/util/BoundaryV2Util.java @@ -0,0 +1,84 @@ +package org.egov.project.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.core.Boundary; +import org.egov.project.web.models.boundary.BoundaryResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +/** + * Utility class to validate boundary details. + */ +@Component +@Slf4j +public class BoundaryV2Util { + + // Injecting boundary host value from configuration + @Value("${egov.boundary.host}") + private String boundaryHost; + + // Injecting boundary search URL value from configuration + @Value("${egov.boundary.search.url}") + private String boundarySearchUrl; + + @Autowired + private ServiceRequestClient serviceRequestClient; + + /** + * Validates boundary details against the egov-location service response. + * + * @param boundaryTypeBoundariesMap A map of boundary types with lists of boundary codes + * @param tenantId The tenant ID + * @param requestInfo Request information + * @param hierarchyTypeCode Hierarchy type code + */ + public void validateBoundaryDetails(Map> boundaryTypeBoundariesMap, String tenantId, + RequestInfo requestInfo, String hierarchyTypeCode) { + // Flatten the lists of boundary codes from the map values + List boundaries = boundaryTypeBoundariesMap.values().stream().flatMap(List::stream) + .collect(Collectors.toList()); + if(CollectionUtils.isEmpty(boundaries)) return; + try { + // Fetch boundary details from the service + log.debug("Fetching boundary details for tenantId: {}, boundaries: {}", tenantId, boundaries); + BoundaryResponse boundarySearchResponse = serviceRequestClient.fetchResult( + new StringBuilder(boundaryHost + + boundarySearchUrl + + "?limit=" + boundaries.size() + + "&offset=0&tenantId=" + tenantId + + "&codes=" + String.join(",", boundaries)), + requestInfo, + BoundaryResponse.class + ); + log.debug("Boundary details fetched successfully for tenantId: {}", tenantId); + + // Extract invalid boundary codes + List invalidBoundaryCodes = new ArrayList<>(boundaries); + invalidBoundaryCodes.removeAll(boundarySearchResponse.getBoundary().stream() + .map(Boundary::getCode) + .collect(Collectors.toList()) + ); + + // Throw exception if invalid boundary codes are found + if (!invalidBoundaryCodes.isEmpty()) { + log.error("The boundary data for the codes {} is not available.", invalidBoundaryCodes); + throw new CustomException("INVALID_BOUNDARY_DATA", "The boundary data for the code " + + invalidBoundaryCodes + " is not available"); + } + } catch (Exception e) { + log.error("Exception while searching boundaries for tenantId: {}", tenantId, e); + // Throw a custom exception if an error occurs during boundary search + throw new CustomException("BOUNDARY_SEARCH_ERROR", e.getMessage()); + } + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbExistentEntityValidator.java new file mode 100644 index 00000000000..73a622a6d1e --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbExistentEntityValidator.java @@ -0,0 +1,77 @@ +package org.egov.project.validator.beneficiary; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.common.models.Error; +import org.egov.common.models.project.BeneficiaryBulkRequest; +import org.egov.common.models.project.ProjectBeneficiary; +import org.egov.common.models.project.ProjectBeneficiarySearch; +import org.egov.common.validator.Validator; +import org.egov.project.repository.ProjectBeneficiaryRepository; +import org.springframework.util.CollectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of entities with the given client reference IDs. + * This validator checks if the provided ProjectBeneficiary entities already exist in the database based on their client reference IDs. + * + * @author kanishq-egov + */ +public class PbExistentEntityValidator implements Validator { + + private final ProjectBeneficiaryRepository projectBeneficiaryRepository; + + /** + * Constructor to initialize the ProjectBeneficiaryRepository dependency. + * + * @param projectBeneficiaryRepository The repository for ProjectBeneficiary entities. + */ + public PbExistentEntityValidator(ProjectBeneficiaryRepository projectBeneficiaryRepository) { + this.projectBeneficiaryRepository = projectBeneficiaryRepository; + } + + /** + * Validates the existence of entities with the given client reference IDs. + * + * @param request The bulk request containing ProjectBeneficiary entities. + * @return A map containing ProjectBeneficiary entities and their associated error details. + */ + @Override + public Map> validate(BeneficiaryBulkRequest request) { + // Map to hold ProjectBeneficiary entities and their error details + Map> errorDetailsMap = new HashMap<>(); + // Get the list of ProjectBeneficiary entities from the request + List entities = request.getProjectBeneficiaries(); + // Extract client reference IDs from ProjectBeneficiary entities without errors + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) + .map(ProjectBeneficiary::getClientReferenceId) + .collect(Collectors.toList()); + // Create a search object for querying entities by client reference IDs + ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() + .clientReferenceId(clientReferenceIdList) + .build(); + // Check if the client reference ID list is not empty + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing entities by client reference IDs + List existentEntities = projectBeneficiaryRepository.findById( + clientReferenceIdList, + getIdFieldName(projectBeneficiarySearch), + Boolean.FALSE).getResponse(); + // For each existing entity, populate error details for uniqueness + existentEntities.forEach(entity -> { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(entity, error, errorDetailsMap); + }); + } + return errorDetailsMap; + } + +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbRowVersionValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbRowVersionValidator.java index d6de91c5439..a36e39664a6 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbRowVersionValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbRowVersionValidator.java @@ -49,7 +49,7 @@ public Map> validate(BeneficiaryBulkRequest requ if (!iMap.isEmpty()) { List individualIds = new ArrayList<>(iMap.keySet()); List existingProjectBeneficiaries = projectBeneficiaryRepository.findById(individualIds, - false, getIdFieldName(idMethod)); + getIdFieldName(idMethod), false).getResponse(); List entitiesWithMismatchedRowVersion = getEntitiesWithMismatchedRowVersion(iMap, existingProjectBeneficiaries, idMethod); entitiesWithMismatchedRowVersion.forEach(projectBeneficiary -> { diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForCreateValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForCreateValidator.java index dbac480cccd..7140c580507 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForCreateValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForCreateValidator.java @@ -6,7 +6,7 @@ import org.egov.common.models.project.ProjectBeneficiary; import org.egov.common.validator.Validator; import org.egov.project.repository.ProjectBeneficiaryRepository; -import org.egov.project.web.models.ProjectBeneficiarySearch; +import org.egov.common.models.project.ProjectBeneficiarySearch; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; @@ -106,7 +106,7 @@ private List getInvalidVoucherTags(List existingProjectBeneficiaries = projectBeneficiaryRepository.find( projectBeneficiarySearch, voucherTags.size(), 0, validProjectBeneficiaries.get(0).getTenantId(), null, false - ); + ).getResponse(); } catch (Exception e) { log.error("Exception while fetching project beneficiary service : ", e); throw new CustomException("PROJECT_BENEFICIARY_VOUCHER_TAG_SEARCH_FAILED","Error occurred while fetching project beneficiary based on voucher tags. "+e); diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForUpdateValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForUpdateValidator.java index 8450427492f..20c7084b680 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForUpdateValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbVoucherTagUniqueForUpdateValidator.java @@ -1,23 +1,23 @@ package org.egov.project.validator.beneficiary; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; import org.egov.common.models.project.BeneficiaryBulkRequest; import org.egov.common.models.project.ProjectBeneficiary; import org.egov.common.validator.Validator; import org.egov.project.repository.ProjectBeneficiaryRepository; -import org.egov.project.web.models.ProjectBeneficiarySearch; +import org.egov.common.models.project.ProjectBeneficiarySearch; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; @@ -53,7 +53,7 @@ public Map> validate(BeneficiaryBulkRequest bene // Filter valid project beneficiaries (those without errors) List validProjectBeneficiaries = beneficiaryBulkRequest.getProjectBeneficiaries() - .stream().filter(notHavingErrors()).collect(Collectors.toList()); + .stream().filter(notHavingErrors()).filter(projectBeneficiary -> projectBeneficiary.getTag() != null).collect(Collectors.toList()); if(!validProjectBeneficiaries.isEmpty()) { // Get a list of existing ProjectBeneficiaries based on IDs @@ -86,7 +86,7 @@ private List getExistingProjectBeneficiaries(List getExistingProjectBeneficiaries(List validProjectBeneficiaries, List existingProjectBeneficiaries, Map> errorDetailsMap) { Map existingProjectBeneficiaryMap = existingProjectBeneficiaries.stream().collect(Collectors.toMap(ProjectBeneficiary::getId, projectBeneficiary -> projectBeneficiary)); // Filter project beneficiaries that are valid and have invalid voucher tags - List invalidEntities = validProjectBeneficiaries.stream().filter(notHavingErrors()) + List invalidEntities = validProjectBeneficiaries.stream() + .filter(notHavingErrors()) .filter(entity -> !existingProjectBeneficiaryMap.containsKey(entity.getId())) .collect(Collectors.toList()); diff --git a/health-services/project/src/main/java/org/egov/project/validator/project/ProjectValidator.java b/health-services/project/src/main/java/org/egov/project/validator/project/ProjectValidator.java index 754fbc26fbe..266f664312d 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/project/ProjectValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/project/ProjectValidator.java @@ -13,15 +13,19 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.jayway.jsonpath.JsonPath; +import jakarta.validation.Valid; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.ProjectSearchURLParams; import org.egov.common.models.project.Document; import org.egov.common.models.project.Project; import org.egov.common.models.project.ProjectRequest; +import org.egov.common.models.project.ProjectSearch; +import org.egov.common.models.project.ProjectSearchRequest; import org.egov.common.models.project.Target; import org.egov.project.config.ProjectConfiguration; -import org.egov.project.util.BoundaryUtil; +import org.egov.project.util.BoundaryV2Util; import org.egov.project.util.MDMSUtils; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; @@ -46,7 +50,7 @@ public class ProjectValidator { MDMSUtils mdmsUtils; @Autowired - BoundaryUtil boundaryUtil; + BoundaryV2Util boundaryV2Util; @Autowired ProjectConfiguration config; @@ -106,6 +110,64 @@ public void validateSearchProjectRequest(ProjectRequest project, Integer limit, throw new CustomException(errorMap); } + /* Validates Project search request body */ + public void validateSearchV2ProjectRequest(ProjectSearchRequest projectSearchRequest, @Valid ProjectSearchURLParams urlParams) { + Map errorMap = new HashMap<>(); + RequestInfo requestInfo = projectSearchRequest.getRequestInfo(); + ProjectSearch projectSearch = projectSearchRequest.getProject(); + + // Verify if RequestInfo and UserInfo is present + validateRequestInfo(requestInfo); + + // Verify if search project request parameters are valid + validateSearchProjectRequestParams( + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + projectSearch.getCreatedFrom(), + projectSearch.getCreatedTo() + ); + + // Check if tenant ID is present in the request + if (StringUtils.isBlank(urlParams.getTenantId())) { + log.error("Tenant ID is mandatory in Project request body"); + throw new CustomException("TENANT_ID", "Tenant ID is mandatory"); + } + + // Validate if at least one project search field is present + if (CollectionUtils.isEmpty(projectSearch.getId()) + && StringUtils.isBlank(projectSearch.getProjectTypeId()) + && StringUtils.isBlank(projectSearch.getName()) + && StringUtils.isBlank(projectSearch.getSubProjectTypeId()) + && (projectSearch.getStartDate() == null || projectSearch.getStartDate() == 0) + && (projectSearch.getEndDate() == null || projectSearch.getEndDate() == 0) + && (projectSearch.getCreatedFrom() == null || projectSearch.getCreatedFrom() == 0) + && (projectSearch.getBoundaryCode() == null || StringUtils.isBlank(projectSearch.getBoundaryCode()))) { + log.error("Any one project search field is required for Project Search"); + throw new CustomException("PROJECT_SEARCH_FIELDS", "Any one project search field is required"); + } + + // Validate that start date is less than or equal to end date + if ((projectSearch.getStartDate() != null && projectSearch.getEndDate() != null && projectSearch.getEndDate() != 0) + && (projectSearch.getStartDate().compareTo(projectSearch.getEndDate()) > 0)) { + log.error("Start date should be less than end date"); + throw new CustomException("INVALID_DATE", "Start date should be less than end date"); + } + + // Validate that if end date is provided, start date should also be provided + if ((projectSearch.getStartDate() == null || projectSearch.getStartDate() == 0) + && (projectSearch.getEndDate() != null && projectSearch.getEndDate() != 0)) { + log.error("Start date is required if end date is passed"); + throw new CustomException("INVALID_DATE", "Start date is required if end date is passed"); + } + + // If there are any collected errors, throw a CustomException with the error map + if (!errorMap.isEmpty()) { + throw new CustomException(errorMap); + } + } + + /* Validates Update Project request body */ public void validateUpdateProjectRequest(ProjectRequest request) { Map errorMap = new HashMap<>(); @@ -401,7 +463,7 @@ private Map> getBoundaryForValidation(List project /* Validates Boundary data with location service */ private void validateBoundary(Map> boundaries, String tenantId, RequestInfo requestInfo, Map errorMap) { if (boundaries.size() > 0) { - boundaryUtil.validateBoundaryDetails(boundaries, tenantId, requestInfo, config.getLocationHierarchyType()); + boundaryV2Util.validateBoundaryDetails(boundaries, tenantId, requestInfo, config.getLocationHierarchyType()); } } diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtExistentEntityValidator.java new file mode 100644 index 00000000000..3a65cc6acc9 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtExistentEntityValidator.java @@ -0,0 +1,76 @@ +package org.egov.project.validator.task; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.common.models.Error; +import org.egov.common.models.project.Task; +import org.egov.common.models.project.TaskBulkRequest; +import org.egov.common.models.project.TaskSearch; +import org.egov.common.validator.Validator; +import org.egov.project.repository.ProjectTaskRepository; +import org.springframework.util.CollectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of entities with the given client reference IDs. + * This validator checks if the provided Task entities already exist in the database based on their client reference IDs. + * + * @author: kanishq-egov + */ +public class PtExistentEntityValidator implements Validator { + + private final ProjectTaskRepository projectTaskRepository; + + /** + * Constructor to initialize the ProjectTaskRepository dependency. + * + * @param projectTaskRepository The repository for project task entities. + */ + public PtExistentEntityValidator(ProjectTaskRepository projectTaskRepository) { + this.projectTaskRepository = projectTaskRepository; + } + + /** + * Validates the existence of entities with the given client reference IDs. + * + * @param request The bulk request containing Task entities. + * @return A map containing Task entities and their associated error details. + */ + @Override + public Map> validate(TaskBulkRequest request) { + // Map to hold Task entities and their error details + Map> errorDetailsMap = new HashMap<>(); + // Get the list of Task entities from the request + List entities = request.getTasks(); + // Extract client reference IDs from Task entities without errors + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) + .map(Task::getClientReferenceId) + .collect(Collectors.toList()); + // Create a search object for querying entities by client reference IDs + TaskSearch taskSearch = TaskSearch.builder() + .clientReferenceId(clientReferenceIdList) + .build(); + // Check if the client reference ID list is not empty + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing entities by client reference IDs + List existentEntities = projectTaskRepository.findById( + clientReferenceIdList, + getIdFieldName(taskSearch), + Boolean.FALSE).getResponse(); + // For each existing entity, populate error details for uniqueness + existentEntities.forEach(entity -> { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(entity, error, errorDetailsMap); + }); + } + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtNonExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtNonExistentEntityValidator.java index 16b94a50ae0..5342d6ff90a 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtNonExistentEntityValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtNonExistentEntityValidator.java @@ -58,7 +58,7 @@ public Map> validate(TaskBulkRequest request) { if (!eMap.isEmpty()) { List entityIds = new ArrayList<>(eMap.keySet()); List existingEntities = projectTaskRepository.findById(entityIds, - getIdFieldName(idMethod), false); + getIdFieldName(idMethod), false).getResponse(); List nonExistentEntities = checkNonExistentEntities(eMap, existingEntities, idMethod); nonExistentEntities.forEach(task -> { diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtRowVersionValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtRowVersionValidator.java index 48332dfcbe7..435c330daaf 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtRowVersionValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtRowVersionValidator.java @@ -49,7 +49,7 @@ public Map> validate(TaskBulkRequest request) { if (!eMap.isEmpty()) { List entityIds = new ArrayList<>(eMap.keySet()); List existingEntities = projectTaskRepository.findById(entityIds, - getIdFieldName(idMethod), false); + getIdFieldName(idMethod), false).getResponse(); List entitiesWithMismatchedRowVersion = getEntitiesWithMismatchedRowVersion(eMap, existingEntities, idMethod); entitiesWithMismatchedRowVersion.forEach(individual -> { diff --git a/health-services/project/src/main/java/org/egov/project/web/controllers/BandwidthController.java b/health-services/project/src/main/java/org/egov/project/web/controllers/BandwidthController.java index e18a7cc1c41..848ec089f4c 100644 --- a/health-services/project/src/main/java/org/egov/project/web/controllers/BandwidthController.java +++ b/health-services/project/src/main/java/org/egov/project/web/controllers/BandwidthController.java @@ -13,7 +13,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import javax.validation.Valid; +import jakarta.validation.Valid; @Controller @RequestMapping("") diff --git a/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectApiController.java b/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectApiController.java index 806a61bdffa..1b74b7ab1d7 100644 --- a/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectApiController.java +++ b/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectApiController.java @@ -1,13 +1,24 @@ package org.egov.project.web.controllers; +import java.util.List; + import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Max; +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.NotNull; import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.ProjectSearchURLParams; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; import org.egov.common.models.project.BeneficiaryBulkRequest; import org.egov.common.models.project.BeneficiaryBulkResponse; import org.egov.common.models.project.BeneficiaryRequest; import org.egov.common.models.project.BeneficiaryResponse; +import org.egov.common.models.project.BeneficiarySearchRequest; import org.egov.common.models.project.Project; import org.egov.common.models.project.ProjectBeneficiary; import org.egov.common.models.project.ProjectFacility; @@ -15,13 +26,16 @@ import org.egov.common.models.project.ProjectFacilityBulkResponse; import org.egov.common.models.project.ProjectFacilityRequest; import org.egov.common.models.project.ProjectFacilityResponse; +import org.egov.common.models.project.ProjectFacilitySearchRequest; import org.egov.common.models.project.ProjectRequest; import org.egov.common.models.project.ProjectResponse; +import org.egov.common.models.project.ProjectSearchRequest; import org.egov.common.models.project.ProjectStaff; import org.egov.common.models.project.ProjectStaffBulkRequest; import org.egov.common.models.project.ProjectStaffBulkResponse; import org.egov.common.models.project.ProjectStaffRequest; import org.egov.common.models.project.ProjectStaffResponse; +import org.egov.common.models.project.ProjectStaffSearchRequest; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskBulkRequest; import org.egov.common.models.project.TaskBulkResponse; @@ -36,27 +50,18 @@ import org.egov.project.service.ProjectService; import org.egov.project.service.ProjectStaffService; import org.egov.project.service.ProjectTaskService; -import org.egov.project.web.models.BeneficiarySearchRequest; -import org.egov.project.web.models.ProjectFacilitySearchRequest; -import org.egov.project.web.models.ProjectStaffSearchRequest; 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.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import java.util.List; -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-14T20:57:07.075+05:30") @Controller @RequestMapping("") @Validated @@ -101,6 +106,7 @@ public ProjectApiController(ObjectMapper objectMapper, HttpServletRequest httpSe @RequestMapping(value = "/beneficiary/v1/bulk/_create", method = RequestMethod.POST) public ResponseEntity projectBeneficiaryV1BulkCreatePost(@ApiParam(value = "Capture details of benificiary type.", required = true) @Valid @RequestBody BeneficiaryBulkRequest beneficiaryRequest) { + beneficiaryRequest.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); beneficiaryRequest.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); projectBeneficiaryService.putInCache(beneficiaryRequest.getProjectBeneficiaries()); producer.push(projectConfiguration.getBulkCreateProjectBeneficiaryTopic(), beneficiaryRequest); @@ -122,20 +128,21 @@ public ResponseEntity projectBeneficiaryV1CreatePost(@ApiPa } @RequestMapping(value = "/beneficiary/v1/_search", method = RequestMethod.POST) - public ResponseEntity projectBeneficiaryV1SearchPost(@ApiParam(value = "Project Beneficiary Search.", required = true) @Valid @RequestBody BeneficiarySearchRequest beneficiarySearchRequest, @NotNull - @Min(0) - @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, @NotNull - @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { - List projectBeneficiaries = projectBeneficiaryService.search( + public ResponseEntity projectBeneficiaryV2SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Project Beneficiary Search.", required = true) @Valid @RequestBody BeneficiarySearchRequest beneficiarySearchRequest + ) throws Exception { + SearchResponse searchResponse = projectBeneficiaryService.search( beneficiarySearchRequest, - limit, - offset, - tenantId, - lastChangedSince, - includeDeleted + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted() ); BeneficiaryBulkResponse beneficiaryResponse = BeneficiaryBulkResponse.builder() - .projectBeneficiaries(projectBeneficiaries) + .projectBeneficiaries(searchResponse.getResponse()) + .totalCount(searchResponse.getTotalCount()) .responseInfo(ResponseInfoFactory .createResponseInfo(beneficiarySearchRequest.getRequestInfo(), true)) .build(); @@ -207,20 +214,19 @@ public ResponseEntity projectFacilityV1BulkCreatePost(@ApiParam(va .createResponseInfo(request.getRequestInfo(), true)); } + @RequestMapping(value = "/facility/v1/_search", method = RequestMethod.POST) - public ResponseEntity projectFacilityV1SearchPost(@ApiParam(value = "Capture details of Project facility.", required = true) @Valid @RequestBody ProjectFacilitySearchRequest projectFacilitySearchRequest, - @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, - @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, - @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, - @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, - @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { + public ResponseEntity projectFacilityV2SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Capture details of Project facility.", required = true) @Valid @RequestBody ProjectFacilitySearchRequest projectFacilitySearchRequest + ) throws Exception { List projectFacilities = projectFacilityService.search( projectFacilitySearchRequest, - limit, - offset, - tenantId, - lastChangedSince, - includeDeleted + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted() ); ProjectFacilityBulkResponse response = ProjectFacilityBulkResponse.builder() .projectFacilities(projectFacilities) @@ -298,20 +304,19 @@ public ResponseEntity projectStaffV1CreatePost(@ApiParam(value = " .createResponseInfo(request.getRequestInfo(), true)); } + @RequestMapping(value = "/staff/v1/_search", method = RequestMethod.POST) - public ResponseEntity projectStaffV1SearchPost(@ApiParam(value = "Capture details of Project staff.", required = true) @Valid @RequestBody ProjectStaffSearchRequest projectStaffSearchRequest, - @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, - @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, - @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, - @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, - @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { + public ResponseEntity projectStaffV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Capture details of Project staff.", required = true) @Valid @RequestBody ProjectStaffSearchRequest projectStaffSearchRequest + ) throws Exception { List projectStaffList = projectStaffService.search( projectStaffSearchRequest, - limit, - offset, - tenantId, - lastChangedSince, - includeDeleted + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted() ); ProjectStaffBulkResponse response = ProjectStaffBulkResponse.builder() .projectStaff(projectStaffList) @@ -393,17 +398,23 @@ public ResponseEntity projectTaskBulkV1CreatePost(@ApiParam(value .createResponseInfo(request.getRequestInfo(), true)); } + @RequestMapping(value = "/task/v1/_search", method = RequestMethod.POST) - public ResponseEntity projectTaskV1SearchPost(@ApiParam(value = "Project Task Search.", required = true) @Valid @RequestBody TaskSearchRequest request, - @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, - @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, - @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, - @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, - @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) { - - List households = projectTaskService.search(request.getTask(), limit, offset, tenantId, lastChangedSince, includeDeleted); + public ResponseEntity projectTaskV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Project Task Search.", required = true) @Valid @RequestBody TaskSearchRequest taskSearchRequest + ) { + SearchResponse taskSearchResponse = projectTaskService.search( + taskSearchRequest.getTask(), + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted() + ); + TaskBulkResponse response = TaskBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).tasks(households).build(); + .createResponseInfo(taskSearchRequest.getRequestInfo(), true)).tasks(taskSearchResponse.getResponse()).totalCount(taskSearchResponse.getTotalCount()).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } @@ -463,14 +474,52 @@ public ResponseEntity createProject(@ApiParam(value = "Details } @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) - public ResponseEntity searchProject(@ApiParam(value = "Details for the project.", required = true) @Valid @RequestBody ProjectRequest project, @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted , @ApiParam(value = "Used in project search API to specify if response should include project elements that are in the preceding hierarchy of matched projects.", defaultValue = "false") @Valid @RequestParam(value = "includeAncestors", required = false, defaultValue = "false") Boolean includeAncestors, @ApiParam(value = "Used in project search API to specify if response should include project elements that are in the following hierarchy of matched projects.", defaultValue = "false") @Valid @RequestParam(value = "includeDescendants", required = false, defaultValue = "false") Boolean includeDescendants, @ApiParam(value = "Used in project search API to limit the search results to only those projects whose creation date is after the specified 'createdFrom' date", defaultValue = "false") @Valid @RequestParam(value = "createdFrom", required = false) Long createdFrom, @ApiParam(value = "Used in project search API to limit the search results to only those projects whose creation date is before the specified 'createdTo' date", defaultValue = "false") @Valid @RequestParam(value = "createdTo", required = false) Long createdTo) { - List projects = projectService.searchProject(project, limit, offset, tenantId, lastChangedSince, includeDeleted, includeAncestors, includeDescendants, createdFrom, createdTo); + public ResponseEntity searchProject( + @ApiParam(value = "Details for the project.", required = true) @Valid @RequestBody ProjectRequest project, + @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, + @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, + @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, + @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, + @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted, + @ApiParam(value = "Used in project search API to specify if response should include project elements that are in the preceding hierarchy of matched projects.", defaultValue = "false") @Valid @RequestParam(value = "includeAncestors", required = false, defaultValue = "false") Boolean includeAncestors, + @ApiParam(value = "Used in project search API to specify if response should include project elements that are in the following hierarchy of matched projects.", defaultValue = "false") @Valid @RequestParam(value = "includeDescendants", required = false, defaultValue = "false") Boolean includeDescendants, + @ApiParam(value = "Used in project search API to limit the search results to only those projects whose creation date is after the specified 'createdFrom' date", defaultValue = "false") @Valid @RequestParam(value = "createdFrom", required = false) Long createdFrom, + @ApiParam(value = "Used in project search API to limit the search results to only those projects whose creation date is before the specified 'createdTo' date", defaultValue = "false") @Valid @RequestParam(value = "createdTo", required = false) Long createdTo + ) { + List projects = projectService.searchProject( + project, + limit, + offset, + tenantId, + lastChangedSince, + includeDeleted, + includeAncestors, + includeDescendants, + createdFrom, + createdTo + ); ResponseInfo responseInfo = ResponseInfoFactory.createResponseInfo(project.getRequestInfo(), true); Integer count = projectService.countAllProjects(project, tenantId, lastChangedSince, includeDeleted, createdFrom, createdTo); ProjectResponse projectResponse = ProjectResponse.builder().responseInfo(responseInfo).project(projects).totalCount(count).build(); return new ResponseEntity(projectResponse, HttpStatus.OK); } + @RequestMapping(value = "/v2/_search", method = RequestMethod.POST) + public ResponseEntity searchV2Project( + @Valid @ModelAttribute ProjectSearchURLParams urlParams, + @ApiParam(value = "Details for the project.", required = true) @Valid @RequestBody ProjectSearchRequest projectSearchRequest + ) { + List projects = projectService.searchProject(projectSearchRequest, urlParams); + ResponseInfo responseInfo = ResponseInfoFactory.createResponseInfo(projectSearchRequest.getRequestInfo(), true); + Integer count = projectService.countAllProjects(projectSearchRequest, urlParams); + ProjectResponse projectResponse = ProjectResponse.builder() + .responseInfo(responseInfo) + .project(projects) + .totalCount(count) + .build(); + return new ResponseEntity(projectResponse, HttpStatus.OK); + } + @RequestMapping(value = "/v1/_update", method = RequestMethod.POST) public ResponseEntity updateProject(@ApiParam(value = "Details for the updated Project.", required = true) @Valid @RequestBody ProjectRequest project) { ProjectRequest enrichedProjectRequest = projectService.updateProject(project); diff --git a/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectResourceApiController.java b/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectResourceApiController.java index 499123db26b..6f71ea7ef93 100644 --- a/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectResourceApiController.java +++ b/health-services/project/src/main/java/org/egov/project/web/controllers/ProjectResourceApiController.java @@ -1,36 +1,34 @@ package org.egov.project.web.controllers; +import java.util.List; + import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.models.core.URLParams; import org.egov.common.models.project.ProjectResource; import org.egov.common.models.project.ProjectResourceBulkRequest; import org.egov.common.models.project.ProjectResourceBulkResponse; import org.egov.common.models.project.ProjectResourceRequest; import org.egov.common.models.project.ProjectResourceResponse; +import org.egov.common.models.project.ProjectResourceSearchRequest; import org.egov.common.producer.Producer; import org.egov.common.utils.ResponseInfoFactory; import org.egov.project.config.ProjectConfiguration; import org.egov.project.service.ProjectResourceService; -import org.egov.project.web.models.ProjectResourceSearchRequest; 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.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import java.util.List; -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-14T20:57:07.075+05:30") @Controller @RequestMapping("") @Validated @@ -72,16 +70,21 @@ public ResponseEntity resourceV1BulkCreatePost(@ApiParam(value = " } @RequestMapping(value = "/resource/v1/_search", method = RequestMethod.POST) - public ResponseEntity resourceV1SearchPost(@ApiParam( - value = "Search linkage of Project and resource.", required = true) @Valid @RequestBody - ProjectResourceSearchRequest request, @NotNull - @Min(0) - @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, @NotNull - @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws QueryBuilderException { - - List projectResource = projectResourceService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); + public ResponseEntity resourceV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Search linkage of Project and resource.", required = true) @Valid @RequestBody ProjectResourceSearchRequest projectResourceSearchRequest + ) throws QueryBuilderException { + + List projectResource = projectResourceService.search( + projectResourceSearchRequest, + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted() + ); ProjectResourceBulkResponse response = ProjectResourceBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).projectResource(projectResource).build(); + .createResponseInfo(projectResourceSearchRequest.getRequestInfo(), true)).projectResource(projectResource).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckRequest.java b/health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckRequest.java index ceffcb45320..2a34df10592 100644 --- a/health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckRequest.java +++ b/health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckRequest.java @@ -10,8 +10,8 @@ import org.egov.common.models.project.AdditionalFields; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; @Validated @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckResponse.java b/health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckResponse.java index 96b977556fb..5fdcf303eaf 100644 --- a/health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckResponse.java +++ b/health-services/project/src/main/java/org/egov/project/web/models/BandwidthCheckResponse.java @@ -10,8 +10,8 @@ import org.egov.common.models.project.AdditionalFields; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; @Validated @JsonIgnoreProperties(ignoreUnknown = true) diff --git a/health-services/project/src/main/java/org/egov/project/web/models/BeneficiarySearchRequest.java b/health-services/project/src/main/java/org/egov/project/web/models/BeneficiarySearchRequest.java index 87025f0202a..ba1cd058378 100644 --- a/health-services/project/src/main/java/org/egov/project/web/models/BeneficiarySearchRequest.java +++ b/health-services/project/src/main/java/org/egov/project/web/models/BeneficiarySearchRequest.java @@ -7,16 +7,17 @@ import lombok.Data; import lombok.NoArgsConstructor; import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.project.ProjectBeneficiarySearch; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import javax.validation.constraints.NotNull; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; /** * BeneficiarySearchRequest */ @Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") + @Data @NoArgsConstructor diff --git a/health-services/project/src/main/java/org/egov/project/web/models/ProjectBeneficiarySearch.java b/health-services/project/src/main/java/org/egov/project/web/models/ProjectBeneficiarySearch.java deleted file mode 100644 index 1e58c06fd11..00000000000 --- a/health-services/project/src/main/java/org/egov/project/web/models/ProjectBeneficiarySearch.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.egov.project.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.data.query.annotations.Table; -import org.springframework.validation.annotation.Validated; - -import javax.validation.constraints.Size; -import java.util.List; - -/** -* Search model for project beneficiary. -*/ - @ApiModel(description = "Search model for project beneficiary.") -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -@Table(name="project_beneficiary") -public class ProjectBeneficiarySearch { - - @JsonProperty("id") - private List id = null; - - @JsonProperty("tenantId") - @Size(min=2,max=1000) - private String tenantId = null; - - @JsonProperty("projectId") - @Size(min=2,max=64) - private String projectId = null; - - @JsonProperty("beneficiaryId") - @Size(min=2,max=64) - private String beneficiaryId = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; - - @JsonProperty("dateOfRegistration") - private Long dateOfRegistration = null; - - @JsonProperty("tag") - private List tag; -} - diff --git a/health-services/project/src/main/java/org/egov/project/web/models/ProjectFacilitySearch.java b/health-services/project/src/main/java/org/egov/project/web/models/ProjectFacilitySearch.java deleted file mode 100644 index 1bba9410e75..00000000000 --- a/health-services/project/src/main/java/org/egov/project/web/models/ProjectFacilitySearch.java +++ /dev/null @@ -1,42 +0,0 @@ -package org.egov.project.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.data.query.annotations.Table; -import org.springframework.validation.annotation.Validated; - -import java.util.List; - -/** -* This object defines the mapping of a facility to a project. -*/ - @ApiModel(description = "This object defines the mapping of a facility to a project.") -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -@Table(name="project_facility") -public class ProjectFacilitySearch { - - @JsonProperty("id") - private List id = null; - - @JsonProperty("tenantId") - private String tenantId = null; - - @JsonProperty("facilityId") - private List facilityId = null; - - @JsonProperty("projectId") - private List projectId = null; - -} \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/web/models/ProjectFacilitySearchRequest.java b/health-services/project/src/main/java/org/egov/project/web/models/ProjectFacilitySearchRequest.java deleted file mode 100644 index 88ca607f150..00000000000 --- a/health-services/project/src/main/java/org/egov/project/web/models/ProjectFacilitySearchRequest.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.egov.project.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.contract.request.RequestInfo; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - -/** -* ProjectFacilitySearchRequest -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectFacilitySearchRequest { - - @JsonProperty("RequestInfo") - @NotNull - @Valid - private RequestInfo requestInfo = null; - - @JsonProperty("ProjectFacility") - @NotNull - @Valid - private ProjectFacilitySearch projectFacility = null; - -} - diff --git a/health-services/project/src/main/java/org/egov/project/web/models/ProjectResourceSearch.java b/health-services/project/src/main/java/org/egov/project/web/models/ProjectResourceSearch.java deleted file mode 100644 index 09e6d1bbaca..00000000000 --- a/health-services/project/src/main/java/org/egov/project/web/models/ProjectResourceSearch.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.egov.project.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.data.query.annotations.Table; -import org.springframework.validation.annotation.Validated; - -import javax.validation.constraints.Size; -import java.util.List; - -/** -* This object defines the mapping of a resource to a project. -*/ - @ApiModel(description = "This object defines the mapping of a resource to a project.") -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -@Table(name = "project_resource") -public class ProjectResourceSearch { - - @JsonProperty("id") - private List id = null; - - @JsonProperty("projectId") - @Size(min=2,max=64) - private String projectId = null; - -} - diff --git a/health-services/project/src/main/java/org/egov/project/web/models/ProjectResourceSearchRequest.java b/health-services/project/src/main/java/org/egov/project/web/models/ProjectResourceSearchRequest.java deleted file mode 100644 index 7b62b15d564..00000000000 --- a/health-services/project/src/main/java/org/egov/project/web/models/ProjectResourceSearchRequest.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.egov.project.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - -/** -* ProjectResourceSearchRequest -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectResourceSearchRequest { - - @JsonProperty("RequestInfo") - @NotNull - @Valid - private org.egov.common.contract.request.RequestInfo requestInfo = null; - - @JsonProperty("ProjectResource") - @NotNull - @Valid - private ProjectResourceSearch projectResource = null; - - -} - diff --git a/health-services/project/src/main/java/org/egov/project/web/models/ProjectSearch.java b/health-services/project/src/main/java/org/egov/project/web/models/ProjectSearch.java deleted file mode 100644 index a6ddd479dc5..00000000000 --- a/health-services/project/src/main/java/org/egov/project/web/models/ProjectSearch.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.egov.project.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.data.query.annotations.Table; -import org.springframework.validation.annotation.Validated; - -import javax.validation.constraints.Size; - -/** -* ProjectSearch -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -@Table(name="project") -public class ProjectSearch { - - @JsonProperty("id") - private String id = null; - - @JsonProperty("tenantId") - private String tenantId = null; - - @JsonProperty("startDate") - private Long startDate = null; - - @JsonProperty("endDate") - private Long endDate = null; - - @JsonProperty("isTaskEnabled") - private Boolean isTaskEnabled = false; - - @JsonProperty("parent") - @Size(min=2,max=64) - private String parent = null; - - @JsonProperty("projectTypeId") - private String projectTypeId = null; - - @JsonProperty("subProjectTypeId") - private String subProjectTypeId = null; - - @JsonProperty("department") - @Size(min=2,max=64) - private String department = null; - - @JsonProperty("referenceId") - @Size(min=2,max=100) - private String referenceId = null; - - @JsonProperty("boundaryCode") - private String boundaryCode = null; - -} - diff --git a/health-services/project/src/main/java/org/egov/project/web/models/ProjectStaffSearch.java b/health-services/project/src/main/java/org/egov/project/web/models/ProjectStaffSearch.java deleted file mode 100644 index c2279738914..00000000000 --- a/health-services/project/src/main/java/org/egov/project/web/models/ProjectStaffSearch.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.egov.project.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import io.swagger.annotations.ApiModel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.data.query.annotations.Table; -import org.springframework.validation.annotation.Validated; - -import javax.validation.constraints.Size; -import java.util.List; - -/** -* This object defines the mapping of a system staff user to a project for a certain period. -*/ - @ApiModel(description = "This object defines the mapping of a system staff user to a project for a certain period.") -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder - @JsonIgnoreProperties(ignoreUnknown = true) -@Table(name="project_staff") -public class ProjectStaffSearch { - - - @JsonProperty("id") - private List id = null; - - @JsonProperty("tenantId") - @Size(min=2,max=1000) - private String tenantId = null; - - @JsonProperty("staffId") - private List staffId = null; - - @JsonProperty("projectId") - @Size(min=2,max=64) - private String projectId = null; - - @JsonProperty("startDate") - private Long startDate = null; - - @JsonProperty("endDate") - private Long endDate = null; - - -} - diff --git a/health-services/project/src/main/java/org/egov/project/web/models/ProjectStaffSearchRequest.java b/health-services/project/src/main/java/org/egov/project/web/models/ProjectStaffSearchRequest.java deleted file mode 100644 index ce13fa1a73e..00000000000 --- a/health-services/project/src/main/java/org/egov/project/web/models/ProjectStaffSearchRequest.java +++ /dev/null @@ -1,39 +0,0 @@ -package org.egov.project.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.contract.request.RequestInfo; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - -/** -* ProjectStaffSearchRequest -*/ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2022-12-02T17:32:25.406+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class ProjectStaffSearchRequest { - - @JsonProperty("RequestInfo") - @NotNull - @Valid - private RequestInfo requestInfo = null; - - @JsonProperty("ProjectStaff") - @NotNull - @Valid - private ProjectStaffSearch projectStaff = null; - -} - diff --git a/health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundaryRequest.java b/health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundaryRequest.java new file mode 100644 index 00000000000..09921ea9493 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundaryRequest.java @@ -0,0 +1,38 @@ +package org.egov.project.web.models.boundary; + +import java.util.List; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.Boundary; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryRequest + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @Valid + @NotNull + @JsonProperty("Boundary") + @Size(min = 1, max = 300) + private List boundary = null; + +} diff --git a/health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundaryResponse.java b/health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundaryResponse.java new file mode 100644 index 00000000000..993f24fd8ce --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundaryResponse.java @@ -0,0 +1,44 @@ +package org.egov.project.web.models.boundary; + +import java.util.ArrayList; +import java.util.List; +import jakarta.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.Boundary; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryResponse + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Boundary") + @Valid + private List boundary = null; + + + public BoundaryResponse addBoundaryItem(Boundary boundaryItem) { + if (this.boundary == null) { + this.boundary = new ArrayList<>(); + } + this.boundary.add(boundaryItem); + return this; + } + +} diff --git a/health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundarySearchCriteria.java b/health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundarySearchCriteria.java new file mode 100644 index 00000000000..94eaa56c2b3 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/web/models/boundary/BoundarySearchCriteria.java @@ -0,0 +1,37 @@ +package org.egov.project.web.models.boundary; + +import java.util.List; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundarySearchCriteria { + + @NotNull + @Size(min = 1) + @JsonProperty("codes") + private List codes; + + @NotNull + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} diff --git a/health-services/project/src/main/resources/application.properties b/health-services/project/src/main/resources/application.properties index 8364f5f71da..caed5303565 100644 --- a/health-services/project/src/main/resources/application.properties +++ b/health-services/project/src/main/resources/application.properties @@ -68,7 +68,9 @@ kafka.topics.consumer=project-consumer-topic # USER CONFIG egov.user.host=https://dev.digit.org #egov.user.host=http://localhost:8286 +egov.create.user.url=/user/users/_createnovalidate egov.search.user.url=/user/_search +egov.update.user.url=/user/users/_updatenovalidate egov.user.integration.enabled=true # MDMS CONFIG @@ -143,12 +145,10 @@ project.search.max.limit=200 project.management.system.kafka.create.topic=save-project project.management.system.kafka.update.topic=update-project -#location config -egov.location.host=https://works-dev.digit.org -#egov.location.host=http://localhost:8082 -egov.location.context.path=/egov-location/location/v11/ -egov.location.endpoint=/boundarys/_search -egov.location.code.query.param=codes +# BOUNDARY SERVICE +egov.boundary.host=http://localhost:8081 +egov.boundary.search.url=/boundary-service/boundary/_search +egov.boundary.hierarchy=HCM-Moz-Hierarchy project.document.id.verification.required=false diff --git a/health-services/project/src/main/resources/db/migration/main/V20240305113500__project_beneficiary_search_index_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20240305113500__project_beneficiary_search_index_ddl.sql new file mode 100644 index 00000000000..bd18dd5bbb5 --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20240305113500__project_beneficiary_search_index_ddl.sql @@ -0,0 +1 @@ +CREATE INDEX IF NOT EXISTS idx_project_beneficiary_beneficiaryClientReferenceId ON project_beneficiary(beneficiaryClientReferenceId); \ No newline at end of file diff --git a/health-services/project/src/main/resources/db/migration/main/V20240305114021__task_resource_search_index_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20240305114021__task_resource_search_index_ddl.sql new file mode 100644 index 00000000000..a4b5a6caf29 --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20240305114021__task_resource_search_index_ddl.sql @@ -0,0 +1 @@ +CREATE INDEX IF NOT EXISTS idx_task_resource_taskid ON task_resource(taskid); \ No newline at end of file diff --git a/health-services/project/src/test/java/org/egov/project/helper/ProjectBeneficiaryTestBuilder.java b/health-services/project/src/test/java/org/egov/project/helper/ProjectBeneficiaryTestBuilder.java index 13f2b0a38e9..540018a7a95 100644 --- a/health-services/project/src/test/java/org/egov/project/helper/ProjectBeneficiaryTestBuilder.java +++ b/health-services/project/src/test/java/org/egov/project/helper/ProjectBeneficiaryTestBuilder.java @@ -1,16 +1,16 @@ package org.egov.project.helper; import org.egov.common.helper.AuditDetailsTestBuilder; -import org.egov.common.models.project.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.ProjectBeneficiary; public class ProjectBeneficiaryTestBuilder { - private ProjectBeneficiary.ProjectBeneficiaryBuilder builder; + private ProjectBeneficiary.ProjectBeneficiaryBuilder builder; public ProjectBeneficiaryTestBuilder() { - this.builder = ProjectBeneficiary.builder(); + this.builder = (ProjectBeneficiary.ProjectBeneficiaryBuilder) ProjectBeneficiary.builder(); } public static ProjectBeneficiaryTestBuilder builder() { @@ -18,25 +18,27 @@ public static ProjectBeneficiaryTestBuilder builder() { } public ProjectBeneficiary build() { - return this.builder.hasErrors(false).build(); + return this.builder.hasErrors(Boolean.FALSE).build(); } public ProjectBeneficiaryTestBuilder withIdNull() { this.builder.projectId("some-project-id") + .beneficiaryId("beneficiary-id") + .dateOfRegistration(Long.valueOf(1673577580L)) .clientReferenceId("beneficiaryClientReferenceId") .id(null) - .beneficiaryId("beneficiary-id") - .dateOfRegistration(1673577580L) .tenantId("some-tenant-id") - .rowVersion(1); + .rowVersion(Integer.valueOf(1)); return this; } public ProjectBeneficiaryTestBuilder withId() { - withIdNull().builder.id("some-id").beneficiaryId("beneficiary-id") - .dateOfRegistration(1673577580L) + withIdNull().builder + .beneficiaryId("beneficiary-id") + .dateOfRegistration(Long.valueOf(1673577580L)) .projectId("some-project-id") .clientReferenceId("beneficiaryClientReferenceId") + .id("some-id") .tenantId("some-tenant-id"); return this; } @@ -55,9 +57,9 @@ public ProjectBeneficiaryTestBuilder goodProjectBeneficiary() { this.builder.projectId("some-project-id") .beneficiaryId("beneficiary-id") .clientReferenceId("beneficiaryClientReferenceId") - .dateOfRegistration(1673577580L) + .dateOfRegistration(Long.valueOf(1673577580L)) .tenantId("some-tenant-id") - .rowVersion(1) + .rowVersion(Integer.valueOf(1)) .additionalFields(AdditionalFields.builder().build()) .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()); return this; @@ -69,7 +71,7 @@ public ProjectBeneficiaryTestBuilder withAuditDetails() { } public ProjectBeneficiaryTestBuilder withDeleted() { - this.builder.isDeleted(true); + this.builder.isDeleted(Boolean.TRUE); return this; } } diff --git a/health-services/project/src/test/java/org/egov/project/helper/ProjectFacilityTestBuilder.java b/health-services/project/src/test/java/org/egov/project/helper/ProjectFacilityTestBuilder.java index 07380c1f025..b14aa21e008 100644 --- a/health-services/project/src/test/java/org/egov/project/helper/ProjectFacilityTestBuilder.java +++ b/health-services/project/src/test/java/org/egov/project/helper/ProjectFacilityTestBuilder.java @@ -1,16 +1,16 @@ package org.egov.project.helper; import org.egov.common.helper.AuditDetailsTestBuilder; -import org.egov.common.models.project.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.ProjectFacility; public class ProjectFacilityTestBuilder { - private ProjectFacility.ProjectFacilityBuilder builder; + private ProjectFacility.ProjectFacilityBuilder builder; public ProjectFacilityTestBuilder() { - this.builder = ProjectFacility.builder(); + this.builder = (ProjectFacility.ProjectFacilityBuilder) ProjectFacility.builder(); } public static ProjectFacilityTestBuilder builder() { @@ -33,7 +33,9 @@ public ProjectFacilityTestBuilder withIdNull() { } public ProjectFacilityTestBuilder withId() { - withIdNull().builder.id("some-id").facilityId("facility-id"); + withIdNull().builder + .facilityId("facility-id") + .id("some-id"); return this; } diff --git a/health-services/project/src/test/java/org/egov/project/helper/ProjectResourceTestBuilder.java b/health-services/project/src/test/java/org/egov/project/helper/ProjectResourceTestBuilder.java index 36589d22399..00d904d7cfd 100644 --- a/health-services/project/src/test/java/org/egov/project/helper/ProjectResourceTestBuilder.java +++ b/health-services/project/src/test/java/org/egov/project/helper/ProjectResourceTestBuilder.java @@ -7,10 +7,10 @@ public class ProjectResourceTestBuilder { - private final ProjectResource.ProjectResourceBuilder builder; + private final ProjectResource.ProjectResourceBuilder builder; public ProjectResourceTestBuilder() { - this.builder = ProjectResource.builder(); + this.builder = (ProjectResource.ProjectResourceBuilder) ProjectResource.builder(); } public static ProjectResourceTestBuilder builder() { diff --git a/health-services/project/src/test/java/org/egov/project/helper/ProjectStaffTestBuilder.java b/health-services/project/src/test/java/org/egov/project/helper/ProjectStaffTestBuilder.java index 4e7437a0ff3..21d5fe001f9 100644 --- a/health-services/project/src/test/java/org/egov/project/helper/ProjectStaffTestBuilder.java +++ b/health-services/project/src/test/java/org/egov/project/helper/ProjectStaffTestBuilder.java @@ -1,16 +1,16 @@ package org.egov.project.helper; import org.egov.common.helper.AuditDetailsTestBuilder; -import org.egov.common.models.project.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.project.ProjectStaff; public class ProjectStaffTestBuilder { - private ProjectStaff.ProjectStaffBuilder builder; + private ProjectStaff.ProjectStaffBuilder builder; public ProjectStaffTestBuilder() { - this.builder = ProjectStaff.builder(); + this.builder = (ProjectStaff.ProjectStaffBuilder) ProjectStaff.builder(); } public static ProjectStaffTestBuilder builder() { diff --git a/health-services/project/src/test/java/org/egov/project/helper/TaskTestBuilder.java b/health-services/project/src/test/java/org/egov/project/helper/TaskTestBuilder.java index 95a7fb2c3b7..8cec710de7b 100644 --- a/health-services/project/src/test/java/org/egov/project/helper/TaskTestBuilder.java +++ b/health-services/project/src/test/java/org/egov/project/helper/TaskTestBuilder.java @@ -8,10 +8,10 @@ public class TaskTestBuilder { - private final Task.TaskBuilder builder; + private final Task.TaskBuilder builder; public TaskTestBuilder() { - this.builder = Task.builder(); + this.builder = (Task.TaskBuilder) Task.builder(); } public static TaskTestBuilder builder() { @@ -23,19 +23,22 @@ public Task build() { } public TaskTestBuilder withTask() { - this.builder.id("some-id").actualEndDate(100L).actualStartDate(100L) - .hasErrors(Boolean.FALSE) - .tenantId("default") + this.builder.actualEndDate(100L).actualStartDate(100L) .plannedStartDate(100L).plannedEndDate(101L) - .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()) .address(AddressTestBuilder.builder().withAddress().build()) .resources(Arrays.asList(TaskResource.builder().tenantId("default").isDelivered(false) - .quantity(100L).productVariantId("v101").build(), + .quantity(100L).productVariantId("v101").build(), TaskResource.builder().tenantId("default").isDelivered(false) .quantity(100L).productVariantId("v101").build())) - .isDeleted(false).rowVersion(0).projectBeneficiaryId("some-id") .projectId("some-id").createdBy("some-id") - .createdDate(100L).status("status").build(); + .createdDate(100L).status("status") + .isDeleted(false).projectBeneficiaryId("some-id") + .rowVersion(0) + .hasErrors(Boolean.FALSE) + .tenantId("default") + .id("some-id") + .auditDetails(AuditDetailsTestBuilder.builder().withAuditDetails().build()) + .build(); return this; } } diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryEnrichmentServiceUpdateTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryEnrichmentServiceUpdateTest.java index 4d4abb69acf..fe4d3b9e597 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryEnrichmentServiceUpdateTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryEnrichmentServiceUpdateTest.java @@ -1,5 +1,6 @@ package org.egov.project.service; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.BeneficiaryBulkRequest; import org.egov.common.models.project.ProjectBeneficiary; import org.egov.common.service.IdGenService; @@ -66,9 +67,9 @@ void setUp() throws Exception { private void mockFindById() { lenient().when(projectBeneficiaryRepository.findById( eq(projectBeneficiaryIds), - eq(false), - anyString()) - ).thenReturn(request.getProjectBeneficiaries()); + anyString(), + eq(false)) + ).thenReturn(SearchResponse.builder().response(request.getProjectBeneficiaries()).build()); } @Test @@ -98,7 +99,7 @@ void shouldUpdateTheRowVersionInTheResult() throws Exception { void shouldFetchExistingRecordsUsingId() throws Exception { mockFindById(); projectBeneficiaryEnrichmentService.update(request.getProjectBeneficiaries(), request); - verify(projectBeneficiaryRepository, times(1)).findById(anyList(), eq(false), anyString()); + verify(projectBeneficiaryRepository, times(1)).findById(anyList(), anyString(), eq(false)); } @Test diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceSearchTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceSearchTest.java index 6744e51ba7d..89caae1f1d0 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceSearchTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceSearchTest.java @@ -2,11 +2,12 @@ import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.ProjectBeneficiary; import org.egov.project.helper.ProjectBeneficiaryTestBuilder; import org.egov.project.repository.ProjectBeneficiaryRepository; -import org.egov.project.web.models.BeneficiarySearchRequest; -import org.egov.project.web.models.ProjectBeneficiarySearch; +import org.egov.common.models.project.BeneficiarySearchRequest; +import org.egov.common.models.project.ProjectBeneficiarySearch; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -49,9 +50,9 @@ void setUp() throws QueryBuilderException { @DisplayName("should not raise exception if no search results are found") void shouldNotRaiseExceptionIfNoProjectBeneficiaryFound() throws Exception { when(projectBeneficiaryRepository.find(any(ProjectBeneficiarySearch.class), any(Integer.class), - any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(Collections.emptyList()); + any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(SearchResponse.builder().build()); ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() - .id(Collections.singletonList("ID101")).projectId("some-id").build(); + .id(Collections.singletonList("ID101")).projectId(Collections.singletonList("some-id")).build(); BeneficiarySearchRequest beneficiarySearchRequest = BeneficiarySearchRequest.builder() .projectBeneficiary(projectBeneficiarySearch).requestInfo(RequestInfoTestBuilder.builder() .withCompleteRequestInfo().build()).build(); @@ -64,17 +65,17 @@ void shouldNotRaiseExceptionIfNoProjectBeneficiaryFound() throws Exception { @DisplayName("should return project beneficiary if search criteria is matched") void shouldReturnProjectStaffIfSearchCriteriaIsMatched() throws Exception { when(projectBeneficiaryRepository.find(any(ProjectBeneficiarySearch.class), any(Integer.class), - any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(projectBeneficiary); + any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(SearchResponse.builder().response(projectBeneficiary).build()); projectBeneficiary.add(ProjectBeneficiaryTestBuilder.builder().withId().withId().withAuditDetails().build()); ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() - .id(Collections.singletonList("ID101")).projectId("some-projectId").build(); + .id(Collections.singletonList("ID101")).projectId(Collections.singletonList("some-projectId")).build(); BeneficiarySearchRequest beneficiarySearchRequest = BeneficiarySearchRequest.builder() .projectBeneficiary(projectBeneficiarySearch).requestInfo(RequestInfoTestBuilder.builder() .withCompleteRequestInfo().build()).build(); - List projectStaffs = projectBeneficiaryService.search(beneficiarySearchRequest, 10, 0, "default", null, false); + List projectBeneficiaries = projectBeneficiaryService.search(beneficiarySearchRequest, 10, 0, "default", null, false).getResponse(); - assertEquals(1, projectStaffs.size()); + assertEquals(1, projectBeneficiaries.size()); } @Test @@ -86,10 +87,10 @@ void shouldReturnFromCacheIfSearchCriteriaHasIdOnly() throws Exception { BeneficiarySearchRequest projectStaffSearchRequest = BeneficiarySearchRequest.builder() .projectBeneficiary(projectBeneficiarySearch).requestInfo(RequestInfoTestBuilder.builder() .withCompleteRequestInfo().build()).build(); - when(projectBeneficiaryRepository.findById(anyList(), anyBoolean(), anyString())).thenReturn(projectBeneficiary); + when(projectBeneficiaryRepository.findById(anyList(), anyString(), anyBoolean())).thenReturn(SearchResponse.builder().response(projectBeneficiary).build()); List projectBeneficiaries = projectBeneficiaryService.search(projectStaffSearchRequest, - 10, 0, null, null, true); + 10, 0, null, null, true).getResponse(); assertEquals(1, projectBeneficiaries.size()); } diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceUpdateTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceUpdateTest.java index ecd674abd25..805fba5c474 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceUpdateTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectBeneficiaryServiceUpdateTest.java @@ -5,6 +5,7 @@ import digit.models.coremodels.mdms.MdmsCriteriaReq; import org.apache.commons.io.IOUtils; import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdBulkResponse; import org.egov.common.models.household.HouseholdSearchRequest; @@ -158,9 +159,9 @@ private void mockValidateBeneficiarytId() { private void mockFindById() { lenient().when(projectBeneficiaryRepository.findById( eq(projectBeneficiaryIds), - eq(false), - anyString()) - ).thenReturn(request.getProjectBeneficiaries()); + anyString(), + eq(false)) + ).thenReturn(SearchResponse.builder().response(request.getProjectBeneficiaries()).build()); } private void mockMdms(String responseFileName) throws Exception { @@ -208,7 +209,7 @@ void shouldThrowExceptionIfFetchedRecordsCountDoesntMatchTheCountInRequest() thr mockServiceRequestClient(); mockMdms(HOUSEHOLD_RESPONSE_FILE_NAME); mockProjectFindIds(); - when(projectBeneficiaryRepository.findById(anyList(), eq(false), anyString())).thenReturn(Collections.emptyList()); + when(projectBeneficiaryRepository.findById(anyList(), anyString(), eq(false))).thenReturn(SearchResponse.builder().build()); assertThrows(CustomException.class, () -> projectBeneficiaryService.update(request, false)); } diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectFacilityServiceSearchTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectFacilityServiceSearchTest.java index 067d9e58f31..6eed8465ca5 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectFacilityServiceSearchTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectFacilityServiceSearchTest.java @@ -4,8 +4,8 @@ import org.egov.common.models.project.ProjectFacility; import org.egov.project.helper.ProjectFacilityTestBuilder; import org.egov.project.repository.ProjectFacilityRepository; -import org.egov.project.web.models.ProjectFacilitySearch; -import org.egov.project.web.models.ProjectFacilitySearchRequest; +import org.egov.common.models.project.ProjectFacilitySearch; +import org.egov.common.models.project.ProjectFacilitySearchRequest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectStaffServiceSearchTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectStaffServiceSearchTest.java index 522b79708d3..36aa7100f8d 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectStaffServiceSearchTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectStaffServiceSearchTest.java @@ -4,8 +4,8 @@ import org.egov.common.models.project.ProjectStaff; import org.egov.project.helper.ProjectStaffTestBuilder; import org.egov.project.repository.ProjectStaffRepository; -import org.egov.project.web.models.ProjectStaffSearch; -import org.egov.project.web.models.ProjectStaffSearchRequest; +import org.egov.common.models.project.ProjectStaffSearch; +import org.egov.common.models.project.ProjectStaffSearchRequest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -78,7 +78,7 @@ void shouldReturnProjectStaffIfSearchCriteriaIsMatched() throws Exception { when(projectStaffRepository.find(any(ProjectStaffSearch.class), any(Integer.class), any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(projectStaffs); projectStaffs.add(ProjectStaffTestBuilder.builder().withId().withId().withAuditDetails().build()); - ProjectStaffSearch projectStaffSearch = ProjectStaffSearch.builder().id(Collections.singletonList("ID101")).projectId("some-projectId").build(); + ProjectStaffSearch projectStaffSearch = ProjectStaffSearch.builder().id(Collections.singletonList("ID101")).projectId(Collections.singletonList("some-projectId")).build(); ProjectStaffSearchRequest projectStaffSearchRequest = ProjectStaffSearchRequest.builder() .projectStaff(projectStaffSearch).requestInfo(RequestInfoTestBuilder.builder() .withCompleteRequestInfo().build()).build(); diff --git a/health-services/project/src/test/java/org/egov/project/service/ProjectTaskServiceSearchTest.java b/health-services/project/src/test/java/org/egov/project/service/ProjectTaskServiceSearchTest.java index b81d80be1f3..418f9321695 100644 --- a/health-services/project/src/test/java/org/egov/project/service/ProjectTaskServiceSearchTest.java +++ b/health-services/project/src/test/java/org/egov/project/service/ProjectTaskServiceSearchTest.java @@ -2,6 +2,7 @@ import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskSearch; import org.egov.common.models.project.TaskSearchRequest; @@ -55,7 +56,7 @@ void shouldOnlySearchByIdIfOnlyIdIsPresent() { .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .task(TaskSearch.builder().id(Collections.singletonList("some-id")).build()).build(); when(projectTaskRepository.findById(anyList(), eq("id"), anyBoolean())) - .thenReturn(Collections.emptyList()); + .thenReturn(SearchResponse.builder().build()); projectTaskService.search(taskSearchRequest.getTask(), 10, 0, "default", null, false); @@ -71,7 +72,7 @@ void shouldOnlySearchByClientReferenceIdIfOnlyClientReferenceIdIsPresent() { .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .task(TaskSearch.builder().clientReferenceId(Collections.singletonList("some-id")).build()).build(); when(projectTaskRepository.findById(anyList(), eq("clientReferenceId"), anyBoolean())) - .thenReturn(Collections.emptyList()); + .thenReturn(SearchResponse.builder().build()); projectTaskService.search(taskSearchRequest.getTask(), 10, 0, "default", null, false); @@ -87,7 +88,7 @@ void shouldNotCallFindByIfIfMoreParametersAreAvailable() throws QueryBuilderExce .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .task(TaskSearch.builder().id(Collections.singletonList("some-id")).clientReferenceId(Collections.singletonList("some-id")).build()).build(); when(projectTaskRepository.find(any(TaskSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(SearchResponse.builder().build()); projectTaskService.search(taskSearchRequest.getTask(), 10, 0, "default", 0L, false); @@ -103,7 +104,7 @@ void shouldCallFindIfMoreParametersAreAvailable() throws QueryBuilderException { .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .task(TaskSearch.builder().id(Collections.singletonList("some-id")).clientReferenceId(Collections.singletonList("some-id")).build()).build(); when(projectTaskRepository.find(any(TaskSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(SearchResponse.builder().build()); projectTaskService.search(taskSearchRequest.getTask(), 10, 0, "default", 0L, false); @@ -117,7 +118,7 @@ void shouldCallFindIfMoreParametersAreAvailable() throws QueryBuilderException { @DisplayName("should not raise exception if no search results are found") void shouldNotRaiseExceptionIfNoProjectTaskFound() throws Exception { when(projectTaskRepository.find(any(TaskSearch.class), any(Integer.class), - any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(Collections.emptyList()); + any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(SearchResponse.builder().build()); TaskSearchRequest taskSearchRequest = TaskSearchRequest.builder() .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .task(TaskSearch.builder().id(Collections.singletonList("someid")).clientReferenceId(Collections.singletonList("some-id")).build()).build(); @@ -130,7 +131,7 @@ void shouldNotRaiseExceptionIfNoProjectTaskFound() throws Exception { @Test @DisplayName("should not raise exception if no search results are found for search by id") void shouldNotRaiseExceptionIfNoProjectTaskFoundForSearchById() throws Exception { - when(projectTaskRepository.findById(anyList(), anyString(), anyBoolean())).thenReturn(Collections.emptyList()); + when(projectTaskRepository.findById(anyList(), anyString(), anyBoolean())).thenReturn(SearchResponse.builder().build()); TaskSearchRequest taskSearchRequest = TaskSearchRequest.builder() .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .task(TaskSearch.builder().id(Collections.singletonList("some-id")).build()).build(); @@ -144,13 +145,13 @@ void shouldNotRaiseExceptionIfNoProjectTaskFoundForSearchById() throws Exception void shouldReturnProjectStaffIfSearchCriteriaIsMatched() throws Exception { projectTasks.add(TaskTestBuilder.builder().withTask().build()); when(projectTaskRepository.find(any(TaskSearch.class), any(Integer.class), - any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(projectTasks); + any(Integer.class), any(String.class), eq(null), any(Boolean.class))).thenReturn(SearchResponse.builder().response(projectTasks).build()); TaskSearchRequest taskSearchRequest = TaskSearchRequest.builder() .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) - .task(TaskSearch.builder().id(Collections.singletonList("some-id")).projectId("some-id").build()).build(); + .task(TaskSearch.builder().id(Collections.singletonList("some-id")).projectId(Collections.singletonList("some-id")).build()).build(); List projectTasks = projectTaskService.search(taskSearchRequest.getTask(), 10, 0, - "default", null, false); + "default", null, false).getResponse(); assertEquals(1, projectTasks.size()); } @@ -159,13 +160,13 @@ void shouldReturnProjectStaffIfSearchCriteriaIsMatched() throws Exception { @DisplayName("should return from find by id if search criteria has id only") void shouldReturnFromFindByIdIfSearchCriteriaHasIdOnly() throws Exception { projectTasks.add(TaskTestBuilder.builder().withTask().build()); - when(projectTaskRepository.findById(anyList(), anyString(), anyBoolean())).thenReturn(projectTasks); + when(projectTaskRepository.findById(anyList(), anyString(), anyBoolean())).thenReturn(SearchResponse.builder().response(projectTasks).build()); TaskSearchRequest taskSearchRequest = TaskSearchRequest.builder() .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .task(TaskSearch.builder().id(Collections.singletonList("some-id")).build()).build(); List projectTasks = projectTaskService.search(taskSearchRequest.getTask(), 10, 0, - "default", null, false); + "default", null, false).getResponse(); assertEquals(1, projectTasks.size()); } diff --git a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectBeneficiaryApiControllerTest.java b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectBeneficiaryApiControllerTest.java index d7705cbd0e8..264d9336590 100644 --- a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectBeneficiaryApiControllerTest.java +++ b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectBeneficiaryApiControllerTest.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.BeneficiaryBulkResponse; import org.egov.common.models.project.BeneficiaryRequest; import org.egov.common.models.project.BeneficiaryResponse; @@ -16,8 +17,8 @@ import org.egov.project.service.ProjectService; import org.egov.project.service.ProjectStaffService; import org.egov.project.service.ProjectTaskService; -import org.egov.project.web.models.BeneficiarySearchRequest; -import org.egov.project.web.models.ProjectBeneficiarySearch; +import org.egov.common.models.project.BeneficiarySearchRequest; +import org.egov.common.models.project.ProjectBeneficiarySearch; import org.egov.tracer.model.CustomException; import org.egov.tracer.model.ErrorRes; import org.junit.jupiter.api.DisplayName; @@ -216,7 +217,7 @@ void shouldSend400BadRequestInCaseOfIncorrectApiOperationForUpdate() throws Exce void shouldAcceptSearchRequestAndReturnProjectStaff() throws Exception { BeneficiarySearchRequest beneficiarySearchRequest = BeneficiarySearchRequest.builder().projectBeneficiary( - ProjectBeneficiarySearch.builder().projectId("12").build() + ProjectBeneficiarySearch.builder().projectId(Arrays.asList("12","11")).build() ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); when(projectBeneficiaryService.search(any(BeneficiarySearchRequest.class), @@ -224,7 +225,7 @@ void shouldAcceptSearchRequestAndReturnProjectStaff() throws Exception { any(Integer.class), any(String.class), any(Long.class), - any(Boolean.class))).thenReturn(Arrays.asList(ProjectBeneficiaryTestBuilder.builder().withId().withAuditDetails().build())); + any(Boolean.class))).thenReturn(SearchResponse.builder().response(Arrays.asList(ProjectBeneficiaryTestBuilder.builder().withId().withAuditDetails().build())).build()); final MvcResult result = mockMvc.perform(post( "/beneficiary/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") @@ -245,7 +246,7 @@ void shouldAcceptSearchRequestAndReturnProjectStaff() throws Exception { void shouldThrowExceptionIfNoResultFound() throws Exception { BeneficiarySearchRequest beneficiarySearchRequest = BeneficiarySearchRequest.builder().projectBeneficiary( - ProjectBeneficiarySearch.builder().projectId("12").build() + ProjectBeneficiarySearch.builder().projectId(Arrays.asList("12","11")).build() ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); when(projectBeneficiaryService.search(any(BeneficiarySearchRequest.class), diff --git a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectFacilityApiControllerTest.java b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectFacilityApiControllerTest.java index 156b3a53a2a..e6a97cf70c8 100644 --- a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectFacilityApiControllerTest.java +++ b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectFacilityApiControllerTest.java @@ -18,8 +18,8 @@ import org.egov.project.service.ProjectService; import org.egov.project.service.ProjectStaffService; import org.egov.project.service.ProjectTaskService; -import org.egov.project.web.models.ProjectFacilitySearch; -import org.egov.project.web.models.ProjectFacilitySearchRequest; +import org.egov.common.models.project.ProjectFacilitySearch; +import org.egov.common.models.project.ProjectFacilitySearchRequest; import org.egov.tracer.model.ErrorRes; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; diff --git a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectStaffApiControllerTest.java b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectStaffApiControllerTest.java index eb7e38fed50..1e1b5409485 100644 --- a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectStaffApiControllerTest.java +++ b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectStaffApiControllerTest.java @@ -16,8 +16,8 @@ import org.egov.project.service.ProjectService; import org.egov.project.service.ProjectStaffService; import org.egov.project.service.ProjectTaskService; -import org.egov.project.web.models.ProjectStaffSearch; -import org.egov.project.web.models.ProjectStaffSearchRequest; +import org.egov.common.models.project.ProjectStaffSearch; +import org.egov.common.models.project.ProjectStaffSearchRequest; import org.egov.tracer.model.ErrorRes; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -168,7 +168,7 @@ void shouldSendErrorResWithErrorDetailsWith400BadRequestForUpdate() throws Excep void shouldAcceptSearchRequestAndReturnProjectStaff() throws Exception { ProjectStaffSearchRequest projectStaffSearchRequest = ProjectStaffSearchRequest.builder().projectStaff( - ProjectStaffSearch.builder().projectId("12").build() + ProjectStaffSearch.builder().projectId(Arrays.asList("12","11")).build() ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); when(projectStaffService.search(any(ProjectStaffSearchRequest.class), any(Integer.class), diff --git a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectTaskApiControllerTest.java b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectTaskApiControllerTest.java index 9da98813641..4288828d158 100644 --- a/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectTaskApiControllerTest.java +++ b/health-services/project/src/test/java/org/egov/project/web/controllers/ProjectTaskApiControllerTest.java @@ -2,6 +2,8 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskRequest; import org.egov.common.models.project.TaskSearch; import org.egov.common.models.project.TaskSearchRequest; @@ -23,8 +25,6 @@ import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; -import java.util.Collections; - import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -81,7 +81,7 @@ void shouldPassSearchRequestIfQueryParamsArePresent() throws Exception { .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .task(TaskSearch.builder().build()).build(); when(projectTaskService.search(any(TaskSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), any(), any())).thenReturn(SearchResponse.builder().build()); mockMvc.perform(post("/task/v1/_search?limit=10&offset=0&tenantId=default").contentType(MediaType .APPLICATION_JSON).content(objectMapper.writeValueAsString(taskSearchRequest))) @@ -95,7 +95,7 @@ void shouldFailSearchRequestIfQueryParamsAreMissing() throws Exception { .requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()) .task(TaskSearch.builder().build()).build(); when(projectTaskService.search(any(TaskSearch.class), anyInt(), - anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(Collections.emptyList()); + anyInt(), anyString(), anyLong(), anyBoolean())).thenReturn(SearchResponse.builder().build()); mockMvc.perform(post("/task/v1/_search?limit=10&offset=0").contentType(MediaType .APPLICATION_JSON).content(objectMapper.writeValueAsString(taskSearchRequest))) diff --git a/health-services/referralmanagement/CHANGELOG.md b/health-services/referralmanagement/CHANGELOG.md index 55b1ba23b50..d0b1da750c3 100644 --- a/health-services/referralmanagement/CHANGELOG.md +++ b/health-services/referralmanagement/CHANGELOG.md @@ -1,6 +1,13 @@ # Changelog All notable changes to this module will be documented in this file. +## 1.0.2 - 2024-05-29 +- Upgraded to Core 2.9LTS +- Client reference ID validation added +- Upgraded to health models 1.0.20 and health common 1.0.16 +- Boundary v2 Integration +- MDMS v2 integration + ## 1.0.1 - 2024-02-28 - Added functionality for referrals handled by health facilities, referred to as "hfreferral". diff --git a/health-services/referralmanagement/pom.xml b/health-services/referralmanagement/pom.xml index a13ab7a0182..d4aa379affc 100644 --- a/health-services/referralmanagement/pom.xml +++ b/health-services/referralmanagement/pom.xml @@ -6,16 +6,17 @@ referralmanagement jar referralmanagement - 1.0.1 + 1.0.2 - 1.8 + 17 ${java.version} ${java.version} + 1.18.22 org.springframework.boot spring-boot-starter-parent - 2.2.6.RELEASE + 3.2.2 src/main/java @@ -45,12 +46,12 @@ org.egov.common health-services-common - 1.0.12-SNAPSHOT + 1.0.16-SNAPSHOT org.egov.common health-services-models - 1.0.14-SNAPSHOT + 1.0.20-SNAPSHOT compile @@ -67,51 +68,46 @@ redis.clients jedis - - org.flywaydb - flyway-core - org.springframework.boot spring-boot-devtools + + org.flywaydb + flyway-core + 9.22.3 + org.postgresql postgresql - 42.2.2.jre7 + 42.7.1 + + + org.egov.services + tracer + 2.9.0-SNAPSHOT org.springframework.boot spring-boot-starter-test test - io.swagger swagger-core 1.5.18 - - - org.egov.services - digit-models - 1.0.0-SNAPSHOT - org.projectlombok lombok + ${lombok.version} true com.fasterxml.jackson.datatype jackson-datatype-jsr310 - - - javax.validation - validation-api - diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/MainConfiguration.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/MainConfiguration.java index 86310611791..dfd9401a2d7 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/MainConfiguration.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/MainConfiguration.java @@ -22,7 +22,7 @@ import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import java.util.TimeZone; @Import({TracerConfiguration.class}) @@ -79,8 +79,7 @@ public RedisConnectionFactory redisConnectionFactory() { @Bean public RedisTemplate redisTemplate(@Qualifier("redisObjectMapper") ObjectMapper redisObjectMapper, RedisConnectionFactory redisConnectionFactory) { - Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(Object.class); - serializer.setObjectMapper(redisObjectMapper); + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(redisObjectMapper, Object.class); RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); redisTemplate.setKeySerializer(new StringRedisSerializer()); diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java index f3b05004718..18e2967741a 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java @@ -91,7 +91,7 @@ public List find(HFReferralSearch searchObject, Integer limit, Integ } // Add ORDER BY, LIMIT, and OFFSET clauses to the query. - query = query + "ORDER BY hf.id ASC LIMIT :limit OFFSET :offset"; + query = query + "ORDER BY hf.createdtime DESC LIMIT :limit OFFSET :offset"; paramsMap.put("tenantId", tenantId); paramsMap.put("isDeleted", includeDeleted); paramsMap.put("lastModifiedTime", lastChangedSince); diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java index 32dd98e64b2..ade10b1392e 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java @@ -1,7 +1,5 @@ package org.egov.referralmanagement.repository; -import static org.egov.common.utils.CommonUtils.getIdMethod; - import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; @@ -9,10 +7,12 @@ import java.util.Optional; import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; import org.egov.common.data.query.builder.GenericQueryBuilder; import org.egov.common.data.query.builder.QueryFieldChecker; import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.referralmanagement.Referral; import org.egov.common.models.referralmanagement.ReferralSearch; import org.egov.common.producer.Producer; @@ -23,7 +23,8 @@ import org.springframework.stereotype.Repository; import org.springframework.util.ReflectionUtils; -import lombok.extern.slf4j.Slf4j; +import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; +import static org.egov.common.utils.CommonUtils.getIdMethod; @Repository @Slf4j @@ -38,10 +39,10 @@ protected ReferralRepository(Producer producer, NamedParameterJdbcTemplate named super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, rowMapper, Optional.of("referral")); } - public List find(ReferralSearch searchObject, Integer limit, Integer offset, String tenantId, + public SearchResponse find(ReferralSearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) { - String query = "SELECT r.id, r.clientreferenceid, r.tenantid, r.projectbeneficiaryid, r.projectbeneficiaryclientreferenceid, r.referrerid, r.recipientid, r.recipienttype, r.reasons, r.sideeffectid, r.sideeffectclientreferenceid, r.createdby, r.createdtime, r.lastmodifiedby, r.lastmodifiedtime, r.clientcreatedby, r.clientcreatedtime, r.clientlastmodifiedby, r.clientlastmodifiedtime, r.rowversion, r.isdeleted, r.additionaldetails, se.id sId, se.clientreferenceid sClientReferenceId, se.tenantid sTenantId, se.taskid sTaskId, se.taskclientreferenceid sTaskClientReferenceId, se.projectbeneficiaryId sProjectBeneficiaryId, se.projectBeneficiaryClientReferenceId sProjectBeneficiaryClientReferenceId, se.symptoms sSymptoms, se.additionalDetails sAdditionalDetails, se.createdby sCreatedBy, se.createdtime sCreatedTime, se.lastmodifiedby sLastModifiedBy, se.lastmodifiedtime sLastModifiedTime, se.clientCreatedBy sClientCreatedBy, se.clientcreatedtime sClientCreatedTime, se.clientlastmodifiedby sClientLastModifiedBy, se.clientlastmodifiedtime sClientLastModifiedTime, se.rowversion sRowVersion, se.isdeleted sIsDeleted FROM referral r left join side_effect se on r.sideEffectClientReferenceid = se.clientreferenceid"; + String query = "SELECT r.id, r.clientreferenceid, r.tenantid, r.projectbeneficiaryid, r.projectbeneficiaryclientreferenceid, r.referrerid, r.recipientid, r.recipienttype, r.reasons, r.sideeffectid, r.referralCode, r.sideeffectclientreferenceid, r.createdby, r.createdtime, r.lastmodifiedby, r.lastmodifiedtime, r.clientcreatedby, r.clientcreatedtime, r.clientlastmodifiedby, r.clientlastmodifiedtime, r.rowversion, r.isdeleted, r.additionaldetails, se.id sId, se.clientreferenceid sClientReferenceId, se.tenantid sTenantId, se.taskid sTaskId, se.taskclientreferenceid sTaskClientReferenceId, se.projectbeneficiaryId sProjectBeneficiaryId, se.projectBeneficiaryClientReferenceId sProjectBeneficiaryClientReferenceId, se.symptoms sSymptoms, se.additionalDetails sAdditionalDetails, se.createdby sCreatedBy, se.createdtime sCreatedTime, se.lastmodifiedby sLastModifiedBy, se.lastmodifiedtime sLastModifiedTime, se.clientCreatedBy sClientCreatedBy, se.clientcreatedtime sClientCreatedTime, se.clientlastmodifiedby sClientLastModifiedBy, se.clientlastmodifiedtime sClientLastModifiedTime, se.rowversion sRowVersion, se.isdeleted sIsDeleted FROM referral r left join side_effect se on r.sideEffectClientReferenceid = se.clientreferenceid"; Map paramsMap = new HashMap<>(); List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); @@ -59,17 +60,20 @@ public List find(ReferralSearch searchObject, Integer limit, Integer o if (lastChangedSince != null) { query = query + "and r.lastModifiedTime>=:lastModifiedTime "; } - query = query + "ORDER BY r.id ASC LIMIT :limit OFFSET :offset"; paramsMap.put("tenantId", tenantId); paramsMap.put("isDeleted", includeDeleted); paramsMap.put("lastModifiedTime", lastChangedSince); + + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + + query = query + "ORDER BY r.createdtime ASC LIMIT :limit OFFSET :offset"; paramsMap.put("limit", limit); paramsMap.put("offset", offset); List referralList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); - return referralList; + return SearchResponse.builder().response(referralList).totalCount(totalCount).build(); } - public List findById(List ids, Boolean includeDeleted, String columnName) { + public SearchResponse findById(List ids, String columnName, Boolean includeDeleted) { List objFound = findInCache(ids).stream() .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) .collect(Collectors.toList()); @@ -79,11 +83,11 @@ public List findById(List ids, Boolean includeDeleted, String .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) .collect(Collectors.toList())); if (ids.isEmpty()) { - return objFound; + return SearchResponse.builder().response(objFound).build(); } } - String query = String.format("SELECT r.id, r.clientreferenceid, r.tenantid, r.projectbeneficiaryid, r.projectbeneficiaryclientreferenceid, r.referrerid, r.recipientid, r.recipienttype, r.reasons, r.sideeffectid, r.sideeffectclientreferenceid, r.createdby, r.createdtime, r.lastmodifiedby, r.lastmodifiedtime, r.clientcreatedby, r.clientcreatedtime, r.clientlastmodifiedby, r.clientlastmodifiedtime, r.rowversion, r.isdeleted, r.additionaldetails, se.id sId, se.clientreferenceid sClientReferenceId, se.tenantid sTenantId, se.taskid sTaskId, se.taskclientreferenceid sTaskClientReferenceId, se.projectbeneficiaryId sProjectBeneficiaryId, se.projectBeneficiaryClientReferenceId sProjectBeneficiaryClientReferenceId, se.symptoms sSymptoms, se.additionalDetails sAdditionalDetails, se.createdby sCreatedBy, se.createdtime sCreatedTime, se.lastmodifiedby sLastModifiedBy, se.lastmodifiedtime sLastModifiedTime, se.clientCreatedBy sClientCreatedBy, se.clientcreatedtime sClientCreatedTime, se.clientlastmodifiedby sClientLastModifiedBy, se.clientlastmodifiedtime sClientLastModifiedTime, se.rowversion sRowVersion, se.isdeleted sIsDeleted FROM referral r left join side_effect se on r.sideEffectClientReferenceid = se.clientreferenceid WHERE r.%s IN (:ids) ", columnName); + String query = String.format("SELECT r.id, r.clientreferenceid, r.tenantid, r.projectbeneficiaryid, r.projectbeneficiaryclientreferenceid, r.referrerid, r.recipientid, r.recipienttype, r.reasons, r.sideeffectid, r.referralCode, r.sideeffectclientreferenceid, r.createdby, r.createdtime, r.lastmodifiedby, r.lastmodifiedtime, r.clientcreatedby, r.clientcreatedtime, r.clientlastmodifiedby, r.clientlastmodifiedtime, r.rowversion, r.isdeleted, r.additionaldetails, se.id sId, se.clientreferenceid sClientReferenceId, se.tenantid sTenantId, se.taskid sTaskId, se.taskclientreferenceid sTaskClientReferenceId, se.projectbeneficiaryId sProjectBeneficiaryId, se.projectBeneficiaryClientReferenceId sProjectBeneficiaryClientReferenceId, se.symptoms sSymptoms, se.additionalDetails sAdditionalDetails, se.createdby sCreatedBy, se.createdtime sCreatedTime, se.lastmodifiedby sLastModifiedBy, se.lastmodifiedtime sLastModifiedTime, se.clientCreatedBy sClientCreatedBy, se.clientcreatedtime sClientCreatedTime, se.clientlastmodifiedby sClientLastModifiedBy, se.clientlastmodifiedtime sClientLastModifiedTime, se.rowversion sRowVersion, se.isdeleted sIsDeleted FROM referral r left join side_effect se on r.sideEffectClientReferenceid = se.clientreferenceid WHERE r.%s IN (:ids) ", columnName); if (includeDeleted == null || !includeDeleted) { query += " AND r.isDeleted = false "; } @@ -93,6 +97,6 @@ public List findById(List ids, Boolean includeDeleted, String objFound.addAll(referralList); putInCache(objFound); - return objFound; + return SearchResponse.builder().response(objFound).build(); } } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java index e72a3778817..91ea1628d32 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java @@ -1,5 +1,6 @@ package org.egov.referralmanagement.repository; +import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; import static org.egov.common.utils.CommonUtils.getIdList; import static org.egov.common.utils.CommonUtils.getIdMethod; @@ -16,6 +17,7 @@ import org.egov.common.data.query.builder.QueryFieldChecker; import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.project.Task; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearch; @@ -67,7 +69,7 @@ public Map> fetchSideEffects(List taskList) { return idToObjMap; } - public List find(SideEffectSearch searchObject, Integer limit, Integer offset, String tenantId, + public SearchResponse find(SideEffectSearch searchObject, Integer limit, Integer offset, String tenantId, Long lastChangedSince, Boolean includeDeleted) { String query = "SELECT * FROM side_effect ae LEFT JOIN project_task pt ON ae.taskId = pt.id "; @@ -86,14 +88,18 @@ public List find(SideEffectSearch searchObject, Integer limit, Integ if (lastChangedSince != null) { query = query + "and as.lastModifiedTime>=:lastModifiedTime "; } - query = query + "ORDER BY ae.id ASC LIMIT :limit OFFSET :offset"; paramsMap.put("tenantId", tenantId); paramsMap.put("isDeleted", includeDeleted); paramsMap.put("lastModifiedTime", lastChangedSince); + + Long totalCount = constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + + query = query + "ORDER BY ae.createdtime ASC LIMIT :limit OFFSET :offset"; paramsMap.put("limit", limit); paramsMap.put("offset", offset); + List sideEffectList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); - return sideEffectList; + return SearchResponse.builder().response(sideEffectList).totalCount(totalCount).build(); } public List findById(List ids, String columnName, Boolean includeDeleted) { diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HFReferralRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HFReferralRowMapper.java index 3f9b5084872..5456cd9179c 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HFReferralRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/HFReferralRowMapper.java @@ -6,7 +6,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.project.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.referralmanagement.hfreferral.HFReferral; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.RowMapper; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java index 244c91126d2..181aa1b6a55 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/ReferralRowMapper.java @@ -1,75 +1,97 @@ package org.egov.referralmanagement.repository.rowmapper; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.project.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.referralmanagement.Referral; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; - @Component public class ReferralRowMapper implements RowMapper { @Autowired ObjectMapper objectMapper; + /** + * Maps a row of the ResultSet to a Referral object. + * + * @param resultSet the ResultSet containing the data from the database + * @param i the current row number + * @return a Referral object mapped from the ResultSet + * @throws SQLException if an SQL exception occurs + */ @Override public Referral mapRow(ResultSet resultSet, int i) throws SQLException { try { + // Initialize sideEffect to null SideEffect sideEffect = null; + // Check if side effect client reference ID is not null String sideEffectClientReferenceId = resultSet.getString("sideEffectClientReferenceId"); - if(sideEffectClientReferenceId != null) { + if (sideEffectClientReferenceId != null) { + // Map side effect AuditDetails AuditDetails sideEffectAuditDetails = AuditDetails.builder() .createdBy(resultSet.getString("sCreatedBy")) .createdTime(resultSet.getLong("sCreatedTime")) .lastModifiedBy(resultSet.getString("sLastModifiedBy")) .lastModifiedTime(resultSet.getLong("sLastModifiedTime")) .build(); + // Map side effect client AuditDetails AuditDetails sideEffectClientAuditDetails = AuditDetails.builder() .createdBy(resultSet.getString("sClientCreatedBy")) .createdTime(resultSet.getLong("sClientCreatedTime")) .lastModifiedBy(resultSet.getString("sClientLastModifiedBy")) .lastModifiedTime(resultSet.getLong("sClientLastModifiedTime")) .build(); + // Build SideEffect object sideEffect = SideEffect.builder() .id(resultSet.getString("sId")) + .additionalFields(resultSet.getString("sAdditionalDetails") == null ? null : objectMapper + .readValue(resultSet.getString("sAdditionalDetails"), AdditionalFields.class)) + .rowVersion(resultSet.getInt("sRowVersion")) + .isDeleted(resultSet.getBoolean("sIsDeleted")) + .auditDetails(sideEffectAuditDetails) + .tenantId(resultSet.getString("sTenantId")) + .clientAuditDetails(sideEffectClientAuditDetails) .clientReferenceId(resultSet.getString("sClientReferenceId")) .taskId(resultSet.getString("sTaskId")) .taskClientReferenceId(resultSet.getString("sTaskClientReferenceId")) .projectBeneficiaryId(resultSet.getString("sProjectBeneficiaryId")) .projectBeneficiaryClientReferenceId(resultSet.getString("sProjectBeneficiaryClientReferenceId")) - .tenantId(resultSet.getString("sTenantId")) .symptoms(resultSet.getString("sSymptoms") == null ? null : objectMapper .readValue(resultSet.getString("sSymptoms"), ArrayList.class)) - .additionalFields(resultSet.getString("sAdditionalDetails") == null ? null : objectMapper - .readValue(resultSet.getString("sAdditionalDetails"), AdditionalFields.class)) - .rowVersion(resultSet.getInt("sRowVersion")) - .isDeleted(resultSet.getBoolean("sIsDeleted")) - .auditDetails(sideEffectAuditDetails) - .clientAuditDetails(sideEffectClientAuditDetails) .build(); } + // Map main Referral AuditDetails AuditDetails auditDetails = AuditDetails.builder() .createdBy(resultSet.getString("createdBy")) .createdTime(resultSet.getLong("createdTime")) .lastModifiedBy(resultSet.getString("lastModifiedBy")) .lastModifiedTime(resultSet.getLong("lastModifiedTime")) .build(); - AuditDetails clientAuditDetails= AuditDetails.builder() + // Map main Referral client AuditDetails + AuditDetails clientAuditDetails = AuditDetails.builder() .createdBy(resultSet.getString("clientCreatedBy")) .createdTime(resultSet.getLong("clientCreatedTime")) .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) .build(); + // Build Referral object return Referral.builder() .id(resultSet.getString("id")) + .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper + .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) + .rowVersion(resultSet.getInt("rowversion")) + .isDeleted(resultSet.getBoolean("isdeleted")) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) .clientReferenceId(resultSet.getString("clientreferenceid")) .projectBeneficiaryId(resultSet.getString("projectBeneficiaryId")) .projectBeneficiaryClientReferenceId(resultSet.getString("projectbeneficiaryclientreferenceid")) @@ -77,16 +99,12 @@ public Referral mapRow(ResultSet resultSet, int i) throws SQLException { .recipientId(resultSet.getString("recipientId")) .recipientType(resultSet.getString("recipientType")) .sideEffect(sideEffect) + .referralCode(resultSet.getString("referralCode")) .tenantId(resultSet.getString("tenantid")) .reasons(resultSet.getString("reasons") == null ? null : objectMapper.readValue(resultSet.getString("reasons"), ArrayList.class)) - .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper - .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) - .rowVersion(resultSet.getInt("rowversion")) - .isDeleted(resultSet.getBoolean("isdeleted")) - .auditDetails(auditDetails) - .clientAuditDetails(clientAuditDetails) .build(); } catch (JsonProcessingException e) { + // Wrap JsonProcessingException into RuntimeException throw new RuntimeException(e); } } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java index 3fdae4349ea..3832d8bd7e3 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/rowmapper/SideEffectRowMapper.java @@ -1,56 +1,72 @@ package org.egov.referralmanagement.repository.rowmapper; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.project.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; - @Component public class SideEffectRowMapper implements RowMapper { @Autowired ObjectMapper objectMapper; + /** + * Maps a row of the ResultSet to a SideEffect object. + * + * @param resultSet the ResultSet containing the data from the database + * @param i the current row number + * @return a SideEffect object mapped from the ResultSet + * @throws SQLException if an SQL exception occurs + */ @Override public SideEffect mapRow(ResultSet resultSet, int i) throws SQLException { try { + // Mapping AuditDetails AuditDetails auditDetails = AuditDetails.builder() .createdBy(resultSet.getString("createdBy")) .createdTime(resultSet.getLong("createdTime")) .lastModifiedBy(resultSet.getString("lastModifiedBy")) .lastModifiedTime(resultSet.getLong("lastModifiedTime")) .build(); + + // Mapping client AuditDetails AuditDetails clientAuditDetails = AuditDetails.builder() .createdBy(resultSet.getString("clientCreatedBy")) .createdTime(resultSet.getLong("clientCreatedTime")) .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) .build(); + + // Building SideEffect object return SideEffect.builder() .id(resultSet.getString("id")) + .rowVersion(resultSet.getInt("rowversion")) + .isDeleted(resultSet.getBoolean("isdeleted")) + .auditDetails(auditDetails) + .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper + .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) + .clientAuditDetails(clientAuditDetails) .clientReferenceId(resultSet.getString("clientreferenceid")) .taskId(resultSet.getString("taskId")) .taskClientReferenceId(resultSet.getString("taskClientreferenceid")) .projectBeneficiaryId(resultSet.getString("projectBeneficiaryId")) .projectBeneficiaryClientReferenceId(resultSet.getString("projectBeneficiaryClientReferenceId")) .tenantId(resultSet.getString("tenantid")) - .symptoms(resultSet.getString("symptoms") == null ? null : objectMapper.readValue(resultSet.getString("symptoms"), ArrayList.class)) - .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper - .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) - .rowVersion(resultSet.getInt("rowversion")) - .isDeleted(resultSet.getBoolean("isdeleted")) - .auditDetails(auditDetails) - .clientAuditDetails(clientAuditDetails) + // Deserializing JSON array stored in the 'symptoms' column to ArrayList + .symptoms(resultSet.getString("symptoms") == null ? null : + objectMapper.readValue(resultSet.getString("symptoms"), ArrayList.class)) .build(); } catch (JsonProcessingException e) { + // Wrapping JsonProcessingException into SQLException throw new SQLException(e); } } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java index 23c5e2328a9..f3ca4fa075d 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java @@ -47,202 +47,197 @@ @Service public class DownsyncService { - - private ServiceRequestClient restClient; - - private ReferralManagementConfiguration configs; - - private NamedParameterJdbcTemplate jdbcTemplate; - - private SideEffectService sideEffectService; - - private ReferralManagementService referralService; - - @Autowired - public DownsyncService( ServiceRequestClient serviceRequestClient, - ReferralManagementConfiguration referralManagementConfiguration, - NamedParameterJdbcTemplate jdbcTemplate, - SideEffectService sideEffectService, - ReferralManagementService referralService) { - - this.restClient = serviceRequestClient; - this.configs = referralManagementConfiguration; - this.jdbcTemplate = jdbcTemplate; - this.sideEffectService=sideEffectService; - this.referralService=referralService; - - } - /** - * - * @param downsyncRequest - * @return Downsync - */ - public Downsync prepareDownsyncData(DownsyncRequest downsyncRequest) { + private ServiceRequestClient restClient; - Downsync downsync = new Downsync(); + private ReferralManagementConfiguration configs; - List householdIds = null; - Set individualIds = null; - List individualClientRefIds = null; - List beneficiaryClientRefIds = null; - List taskClientRefIds = null; + private NamedParameterJdbcTemplate jdbcTemplate; - downsync.setDownsyncCriteria(downsyncRequest.getDownsyncCriteria()); - /* search household */ - householdIds = searchHouseholds(downsyncRequest, downsync); + private SideEffectService sideEffectService; - if (!CollectionUtils.isEmpty(householdIds)) - /* search household member using household ids */ - individualIds = searchMembers(downsyncRequest, downsync, householdIds); + private ReferralManagementService referralService; - if (!CollectionUtils.isEmpty(individualIds)) { + @Autowired + public DownsyncService(ServiceRequestClient serviceRequestClient, + ReferralManagementConfiguration referralManagementConfiguration, + NamedParameterJdbcTemplate jdbcTemplate, + SideEffectService sideEffectService, + ReferralManagementService referralService) { - /* search individuals using individual ids */ - individualClientRefIds = searchIndividuals(downsyncRequest, downsync, individualIds); - } + this.restClient = serviceRequestClient; + this.configs = referralManagementConfiguration; + this.jdbcTemplate = jdbcTemplate; + this.sideEffectService = sideEffectService; + this.referralService = referralService; - if (!CollectionUtils.isEmpty(individualClientRefIds)) { - /* search beneficiary using individual ids */ - beneficiaryClientRefIds = searchBeneficiaries(downsyncRequest, downsync, individualClientRefIds); - } + } - if (!CollectionUtils.isEmpty(beneficiaryClientRefIds)) { + /** + * @param downsyncRequest + * @return Downsync + */ + public Downsync prepareDownsyncData(DownsyncRequest downsyncRequest) { - /* search tasks using beneficiary uuids */ - taskClientRefIds = searchTasks(downsyncRequest, downsync, beneficiaryClientRefIds); + Downsync downsync = new Downsync(); - /* ref search */ - referralSearch(downsyncRequest, downsync, beneficiaryClientRefIds); - } + List householdIds = null; + Set individualIds = null; + List individualClientRefIds = null; + List beneficiaryClientRefIds = null; + List taskClientRefIds = null; - if (!CollectionUtils.isEmpty(taskClientRefIds)) { + downsync.setDownsyncCriteria(downsyncRequest.getDownsyncCriteria()); + /* search household */ + householdIds = searchHouseholds(downsyncRequest, downsync); - searchSideEffect(downsyncRequest, downsync, taskClientRefIds); - } + if (!CollectionUtils.isEmpty(householdIds)) + /* search household member using household ids */ + individualIds = searchMembers(downsyncRequest, downsync, householdIds); - return downsync; - } + if (!CollectionUtils.isEmpty(individualIds)) { - /** - * - * @param downsyncRequest - * @param downsync - * @return - */ - private List searchHouseholds(DownsyncRequest downsyncRequest, Downsync downsync) { + /* search individuals using individual ids */ + individualClientRefIds = searchIndividuals(downsyncRequest, downsync, individualIds); + } - DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); - RequestInfo requestInfo = downsyncRequest.getRequestInfo(); - - StringBuilder householdUrl = new StringBuilder(configs.getHouseholdHost()) - .append(configs.getHouseholdSearchUrl()); - householdUrl = appendUrlParams(householdUrl, criteria, null, null); - - HouseholdSearch householdSearch = HouseholdSearch.builder() - .localityCode(criteria.getLocality()) - .build(); - - HouseholdSearchRequest searchRequest = HouseholdSearchRequest.builder() - .household(householdSearch) - .requestInfo(requestInfo) - .build(); - - HouseholdBulkResponse res = restClient.fetchResult(householdUrl, searchRequest, HouseholdBulkResponse.class); - List households = res.getHouseholds(); - downsync.setHouseholds(households); - downsync.getDownsyncCriteria().setTotalCount(res.getTotalCount()); - - if(CollectionUtils.isEmpty(households)) - return Collections.emptyList(); - - return households.stream().map(Household::getId).collect(Collectors.toList()); - } + if (!CollectionUtils.isEmpty(individualClientRefIds)) { + /* search beneficiary using individual ids */ + beneficiaryClientRefIds = searchBeneficiaries(downsyncRequest, downsync, individualClientRefIds); + } - /** - * - * @param downsyncRequest - * @param downsync - * @param individualIds - * @return individual ClientReferenceIds - */ - private List searchIndividuals(DownsyncRequest downsyncRequest, Downsync downsync, - Set individualIds) { + if (!CollectionUtils.isEmpty(beneficiaryClientRefIds)) { - DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); - RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + /* search tasks using beneficiary uuids */ + taskClientRefIds = searchTasks(downsyncRequest, downsync, beneficiaryClientRefIds); - StringBuilder url = new StringBuilder(configs.getIndividualHost()) - .append(configs.getIndividualSearchUrl()); - url = appendUrlParams(url, criteria, 0, individualIds.size()); - - IndividualSearch individualSearch = IndividualSearch.builder() - .id(new ArrayList<>(individualIds)) - .build(); - - IndividualSearchRequest searchRequest = IndividualSearchRequest.builder() - .individual(individualSearch) - .requestInfo(requestInfo) - .build(); - - List individuals = restClient.fetchResult(url, searchRequest, IndividualBulkResponse.class).getIndividual(); - downsync.setIndividuals(individuals); - - return individuals.stream().map(Individual::getClientReferenceId).collect(Collectors.toList()); - } + /* ref search */ + referralSearch(downsyncRequest, downsync, beneficiaryClientRefIds); + } - /** - * - * @param downsyncRequest - * @param householdIds - * @return - */ - private Set searchMembers(DownsyncRequest downsyncRequest, Downsync downsync, - List householdIds) { - - StringBuilder memberUrl = new StringBuilder(configs.getHouseholdHost()) - .append(configs.getHouseholdMemberSearchUrl()); - - String memberIdsquery = "SELECT id from HOUSEHOLD_MEMBER where householdId IN (:householdIds)"; - - Map paramMap = new HashMap<>(); - paramMap.put("householdIds", householdIds); - appendUrlParams(memberUrl, downsyncRequest.getDownsyncCriteria(), 0, householdIds.size()); + if (!CollectionUtils.isEmpty(taskClientRefIds)) { - /* FIXME SHOULD BE REMOVED AND SEARCH SHOULD BE enhanced with list of household ids*/ - List memberids = jdbcTemplate.queryForList(memberIdsquery, paramMap, String.class); - - if (CollectionUtils.isEmpty(memberids)) - return Collections.emptySet(); - - - HouseholdMemberSearch memberSearch = HouseholdMemberSearch.builder() - .id(memberids) - .build(); - - HouseholdMemberSearchRequest searchRequest = HouseholdMemberSearchRequest.builder() - .householdMemberSearch(memberSearch) - .requestInfo(downsyncRequest.getRequestInfo()) - .build(); - - List members = restClient.fetchResult(memberUrl, searchRequest, HouseholdMemberBulkResponse.class).getHouseholdMembers(); - downsync.setHouseholdMembers(members); - - return members.stream().map(HouseholdMember::getIndividualId).collect(Collectors.toSet()); - } + searchSideEffect(downsyncRequest, downsync, taskClientRefIds); + } - /** - * - * @param downsyncRequest - * @param downsync - * @param individualClientRefIds - * @return clientreferenceid of beneficiary object - */ - private List searchBeneficiaries(DownsyncRequest downsyncRequest, Downsync downsync, - List individualClientRefIds) { + return downsync; + } - DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); - RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + /** + * @param downsyncRequest + * @param downsync + * @return + */ + private List searchHouseholds(DownsyncRequest downsyncRequest, Downsync downsync) { + + DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + + StringBuilder householdUrl = new StringBuilder(configs.getHouseholdHost()) + .append(configs.getHouseholdSearchUrl()); + householdUrl = appendUrlParams(householdUrl, criteria, null, null); + + HouseholdSearch householdSearch = HouseholdSearch.builder() + .localityCode(criteria.getLocality()) + .build(); + + HouseholdSearchRequest searchRequest = HouseholdSearchRequest.builder() + .household(householdSearch) + .requestInfo(requestInfo) + .build(); + + HouseholdBulkResponse res = restClient.fetchResult(householdUrl, searchRequest, HouseholdBulkResponse.class); + List households = res.getHouseholds(); + downsync.setHouseholds(households); + downsync.getDownsyncCriteria().setTotalCount(res.getTotalCount()); + + if (CollectionUtils.isEmpty(households)) + return Collections.emptyList(); + + return households.stream().map(Household::getId).collect(Collectors.toList()); + } + + /** + * @param downsyncRequest + * @param downsync + * @param individualIds + * @return individual ClientReferenceIds + */ + private List searchIndividuals(DownsyncRequest downsyncRequest, Downsync downsync, + Set individualIds) { + + DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + + StringBuilder url = new StringBuilder(configs.getIndividualHost()) + .append(configs.getIndividualSearchUrl()); + url = appendUrlParams(url, criteria, 0, individualIds.size()); + + IndividualSearch individualSearch = IndividualSearch.builder() + .id(new ArrayList<>(individualIds)) + .build(); + + IndividualSearchRequest searchRequest = IndividualSearchRequest.builder() + .individual(individualSearch) + .requestInfo(requestInfo) + .build(); + + List individuals = restClient.fetchResult(url, searchRequest, IndividualBulkResponse.class).getIndividual(); + downsync.setIndividuals(individuals); + + return individuals.stream().map(Individual::getClientReferenceId).collect(Collectors.toList()); + } + + /** + * @param downsyncRequest + * @param householdIds + * @return + */ + private Set searchMembers(DownsyncRequest downsyncRequest, Downsync downsync, + List householdIds) { + + StringBuilder memberUrl = new StringBuilder(configs.getHouseholdHost()) + .append(configs.getHouseholdMemberSearchUrl()); + + String memberIdsquery = "SELECT id from HOUSEHOLD_MEMBER where householdId IN (:householdIds)"; + + Map paramMap = new HashMap<>(); + paramMap.put("householdIds", householdIds); + appendUrlParams(memberUrl, downsyncRequest.getDownsyncCriteria(), 0, householdIds.size()); + + /* FIXME SHOULD BE REMOVED AND SEARCH SHOULD BE enhanced with list of household ids*/ + List memberids = jdbcTemplate.queryForList(memberIdsquery, paramMap, String.class); + + if (CollectionUtils.isEmpty(memberids)) + return Collections.emptySet(); + + + HouseholdMemberSearch memberSearch = HouseholdMemberSearch.builder() + .id(memberids) + .build(); + + HouseholdMemberSearchRequest searchRequest = HouseholdMemberSearchRequest.builder() + .householdMemberSearch(memberSearch) + .requestInfo(downsyncRequest.getRequestInfo()) + .build(); + + List members = restClient.fetchResult(memberUrl, searchRequest, HouseholdMemberBulkResponse.class).getHouseholdMembers(); + downsync.setHouseholdMembers(members); + + return members.stream().map(HouseholdMember::getIndividualId).collect(Collectors.toSet()); + } + + /** + * @param downsyncRequest + * @param downsync + * @param individualClientRefIds + * @return clientreferenceid of beneficiary object + */ + private List searchBeneficiaries(DownsyncRequest downsyncRequest, Downsync downsync, + List individualClientRefIds) { + + DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo requestInfo = downsyncRequest.getRequestInfo(); StringBuilder url = new StringBuilder(configs.getProjectHost()) .append(configs.getProjectBeneficiarySearchUrl()); @@ -261,7 +256,7 @@ private List searchBeneficiaries(DownsyncRequest downsyncRequest, Downsy ProjectBeneficiarySearch search = ProjectBeneficiarySearch.builder() .id(ids) - .projectId(downsyncRequest.getDownsyncCriteria().getProjectId()) + .projectId(Collections.singletonList(downsyncRequest.getDownsyncCriteria().getProjectId())) .build(); BeneficiarySearchRequest searchRequest = BeneficiarySearchRequest.builder() @@ -275,15 +270,14 @@ private List searchBeneficiaries(DownsyncRequest downsyncRequest, Downsy return beneficiaries.stream().map(ProjectBeneficiary::getClientReferenceId).collect(Collectors.toList()); } - /** - * - * @param downsyncRequest - * @param downsync - * @param beneficiaryClientRefIds - * @return - */ - private List searchTasks(DownsyncRequest downsyncRequest, Downsync downsync, - List beneficiaryClientRefIds) { + /** + * @param downsyncRequest + * @param downsync + * @param beneficiaryClientRefIds + * @return + */ + private List searchTasks(DownsyncRequest downsyncRequest, Downsync downsync, + List beneficiaryClientRefIds) { DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); RequestInfo requestInfo = downsyncRequest.getRequestInfo(); @@ -305,7 +299,7 @@ private List searchTasks(DownsyncRequest downsyncRequest, Downsync downs TaskSearch search = TaskSearch.builder() .id(taskIds) - .projectId(downsyncRequest.getDownsyncCriteria().getProjectId()) + .projectId(Collections.singletonList(downsyncRequest.getDownsyncCriteria().getProjectId())) .build(); TaskSearchRequest searchRequest = TaskSearchRequest.builder() @@ -319,105 +313,104 @@ private List searchTasks(DownsyncRequest downsyncRequest, Downsync downs return tasks.stream().map(Task::getClientReferenceId).collect(Collectors.toList()); } - /** - * - * @param downsyncRequest - * @param downsync - * @param taskClientRefIds - */ - private void searchSideEffect(DownsyncRequest downsyncRequest, Downsync downsync, - List taskClientRefIds) { - - DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); - RequestInfo requestInfo = downsyncRequest.getRequestInfo(); - - // search side effect FIXME - tasks id array search not available - String sEIdQuery = "SELECT id from SIDE_EFFECT where taskClientReferenceId IN (:taskClientRefIds)"; - - Map paramMap = new HashMap<>(); - paramMap.put("taskClientRefIds", taskClientRefIds); - - /* FIXME SHOULD BE REMOVED AND TASK SEARCH SHOULD BE enhanced with list of client-ref-beneficiary ids*/ - List SEIds = jdbcTemplate.queryForList(sEIdQuery, paramMap, String.class); - - if(CollectionUtils.isEmpty(SEIds)) - return; - - SideEffectSearch search = SideEffectSearch.builder() - .id(SEIds) - .build(); - SideEffectSearchRequest effectSearchRequest = SideEffectSearchRequest.builder() - .sideEffect(search) - .requestInfo(requestInfo) - .build(); - - List effects = sideEffectService.search( - effectSearchRequest, - SEIds.size(), - 0, - criteria.getTenantId(), - criteria.getLastSyncedTime(), - criteria.getIncludeDeleted()); - - downsync.setSideEffects(effects); - } - - private void referralSearch(DownsyncRequest downsyncRequest, Downsync downsync, - List beneficiaryClientRefIds) { - - DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); - RequestInfo requestInfo = downsyncRequest.getRequestInfo(); - - ReferralSearch search = ReferralSearch.builder() - .projectBeneficiaryClientReferenceId(beneficiaryClientRefIds) - .build(); - - ReferralSearchRequest searchRequest = ReferralSearchRequest.builder() - .referral(search) - .requestInfo(requestInfo) - .build(); - - List referrals = referralService.search( - searchRequest, - beneficiaryClientRefIds.size(), - 0, - criteria.getTenantId(), - criteria.getLastSyncedTime(), - criteria.getIncludeDeleted()); - - downsync.setReferrals(referrals); - } - - - - /** - * append url params - * - * @param url - * @param criteria - * @param includeLimitOffset - * @return - */ - private StringBuilder appendUrlParams(StringBuilder url, DownsyncCriteria criteria, Integer offset, Integer limit) { - - url.append("?tenantId=") - .append(criteria.getTenantId()) - .append("&includeDeleted=") - .append(criteria.getIncludeDeleted()) - .append("&limit="); - - if (null != limit) - url.append(limit); - else - url.append(criteria.getLimit()); - - url.append("&offset="); - - if(null != offset) - url.append(offset); - else - url.append(criteria.getOffset()); - - return url; - } + /** + * @param downsyncRequest + * @param downsync + * @param taskClientRefIds + */ + private void searchSideEffect(DownsyncRequest downsyncRequest, Downsync downsync, + List taskClientRefIds) { + + DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + + // search side effect FIXME - tasks id array search not available + String sEIdQuery = "SELECT id from SIDE_EFFECT where taskClientReferenceId IN (:taskClientRefIds)"; + + Map paramMap = new HashMap<>(); + paramMap.put("taskClientRefIds", taskClientRefIds); + + /* FIXME SHOULD BE REMOVED AND TASK SEARCH SHOULD BE enhanced with list of client-ref-beneficiary ids*/ + List SEIds = jdbcTemplate.queryForList(sEIdQuery, paramMap, String.class); + + if (CollectionUtils.isEmpty(SEIds)) + return; + + SideEffectSearch search = SideEffectSearch.builder() + .id(SEIds) + .build(); + SideEffectSearchRequest effectSearchRequest = SideEffectSearchRequest.builder() + .sideEffect(search) + .requestInfo(requestInfo) + .build(); + + List effects = sideEffectService.search( + effectSearchRequest, + SEIds.size(), + 0, + criteria.getTenantId(), + criteria.getLastSyncedTime(), + criteria.getIncludeDeleted()).getResponse(); + + downsync.setSideEffects(effects); + } + + private void referralSearch(DownsyncRequest downsyncRequest, Downsync downsync, + List beneficiaryClientRefIds) { + + DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + + ReferralSearch search = ReferralSearch.builder() + .projectBeneficiaryClientReferenceId(beneficiaryClientRefIds) + .build(); + + ReferralSearchRequest searchRequest = ReferralSearchRequest.builder() + .referral(search) + .requestInfo(requestInfo) + .build(); + + List referrals = referralService.search( + searchRequest, + beneficiaryClientRefIds.size(), + 0, + criteria.getTenantId(), + criteria.getLastSyncedTime(), + criteria.getIncludeDeleted()).getResponse(); + + downsync.setReferrals(referrals); + } + + + /** + * append url params + * + * @param url + * @param criteria + * @param offset + * @param limit + * @return + */ + private StringBuilder appendUrlParams(StringBuilder url, DownsyncCriteria criteria, Integer offset, Integer limit) { + + url.append("?tenantId=") + .append(criteria.getTenantId()) + .append("&includeDeleted=") + .append(criteria.getIncludeDeleted()) + .append("&limit="); + + if (null != limit) + url.append(limit); + else + url.append(criteria.getLimit()); + + url.append("&offset="); + + if (null != offset) + url.append(offset); + else + url.append(criteria.getOffset()); + + return url; + } } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/HFReferralService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/HFReferralService.java index aaf317acafc..c3c287bcff3 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/HFReferralService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/HFReferralService.java @@ -20,6 +20,7 @@ import org.egov.referralmanagement.config.ReferralManagementConfiguration; import org.egov.referralmanagement.repository.HFReferralRepository; import org.egov.referralmanagement.service.enrichment.HFReferralEnrichmentService; +import org.egov.referralmanagement.validator.hfreferral.HfrExistentEntityValidator; import org.egov.referralmanagement.validator.hfreferral.HfrIsDeletedValidator; import org.egov.referralmanagement.validator.hfreferral.HfrNonExistentEntityValidator; import org.egov.referralmanagement.validator.hfreferral.HfrNullIdValidator; @@ -60,6 +61,7 @@ public class HFReferralService { // Predicates to determine which validators are applicable for create, update, and delete operations private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(HfrProjectIdValidator.class) + || validator.getClass().equals(HfrExistentEntityValidator.class) || validator.getClass().equals(HfrProjectFacilityIdValidator.class); private final Predicate> isApplicableForUpdate = validator -> diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java index 7c35b9747fe..25c41986eea 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java @@ -1,24 +1,16 @@ package org.egov.referralmanagement.service; -import static org.egov.common.utils.CommonUtils.getIdFieldName; -import static org.egov.common.utils.CommonUtils.getIdMethod; -import static org.egov.common.utils.CommonUtils.handleErrors; -import static org.egov.common.utils.CommonUtils.havingTenantId; -import static org.egov.common.utils.CommonUtils.includeDeleted; -import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; -import static org.egov.common.utils.CommonUtils.lastChangedSince; -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; - import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.Predicate; import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.referralmanagement.Referral; import org.egov.common.models.referralmanagement.ReferralBulkRequest; import org.egov.common.models.referralmanagement.ReferralRequest; @@ -30,6 +22,7 @@ import org.egov.referralmanagement.config.ReferralManagementConfiguration; import org.egov.referralmanagement.repository.ReferralRepository; import org.egov.referralmanagement.service.enrichment.ReferralManagementEnrichmentService; +import org.egov.referralmanagement.validator.RmExistentEntityValidator; import org.egov.referralmanagement.validator.RmIsDeletedValidator; import org.egov.referralmanagement.validator.RmNonExistentEntityValidator; import org.egov.referralmanagement.validator.RmNullIdValidator; @@ -42,7 +35,15 @@ import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; -import lombok.extern.slf4j.Slf4j; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; @Service @Slf4j @@ -60,6 +61,7 @@ public class ReferralManagementService { private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(RmProjectBeneficiaryIdValidator.class) + || validator.getClass().equals(RmExistentEntityValidator.class) || validator.getClass().equals(RmReferrerIdValidator.class) || validator.getClass().equals(RmRecipientIdValidator.class) || validator.getClass().equals(RmSideEffectIdValidator.class); @@ -153,12 +155,12 @@ public List update(ReferralBulkRequest referralRequest, boolean isBulk return validReferrals; } - public List search(ReferralSearchRequest referralSearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) { + public SearchResponse search(ReferralSearchRequest referralSearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) { log.info("received request to search referrals"); String idFieldName = getIdFieldName(referralSearchRequest.getReferral()); if (isSearchByIdOnly(referralSearchRequest.getReferral(), idFieldName)) { @@ -167,11 +169,12 @@ public List search(ReferralSearchRequest referralSearchRequest, .singletonList(referralSearchRequest.getReferral())), referralSearchRequest.getReferral()); log.info("fetching referrals with ids: {}", ids); - return referralRepository.findById(ids, includeDeleted, idFieldName).stream() + List referrals = referralRepository.findById(ids, idFieldName, includeDeleted).getResponse().stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) .collect(Collectors.toList()); + return SearchResponse.builder().response(referrals).build(); } log.info("searching referrals using criteria"); return referralRepository.find(referralSearchRequest.getReferral(), diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java index 4850402507c..e5cfd43e00d 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java @@ -18,6 +18,7 @@ import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; import org.egov.common.models.referralmanagement.sideeffect.SideEffectRequest; @@ -28,6 +29,7 @@ import org.egov.referralmanagement.config.ReferralManagementConfiguration; import org.egov.referralmanagement.repository.SideEffectRepository; import org.egov.referralmanagement.service.enrichment.SideEffectEnrichmentService; +import org.egov.referralmanagement.validator.sideeffect.SeExistentEntityValidator; import org.egov.referralmanagement.validator.sideeffect.SeIsDeletedValidator; import org.egov.referralmanagement.validator.sideeffect.SeNonExistentEntityValidator; import org.egov.referralmanagement.validator.sideeffect.SeNullIdValidator; @@ -58,6 +60,7 @@ public class SideEffectService { private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(SeProjectTaskIdValidator.class) + || validator.getClass().equals(SeExistentEntityValidator.class) || validator.getClass().equals(SeProjectBeneficiaryIdValidator.class); private final Predicate> isApplicableForUpdate = validator -> @@ -185,12 +188,12 @@ public List update(SideEffectBulkRequest sideEffectRequest, boolean * @return * @throws Exception */ - public List search(SideEffectSearchRequest sideEffectSearchRequest, - Integer limit, - Integer offset, - String tenantId, - Long lastChangedSince, - Boolean includeDeleted) { + public SearchResponse search(SideEffectSearchRequest sideEffectSearchRequest, + Integer limit, + Integer offset, + String tenantId, + Long lastChangedSince, + Boolean includeDeleted) { log.info("received request to search side effects"); String idFieldName = getIdFieldName(sideEffectSearchRequest.getSideEffect()); if (isSearchByIdOnly(sideEffectSearchRequest.getSideEffect(), idFieldName)) { @@ -199,11 +202,12 @@ public List search(SideEffectSearchRequest sideEffectSearchRequest, .singletonList(sideEffectSearchRequest.getSideEffect())), sideEffectSearchRequest.getSideEffect()); log.info("fetching side effects with ids: {}", ids); - return sideEffectRepository.findById(ids, includeDeleted, idFieldName).stream() + List sideEffectList = sideEffectRepository.findById(ids, includeDeleted, idFieldName); + return SearchResponse.builder().response(sideEffectList.stream() .filter(lastChangedSince(lastChangedSince)) .filter(havingTenantId(tenantId)) .filter(includeDeleted(includeDeleted)) - .collect(Collectors.toList()); + .collect(Collectors.toList())).build(); } log.info("searching side effects using criteria"); return sideEffectRepository.find(sideEffectSearchRequest.getSideEffect(), diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmExistentEntityValidator.java new file mode 100644 index 00000000000..6b760985b92 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmExistentEntityValidator.java @@ -0,0 +1,76 @@ +package org.egov.referralmanagement.validator; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.models.referralmanagement.ReferralSearch; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.repository.ReferralRepository; +import org.springframework.util.CollectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of entities with the given client reference IDs. + * This validator checks if the provided referral entities already exist in the database based on their client reference IDs. + * @author kanishq-egov + */ +public class RmExistentEntityValidator implements Validator { + + private final ReferralRepository referralRepository; + + /** + * Constructor to initialize the ReferralRepository dependency. + * + * @param referralRepository The repository for referral entities. + */ + public RmExistentEntityValidator(ReferralRepository referralRepository) { + this.referralRepository = referralRepository; + } + + /** + * Validates the existence of entities with the given client reference IDs. + * + * @param request The bulk request containing referral entities. + * @return A map containing referral entities and their associated error details. + */ + @Override + public Map> validate(ReferralBulkRequest request) { + // Map to hold referral entities and their error details + Map> errorDetailsMap = new HashMap<>(); + // Get the list of referral entities from the request + List entities = request.getReferrals(); + // Extract client reference IDs from referral entities without errors + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) + .map(Referral::getClientReferenceId) + .collect(Collectors.toList()); + // Create a search object for querying entities by client reference IDs + ReferralSearch referralSearch = ReferralSearch.builder() + .clientReferenceId(clientReferenceIdList) + .build(); + // Check if the client reference ID list is not empty + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing entities by client reference IDs + List existentEntities = referralRepository.findById( + clientReferenceIdList, + getIdFieldName(referralSearch), + Boolean.FALSE).getResponse(); + // For each existing entity, populate error details for uniqueness + existentEntities.forEach(entity -> { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(entity, error, errorDetailsMap); + }); + } + return errorDetailsMap; + } + +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java index 5009ee003f2..8189c560ef1 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmNonExistentEntityValidator.java @@ -56,7 +56,7 @@ public Map> validate(ReferralBulkRequest request) { if (!iMap.isEmpty()) { List referralIds = new ArrayList<>(iMap.keySet()); List existingReferrals = referralRepository - .findById(referralIds, false, getIdFieldName(idMethod)); + .findById(referralIds, getIdFieldName(idMethod),false).getResponse(); List nonExistentReferrals = checkNonExistentEntities(iMap, existingReferrals, idMethod); nonExistentReferrals.forEach(sideEffect -> { diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmSideEffectIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmSideEffectIdValidator.java index 565bfff6f30..c0fa26bf55c 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmSideEffectIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmSideEffectIdValidator.java @@ -58,7 +58,7 @@ public Map> validate(ReferralBulkRequest request) { validSideEffectIds = sideEffectService.search( SideEffectSearchRequest.builder().sideEffect(SideEffectSearch.builder().id(sideEffectIds).build()).build(), sideEffectIds.size(), 0, tenantId, null, false - ).stream().map(SideEffect::getId).collect(Collectors.toList()); + ).getResponse().stream().map(SideEffect::getId).collect(Collectors.toList()); } catch (Exception e) { throw new CustomException("Side Effect failed to fetch", "Exception : " + e.getMessage()); } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrExistentEntityValidator.java new file mode 100644 index 00000000000..2eaebb8d5c2 --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrExistentEntityValidator.java @@ -0,0 +1,78 @@ +package org.egov.referralmanagement.validator.hfreferral; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.hfreferral.HFReferral; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; +import org.egov.common.models.referralmanagement.hfreferral.HFReferralSearch; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.repository.HFReferralRepository; +import org.springframework.util.CollectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of entities with the given client reference IDs. + * This validator checks if the provided HFReferral entities already exist in the database based on their client reference IDs. + * + * @author kanishq-egov + */ +public class HfrExistentEntityValidator implements Validator { + + private final HFReferralRepository hfReferralRepository; + + /** + * Constructor to initialize the HFReferralRepository dependency. + * + * @param hfReferralRepository The repository for HFReferral entities. + */ + public HfrExistentEntityValidator(HFReferralRepository hfReferralRepository) { + this.hfReferralRepository = hfReferralRepository; + } + + /** + * Validates the existence of entities with the given client reference IDs. + * + * @param request The bulk request containing HFReferral entities. + * @return A map containing HFReferral entities and their associated error details. + */ + @Override + public Map> validate(HFReferralBulkRequest request) { + // Map to hold HFReferral entities and their error details + Map> errorDetailsMap = new HashMap<>(); + // Get the list of HFReferral entities from the request + List entities = request.getHfReferrals(); + // Extract client reference IDs from HFReferral entities without errors + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) + .map(HFReferral::getClientReferenceId) + .collect(Collectors.toList()); + // Create a search object for querying entities by client reference IDs + HFReferralSearch hfReferralSearch = HFReferralSearch.builder() + .clientReferenceId(clientReferenceIdList) + .build(); + // Check if the client reference ID list is not empty + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing entities by client reference IDs + List existentEntities = hfReferralRepository.findById( + clientReferenceIdList, + Boolean.FALSE, + getIdFieldName(hfReferralSearch) + ); + // For each existing entity, populate error details for uniqueness + existentEntities.forEach(entity -> { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(entity, error, errorDetailsMap); + }); + } + return errorDetailsMap; + } + +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrProjectFacilityIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrProjectFacilityIdValidator.java index 82ac9dba00a..2cadd5e38ab 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrProjectFacilityIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrProjectFacilityIdValidator.java @@ -86,7 +86,6 @@ private List getExistingProjects(String tenantId, List { + + private final SideEffectRepository sideEffectRepository; + + /** + * Constructor to initialize the SideEffectRepository dependency. + * + * @param sideEffectRepository The repository for SideEffect entities. + */ + public SeExistentEntityValidator(SideEffectRepository sideEffectRepository) { + this.sideEffectRepository = sideEffectRepository; + } + + /** + * Validates the existence of SideEffect entities with the given client reference IDs. + * + * @param request The bulk request containing SideEffect entities. + * @return A map containing SideEffect entities and their associated error details. + */ + @Override + public Map> validate(SideEffectBulkRequest request) { + // Map to hold SideEffect entities and their error details + Map> errorDetailsMap = new HashMap<>(); + // Get the list of SideEffect entities from the request + List entities = request.getSideEffects(); + // Extract client reference IDs from SideEffect entities without errors + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) + .map(SideEffect::getClientReferenceId) + .collect(Collectors.toList()); + // Create a search object for querying entities by client reference IDs + SideEffectSearch sideEffectSearch = SideEffectSearch.builder() + .clientReferenceId(clientReferenceIdList) + .build(); + // Check if the client reference ID list is not empty + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing entities by client reference IDs + List existentEntities = sideEffectRepository.findById( + clientReferenceIdList, + getIdFieldName(sideEffectSearch), + Boolean.FALSE); + // For each existing entity, populate error details for uniqueness + existentEntities.forEach(entity -> { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(entity, error, errorDetailsMap); + }); + } + return errorDetailsMap; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java index 363b398bff9..216d7d48507 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeProjectBeneficiaryIdValidator.java @@ -1,9 +1,5 @@ package org.egov.referralmanagement.validator.sideeffect; -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -11,6 +7,7 @@ import java.util.Objects; import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; import org.egov.common.models.project.BeneficiaryBulkResponse; @@ -26,7 +23,9 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; -import lombok.extern.slf4j.Slf4j; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; /** * Validate whether project beneficiary exist in db or not using project beneficiary id and project beneficiary client beneficiary id for SideEffect object diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/BeneficiaryDownsyncController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/BeneficiaryDownsyncController.java index 80860ab2096..bd6a1a2ad2d 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/BeneficiaryDownsyncController.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/BeneficiaryDownsyncController.java @@ -1,6 +1,6 @@ package org.egov.referralmanagement.web.controllers; -import javax.validation.Valid; +import jakarta.validation.Valid; import org.egov.common.models.referralmanagement.beneficiarydownsync.Downsync; import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncRequest; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/HFReferralApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/HFReferralApiController.java index 97650777201..f09a4c578e8 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/HFReferralApiController.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/HFReferralApiController.java @@ -1,14 +1,12 @@ package org.egov.referralmanagement.web.controllers; import java.util.List; -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.URLParams; import org.egov.common.models.referralmanagement.hfreferral.HFReferral; import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkRequest; import org.egov.common.models.referralmanagement.hfreferral.HFReferralBulkResponse; @@ -23,10 +21,10 @@ import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; /** * Controller class for managing HF Referrals. @@ -100,23 +98,22 @@ public ResponseEntity referralBulkV1CreatePost(@ApiParam(value = " * API endpoint to search for HFReferrals based on certain criteria. * * @param request The HFReferralSearchRequest containing search criteria. - * @param limit Pagination - limit records in response. - * @param offset Pagination - offset from which records should be returned in response. - * @param tenantId Unique id for a tenant. - * @param lastChangedSince Epoch of the time since when the changes on the object should be picked up. - * @param includeDeleted Used in search APIs to specify if (soft) deleted records should be included in search results. * @return ResponseEntity containing HFReferralBulkResponse. * @throws Exception */ @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) - public ResponseEntity referralV1SearchPost(@ApiParam(value = "HFReferral Search.", required = true) @Valid @RequestBody HFReferralSearchRequest request, - @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, - @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, - @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, - @ApiParam(value = "Epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, - @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { - - List hfReferrals = hfReferralService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); + public ResponseEntity referralV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "HFReferral Search.", required = true) @Valid @RequestBody HFReferralSearchRequest request + ) throws Exception { + + List hfReferrals = hfReferralService.search( + request, + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted()); HFReferralBulkResponse response = HFReferralBulkResponse.builder().responseInfo(ResponseInfoFactory .createResponseInfo(request.getRequestInfo(), true)).hfReferrals(hfReferrals).build(); diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java index 92d867479ee..0d65d31d5c9 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiController.java @@ -1,8 +1,11 @@ package org.egov.referralmanagement.web.controllers; import io.swagger.annotations.ApiParam; -import org.egov.referralmanagement.service.ReferralManagementService; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; import org.egov.common.models.referralmanagement.Referral; import org.egov.common.models.referralmanagement.ReferralBulkRequest; import org.egov.common.models.referralmanagement.ReferralBulkResponse; @@ -12,21 +15,15 @@ import org.egov.common.producer.Producer; import org.egov.common.utils.ResponseInfoFactory; import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.service.ReferralManagementService; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; - -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import java.util.List; /** * Referral Management Api Controller @@ -91,26 +88,28 @@ public ResponseEntity referralBulkV1CreatePost(@ApiParam(value = " /** * - * @param request - * @param limit - * @param offset - * @param tenantId - * @param lastChangedSince - * @param includeDeleted + * @param referralSearchRequest * @return * @throws Exception */ @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) - public ResponseEntity referralV1SearchPost(@ApiParam(value = "Referral Search.", required = true) @Valid @RequestBody ReferralSearchRequest request, - @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, - @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, - @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, - @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, - @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { - - List referrals = referralManagementService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); + public ResponseEntity referralV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Referral Search.", required = true) @Valid @RequestBody ReferralSearchRequest referralSearchRequest + ) throws Exception { + + SearchResponse referralSearchResponse = referralManagementService.search( + referralSearchRequest, + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted()); ReferralBulkResponse response = ReferralBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).referrals(referrals).build(); + .createResponseInfo(referralSearchRequest.getRequestInfo(), true)) + .referrals(referralSearchResponse.getResponse()) + .totalCount(referralSearchResponse.getTotalCount()) + .build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/SideEffectApiController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/SideEffectApiController.java index c43db332fa7..65b777c9a1f 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/SideEffectApiController.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/SideEffectApiController.java @@ -1,9 +1,11 @@ package org.egov.referralmanagement.web.controllers; import io.swagger.annotations.ApiParam; -import org.egov.referralmanagement.config.ReferralManagementConfiguration; -import org.egov.referralmanagement.service.SideEffectService; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkResponse; @@ -12,21 +14,16 @@ import org.egov.common.models.referralmanagement.sideeffect.SideEffectSearchRequest; import org.egov.common.producer.Producer; import org.egov.common.utils.ResponseInfoFactory; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.referralmanagement.service.SideEffectService; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; - -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import java.util.List; @Controller @RequestMapping("/side-effect") @@ -79,16 +76,22 @@ public ResponseEntity sideEffectBulkV1CreatePost(@ApiParam(value = } @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) - public ResponseEntity sideEffectV1SearchPost(@ApiParam(value = "Side Effect Search.", required = true) @Valid @RequestBody SideEffectSearchRequest request, - @NotNull @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, - @NotNull @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, - @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, - @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, - @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { - - List sideEffects = sideEffectService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); + public ResponseEntity sideEffectV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Side Effect Search.", required = true) @Valid @RequestBody SideEffectSearchRequest request + ) throws Exception { + + SearchResponse sideEffectSearchResponse = sideEffectService.search( + request, + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted() + ); SideEffectBulkResponse response = SideEffectBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).sideEffects(sideEffects).build(); + .createResponseInfo(request.getRequestInfo(), true)).sideEffects(sideEffectSearchResponse.getResponse()) + .totalCount(sideEffectSearchResponse.getTotalCount()).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/referralmanagement/src/main/resources/db/migration/main/V20240416111000__referral_referral_code_create_ddl.sql b/health-services/referralmanagement/src/main/resources/db/migration/main/V20240416111000__referral_referral_code_create_ddl.sql new file mode 100644 index 00000000000..23a174ce793 --- /dev/null +++ b/health-services/referralmanagement/src/main/resources/db/migration/main/V20240416111000__referral_referral_code_create_ddl.sql @@ -0,0 +1 @@ +ALTER TABLE REFERRAL ADD COLUMN referralCode character varying(256); \ No newline at end of file diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/AppTest.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/AppTest.java index 48b5fb750f6..9b872dba7b8 100644 --- a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/AppTest.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/AppTest.java @@ -1,8 +1,9 @@ package org.egov.referralmanagement; -import static org.junit.Assert.assertTrue; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Unit test for simple App. diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/ReferralTestBuilder.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/ReferralTestBuilder.java index 8ea5a37e267..1f2dfd310d9 100644 --- a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/ReferralTestBuilder.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/ReferralTestBuilder.java @@ -8,10 +8,10 @@ public class ReferralTestBuilder { - private Referral.ReferralBuilder builder; + private Referral.ReferralBuilder builder; public ReferralTestBuilder() { - this.builder = Referral.builder(); + this.builder = (Referral.ReferralBuilder) Referral.builder(); } public static ReferralTestBuilder builder() { diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java index d4c3c04c686..e2adc35eb3f 100644 --- a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/helper/SideEffectTestBuilder.java @@ -8,10 +8,10 @@ public class SideEffectTestBuilder { - private SideEffect.SideEffectBuilder builder; + private SideEffect.SideEffectBuilder builder; public SideEffectTestBuilder() { - this.builder = SideEffect.builder(); + this.builder = (SideEffect.SideEffectBuilder) SideEffect.builder(); } public static SideEffectTestBuilder builder() { diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiControllerTest.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiControllerTest.java index bcf1518c0c1..81c5a664f1f 100644 --- a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiControllerTest.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/ReferralManagementApiControllerTest.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.referralmanagement.Referral; import org.egov.common.models.referralmanagement.ReferralBulkResponse; import org.egov.common.models.referralmanagement.ReferralRequest; @@ -160,7 +161,11 @@ void shouldAcceptSearchRequestAndReturnReferral() throws Exception { ArgumentMatchers.any(Integer.class), ArgumentMatchers.any(String.class), ArgumentMatchers.any(Long.class), - ArgumentMatchers.any(Boolean.class))).thenReturn(Arrays.asList(ReferralTestBuilder.builder().withId().withAuditDetails().build())); + ArgumentMatchers.any(Boolean.class))).thenReturn( + SearchResponse.builder() + .response(Arrays.asList(ReferralTestBuilder.builder().withId().withAuditDetails().build())) + .build() + ); final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post( "/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") diff --git a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java index d163458fd62..b3413b77311 100644 --- a/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java +++ b/health-services/referralmanagement/src/test/java/org/egov/referralmanagement/web/controllers/SideEffectApiControllerTest.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.egov.common.helper.RequestInfoTestBuilder; +import org.egov.common.models.core.SearchResponse; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkResponse; import org.egov.common.models.referralmanagement.sideeffect.SideEffectRequest; @@ -33,6 +34,7 @@ import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; @WebMvcTest(SideEffectApiController.class) @@ -152,7 +154,7 @@ void shouldSendErrorResWithErrorDetailsWith400BadRequestForUpdate() throws Excep void shouldAcceptSearchRequestAndReturnSideEffect() throws Exception { SideEffectSearchRequest sideEffectSearchRequest = SideEffectSearchRequest.builder().sideEffect( - SideEffectSearch.builder().taskId("some-task-id").build() + SideEffectSearch.builder().taskId(Collections.singletonList("some-task-id")).build() ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); Mockito.when(sideEffectService.search(ArgumentMatchers.any(SideEffectSearchRequest.class), @@ -160,7 +162,10 @@ void shouldAcceptSearchRequestAndReturnSideEffect() throws Exception { ArgumentMatchers.any(Integer.class), ArgumentMatchers.any(String.class), ArgumentMatchers.any(Long.class), - ArgumentMatchers.any(Boolean.class))).thenReturn(Arrays.asList(SideEffectTestBuilder.builder().withId().withAuditDetails().build())); + ArgumentMatchers.any(Boolean.class))).thenReturn( + SearchResponse.builder() + .response(Arrays.asList(SideEffectTestBuilder.builder().withId().withAuditDetails().build())) + .build()); final MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post( "/side-effect/v1/_search?limit=10&offset=100&tenantId=default&lastChangedSince=1234322&includeDeleted=false") @@ -181,7 +186,7 @@ void shouldAcceptSearchRequestAndReturnSideEffect() throws Exception { void shouldThrowExceptionIfNoResultFound() throws Exception { SideEffectSearchRequest sideEffectSearchRequest = SideEffectSearchRequest.builder().sideEffect( - SideEffectSearch.builder().taskId("some-task-id").build() + SideEffectSearch.builder().taskId(Collections.singletonList("some-task-id")).build() ).requestInfo(RequestInfoTestBuilder.builder().withCompleteRequestInfo().build()).build(); Mockito.when(sideEffectService.search(ArgumentMatchers.any(SideEffectSearchRequest.class), diff --git a/health-services/stock/CHANGELOG.md b/health-services/stock/CHANGELOG.md index 83d0dd54070..43b00d03e48 100644 --- a/health-services/stock/CHANGELOG.md +++ b/health-services/stock/CHANGELOG.md @@ -1,5 +1,11 @@ All notable changes to this module will be documented in this file. +## 1.1.3 - 2024-05-29 +- Upgraded to Core 2.9LTS +- Upgraded to health models 1.0.20 and health common 1.0.16 +- Boundary v2 Integration +- MDMS v2 integration + ## 1.1.2 - 2024-02-26 - Enhance inventory flow with sender id and receiver id added. diff --git a/health-services/stock/README.md b/health-services/stock/README.md index 1a507a3c922..7989b3ea73b 100644 --- a/health-services/stock/README.md +++ b/health-services/stock/README.md @@ -75,3 +75,13 @@ Stock service APIs - contains create, update, delete and search end point ## Pre commit script [commit-msg](https://gist.github.com/jayantp-egov/14f55deb344f1648503c6be7e580fa12) + +## Updates +- Stock Search + - `productVariantId`, and `waybillNumber` now accepts a list of entities instead of single entity to search stock +- Stock Reconciliation Search + - `facilityId`, and `productVariantId` now accepts a list of entities instead of single entity to search stock reconciliation +## Usage +- Start the service +- Access the API endpoints for searching `stock` and `stock reconciliation` +- Pass list parameters for the search fields mentioned in updates diff --git a/health-services/stock/pom.xml b/health-services/stock/pom.xml index a6d29a41ba7..6387b32a497 100644 --- a/health-services/stock/pom.xml +++ b/health-services/stock/pom.xml @@ -5,16 +5,17 @@ stock jar stock - 1.1.2 + 1.1.3 - 1.8 + 17 ${java.version} ${java.version} + 1.18.22 org.springframework.boot spring-boot-starter-parent - 2.2.6.RELEASE + 3.2.2 src/main/java @@ -44,12 +45,12 @@ org.egov.common health-services-common - 1.0.8-SNAPSHOT + 1.0.16-SNAPSHOT org.egov.common health-services-models - 1.0.15-SNAPSHOT + 1.0.20-SNAPSHOT @@ -69,11 +70,17 @@ org.flywaydb flyway-core + 9.22.3 org.postgresql postgresql - 42.2.2.jre7 + 42.7.1 + + + org.egov.services + tracer + 2.9.0-SNAPSHOT org.springframework.boot @@ -90,6 +97,7 @@ org.projectlombok lombok + ${lombok.version} true @@ -97,11 +105,6 @@ com.fasterxml.jackson.datatype jackson-datatype-jsr310 - - - javax.validation - validation-api - diff --git a/health-services/stock/src/main/java/org/egov/stock/config/MainConfiguration.java b/health-services/stock/src/main/java/org/egov/stock/config/MainConfiguration.java index b067e1cb2ab..01fd5d00559 100644 --- a/health-services/stock/src/main/java/org/egov/stock/config/MainConfiguration.java +++ b/health-services/stock/src/main/java/org/egov/stock/config/MainConfiguration.java @@ -24,7 +24,7 @@ import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import javax.annotation.PostConstruct; +import jakarta.annotation.PostConstruct; import java.util.TimeZone; @Import({TracerConfiguration.class}) @Configuration diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java index 831c8f4e331..813246f8a2b 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockReconciliationRowMapper.java @@ -1,16 +1,16 @@ package org.egov.stock.repository.rowmapper; +import java.sql.ResultSet; +import java.sql.SQLException; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.stock.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.stock.StockReconciliation; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; -import java.sql.ResultSet; -import java.sql.SQLException; - @Component public class StockReconciliationRowMapper implements RowMapper { diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java index d011f3301a4..d8d417b4fc0 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java @@ -3,7 +3,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; -import org.egov.common.models.stock.AdditionalFields; +import org.egov.common.models.core.AdditionalFields; import org.egov.common.models.stock.ReferenceIdType; import org.egov.common.models.stock.SenderReceiverType; import org.egov.common.models.stock.Stock; diff --git a/health-services/stock/src/main/java/org/egov/stock/service/StockReconciliationService.java b/health-services/stock/src/main/java/org/egov/stock/service/StockReconciliationService.java index 718c8389a53..1765e34c015 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/StockReconciliationService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/StockReconciliationService.java @@ -10,6 +10,7 @@ import org.egov.stock.config.StockReconciliationConfiguration; import org.egov.stock.repository.StockReconciliationRepository; import org.egov.stock.service.enrichment.StockReconciliationEnrichmentService; +import org.egov.stock.validator.stockreconciliation.SrExistentEntityValidator; import org.egov.stock.validator.stockreconciliation.SrFacilityIdValidator; import org.egov.stock.validator.stockreconciliation.SrIsDeletedValidator; import org.egov.stock.validator.stockreconciliation.SrNonExistentValidator; @@ -18,7 +19,7 @@ import org.egov.stock.validator.stockreconciliation.SrReferenceIdValidator; import org.egov.stock.validator.stockreconciliation.SrRowVersionValidator; import org.egov.stock.validator.stockreconciliation.SrUniqueEntityValidator; -import org.egov.stock.web.models.StockReconciliationSearchRequest; +import org.egov.common.models.stock.StockReconciliationSearchRequest; import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; @@ -56,6 +57,7 @@ public class StockReconciliationService { private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(SrProductVariantIdValidator.class) + || validator.getClass().equals(SrExistentEntityValidator.class) || validator.getClass().equals(SrFacilityIdValidator.class) || validator.getClass().equals(SrReferenceIdValidator.class); diff --git a/health-services/stock/src/main/java/org/egov/stock/service/StockService.java b/health-services/stock/src/main/java/org/egov/stock/service/StockService.java index 7876d60ac63..97ac13ff46b 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/StockService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/StockService.java @@ -1,33 +1,23 @@ package org.egov.stock.service; -import static org.egov.common.utils.CommonUtils.getIdFieldName; -import static org.egov.common.utils.CommonUtils.getIdMethod; -import static org.egov.common.utils.CommonUtils.handleErrors; -import static org.egov.common.utils.CommonUtils.havingTenantId; -import static org.egov.common.utils.CommonUtils.includeDeleted; -import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; -import static org.egov.common.utils.CommonUtils.lastChangedSince; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.common.utils.CommonUtils.validate; -import static org.egov.stock.Constants.GET_STOCK; -import static org.egov.stock.Constants.SET_STOCK; -import static org.egov.stock.Constants.VALIDATION_ERROR; - import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.Predicate; import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.StockBulkRequest; import org.egov.common.models.stock.StockRequest; +import org.egov.common.models.stock.StockSearchRequest; import org.egov.common.validator.Validator; import org.egov.stock.config.StockConfiguration; import org.egov.stock.repository.StockRepository; import org.egov.stock.service.enrichment.StockEnrichmentService; +import org.egov.stock.validator.stock.SExistentEntityValidator; import org.egov.stock.validator.stock.SIsDeletedValidator; import org.egov.stock.validator.stock.SNonExistentValidator; import org.egov.stock.validator.stock.SNullIdValidator; @@ -37,11 +27,21 @@ import org.egov.stock.validator.stock.SSenderIdReceiverIdEqualsValidator; import org.egov.stock.validator.stock.SUniqueEntityValidator; import org.egov.stock.validator.stock.StocktransferPartiesValidator; -import org.egov.stock.web.models.StockSearchRequest; import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; -import lombok.extern.slf4j.Slf4j; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.CommonUtils.validate; +import static org.egov.stock.Constants.GET_STOCK; +import static org.egov.stock.Constants.SET_STOCK; +import static org.egov.stock.Constants.VALIDATION_ERROR; @Service @@ -58,6 +58,7 @@ public class StockService { private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(SProductVariantIdValidator.class) + || validator.getClass().equals(SExistentEntityValidator.class) || validator.getClass().equals(SSenderIdReceiverIdEqualsValidator.class) || validator.getClass().equals(StocktransferPartiesValidator.class) || validator.getClass().equals(SReferenceIdValidator.class); diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SExistentEntityValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SExistentEntityValidator.java new file mode 100644 index 00000000000..2db82a921ac --- /dev/null +++ b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SExistentEntityValidator.java @@ -0,0 +1,77 @@ +package org.egov.stock.validator.stock; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.common.models.Error; +import org.egov.common.models.stock.Stock; +import org.egov.common.models.stock.StockBulkRequest; +import org.egov.common.models.stock.StockSearch; +import org.egov.common.validator.Validator; +import org.egov.stock.repository.StockRepository; +import org.springframework.util.CollectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of Stock entities with the given client reference IDs. + * This validator checks if the provided Stock entities already exist in the database based on their client reference IDs. + * + * @author kanishq-egov + */ +public class SExistentEntityValidator implements Validator { + + private final StockRepository stockRepository; + + /** + * Constructor to initialize the StockRepository dependency. + * + * @param stockRepository The repository for Stock entities. + */ + public SExistentEntityValidator(StockRepository stockRepository) { + this.stockRepository = stockRepository; + } + + /** + * Validates the existence of Stock entities with the given client reference IDs. + * + * @param request The bulk request containing Stock entities. + * @return A map containing Stock entities and their associated error details. + */ + @Override + public Map> validate(StockBulkRequest request) { + // Map to hold Stock entities and their error details + Map> errorDetailsMap = new HashMap<>(); + // Get the list of Stock entities from the request + List entities = request.getStock(); + // Extract client reference IDs from Stock entities without errors + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) + .map(Stock::getClientReferenceId) + .collect(Collectors.toList()); + // Create a search object for querying entities by client reference IDs + StockSearch stockSearch = StockSearch.builder() + .clientReferenceId(clientReferenceIdList) + .build(); + // Check if the client reference ID list is not empty + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing entities by client reference IDs + List existentEntities = stockRepository.findById( + clientReferenceIdList, + Boolean.FALSE, + getIdFieldName(stockSearch) + ); + // For each existing entity, populate error details for uniqueness + existentEntities.forEach(entity -> { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(entity, error, errorDetailsMap); + }); + } + return errorDetailsMap; + } +} diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stockreconciliation/SrExistentEntityValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stockreconciliation/SrExistentEntityValidator.java new file mode 100644 index 00000000000..e804a150db2 --- /dev/null +++ b/health-services/stock/src/main/java/org/egov/stock/validator/stockreconciliation/SrExistentEntityValidator.java @@ -0,0 +1,77 @@ +package org.egov.stock.validator.stockreconciliation; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.common.models.Error; +import org.egov.common.models.stock.StockReconciliation; +import org.egov.common.models.stock.StockReconciliationBulkRequest; +import org.egov.common.models.stock.StockReconciliationSearch; +import org.egov.common.validator.Validator; +import org.egov.stock.repository.StockReconciliationRepository; +import org.springframework.util.CollectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of StockReconciliation entities with the given client reference IDs. + * This validator checks if the provided StockReconciliation entities already exist in the database based on their client reference IDs. + * + * @author kanishq-egov + */ +public class SrExistentEntityValidator implements Validator { + + private final StockReconciliationRepository stockReconciliationRepository; + + /** + * Constructor to initialize the StockReconciliationRepository dependency. + * + * @param stockReconciliationRepository The repository for StockReconciliation entities. + */ + public SrExistentEntityValidator(StockReconciliationRepository stockReconciliationRepository) { + this.stockReconciliationRepository = stockReconciliationRepository; + } + + /** + * Validates the existence of StockReconciliation entities with the given client reference IDs. + * + * @param request The bulk request containing StockReconciliation entities. + * @return A map containing StockReconciliation entities and their associated error details. + */ + @Override + public Map> validate(StockReconciliationBulkRequest request) { + // Map to hold StockReconciliation entities and their error details + Map> errorDetailsMap = new HashMap<>(); + // Get the list of StockReconciliation entities from the request + List entities = request.getStockReconciliation(); + // Extract client reference IDs from StockReconciliation entities without errors + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) + .map(StockReconciliation::getClientReferenceId) + .collect(Collectors.toList()); + // Create a search object for querying entities by client reference IDs + StockReconciliationSearch stockReconciliationSearch = StockReconciliationSearch.builder() + .clientReferenceId(clientReferenceIdList) + .build(); + // Check if the client reference ID list is not empty + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing entities by client reference IDs + List existentEntities = stockReconciliationRepository.findById( + clientReferenceIdList, + Boolean.FALSE, + getIdFieldName(stockReconciliationSearch) + ); + // For each existing entity, populate error details for uniqueness + existentEntities.forEach(entity -> { + Error error = getErrorForUniqueEntity(); + populateErrorDetails(entity, error, errorDetailsMap); + }); + } + return errorDetailsMap; + } +} diff --git a/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockApiController.java b/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockApiController.java index 5fb0aef98b4..913213dd191 100644 --- a/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockApiController.java +++ b/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockApiController.java @@ -1,36 +1,34 @@ package org.egov.stock.web.controllers; +import java.util.List; + import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.URLParams; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.StockBulkRequest; import org.egov.common.models.stock.StockBulkResponse; import org.egov.common.models.stock.StockRequest; import org.egov.common.models.stock.StockResponse; +import org.egov.common.models.stock.StockSearchRequest; import org.egov.common.producer.Producer; import org.egov.common.utils.ResponseInfoFactory; import org.egov.stock.config.StockConfiguration; import org.egov.stock.service.StockService; -import org.egov.stock.web.models.StockSearchRequest; 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.ModelAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import java.util.List; -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") @Controller @RequestMapping("") @@ -77,13 +75,21 @@ public ResponseEntity stockV1CreatePost(@ApiParam(value = "Capture } @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) - public ResponseEntity stockV1SearchPost(@ApiParam(value = "Capture details of Stock Transfer.", required = true) @Valid @RequestBody StockSearchRequest request, @NotNull - @Min(0) @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, @NotNull - @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { - - List stock = stockService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); + public ResponseEntity stockV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Capture details of Stock Transfer.", required = true) @Valid @RequestBody StockSearchRequest stockSearchRequest + ) throws Exception { + + List stock = stockService.search( + stockSearchRequest, + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted() + ); StockBulkResponse response = StockBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).stock(stock).build(); + .createResponseInfo(stockSearchRequest.getRequestInfo(), true)).stock(stock).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockReconciliationApiController.java b/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockReconciliationApiController.java index 96633e81891..e612c3b692f 100644 --- a/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockReconciliationApiController.java +++ b/health-services/stock/src/main/java/org/egov/stock/web/controllers/StockReconciliationApiController.java @@ -1,32 +1,30 @@ package org.egov.stock.web.controllers; +import java.util.List; + import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.URLParams; import org.egov.common.models.stock.StockReconciliation; import org.egov.common.models.stock.StockReconciliationBulkRequest; import org.egov.common.models.stock.StockReconciliationBulkResponse; import org.egov.common.models.stock.StockReconciliationRequest; import org.egov.common.models.stock.StockReconciliationResponse; +import org.egov.common.models.stock.StockReconciliationSearchRequest; import org.egov.common.producer.Producer; import org.egov.common.utils.ResponseInfoFactory; import org.egov.stock.config.StockReconciliationConfiguration; import org.egov.stock.service.StockReconciliationService; -import org.egov.stock.web.models.StockReconciliationSearchRequest; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.bind.annotation.RequestParam; - -import javax.servlet.http.HttpServletRequest; -import javax.validation.Valid; -import javax.validation.constraints.Max; -import javax.validation.constraints.Min; -import javax.validation.constraints.NotNull; -import java.util.List; @Controller @RequestMapping("") @@ -74,14 +72,21 @@ public ResponseEntity stockReconciliationV1CreatePost(@ApiParam(va } @RequestMapping(value = "/reconciliation/v1/_search", method = RequestMethod.POST) - public ResponseEntity stockReconciliationV1SearchPost(@ApiParam(value = "Capture details of Stock Reconciliation.", required = true) @Valid @RequestBody StockReconciliationSearchRequest request, @NotNull - @Min(0) - @Max(1000) @ApiParam(value = "Pagination - limit records in response", required = true) @Valid @RequestParam(value = "limit", required = true) Integer limit, @NotNull - @Min(0) @ApiParam(value = "Pagination - offset from which records should be returned in response", required = true) @Valid @RequestParam(value = "offset", required = true) Integer offset, @NotNull @ApiParam(value = "Unique id for a tenant.", required = true) @Valid @RequestParam(value = "tenantId", required = true) String tenantId, @ApiParam(value = "epoch of the time since when the changes on the object should be picked up. Search results from this parameter should include both newly created objects since this time as well as any modified objects since this time. This criterion is included to help polling clients to get the changes in system since a last time they synchronized with the platform. ") @Valid @RequestParam(value = "lastChangedSince", required = false) Long lastChangedSince, @ApiParam(value = "Used in search APIs to specify if (soft) deleted records should be included in search results.", defaultValue = "false") @Valid @RequestParam(value = "includeDeleted", required = false, defaultValue = "false") Boolean includeDeleted) throws Exception { - - List stock = stockReconciliationService.search(request, limit, offset, tenantId, lastChangedSince, includeDeleted); + public ResponseEntity stockReconciliationV1SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Capture details of Stock Reconciliation.", required = true) @Valid @RequestBody StockReconciliationSearchRequest stockReconciliationSearchRequest + ) throws Exception { + + List stock = stockReconciliationService.search( + stockReconciliationSearchRequest, + urlParams.getLimit(), + urlParams.getOffset(), + urlParams.getTenantId(), + urlParams.getLastChangedSince(), + urlParams.getIncludeDeleted() + ); StockReconciliationBulkResponse response = StockReconciliationBulkResponse.builder().responseInfo(ResponseInfoFactory - .createResponseInfo(request.getRequestInfo(), true)).stockReconciliation(stock).build(); + .createResponseInfo(stockReconciliationSearchRequest.getRequestInfo(), true)).stockReconciliation(stock).build(); return ResponseEntity.status(HttpStatus.OK).body(response); } diff --git a/health-services/stock/src/main/java/org/egov/stock/web/models/StockReconciliationSearch.java b/health-services/stock/src/main/java/org/egov/stock/web/models/StockReconciliationSearch.java deleted file mode 100644 index 47aa3ea28d1..00000000000 --- a/health-services/stock/src/main/java/org/egov/stock/web/models/StockReconciliationSearch.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.egov.stock.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.data.query.annotations.Table; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.Size; -import java.util.List; - -/** - * StockReconciliationSearch - */ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -@Table(name = "stock_reconciliation_log") -public class StockReconciliationSearch { - @JsonProperty("id") - @Valid - private List id = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; - - @JsonProperty("facilityId") - @Size(min=2, max=64) - private String facilityId = null; - - @JsonProperty("productVariantId") - @Size(min=2, max=64) - private String productVariantId = null; -} - diff --git a/health-services/stock/src/main/java/org/egov/stock/web/models/StockReconciliationSearchRequest.java b/health-services/stock/src/main/java/org/egov/stock/web/models/StockReconciliationSearchRequest.java deleted file mode 100644 index e09efe6db86..00000000000 --- a/health-services/stock/src/main/java/org/egov/stock/web/models/StockReconciliationSearchRequest.java +++ /dev/null @@ -1,38 +0,0 @@ -package org.egov.stock.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.NotNull; - -/** - * StockReconciliationSearchRequest - */ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -public class StockReconciliationSearchRequest { - @JsonProperty("RequestInfo") - @NotNull - @Valid - private org.egov.common.contract.request.RequestInfo requestInfo = null; - - @JsonProperty("StockReconciliation") - @NotNull - @Valid - private StockReconciliationSearch stockReconciliation = null; - - -} - diff --git a/health-services/stock/src/main/java/org/egov/stock/web/models/StockSearch.java b/health-services/stock/src/main/java/org/egov/stock/web/models/StockSearch.java deleted file mode 100644 index 2c5e574878c..00000000000 --- a/health-services/stock/src/main/java/org/egov/stock/web/models/StockSearch.java +++ /dev/null @@ -1,71 +0,0 @@ -package org.egov.stock.web.models; - -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.Data; -import lombok.NoArgsConstructor; -import org.egov.common.data.query.annotations.Table; -import org.egov.common.models.stock.TransactionReason; -import org.egov.common.models.stock.TransactionType; -import org.springframework.validation.annotation.Validated; - -import javax.validation.Valid; -import javax.validation.constraints.Size; -import java.util.List; - -/** - * StockSearch - */ -@Validated -@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2023-02-08T11:49:06.320+05:30") - -@Data -@NoArgsConstructor -@AllArgsConstructor -@Builder -@JsonIgnoreProperties(ignoreUnknown = true) -@Table(name="stock") -public class StockSearch { - - @JsonProperty("id") - private List id = null; - - @JsonProperty("clientReferenceId") - private List clientReferenceId = null; - - @JsonProperty("facilityId") - @Size(min=2, max=64) - private String facilityId = null; - - @JsonProperty("productVariantId") - @Size(min=2, max=64) - private String productVariantId = null; - - @JsonProperty("referenceId") - private String referenceId = null; - - @JsonProperty("wayBillNumber") - private String wayBillNumber = null; - - @JsonProperty("referenceIdType") - @Size(min=2, max=64) - private String referenceIdType = null; - - @JsonProperty("transactionType") - @Valid - private TransactionType transactionType = null; - - @JsonProperty("transactionReason") - @Valid - private TransactionReason transactionReason = null; - - @JsonProperty("transactingPartyId") - @Size(min=2, max=64) - private String transactingPartyId = null; - - @JsonProperty("transactingPartyType") - private String transactingPartyType = null; -} - diff --git a/health-services/stock/src/main/resources/application.properties b/health-services/stock/src/main/resources/application.properties index 5f192d7bdf8..47372ce87b1 100644 --- a/health-services/stock/src/main/resources/application.properties +++ b/health-services/stock/src/main/resources/application.properties @@ -65,6 +65,7 @@ egov.user.integration.enabled=true egov.user.host=https://dev.digit.org egov.user.context.path=/user/users egov.create.user.path=/_createnovalidate +egov.create.user.url=/_createnovalidate egov.search.user.url=/user/_search egov.update.user.url=/_updatenovalidate diff --git a/health-services/stock/src/test/java/org/egov/stock/helper/StockReconciliationTestBuilder.java b/health-services/stock/src/test/java/org/egov/stock/helper/StockReconciliationTestBuilder.java index d7cfc4c247d..e841f6af674 100644 --- a/health-services/stock/src/test/java/org/egov/stock/helper/StockReconciliationTestBuilder.java +++ b/health-services/stock/src/test/java/org/egov/stock/helper/StockReconciliationTestBuilder.java @@ -1,15 +1,16 @@ package org.egov.stock.helper; import org.egov.common.helper.AuditDetailsTestBuilder; +import org.egov.common.models.household.Household; import org.egov.common.models.stock.StockReconciliation; public class StockReconciliationTestBuilder { - private final StockReconciliation.StockReconciliationBuilder builder; + private final StockReconciliation.StockReconciliationBuilder builder; public StockReconciliationTestBuilder() { - this.builder = StockReconciliation.builder(); + this.builder = (StockReconciliation.StockReconciliationBuilder) StockReconciliation.builder(); } public static StockReconciliationTestBuilder builder() { diff --git a/health-services/stock/src/test/java/org/egov/stock/helper/StockTestBuilder.java b/health-services/stock/src/test/java/org/egov/stock/helper/StockTestBuilder.java index fd83333e42e..7499c8e92f4 100644 --- a/health-services/stock/src/test/java/org/egov/stock/helper/StockTestBuilder.java +++ b/health-services/stock/src/test/java/org/egov/stock/helper/StockTestBuilder.java @@ -10,10 +10,10 @@ public class StockTestBuilder { - private final Stock.StockBuilder builder; + private final Stock.StockBuilder builder; public StockTestBuilder() { - this.builder = Stock.builder(); + this.builder = (Stock.StockBuilder) Stock.builder(); } public static StockTestBuilder builder() { diff --git a/health-services/transformer/CHANGELOG.md b/health-services/transformer/CHANGELOG.md index 645e12b40e1..1d11977c2a5 100644 --- a/health-services/transformer/CHANGELOG.md +++ b/health-services/transformer/CHANGELOG.md @@ -1,7 +1,16 @@ All notable changes to this module will be documented in this file. +## 1.1.2 - 2024-05-29 +- Integrated Core 2.9LTS +- Upgraded to health models 1.0.20 and health common 1.0.16 +- Boundary v2 Integration +- MDMS v2 integration + +## 1.1.1 - 2024-05-10 +- Integrated Boundary v2 functionality + ## 1.0.0 - Base version -## 1.1.0 \ No newline at end of file +## 1.1.0 diff --git a/health-services/transformer/pom.xml b/health-services/transformer/pom.xml index ea3bb03ab4b..a38c13d9583 100644 --- a/health-services/transformer/pom.xml +++ b/health-services/transformer/pom.xml @@ -5,16 +5,17 @@ transformer jar transformer - 1.1.0 + 1.1.2 - 1.8 + 17 ${java.version} ${java.version} + 1.18.22 org.springframework.boot spring-boot-starter-parent - 2.2.6.RELEASE + 3.2.2 src/main/java @@ -46,6 +47,7 @@ org.projectlombok lombok + ${lombok.version} true @@ -57,22 +59,34 @@ org.egov.common health-services-models - 1.0.6-SNAPSHOT + 1.0.20-SNAPSHOT + compile + + + org.egov.common + health-services-common + 1.0.16-SNAPSHOT compile org.egov.services tracer - 2.1.4-SNAPSHOT + 2.9.0-SNAPSHOT - com.fasterxml.jackson.datatype - jackson-datatype-jsr310 + org.postgresql + postgresql + 42.7.1 - - javax.validation - validation-api + junit + junit + 4.13.2 + test + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 diff --git a/health-services/transformer/src/main/java/org/egov/transformer/boundary/BoundaryMapper.java b/health-services/transformer/src/main/java/org/egov/transformer/boundary/BoundaryMapper.java index b9b0f2b0ee3..e6fbfbd4eb8 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/boundary/BoundaryMapper.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/boundary/BoundaryMapper.java @@ -1,17 +1,16 @@ package org.egov.transformer.boundary; -import org.egov.common.models.transformer.upstream.Boundary; +import org.egov.common.models.core.Boundary; public class BoundaryMapper { public static BoundaryNode from(Boundary boundary) { return BoundaryNode.builder() - .name(boundary.getName()) + .id(boundary.getId()) .code(boundary.getCode()) - .label(boundary.getLabel()) - .latitude(boundary.getLatitude()) - .longitude(boundary.getLongitude()) + .tenantId(boundary.getTenantId()) + .geometry(boundary.getGeometry()) .build(); } diff --git a/health-services/transformer/src/main/java/org/egov/transformer/boundary/BoundaryNode.java b/health-services/transformer/src/main/java/org/egov/transformer/boundary/BoundaryNode.java index f9189e869a1..72e14c5b9ed 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/boundary/BoundaryNode.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/boundary/BoundaryNode.java @@ -1,5 +1,6 @@ package org.egov.transformer.boundary; +import com.fasterxml.jackson.databind.JsonNode; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -10,9 +11,8 @@ @NoArgsConstructor @Builder public class BoundaryNode { + private String id; + private String tenantId; private String code; - private String name; - private String label; - private String latitude; - private String longitude; + private JsonNode geometry; } diff --git a/health-services/transformer/src/main/java/org/egov/transformer/boundary/TreeGenerator.java b/health-services/transformer/src/main/java/org/egov/transformer/boundary/TreeGenerator.java deleted file mode 100644 index 4a96ed10f95..00000000000 --- a/health-services/transformer/src/main/java/org/egov/transformer/boundary/TreeGenerator.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.egov.transformer.boundary; - - -import org.egov.common.models.transformer.upstream.Boundary; -import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.List; - -@Component -public class TreeGenerator { - - - public BoundaryTree generateTree(Boundary boundary) { - BoundaryTree boundaryTree = new BoundaryTree(); - boundaryTree.setBoundaryNode(BoundaryMapper.from(boundary)); - if (boundary.getChildren() != null && !boundary.getChildren().isEmpty()) { - List boundaryTrees = new ArrayList<>(); - boundaryTree.setBoundaryTrees(boundaryTrees); - for (Boundary child : boundary.getChildren()) { - BoundaryTree resultTree = generateTree(child); - resultTree.setParent(boundaryTree); - boundaryTrees.add(resultTree); - } - } - return boundaryTree; - } - - public BoundaryTree search(BoundaryTree boundaryTree, String code) { - if (code.equals(boundaryTree.getBoundaryNode().getCode())) { - return boundaryTree; - } - BoundaryTree bt = null; - if (boundaryTree.getBoundaryTrees() != null && !boundaryTree.getBoundaryTrees().isEmpty()) { - for (BoundaryTree child : boundaryTree.getBoundaryTrees()) { - bt = search(child, code); - if (bt != null) { - break; - } - } - } - return bt; - } -} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java b/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java index 9c7debc9f31..050c1ea7217 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/config/MainConfiguration.java @@ -1,5 +1,10 @@ package org.egov.transformer.config; +import java.util.List; +import java.util.Map; +import java.util.TimeZone; +import java.util.stream.Collectors; + import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.PropertyAccessor; @@ -7,6 +12,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import jakarta.annotation.PostConstruct; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.project.Project; import org.egov.common.models.project.ProjectStaff; @@ -23,14 +29,14 @@ import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.RedisStandaloneConfiguration; +import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; -import javax.annotation.PostConstruct; -import java.util.List; -import java.util.Map; -import java.util.TimeZone; -import java.util.stream.Collectors; - @Import({TracerConfiguration.class}) @Configuration @ComponentScan(basePackages = {"org.egov"}) @@ -40,6 +46,9 @@ public class MainConfiguration { @Value("${app.timezone}") private String timeZone; + @Value("${spring.redis.host}") + private String redisHost; + @PostConstruct public void initialize() { TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); @@ -130,4 +139,26 @@ public Map>> getOperationTransfor log.info(map.toString()); return map; } + + @Bean + public RedisConnectionFactory redisConnectionFactory() { + RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(); + redisStandaloneConfiguration.setHostName(redisHost); + return new JedisConnectionFactory(redisStandaloneConfiguration); + } + + @Bean + public RedisTemplate redisTemplate(@Qualifier("redisObjectMapper") ObjectMapper redisObjectMapper, + RedisConnectionFactory redisConnectionFactory) { + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(redisObjectMapper, Object.class); + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(serializer); + redisTemplate.setHashKeySerializer(new StringRedisSerializer()); + redisTemplate.setHashValueSerializer(serializer); + redisTemplate.afterPropertiesSet(); + return redisTemplate; + } + } \ No newline at end of file diff --git a/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java b/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java index 2801294e64f..1a577a98fb7 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/config/TransformerProperties.java @@ -74,5 +74,16 @@ public class TransformerProperties { @Value("${boundary.label.name.administrativeProvince}") private String administrativeProvince; + @Value("${egov.boundary.host}") + private String boundaryServiceHost; + + @Value("${egov.boundary.search.url}") + private String boundarySearchUrl; + + @Value("${egov.boundary.relationship.search.url}") + private String boundaryRelationshipSearchUrl; + + @Value("${egov.boundary.hierarchy.name}") + private String boundaryHierarchyName; } diff --git a/health-services/transformer/src/main/java/org/egov/transformer/http/client/ServiceRequestClient.java b/health-services/transformer/src/main/java/org/egov/transformer/http/client/ServiceRequestClient.java index edde27c1486..b3a36bcb10b 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/http/client/ServiceRequestClient.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/http/client/ServiceRequestClient.java @@ -11,7 +11,7 @@ import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; -@Repository +//@Repository @Slf4j public class ServiceRequestClient { diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundaryRequest.java b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundaryRequest.java new file mode 100644 index 00000000000..3e128bcd434 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundaryRequest.java @@ -0,0 +1,38 @@ +package org.egov.transformer.models.boundary; + +import java.util.List; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.core.Boundary; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryRequest + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryRequest { + + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @Valid + @NotNull + @JsonProperty("Boundary") + @Size(min = 1, max = 300) + private List boundary = null; + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundaryResponse.java b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundaryResponse.java new file mode 100644 index 00000000000..afcdfa94736 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundaryResponse.java @@ -0,0 +1,44 @@ +package org.egov.transformer.models.boundary; + +import java.util.ArrayList; +import java.util.List; +import jakarta.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.Boundary; +import org.springframework.validation.annotation.Validated; + +/** + * BoundaryResponse + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundaryResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("Boundary") + @Valid + private List boundary = null; + + + public BoundaryResponse addBoundaryItem(Boundary boundaryItem) { + if (this.boundary == null) { + this.boundary = new ArrayList<>(); + } + this.boundary.add(boundaryItem); + return this; + } + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundarySearchCriteria.java b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundarySearchCriteria.java new file mode 100644 index 00000000000..cfcd2c81732 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundarySearchCriteria.java @@ -0,0 +1,37 @@ +package org.egov.transformer.models.boundary; + +import java.util.List; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundarySearchCriteria { + + @NotNull + @Size(min = 1) + @JsonProperty("codes") + private List codes; + + @NotNull + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundarySearchResponse.java b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundarySearchResponse.java new file mode 100644 index 00000000000..244af7e5a27 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/BoundarySearchResponse.java @@ -0,0 +1,33 @@ +package org.egov.transformer.models.boundary; + +import java.util.List; +import jakarta.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +/** + * BoundarySearchResponse + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundarySearchResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("TenantBoundary") + @Valid + private List tenantBoundary = null; + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/EnrichedBoundary.java b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/EnrichedBoundary.java new file mode 100644 index 00000000000..8b85a96e3a5 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/EnrichedBoundary.java @@ -0,0 +1,43 @@ +package org.egov.transformer.models.boundary; + +import java.util.List; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * EnrichedBoundary + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class EnrichedBoundary { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("code") + @NotNull + private String code = null; + + @JsonProperty("boundaryType") + private String boundaryType = null; + + @JsonProperty("children") + @Valid + private List children = null; + + @JsonIgnore + private String parent = null; + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/HierarchyRelation.java b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/HierarchyRelation.java new file mode 100644 index 00000000000..b1faf8f5f98 --- /dev/null +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/boundary/HierarchyRelation.java @@ -0,0 +1,34 @@ +package org.egov.transformer.models.boundary; + +import java.util.List; +import jakarta.validation.Valid; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * HierarchyRelation + */ +@Validated + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class HierarchyRelation { + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("hierarchyType") + private String hierarchyType = null; + + @JsonProperty("boundary") + @Valid + private List boundary = null; + +} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/producer/Producer.java b/health-services/transformer/src/main/java/org/egov/transformer/producer/Producer.java index 009ccc4c089..0d5eef066df 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/producer/Producer.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/producer/Producer.java @@ -7,7 +7,7 @@ // NOTE: If tracer is disabled change CustomKafkaTemplate to KafkaTemplate in autowiring -@Service + @Slf4j public class Producer { diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/BoundaryService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/BoundaryService.java deleted file mode 100644 index 61591ce91c2..00000000000 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/BoundaryService.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.egov.transformer.service; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.jayway.jsonpath.Configuration; -import com.jayway.jsonpath.DocumentContext; -import com.jayway.jsonpath.JsonPath; -import com.jayway.jsonpath.Option; -import lombok.extern.slf4j.Slf4j; -import net.minidev.json.JSONArray; -import net.minidev.json.JSONObject; -import org.egov.common.contract.request.RequestInfo; -import org.egov.common.models.transformer.upstream.Boundary; -import org.egov.tracer.model.CustomException; -import org.egov.transformer.boundary.BoundaryTree; -import org.egov.transformer.boundary.TreeGenerator; -import org.egov.transformer.config.TransformerProperties; -import org.egov.transformer.http.client.ServiceRequestClient; -import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; - -import java.util.Arrays; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -@Component -@Slf4j -public class BoundaryService { - - private final TransformerProperties transformerProperties; - - private final ServiceRequestClient serviceRequestClient; - - private final ObjectMapper objectMapper; - - private final TreeGenerator treeGenerator; - - private static final Map> boundaryListMap = new ConcurrentHashMap<>(); - - public BoundaryService(TransformerProperties transformerProperties, - ServiceRequestClient serviceRequestClient, - ObjectMapper objectMapper, TreeGenerator treeGenerator) { - this.transformerProperties = transformerProperties; - this.serviceRequestClient = serviceRequestClient; - this.objectMapper = objectMapper; - this.treeGenerator = treeGenerator; - } - - public List getBoundary(String code, String hierarchyTypeCode, String tenantId) { - if (boundaryListMap.containsKey(code)) { - log.info("getting boudary data for code {} from cache", code); - return boundaryListMap.get(code); - } - List boundaryList = searchBoundary(code, hierarchyTypeCode, tenantId); - if (!boundaryList.isEmpty()) { - boundaryListMap.put(code, boundaryList); - } else { - boundaryList = Collections.emptyList(); - } - return boundaryList; - } - - public BoundaryTree generateTree(Boundary boundary) { - return treeGenerator.generateTree(boundary); - } - - public BoundaryTree search(BoundaryTree boundaryTree, String code) { - return treeGenerator.search(boundaryTree, code); - } - - private List searchBoundary(String code, String hierarchyTypeCode, String tenantId) { - - LinkedHashMap response; - try { - StringBuilder uri = new StringBuilder(); - uri.append(transformerProperties.getLocationHost()) - .append(transformerProperties.getLocationSearchUrl()) - .append("?limit=").append(transformerProperties.getSearchApiLimit()) - .append("&offset=0") - .append("&tenantId=").append(tenantId); - if (hierarchyTypeCode != null) { - uri.append("&hierarchyTypeCode=").append(hierarchyTypeCode); - } - uri.append("&code=").append(code); - response = serviceRequestClient.fetchResult(uri, - RequestInfo.builder().build(), - LinkedHashMap.class); - } catch (Exception e) { - log.error("error while calling boundary service", e); - throw new CustomException("BOUNDARY_ERROR", "error while calling boundary service"); - } - if (response != null) { - if (CollectionUtils.isEmpty(response)) { - log.error("empty response received from boundary service"); - throw new CustomException("BOUNDARY_ERROR", "the response from location service is empty or null"); - } - Configuration cf = Configuration.builder().options(Option.ALWAYS_RETURN_LIST).build(); - String jsonString = new JSONObject(response).toString(); - DocumentContext context = JsonPath.using(cf).parse(jsonString); - JSONArray jsonArray = context.read("$.TenantBoundary[?(@.hierarchyType.code == 'ADMIN')].boundary"); - if (jsonArray != null) { - String str = jsonArray.get(0).toString(); - try { - return Arrays.asList(objectMapper - .readValue(str, - Boundary[].class)); - } catch (JsonProcessingException e) { - log.error("error in paring json", e); - throw new CustomException("JSON_ERROR", "error in parsing json"); - } - } - log.warn("boundary list is empty"); - } - return Collections.emptyList(); - } -} diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/FacilityService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/FacilityService.java index 17caf3ec5da..91f8a4aa68c 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/FacilityService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/FacilityService.java @@ -1,5 +1,11 @@ package org.egov.transformer.service; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; @@ -9,15 +15,9 @@ import org.egov.common.models.facility.FacilitySearch; import org.egov.common.models.facility.FacilitySearchRequest; import org.egov.transformer.config.TransformerProperties; -import org.egov.transformer.http.client.ServiceRequestClient; +import org.egov.common.http.client.ServiceRequestClient; import org.springframework.stereotype.Service; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - @Service @Slf4j public class FacilityService { diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/MdmsService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/MdmsService.java index 7599cd82242..f29309f74de 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/MdmsService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/MdmsService.java @@ -2,7 +2,7 @@ import lombok.extern.slf4j.Slf4j; import org.egov.tracer.model.CustomException; -import org.egov.transformer.http.client.ServiceRequestClient; +import org.egov.common.http.client.ServiceRequestClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectIndexV1TransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectIndexV1TransformationService.java index 674d2ccdbe6..62b453eaf66 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectIndexV1TransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectIndexV1TransformationService.java @@ -3,7 +3,7 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.project.Project; import org.egov.transformer.config.TransformerProperties; -import org.egov.transformer.producer.Producer; +import org.egov.common.producer.Producer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectService.java index 3853e41b460..603906733c7 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectService.java @@ -1,5 +1,14 @@ package org.egov.transformer.service; +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Deque; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; @@ -14,20 +23,13 @@ import org.egov.common.models.project.Project; import org.egov.common.models.project.ProjectRequest; import org.egov.common.models.project.ProjectResponse; -import org.egov.common.models.transformer.upstream.Boundary; import org.egov.tracer.model.CustomException; -import org.egov.transformer.boundary.BoundaryNode; -import org.egov.transformer.boundary.BoundaryTree; import org.egov.transformer.config.TransformerProperties; -import org.egov.transformer.http.client.ServiceRequestClient; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.transformer.models.boundary.BoundarySearchResponse; +import org.egov.transformer.models.boundary.EnrichedBoundary; import org.springframework.stereotype.Component; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; -import java.util.stream.Collectors; +import org.springframework.util.CollectionUtils; import static org.egov.transformer.Constants.INTERNAL_SERVER_ERROR; import static org.egov.transformer.Constants.MDMS_RESPONSE; @@ -43,19 +45,16 @@ public class ProjectService { private final ObjectMapper objectMapper; - private final BoundaryService boundaryService; - private final MdmsService mdmsService; private static final Map projectMap = new ConcurrentHashMap<>(); public ProjectService(TransformerProperties transformerProperties, ServiceRequestClient serviceRequestClient, - ObjectMapper objectMapper, BoundaryService boundaryService, MdmsService mdmsService) { + ObjectMapper objectMapper, MdmsService mdmsService) { this.transformerProperties = transformerProperties; this.serviceRequestClient = serviceRequestClient; this.objectMapper = objectMapper; - this.boundaryService = boundaryService; this.mdmsService = mdmsService; } @@ -92,24 +91,73 @@ public Project getProjectByName(String projectName, String tenantId) { return project; } - public Map getBoundaryLabelToNameMapByProjectId(String projectId, String tenantId) { + public Map getBoundaryCodeToNameMapByProjectId(String projectId, String tenantId) { Project project = getProject(projectId, tenantId); String locationCode = project.getAddress().getBoundary(); - return getBoundaryLabelToNameMap(locationCode, tenantId); + return getBoundaryCodeToNameMap(locationCode, tenantId); } - public Map getBoundaryLabelToNameMap(String locationCode, String tenantId) { - List boundaryList = boundaryService.getBoundary(locationCode, "ADMIN", - tenantId); - BoundaryTree boundaryTree = boundaryService.generateTree(boundaryList.get(0)); - BoundaryTree locationTree = boundaryService.search(boundaryTree, locationCode); - List parentNodes = locationTree.getParentNodes(); - Map resultMap = parentNodes.stream().collect(Collectors - .toMap(BoundaryNode::getLabel, BoundaryNode::getName)); - resultMap.put(locationTree.getBoundaryNode().getLabel(), locationTree.getBoundaryNode().getName()); - return resultMap; + public Map getBoundaryCodeToNameMap(String locationCode, String tenantId) { + List boundaries = new ArrayList<>(); + try { + // Fetch boundary details from the service + log.debug("Fetching boundary relation details for tenantId: {}, boundary: {}", tenantId, locationCode); + BoundarySearchResponse boundarySearchResponse = serviceRequestClient.fetchResult( + new StringBuilder(transformerProperties.getBoundaryServiceHost() + + transformerProperties.getBoundaryRelationshipSearchUrl() + +"?includeParents=true&tenantId=" + tenantId + + "&hierarchyType=" + transformerProperties.getBoundaryHierarchyName() + + "&codes=" + locationCode), + RequestInfo.builder().build(), + BoundarySearchResponse.class + ); + log.debug("Boundary Relationship details fetched successfully for tenantId: {}", tenantId); + + List enrichedBoundaries = boundarySearchResponse.getTenantBoundary().stream() + .filter(hierarchyRelation -> !CollectionUtils.isEmpty(hierarchyRelation.getBoundary())) + .flatMap(hierarchyRelation -> hierarchyRelation.getBoundary().stream()) + .collect(Collectors.toList()); + + getAllBoundaryCodes(enrichedBoundaries, boundaries); + + } catch (Exception e) { + log.error("Exception while searching boundaries for tenantId: {}", tenantId, e); + // Throw a custom exception if an error occurs during boundary search + throw new CustomException("BOUNDARY_SEARCH_ERROR", e.getMessage()); + } + + return boundaries.stream() + .collect(Collectors.toMap( + EnrichedBoundary::getBoundaryType, + boundary -> boundary.getCode().substring(boundary.getCode().lastIndexOf('_') + 1) + )); } + private void getAllBoundaryCodes(List enrichedBoundaries, List boundaries) { + if (enrichedBoundaries == null || enrichedBoundaries.isEmpty()) { + return; + } + + for (EnrichedBoundary root : enrichedBoundaries) { + if (root != null) { + Deque stack = new ArrayDeque<>(); + stack.push(root); + + while (!stack.isEmpty()) { + EnrichedBoundary current = stack.pop(); + if (current != null) { + boundaries.add(current); + if (current.getChildren() != null) { + stack.addAll(current.getChildren()); + } + } + } + } + } + } + + + private List searchProjectByName(String projectName, String tenantId) { ProjectRequest request = ProjectRequest.builder() diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectStaffIndexV1TransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectStaffIndexV1TransformationService.java index 199ef6d248c..b9f9f68109c 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectStaffIndexV1TransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectStaffIndexV1TransformationService.java @@ -3,7 +3,7 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.project.ProjectStaff; import org.egov.transformer.config.TransformerProperties; -import org.egov.transformer.producer.Producer; +import org.egov.common.producer.Producer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectStaffTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectStaffTransformationService.java index 9527ee5848a..d4966a6512f 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectStaffTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectStaffTransformationService.java @@ -5,7 +5,7 @@ import org.egov.transformer.config.TransformerProperties; import org.egov.transformer.enums.Operation; import org.egov.transformer.models.downstream.ProjectStaffIndexV1; -import org.egov.transformer.producer.Producer; +import org.egov.common.producer.Producer; import org.egov.transformer.service.transformer.Transformer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -67,7 +67,7 @@ static class ProjectStaffIndexV1Transformer implements @Override public List transform(ProjectStaff projectStaff) { Map boundaryLabelToNameMap = projectService - .getBoundaryLabelToNameMapByProjectId(projectStaff.getProjectId(), projectStaff.getTenantId()); + .getBoundaryCodeToNameMapByProjectId(projectStaff.getProjectId(), projectStaff.getTenantId()); log.info("boundary labels {}", boundaryLabelToNameMap.toString()); return Collections.singletonList(ProjectStaffIndexV1.builder() .id(projectStaff.getId()) diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskIndexV1TransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskIndexV1TransformationService.java index 4d94b935419..87b877472b9 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskIndexV1TransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskIndexV1TransformationService.java @@ -3,7 +3,7 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.project.Task; import org.egov.transformer.config.TransformerProperties; -import org.egov.transformer.producer.Producer; +import org.egov.common.producer.Producer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java index d4aa3898406..286b416649f 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java @@ -5,7 +5,7 @@ import org.egov.transformer.config.TransformerProperties; import org.egov.transformer.enums.Operation; import org.egov.transformer.models.downstream.ProjectTaskIndexV1; -import org.egov.transformer.producer.Producer; +import org.egov.common.producer.Producer; import org.egov.transformer.service.transformer.Transformer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -68,10 +68,10 @@ public List transform(Task task) { Map boundaryLabelToNameMap = null; if (task.getAddress().getLocality() != null && task.getAddress().getLocality().getCode() != null) { boundaryLabelToNameMap = projectService - .getBoundaryLabelToNameMap(task.getAddress().getLocality().getCode(), task.getTenantId()); + .getBoundaryCodeToNameMap(task.getAddress().getLocality().getCode(), task.getTenantId()); } else { boundaryLabelToNameMap = projectService - .getBoundaryLabelToNameMapByProjectId(task.getProjectId(), task.getTenantId()); + .getBoundaryCodeToNameMapByProjectId(task.getProjectId(), task.getTenantId()); } log.info("boundary labels {}", boundaryLabelToNameMap.toString()); Map finalBoundaryLabelToNameMap = boundaryLabelToNameMap; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTransformationService.java index fae2d3667f8..a9e1d11dde7 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTransformationService.java @@ -6,7 +6,7 @@ import org.egov.transformer.config.TransformerProperties; import org.egov.transformer.enums.Operation; import org.egov.transformer.models.downstream.ProjectIndexV1; -import org.egov.transformer.producer.Producer; +import org.egov.common.producer.Producer; import org.egov.transformer.service.transformer.Transformer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -70,7 +70,7 @@ static class ProjectIndexV1Transformer implements @Override public List transform(Project project) { Map boundaryLabelToNameMap = projectService - .getBoundaryLabelToNameMap(project.getAddress().getBoundary(), project.getTenantId()); + .getBoundaryCodeToNameMap(project.getAddress().getBoundary(), project.getTenantId()); log.info("boundary labels {}", boundaryLabelToNameMap.toString()); List targets = project.getTargets(); if (targets == null || targets.isEmpty()) { diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceDefinitionService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceDefinitionService.java index 012d95c4687..ef694f513f8 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceDefinitionService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceDefinitionService.java @@ -1,22 +1,22 @@ package org.egov.transformer.service; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + import lombok.extern.slf4j.Slf4j; import org.egov.common.contract.request.RequestInfo; import org.egov.common.contract.request.User; import org.egov.tracer.model.CustomException; import org.egov.transformer.config.TransformerProperties; -import org.egov.transformer.http.client.ServiceRequestClient; +import org.egov.common.http.client.ServiceRequestClient; import org.egov.transformer.models.upstream.ServiceDefinition; import org.egov.transformer.models.upstream.ServiceDefinitionCriteria; import org.egov.transformer.models.upstream.ServiceDefinitionResponse; import org.egov.transformer.models.upstream.ServiceDefinitionSearchRequest; import org.springframework.stereotype.Component; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - @Component @Slf4j public class ServiceDefinitionService { diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskIndexV1TransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskIndexV1TransformationService.java index 859cf0f63a6..403756acfe6 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskIndexV1TransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskIndexV1TransformationService.java @@ -3,7 +3,7 @@ import lombok.extern.slf4j.Slf4j; import org.egov.transformer.config.TransformerProperties; import org.egov.transformer.models.upstream.Service; -import org.egov.transformer.producer.Producer; +import org.egov.common.producer.Producer; import org.springframework.stereotype.Component; import java.util.List; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java index 4bdb2ddfd6c..3d743e98750 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ServiceTaskTransformationService.java @@ -7,7 +7,7 @@ import org.egov.transformer.models.downstream.ServiceIndexV1; import org.egov.transformer.models.upstream.Service; import org.egov.transformer.models.upstream.ServiceDefinition; -import org.egov.transformer.producer.Producer; +import org.egov.common.producer.Producer; import org.egov.transformer.service.transformer.Transformer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -77,7 +77,7 @@ public List transform(Service service) { String projectName = parts[0]; String supervisorLevel = parts[2]; String projectId = projectService.getProjectByName(projectName, service.getTenantId()).getId(); - Map boundaryLabelToNameMap = projectService.getBoundaryLabelToNameMapByProjectId(projectId, service.getTenantId()); + Map boundaryLabelToNameMap = projectService.getBoundaryCodeToNameMapByProjectId(projectId, service.getTenantId()); log.info("boundary labels {}", boundaryLabelToNameMap.toString()); return Collections.singletonList(ServiceIndexV1.builder() diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/StockIndexV1TransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/StockIndexV1TransformationService.java index 268ce898c8c..e0b4ac41750 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/StockIndexV1TransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/StockIndexV1TransformationService.java @@ -3,7 +3,7 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.stock.Stock; import org.egov.transformer.config.TransformerProperties; -import org.egov.transformer.producer.Producer; +import org.egov.common.producer.Producer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java index 2044dbe1658..7bc8e963fc0 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/StockTransformationService.java @@ -2,11 +2,13 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.models.facility.Facility; +import org.egov.common.models.stock.ReferenceIdType; +import org.egov.common.models.stock.SenderReceiverType; import org.egov.common.models.stock.Stock; import org.egov.transformer.config.TransformerProperties; import org.egov.transformer.enums.Operation; import org.egov.transformer.models.downstream.StockIndexV1; -import org.egov.transformer.producer.Producer; +import org.egov.common.producer.Producer; import org.egov.transformer.service.transformer.Transformer; import org.springframework.stereotype.Component; @@ -74,22 +76,25 @@ static class StockIndexV1Transformer implements @Override public List transform(Stock stock) { Map boundaryLabelToNameMap = null; - Facility facility = facilityService.findFacilityById(stock.getFacilityId(), stock.getTenantId()); - if (facility.getAddress().getLocality() != null && facility.getAddress().getLocality().getCode() != null) { + Facility facility = null; + if (stock.getSenderType().equals(SenderReceiverType.WAREHOUSE)) { + facility = facilityService.findFacilityById(stock.getSenderId(), stock.getTenantId()); + } + if (facility != null && facility.getAddress().getLocality() != null && facility.getAddress().getLocality().getCode() != null) { boundaryLabelToNameMap = projectService - .getBoundaryLabelToNameMap(facility.getAddress().getLocality().getCode(), stock.getTenantId()); + .getBoundaryCodeToNameMap(facility.getAddress().getLocality().getCode(), stock.getTenantId()); } else { - if (stock.getReferenceIdType().equals(PROJECT)) { + if (stock.getReferenceIdType().equals(ReferenceIdType.PROJECT)) { boundaryLabelToNameMap = projectService - .getBoundaryLabelToNameMapByProjectId(stock.getReferenceId(), stock.getTenantId()); + .getBoundaryCodeToNameMapByProjectId(stock.getReferenceId(), stock.getTenantId()); } } return Collections.singletonList(StockIndexV1.builder() .id(stock.getId()) .productVariant(stock.getProductVariantId()) - .facilityId(stock.getFacilityId()) - .facilityName(facility.getName()) + .facilityId(stock.getSenderId()) + .facilityName(facility != null ? facility.getName() : stock.getSenderId()) .physicalCount(stock.getQuantity()) .eventType(stock.getTransactionType()) .reason(stock.getTransactionReason()) diff --git a/health-services/transformer/src/main/resources/application.properties b/health-services/transformer/src/main/resources/application.properties index bfa6972506b..cab2e828256 100644 --- a/health-services/transformer/src/main/resources/application.properties +++ b/health-services/transformer/src/main/resources/application.properties @@ -102,4 +102,10 @@ boundary.label.name.province="Province" boundary.label.name.district="District" boundary.label.name.administrativeProvince="AdministrativeProvince" boundary.label.name.locality="Locality" -boundary.label.name.village="Village" \ No newline at end of file +boundary.label.name.village="Village" + +# BOUNDARY SERVICE +egov.boundary.host=http://localhost:8081 +egov.boundary.search.url=/boundary-service/boundary/_search +egov.boundary.relationship.search.url=/boundary-service/boundary-relationships/_search +egov.boundary.hierarchy.name=HCM-Moz-Hierarchy diff --git a/health-services/transformer/src/test/java/org/egov/transformer/location/TreeGeneratorTest.java b/health-services/transformer/src/test/java/org/egov/transformer/location/TreeGeneratorTest.java deleted file mode 100644 index 438bc1c70d7..00000000000 --- a/health-services/transformer/src/test/java/org/egov/transformer/location/TreeGeneratorTest.java +++ /dev/null @@ -1,169 +0,0 @@ -package org.egov.transformer.location; - -import lombok.extern.slf4j.Slf4j; -import org.egov.common.models.transformer.upstream.Boundary; -import org.egov.transformer.boundary.BoundaryNode; -import org.egov.transformer.boundary.BoundaryTree; -import org.egov.transformer.boundary.TreeGenerator; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -@Slf4j -class TreeGeneratorTest { - - private TreeGenerator treeGenerator; - - @BeforeEach - void setUp() { - treeGenerator = new TreeGenerator(); - } - - private static List getTestBoundaryList() { - List boundaryList = new ArrayList<>(); - boundaryList.add(Boundary.builder() - .code("LC00001") - .name("Tete") - .label("Province") - .children(Arrays.asList(Boundary.builder() - .code("LC00002") - .name("Angónia") - .label("District") - .children(Arrays.asList(Boundary.builder() - .code("LC00003") - .name("Ulongué") - .label("AdministrativeProvince") - .children(Arrays.asList(Boundary.builder() - .code("LC00004") - .name("TAU L1") - .label("Locality") - .build(), - Boundary.builder() - .code("LC00007") - .name("TAU L2 V1") - .label("Village") - .children(Arrays.asList()) - .build())) - .build(), - Boundary.builder() - .code("LC000010") - .name("Dómuè") - .label("AdministrativeProvince") - .build())) - .build())) - .build()); - return boundaryList; - } - - @Test - void shouldGenerateATreeWithNodeHavingNoChildren() { - List boundaryList = new ArrayList<>(); - boundaryList.add(Boundary.builder() - .code("LC00001") - .name("Tete") - .label("Province") - .build()); - BoundaryTree boundaryTree = treeGenerator.generateTree(boundaryList.get(0)); - assertEquals("LC00001", boundaryTree.getBoundaryNode().getCode()); - assertNull(boundaryTree.getParent()); - assertNull(boundaryTree.getBoundaryTrees()); - } - - @Test - void shouldGenerateATreeWithNodeHavingOneChild() { - List boundaryList = new ArrayList<>(); - boundaryList.add(Boundary.builder() - .code("LC00001") - .name("Tete") - .label("Province") - .children(Arrays.asList(Boundary.builder() - .code("LC00002") - .name("Angónia") - .label("District") - .build())) - .build()); - BoundaryTree boundaryTree = treeGenerator.generateTree(boundaryList.get(0)); - assertTrue(boundaryTree.getBoundaryTrees().stream() - .anyMatch(b -> b.getBoundaryNode().getCode().equals("LC00002"))); - assertEquals("LC00001", boundaryTree.getBoundaryTrees() - .stream().findFirst().get().getParent().getBoundaryNode().getCode()); - } - - @Test - void shouldGenerateATreeWithNodeHavingTwoChildrenOfAChild() { - List boundaryList = new ArrayList<>(); - boundaryList.add(Boundary.builder() - .code("LC00001") - .name("Tete") - .label("Province") - .children(Arrays.asList(Boundary.builder() - .code("LC00002") - .name("Angónia") - .label("District") - .children(Arrays.asList(Boundary.builder() - .code("LC00003") - .name("Ulongué") - .label("AdministrativeProvince") - .build(), - Boundary.builder() - .code("LC000010") - .name("Dómuè") - .label("AdministrativeProvince") - .build())) - .build())) - .build()); - BoundaryTree boundaryTree = treeGenerator.generateTree(boundaryList.get(0)); - assertTrue(boundaryTree.getBoundaryTrees().stream() - .filter(b -> b.getBoundaryNode().getCode().equals("LC00002")).findFirst() - .filter(b -> b.getBoundaryTrees().stream().findAny().isPresent()).isPresent()); - assertEquals("LC00002", boundaryTree.getBoundaryTrees().stream() - .filter(b -> b.getBoundaryNode().getCode().equals("LC00002")) - .flatMap(b -> b.getBoundaryTrees().stream() - .filter(b2 -> b2.getBoundaryNode().getCode().equals("LC000010"))) - .findFirst() - .get().getParent().getBoundaryNode().getCode()); - } - - @Test - void shouldGenerateATreeWithNodeHavingTwoChildrenOfAChildAndTwoChildrenOfOneChildrenOfAChild() { - List boundaryList = getTestBoundaryList(); - BoundaryTree boundaryTree = treeGenerator.generateTree(boundaryList.get(0)); - assertTrue(boundaryTree.getBoundaryTrees().stream() - .filter(b -> b.getBoundaryNode().getCode().equals("LC00002")) - .map(b -> b.getBoundaryTrees().stream() - .filter(b2 -> b2.getBoundaryNode().getCode().equals("LC00003")) - .map(b3 -> b3.getBoundaryTrees().size() == 2)).findAny().isPresent()); - } - - @Test - void shouldReturnTrueIfAGivenBoundaryNodeExistsInTheTree() { - List boundaryList = getTestBoundaryList(); - BoundaryTree boundaryTree = treeGenerator.generateTree(boundaryList.get(0)); - assertNotNull(treeGenerator.search(boundaryTree, "LC00004")); - } - - @Test - void shouldReturnFalseIfAGivenBoundaryNodeDoesNotExistInTheTree() { - List boundaryList = getTestBoundaryList(); - BoundaryTree boundaryTree = treeGenerator.generateTree(boundaryList.get(0)); - assertNull(treeGenerator.search(boundaryTree, "LC00005")); - } - - @Test - void shouldReturnAFlattenedListOfAllTheParentNodesOfABoundaryNode() { - List boundaryList = getTestBoundaryList(); - BoundaryTree root = treeGenerator.generateTree(boundaryList.get(0)); - BoundaryTree found = treeGenerator.search(root, "LC00004"); - List parentNodes = found.getParentNodes(); - assertEquals(3, parentNodes.size()); - log.info(parentNodes.toString()); - } -} \ No newline at end of file From 8822717a50014130a6d231d7b119592dcce88f84 Mon Sep 17 00:00:00 2001 From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Date: Wed, 29 May 2024 18:47:49 +0530 Subject: [PATCH 251/283] Campaign merged (#738) * Updated the error logging logic and other utils * added validation toast after file check (#533) * Removed other unwanted logs ::cleaned up the code * campaign search by type fix (#538) * upload draft fixes * campaign type search fix --------- Co-authored-by: nabeelmd-eGov * Added basic Loggers to know the API Behaviours * Added In Progress to show in mycamapign screen * updated version (#541) * Hlm 5855 (#544) * upload draft fixes * campaign type search fix * fixes --------- Co-authored-by: nabeelmd-eGov * Feat : added today's date logic in search * Revert kafka changes * Added campaignsIncludesDates in schema * Refactored * Feat : added today's date logic in search (#546) * Feat : added today's date logic in search * Revert kafka changes * Added campaignsIncludesDates in schema * Refactored * formatted and corrected few logs * Added localisation on create of boundary data * HLM-5830 refreshing page is retaining values (#547) * target validation (#548) Co-authored-by: nitiman7765 * selecting boudaries fixes * Feat : added campaign mapping check * summary date format fix (#550) Co-authored-by: nabeelmd-eGov * Update campaignUtils.ts * HLM 5848 (#553) * summary date format fix * product error fix, draft calls fix --------- Co-authored-by: nabeelmd-eGov * added upcoming tab in my campaign (#555) * summary date format fix * product error fix, draft calls fix * added upcoming tab in my campaign --------- Co-authored-by: nabeelmd-eGov * fixed selection from the draft issue (#556) * Updated the loggers logic * validate upload data in summary (#557) * summary date format fix * product error fix, draft calls fix * added upcoming tab in my campaign * validate upload data in summary --------- Co-authored-by: nabeelmd-eGov * Feat : added codes and mapping check (#559) * added log level environment config * fixed HLM-5879 toast message (#561) * Feat : user mapping for all boundaries (#562) * no of cycle and deivery drafted changes (#564) Co-authored-by: nabeelmd-eGov * changes for boundary bulk localization HLM-5874 (#560) Co-authored-by: nitiman7765 * made toast message time longer (#566) * Fixed the project mapping issue during campaign create * retaining api message (#567) * HLM 5791 (#569) * no of cycle and deivery drafted changes * fixes --------- Co-authored-by: nabeelmd-eGov * add localisation code for boundaries (#570) * no of cycle and deivery drafted changes * fixes * add localisation code for boundaries * fixes * fixes --------- Co-authored-by: nabeelmd-eGov * made the delivery conditions as dynamic * fixed message in target upload (#572) * fixed HLM-5871 selection of children (#571) * fixed HLM-5871 selection of children * corrected includeAllChildren * Update SelectingBoundaries.js * Added health master * Feat : added validations and keys reorder * Differenttab (#574) * changes for boundary bulk localization HLM-5874 * localized boundary tab on which split happens * config --------- Co-authored-by: nitiman7765 * changed filters to true (#575) * Patch 1 (#578) * changes for boundary bulk localization HLM-5874 * localized generateDifferentTabsOnBasisOf --------- Co-authored-by: nitiman7765 * Bhavya filter (#577) * changed filters to true * fixed includeAllChildren for the lowest * Update micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Project type object key updated for condition * API Error localisation change, Gender localisation in summary (#579) * no of cycle and deivery drafted changes * fixes * add localisation code for boundaries * fixes * fixes * Value localise in summary screen, api error change --------- Co-authored-by: nabeelmd-eGov * HLM 5791 (#581) * no of cycle and deivery drafted changes * fixes * add localisation code for boundaries * fixes * fixes * Value localise in summary screen, api error change * fixes --------- Co-authored-by: nabeelmd-eGov * Fixed the boundary filtered logic for different types of data injestions (#583) * making generate api to fetch filters from campaign id commit ca425591b1d1ec91a05facb6e2bdf9b5100e9570 Merge: 3ba4c5ddac b491428fc0 Author: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Date: Wed May 15 16:13:32 2024 +0530 Merge branch 'campaign' into boundary-upload-bulk commit 3ba4c5ddac8a9d13145892bfd7c772a8853d6e7b Author: nitiman7765 Date: Tue May 14 12:24:53 2024 +0530 COMMIT commit f775e17aa68cffa622a038b22119082486f064fe Author: nitiman7765 Date: Mon May 13 18:36:28 2024 +0530 changes for boundary bulk localization HLM-5874 * Fixed the boundary filtered logic for different types of data injestions * updated comments * Readme config (#582) * Feat : initialised readme * Feat : added readme * Feat : added readMe Config for target * Feat : added localisation for sheetName * Feat : updated columnwidth in boundary --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Bhavya check (#585) * changes * Update UploadData.js * Generate API call fix (#584) * no of cycle and deivery drafted changes * fixes * add localisation code for boundaries * fixes * fixes * Value localise in summary screen, api error change * fixes * genarate api call fix * font size change for summary * login css change --------- Co-authored-by: nabeelmd-eGov * Capital error (#586) * Feat : initialised readme * Feat : added readme * Feat : added readMe Config for target * Feat : added localisation for sheetName * Feat : updated columnwidth in boundary * Feat : capital name in error * Target (#587) * changes for boundary bulk localization HLM-5874 * refactored localization logic --------- Co-authored-by: nitiman7765 * generate api fixes, user generate fixes (#588) Co-authored-by: nabeelmd-eGov * Updated the status in camapign API * added info card (#589) * changes in card (#593) * Corrected the project type condition logic * generate api call fix (#595) Co-authored-by: nabeelmd-eGov * Update campaignMappingUtils.ts * Update genericApis.ts * Fixed the conditions logic for delivery * Update genericUtils.ts (#599) * Update genericUtils.ts * Update constants.ts * HLM 5872 (#600) * generate api fix, user generate file fix * remove console --------- Co-authored-by: nabeelmd-eGov * updated the condition logic according to the parsing logic * HLM 5872 (#601) * generate api fix, user generate file fix * remove console * downlaod pop up fixes --------- Co-authored-by: nabeelmd-eGov * addded toast for extra parent (#603) * HLM 5872 (#604) * generate api fix, user generate file fix * remove console * downlaod pop up fixes * localisation update --------- Co-authored-by: nabeelmd-eGov * updated info css and fetching according to type (#605) * Target nitish (#607) * upated target validaton * updated target vaidation * Update utilities/project-factory/src/server/utils/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/utils/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/utils/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * upated target validaton * updated target vaidation * added one condition for target * added some chage in condition for valdiate target * Feat : added boundary code mandatory * download with filename fixes (#610) Co-authored-by: nabeelmd-eGov * fixed localistion (#611) * Update campaignValidators.ts * Update campaignValidators.ts * core/css version update & revert filedownload changes (#614) Co-authored-by: nabeelmd-eGov * Update campaignValidators.ts * HLM-5908 Genrate issue fix (#616) Co-authored-by: nabeelmd-eGov * change && to and (#620) Co-authored-by: nabeelmd-eGov * toast back issue fix (#621) Co-authored-by: nabeelmd-eGov * toast error fix (#622) * toast back issue fix * version update --------- Co-authored-by: nabeelmd-eGov * localization logic update * Update campaignValidators.ts * Update campaignValidators.ts * core/css version update & revert filedownload changes (#614) Co-authored-by: nabeelmd-eGov * Update campaignValidators.ts * HLM-5908 Genrate issue fix (#616) Co-authored-by: nabeelmd-eGov * change && to and (#620) Co-authored-by: nabeelmd-eGov * toast back issue fix (#621) Co-authored-by: nabeelmd-eGov * toast error fix (#622) * toast back issue fix * version update --------- Co-authored-by: nabeelmd-eGov * fixed random error (#626) * download file in summary screen fix (#627) Co-authored-by: nabeelmd-eGov * fix rerender (#628) Co-authored-by: nabeelmd-eGov * Fixed the boundary localisation issue in user and facility generation, Added few logs * Added few logs in boundary generation * Update genericApis.ts * generate fix (#629) * fix rerender * generate api and download error fix --------- Co-authored-by: nabeelmd-eGov * localisation fetch logic updated and made singleton class * remove filter from boudary (#632) Co-authored-by: nabeelmd-eGov * Removed filter validation in the generate API * toast message fix (#635) * Cleaned up few file structures * updated the loggers * Updated the campaign cycles conditions for App Integration * Service layer (#631) * Feat : service layer implementation * Feat : service layer implementation * Feat : refactor * updated --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Changed imports of kafka * Feat : updated kafka name (#637) * Generate API response time reduced and optimized * Update campaignValidators.ts (#639) * page size fix to 10 (#638) Co-authored-by: nabeelmd-eGov * summary to back screen redirection fix * summary to back screen redirection fix (#640) Co-authored-by: nabeelmd-eGov * preview params fix * formatted the code and removed few loggers * auto redirection fix & auto uploaded deleted file fix (#642) Co-authored-by: nabeelmd-eGov * Generationlogic (#630) * changes for boundary bulk localization HLM-5874 * commit for bulk boundary * commiting the changes fot boundary code generation * upated target validaton * updated target vaidation * commmit * code generation * updary boundary bulk upload logic * generate fix (#629) * fix rerender * generate api and download error fix --------- Co-authored-by: nabeelmd-eGov * localisation fetch logic updated and made singleton class * updated logic for update boundary data * remove filter from boudary (#632) Co-authored-by: nabeelmd-eGov * Removed filter validation in the generate API * toast message fix (#635) * Cleaned up few file structures * updated the loggers * Updated the campaign cycles conditions for App Integration * Service layer (#631) * Feat : service layer implementation * Feat : service layer implementation * Feat : refactor * updated --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Changed imports of kafka * Feat : updated kafka name (#637) * Generate API response time reduced and optimized * Update campaignValidators.ts (#639) * page size fix to 10 (#638) Co-authored-by: nabeelmd-eGov * summary to back screen redirection fix * preview params fix * commit suggested by jagan --------- Co-authored-by: nitiman7765 Co-authored-by: nabeelmd-eGov <94039229+nabeelmd-eGov@users.noreply.github.com> Co-authored-by: nabeelmd-eGov Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: Bhavya-egov <137176879+Bhavya-egov@users.noreply.github.com> Co-authored-by: ashish-egov <137176738+ashish-egov@users.noreply.github.com> Co-authored-by: ashish-egov * Updates the delivery rules logic for gender * * info message for status creating (#644) * success message if user cred sheet * send id with key resourceid * Send variant in sku also Co-authored-by: nabeelmd-eGov * Feat : added boundary validation (#643) Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Update campaignValidators.ts (#645) * added delay in download (#646) * Update campaignValidators.ts (#647) * fixes (#649) Co-authored-by: nabeelmd-eGov * fixed header validation (#648) * change in filter recursive (#650) * Update genericUtils.ts (#652) * fix (#651) Co-authored-by: nabeelmd-eGov * updated lowest level hierarchy validation for target HLM -5948 (#654) * Update campaignValidators.ts (#655) * fixes-> cyclenumber issue, hover issue, dropdown height issue, * css * fixes-> cyclenumber issue, hover issue, dropdown height issue, (#656) * fixes-> cyclenumber issue, hover issue, dropdown height issue, * css --------- Co-authored-by: nabeelmd-eGov * Update campaignUtils.ts * fixed HLM-5970 * Feat : added boundary validation at data level * fixes * local add * Added boundary validation * Refactor * fixed HLM-5935 and HLM-5749 * Refactor * Feat : updated table * change campaignid in payload * Feat : added campaignId * Update campaignApis.ts * Update campaignValidators.ts * refactored * Refactor * assigned campaignId * Refactor * updated createRequest Schema * Feat : invalid Status Persist * status fix * version-fix * Update CODEOWNERS * core version updated and css fix for language dropdown * refactor (#676) * Uat signoff (#678) * change in filter recursive * lowest level * added validation related to target sheet headers * HLM-5916 * download button fixes in summary (#682) Co-authored-by: nabeelmd-eGov * Hlm 5927 (#687) * change in filter recursive * lowest level * added validation for boundary codes to be invalid other than that selected from UI in target upload * Added Delivery and cycle config for LLIN and SMC both (#688) * no of cycle and deivery drafted changes * fixes * add localisation code for boundaries * fixes * fixes * Value localise in summary screen, api error change * fixes * genarate api call fix * font size change for summary * login css change * HLM-5718: SMC delivery config enhancement * config update * added config for in between * fix config for llin * added mdms integration --------- Co-authored-by: nabeelmd-eGov * Fixed HLM-5988_warning message (#689) Co-authored-by: nabeelmd-eGov <94039229+nabeelmd-eGov@users.noreply.github.com> * download filename fixes (#693) * download button fixes in summary * download filename with custom name changes added --------- Co-authored-by: nabeelmd-eGov * download filename fixes (#694) * download button fixes in summary * download filename with custom name changes added * config fix for llin --------- Co-authored-by: nabeelmd-eGov * successful toast message is fixed (#695) * successful toast message is fixed * Update UploadData.js * HLM-5991: Alert Pop UP CR (#696) Co-authored-by: nabeelmd-eGov * HLM-5718 changes (#703) Co-authored-by: nabeelmd-eGov * Localization cache (#706) * change in filter recursive * lowest level * refactored localization cache logic * Update README.md (#707) * Update README.md * Update README.md * Update utilities/project-factory/README.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update README.md --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * HLM-5985_made lowest level changes (#708) * HLM-5985_made lowest level changes * resolved codeRabbit comments * Create LOCALSETUP.md (#709) * Create LOCALSETUP.md * Refactored config * Update LOCALSETUP.md * Update utilities/project-factory/LOCALSETUP.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/LOCALSETUP.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/LOCALSETUP.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/LOCALSETUP.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update LOCALSETUP.md --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * updated the localisation module config * Refactor config (#713) * Refactor config * Update utilities/project-factory/src/server/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update postman_collection.json (#714) * Update postman_collection.json * Update postman_collection.json * Delete utilities/project-factory/project_factory_swagger.yml (#715) * Feat : removed campaignId validation for boundary upload (#718) * updated the delay for boundary relationship * added logger for request TODO TEST will be reverted * Revert "added logger for request TODO TEST" This reverts commit d5c2bf570400ada8183eebfec71f0a3449143117. * Schema validation (#719) * Feat : removed campaignId validation for boundary upload * Feat : added schema validation * Fixed mdms host * updated the logger messages * updated the loggers * delivery new changes, toast fix, error fix (#716) * delivery new changes, toast fix, error fix * new fixes * fixes * change text component to field component * added hierarchy * fix * fix * fix * fix * passing hierarchy from props --------- Co-authored-by: nabeelmd-eGov * Schema validation2 (#721) * Feat : removed campaignId validation for boundary upload * Feat : added schema validation * Fixed mdms host * Feat : added boundary validation * Feat : optimized product search * Fix : project mapping fixed (#722) * Fixed project search (#723) * smc fixes (#724) Co-authored-by: nabeelmd-eGov * Feat : added boundary confirmation (#727) * Fix: fixed processing boundary * Refactor * fixed HLM-6109 (#729) * gate fixes validation, ui ux (#731) Co-authored-by: nabeelmd-eGov * integrated panelcard component (#732) * integrated panelcard component * Update micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/Response.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update genericUtils.ts (#733) * updated the folder structure * Create CHANGELOG.md (#717) * updated the versions --------- Co-authored-by: Bhavya-egov <137176879+Bhavya-egov@users.noreply.github.com> Co-authored-by: nabeelmd-eGov <94039229+nabeelmd-eGov@users.noreply.github.com> Co-authored-by: nabeelmd-eGov Co-authored-by: ashish-egov Co-authored-by: ashish-egov <137176738+ashish-egov@users.noreply.github.com> Co-authored-by: nitish-egov <137176807+nitish-egov@users.noreply.github.com> Co-authored-by: nitiman7765 Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: admin1 Co-authored-by: Bhavya-egov Co-authored-by: Swathi-eGov <137176788+Swathi-eGov@users.noreply.github.com> --- .github/workflows/publishAllPackages.yml | 25 + .../workflows/publishAllPackagesRelease.yml | 20 + .github/workflows/publishProjectFactory.yml | 75 + .gitignore | 7 +- .vscode/launch.json | 17 + .vscode/settings.json | 3 + build/build-config.yml | 46 +- frontend/micro-ui/.gitignore | 32 + frontend/micro-ui/Jenkinsfile | 3 + frontend/micro-ui/README.md | 140 + frontend/micro-ui/package.json | 4 + frontend/micro-ui/web/.babelrc | 5 + frontend/micro-ui/web/.env.sample | 3 + frontend/micro-ui/web/docker/Dockerfile | 25 + frontend/micro-ui/web/docker/devDockerfile | 26 + frontend/micro-ui/web/docker/masDockerfile | 25 + frontend/micro-ui/web/docker/nginx.conf | 12 + frontend/micro-ui/web/envs.js | 0 frontend/micro-ui/web/install-deps.sh | 14 + .../web/micro-ui-internals/.gitignore | 143 + .../web/micro-ui-internals/.prettierignore | 23 + .../web/micro-ui-internals/.prettierrc.json | 3 + .../micro-ui/web/micro-ui-internals/README.md | 100 + .../micro-ui/web/micro-ui-internals/clean.sh | 28 + .../micro-ui-internals/example/.env-health-qa | 7 + .../micro-ui-internals/example/.env-mz-prod | 7 + .../micro-ui-internals/example/.env-mz-uat | 7 + .../example/.env-unifieddev | 9 + .../micro-ui-internals/example/package.json | 39 + .../example/public/index.html | 35 + .../example/src/ComponentRegistry.js | 11 + .../example/src/UICustomizations.js | 663 ++ .../example/src/complaintConfig.js | 31 + .../example/src/components/SelectName.js | 8 + .../web/micro-ui-internals/example/src/fsm.js | 38 + .../micro-ui-internals/example/src/index.js | 84 + .../web/micro-ui-internals/example/src/pgr.js | 15 + .../example/src/setupProxy.js | 100 + .../web/micro-ui-internals/package.json | 57 + .../micro-ui-internals/packages/css/README.md | 62 + .../packages/css/gulpfile.js | 71 + .../packages/css/package.json | 65 + .../packages/css/postcss.config.js | 55 + .../css/src/components/microplanning.scss | 363 + .../packages/css/src/index.scss | 13 + .../css/src/pages/employee/campaign.scss | 76 + .../css/src/pages/employee/campaignCycle.scss | 325 + .../css/src/pages/employee/coreOverride.scss | 156 + .../css/src/pages/employee/index.scss | 349 + .../packages/css/src/typography.scss | 512 + .../packages/css/tailwind.config.js | 231 + .../modules/campaign-manager/README.md | 159 + .../modules/campaign-manager/package.json | 51 + .../modules/campaign-manager/src/Module.js | 141 + .../src/components/AddProductField.js | 144 + .../src/components/BulkUpload.js | 201 + .../src/components/CampaignCard.js | 71 + .../src/components/CampaignDates.js | 119 + .../components/CampaignDocumentsPreview.js | 80 + .../src/components/CampaignHeader.js | 32 + .../src/components/CampaignName.js | 65 + .../components/CampaignResourceDocuments.js | 50 + .../src/components/CampaignSummary.js | 439 + .../src/components/CampaignType.js | 85 + .../src/components/CycleDataPreview.js | 173 + .../src/components/CycleDetaisPreview.js | 143 + .../src/components/DetailsTable.js | 76 + .../src/components/DocumentIcon.js | 29 + .../src/components/PlusMinusInput.js | 47 + .../src/components/RemovableTagNew.js | 16 + .../src/components/SelectingBoundaries.js | 479 + .../src/components/TimelineCampaign.js | 46 + .../src/components/UploadData.js | 843 ++ .../src/components/XlsPreview.js | 69 + .../src/components/icons/DustbinIcon.js | 10 + .../src/components/icons/XlsxFile.js | 32 + .../src/configs/CampaignConfig.js | 264 + .../src/configs/UICustomizations.js | 472 + .../src/configs/addProductConfig.js | 19 + .../src/configs/attributeConfig.js | 23 + .../src/configs/deliveryConfig.js | 198 + .../src/configs/headerConfig.js | 20 + .../src/configs/mailConfig.js | 5 + .../src/configs/myCampaignConfig.js | 667 ++ .../src/configs/operatorConfig.js | 27 + .../src/configs/previewConfig.js | 124 + .../src/configs/productType.js | 15 + .../src/configs/schemaConfig.js | 80 + .../campaign-manager/src/hooks/index.js | 45 + .../hooks/services/createCampaignService.js | 19 + .../hooks/services/updateCampaignService.js | 20 + .../src/hooks/services/useSearchCampaign.js | 21 + .../src/hooks/useCreateCampaign.js | 10 + .../src/hooks/useCreateProduct.js | 24 + .../src/hooks/useCreateProductVariant.js | 24 + .../src/hooks/useGenerateIdCampaign.js | 26 + .../src/hooks/useProductList.js | 53 + .../src/hooks/useResourceData.js | 71 + .../src/hooks/useUpdateCampaign.js | 10 + .../src/pages/employee/AddProduct.js | 161 + .../src/pages/employee/CycleConfiguration.js | 217 + .../src/pages/employee/MyCampaign.js | 46 + .../src/pages/employee/Response.js | 65 + .../src/pages/employee/SetupCampaign.js | 1270 +++ .../deliveryRule/AddDeliverycontext.js | 766 ++ .../deliveryRule/AddProductscontext.js | 290 + .../employee/deliveryRule/MultiTabcontext.js | 242 + .../src/pages/employee/deliveryRule/index.js | 519 + .../src/pages/employee/index.js | 102 + .../campaign-manager/src/utils/TourSteps.js | 144 + .../src/utils/downloadExcel.js | 46 + .../campaign-manager/src/utils/index.js | 6 + .../Modal/AttendanceActionModal.js | 133 + .../Modal/BPAActionModal.js | 283 + .../Modal/BPAREGActionModal.js | 153 + .../Modal/ExpenditureActionModal.js | 190 + .../Modal/FSMActionModal.js | 298 + .../Modal/NOCActionModal.js | 169 + .../ApplicationDetails/Modal/PTActionModal.js | 190 + .../ApplicationDetails/Modal/TLActionModal.js | 166 + .../Modal/WNSActionModal.js | 261 + .../Modal/WorksActionModal.js | 262 + .../ApplicationDetails/Modal/index.js | 49 + .../components/ApplicationDetailsActionBar.js | 80 + .../components/ApplicationDetailsContent.js | 484 + .../components/ApplicationDetailsToast.js | 74 + .../ApplicationDetailsWarningPopup.js | 54 + .../components/BPADocuments.js | 234 + .../components/DocumentsPreview.js | 49 + .../components/InfoDetails.js | 34 + .../components/InspectionReport.js | 49 + .../components/NOCDocuments.js | 202 + .../components/PermissionCheck.js | 87 + .../components/PropertyDocuments.js | 83 + .../components/PropertyEstimates.js | 39 + .../components/PropertyFloors.js | 49 + .../components/PropertyOwners.js | 94 + .../ApplicationDetails/components/Reason.js | 10 + .../components/ScruntinyDetails.js | 46 + .../components/SubOccupancyTable.js | 126 + .../components/SubWorkTableDetails.js | 77 + .../components/TLCaption.js | 34 + .../components/TLTradeAccessories.js | 52 + .../components/TLTradeUnits.js | 51 + .../components/ViewBreakup.js | 73 + .../components/WSAdditonalDetails.js | 399 + .../components/WSFeeEstimation.js | 346 + .../components/WeekDateRange.js | 30 + .../ApplicationDetails/config/AcceptDso.js | 45 + .../ApplicationDetails/config/AssignDso.js | 115 + .../config/BPAApproverApplication.js | 77 + .../config/BPAREGApproverApplication.js | 71 + .../config/CompleteApplication.js | 46 + .../config/NOCApproverApplication.js | 79 + .../config/PTApproverApplication.js | 66 + .../config/PTAssessProperty.js | 26 + .../ApplicationDetails/config/ReassignDso.js | 101 + .../config/RejectApplication.js | 31 + .../config/TLApproverApplication.js | 83 + .../config/WSApproverApplication.js | 73 + .../config/WSDisconnectApplication.js | 89 + .../config/configApproveModal.js | 53 + .../config/configAttendanceApproveModal.js | 27 + .../config/configAttendanceCheckModal.js | 93 + .../config/configAttendanceRejectModal.js | 61 + .../config/configCheckModal.js | 105 + .../config/configRejectModal.js | 127 + .../config/configViewBillApproveModal.js | 57 + .../config/configViewBillCheckModal.js | 107 + .../config/configViewBillRejectModal.js | 59 + .../ApplicationDetails/config/index.js | 47 + .../templates/ApplicationDetails/index.js | 368 + .../web/micro-ui-internals/publish-develop.sh | 20 + .../web/micro-ui-internals/publish.sh | 20 + .../web/micro-ui-internals/scripts/create.sh | 3 + .../web/micro-ui-internals/scripts/deploy.sh | 8 + .../web/micro-ui-internals/scripts/jenkins.sh | 3 + .../web/micro-ui-internals/scripts/run.sh | 32 + .../micro-ui/web/micro-ui-internals/test.js | 31 + frontend/micro-ui/web/package.json | 85 + frontend/micro-ui/web/public/index.html | 37 + frontend/micro-ui/web/public/robots.txt | 3 + frontend/micro-ui/web/src/App.js | 74 + .../micro-ui/web/src/ComponentRegistry.js | 11 + .../src/Customisations/UICustomizations.js | 428 + .../micro-ui/web/src/Customisations/index.js | 19 + .../web/src/Customisations/pt/index.js | 13 + .../pt/pageComponents/PTAllotmentDetails.js | 64 + .../pt/pageComponents/PTBusinessDetails.js | 68 + .../pt/pageComponents/PTVasikaDetails.js | 79 + .../pt/pageComponents/PropertyUsageType.js | 134 + .../src/Customisations/tl/TLCustomisation.js | 5 + .../web/src/Customisations/tl/index.js | 7 + .../tl/pageComponents/PropertyUsageType.js | 136 + frontend/micro-ui/web/src/index.css | 0 frontend/micro-ui/web/src/index.js | 62 + frontend/micro-ui/web/src/setupProxy.js | 30 + frontend/micro-ui/web/webpack.config.js | 43 + frontend/micro-ui/web/workbench/App.js | 72 + frontend/micro-ui/web/workbench/Dockerfile | 29 + .../micro-ui/web/workbench/install-deps.sh | 18 + .../micro-ui/web/workbench/inter-package.json | 56 + frontend/micro-ui/web/workbench/nginx.conf | 12 + frontend/micro-ui/web/workbench/package.json | 81 + .../micro-ui/web/workbench/webpack.config.js | 44 + health-services/project-factory/.gitignore | 120 + health-services/project-factory/CHANGELOG.md | 10 + health-services/project-factory/Dockerfile | 34 + health-services/project-factory/LICENSE | 21 + health-services/project-factory/LOCALSETUP.md | 32 + health-services/project-factory/README.md | 84 + .../project-factory/migration/Dockerfile | 11 + .../V20240315110400__resource_details_ddl.sql | 46 + .../V20240315110513__campaign_details_ddl.sql | 16 + ...01154500__campaign_details_add_columns.sql | 3 + ...2134500__campaign_details_alter_column.sql | 2 + ...0154500__campaign_details_alter_column.sql | 3 + .../V20240416170000__generate_add_column.sql | 2 + .../V20240427174100__campaign_add_column.sql | 2 + ...2143500__resource_details_alter_column.sql | 2 + .../project-factory/migration/migrate.sh | 4 + .../project-factory/package-lock.json | 9058 +++++++++++++++++ health-services/project-factory/package.json | 60 + .../project-factory/postman_collection.json | 899 ++ .../src/server/api/campaignApis.ts | 791 ++ .../src/server/api/genericApis.ts | 1105 ++ .../project-factory/src/server/app.ts | 51 + .../src/server/config/constants.ts | 130 + .../src/server/config/createAndSearch.ts | 260 + .../src/server/config/dbPoolConfig.ts | 13 + .../src/server/config/error.interface.ts | 7 + .../src/server/config/generateQuery.ts | 145 + .../src/server/config/index.ts | 129 + .../server/config/models/SearchCriteria.ts | 26 + .../server/config/models/campaignDetails.ts | 102 + .../models/campaignDetailsDraftSchema.ts | 98 + .../config/models/createRequestSchema.ts | 39 + .../config/models/downloadRequestSchema.ts | 35 + .../config/models/generateRequestSchema.ts | 37 + .../config/models/searchCampaignDetails.ts | 74 + .../campaignManage.controller.ts | 118 + .../dataManage/dataManage.controller.ts | 107 + .../src/server/controllers/index.ts | 12 + .../localisation.controller.ts | 118 + .../project-factory/src/server/index.ts | 10 + .../src/server/kafka/Listener.ts | 96 + .../src/server/kafka/Producer.ts | 25 + .../server/service/campaignManageService.ts | 62 + .../src/server/service/dataManageService.ts | 87 + .../src/server/utils/Pagination.ts | 6 + .../src/server/utils/boundaryUtils.ts | 15 + .../src/server/utils/campaignMappingUtils.ts | 234 + .../src/server/utils/campaignUtils.ts | 1599 +++ .../src/server/utils/db/index.ts | 31 + .../src/server/utils/genericUtils.ts | 973 ++ .../src/server/utils/localisationUtils.ts | 38 + .../src/server/utils/logger/index.ts | 32 + .../utils/middlewares/asyncMiddleware.ts | 11 + .../utils/middlewares/cacheMiddleware.ts | 31 + .../src/server/utils/middlewares/index.ts | 9 + .../utils/middlewares/requestMiddleware.ts | 46 + .../src/server/utils/request.ts | 146 + .../localisationMessageConstructor.ts | 46 + .../utils/transforms/projectTypeUtils.ts | 290 + .../transforms/searchResponseConstructor.ts | 92 + .../server/validators/campaignValidators.ts | 1096 ++ .../src/server/validators/genericValidator.ts | 353 + .../project-factory/src/tsconfig.json | 66 + health-services/project-factory/tsconfig.json | 66 + health-services/project-factory/yarn.lock | 5138 ++++++++++ yarn.lock | 4 + 271 files changed, 47027 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/publishAllPackages.yml create mode 100644 .github/workflows/publishAllPackagesRelease.yml create mode 100644 .github/workflows/publishProjectFactory.yml create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 frontend/micro-ui/.gitignore create mode 100644 frontend/micro-ui/Jenkinsfile create mode 100644 frontend/micro-ui/README.md create mode 100644 frontend/micro-ui/package.json create mode 100644 frontend/micro-ui/web/.babelrc create mode 100644 frontend/micro-ui/web/.env.sample create mode 100644 frontend/micro-ui/web/docker/Dockerfile create mode 100644 frontend/micro-ui/web/docker/devDockerfile create mode 100644 frontend/micro-ui/web/docker/masDockerfile create mode 100644 frontend/micro-ui/web/docker/nginx.conf create mode 100644 frontend/micro-ui/web/envs.js create mode 100755 frontend/micro-ui/web/install-deps.sh create mode 100644 frontend/micro-ui/web/micro-ui-internals/.gitignore create mode 100644 frontend/micro-ui/web/micro-ui-internals/.prettierignore create mode 100644 frontend/micro-ui/web/micro-ui-internals/.prettierrc.json create mode 100644 frontend/micro-ui/web/micro-ui-internals/README.md create mode 100644 frontend/micro-ui/web/micro-ui-internals/clean.sh create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/.env-health-qa create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/.env-mz-prod create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/.env-mz-uat create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/package.json create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/public/index.html create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/ComponentRegistry.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/complaintConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/components/SelectName.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/fsm.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/index.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/pgr.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/setupProxy.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/package.json create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/README.md create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/gulpfile.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/package.json create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/postcss.config.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/index.scss create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/typography.scss create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/README.md create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AddProductField.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/BulkUpload.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignCard.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDates.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDocumentsPreview.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignHeader.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignName.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignResourceDocuments.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignSummary.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignType.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDataPreview.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDetaisPreview.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DetailsTable.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DocumentIcon.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/PlusMinusInput.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RemovableTagNew.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/TimelineCampaign.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/XlsPreview.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/DustbinIcon.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/XlsxFile.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/CampaignConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/UICustomizations.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/addProductConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/attributeConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/deliveryConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/headerConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/mailConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/myCampaignConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/operatorConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/previewConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/productType.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/schemaConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/index.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/createCampaignService.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/updateCampaignService.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/useSearchCampaign.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateCampaign.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProduct.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProductVariant.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useGenerateIdCampaign.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useProductList.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useResourceData.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useUpdateCampaign.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/AddProduct.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/CycleConfiguration.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/Response.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/AddDeliverycontext.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/AddProductscontext.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/MultiTabcontext.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/index.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/index.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/TourSteps.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/downloadExcel.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/index.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/AttendanceActionModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAActionModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAREGActionModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/ExpenditureActionModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/FSMActionModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/NOCActionModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/PTActionModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/TLActionModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WNSActionModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WorksActionModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/index.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsActionBar.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsContent.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsToast.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsWarningPopup.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/BPADocuments.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/DocumentsPreview.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InfoDetails.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InspectionReport.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/NOCDocuments.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PermissionCheck.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyDocuments.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyEstimates.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyFloors.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyOwners.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/Reason.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ScruntinyDetails.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubOccupancyTable.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubWorkTableDetails.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLCaption.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeAccessories.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeUnits.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ViewBreakup.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSAdditonalDetails.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSFeeEstimation.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WeekDateRange.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AcceptDso.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AssignDso.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAApproverApplication.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAREGApproverApplication.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/CompleteApplication.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/NOCApproverApplication.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTApproverApplication.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTAssessProperty.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/ReassignDso.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/RejectApplication.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/TLApproverApplication.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSApproverApplication.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSDisconnectApplication.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configApproveModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceApproveModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceCheckModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceRejectModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configCheckModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configRejectModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillApproveModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillCheckModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillRejectModal.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/index.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/index.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/publish-develop.sh create mode 100644 frontend/micro-ui/web/micro-ui-internals/publish.sh create mode 100755 frontend/micro-ui/web/micro-ui-internals/scripts/create.sh create mode 100755 frontend/micro-ui/web/micro-ui-internals/scripts/deploy.sh create mode 100755 frontend/micro-ui/web/micro-ui-internals/scripts/jenkins.sh create mode 100755 frontend/micro-ui/web/micro-ui-internals/scripts/run.sh create mode 100644 frontend/micro-ui/web/micro-ui-internals/test.js create mode 100644 frontend/micro-ui/web/package.json create mode 100644 frontend/micro-ui/web/public/index.html create mode 100644 frontend/micro-ui/web/public/robots.txt create mode 100644 frontend/micro-ui/web/src/App.js create mode 100644 frontend/micro-ui/web/src/ComponentRegistry.js create mode 100644 frontend/micro-ui/web/src/Customisations/UICustomizations.js create mode 100644 frontend/micro-ui/web/src/Customisations/index.js create mode 100644 frontend/micro-ui/web/src/Customisations/pt/index.js create mode 100644 frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTAllotmentDetails.js create mode 100644 frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTBusinessDetails.js create mode 100644 frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTVasikaDetails.js create mode 100644 frontend/micro-ui/web/src/Customisations/pt/pageComponents/PropertyUsageType.js create mode 100644 frontend/micro-ui/web/src/Customisations/tl/TLCustomisation.js create mode 100644 frontend/micro-ui/web/src/Customisations/tl/index.js create mode 100644 frontend/micro-ui/web/src/Customisations/tl/pageComponents/PropertyUsageType.js create mode 100644 frontend/micro-ui/web/src/index.css create mode 100644 frontend/micro-ui/web/src/index.js create mode 100644 frontend/micro-ui/web/src/setupProxy.js create mode 100644 frontend/micro-ui/web/webpack.config.js create mode 100644 frontend/micro-ui/web/workbench/App.js create mode 100644 frontend/micro-ui/web/workbench/Dockerfile create mode 100755 frontend/micro-ui/web/workbench/install-deps.sh create mode 100644 frontend/micro-ui/web/workbench/inter-package.json create mode 100644 frontend/micro-ui/web/workbench/nginx.conf create mode 100644 frontend/micro-ui/web/workbench/package.json create mode 100644 frontend/micro-ui/web/workbench/webpack.config.js create mode 100644 health-services/project-factory/.gitignore create mode 100644 health-services/project-factory/CHANGELOG.md create mode 100644 health-services/project-factory/Dockerfile create mode 100644 health-services/project-factory/LICENSE create mode 100644 health-services/project-factory/LOCALSETUP.md create mode 100644 health-services/project-factory/README.md create mode 100644 health-services/project-factory/migration/Dockerfile create mode 100644 health-services/project-factory/migration/ddl/V20240315110400__resource_details_ddl.sql create mode 100644 health-services/project-factory/migration/ddl/V20240315110513__campaign_details_ddl.sql create mode 100644 health-services/project-factory/migration/ddl/V20240401154500__campaign_details_add_columns.sql create mode 100644 health-services/project-factory/migration/ddl/V20240402134500__campaign_details_alter_column.sql create mode 100644 health-services/project-factory/migration/ddl/V20240410154500__campaign_details_alter_column.sql create mode 100644 health-services/project-factory/migration/ddl/V20240416170000__generate_add_column.sql create mode 100644 health-services/project-factory/migration/ddl/V20240427174100__campaign_add_column.sql create mode 100644 health-services/project-factory/migration/ddl/V20240522143500__resource_details_alter_column.sql create mode 100755 health-services/project-factory/migration/migrate.sh create mode 100644 health-services/project-factory/package-lock.json create mode 100644 health-services/project-factory/package.json create mode 100644 health-services/project-factory/postman_collection.json create mode 100644 health-services/project-factory/src/server/api/campaignApis.ts create mode 100644 health-services/project-factory/src/server/api/genericApis.ts create mode 100644 health-services/project-factory/src/server/app.ts create mode 100644 health-services/project-factory/src/server/config/constants.ts create mode 100644 health-services/project-factory/src/server/config/createAndSearch.ts create mode 100644 health-services/project-factory/src/server/config/dbPoolConfig.ts create mode 100644 health-services/project-factory/src/server/config/error.interface.ts create mode 100644 health-services/project-factory/src/server/config/generateQuery.ts create mode 100644 health-services/project-factory/src/server/config/index.ts create mode 100644 health-services/project-factory/src/server/config/models/SearchCriteria.ts create mode 100644 health-services/project-factory/src/server/config/models/campaignDetails.ts create mode 100644 health-services/project-factory/src/server/config/models/campaignDetailsDraftSchema.ts create mode 100644 health-services/project-factory/src/server/config/models/createRequestSchema.ts create mode 100644 health-services/project-factory/src/server/config/models/downloadRequestSchema.ts create mode 100644 health-services/project-factory/src/server/config/models/generateRequestSchema.ts create mode 100644 health-services/project-factory/src/server/config/models/searchCampaignDetails.ts create mode 100644 health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts create mode 100644 health-services/project-factory/src/server/controllers/dataManage/dataManage.controller.ts create mode 100644 health-services/project-factory/src/server/controllers/index.ts create mode 100644 health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts create mode 100644 health-services/project-factory/src/server/index.ts create mode 100644 health-services/project-factory/src/server/kafka/Listener.ts create mode 100644 health-services/project-factory/src/server/kafka/Producer.ts create mode 100644 health-services/project-factory/src/server/service/campaignManageService.ts create mode 100644 health-services/project-factory/src/server/service/dataManageService.ts create mode 100644 health-services/project-factory/src/server/utils/Pagination.ts create mode 100644 health-services/project-factory/src/server/utils/boundaryUtils.ts create mode 100644 health-services/project-factory/src/server/utils/campaignMappingUtils.ts create mode 100644 health-services/project-factory/src/server/utils/campaignUtils.ts create mode 100644 health-services/project-factory/src/server/utils/db/index.ts create mode 100644 health-services/project-factory/src/server/utils/genericUtils.ts create mode 100644 health-services/project-factory/src/server/utils/localisationUtils.ts create mode 100644 health-services/project-factory/src/server/utils/logger/index.ts create mode 100644 health-services/project-factory/src/server/utils/middlewares/asyncMiddleware.ts create mode 100644 health-services/project-factory/src/server/utils/middlewares/cacheMiddleware.ts create mode 100644 health-services/project-factory/src/server/utils/middlewares/index.ts create mode 100644 health-services/project-factory/src/server/utils/middlewares/requestMiddleware.ts create mode 100644 health-services/project-factory/src/server/utils/request.ts create mode 100644 health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts create mode 100644 health-services/project-factory/src/server/utils/transforms/projectTypeUtils.ts create mode 100644 health-services/project-factory/src/server/utils/transforms/searchResponseConstructor.ts create mode 100644 health-services/project-factory/src/server/validators/campaignValidators.ts create mode 100644 health-services/project-factory/src/server/validators/genericValidator.ts create mode 100644 health-services/project-factory/src/tsconfig.json create mode 100644 health-services/project-factory/tsconfig.json create mode 100644 health-services/project-factory/yarn.lock create mode 100644 yarn.lock diff --git a/.github/workflows/publishAllPackages.yml b/.github/workflows/publishAllPackages.yml new file mode 100644 index 00000000000..6bb4b51d612 --- /dev/null +++ b/.github/workflows/publishAllPackages.yml @@ -0,0 +1,25 @@ +name: Node.js Publish UI Packages + +on: + push: + branches: [ 'develop','campaign' ] + paths: + - 'micro-ui/web/micro-ui-internals/**' + + pull_request: + branches: + - 'dev-hcm' + # Push events to branches matching refs/heads/mona/octocat + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 14 + registry-url: https://registry.npmjs.org/ + - run: cd micro-ui/web/micro-ui-internals/ && bash ./publish-develop.sh + env: + NODE_AUTH_TOKEN: ${{secrets.npm_token}} diff --git a/.github/workflows/publishAllPackagesRelease.yml b/.github/workflows/publishAllPackagesRelease.yml new file mode 100644 index 00000000000..ff9b6a3a93f --- /dev/null +++ b/.github/workflows/publishAllPackagesRelease.yml @@ -0,0 +1,20 @@ +name: Node.js Publish UI Packages + +on: + push: + branches: [ 'master' ] + paths: + - 'micro-ui/web/micro-ui-internals/**' + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 14 + registry-url: https://registry.npmjs.org/ + - run: cd micro-ui/web/micro-ui-internals/ && bash ./publish.sh + env: + NODE_AUTH_TOKEN: ${{secrets.npm_token}} diff --git a/.github/workflows/publishProjectFactory.yml b/.github/workflows/publishProjectFactory.yml new file mode 100644 index 00000000000..a606c08c952 --- /dev/null +++ b/.github/workflows/publishProjectFactory.yml @@ -0,0 +1,75 @@ +name: project factory service docker Image CI + +on: + push: + branches: [ "campaign" ] + pull_request: + branches: [ "campaign" ] + +jobs: + + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # Fetch all history for tags and branches + + - name: Set up environment variables + id: env + run: | + echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV + echo "ACTION_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV + echo "COMMIT_ID=${GITHUB_SHA: -8}" >> $GITHUB_ENV # Extract last 8 characters of SHA + + - name: Build the service Docker image + id: docker_build + working-directory: ./utilities/project-factory + run: | + IMAGE_TAG=egovio/project-factory:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} + docker build . \ + --file Dockerfile \ + --tag $IMAGE_TAG + echo "::set-output name=image_name::$IMAGE_TAG" + + + - name: Build the db migration Docker image + id: docker_db_build + working-directory: ./utilities/project-factory/migration + run: | + IMAGE_TAG=egovio/project-factory-db:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} + docker build . \ + --file Dockerfile \ + --tag $IMAGE_TAG + echo "::set-output name=db_image_name::$IMAGE_TAG" + + + - name: Login to Docker Hub and Push Docker Image + working-directory: ./utilities/project-factory + env: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + IMAGE_NAME: ${{ steps.docker_build.outputs.image_name }} + run: | + # Authenticate with Docker Hub + echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin + + # Push the image to Docker Hub + docker push $IMAGE_NAME + echo "Docker image pushed: $IMAGE_NAME" + + - name: Login to Docker Hub and Push DB Migration Docker Image + working-directory: ./utilities/project-factory/migration + env: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + DB_IMAGE_NAME: ${{ steps.docker_db_build.outputs.db_image_name }} + run: | + # Authenticate with Docker Hub + echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin + + # Push the image to Docker Hub + docker push $DB_IMAGE_NAME + echo "Docker image pushed: $DB_IMAGE_NAME" diff --git a/.gitignore b/.gitignore index d1d7c47d852..010719f49a9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ .DS_Store -frontend/micro-ui-internals/node_modules/* +accelerators/frontend/micro-ui-internals/node_modules/* .idea index.lock /health-services/stock/stock.iml @@ -83,4 +83,7 @@ Thumbs.db # Ignore system-specific files .DS_Store -Thumbs.db \ No newline at end of file +Thumbs.db + +utilities/project-factory/node_modules/* +frontend/*/node_modules/* \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000000..65322fe9f51 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,17 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "attach", + "name": "Attach to Remote", + "address": "localhost", + "port": 9229, + "localRoot": "${workspaceFolder}", + "remoteRoot": "/app" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000000..14f60307eb1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.inlineSuggest.showToolbar": "onHover" +} \ No newline at end of file diff --git a/build/build-config.yml b/build/build-config.yml index fff532768be..2e09926ab6a 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -239,4 +239,48 @@ config: - name: "builds/health-campaign-services/analytics/auth-proxy" build: - work-dir: "analytics/auth-proxy" - image-name: "auth-proxy" \ No newline at end of file + image-name: "auth-proxy" + +# frontend + - name: builds/Digit-Frontend/workbench-ui + build: + - work-dir: micro-ui/ + dockerfile: micro-ui/web/workbench/Dockerfile + image-name: workbench-ui + + - name: builds/Digit-Frontend/microplan-ui + build: + - work-dir: micro-ui/ + dockerfile: micro-ui/web/microplan/Dockerfile + image-name: microplan-ui + + - name: builds/Digit-Frontend/storybook-svg + build: + - work-dir: micro-ui/web/micro-ui-internals/packages/svg-components/ + dockerfile: micro-ui/web/micro-ui-internals/packages/svg-components/docker/Dockerfile + image-name: storybook-svg + + - name: builds/Digit-Frontend/storybook + build: + - work-dir: micro-ui/web/micro-ui-internals/packages/components-core/ + dockerfile: micro-ui/web/micro-ui-internals/packages/components-core/docker/Dockerfile + image-name: storybook + + - name: builds/Digit-Frontend/digit-ui + build: + - work-dir: micro-ui/ + dockerfile: micro-ui/web/docker/Dockerfile + image-name: digit-ui + + - name: builds/Digit-Frontend/core-ui + build: + - work-dir: micro-ui/ + dockerfile: micro-ui/web/core/Dockerfile + image-name: core-ui +#Utilities + - name: "builds/Digit-Frontend/utilities/project-factory" + build: + - work-dir: "utilities/project-factory" + image-name: "project-factory" + - work-dir: "utilities/project-factory/migration" + image-name: "project-factory-db" diff --git a/frontend/micro-ui/.gitignore b/frontend/micro-ui/.gitignore new file mode 100644 index 00000000000..feb4cac5c94 --- /dev/null +++ b/frontend/micro-ui/.gitignore @@ -0,0 +1,32 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +.env +.eslintcache + +# yarn $ +.yarn +yarn.lock +.yarnrc.yml + +# dependencies +node_modules +.yarn +/.pnp +.pnp.js + +# testing +/coverage + +# production +/web/build +dist +# misc +.DS_Store +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/frontend/micro-ui/Jenkinsfile b/frontend/micro-ui/Jenkinsfile new file mode 100644 index 00000000000..1206b9c141d --- /dev/null +++ b/frontend/micro-ui/Jenkinsfile @@ -0,0 +1,3 @@ +library 'ci-libs' + +buildPipeline(configFile: './build/build-config.yml') diff --git a/frontend/micro-ui/README.md b/frontend/micro-ui/README.md new file mode 100644 index 00000000000..9420dbb760d --- /dev/null +++ b/frontend/micro-ui/README.md @@ -0,0 +1,140 @@ + +# workbench ui + +A React App built on top of DIGIT UI Core. + +# DIGIT + +DIGIT eGovernance Platform Services + +DIGIT (Digital Infrastructure for Governance, Impact & Transformation) is India's largest platform for governance services. Visit https://core.digit.org/ for more details. + +DIGIT platform is microservices based API platform enabling quick rebundling of services as per specific needs. This is a repo that lays down the core platform on top of which other mission services depend. + + +# DIGIT UI + + +This repository contains source code for web implementation of the new Digit UI modules with dependencies and libraries. + +Workbench module is used to Manage the master data (MDMS V2 Service) used across the DIGIT Services / Applications + +It is also used to manage the Localisation data present in the system (Localisation service) + + +## Run Locally + +Clone the project + +```bash + git clone https://github.com/egovernments/DIGIT-Frontend.git +``` + +Go to the Sub directory to run UI +```bash + cd into micro-ui/web/micro-ui-internals +``` + +Install dependencies + +```bash + yarn install +``` + +Add .env file +```bash + micro-ui/web/micro-ui-internals/example/.env +``` + +Start the server + +```bash + yarn start +``` + + +## Environment Variables + +To run this project, you will need to add the following environment variables to your .env file + +`REACT_APP_PROXY_API` :: `{{server url}}` + +`REACT_APP_GLOBAL` :: `{{server url}}` + +`REACT_APP_PROXY_ASSETS` :: `{{server url}}` + +`REACT_APP_USER_TYPE` :: `{{EMPLOYEE||CITIZEN}}` + +`SKIP_PREFLIGHT_CHECK` :: `true` + +[sample .env file](https://github.com/egovernments/Digit-Core/blob/workbench/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev) + +## Tech Stack + +**Libraries:** + +[React](https://react.dev/) + +[React Hook Form](https://www.react-hook-form.com/) + +[React Query](https://tanstack.com/query/v3/) + +[Tailwind CSS](https://tailwindcss.com/) + +[Webpack](https://webpack.js.org/) + +## License + +[MIT](https://choosealicense.com/licenses/mit/) + + +## Author + +- [@jagankumar-egov](https://www.github.com/jagankumar-egov) + + +## Documentation + +[Documentation](https://https://core.digit.org/guides/developer-guide/ui-developer-guide/digit-ui) + + +## Support + +For support, add the issues in https://github.com/egovernments/DIGIT-core/issues. + + +## Modules + + 1. Core + 2. Workbench + 3. HRMS + 4. Dashboard + 5. Engagement + 6. Payment + +## Starting with Digit-UI App (Impelmentation Teams) - MICRO-UI + + +Go to the Sub directory to run UI + +```bash + cd into micro-ui/web +``` + +```bash + yarn install +``` + +Add .env file +```bash + micro-ui/web/.env +``` + +Start the server + +```bash + yarn start +``` + + +![Logo](https://s3.ap-south-1.amazonaws.com/works-dev-asset/mseva-white-logo.png) diff --git a/frontend/micro-ui/package.json b/frontend/micro-ui/package.json new file mode 100644 index 00000000000..78ab4e7aa40 --- /dev/null +++ b/frontend/micro-ui/package.json @@ -0,0 +1,4 @@ +{ + "name": "workbench-ui", + "version": "0.1.0" +} \ No newline at end of file diff --git a/frontend/micro-ui/web/.babelrc b/frontend/micro-ui/web/.babelrc new file mode 100644 index 00000000000..5f90443d15e --- /dev/null +++ b/frontend/micro-ui/web/.babelrc @@ -0,0 +1,5 @@ +{ + "presets": [ + "@babel/preset-env","@babel/preset-react" + ] + } \ No newline at end of file diff --git a/frontend/micro-ui/web/.env.sample b/frontend/micro-ui/web/.env.sample new file mode 100644 index 00000000000..e87c7f586c4 --- /dev/null +++ b/frontend/micro-ui/web/.env.sample @@ -0,0 +1,3 @@ +SKIP_PREFLIGHT_CHECK=true +REACT_APP_STATE_LEVEL_TENANT_ID=pb +REACT_APP_PROXY_URL=https://works-dev.digit.org diff --git a/frontend/micro-ui/web/docker/Dockerfile b/frontend/micro-ui/web/docker/Dockerfile new file mode 100644 index 00000000000..8e9b173bb85 --- /dev/null +++ b/frontend/micro-ui/web/docker/Dockerfile @@ -0,0 +1,25 @@ +# FROM egovio/alpine-node-builder-14:yarn AS build +FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build +RUN apk update && apk upgrade +RUN apk add --no-cache git>2.30.0 +ARG WORK_DIR +WORKDIR /app +ENV NODE_OPTIONS "--max-old-space-size=8168" + +COPY ${WORK_DIR} . +RUN ls -lah + +#RUN node web/envs.js +RUN cd web/ \ + && ./install-deps.sh \ + && yarn install \ + && yarn build:webpack + +FROM nginx:mainline-alpine +#FROM ghcr.io/egovernments/nginx:mainline-alpine +ENV WORK_DIR=/var/web/digit-ui + +RUN mkdir -p ${WORK_DIR} + +COPY --from=build /app/web/build ${WORK_DIR}/ +COPY --from=build /app/web/docker/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/micro-ui/web/docker/devDockerfile b/frontend/micro-ui/web/docker/devDockerfile new file mode 100644 index 00000000000..d7b1ba1870a --- /dev/null +++ b/frontend/micro-ui/web/docker/devDockerfile @@ -0,0 +1,26 @@ +#FROM egovio/alpine-node-builder-14:yarn AS build +FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build +RUN apk update && apk upgrade +RUN apk add --no-cache git>2.30.0 +ARG WORK_DIR +WORKDIR /app +ENV NODE_OPTIONS "--max-old-space-size=1792" + +COPY ${WORK_DIR} . +RUN ls -lah + +#RUN node web/envs.js +RUN cd web/ \ + && node envs.js \ + && ./install-deps.sh \ + && yarn install \ + && yarn build + +#FROM nginx:mainline-alpine +FROM ghcr.io/egovernments/nginx:mainline-alpine +ENV WORK_DIR=/var/web/digit-ui + +RUN mkdir -p ${WORK_DIR} + +COPY --from=build /app/web/build ${WORK_DIR}/ +COPY --from=build /app/web/docker/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/micro-ui/web/docker/masDockerfile b/frontend/micro-ui/web/docker/masDockerfile new file mode 100644 index 00000000000..5d7cf45dd87 --- /dev/null +++ b/frontend/micro-ui/web/docker/masDockerfile @@ -0,0 +1,25 @@ +#FROM egovio/alpine-node-builder-14:yarn AS build +FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build +RUN apk update && apk upgrade +RUN apk add --no-cache git>2.30.0 +ARG WORK_DIR +WORKDIR /app +ENV NODE_OPTIONS "--max-old-space-size=3792" + +COPY ${WORK_DIR} . +RUN ls -lah + +#RUN node web/envs.js +RUN cd web/ \ + && node envs.js \ + && yarn install \ + && yarn build + +#FROM nginx:mainline-alpine +FROM ghcr.io/egovernments/nginx:mainline-alpine +ENV WORK_DIR=/var/web/digit-ui + +RUN mkdir -p ${WORK_DIR} + +COPY --from=build /app/web/build ${WORK_DIR}/ +COPY --from=build /app/web/docker/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/micro-ui/web/docker/nginx.conf b/frontend/micro-ui/web/docker/nginx.conf new file mode 100644 index 00000000000..4f532e4a6ed --- /dev/null +++ b/frontend/micro-ui/web/docker/nginx.conf @@ -0,0 +1,12 @@ +server +{ + listen 80; + underscores_in_headers on; + + location /digit-ui + { + root /var/web; + index index.html index.htm; + try_files $uri $uri/ /digit-ui/index.html; + } +} \ No newline at end of file diff --git a/frontend/micro-ui/web/envs.js b/frontend/micro-ui/web/envs.js new file mode 100644 index 00000000000..e69de29bb2d diff --git a/frontend/micro-ui/web/install-deps.sh b/frontend/micro-ui/web/install-deps.sh new file mode 100755 index 00000000000..efaceaee20d --- /dev/null +++ b/frontend/micro-ui/web/install-deps.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +BRANCH="$(git branch --show-current)" + +echo "Main Branch: $BRANCH" + +INTERNALS="micro-ui-internals" + +cp $INTERNALS/example/src/UICustomizations.js src/Customisations + +cd $INTERNALS && echo "Branch: $(git branch --show-current)" && echo "$(git log -1 --pretty=%B)" && echo "installing packages" + + +# yarn install diff --git a/frontend/micro-ui/web/micro-ui-internals/.gitignore b/frontend/micro-ui/web/micro-ui-internals/.gitignore new file mode 100644 index 00000000000..1747c795d6f --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/.gitignore @@ -0,0 +1,143 @@ +# Created by https://www.toptal.com/developers/gitignore/api/node,react +# Edit at https://www.toptal.com/developers/gitignore?templates=node,react + +### eGov ### +packages/css/example/index.css +package-lock.json +locales/ +build/ +packages/**/dist/ + +# yarn # +.yarn +.yarnrc.yml + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test +.env*.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist +dist-storybook + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +### react ### +.DS_* +**/*.backup.* +**/*.back.* + +node_modules + +*.sublime* + +psd +thumb +sketch + +# vs code +.vscode/ + +# End of https://www.toptal.com/developers/gitignore/api/node,react \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/.prettierignore b/frontend/micro-ui/web/micro-ui-internals/.prettierignore new file mode 100644 index 00000000000..d54de016ef0 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/.prettierignore @@ -0,0 +1,23 @@ + +# See https://help.github.com/ignore-files/ for more about ignoring files. +# dependencies +node_modules +# builds +build +dist +.rpt2_cache +# dev +dev.css +index.css +index.compat.css +index.min.css +# misc +.DS_Store +.env +.env.local +.env.development.local +.env.test.local +.env.production.local +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/frontend/micro-ui/web/micro-ui-internals/.prettierrc.json b/frontend/micro-ui/web/micro-ui-internals/.prettierrc.json new file mode 100644 index 00000000000..b975008d6f8 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/.prettierrc.json @@ -0,0 +1,3 @@ +{ + "printWidth": 150 +} diff --git a/frontend/micro-ui/web/micro-ui-internals/README.md b/frontend/micro-ui/web/micro-ui-internals/README.md new file mode 100644 index 00000000000..f23a1fcfe9c --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/README.md @@ -0,0 +1,100 @@ + +# workbench ui + +A React App built on top of DIGIT UI Core. + + +# DIGIT UI + +DIGIT (Digital Infrastructure for Governance, Impact & Transformation) is India's largest platform for governance services. Visit https://www.digit.org for more details. + +This repository contains source code for web implementation of the new Digit UI modules with dependencies and libraries. + +Workbench module is used to Manage the master data (MDMS V2 Service) used across the DIGIT Services / Applications + +It is also used to manage the Localisation data present in the system (Localisation service) + + +## Run Locally + +Clone the project + +```bash + git clone https://github.com/egovernments/Digit-Core.git +``` + +Go to the Sub directory to run UI +```bash + cd into frontend/micro-ui/web/micro-ui-internals +``` + +Install dependencies + +```bash + yarn install +``` + +Add .env file +```bash + frontend/micro-ui/web/micro-ui-internals/example/.env +``` + +Start the server + +```bash + yarn start +``` + + +## Environment Variables + +To run this project, you will need to add the following environment variables to your .env file + +`REACT_APP_PROXY_API` :: `{{server url}}` + +`REACT_APP_GLOBAL` :: `{{server url}}` + +`REACT_APP_PROXY_ASSETS` :: `{{server url}}` + +`REACT_APP_USER_TYPE` :: `{{EMPLOYEE||CITIZEN}}` + +`SKIP_PREFLIGHT_CHECK` :: `true` + +[sample .env file](https://github.com/egovernments/Digit-Core/blob/workbench/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev) + +## Tech Stack + +**Libraries:** + +[React](https://react.dev/) + +[React Hook Form](https://www.react-hook-form.com/) + +[React Query](https://tanstack.com/query/v3/) + +[Tailwind CSS](https://tailwindcss.com/) + +[Webpack](https://webpack.js.org/) + +## License + +[MIT](https://choosealicense.com/licenses/mit/) + + +## Author + +- [@jagankumar-egov](https://www.github.com/jagankumar-egov) + + +## Documentation + +[Documentation](https://https://core.digit.org/guides/developer-guide/ui-developer-guide/digit-ui) + + +## Support + +For support, add the issues in https://github.com/egovernments/DIGIT-core/issues. + + +![Logo](https://s3.ap-south-1.amazonaws.com/works-dev-asset/mseva-white-logo.png) + diff --git a/frontend/micro-ui/web/micro-ui-internals/clean.sh b/frontend/micro-ui/web/micro-ui-internals/clean.sh new file mode 100644 index 00000000000..2235ef1c1d0 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/clean.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +BASEDIR="$( cd "$( dirname "$0" )" && pwd )" + +msg() { + echo -e "\n\n\033[32;32m$1\033[0m" +} + +msg "Cleaning root" +rm -rf node_modules + +msg "Cleaning css" +cd "$BASEDIR/packages/css" && rm -rf node_modules + +msg "Cleaning libraries" +cd "$BASEDIR/packages/libraries" && rm -rf node_modules + +msg "Cleaning react-components" +cd "$BASEDIR/packages/react-components" && rm -rf node_modules + +msg "Cleaning PGR module" +cd "$BASEDIR/packages/modules/pgr" && rm -rf node_modules + +msg "Cleaning FSM module" +cd "$BASEDIR/packages/modules/fsm" && rm -rf node_modules + +msg "Cleaning Core module" +cd "$BASEDIR/packages/modules/core" && rm -rf node_modules diff --git a/frontend/micro-ui/web/micro-ui-internals/example/.env-health-qa b/frontend/micro-ui/web/micro-ui-internals/example/.env-health-qa new file mode 100644 index 00000000000..73b42b7dfad --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/.env-health-qa @@ -0,0 +1,7 @@ +SKIP_PREFLIGHT_CHECK=true +REACT_APP_USER_TYPE=EMPLOYEE +REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a +REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c +REACT_APP_PROXY_API=https://health-qa.digit.org +REACT_APP_PROXY_ASSETS=https://health-qa.digit.org +REACT_APP_GLOBAL=https://egov-dev-assets.s3.ap-south-1.amazonaws.com/globalConfigsWorkbenchHCM.js diff --git a/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-prod b/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-prod new file mode 100644 index 00000000000..2d02707d7eb --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-prod @@ -0,0 +1,7 @@ +SKIP_PREFLIGHT_CHECK=true +REACT_APP_USER_TYPE=EMPLOYEE +REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a +REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c +REACT_APP_PROXY_API=https://salama.digit.org +REACT_APP_PROXY_ASSETS=https://salama.digit.org +REACT_APP_GLOBAL=https://moz-health-prd.s3.af-south-1.amazonaws.com/globalConfig.js diff --git a/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-uat b/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-uat new file mode 100644 index 00000000000..bedf28a95b1 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-uat @@ -0,0 +1,7 @@ +SKIP_PREFLIGHT_CHECK=true +REACT_APP_USER_TYPE=EMPLOYEE +REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a +REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c +REACT_APP_PROXY_API=https://moz-health-uat.digit.org +REACT_APP_PROXY_ASSETS=https://moz-health-uat.digit.org +REACT_APP_GLOBAL=https://moz-health-uat.s3.ap-south-1.amazonaws.com/globalConfig.js diff --git a/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev b/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev new file mode 100644 index 00000000000..81fd56e040a --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev @@ -0,0 +1,9 @@ +SKIP_PREFLIGHT_CHECK=true +REACT_APP_USER_TYPE=EMPLOYEE +REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a +REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c +REACT_APP_PROXY_API=https://unified-dev.digit.org +REACT_APP_PROXY_ASSETS=https://unified-dev.digit.org +REACT_APP_GLOBAL=https://egov-dev-assets.s3.ap-south-1.amazonaws.com/globalConfigsMicroplan.js +REACT_APP_CONTEXT=works +WORKBENCH=https://egov-dev-assets.s3.ap-south-1.amazonaws.com/globalConfigsWorkbenchHCMMZ.js \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/example/package.json b/frontend/micro-ui/web/micro-ui-internals/example/package.json new file mode 100644 index 00000000000..495c3688d23 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/package.json @@ -0,0 +1,39 @@ +{ + "name": "@egovernments/digit-ui-example", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "private": true, + "homepage": "digit-ui", + "scripts": { + "start": "react-scripts start" + }, + "devDependencies": { + "@egovernments/digit-ui-libraries": "1.8.1-beta.4", + "@egovernments/digit-ui-module-core": "1.8.1-beta.23", + "@egovernments/digit-ui-module-utilities": "1.0.1-beta.2", + "@egovernments/digit-ui-components": "0.0.1-beta.28", + "@egovernments/digit-ui-react-components": "1.8.1-beta.23", + "@egovernments/digit-ui-module-workbench": "1.0.1-beta.16", + "@egovernments/digit-ui-module-hcmworkbench":"0.0.38", + "@egovernments/digit-ui-module-campaign-manager": "0.0.1", + "http-proxy-middleware": "^1.0.5", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-i18next": "11.16.2", + "react-router-dom": "5.3.0", + "react-scripts": "^4.0.1" + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/example/public/index.html b/frontend/micro-ui/web/micro-ui-internals/example/public/index.html new file mode 100644 index 00000000000..64c6f223cec --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/public/index.html @@ -0,0 +1,35 @@ + + + + + + + + + + DIGIT + + + + + + + + + + + + + + + + +
+ + + \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/ComponentRegistry.js b/frontend/micro-ui/web/micro-ui-internals/example/src/ComponentRegistry.js new file mode 100644 index 00000000000..9bafce3dc89 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/src/ComponentRegistry.js @@ -0,0 +1,11 @@ +class Registry { + constructor(registry = {}) { + this._registry = registry; + } + + getComponent(id) { + return this._registry[id]; + } +} + +export default Registry; diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js b/frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js new file mode 100644 index 00000000000..d21e82500b7 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js @@ -0,0 +1,663 @@ +import { Link } from "react-router-dom"; +import _ from "lodash"; +import { useLocation, useHistory } from "react-router-dom"; +import { useParams } from "react-router-dom"; + +//create functions here based on module name set in mdms(eg->SearchProjectConfig) +//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName] +// these functions will act as middlewares +var Digit = window.Digit || {}; + +const businessServiceMap = { + "muster roll": "MR", +}; + +const inboxModuleNameMap = { + "muster-roll-approval": "muster-roll-service", +}; + +export const UICustomizations = { + businessServiceMap, + updatePayload: (applicationDetails, data, action, businessService) => { + if (businessService === businessServiceMap.estimate) { + const workflow = { + comment: data.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + estimate: applicationDetails, + workflow, + }; + } + if (businessService === businessServiceMap.contract) { + const workflow = { + comment: data?.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + contract: applicationDetails, + workflow, + }; + } + if (businessService === businessServiceMap?.["muster roll"]) { + const workflow = { + comment: data?.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + musterRoll: applicationDetails, + workflow, + }; + } + if (businessService === businessServiceMap?.["works.purchase"]) { + const workflow = { + comment: data.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + const additionalFieldsToSet = { + projectId: applicationDetails.additionalDetails.projectId, + invoiceDate: applicationDetails.billDate, + invoiceNumber: applicationDetails.referenceId.split("_")?.[1], + contractNumber: applicationDetails.referenceId.split("_")?.[0], + documents: applicationDetails.additionalDetails.documents, + }; + return { + bill: { ...applicationDetails, ...additionalFieldsToSet }, + workflow, + }; + } + }, + enableModalSubmit: (businessService, action, setModalSubmit, data) => { + if (businessService === businessServiceMap?.["muster roll"] && action.action === "APPROVE") { + setModalSubmit(data?.acceptTerms); + } + }, + enableHrmsSearch: (businessService, action) => { + if (businessService === businessServiceMap.estimate) { + return action.action.includes("TECHNICALSANCTION") || action.action.includes("VERIFYANDFORWARD"); + } + if (businessService === businessServiceMap.contract) { + return action.action.includes("VERIFY_AND_FORWARD"); + } + if (businessService === businessServiceMap?.["muster roll"]) { + return action.action.includes("VERIFY"); + } + if (businessService === businessServiceMap?.["works.purchase"]) { + return action.action.includes("VERIFY_AND_FORWARD"); + } + return false; + }, + getBusinessService: (moduleCode) => { + if (moduleCode?.includes("estimate")) { + return businessServiceMap?.estimate; + } else if (moduleCode?.includes("contract")) { + return businessServiceMap?.contract; + } else if (moduleCode?.includes("muster roll")) { + return businessServiceMap?.["muster roll"]; + } else if (moduleCode?.includes("works.purchase")) { + return businessServiceMap?.["works.purchase"]; + } else if (moduleCode?.includes("works.wages")) { + return businessServiceMap?.["works.wages"]; + } else if (moduleCode?.includes("works.supervision")) { + return businessServiceMap?.["works.supervision"]; + } else { + return businessServiceMap; + } + }, + getInboxModuleName: (moduleCode) => { + if (moduleCode?.includes("estimate")) { + return inboxModuleNameMap?.estimate; + } else if (moduleCode?.includes("contract")) { + return inboxModuleNameMap?.contracts; + } else if (moduleCode?.includes("attendence")) { + return inboxModuleNameMap?.attendencemgmt; + } else { + return inboxModuleNameMap; + } + }, + + AttendanceInboxConfig: { + preProcess: (data) => { + //set tenantId + data.body.inbox.tenantId = Digit.ULBService.getCurrentTenantId(); + data.body.inbox.processSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); + + const musterRollNumber = data?.body?.inbox?.moduleSearchCriteria?.musterRollNumber?.trim(); + if (musterRollNumber) data.body.inbox.moduleSearchCriteria.musterRollNumber = musterRollNumber; + + const attendanceRegisterName = data?.body?.inbox?.moduleSearchCriteria?.attendanceRegisterName?.trim(); + if (attendanceRegisterName) data.body.inbox.moduleSearchCriteria.attendanceRegisterName = attendanceRegisterName; + + // deleting them for now(assignee-> need clarity from pintu,ward-> static for now,not implemented BE side) + const assignee = _.clone(data.body.inbox.moduleSearchCriteria.assignee); + delete data.body.inbox.moduleSearchCriteria.assignee; + if (assignee?.code === "ASSIGNED_TO_ME") { + data.body.inbox.moduleSearchCriteria.assignee = Digit.UserService.getUser().info.uuid; + } + + //cloning locality and workflow states to format them + // let locality = _.clone(data.body.inbox.moduleSearchCriteria.locality ? data.body.inbox.moduleSearchCriteria.locality : []); + + let selectedOrg = _.clone(data.body.inbox.moduleSearchCriteria.orgId ? data.body.inbox.moduleSearchCriteria.orgId : null); + delete data.body.inbox.moduleSearchCriteria.orgId; + if (selectedOrg) { + data.body.inbox.moduleSearchCriteria.orgId = selectedOrg?.[0]?.applicationNumber; + } + + // let selectedWard = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : null); + // delete data.body.inbox.moduleSearchCriteria.ward; + // if(selectedWard) { + // data.body.inbox.moduleSearchCriteria.ward = selectedWard?.[0]?.code; + // } + + let states = _.clone(data.body.inbox.moduleSearchCriteria.state ? data.body.inbox.moduleSearchCriteria.state : []); + let ward = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : []); + // delete data.body.inbox.moduleSearchCriteria.locality; + delete data.body.inbox.moduleSearchCriteria.state; + delete data.body.inbox.moduleSearchCriteria.ward; + + // locality = locality?.map((row) => row?.code); + states = Object.keys(states)?.filter((key) => states[key]); + ward = ward?.map((row) => row?.code); + + // //adding formatted data to these keys + // if (locality.length > 0) data.body.inbox.moduleSearchCriteria.locality = locality; + if (states.length > 0) data.body.inbox.moduleSearchCriteria.status = states; + if (ward.length > 0) data.body.inbox.moduleSearchCriteria.ward = ward; + const projectType = _.clone(data.body.inbox.moduleSearchCriteria.projectType ? data.body.inbox.moduleSearchCriteria.projectType : {}); + if (projectType?.code) data.body.inbox.moduleSearchCriteria.projectType = projectType.code; + + //adding tenantId to moduleSearchCriteria + data.body.inbox.moduleSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); + + //setting limit and offset becoz somehow they are not getting set in muster inbox + data.body.inbox.limit = data.state.tableForm.limit; + data.body.inbox.offset = data.state.tableForm.offset; + delete data.state; + return data; + }, + postProcess: (responseArray, uiConfig) => { + const statusOptions = responseArray?.statusMap + ?.filter((item) => item.applicationstatus) + ?.map((item) => ({ code: item.applicationstatus, i18nKey: `COMMON_MASTERS_${item.applicationstatus}` })); + if (uiConfig?.type === "filter") { + let fieldConfig = uiConfig?.fields?.filter((item) => item.type === "dropdown" && item.populators.name === "musterRollStatus"); + if (fieldConfig.length) { + fieldConfig[0].populators.options = statusOptions; + } + } + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + if (key === "ATM_MUSTER_ROLL_ID") { + return ( + + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + ); + } + if (key === "ATM_ATTENDANCE_WEEK") { + const week = `${Digit.DateUtils.ConvertTimestampToDate(value?.startDate, "dd/MM/yyyy")}-${Digit.DateUtils.ConvertTimestampToDate( + value?.endDate, + "dd/MM/yyyy" + )}`; + return
{week}
; + } + if (key === "ATM_NO_OF_INDIVIDUALS") { + return
{value?.length}
; + } + if (key === "ATM_AMOUNT_IN_RS") { + return {value ? Digit.Utils.dss.formatterWithoutRound(value, "number") : t("ES_COMMON_NA")}; + } + if (key === "ATM_SLA") { + return parseInt(value) > 0 ? ( + {t(value) || ""} + ) : ( + {t(value) || ""} + ); + } + if (key === "COMMON_WORKFLOW_STATES") { + return {t(`WF_MUSTOR_${value}`)}; + } + //added this in case we change the key and not updated here , it'll throw that nothing was returned from cell error if that case is not handled here. To prevent that error putting this default + return {t(`CASE_NOT_HANDLED`)}; + }, + MobileDetailsOnClick: (row, tenantId) => { + let link; + Object.keys(row).map((key) => { + if (key === "ATM_MUSTER_ROLL_ID") + link = `/${window.contextPath}/employee/attendencemgmt/view-attendance?tenantId=${tenantId}&musterRollNumber=${row[key]}`; + }); + return link; + }, + populateReqCriteria: () => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + return { + url: "/org-services/organisation/v1/_search", + params: { limit: 50, offset: 0 }, + body: { + SearchCriteria: { + tenantId: tenantId, + functions: { + type: "CBO", + }, + }, + }, + config: { + enabled: true, + select: (data) => { + return data?.organisations; + }, + }, + }; + }, + }, + SearchWageSeekerConfig: { + customValidationCheck: (data) => { + //checking both to and from date are present + const { createdFrom, createdTo } = data; + if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === "")) + return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; + + return false; + }, + preProcess: (data) => { + data.params = { ...data.params, tenantId: Digit.ULBService.getCurrentTenantId() }; + + let requestBody = { ...data.body.Individual }; + const pathConfig = { + name: "name.givenName", + }; + const dateConfig = { + createdFrom: "daystart", + createdTo: "dayend", + }; + const selectConfig = { + wardCode: "wardCode[0].code", + socialCategory: "socialCategory.code", + }; + const textConfig = ["name", "individualId"]; + let Individual = Object.keys(requestBody) + .map((key) => { + if (selectConfig[key]) { + requestBody[key] = _.get(requestBody, selectConfig[key], null); + } else if (typeof requestBody[key] == "object") { + requestBody[key] = requestBody[key]?.code; + } else if (textConfig?.includes(key)) { + requestBody[key] = requestBody[key]?.trim(); + } + return key; + }) + .filter((key) => requestBody[key]) + .reduce((acc, curr) => { + if (pathConfig[curr]) { + _.set(acc, pathConfig[curr], requestBody[curr]); + } else if (dateConfig[curr] && dateConfig[curr]?.includes("day")) { + _.set(acc, curr, Digit.Utils.date.convertDateToEpoch(requestBody[curr], dateConfig[curr])); + } else { + _.set(acc, curr, requestBody[curr]); + } + return acc; + }, {}); + + data.body.Individual = { ...Individual }; + return data; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + //here we can add multiple conditions + //like if a cell is link then we return link + //first we can identify which column it belongs to then we can return relevant result + switch (key) { + case "MASTERS_WAGESEEKER_ID": + return ( + + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + ); + + case "MASTERS_SOCIAL_CATEGORY": + return value ? {String(t(`MASTERS_${value}`))} : t("ES_COMMON_NA"); + + case "CORE_COMMON_PROFILE_CITY": + return value ? {String(t(Digit.Utils.locale.getCityLocale(value)))} : t("ES_COMMON_NA"); + + case "MASTERS_WARD": + return value ? ( + {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} + ) : ( + t("ES_COMMON_NA") + ); + + case "MASTERS_LOCALITY": + return value ? ( + {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} + ) : ( + t("ES_COMMON_NA") + ); + default: + return t("ES_COMMON_NA"); + } + }, + MobileDetailsOnClick: (row, tenantId) => { + let link; + Object.keys(row).map((key) => { + if (key === "MASTERS_WAGESEEKER_ID") + link = `/${window.contextPath}/employee/masters/view-wageseeker?tenantId=${tenantId}&wageseekerId=${row[key]}`; + }); + return link; + }, + additionalValidations: (type, data, keys) => { + if (type === "date") { + return data[keys.start] && data[keys.end] ? () => new Date(data[keys.start]).getTime() <= new Date(data[keys.end]).getTime() : true; + } + }, + }, + SearchDefaultConfig: { + customValidationCheck: (data) => { + //checking both to and from date are present + const { createdFrom, createdTo } = data; + if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === "")) + return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; + + return false; + }, + preProcess: (data) => { + const location = useLocation(); + data.params = { ...data.params }; + const { masterName } = useParams(); + + const searchParams = new URLSearchParams(location.search); + const paths = { + "SearchProjectConfig": { + basePath: "Projects", + pathConfig: { + // id: "id[0]", + tenantId: "tenantId", + }, + dateConfig: { + endDate: "dayend", + startDate: "daystart" + }, + selectConfig: { + }, + textConfig :["id", "tenantId", "name", "projectNumber", "projectSubType" , "projectType"] + }, + "SearchProductConfig": { + basePath: "Product", + pathConfig: { + id: "id[0]", + }, + dateConfig: { + }, + selectConfig: { + }, + textConfig :["id", "manufacturer", "name", "type"] + }, + "SearchHouseholdConfig": { + basePath: "Household", + pathConfig: { + id: "id[0]", + clientReferenceId: "clientReferenceId[0]", + }, + dateConfig: { + }, + selectConfig: { + }, + textConfig :["boundaryCode", "clientReferenceId", "id"] + }, + "SearchProductVariantConfig": { + basePath: "ProductVariant", + pathConfig: { + id: "id[0]", + }, + dateConfig: { + }, + selectConfig: { + }, + textConfig :["productId", "sku", "variation"] + }, + "SearchProjectBeneficiaryConfig": { + basePath: "ProjectBeneficiary", + pathConfig: { + id: "id[0]", + clientReferenceId: "clientReferenceId[0]", + + }, + dateConfig: { + dateOfRegistration: "daystart" + }, + selectConfig: { + }, + textConfig :["beneficiaryId", "projectId"] + }, + "SearchProjectStaffConfig": { + basePath: "ProjectStaff", + pathConfig: { + id: "id[0]", + }, + dateConfig: { + startDate: "daystart", + endDate: "dayend", + }, + selectConfig: { + }, + textConfig :["projectId", "userId"] + }, + "SearchProjectResourceConfig": { + basePath: "ProjectResource", + pathConfig: { + id: "id[0]" + }, + dateConfig: { + }, + selectConfig: { + }, + textConfig : [] + }, + "SearchProjectTaskConfig": { + basePath: "Task", + pathConfig: { + id: "id[0]", + clientReferenceId: "clientReferenceId[0]", + }, + dateConfig: { + plannedEndDate: "dayend", + plannedStartDate: "daystart", + actualEndDate: "dayend", + actualStartDate: "daystart", + }, + selectConfig: { + }, + textConfig :["projectId","localityCode", "projectBeneficiaryId", "status"] + }, + "SearchFacilityConfig": { + basePath: "Facility", + pathConfig: { + id: "id[0]" + }, + dateConfig: { + }, + selectConfig: { + }, + textConfig :["faciltyUsage","localityCode", "storageCapacity","id"] + }, + "SearchProjectFacilityConfig": { + basePath: "ProjectFacility", + pathConfig: { + id: "id[0]", + projectId: "projectId[0]", + facilityId: "facilityId[0]" + }, + dateConfig: { + }, + selectConfig: { + }, + textConfig :[] + }, + } + + const id = searchParams.get("config")|| masterName; + + if(!paths||!paths?.[id]){ + return data; + } + let requestBody = { ...data.body[paths[id]?.basePath] }; + const pathConfig = paths[id]?.pathConfig; + const dateConfig = paths[id]?.dateConfig; + const selectConfig = paths[id]?.selectConfig; + const textConfig = paths[id]?.textConfig + + if(paths[id].basePath == "Projects"){ + data.state.searchForm={...data.state.searchForm,tenantId:"mz"} + } + let Product = Object.keys(requestBody) + .map((key) => { + if (selectConfig[key]) { + requestBody[key] = _.get(requestBody, selectConfig[key], null); + } else if (typeof requestBody[key] == "object") { + requestBody[key] = requestBody[key]?.code; + } else if (textConfig?.includes(key)) { + requestBody[key] = requestBody[key]?.trim(); + } + return key; + }) + .filter((key) => requestBody[key]) + .reduce((acc, curr) => { + if (pathConfig[curr]) { + _.set(acc, pathConfig[curr], requestBody[curr]); + } else if (dateConfig[curr] && dateConfig[curr]?.includes("day")) { + _.set(acc, curr, Digit.Utils.date.convertDateToEpoch(requestBody[curr], dateConfig[curr])); + } else { + _.set(acc, curr, requestBody[curr]); + } + return acc; + }, {}); + + if(paths[id].basePath == "Projects"){ + + data.body[paths[id].basePath] = [{ ...Product}]; + } + else data.body[paths[id].basePath] = { ...Product}; + return data; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + //here we can add multiple conditions + //like if a cell is link then we return link + //first we can identify which column it belongs to then we can return relevant result + switch (key) { + case "ID": + + return ( + + + + + ); + + case "MASTERS_SOCIAL_CATEGORY": + return value ? {String(t(`MASTERS_${value}`))} : t("ES_COMMON_NA"); + + case "CORE_COMMON_PROFILE_CITY": + return value ? {String(t(Digit.Utils.locale.getCityLocale(value)))} : t("ES_COMMON_NA"); + + case "MASTERS_WARD": + return value ? ( + {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} + ) : ( + t("ES_COMMON_NA") + ); + + case "MASTERS_LOCALITY": + return value ? ( + {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} + ) : ( + t("ES_COMMON_NA") + ); + default: + return t("ES_COMMON_NA"); + } + }, + MobileDetailsOnClick: (row, tenantId) => { + let link; + Object.keys(row).map((key) => { + if (key === "MASTERS_WAGESEEKER_ID") + link = `/${window.contextPath}/employee/masters/view-wageseeker?tenantId=${tenantId}&wageseekerId=${row[key]}`; + }); + return link; + }, + additionalValidations: (type, data, keys) => { + if (type === "date") { + return data[keys.start] && data[keys.end] ? () => new Date(data[keys.start]).getTime() <= new Date(data[keys.end]).getTime() : true; + } + }, + } +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/complaintConfig.js b/frontend/micro-ui/web/micro-ui-internals/example/src/complaintConfig.js new file mode 100644 index 00000000000..28c85515205 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/src/complaintConfig.js @@ -0,0 +1,31 @@ +export const config = { + routes: { + "complaint-type": { + nextStep: "pincode", + }, + landmark: { + nextStep: "apartment", + }, + apartment: { + component: "SelectName", + texts: { + header: "Apartment or Society", + cardText: "CS_COMPLAINT_SUBTYPE_TEXT", + submitBarLabel: "PT_COMMONS_NEXT", + }, + inputs: [ + { + label: "Apartment", + type: "text", + name: "custom.additionalDetails.apartment", + validation: { + minLength: 6, + maxLength: 7, + }, + error: "CORE_COMMON_PINCODE_INVALID", + }, + ], + nextStep: "upload-photos", + }, + }, +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/components/SelectName.js b/frontend/micro-ui/web/micro-ui-internals/example/src/components/SelectName.js new file mode 100644 index 00000000000..56d2a195c12 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/src/components/SelectName.js @@ -0,0 +1,8 @@ +import React from "react"; +import { FormStep } from "@egovernments/digit-ui-react-components"; + +const SelectName = ({ config, onSelect, onSkip, t }) => { + return ; +}; + +export default SelectName; diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/fsm.js b/frontend/micro-ui/web/micro-ui-internals/example/src/fsm.js new file mode 100644 index 00000000000..271d3ddad56 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/src/fsm.js @@ -0,0 +1,38 @@ +const fsmCustomizations = { + getEmployeeApplicationCustomization: (config, t) => { + const employeeConfig = [ + { + name: "applicationDetails", + // fields: ["sanitationType", "applicationChannel"], + // fieldsOrder: {sanitationType: 0, applicationChannel: 1}, // TODO + allFields: true, // for example: If in applicationDetails you have 10 fields and in fieldsOrder you only enter 3 fields name then on browser you will only see 3 fields in that order but if you want to see rest of 7 fields at the bottom. + // removeFields: ["applicantName"], // type the name of the field in camelCase to remove it + addFields: [ + // by default all the custom fields will add at the bottom, you can add "field name" to "fieldsOrder" if you want them in your custom order. + { + name: "example", + label: t("EXAMPLE"), + type: "text", + isMandatory: true, + populators: { + name: "example", + validation: { + required: true, + pattern: /[A-Za-z]/, + }, + }, + }, + ], + }, + ]; + + return { + config: employeeConfig, + defaultConfig: true, // You want to use defaultConfig and you only want to update one field section. The above employeeConfig is also an order for all the field section. So if defaultConfig is false then on browser you will only see those field section who are inside employeeConfig + }; + }, +}; + +const fsmComponents = {}; + +export { fsmCustomizations, fsmComponents }; diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/index.js b/frontend/micro-ui/web/micro-ui-internals/example/src/index.js new file mode 100644 index 00000000000..2f01957d5b8 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/src/index.js @@ -0,0 +1,84 @@ +import React from "react"; +import ReactDOM from "react-dom"; + +import { initLibraries } from "@egovernments/digit-ui-libraries"; +// import { paymentConfigs, PaymentLinks, PaymentModule } from "@egovernments/digit-ui-module-common"; +import { DigitUI } from "@egovernments/digit-ui-module-core"; +import "@egovernments/digit-ui-css/example/index.css"; + +import { pgrCustomizations } from "./pgr"; +import { UICustomizations } from "./UICustomizations"; +import { initCampaignComponents } from "@egovernments/digit-ui-module-campaign-manager" +import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench"; +import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities"; +import { initWorkbenchHCMComponents } from "@egovernments/digit-ui-module-hcmworkbench"; + +var Digit = window.Digit || {}; + +const enabledModules = [ + "DSS", + "HRMS", + "Workbench", + "HCMWORKBENCH", + "Campaign", + // "Engagement", "NDSS","QuickPayLinks", "Payment", + "Utilities", + "Microplanning" + //added to check fsm + // "FSM" +]; + +const initTokens = (stateCode) => { + const userType = window.sessionStorage.getItem("userType") || process.env.REACT_APP_USER_TYPE || "CITIZEN"; + const token = window.localStorage.getItem("token") || process.env[`REACT_APP_${userType}_TOKEN`]; + + const citizenInfo = window.localStorage.getItem("Citizen.user-info"); + + const citizenTenantId = window.localStorage.getItem("Citizen.tenant-id") || stateCode; + + const employeeInfo = window.localStorage.getItem("Employee.user-info"); + const employeeTenantId = window.localStorage.getItem("Employee.tenant-id"); + + const userTypeInfo = userType === "CITIZEN" || userType === "QACT" ? "citizen" : "employee"; + window.Digit.SessionStorage.set("user_type", userTypeInfo); + window.Digit.SessionStorage.set("userType", userTypeInfo); + + if (userType !== "CITIZEN") { + window.Digit.SessionStorage.set("User", { access_token: token, info: userType !== "CITIZEN" ? JSON.parse(employeeInfo) : citizenInfo }); + } else { + // if (!window.Digit.SessionStorage.get("User")?.extraRoleInfo) window.Digit.SessionStorage.set("User", { access_token: token, info: citizenInfo }); + } + + window.Digit.SessionStorage.set("Citizen.tenantId", citizenTenantId); + + if (employeeTenantId && employeeTenantId.length) window.Digit.SessionStorage.set("Employee.tenantId", employeeTenantId); +}; + +const initDigitUI = () => { + window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH") || "digit-ui"; + window.Digit.Customizations = { + PGR: pgrCustomizations, + commonUiConfig: UICustomizations + }; + window?.Digit.ComponentRegistryService.setupRegistry({ + // PaymentModule, + // ...paymentConfigs, + // PaymentLinks, + }); + initUtilitiesComponents(); + initWorkbenchComponents(); + initWorkbenchHCMComponents(); + initCampaignComponents(); + + const moduleReducers = (initData) => initData; + + + const stateCode = window?.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || "pb"; + initTokens(stateCode); + + ReactDOM.render(, document.getElementById("root")); +}; + +initLibraries().then(() => { + initDigitUI(); +}); diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/pgr.js b/frontend/micro-ui/web/micro-ui-internals/example/src/pgr.js new file mode 100644 index 00000000000..48a498e4582 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/src/pgr.js @@ -0,0 +1,15 @@ +import SelectName from "./components/SelectName"; + +// import { config as complaintConfig } from "./complaintConfig"; + +const pgrCustomizations = { + // complaintConfig, + getComplaintDetailsTableRows: ({ id, service, role, t }) => { + return {}; + }, +}; + +const pgrComponents = { + SelectName: SelectName, +}; +export { pgrCustomizations, pgrComponents }; diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/setupProxy.js b/frontend/micro-ui/web/micro-ui-internals/example/src/setupProxy.js new file mode 100644 index 00000000000..fbc52c4a879 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/src/setupProxy.js @@ -0,0 +1,100 @@ +const { createProxyMiddleware } = require("http-proxy-middleware"); + +const createProxy = createProxyMiddleware({ + //target: process.env.REACT_APP_PROXY_API || "https://uat.digit.org", + // target: process.env.REACT_APP_PROXY_API || "https://qa.digit.org", + target: process.env.REACT_APP_PROXY_API || "https://works-dev.digit.org", + changeOrigin: true, + secure: false, +}); +const assetsProxy = createProxyMiddleware({ + target: process.env.REACT_APP_PROXY_ASSETS || "https://works-dev.digit.org", + changeOrigin: true, + secure: false, +}); +const mdmsProxy = createProxyMiddleware({ + target: process.env.REACT_APP_PROXY_ASSETS || "http://localhost:8080", + changeOrigin: true, + secure: false, +}); +module.exports = function (app) { + ["/mdms-v2/v2/_create"].forEach((location) => app.use(location, mdmsProxy)); + [ + "/access/v1/actions/mdms", + "/egov-mdms-service", + "/mdms-v2", + "/egov-idgen", + "/egov-location", + "/localization", + "/egov-workflow-v2", + "/pgr-services", + "/filestore", + "/egov-hrms", + "/user-otp", + "/user", + "/fsm", + "/billing-service", + "/collection-services", + "/pdf-service", + "/pg-service", + "/vehicle", + "/vendor", + "/property-services", + "/fsm-calculator/v1/billingSlab/_search", + "/pt-calculator-v2", + "/dashboard-analytics", + "/echallan-services", + "/egov-searcher/bill-genie/mcollectbills/_get", + "/egov-searcher/bill-genie/billswithaddranduser/_get", + "/egov-searcher/bill-genie/waterbills/_get", + "/egov-searcher/bill-genie/seweragebills/_get", + "/egov-pdf/download/UC/mcollect-challan", + "/egov-hrms/employees/_count", + "/tl-services/v1/_create", + "/tl-services/v1/_search", + "/egov-url-shortening/shortener", + "/inbox/v1/_search", + "/inbox/v2/_search", + "/tl-services", + "/tl-calculator", + "/org-services", + "/edcr", + "/bpa-services", + "/noc-services", + "/egov-user-event", + "/egov-document-uploader", + "/egov-pdf", + "/egov-survey-services", + "/ws-services", + "/sw-services", + "/ws-calculator", + "/sw-calculator/", + "/egov-searcher", + "/report", + "/inbox/v1/dss/_search", + "/loi-service", + "/project/v1/", + "/estimate-service", + "/loi-service", + "/works-inbox-service/v2/_search", + "/egov-pdf/download/WORKSESTIMATE/estimatepdf", + "/muster-roll", + "/individual", + "/mdms-v2", + "/hcm-moz-impl", + "/project", + "/project/staff/v1/_search", + "/project/v1/_search", + "/facility/v1/_search", + "/product/v1/_search", + "/product/variant/v1/_search", + "/hcm-bff/bulk/_transform", + "/hcm-bff/hcm/_processmicroplan", + "/health-hrms", + "/project-factory", + "/boundary-service", + "/product", + ].forEach((location) => app.use(location, createProxy)); + ["/pb-egov-assets"].forEach((location) => app.use(location, assetsProxy)); + ["/mdms-v2/v2/_create"].forEach((location) => app.use(location, mdmsProxy)); +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/package.json b/frontend/micro-ui/web/micro-ui-internals/package.json new file mode 100644 index 00000000000..1545335ab30 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/package.json @@ -0,0 +1,57 @@ +{ + "name": "egovernments", + "version": "1.0.0", + "main": "index.js", + "workspaces": [ + "example", + "packages/css", + "packages/modules/*" + ], + "author": "JaganKumar ", + "license": "MIT", + "private": true, + "engines": { + "node": ">=14" + }, + "scripts": { + "start": "SKIP_PREFLIGHT_CHECK=true run-s build start:dev", + "sprint": "SKIP_PREFLIGHT_CHECK=true run-s start:script", + "start:dev": "run-p dev:**", + "start:script": "./scripts/create.sh", + "dev:css": "cd packages/css && yarn start", + "publish:css": "cd packages/css && yarn && npm publish --tag workbench-1.0", + "dev:example": "cd example && yarn start", + "dev:campaign": "cd packages/modules/campaign-manager && yarn start", + "build": "run-p build:**", + "build:campaign": "cd packages/modules/campaign-manager && yarn build", + "deploy:jenkins": "./scripts/jenkins.sh", + "clean": "rm -rf node_modules" + }, + "resolutions": { + "**/@babel/runtime": "7.20.1", + "**/babel-preset-react-app": "10.0.0" + }, + "devDependencies": { + "husky": "7.0.4", + "lint-staged": "12.3.7", + "npm-run-all": "4.1.5", + "prettier": "2.1.2" + }, + "husky": {}, + "lint-staged": { + "*.{js,css,md}": "prettier --write" + }, + "dependencies": { + "ajv": "^8.12.0", + "lodash": "4.17.21", + "microbundle-crl": "0.13.11", + "@egovernments/digit-ui-react-components": "1.8.1-beta.23", + "@egovernments/digit-ui-components": "0.0.1-beta.28", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "react-router-dom": "5.3.0" + } +} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/README.md b/frontend/micro-ui/web/micro-ui-internals/packages/css/README.md new file mode 100644 index 00000000000..6efe08ae5c5 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/README.md @@ -0,0 +1,62 @@ + + +# digit-ui-css + +## Install + +```bash +npm install --save @egovernments/digit-ui-css +``` + +## Limitation + +```bash +This Package is more specific to DIGIT-UI's can be used across mission's +It is the base css for all Digit UI's +``` + +## Usage + +After adding the dependency make sure you have this dependency in + +```bash +frontend/micro-ui/web/package.json +``` + +```json +"@egovernments/digit-ui-css":"^1.5.0", +``` + +then navigate to App.js + +```bash +frontend/micro-ui/web/public/index.html +``` + +```jsx +/** add this import **/ + + + +``` +### Changelog + +```bash +1.0.7-campaign some css fixes in attribute +1.0.5-campaign some css fixes in previous button +1.0.4-campaign updated styling for create campaign screens +1.0.2-campaign update Styling added for delivery rule screen +1.0.1-campaign Styling added for delivery rule screen +1.0.0-campaign Base version + +``` +## Contributors + +[jagankumar-egov] [nipunarora-eGov] + +### Published from DIGIT Frontend +DIGIT Frontend Repo (https://github.com/egovernments/Digit-Frontend/tree/develop) + +## License + +MIT © [jagankumar-egov](https://github.com/jagankumar-egov) diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/gulpfile.js b/frontend/micro-ui/web/micro-ui-internals/packages/css/gulpfile.js new file mode 100644 index 00000000000..5d1a705494a --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/gulpfile.js @@ -0,0 +1,71 @@ +const fs = require("fs"); +const { name, version, author, cssConfig } = JSON.parse(fs.readFileSync("package.json")); + +const headerString = ` +@charset "UTF-8"; +/*! + * ${name} - ${version} + * + * Copyright (c) ${new Date().getFullYear()} ${author} + * + */ + `; +const { series, src, dest, watch, task } = require("gulp"); +const header = require("postcss-header"); + +const clean = require("gulp-clean"); +const postcss = require("gulp-postcss"); +const sass = require('gulp-sass'); + +const postcssPresetEnv = require("postcss-preset-env"); +const cleanCSS = require("gulp-clean-css"); +const rename = require("gulp-rename"); +const livereload = require("gulp-livereload"); + +let output = "./example"; +if (process.env.NODE_ENV === "production") { + output = "./dist"; +} + +function cleanStyles() { + return src(`${output}/*.css`, { read: false }).pipe(clean()); +} + +function styles() { + const plugins = [ + require("postcss-import"), + require("tailwindcss"), + postcssPresetEnv({ stage: 2, autoprefixer: { cascade: false }, features: { "custom-properties": true } }), + require("autoprefixer"), + require("cssnano"), + header({ header: headerString }), + ]; + return src("src/index.scss").pipe(postcss(plugins)).pipe(sass()).pipe(dest(output)); +} + +function minify() { + return src(`${output}/index.css`).pipe(cleanCSS()).pipe(rename(`index.min.css`)).pipe(dest(output)); +} + +function stylesLive() { + styles().pipe(livereload({ start: true })); +} + +function livereloadStyles() { + livereload.listen(); + watch("src/**/*.scss", series(stylesLive)); +} + +exports.styles = styles; +exports.default = series(styles); +exports.watch = livereloadStyles; +if (process.env.NODE_ENV === "production") { + exports.build = series(cleanStyles, styles, minify); +} else { + exports.build = series(styles, livereloadStyles); +} + +// gulp.task("watch:styles", function () { +// livereload.listen(); +// gulp.watch("**/*.scss", ["styles"]); +// }); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json b/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json new file mode 100644 index 00000000000..af328f65f0f --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json @@ -0,0 +1,65 @@ +{ + "name": "@egovernments/digit-ui-css", + "version": "1.0.47-campaign", + "license": "MIT", + "main": "dist/index.css", + "author": "Jagankumar ", + "engines": { + "node": ">=14" + }, + "cssConfig": { + "prefix": "" + }, + "scripts": { + "start": "gulp build", + "build:prod": "NODE_ENV=production gulp build", + "prepublish": "yarn build:prod", + "deploy": "gulp && cp -R svg example && cp -R img example && gh-pages -d example" + }, + "browserslist": [ + "> 3%", + "last 2 versions" + ], + "style": "./dist/index.css", + "dependencies": { + "node-sass": "4.14.1", + "normalize.css": "8.0.1", + "postcss-scss": "3.0.5", + "tailwindcss": "1.9.6" + }, + "devDependencies": { + "autoprefixer": "10.4.14", + "cssnano": "4.1.11", + "gh-pages": "3.2.3", + "gulp": "4.0.2", + "gulp-clean": "0.4.0", + "gulp-clean-css": "4.3.0", + "gulp-livereload": "4.0.2", + "gulp-postcss": "9.0.1", + "gulp-rename": "2.0.0", + "gulp-sass": "4.1.1", + "postcss": "8.4.26", + "postcss-cli": "8.3.1", + "postcss-header": "2.0.0", + "postcss-import": "12.0.1", + "postcss-prefixer": "2.1.3", + "postcss-preset-env": "6.7.1", + "postcss-scss": "3.0.5", + "sass": "^1.26.11" + }, + "files": [ + "dist/index.min.css", + "dist/index.css", + "svg/**/*.svg", + "img/**/*.png", + "src/**/*.scss", + "src/**/*.css" + ], + "keywords": [ + "digit", + "egov", + "dpg", + "digit-ui", + "css" + ] +} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/postcss.config.js b/frontend/micro-ui/web/micro-ui-internals/packages/css/postcss.config.js new file mode 100644 index 00000000000..18485de221e --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/postcss.config.js @@ -0,0 +1,55 @@ +const postcssPresetEnv = require("postcss-preset-env"); + +module.exports = { + parser: require("postcss-scss"), + plugins: [ + require("postcss-import"), + require("postcss-nested").default, + require("tailwindcss"), + require("postcss-preset-env"), + require("autoprefixer"), + // require("cssnano"), + ], +}; + +// const fs = require('fs'); +// const { name, version, author, cssConfig } = JSON.parse(fs.readFileSync('package.json')); + +// const header = ` +// @charset "UTF-8"; +// /*! +// * ${name} - ${version} +// * +// * Copyright (c) ${new Date().getFullYear()} ${author.name} +// */ +// `; + +// module.exports = (ctx) => { +// const prefix = ctx.env === 'compat' ? '' : cssConfig.prefix; +// const devMessage = `🎉🎉🎉🎉 \n${name} ${ctx.env} build was compiled sucessfully! \n`; + + +// return { +// map: ctx.options.map, +// parser: ctx.options.parser, +// plugins: { +// 'postcss-import': { root: ctx.file.dirname }, +// 'postcss-prefixer': { +// prefix, +// ignore: [/\[class\*=.*\]/], +// }, +// 'postcss-preset-env': { +// autoprefixer: { +// cascade: false, +// }, +// features: { +// 'custom-properties': true, +// }, +// }, +// cssnano: ctx.env === 'production' || ctx.env === 'compat' ? {} : false, +// 'postcss-header': { +// header, +// }, +// }, +// }; +// }; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss new file mode 100644 index 00000000000..f01756f1e7d --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss @@ -0,0 +1,363 @@ +.microplanning { + .upload { + display: flex; + width: 100%; + justify-content: space-between; + margin-top: 1.25rem; + } + + .upload-section-option { + width: 12.5rem; + min-height: 32rem; + background-color: #ffffff; + border-top-left-radius: 0.5rem; + border-bottom-left-radius: 0.5rem; + padding: 0.625rem; + box-shadow: 0px 1px 2px 0px #00000029; + } + + .upload-section-options-active { + min-height: 3.7rem; + display: flex; + align-items: center; + border-bottom: 1px rgba(214, 213, 212, 1) solid; + cursor: pointer; + border-right: 0.3rem solid rgba(244, 119, 56, 1); + background-color: rgba(244, 119, 56, 0.12); + + p { + color: rgba(80, 90, 95, 1); + font-weight: 400; + font-size: 16px; + } + } + + .upload-section-options-inactive { + min-height: 3.7rem; + display: flex; + align-items: center; + border-bottom: 1px rgba(214, 213, 212, 1) solid; + cursor: pointer; + border-right: none; + background-color: rgba(255, 255, 255, 1); + + p { + color: rgba(80, 90, 95, 1); + font-weight: 400; + font-size: 16px; + } + } + + .upload-component { + width: 80%; + height: min-content; + border-radius: 0.25rem; + padding: 1.5rem; + background-color: rgba(255, 255, 255, 1); + margin: 0; + margin-right: 0.3rem; + padding-bottom: 0.625rem; + } + + .upload-component-active { + display: flex; + flex-direction: column; + margin-bottom: 0; + + .greyedout-name { + color: rgba(177, 180, 182, 1); + margin: 0 0.625rem; + font-size: 1.25rem; + padding-top: 0px; + font-weight: 500; + } + + h2 { + margin-top: 0.625rem; + font-size: 2.5rem; + margin: 0.625rem 0; + font-weight: 700; + } + + p { + margin: 0.625rem 0; + padding-top: 0.625; + font-size: 1rem; + margin-top: 0.625rem; + font-weight: 400; + } + } + + .upload-component-inactive { + display: none; + } + + .upload-option-container { + display: flex; + align-items: center; + justify-content: center; + padding: 1.25rem 0; + flex-wrap: wrap; + + .upload-option-container-selected { + border: 2px rgba(244, 119, 56, 1) solid; + color: rgba(244, 119, 56, 1); + } + } + + .upload-option { + border-radius: 0.25rem; + border: 0.0625rem rgba(214, 213, 212, 1) solid; + min-width: 12.5rem; + min-height: 8.75rem; + box-shadow: 0 0.0625rem rgba(0, 0, 0, 0.16); + padding: 0.625rem 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + justify-items: center; + margin: 0 1.25rem; + cursor: pointer; + + &:hover { + border: 2px rgba(244, 119, 56, 1) solid; + } + + p { + margin-top: 0.625rem; + } + + .upload-option-selected { + border: 0.125rem rgba(244, 119, 56, 1) solid; + color: rgba(244, 119, 56, 1); + } + + .select-button { + justify-self: end; + border: 1px solid rgba(244, 119, 56, 1); + background-color: rgba(255, 255, 255, 1); + width: 11rem; + height: 2.5rem; + padding: 0.6rem 0.5rem; + color: rgba(244, 119, 56, 1); + font-size: 1rem; + font-weight: 600; + } + + .selected-button { + justify-self: end; + border: 1px solid rgba(244, 119, 56, 1); + background-color: rgba(244, 119, 56, 1); + width: 11rem; + height: 2.5rem; + padding: 0.6rem 0.5rem; + color: rgb(255, 255, 255); + font-size: 1rem; + font-weight: 600; + } + } + + .modal-header { + width: 30rem; + font-weight: 700; + font-size: 1.5rem; + padding-left: 1rem; + margin-bottom: 0; + display: flex; + flex-wrap: wrap; + overflow: hidden; + } + + .modal-body { + overflow: hidden; + padding-left: 1rem; + padding-right: 1rem; + margin-bottom: 1rem; + margin-right: 1rem; + + p { + font-weight: 400; + font-size: 1rem; + } + } + + .upload-file { + min-width: 90%; + min-height: 10rem; + padding-top: 0.625; + border: 1px rgba(214, 213, 212, 1) dotted; + margin: 1rem 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background-color: rgba(250, 250, 250, 255); + } + + .uploaded-file { + border: 1px solid rgba(214, 213, 212, 1); + min-height: 4.75rem; + background-color: rgb(256, 252, 252); + display: flex !important; + flex-direction: row; + justify-content: space-between; + align-items: center; + margin-top: 0.625rem; + padding: 0 0.625rem; + flex-wrap: wrap; + + .uploaded-file-details { + display: flex; + flex-direction: row; + align-items: center; + flex-wrap: wrap; + padding: 1rem 0; + + p { + padding: 0; + margin: 0; + height: min-content; + font-weight: 700; + font-size: 1.5rem; + color: rgba(80, 90, 95, 1); + text-align: start; + } + } + + .uploaded-file-operations { + display: flex !important; + flex-direction: row; + align-items: center; + justify-items: end; + flex-wrap: wrap; + .button { + display: flex !important; + flex-direction: row; + align-items: center !important; + justify-content: center; + margin-left: 1rem; + min-width: 9rem; + height: 2.5rem; + border: 1px rgba(244, 119, 56, 1) solid; + background-color: white; + cursor: pointer; + } + + p { + padding: 0; + margin: 0; + color: rgba(244, 119, 56, 1); + font-weight: 600; + font-size: 1rem; + } + + .deletebutton { + background-color: rgb(255, 255, 255, 0); + border: none; + } + } + } + + .loader-container { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + width: 100%; + display: flex; + flex-direction: column; + background-color: rgba(0, 0, 0, 0.7); + position: fixed; + top: 0; + left: 0; + z-index: 99999; + + .loader { + border: 0.5rem solid rgb(255, 255, 255); + border-top: 0.5rem solid rgba(80, 76, 76, 0); + border-radius: 50%; + width: 3.125rem; + height: 3.125rem; + animation: spin 2s linear infinite; + } + + .loader-inner { + border: 1px solid rgb(255, 255, 255); + border-radius: 50%; + width: 100%; + height: 100%; + } + + .loader-text { + color: whitesmoke; + padding-top: 1.25rem; + } + } + + @keyframes spin { + 0% { + transform: rotate(0deg); + } + + 100% { + transform: rotate(360deg); + } + } + + .toast-container { + position: fixed; + width: 50%; + bottom: 1.25rem; + left: 50%; + transform: translateX(-50%); + color: #fff; + padding: 1rem; + z-index: 9999; + } + + .success { + background-color: rgba(0, 112, 60, 1); + } + + .toast-content { + display: flex; + align-items: center; + justify-content: space-between; + } + + .message { + margin-right: 0.6px; + } + + .close-button { + background: transparent; + border: none; + color: inherit; + cursor: pointer; + } + + .altrady-have-template-button { + display: flex !important; + justify-content: center; + font-weight: 600; + font-size: 1rem; + } + + .download-template-button { + display: flex !important; + justify-content: center; + + .icon { + display: flex; + align-items: center; + margin: 0; + padding: 0; + } + + p { + font-weight: 500; + font-size: 1rem; + } + } +} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/index.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/index.scss new file mode 100644 index 00000000000..ff5ace2af3e --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/index.scss @@ -0,0 +1,13 @@ +/*@import 'normalize.css';*/ + +/*@import url("https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@400;500;700&family=Roboto:wght@400;500;700&display=swap");*/ + +@import "tailwindcss/base"; + +@import "tailwindcss/components"; + +@import "tailwindcss/utilities"; + +@import "./components/microplanning.scss"; +@import "./pages/employee/index.scss"; +@import "./pages/employee/campaign.scss"; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss new file mode 100644 index 00000000000..3a10013d8ea --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss @@ -0,0 +1,76 @@ +@import url("../../index.scss"); +@import "../../typography.scss"; + +.summary-header{ + @extend .typography.text-heading-l; + font-size: 2.25rem; +} +.date-field-container { + display: grid; + grid-template-columns: 20rem 20rem; + grid-gap: 1.5rem; + width: 70%; + padding-top: 0.3rem; + margin-top: 0rem; +} +.date-field { + display: grid; + grid-template-columns: 1fr 2fr; + align-items: start; +} +.campaign-type { + margin-right: 5rem; + padding-bottom: 1.2rem; + font-weight: bold; +} +.name-container { + margin-right: 4rem; + font-weight: bold; + text-wrap: nowrap; +} +.beneficiary-type { + margin-right: 5.4rem; + font-weight: bold; +} +.campaign-dates { + display: flex; + font-weight: bold; +} +.mandatory-date { + margin-top: 0.8rem; + margin-left: 0.5rem; + color: red !important; + font-size: 1rem; + font-weight: 700; +} +.description-type { + margin-top: 2rem; + margin-bottom: 2rem; +} +.name-description { + margin-top: 2rem; + margin-bottom: 2rem; +} +.dates-description { + margin-top: 1rem; + margin-bottom: 1rem; + padding-bottom: 1.2rem; +} +.selecting-boundary-div { + padding-top: 0.5rem; +} +.campaign-table { + border-collapse: collapse; + border-color: transparent; + border-width: 0rem 1.5rem; + tbody { + tr:hover { + background: rgba(#f47738, 0.12); + } + } +} +.info-points { + display: flex; + gap: 0.5rem; + margin-bottom: 0.5rem; +} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss new file mode 100644 index 00000000000..69f4b0a9eb7 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss @@ -0,0 +1,325 @@ +@import "../../typography.scss"; + +.campaign-cycle-container { + .campaign-tabs-container { + } + .sub-tab-container { + margin-top: 5px; + padding: 1.5rem; + .card-text{ + margin-bottom: 0; + } + } + .add-resource-container { + background-color: #fafafa; + border: 1px solid #d6d5d4; + border-radius: 0.4rem; + padding: 1rem; + margin-right: 1.5rem; + margin-bottom: 1.5rem; + .card-text { + margin: 0; + font-weight: 700; + } + .header-container { + display: flex; + align-items: flex-end; + justify-content: space-between; + } + } + .delete-resource-icon { + cursor: pointer; + font-weight: 600; + font-size: 1rem; + color: theme(digitv2.lightTheme.primary); + display: flex; + gap: 0.5rem; + align-items: center; + } + .add-resource-label-field-container { + display: grid; + grid-template-columns: 2fr 1fr; + grid-gap: 2rem; + .options-card { + max-height: 10rem !important; + } + } + .popup-wrap { + .popup-module-main { + max-height: 707px; + overflow-y: auto; + width: 99%; + &::-webkit-scrollbar { + width: 0.5rem; + background: transparent; + } + &::-webkit-scrollbar-thumb { + background: #d6d5d4; /* Color of the scrollbar thumb */ + border-radius: 5px; /* Adjust the border-radius for rounded corners */ + height: 0.5rem; + } + } + .popup-module-action-bar { + .selector-button-primary { + padding: 0.6rem 2.5rem; + height: unset; + margin: 1.5rem; + background-color: theme(digitv2.lightTheme.primary); + } + } + } +} +.campaign-breadcrumb { + margin: 0; + margin-bottom: 1.5rem; + color: theme(digitv2.lightTheme.primary) !important; +} +.sc-jlZhew.dVtbRz { + overflow: hidden; +} +.campaign-popup-module { + margin: auto; + width: calc(100% - 5rem); +} +.campaign-bulk-upload { + display: flex; + justify-content: space-between; + margin-bottom: 1.5rem; + .campaign-download-template-btn { + font-weight: 700; + } +} +.bulk-info-text { + margin-bottom: 1.5rem; +} +.delete-and-download-button { + display: flex; + gap: 1.5rem; +} +.bulk-upload-file { + .uploaded-file-container { + margin: 0; + margin-bottom: 1.5rem; + } +} +.uploaded-file-container { + margin-left: 0rem; +} +.upload-drag-drop-container { + background-color: #fafafa; + border: 1.5px dashed #d6d5d4; + border-radius: 5px; + padding: 1rem 1rem 1rem 1rem; + display: flex; + align-items: center; + flex-direction: column; + + .drag-drop-text { + text-decoration: none; + + .browse-text { + text-decoration: none; + color: theme(digitv2.lightTheme.primary); + transition: color 0.3s; + } + + .browse-text:hover { + color: theme(digitv2.lightTheme.primary); + text-decoration: underline; + cursor: pointer; + } + } +} + +.upload-drag-drop-container { + margin-left: 0rem; + .drag-drop { + color: #b1b4b6; + } + .browse-text { + text-decoration: underline; + color: theme(digitv2.lightTheme.primary); + transition: color 0.3s; + } +} + +.campaign-counter-container { + padding: 1.5rem; + padding-bottom: 0.5rem; + .card-text { + margin-top: 0; + } + .label-field-pair { + margin-bottom: 1rem; + .card-label { + font-weight: 700; + } + } + .date-field-container { + display: grid; + grid-template-columns: 18.75rem 18.75rem; + grid-gap: 1.5rem; + width: 100%; + } + .PlusMinus { + width: 30%; + input { + width: 100%; + } + } +} + +.campaign-tab-head { + padding: 1rem; + width: 12.5rem; + height: 3rem; + border-radius: 10px 10px 0px 0px; + background-color: #ffffff; + outline: none; + box-sizing: border-box; + font-weight: 700; + font-size: 1rem; + font-family: "Roboto"; + color: #505a5f; + margin-bottom: -6px; + border: 1px solid #d6d5d4; + background-color: #fafafa; + &.active { + height: 3.375rem; + background-color: #ffffff; + outline: none; + font-weight: bold; + color: theme(digitv2.lightTheme.primary); + border: 1px solid theme(digitv2.lightTheme.primary); + border-bottom: 4px solid theme(digitv2.lightTheme.primary); + box-sizing: border-box; + font-size: 1.5rem; + } + :focus { + outline: none; + } +} +.campaign-sub-tab-head { + outline: none; + background-color: #ffffff; + color: theme(digitv2.lightTheme.primary); + border: 1px solid theme(digitv2.lightTheme.primary); + height: 2rem; + width: 9.188rem; + font-size: 1rem; + font-weight: 400; + &.active { + background-color: theme(digitv2.lightTheme.primary); + color: #ffffff; + font-weight: bold; + outline: none; + height: 2rem; + width: 9.188rem; + font-family: "Roboto"; + font-weight: 700; + font-size: 1rem; + } +} +.tab-content-header { + margin-top: 1.5rem; + margin-bottom: 1.5rem !important; +} + +.delivery-rule-container { + padding-top: 0; + .card-header { + .title { + margin: 0 !important; + } + font-size: 1.5rem !important; + margin: 0; + display: flex; + align-content: center; + justify-content: space-between; + } + .attribute-container { + border: 1px solid #d6d5d4; + background-color: #fafafa; + padding: 1rem; + padding-top: 0; + .add-attribute { + width: 74.5%; + justify-content: center; + h2 { + font-size: 1rem; + font-family: Roboto; + width: unset !important; + font-weight: 600; + } + } + } +} +.attribute-field-wrapper { + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + align-items: center; + gap: 2.5rem; + .label-field-pair { + flex-direction: column; + align-items: flex-start !important; + .employee-select-wrap.form-field { + width: 100%; + } + .digit-employee-card-input { + margin-bottom: 0; + } + } + .options-card { + max-height: 10rem !important; + } + .card-label{ + margin-bottom: 0.5rem; + } +} +.add-rule-btn { + margin: auto; + h2 { + font-family: Roboto; + font-size: 1rem; + font-weight: 600; + } +} +.add-product-btn { + h2 { + font-family: Roboto; + font-size: 1rem; + font-weight: 600; + } +} +.popup-wrap.campaign-product-wrapper { + .popup-module { + width: 70%; + padding-left: 1.5rem; + padding-bottom: 1.5rem; + .header-wrap { + font-size: 1.5rem; + font-weight: 700; + .header-content.popup-header-fix { + margin-top: 1.5rem; + } + } + } + .popup-module-action-bar { + margin-top: 1.5rem; + margin-right: 1.5rem; + } +} +.search-button-wrapper { + grid-column-end: -1 !important; + flex-direction: row !important; +} +.add-resource-modal { +} +.add-resource-wrapper { + .link { + color: theme(digitv2.lightTheme.primary); + } +} +.digit-toast-success { + margin-bottom: -0.5rem; +} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss new file mode 100644 index 00000000000..448357784b2 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss @@ -0,0 +1,156 @@ +@import "../../typography.scss"; + +/* language selection issue*/ +.customBtn-selected { + background-color: theme(digitv2.lightTheme.primary); +} + +/* login screen issue*/ + +.primary-label-btn { + color: theme(digitv2.lightTheme.primary); +} + +/* landing screen issue*/ + +.employeeCard { + .complaint-links-container .header .logo { + background-color: theme(digitv2.lightTheme.primary); + } + + .complaint-links-container .body { + &.link { + color: theme(digitv2.lightTheme.primary); + } + .inbox-total { + background-color: theme(digitv2.lightTheme.primary); + } + } +} + +.employee .topbar .right .user-img-txt { + background-color: theme(digitv2.lightTheme.primary); +} +/* button component issue*/ + +.action-bar-wrap { + .submit-bar { + background-color: theme(digitv2.lightTheme.primary); + } +} + +.jk-digit-secondary-btn { + color: theme(digitv2.lightTheme.primary); + border-color: theme(digitv2.lightTheme.primary); + + svg { + fill: theme(digitv2.lightTheme.primary); + + path { + fill: theme(digitv2.lightTheme.primary); + } + } +} +.error-boundary .error-container button { + background-color: theme(digitv2.lightTheme.primary); +} + +/* inbox screen issue*/ + +.inbox-search-wrapper { + .search-tabs-container .search-tab-head-selected { + color: theme(digitv2.lightTheme.primary); + border-color: theme(digitv2.lightTheme.primary); + } + .submit-bar { + background-color: theme(digitv2.lightTheme.primary); + } + .search-component-table .link { + color: theme(digitv2.lightTheme.primary); + } + .link-label { + color: theme(digitv2.lightTheme.primary) !important; + } +} +.drag-drop-container .drag-drop-text .browse-text { + color: theme(digitv2.lightTheme.primary); +} +/* toast new componnet css added */ + +.toast-success { + gap: 0.5rem; + height: 3rem; + padding: 0.75rem 0.5rem 0.75rem 0.75rem !important; + background-color: theme(digitv2.alert.success); + transition: bottom 0.5s ease; + grid-gap: 0.5rem; + &.error { + background-color: theme(digitv2.alert.error) !important; + } + + &.warning { + background-color: #f19100; + + &.warning-buttons { + @apply block; + } + } + + h2 { + @apply text-left overflow-hidden whitespace-no-wrap flex-grow flex items-center h-6; + letter-spacing: 0rem; + color: theme(digitv2.lightTheme.paper); + margin: 0rem; + text-overflow: ellipsis; + font-family: Roboto; + font-weight: 500; + font-size: 1.25rem; + font-style: normal; + } + svg { + @apply flex-shrink-0; + } +} + +@keyframes slideInFromBottom { + from { + bottom: -3rem; + } + to { + bottom: 4rem; + } +} + +.toast-success.animate { + animation: slideInFromBottom 0.5s ease forwards; +} + +@media screen and (max-width: 768px) { + .topbar { + background: #0b4b66 !important; + color: #fff; + } +} +header { + @extend .typography.text-heading-xl; +} + + +.digit-popup-wrap { + background: rgba(0, 0, 0, 0.7); + @apply flex fixed w-full h-full overflow-auto top-0 left-0 min-h-screen; + z-index: 10000; + max-width: 100% !important; + max-height: 100% !important; +} + +@screen dt { + .digit-popup-wrap { + background: rgba(0, 0, 0, 0.7); + @apply min-h-screen; + } +} + +.digit-popup-close-icon { + @apply flex justify-end; +} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss new file mode 100644 index 00000000000..e8f42d00428 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss @@ -0,0 +1,349 @@ +@import "./campaignCycle.scss"; +@import "./coreOverride.scss"; +@import "../../typography.scss"; + +.wbh-header-container { + margin-top: 1.5rem; +} +.main.digit-home-main { + margin-left: 92px; + .employee-app-wrapper.digit-home-app-wrapper { + margin-left: 0; + .ground-container.digit-home-ground { + padding: 0; + .employee-app-container.digit-home-employee-app { + .ground-container.moduleCardWrapper.gridModuleWrapper.digit-home-moduleCardWrapper { + gap: 2.5rem; + margin-top: 2rem; + padding: 0; + .employeeCard.customEmployeeCard.card-home.home-action-cards { + margin: 0 !important; + } + } + } + } + } +} +.campaign-cycle-container { + .popup-header-fix { + margin-top: 1.5rem !important; + } +} + +.tag.inbox-tag { + max-width: fit-content; + background-color: #d6d5d4; + border-radius: 2rem; + padding: 0.5rem; + display: flex; + align-items: center; + height: 2rem; + margin-bottom: 0.7rem; + grid-gap: 0.2rem; + gap: 0.2rem; +} +.mandatory-span { + margin-left: 0.5rem; + color: red !important; + font-size: 1rem; + font-weight: 700; +} + +.digit-employee-card-input.numeric { + margin-bottom: unset; +} + +.actionBarClass { + display: flex; + justify-content: space-between; + flex-direction: row-reverse; + z-index: 0; +} +.previous-button { + margin-left: 4rem; + min-width: 12.5rem; +} +.info-text { + padding-bottom: 1.5rem; +} + +.view-composer-header-section { + display: flex; + justify-content: space-between; + align-items: baseline; +} +.card-with-background { + margin-top: 1rem; + .card-head { + margin-bottom: 1rem; + color: #505a5f; + } +} +.no-data-found { + display: flex; + flex-direction: column; + align-items: center; + .error-msg { + margin-top: 1rem; + } +} +.search-tab-head { + color: #505a5f; +} +.search-tabs-container { + border-bottom: none; + margin-bottom: 0; +} +.delivery-preview-card { + margin-bottom: 1.5rem !important; + background-color: #fafafa; + border: 1px solid #d6d5d4; + width: 70%; + .custom-table-label { + font-size: 1.5rem; + font-weight: 700; + color: #505a5f; + margin-bottom: 1rem; + } + .campaign-attribute-table { + margin-bottom: 1rem; + table { + background-color: #fafafa; + border: 1px solid #d6d5d4; + border-collapse: collapse; + border-radius: 1rem; + th { + border: 1px solid #d6d5d4; + } + td { + padding: 1rem; + border: 1px solid #d6d5d4; + } + } + } + .campaign-product-table { + margin-bottom: 1rem; + table { + background-color: #fafafa; + border: 1px solid #d6d5d4; + border-collapse: collapse; + border-radius: 1rem; + tbody { + background-color: #fff; + } + th { + border: 1px solid #d6d5d4; + } + td { + padding: 1rem; + border: 1px solid #d6d5d4; + } + } + } +} +.cycle-paragraph { + font-weight: 700; + font-size: 24px; + color: #505a5f; + margin-top: 0.5rem; +} +.header-end { + margin-right: 1rem; +} +.digit-stepper-container { + margin-bottom: 1.5rem; +} +.employee-app-wrapper { + margin: 0rem 1rem; +} +input[type="date"]::-webkit-calendar-picker-indicator { + position: absolute; + right: 5px; + top: 20%; + transform: translateY(-10%); +} +.campaign-preview-edit-container { + display: flex; + gap: 1rem; + span { + color: theme(digitv2.lightTheme.primary); + } +} +.campaign-attribute-table { + tbody { + tr:nth-child(odd) { + background-color: white; + } + } +} + +.popup-wrap.campaign-data-preview { + flex-direction: column; +} + +.digit-employee-card-input.numeric { + pointer-events: none; +} +.product-tag-container { + display: flex; + flex-wrap: wrap; + gap: 1.5rem; + margin-bottom: 1rem; +} + +.workbench-download-template-btn { + font-weight: 700; +} +.digit-employee-card-input.numeric { + text-align: center; +} +.in-between { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 2rem; + @media screen and (min-width: 1024px) { + grid-gap: 10rem; + } +} +.setup-campaign { + .setup-campaign-card { + padding-bottom: 1.5rem; + } + .digit-dropdown-options-card { + max-height: 10rem !important; + } +} +.campaign-summary-container { + .setup-campaign-card { + .employeeCard.employeeCard-override { + padding: 1.5rem; + margin-bottom: 1.5rem !important; + } + } + .row { + justify-content: flex-start; + gap: 5rem; + h2 { + margin: 0; + width: 272px; + } + .value { + width: unset; + p { + margin: 0; + } + } + } +} +.view-composer-header-section { + .employee-card-sub-header { + @extend .typography.text-heading-m; + margin-bottom: 1.5rem; + } +} +.add-new-product-container { + border: 1px solid #d6d5d4; + background-color: #fafafa; + width: 70%; + padding-top: 0; + .heading-bar { + font-weight: 700; + display: flex; + align-items: baseline; + justify-content: space-between; + .card-text { + margin-top: 1rem; + margin-bottom: 1rem; + } + } + .label-field-pair { + gap: 5rem; + align-items: baseline; + .product-label-field { + width: 12rem; + text-wrap: nowrap; + font-weight: 700; + } + } +} +.page-padding-fix { + margin-top: 1.5rem; +} +.loginFormStyleEmployee { + .loginCardClassName { + .digit-header-content { + &:not(label) { + display: flex; + justify-content: center; + } + } + } +} +.selecting-boundaries-dropdown { + .digit-multiselectdropdown-server { + max-height: 15rem; + } +} +.hover { + cursor: pointer; +} +.digit-dropdown-employee-select-wrap { + .digit-dropdown-employee-select-wrap--elipses { + font-size: 1rem !important; + } +} +.digit-dropdown-employee-select-wrap.language-dropdown { + .digit-dropdown-options-card { + min-width: fit-content; + } +} +.campaign-pop-module { + padding: 1.5rem; + border-radius: 4px; + width: 36rem; +} +.campaign-modal-heading { + font-size: 2rem; + font-weight: 700; + margin: 0 !important; +} +.campaign-pop-main { + font-size: 1.25rem; + padding: 0 !important; + font-size: 400; + .card-text { + margin-bottom: 1.5rem !important; + } + .popup-module-action-bar.campaign-pop-action { + .selector-button-border { + background-color: #ffffff; + border: 1px solid #f47738; + h2 { + color: #f47738 !important; + } + } + } +} + +.digit-toast-success { + max-width: 90%; + margin-left: auto; + margin-right: auto; + height: auto; + .toast-label { + line-height: 1.5; + word-break: break-word; + height: auto; + white-space: unset; + } +} + +.digit-dropdown-select.error { + border: 1px solid #d4351c; +} +.campaign-type-wrapper { + .digit-error-icon-message-wrap { + margin-top: 4px; + font-size: 14px; + } +} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/typography.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/typography.scss new file mode 100644 index 00000000000..4a50014cf88 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/typography.scss @@ -0,0 +1,512 @@ +.typography { + &.text-heading-xl { + font-family: theme(digitv2.fontFamily.rc); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.bold); + color: theme(digitv2.lightTheme.text-primary); + line-height: theme(digitv2.lineHeight.normal); + + @media (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.heading-xl.desktop); + } + + @media (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.heading-xl.tablet); + } + + @media (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.heading-xl.mobile); + } + } + + &.text-heading-l { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.bold); + color: theme(digitv2.lightTheme.text-primary); + line-height: theme(digitv2.lineHeight.normal); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.heading-l.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.heading-l.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.heading-l.mobile); + } + } + + &.text-heading-m { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.bold); + color: theme(digitv2.lightTheme.text-primary); + line-height: theme(digitv2.lineHeight.normal); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.heading-m.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.heading-m.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.heading-m.desktop); + } + } + + &.text-heading-s { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.bold); + color: theme(digitv2.lightTheme.text-primary); + line-height: theme(digitv2.lineHeight.normal); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.heading-s.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.heading-s.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.heading-s.mobile); + } + } + + &.text-heading-xs { + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.heading-xs.mobile); + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.bold); + color: theme(digitv2.lightTheme.text-primary); + line-height: theme(digitv2.lineHeight.normal); + } + } + + &.text-caption-l { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.italic); + font-weight: theme(digitv2.fontWeight.medium); + color: theme(digitv2.lightTheme.text-primary); + line-height: theme(digitv2.lineHeight.normal); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.caption-l.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.caption-l.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.caption-l.mobile); + } + } + + &.text-caption-m { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.italic); + font-weight: theme(digitv2.fontWeight.medium); + color: theme(digitv2.lightTheme.text-primary); + line-height: theme(digitv2.lineHeight.normal); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.caption-m.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.caption-m.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.caption-m.mobile); + } + } + + &.text-caption-s { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.italic); + font-weight: theme(digitv2.fontWeight.medium); + color: theme(digitv2.lightTheme.text-primary); + line-height: theme(digitv2.lineHeight.normal); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.caption-s.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.caption-s.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.caption-s.desktop); + } + } + + &.text-body-l { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.italic); + font-weight: theme(digitv2.fontWeight.regular); + color: theme(digitv2.lightTheme.text-primary); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.body-l.desktop); + line-height: theme(digitv2.lineHeight.line-height-body-l.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.body-l.tablet); + line-height: theme(digitv2.lineHeight.line-height-body-l.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.body-l.mobile); + line-height: theme(digitv2.lineHeight.line-height-body-l.mobile); + } + } + + &.text-body-s { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.italic); + font-weight: theme(digitv2.fontWeight.regular); + color: theme(digitv2.lightTheme.text-primary); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.body-s.desktop); + line-height: theme(digitv2.lineHeight.line-height-body-s.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.body-s.tablet); + line-height: theme(digitv2.lineHeight.line-height-body-s.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.body-s.mobile); + line-height: theme(digitv2.lineHeight.line-height-body-s.mobile); + } + } + + &.text-body-xs { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.italic); + font-weight: theme(digitv2.fontWeight.regular); + color: theme(digitv2.lightTheme.text-primary); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.body-xs.desktop); + line-height: theme(digitv2.lineHeight.line-height-body-xs.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.body-xs.tablet); + line-height: theme(digitv2.lineHeight.line-height-body-xs.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.body-xs.mobile); + line-height: theme(digitv2.lineHeight.line-height-body-xs.mobile); + } + } + + &.text-label { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.italic); + font-weight: theme(digitv2.fontWeight.regular); + color: theme(digitv2.lightTheme.text-primary); + line-height: theme(digitv2.lineHeight.normal); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.label.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.label.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.label.mobile); + } + } + + &.text-link { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.regular); + color: theme(digitv2.lightTheme.text-primary); + line-height: theme(digitv2.lineHeight.normal); + text-decoration: theme(digitv2.textDecorationLine.underline); + + @media screen and (min-width: theme(digitv2.screens.desktop)) { + font-size: theme(digitv2.fontSize.link.desktop); + } + + @media screen and (min-width: theme(digitv2.screens.tablet)) { + font-size: theme(digitv2.fontSize.link.tablet); + } + + @media screen and (min-width: theme(digitv2.screens.mobile)) { + font-size: theme(digitv2.fontSize.link.mobile); + } + } + + &.heading-xl { + font-family: theme(digitv2.fontFamily.rc); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.bold); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.heading-xl.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.heading-xl.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.heading-xl.desktop); + } + } + + &.heading-l { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.bold); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.heading-l.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.heading-l.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.heading-l.desktop); + } + } + + &.heading-m { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.bold); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.heading-m.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.heading-m.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.heading-m.desktop); + } + } + + &.heading-s { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.bold); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.heading-s.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.heading-s.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.heading-s.desktop); + } + } + + &.heading-xs { + font-size: theme(digitv2.fontSize.heading-xs.mobile); + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.bold); + } + + &.caption-l { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.italic); + font-weight: theme(digitv2.fontWeight.medium); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.caption-l.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.caption-l.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.caption-l.desktop); + } + } + + &.caption-m { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.italic); + font-weight: theme(digitv2.fontWeight.medium); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.caption-m.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.caption-m.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.caption-m.desktop); + } + } + + &.caption-s { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.italic); + font-weight: theme(digitv2.fontWeight.medium); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.caption-s.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.caption-s.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.caption-s.desktop); + } + } + + &.body-l { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.regular); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.body-l.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.body-l.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.body-l.desktop); + } + } + + &.body-s { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.regular); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.body-s.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.body-s.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.body-s.desktop); + } + } + + &.body-xs { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.regular); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.body-xs.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.body-xs.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.body-xs.desktop); + } + } + + &.label { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.regular); + + @media (max-width: 30rem) { + /* Media query for mobile */ + font-size: theme(digitv2.fontSize.label.mobile); + } + + @media (min-width: 30.063rem) and (max-width: 47.938rem) { + /* Media query for tablets */ + font-size: theme(digitv2.fontSize.label.tablet); + } + + @media (min-width: 48rem) { + /* Media query for desktop */ + font-size: theme(digitv2.fontSize.label.desktop); + } + } + + &.link { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.regular); + text-decoration: theme(digitv2.textDecorationLine.underline); + font-size: theme(digitv2.fontSize.link.desktop); + } + + &.button { + font-family: theme(digitv2.fontFamily.sans); + font-style: theme(digitv2.fontStyle.normal); + font-weight: theme(digitv2.fontWeight.medium); + font-size: theme(digitv2.fontSize.button.desktop); + } +} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js b/frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js new file mode 100644 index 00000000000..b6a497b173d --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js @@ -0,0 +1,231 @@ +module.exports = { + future: { + removeDeprecatedGapUtilities: true, + purgeLayersByDefault: true, + }, + purge: { enabled: true, content: ["./example/index.html"] }, + theme: { + screens: { + dt: "780px", + sm: { max: "425px" }, + }, + colors: { + primary: { + light: "#F18F5E", + main: "#F47738", + dark: "#C8602B", + }, + secondary: "#22394D", + text: { + primary: "#0B0C0C", + secondary: "#505A5F", + }, + link: { + normal: "#1D70B8", + hover: "#003078", + }, + border: "#D6D5D4", + inputBorder: "#464646", + "input-border": "#464646", + focus: "#F47738", + error: "#D4351C", + success: "#00703C", + black: "#000000", + grey: { + dark: "#9E9E9E", + mid: "#EEEEEE", + light: "#FAFAFA", + bg: "#E3E3E3", + }, + white: "#FFFFFF", + }, + fontFamily: { + sans: ["Roboto", "sans-serif"], + rc: ['"Roboto Condensed"', "sans-serif"], + }, + fontSize: { + "heading-xl-dt": ["48px", "56px"], + "heading-xl": ["32px", "40px"], + "heading-l-dt": ["36px", "40px"], + "heading-l": ["24px", "32px"], + "heading-m-dt": ["24px", "32px"], + "heading-m": ["18px", "28px"], + "heading-s": ["16px", "24px"], + "caption-xl-dt": ["27px", "32px"], + "caption-xl": ["18px", "26px"], + "caption-l-dt": ["24px", "28px"], + "caption-l": ["18px", "21px"], + "caption-m-dt": ["19px", "23px"], + "caption-m": ["16px", "19px"], + "form-field": ["16px", "20px"], + "body-l-dt": ["19px", "28px"], + "body-l": ["16px", "24px"], + "body-s-dt": ["16px", "24px"], + "body-s": ["14px", "16px"], + legend: ["19px", "23px"], + link: ["16px", "24px"], + "text-btn": ["16px", "24px"], + }, + fontWeight: { + regular: 400, + medium: 500, + bold: 700, + }, + padding: { + sm: "8px", + md: "16px", + lg: "24px", + xl: "36px", + }, + margin: { + xs: "4px", + sm: "8px", + md: "16px", + lg: "24px", + xl: "64px", + }, + borderWidth: { + default: "1px", + 0: "0", + 2: "1px", + 4: "4px", + 10: "10px", + }, + boxShadow: { + card: "0 1px 2px 0 rgba(0, 0, 0, 0.16)", + radiobtn: "0 0 0 5px #F47738", + }, + inset: { + 0: 0, + 6: "6px", + 10: "10px", + }, + extend: {}, + digitv2: { + lightTheme: { + primary: "#C84C0E", + "text-color-primary": "#0B0C0C", + "text-color-secondary": "#505A5F", + "text-color-disabled": "#B1B4B6", + background: "#EEEEEE", + paper: "#FFFFFF", + "paper-secondary": "#FAFAFA", + divider: "#D6D5D4", + "header-sidenav": "#0B4B66", + "input-border": "#505A5F", + "primary-bg": "#FEEFE7", + }, + alert: { + error: "#b91900", + "error-bg": "#EFC7C1", + success: "#00703C", + "success-bg": "#BAD6C9", + info: "#3498DB", + "info-bg": "#C7E0F1", + }, + chart: { + "chart-1": "#048BD0", + "chart-1-gradient": "#048BD0", + "chart-2": "#FBC02D", + "chart-2-gradient": "#FBC02D", + "chart-3": "#8E29BF", + "chart-4": "#EA8A3B", + "chart-5": "#0BABDE", + }, + fontSize: { + "heading-xl": { + mobile: "2rem", + tablet: "2.25rem", + desktop: "2.5rem", + }, + "heading-l": { + mobile: "1.5rem", + tablet: "1.75rem", + desktop: "2rem", + }, + "heading-m": { + mobile: "1.25rem", + tablet: "1.375rem", + desktop: "1.5rem", + }, + "heading-s": { + mobile: "1rem", + tablet: "1rem", + desktop: "1rem", + }, + "heading-xs": { + mobile: "0.75rem", + }, + "caption-l": { + mobile: "1.5rem", + tablet: "1.75rem", + desktop: "1.75rem", + }, + "caption-m": { + mobile: "1.25rem", + tablet: "1.5rem", + desktop: "1.5rem", + }, + "caption-s": { + mobile: "1rem", + tablet: "1.25rem", + desktop: "1.25rem", + }, + "body-l": { + mobile: "1rem", + tablet: "1.25rem", + desktop: "1.25rem", + }, + "body-s": { + mobile: "0.875rem", + tablet: "1rem", + desktop: "1rem", + }, + "body-xs": { + mobile: "0.75rem", + tablet: "0.875rem", + desktop: "0.875rem", + }, + label: { + mobile: "1rem", + tablet: "1rem", + desktop: "1rem", + }, + link: { + mobile: "1rem", + tablet: "1rem", + desktop: "1rem", + }, + }, + fontFamily: { + sans: ["Roboto"], + rc: ['"Roboto Condensed"'], + }, + fontStyle: { + normal: "normal", + italic: "italic", + }, + textDecorationLine: { + underline: "underline", + }, + fontWeight: { + regular: 400, + medium: 500, + bold: 700, + }, + lineHeight: { + "line-height-body-l": { mobile: "1.5rem", tablet: "1.75rem", desktop: "1.75rem" }, + "line-height-body-s": { mobile: "1.0938rem", tablet: "1.5rem", desktop: "1.5rem" }, + "line-height-body-xs": { mobile: "1.125rem", tablet: "1.5rem", desktop: "1.5rem" }, + normal: "normal", + }, + screens: { + mobile: "400px", + tablet: "768px", + desktop: "1024px", + }, + }, + }, + variants: {}, + plugins: [], +}; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/README.md b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/README.md new file mode 100644 index 00000000000..0d206b3021e --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/README.md @@ -0,0 +1,159 @@ +# digit-ui-module-workbench + +## Install + +```bash +npm install --save digit-ui-module-workbench +``` + +## Limitation + +```bash +This Package is more specific to DIGIT-UI's can be used across mission's +``` + +## Usage + +After adding the dependency make sure you have this dependency in + +```bash +frontend/micro-ui/web/package.json +``` + +```json +"@egovernments/digit-ui-module-workbench":"1.0.0", +``` + +then navigate to App.js + +```bash + frontend/micro-ui/web/src/App.js +``` + +```jsx +/** add this import **/ + +import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench"; + +/** inside enabledModules add this new module key **/ + +const enabledModules = ["workbench"]; + +/** inside init Function call this function **/ + +const initDigitUI = () => { + initWorkbenchComponents(); +}; + +``` + +In MDMS + +_Add this configuration to enable this module [MDMS Enabling Workbench Module](https://github.com/egovernments/works-mdms-data/blob/588d241ba3a9ab30f4d4c2c387a513da811620ca/data/pg/tenant/citymodule.json#L227)_ + +## List of Screens available in this versions were as follows + +1 . Search Master Data + > -Provides a screen based on Schema and renders the search result if data is present + > -It also provides a dynamic filter based on which data can be filtered + + +2 . Add Master Data based on selected schema + > -Provides a screen to add new master data according to the schema + > -Provides a Dropdown if it has any referenced master + +3 . Update Master data for selected data. + > -View the master data from search screen + > -Disable/Enable the master data if required + > -Update the master data value except the unique-identifier field mentioned in the schema + + + +4 . Localisation screens + > -Provides a screen to search the localisation present in the environment + > -Add new localisation + > -Update existing localisation + > -Bulk Upload of Localisation data + +5 . MDMS UI Schema + +6 . Data push for any API based on schema + +### Mandatory changes to use Workbench module + +1 . Assuming core module is already updated with 1.5.38+ and related changes were taken + +2 . add the following hook method in micro-ui-internals/packages/libraries/src/hooks/useCustomAPIMutationHook.js + +reference:: +https://github.com/egovernments/DIGIT-Dev/blob/6e711bdc005c226c7debd533209681fc77078a3e/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/useCustomAPIMutationHook.js + +3 . add the following utility method in micro-ui-internals/packages/libraries/src/utils/index.js +```jsx +didEmployeeHasAtleastOneRole + +const didEmployeeHasAtleastOneRole = (roles = []) => { + return roles.some((role) => didEmployeeHasRole(role)); +}; + +``` + +4 . stylesheet link has to be added +```jsx + +``` +Reference commit for the enabling workbench +https://github.com/egovernments/DIGIT-OSS/pull/99/commits/6e711bdc005c226c7debd533209681fc77078a3e + + + +### Changelog + +```bash +1.0.1-beta.1 Republished after merging with Master due to version issues. +1.0.0-beta.14 Added info message in localisation search +1.0.0-beta.13 Added new role to support hcm localisation create +1.0.0-beta.13 Added customisable label for custom dropdown through workbench ui schema +1.0.0-beta.11 Added customisable label for custom dropdown through workbench ui schema +1.0.0-beta.10 fixed the dropdown undefined issue +1.0.0-beta.9 Added new role to support hcm manage masters +1.0.0-beta.8 minor fixes +1.0.0-beta.7 Added Bulk Upload Ui for MDMS Add +1.0.0-beta.6 Added Bulk Upload Ui for MDMS Add +1.0.0-beta.5 Fixed some loading issue +1.0.0-beta.2 custom api support added +1.0.0-beta.1 republished due to some version issues +1.0.1 Fixes related to the limits +1.0.0 Workbench v1.0 release +1.0.0-beta workbench base version beta release +0.0.3 readme updated +0.0.2 readme updated +0.0.1 base version +``` + +### Contributors + +- [jagankumar-egov](https://github.com/jagankumar-egov) +- [nipun-egov](https://github.com/nipun-egov) + + +## License + +[MIT](https://choosealicense.com/licenses/mit/) + +## Documentation + +Documentation Site (https://core.digit.org/guides/developer-guide/ui-developer-guide/digit-ui) +Workbench Documentation(https://workbench.digit.org/platform/functional-specifications/workbench-ui) + +## Maintainer + +- [jagankumar-egov](https://www.github.com/jagankumar-egov) + + +### Published from DIGIT Frontend +DIGIT Frontend Repo (https://github.com/egovernments/Digit-Frontend/tree/master) + + +![Logo](https://s3.ap-south-1.amazonaws.com/works-dev-asset/mseva-white-logo.png) + diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json new file mode 100644 index 00000000000..470bed80d1a --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json @@ -0,0 +1,51 @@ +{ + "name": "@egovernments/digit-ui-module-campaign-manager", + "version": "0.0.1", + "description": "Campaign", + "main": "dist/index.js", + "module": "dist/index.modern.js", + "source": "src/Module.js", + "files": [ + "dist" + ], + "scripts": { + "start": "microbundle-crl watch --no-compress --format modern,cjs", + "build": "microbundle-crl --compress --no-sourcemap --format cjs", + "prepublish": "yarn build" + }, + "peerDependencies": { + "react": "17.0.2", + "react-router-dom": "5.3.0" + }, + "dependencies": { + "@egovernments/digit-ui-react-components": "1.8.1-beta.23", + "@egovernments/digit-ui-components": "0.0.1-beta.30", + "@rjsf/core": "5.10.0", + "@rjsf/utils": "5.10.0", + "@rjsf/validator-ajv8": "5.10.0", + "ajv": "^8.12.0", + "react": "17.0.2", + "react-date-range": "1.4.0", + "react-dom": "17.0.2", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "react-router-dom": "5.3.0", + "react-select": "5.7.4", + "react-table": "7.7.0", + "xlsx": "0.17.5", + "react-drag-drop-files": "^2.3.10", + "@cyntler/react-doc-viewer": "1.10.3" + }, + "author": "JaganKumar ", + "license": "MIT", + "keywords": [ + "digit", + "egov", + "dpg", + "digit-ui", + "workbench", + "campaign", + "Campaign" + ] +} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js new file mode 100644 index 00000000000..cc2f33443d4 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js @@ -0,0 +1,141 @@ +import { Loader, TourProvider } from "@egovernments/digit-ui-react-components"; +import React from "react"; +import { useRouteMatch } from "react-router-dom"; +import EmployeeApp from "./pages/employee"; +import { CustomisedHooks } from "./hooks"; +import { UICustomizations } from "./configs/UICustomizations"; +import CampaignCard from "./components/CampaignCard"; +import CycleConfiguration from "./pages/employee/CycleConfiguration"; +import DeliverySetup from "./pages/employee/deliveryRule"; +import TimelineCampaign from "./components/TimelineCampaign"; +import CampaignDates from "./components/CampaignDates"; +import CampaignType from "./components/CampaignType"; +import CampaignName from "./components/CampaignName"; +import MyCampaign from "./pages/employee/MyCampaign"; +import CampaignSummary from "./components/CampaignSummary"; +import CycleDetaisPreview from "./components/CycleDetaisPreview"; +import Response from "./pages/employee/Response"; +import SelectingBoundaries from "./components/SelectingBoundaries"; +import UploadData from "./components/UploadData"; +import CampaignSelection from "./components/CampaignType"; +import CampaignDocumentsPreview from "./components/CampaignDocumentsPreview"; +import AddProduct from "./pages/employee/AddProduct"; +import AddProductField from "./components/AddProductField"; +import CycleDataPreview from "./components/CycleDataPreview"; +import { ErrorBoundary } from "@egovernments/digit-ui-components"; +import CampaignResourceDocuments from "./components/CampaignResourceDocuments"; + +/** + * The CampaignModule function fetches store data based on state code, module code, and language, and + * renders the EmployeeApp component within a TourProvider component if the data is not loading. + * @returns The CampaignModule component returns either a Loader component if data is still loading, or + * a TourProvider component wrapping an EmployeeApp component with specific props passed to it. + */ +const CampaignModule = ({ stateCode, userType, tenants }) => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + const { data: BOUNDARY_HIERARCHY_TYPE } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "hierarchyConfig" }], { + select: (data) => { + return data?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.hierarchy; + }, + }); + + const moduleCode = ["campaignmanager", "workbench", "mdms", "schema", "hcm-admin-schemas", `boundary-${BOUNDARY_HIERARCHY_TYPE}`]; + const { path, url } = useRouteMatch(); + const language = Digit.StoreData.getCurrentLanguage(); + const { isLoading, data: store } = Digit.Services.useStore({ + stateCode, + moduleCode, + language, + }); + + if (isLoading) { + return ; + } + + return ( + + + + + + ); +}; + +const componentsToRegister = { + CampaignModule: CampaignModule, + CampaignCard: CampaignCard, + UploadData, + DeliveryRule: DeliverySetup, + CycleConfiguration: CycleConfiguration, + TimelineCampaign, + CampaignDates, + CampaignType, + CampaignName, + MyCampaign, + CampaignSummary, + CycleDetaisPreview, + Response, + SelectingBoundaries, + CampaignSelection, + CampaignDocumentsPreview: CampaignDocumentsPreview, + AddProduct, + AddProductField, + CycleDataPreview, + CampaignResourceDocuments, +}; + +const overrideHooks = () => { + Object.keys(CustomisedHooks).map((ele) => { + if (ele === "Hooks") { + Object.keys(CustomisedHooks[ele]).map((hook) => { + Object.keys(CustomisedHooks[ele][hook]).map((method) => { + setupHooks(hook, method, CustomisedHooks[ele][hook][method]); + }); + }); + } else if (ele === "Utils") { + Object.keys(CustomisedHooks[ele]).map((hook) => { + Object.keys(CustomisedHooks[ele][hook]).map((method) => { + setupHooks(hook, method, CustomisedHooks[ele][hook][method], false); + }); + }); + } else { + Object.keys(CustomisedHooks[ele]).map((method) => { + setupLibraries(ele, method, CustomisedHooks[ele][method]); + }); + } + }); +}; + +/* To Overide any existing hook we need to use similar method */ +const setupHooks = (HookName, HookFunction, method, isHook = true) => { + window.Digit = window.Digit || {}; + window.Digit[isHook ? "Hooks" : "Utils"] = window.Digit[isHook ? "Hooks" : "Utils"] || {}; + window.Digit[isHook ? "Hooks" : "Utils"][HookName] = window.Digit[isHook ? "Hooks" : "Utils"][HookName] || {}; + window.Digit[isHook ? "Hooks" : "Utils"][HookName][HookFunction] = method; +}; +/* To Overide any existing libraries we need to use similar method */ +const setupLibraries = (Library, service, method) => { + window.Digit = window.Digit || {}; + window.Digit[Library] = window.Digit[Library] || {}; + window.Digit[Library][service] = method; +}; + +/* To Overide any existing config/middlewares we need to use similar method */ +const updateCustomConfigs = () => { + setupLibraries("Customizations", "commonUiConfig", { ...window?.Digit?.Customizations?.commonUiConfig, ...UICustomizations }); + // setupLibraries("Utils", "parsingUtils", { ...window?.Digit?.Utils?.parsingUtils, ...parsingUtils }); +}; + +/** + * The `initCampaignComponents` function initializes campaign components by overriding hooks, updating + * custom configurations, and registering components. + */ +const initCampaignComponents = () => { + overrideHooks(); + updateCustomConfigs(); + Object.entries(componentsToRegister).forEach(([key, value]) => { + Digit.ComponentRegistryService.setComponent(key, value); + }); +}; + +export { initCampaignComponents }; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AddProductField.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AddProductField.js new file mode 100644 index 00000000000..94a73fd6b24 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AddProductField.js @@ -0,0 +1,144 @@ +import React, { useState, useEffect } from "react"; +import { AddIcon, Button, Card, CardText, Header, TextInput, Dropdown } from "@egovernments/digit-ui-react-components"; +import { useTranslation } from "react-i18next"; +import { LabelFieldPair } from "@egovernments/digit-ui-react-components"; +import { DustbinIcon } from "./icons/DustbinIcon"; +// import { productType } from "../configs/productType"; +import { PRIMARY_COLOR } from "../utils"; + +const AddProductField = ({ onSelect }) => { + const { t } = useTranslation(); + const tenantId = Digit.ULBService.getCurrentTenantId(); + const { isLoading: productTypeLoading, data: productType } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "productType" }], { + select: (data) => { + return data?.["HCM-ADMIN-CONSOLE"]?.productType; + }, + }); + const [productFieldData, setProductFieldData] = useState([{ key: 1, name: null, type: null, variant: null }]); + + useEffect(() => { + onSelect("addProduct", productFieldData); + }, [productFieldData]); + + const addMoreField = () => { + setProductFieldData((prev) => [ + ...prev, + { + key: prev.length + 1, + name: null, + type: null, + variant: null, + }, + ]); + }; + + const deleteProductField = (index) => { + setProductFieldData((prev) => { + const temp = prev.filter((i) => i.key !== index); + return temp.map((i, n) => ({ ...i, key: n + 1 })); + }); + }; + + const handleUpdateField = (data, target, index) => { + setProductFieldData((prev) => { + return prev.map((i) => { + if (i.key === index) { + return { + ...i, + [target]: data, + }; + } + return { + ...i, + }; + }); + }); + }; + + return ( + +
{t(`HCM_CAMPAIGN_ADD_NEW_PRODUCT_HEADER`)}
+

+ {t(`HCM_CAMPAIGN_ADD_NEW_PRODUCT_DESCRIPTION_PRE_TEXT`)} {t(`HCM_CAMPAIGN_ADD_NEW_PRODUCT_DESCRIPTION_BOLD_TEXT`)} + {t(`HCM_CAMPAIGN_ADD_NEW_PRODUCT_DESCRIPTION_POST_TEXT`)} +

+ {productFieldData?.map((field, index) => { + return ( + +
+ Product {field?.key} + {productFieldData?.length > 1 && ( +
deleteProductField(field.key)} + style={{ + cursor: "pointer", + fontWeight: "600", + marginLeft: "1rem", + fontSize: "1rem", + color: PRIMARY_COLOR, + display: "flex", + gap: "0.5rem", + alignItems: "center", + marginTop: "1rem", + }} + > + + {t(`CAMPAIGN_DELETE_ROW_TEXT`)} +
+ )} +
+ +
+ {`${t("HCM_PRODUCT_NAME")}`} + * +
+ handleUpdateField(event.target.value, "name", field.key)} + /> +
+ +
+ {`${t("HCM_PRODUCT_TYPE")}`} + * +
+ { + handleUpdateField(value, "type", field.key); + }} + /> +
+ +
+ {`${t("HCM_PRODUCT_VARIANT")}`} + * +
+ handleUpdateField(event.target.value, "variant", field?.key)} + /> +
+
+ ); + })} + + ))} + + ); +}; + +const CycleDataPreview = ({ data, items, index }) => { + const { t } = useTranslation(); + const [deliveryData, setDeliveryData] = useState(data?.deliveries); + const [activeTab, setActiveTab] = useState(1); + + useEffect(() => { + setDeliveryData(data?.deliveries); + }, [data?.deliveries]); + + const handleTabChange = (tabIndex, index) => { + setDeliveryData((prev) => { + return prev.map((i) => { + if (i.deliveryIndex == tabIndex) { + return { + ...i, + active: true, + }; + } else { + return { + ...i, + active: false, + }; + } + }); + }); + }; + // return null; + return ( + <> +
+ {data?.startDate && ( + + )} + {data?.endDate && ( + + )} +
+ +
+ + + + {deliveryData + .find((i) => i.active === true) + ?.deliveryRules?.map((rules, ruleIndex) => { + return ( + + {rules?.attributes?.length > 0 && ( + + )} + {rules?.products?.length > 0 && ( + + )} + + ); + })} + + {/* + {item?.conditions?.length > 0 && ( + + )} + {item?.products?.length > 0 && ( + + )} + */} + + ); +}; + +export default CycleDataPreview; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDetaisPreview.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDetaisPreview.js new file mode 100644 index 00000000000..515b25191d9 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDetaisPreview.js @@ -0,0 +1,143 @@ +import { Card, LabelFieldPair, Row } from "@egovernments/digit-ui-react-components"; +import React, { Fragment } from "react"; +import { useTranslation } from "react-i18next"; +import DetailsTable from "./DetailsTable"; + +function mergeObjects(item) { + const arr = item?.conditions; + const mergedArr = []; + const mergedAttributes = new Set(); + + arr.forEach((obj) => { + if (!mergedAttributes.has(obj.attribute)) { + const sameAttrObjs = arr.filter((o) => o.attribute === obj.attribute); + + if (sameAttrObjs.length > 1) { + const fromValue = Math.min(...sameAttrObjs.map((o) => o.value)); + const toValue = Math.max(...sameAttrObjs.map((o) => o.value)); + + mergedArr.push({ + fromValue, + toValue, + value: fromValue > 0 && toValue > 0 ? `${fromValue} to ${toValue}` : null, + operator: "IN_BETWEEN", + attribute: obj.attribute, + }); + + mergedAttributes.add(obj.attribute); + } else { + mergedArr.push(obj); + } + } + }); + + return { ...item, conditions: mergedArr }; +} + +const CycleDetaisPreview = ({ data, items, index }) => { + const { t } = useTranslation(); + const item = mergeObjects(items); + + return ( + <> + + + {/* + {`${t("CYCLE_NUMBER")}`} + {item?.cycleNumber} + + + {`${t("DELIVERY_NUMBER")}`} + {item?.deliveryNumber} + */} + {item?.startDate || item?.endDate ? ( + +
+

+ {t(`CYCLE`)} {item?.cycleNumber} +

+
+ {item?.startDate && ( + + )} + {item?.endDate && ( + + )} +
+ ) : null} + + + {item?.conditions?.length > 0 && ( + + )} + {item?.products?.length > 0 && ( + + )} + + + ); +}; + +export default CycleDetaisPreview; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DetailsTable.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DetailsTable.js new file mode 100644 index 00000000000..5c6e01fcc22 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DetailsTable.js @@ -0,0 +1,76 @@ +import React, { Fragment } from "react"; +import { useTable } from "react-table"; +import { useTranslation } from "react-i18next"; +import { CardLabel, CardSubHeader } from "@egovernments/digit-ui-react-components"; + +const DetailsTable = ({ className = "", columnsData, rowsData, summaryRows, cardHeader }) => { + const { t } = useTranslation(); + + const columns = React.useMemo(() => columnsData, [t]); + + const data = React.useMemo(() => { + const temp = rowsData.map((i) => ({ + ...i, + operator: t(i?.operator), + attribute: i?.attribute ? t(`CAMPAIGN_ATTRIBUTE_${i?.attribute?.toUpperCase()}`) : "", + })); + return temp; + }, [rowsData]); + + const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable({ + columns, + data, + }); + + return ( + <> + {cardHeader && ( + + {cardHeader?.value} + + )} +
+ + + {headerGroups.map((headerGroup) => ( + + {headerGroup.headers.map((column) => ( + + ))} + + ))} + + + + {rows.map((row) => { + prepareRow(row); + return ( + + {row.cells.map((cell) => ( + + ))} + + ); + })} + + {summaryRows && ( + + {summaryRows.map((cell, index) => ( + + ))} + + )} + +
+ {column.render("Header")} +
+ {cell.render("Cell")} +
+ {index === 4 ? {cell} : cell} +
+
+ + ); +}; + +export default DetailsTable; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DocumentIcon.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DocumentIcon.js new file mode 100644 index 00000000000..9b61bf67136 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DocumentIcon.js @@ -0,0 +1,29 @@ +import React from "react"; +export const DocumentIcon = ({ styles = {}, className, fill = "#D4351C" }) => ( + + + + + + + + + + + + + + + + + + + + +); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/PlusMinusInput.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/PlusMinusInput.js new file mode 100644 index 00000000000..89d7b574032 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/PlusMinusInput.js @@ -0,0 +1,47 @@ +import React, { useState } from "react"; + +const PlusMinusInput = (props, customProps) => { + let count = props?.defaultValues || 1; + + function incrementCount() { + if (count >= 1) { + count = count + 1; + props.onSelect(count); + } else { + count = 1; + props.onSelect(count); + } + } + function decrementCount() { + if (count > 1) { + count = count - 1; + props.onSelect(count); + } else { + count = 1; + props.onSelect(count); + } + } + + return ( + +
+ + + +
+
+ ); +}; + +export default PlusMinusInput; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RemovableTagNew.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RemovableTagNew.js new file mode 100644 index 00000000000..b04159181a6 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RemovableTagNew.js @@ -0,0 +1,16 @@ +import React from "react"; +import { Close } from "@egovernments/digit-ui-react-components"; + +const RemoveableTagNew = ({ text = {}, onClick, extraStyles, disabled = false }) => ( +
+ {text?.label && {`${text?.label} :`}} + + {text?.value} + + + + +
+); + +export default RemoveableTagNew; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js new file mode 100644 index 00000000000..00c7a500501 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js @@ -0,0 +1,479 @@ +import React, { useEffect, useState, Fragment ,useMemo} from "react"; +import { CardText, LabelFieldPair, Card, Header, CardLabel, Modal } from "@egovernments/digit-ui-react-components"; +import { useTranslation } from "react-i18next"; +import { Dropdown, InfoCard, MultiSelectDropdown, Toast } from "@egovernments/digit-ui-components"; +import { mailConfig } from "../configs/mailConfig"; +/** + * The function `SelectingBoundaries` in JavaScript handles the selection of boundaries based on + * hierarchy data and allows users to choose specific boundaries within the hierarchy. + * @returns The `SelectingBoundaries` component is being returned. It consists of JSX elements + * including Cards, Headers, Dropdowns, MultiSelectDropdowns, and InfoCard. The component allows users + * to select hierarchy types and boundaries based on the data fetched from API calls. It also handles + * the selection of boundaries and updates the state accordingly. The component is designed to be + * interactive and user-friendly for selecting boundaries within + */ +function SelectingBoundaries({ onSelect, formData, ...props }) { + const { t } = useTranslation(); + const tenantId = Digit.ULBService.getCurrentTenantId(); + const [params, setParams] = useState(props?.props?.dataParams); + const [hierarchy, setHierarchy] = useState(params?.hierarchyType); + const [boundaryType, setBoundaryType] = useState( + props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData ? undefined : null + ); + const [boundaryData, setBoundaryData] = useState(props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData || {}); + // const [parentArray, setParentArray] = useState(props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData.filter(item => item.includeAllChildren).map(item => item.code) || null); + const [parentArray, setParentArray] = useState(null); + const [boundaryTypeDataresult, setBoundaryTypeDataresult] = useState(null); + const [selectedData, setSelectedData] = useState(props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData || []); + const [parentBoundaryTypeRoot, setParentBoundaryTypeRoot] = useState( + (props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData?.find((item) => item?.isRoot === true) || {}) + ?.boundaryType || null + ); + const [showToast, setShowToast] = useState(null); + const [updatedHierarchy, setUpdatedHierarchy] = useState({}); + const [hierarchyTypeDataresult, setHierarchyTypeDataresult] = useState(params?.hierarchy); + const [executionCount, setExecutionCount] = useState(0); + // State variable to store the lowest hierarchy level + // const [lowestHierarchy, setLowestHierarchy] = useState(null); + const [showPopUp, setShowPopUp] = useState(null); + const [restrictSelection, setRestrictSelection] = useState(null); + const [updateBoundary, setUpdateBoundary] = useState(null); + const { isLoading, data: hierarchyConfig } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "hierarchyConfig" }]); + + // const lowestHierarchy = hierarchyConfig?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.lowestHierarchy; + const lowestHierarchy = useMemo(() => hierarchyConfig?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.lowestHierarchy, [hierarchyConfig]); + const lowestChild = hierarchyTypeDataresult?.boundaryHierarchy.filter((item => item.parentBoundaryType === lowestHierarchy))?.[0]?.boundaryType; + const searchParams = new URLSearchParams(location.search); + const isDraft = searchParams.get("draft"); + + useEffect(() => { + if (!updateBoundary) { + if ( + props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile?.length > 0 || + props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile?.length > 0 || + props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile?.length > 0 + ) { + setRestrictSelection(true); + } + } + }, [props?.props?.sessionData, updateBoundary]); + + useEffect(() => { + if (props?.props?.dataParams) { + setParams(props?.props?.dataParams); + } + }, [props?.props?.dataParams]); + + useEffect(() => { + onSelect("boundaryType", { boundaryData: boundaryData, selectedData: selectedData, updateBoundary: updateBoundary }); + }, [boundaryData, selectedData]); + + useEffect(() => { + setHierarchy(params?.hierarchyType); + }, [params?.hierarchyType]); + + useEffect(() => { + setHierarchyTypeDataresult(params?.hierarchy); + }, [params?.hierarchy]); + + useEffect(() => { + if (executionCount < 5) { + onSelect("boundaryType", { boundaryData: boundaryData, selectedData: selectedData, updateBoundary: updateBoundary }); + setExecutionCount((prevCount) => prevCount + 1); + } + }); + + useEffect(() => { + setBoundaryData( + props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData + ? props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData + : {} + ); + setSelectedData( + props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData + ? props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData + : [] + ); + }, [props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType]); + + const closeToast = () => { + setShowToast(null); + }; + + useEffect(() => { + if (hierarchyTypeDataresult) { + const boundaryDataObj = {}; + hierarchyTypeDataresult?.boundaryHierarchy?.forEach((boundary) => { + boundaryDataObj[boundary?.boundaryType] = []; + }); + if (!props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData || Object.keys(boundaryData).length === 0) { + setBoundaryData(boundaryDataObj); + } + const boundaryWithTypeNullParent = hierarchyTypeDataresult?.boundaryHierarchy?.find((boundary) => boundary?.parentBoundaryType === null); + // Set the boundary type with null parentBoundaryType + if (boundaryWithTypeNullParent) { + if (!props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData || Object.keys(boundaryData).length === 0) { + setBoundaryType(boundaryWithTypeNullParent?.boundaryType); + } + setParentBoundaryTypeRoot(boundaryWithTypeNullParent?.boundaryType); + } + createHierarchyStructure(hierarchyTypeDataresult); + + } + }, [hierarchyTypeDataresult]); + + function createHierarchyStructure(hierarchyTypeDataresult) { + const hierarchyStructure = {}; + + // Recursive function to gather all descendants for a given boundary type + function gatherDescendants(boundaryType) { + const descendants = []; + hierarchyTypeDataresult; + + // Find all children for the current boundary type + const children = hierarchyTypeDataresult?.boundaryHierarchy?.filter((item) => item?.parentBoundaryType === boundaryType); + + // Recursively gather descendants for each child + children.forEach((child) => { + const childBoundaryType = child?.boundaryType; + const childDescendants = gatherDescendants(childBoundaryType); + descendants.push(childBoundaryType, ...childDescendants); + }); + + return descendants; + } + + // Iterate through the boundaryHierarchy array to populate hierarchyStructure + hierarchyTypeDataresult?.boundaryHierarchy?.forEach((item) => { + const boundaryType = item?.boundaryType; + const descendants = gatherDescendants(boundaryType); + + hierarchyStructure[boundaryType] = descendants; + }); + + setUpdatedHierarchy(hierarchyStructure); + } + + const newData = []; + const fetchBoundaryTypeData = async () => { + if (boundaryType === undefined || boundaryType === lowestChild) { + // Do nothing if boundaryType is undefined + return; + } + if (parentArray === null) { + const reqCriteriaBoundaryTypeSearch = Digit.CustomService.getResponse({ + url: "/boundary-service/boundary-relationships/_search", + params: { + tenantId: tenantId, + hierarchyType: hierarchy, + boundaryType: boundaryType, + parent: null, + }, + body: {}, + }); + // setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_LOADING_BOUNDARY") }); + const boundaryTypeData = await reqCriteriaBoundaryTypeSearch; + setBoundaryTypeDataresult([{ parentCode: null, boundaryTypeData: boundaryTypeData }]); + // closeToast(); + } else { + for (const parentCode of parentArray) { + const reqCriteriaBoundaryTypeSearch = Digit.CustomService.getResponse({ + url: "/boundary-service/boundary-relationships/_search", + params: { + tenantId: tenantId, + hierarchyType: hierarchy, + boundaryType: boundaryType, + parent: parentCode, + }, + body: {}, + }); + setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_LOADING_BOUNDARY") }); + const boundaryTypeData = await reqCriteriaBoundaryTypeSearch; + newData.push({ parentCode, boundaryTypeData }); + } + setBoundaryTypeDataresult(newData); + closeToast(); + } + }; + + useEffect(() => { + fetchBoundaryTypeData(); + }, [boundaryType, parentArray ,selectedData]); + + useEffect(() => { + if (boundaryTypeDataresult) { + if (boundaryType !== undefined) { + const updatedBoundaryData = { + ...boundaryData, + [boundaryType]: boundaryTypeDataresult, + }; + setBoundaryData(updatedBoundaryData); + } else { + const updatedBoundaryData = { + ...boundaryData, + [boundaryTypeDataresult?.[0]?.boundaryTypeData?.TenantBoundary?.[0]?.boundary?.[0]?.boundaryType]: boundaryTypeDataresult, + }; + setBoundaryData(updatedBoundaryData); + } + } + }, [boundaryTypeDataresult]); + + const checkDataPresent = ({ action }) => { + if (action === false) { + setShowPopUp(false); + setUpdateBoundary(true); + setRestrictSelection(false); + return; + } + if (action === true) { + setShowPopUp(false); + setUpdateBoundary(false); + return; + } + }; + + const handleBoundaryChange = (data, boundary) => { + if ( + !updateBoundary && + restrictSelection && + (props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile?.length > 0 || + props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile?.length > 0 || + props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile?.length > 0) + ) { + setShowPopUp(true); + return; + } + if (!data || data.length === 0) { + const check = updatedHierarchy[boundary?.boundaryType]; + + if (check) { + const typesToRemove = [boundary?.boundaryType, ...check]; + const updatedSelectedData = selectedData?.filter((item) => !typesToRemove?.includes(item?.type)); + const updatedBoundaryData = { ...boundaryData }; + + typesToRemove.forEach((type) => { + if (type !== boundary?.boundaryType && updatedBoundaryData?.hasOwnProperty(type)) { + updatedBoundaryData[type] = []; + } + }); + setSelectedData(updatedSelectedData); + setBoundaryData(updatedBoundaryData); + } + return; + } + + let res = []; + data && + data?.map((ob) => { + res.push(ob?.[1]); + }); + + // const transformedRes = res?.map((item) => ({ + // code: item.code, + // type: item.type || item.boundaryType, + // isRoot: item.boundaryType === parentBoundaryTypeRoot, + // includeAllChildren: item.type === lowestHierarchy || item.boundaryType === lowestHierarchy, + // parent: item?.parent, + // })); + + let transformedRes =[]; + if(!isDraft){ + transformedRes = res?.map((item) => ({ + code: item.code, + type: item.type || item.boundaryType, + isRoot: item.boundaryType === parentBoundaryTypeRoot, + includeAllChildren: item.type === lowestHierarchy || item.boundaryType === lowestHierarchy, + parent: item?.parent, + })); + } + else{ + // transformedRes = selectedData.filter((item) => item?.type === boundary?.boundaryType) + const filteredData = selectedData.filter((item) => item?.type === boundary?.boundaryType); + if (filteredData.length === 0) { + // If no selected data for the particular boundary type, run the transformation logic + transformedRes = res?.map((item) => ({ + code: item.code, + type: item.type || item.boundaryType, + isRoot: item.boundaryType === parentBoundaryTypeRoot, + includeAllChildren: item.type === lowestHierarchy || item.boundaryType === lowestHierarchy, + parent: item?.parent, + })); + } else { + transformedRes = filteredData; + } + } + + const newBoundaryType = transformedRes?.[0]?.type; + const existingBoundaryType = selectedData?.length > 0 ? selectedData?.[0]?.type : null; + if (existingBoundaryType === newBoundaryType) { + // Update only the data for the specific boundaryType + const flattenedRes = transformedRes.flat(); + const updatedSelectedData = selectedData + ?.map((item) => { + if (item.type === newBoundaryType) { + return transformedRes?.flat(); + } else { + return item; + } + }) + .flat(); + + setSelectedData(updatedSelectedData); + } else { + // Update only the data for the new boundaryType + const mergedData = [...selectedData?.filter((item) => item?.type !== newBoundaryType), ...transformedRes]; + + // Filter out items with undefined type + const filteredData = mergedData?.filter( + (item, index, self) => item?.type !== undefined && index === self?.findIndex((t) => t?.code === item?.code) + ); + + // Filter out items whose parent is not present in the array + + const updatedSelectedData = []; + const addChildren = (item) => { + updatedSelectedData.push(item); + const children = filteredData.filter((child) => child.parent === item.code); + children.forEach((child) => addChildren(child)); + }; + filteredData.filter((item) => item.isRoot).forEach((rootItem) => addChildren(rootItem)); + + setSelectedData(updatedSelectedData); + } + const parentBoundaryEntry = hierarchyTypeDataresult + ? hierarchyTypeDataresult?.boundaryHierarchy?.find( + (e) => e?.parentBoundaryType === res?.[0]?.boundaryType || e?.parentBoundaryType === res?.[0]?.type + ) + : null; + setBoundaryType(parentBoundaryEntry?.boundaryType); + const codes = res?.map((item) => item?.code); + if (JSON.stringify(codes) !== JSON.stringify(parentArray)) { + setParentArray(codes); + } + }; + + return ( + <> + +
+
{t(`CAMPAIGN_SELECT_BOUNDARY`)}
+ {t(`CAMPAIGN_SELECT_BOUNDARIES_DESCRIPTION`)} + {hierarchyTypeDataresult?.boundaryHierarchy + .filter((boundary, index, array) => { + // Find the index of the lowest hierarchy + const lowestIndex = array.findIndex((b) => b.boundaryType === lowestHierarchy); + // Include only those boundaries that are above or equal to the lowest hierarchy + return index <= lowestIndex; + }) + .map((boundary, index) => + boundary?.parentBoundaryType == null ? ( + + + {/* {t(`${hierarchy}_${boundary?.boundaryType}`?.toUpperCase())} */} + {t((hierarchy + "_" + boundary?.boundaryType).toUpperCase())} + + * + +
+ item?.boundaryTypeData?.TenantBoundary?.[0]?.boundary)?.flat() || []} + optionsKey={"code"} + selected={selectedData?.filter((item) => item?.type === boundary?.boundaryType) || []} + onSelect={(value) => { + handleBoundaryChange(value, boundary); + }} + /> +
+
+ ) : ( + + + {t((hierarchy + "_" + boundary?.boundaryType).toUpperCase())} + * + +
+ ({ + code: item?.parentCode, + options: + item?.boundaryTypeData?.TenantBoundary?.[0]?.boundary?.map((child) => ({ + code: child?.code, + type: child?.boundaryType, + parent: item?.parentCode, + })) || [], + })) || [] + } + optionsKey={"code"} + onSelect={(value) => { + handleBoundaryChange(value, boundary); + }} + selected={selectedData?.filter((item) => item?.type === boundary?.boundaryType) || []} + addCategorySelectAllCheck={true} + addSelectAllCheck={true} + variant="nestedmultiselect" + /> +
+
+ ) + )} +
+
+ + {t("HCM_BOUNDARY_INFO ")} + + {mailConfig?.mailId} + + , + ]} + label={"Info"} + /> + {showPopUp && ( + {t("ES_CAMPAIGN_UPDATE_BOUNDARY_MODAL_HEADER")}} + actionCancelLabel={t("ES_CAMPAIGN_BOUNDARY_MODAL_BACK")} + actionCancelOnSubmit={() => checkDataPresent({ action: false })} + actionSaveLabel={t("ES_CAMPAIGN_BOUNDARY_MODAL_SUBMIT")} + actionSaveOnSubmit={() => checkDataPresent({ action: true })} + customTheme="v-campaign" + formId="modal-action" + > +
+ {t("ES_CAMPAIGN_UPDATE_BOUNDARY_MODAL_TEXT") + " "} +
+
+ )} + {showToast && ( + + )} + + ); +} +export default SelectingBoundaries; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/TimelineCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/TimelineCampaign.js new file mode 100644 index 00000000000..8e4f6062d86 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/TimelineCampaign.js @@ -0,0 +1,46 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import { TickMark } from "@egovernments/digit-ui-react-components"; + +let actions = []; + +const getAction = (flow) => { + switch (flow) { + case "STAKEHOLDER": + actions = ["BPA_LICENSE_DETAILS_LABEL", "BPA_NEW_ADDRESS_HEADER_DETAILS", "BPA_DOC_DETAILS_SUMMARY", "BPA_STEPPER_SUMMARY_HEADER"]; + break; + case "OCBPA": + actions = ["BPA_BASIC_AND_PLOT_DETAILS_LABEL", "BPA_SCRUTINY_DETAILS", "BPA_DOCUMENT_AND_NOC_DETAILS_LABEL", "BPA_STEPPER_SUMMARY_HEADER"]; + break; + default: + actions = [ + "HCM_CAMPAIGN_SETUP_DETAILS", + "HCM_DELIVERY_DETAILS", + "HCM_BOUNDARY_DETAILS", + "HCM_TARGETS", + "HCM_FACILITY_DETAILS", + "HCM_USER_DETAILS", + "HCM_REVIEW_DETAILS", + ]; + } +}; +const TimelineCampaign = ({ currentStep = 1, flow = "" , onStepClick }) => { + const { t } = useTranslation(); + const isMobile = window.Digit.Utils.browser.isMobile(); + getAction(flow); + return ( +
+ {actions.map((action, index, arr) => ( +
onStepClick(index)}> +
+ {index < currentStep - 1 ? : index + 1} + {t(action)} +
+ {index < arr.length - 1 && } +
+ ))} +
+ ); +}; + +export default TimelineCampaign; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js new file mode 100644 index 00000000000..57a66d1fa16 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js @@ -0,0 +1,843 @@ +import { Button, Header, LoaderWithGap } from "@egovernments/digit-ui-react-components"; +import React, { useRef, useState, useEffect, Fragment } from "react"; +import { useTranslation } from "react-i18next"; +import { DownloadIcon, Card } from "@egovernments/digit-ui-react-components"; +import BulkUpload from "./BulkUpload"; +import Ajv from "ajv"; +import XLSX from "xlsx"; +import { InfoCard, Toast } from "@egovernments/digit-ui-components"; +import { schemaConfig } from "../configs/schemaConfig"; +import { headerConfig } from "../configs/headerConfig"; +import { PRIMARY_COLOR } from "../utils"; +import { downloadExcelWithCustomName } from "../utils"; + +/** + * The `UploadData` function in JavaScript handles the uploading, validation, and management of files + * for different types of data in a web application. + * @returns The `UploadData` component is returning a JSX structure that includes a div with class + * names, a Header component, a Button component for downloading a template, an info-text div, a + * BulkUpload component for handling file uploads, and an InfoCard component for displaying error + * messages if any validation errors occur during file upload. + */ +const UploadData = ({ formData, onSelect, ...props }) => { + const { t } = useTranslation(); + const tenantId = Digit.ULBService.getCurrentTenantId(); + const [uploadedFile, setUploadedFile] = useState([]); + const params = Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_UPLOAD_ID"); + const [showInfoCard, setShowInfoCard] = useState(false); + const [errorsType, setErrorsType] = useState({}); + const [schema, setSchema] = useState(null); + const [showToast, setShowToast] = useState(null); + const type = props?.props?.type; + const [executionCount, setExecutionCount] = useState(0); + const [isError, setIsError] = useState(false); + const [isSuccess, setIsSuccess] = useState(false); + const [apiError, setApiError] = useState(null); + const [isValidation, setIsValidation] = useState(false); + const [fileName, setFileName] = useState(null); + const [downloadError, setDownloadError] = useState(false); + const [resourceId, setResourceId] = useState(null); + const searchParams = new URLSearchParams(location.search); + const id = searchParams.get("id"); + const { isLoading, data: Schemas } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [ + { name: "facilitySchema" }, + { name: "userSchema" }, + { name: "Boundary" }, + ]); + + const { data: readMe } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "ReadMeConfig" }]); + const [sheetHeaders, setSheetHeaders] = useState({}); + const [translatedSchema, setTranslatedSchema] = useState({}); + const [readMeInfo, setReadMeInfo] = useState({}); + + useEffect(() => { + if (type === "facilityWithBoundary") { + onSelect("uploadFacility", { uploadedFile, isError, isValidation, apiError, isSuccess }); + } else if (type === "boundary") { + onSelect("uploadBoundary", { uploadedFile, isError, isValidation, apiError, isSuccess }); + } else { + onSelect("uploadUser", { uploadedFile, isError, isValidation, apiError, isSuccess }); + } + }, [uploadedFile, isError, isValidation, apiError, isSuccess]); + + useEffect(() => { + if (resourceId) { + setUploadedFile((prev) => + prev.map((i) => ({ + ...i, + resourceId: resourceId, + })) + ); + } + }, [resourceId]); + var translateSchema = (schema) => { + var newSchema = { ...schema }; + var newProp = {}; + + Object.keys(schema?.properties) + .map((e) => ({ key: e, value: t(e) })) + .map((e) => { + newProp[e.value] = schema?.properties[e.key]; + }); + const newRequired = schema?.required.map((e) => t(e)); + + newSchema.properties = newProp; + newSchema.required = newRequired; + delete newSchema.unique; + return { ...newSchema }; + }; + + var translateReadMeInfo = (schema) => { + const translatedSchema = schema.map((item) => { + return { + header: t(item.header), + isHeaderBold: item.isHeaderBold, + inSheet: item.inSheet, + inUiInfo: item.inUiInfo, + descriptions: item.descriptions.map((desc) => { + return { + text: t(desc.text), + isStepRequired: desc.isStepRequired, + }; + }), + }; + }); + return translatedSchema; + }; + + useEffect(async () => { + if (Schemas?.["HCM-ADMIN-CONSOLE"]) { + const newFacilitySchema = await translateSchema(Schemas?.["HCM-ADMIN-CONSOLE"]?.facilitySchema?.[0]); + const newBoundarySchema = await translateSchema(Schemas?.["HCM-ADMIN-CONSOLE"]?.Boundary?.[0]); + const newUserSchema = await translateSchema(Schemas?.["HCM-ADMIN-CONSOLE"]?.userSchema?.[0]); + const headers = { + boundary: Object?.keys(newBoundarySchema?.properties), + facilityWithBoundary: Object?.keys(newFacilitySchema?.properties), + userWithBoundary: Object?.keys(newUserSchema?.properties), + }; + + const schema = { + boundary: newBoundarySchema, + facilityWithBoundary: newFacilitySchema, + userWithBoundary: newUserSchema, + }; + + setSheetHeaders(headers); + setTranslatedSchema(schema); + } + }, [Schemas?.["HCM-ADMIN-CONSOLE"], type]); + + useEffect(async () => { + if (readMe?.["HCM-ADMIN-CONSOLE"]) { + const newReadMeFacility = await translateReadMeInfo( + readMe?.["HCM-ADMIN-CONSOLE"]?.ReadMeConfig?.filter((item) => item.type === type)?.[0]?.texts + ); + const newReadMeUser = await translateReadMeInfo(readMe?.["HCM-ADMIN-CONSOLE"]?.ReadMeConfig?.filter((item) => item.type === type)?.[0]?.texts); + const newReadMeboundary = await translateReadMeInfo( + readMe?.["HCM-ADMIN-CONSOLE"]?.ReadMeConfig?.filter((item) => item.type === type)?.[0]?.texts + ); + + const readMeText = { + boundary: newReadMeboundary, + facilityWithBoundary: newReadMeFacility, + userWithBoundary: newReadMeUser, + }; + + setReadMeInfo(readMeText); + } + }, [readMe?.["HCM-ADMIN-CONSOLE"], type]); + + useEffect(() => { + if (executionCount < 5) { + let uploadType = "uploadUser"; + if (type === "boundary") { + uploadType = "uploadBoundary"; + } else if (type === "facilityWithBoundary") { + uploadType = "uploadFacility"; + } + onSelect(uploadType, { uploadedFile }); + setExecutionCount((prevCount) => prevCount + 1); + } + }); + + useEffect(() => { + switch (type) { + case "boundary": + setUploadedFile(props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile || []); + setApiError(null); + setIsValidation(false); + setDownloadError(false); + setIsError(false); + setIsSuccess(props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.isSuccess || null); + break; + case "facilityWithBoundary": + setUploadedFile(props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile || []); + setApiError(null); + setIsValidation(false); + setDownloadError(false); + setIsError(false); + setIsSuccess(props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.isSuccess || null); + break; + default: + setUploadedFile(props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile || []); + setApiError(null); + setIsValidation(false); + setDownloadError(false); + setIsError(false); + setIsSuccess(props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.isSuccess || null); + break; + } + }, [type, props?.props?.sessionData]); + + useEffect(() => { + if (errorsType[type]) { + setShowInfoCard(true); + } else { + setShowInfoCard(false); + } + }, [type, errorsType]); + + const validateData = (data) => { + const ajv = new Ajv(); // Initialize Ajv + let validate = ajv.compile(translatedSchema[type]); + const errors = []; // Array to hold validation errors + + data.forEach((item, index) => { + if (!validate(item)) { + errors.push({ index: item?.["!row#number!"] + 1, errors: validate.errors }); + } + }); + + if (errors.length > 0) { + const errorMessage = errors + .map(({ index, errors }) => { + const formattedErrors = errors + .map((error) => { + let formattedError = `${error.instancePath}: ${error.message}`; + if (error.keyword === "enum" && error.params && error.params.allowedValues) { + formattedError += `. Allowed values are: ${error.params.allowedValues.join("/ ")}`; + } + return formattedError; + }) + .join(", "); + return `Data at row ${index}: ${formattedErrors}`; + }) + .join(" , "); + + setErrorsType((prevErrors) => ({ + ...prevErrors, + [type]: errorMessage, + })); + setIsError(true); + return false; + } else { + setErrorsType((prevErrors) => ({ + ...prevErrors, + [type]: "", // Clear the error message + })); + setShowInfoCard(false); + return true; + } + }; + + const validateTarget = (jsonData, headersToValidate) => { + const boundaryCodeIndex = headersToValidate.indexOf(t("HCM_ADMIN_CONSOLE_BOUNDARY_CODE")); + const headersBeforeBoundaryCode = headersToValidate.slice(0, boundaryCodeIndex); + + const filteredData = jsonData + .filter((e) => { + if (e[headersBeforeBoundaryCode[headersBeforeBoundaryCode.length - 1]]) { + return true; + } + }) + .filter((e) => e[t("HCM_ADMIN_CONSOLE_TARGET_AT_THE_SELECTED_BOUNDARY_LEVEL")]); + + if (filteredData.length == 0) { + const errorMessage = t("HCM_MISSING_TARGET"); + setErrorsType((prevErrors) => ({ + ...prevErrors, + [type]: errorMessage, + })); + setIsError(true); + return false; + } + + const targetValue = filteredData?.[0][t("HCM_ADMIN_CONSOLE_TARGET_AT_THE_SELECTED_BOUNDARY_LEVEL")]; + + if (targetValue <= 0 || targetValue >= 100000000) { + const errorMessage = t("HCM_TARGET_VALIDATION_ERROR"); + setErrorsType((prevErrors) => ({ + ...prevErrors, + [type]: errorMessage, + })); + setIsError(true); + return false; + } + return true; + }; + + // Function to compare arrays for equality + const arraysEqual = (arr1, arr2) => { + if (arr1.length !== arr2.length) return false; + for (let i = 0; i < arr1.length; i++) { + if (arr1[i] !== arr2[i]) return false; + } + return true; + }; + + const validateMultipleTargets = (workbook) => { + let isValid = true; + const sheet = workbook.Sheets[workbook.SheetNames[2]]; + const mdmsHeaders = sheetHeaders[type]; + const expectedHeaders = XLSX.utils.sheet_to_json(sheet, { + header: 1, + })[0]; + + for (const header of mdmsHeaders) { + if (!expectedHeaders.includes(header)) { + const errorMessage = t("HCM_MISSING_HEADERS"); + setErrorsType((prevErrors) => ({ + ...prevErrors, + [type]: errorMessage, + })); + setIsError(true); + isValid = false; + break; + } + } + + if (!isValid) return isValid; + + for (let i = 2; i < workbook.SheetNames.length; i++) { + const sheetName = workbook?.SheetNames[i]; + + const sheet = workbook?.Sheets[sheetName]; + + // Convert the sheet to JSON to extract headers + const headersToValidate = XLSX.utils.sheet_to_json(sheet, { + header: 1, + })[0]; + + // Check if headers match the expected headers + if (!arraysEqual(headersToValidate, expectedHeaders)) { + const errorMessage = t("HCM_MISSING_HEADERS"); + setErrorsType((prevErrors) => ({ + ...prevErrors, + [type]: errorMessage, + })); + setIsError(true); + isValid = false; + break; + } + } + + if (!isValid) return isValid; + + // Iterate over each sheet in the workbook, starting from the second sheet + for (let i = 2; i < workbook.SheetNames.length; i++) { + const sheetName = workbook?.SheetNames[i]; + + const sheet = workbook?.Sheets[sheetName]; + + // Convert the sheet to JSON to extract headers + const headersToValidate = XLSX.utils.sheet_to_json(sheet, { + header: 1, + })[0]; + + const jsonData = XLSX.utils.sheet_to_json(sheet, { blankrows: true }); + + const boundaryCodeIndex = headersToValidate.indexOf(t("HCM_ADMIN_CONSOLE_BOUNDARY_CODE")); + const headersBeforeBoundaryCode = headersToValidate.slice(0, boundaryCodeIndex); + + const columnBeforeBoundaryCode = jsonData.map((row) => row[headersBeforeBoundaryCode[headersBeforeBoundaryCode.length - 1]]); + + // Getting the length of data in the column before the boundary code + const lengthOfColumnBeforeBoundaryCode = columnBeforeBoundaryCode.filter((value) => value !== undefined && value !== "").length; + + const filteredData = jsonData + .filter((e) => e[headersBeforeBoundaryCode[headersBeforeBoundaryCode?.length - 1]]) + .filter((e) => e[t("HCM_ADMIN_CONSOLE_TARGET_AT_THE_SELECTED_BOUNDARY_LEVEL")]); + if (filteredData?.length == 0 || filteredData?.length != lengthOfColumnBeforeBoundaryCode) { + const errorMessage = t("HCM_MISSING_TARGET"); + setErrorsType((prevErrors) => ({ + ...prevErrors, + [type]: errorMessage, + })); + setIsError(true); + isValid = false; + break; + } + + const targetValue = filteredData?.[0][t("HCM_ADMIN_CONSOLE_TARGET_AT_THE_SELECTED_BOUNDARY_LEVEL")]; + + if (targetValue <= 0 || targetValue >= 100000000) { + const errorMessage = t("HCM_TARGET_VALIDATION_ERROR"); + setErrorsType((prevErrors) => ({ + ...prevErrors, + [type]: errorMessage, + })); + setIsError(true); + isValid = false; + break; + } + } + + return isValid; + }; + + const validateExcel = (selectedFile) => { + return new Promise((resolve, reject) => { + // Check if a file is selected + if (!selectedFile) { + reject(t("HCM_FILE_UPLOAD_ERROR")); + return; + } + + // Read the Excel file + const reader = new FileReader(); + reader.onload = (e) => { + try { + const data = new Uint8Array(e.target.result); + const workbook = XLSX.read(data, { type: "array" }); + const sheet = workbook.Sheets[workbook.SheetNames[1]]; + const headersToValidate = XLSX.utils.sheet_to_json(sheet, { + header: 1, + })[0]; + + const SheetNames = workbook.SheetNames[1]; + const expectedHeaders = sheetHeaders[type]; + if (type === "boundary") { + if (SheetNames !== t("HCM_ADMIN_CONSOLE_BOUNDARY_DATA")) { + const errorMessage = t("HCM_INVALID_BOUNDARY_SHEET"); + setErrorsType((prevErrors) => ({ + ...prevErrors, + [type]: errorMessage, + })); + setIsError(true); + return; + } + } else if (type === "facilityWithBoundary") { + if (SheetNames !== t("HCM_ADMIN_CONSOLE_AVAILABLE_FACILITIES")) { + const errorMessage = t("HCM_INVALID_FACILITY_SHEET"); + setErrorsType((prevErrors) => ({ + ...prevErrors, + [type]: errorMessage, + })); + setIsError(true); + return; + } + } else { + if (SheetNames !== t("HCM_ADMIN_CONSOLE_USER_LIST")) { + const errorMessage = t("HCM_INVALID_USER_SHEET"); + setErrorsType((prevErrors) => ({ + ...prevErrors, + [type]: errorMessage, + })); + setIsError(true); + return; + } + } + if (type === "boundary" && workbook?.SheetNames?.length > 3) { + if (!validateMultipleTargets(workbook)) { + return; + } + } else if (type !== "boundary") { + for (const header of expectedHeaders) { + if (!headersToValidate.includes(header)) { + const errorMessage = t("HCM_MISSING_HEADERS"); + setErrorsType((prevErrors) => ({ + ...prevErrors, + [type]: errorMessage, + })); + setIsError(true); + return; + } + } + } + + const sheetData = XLSX.utils.sheet_to_json(workbook.Sheets[workbook.SheetNames[1]], { blankrows: true }); + var jsonData = sheetData.map((row, index) => { + const rowData = {}; + if (Object.keys(row).length > 0) { + Object.keys(row).forEach((key) => { + rowData[key] = row[key] === undefined || row[key] === "" ? "" : row[key]; + }); + rowData["!row#number!"] = index + 1; // Adding row number + return rowData; + } + }); + + jsonData = jsonData.filter((element) => element !== undefined); + + if (type === "boundary" && workbook?.SheetNames.length == 1) { + if (!validateTarget(jsonData, headersToValidate)) { + return; + } + } + + if (jsonData.length == 0) { + const errorMessage = t("HCM_EMPTY_SHEET"); + setErrorsType((prevErrors) => ({ + ...prevErrors, + [type]: errorMessage, + })); + setIsError(true); + return; + } + + if (validateData(jsonData, SheetNames)) { + resolve(true); + } else { + setShowInfoCard(true); + } + } catch (error) { + console.log("error", error); + reject("HCM_FILE_UNAVAILABLE"); + } + }; + + reader.readAsArrayBuffer(selectedFile); + }); + }; + + const onBulkUploadSubmit = async (file) => { + if (file.length > 1) { + setShowToast({ key: "error", label: t("HCM_ERROR_MORE_THAN_ONE_FILE") }); + return; + } + setFileName(file?.[0]?.name); + const module = "HCM-ADMIN-CONSOLE-CLIENT"; + const { data: { files: fileStoreIds } = {} } = await Digit.UploadServices.MultipleFilesStorage(module, file, tenantId); + const filesArray = [fileStoreIds?.[0]?.fileStoreId]; + const { data: { fileStoreIds: fileUrl } = {} } = await Digit.UploadServices.Filefetch(filesArray, tenantId); + const fileData = fileUrl + .map((i) => { + const urlParts = i?.url?.split("/"); + const fileName = file?.[0]?.name; + const id = fileUrl?.[0]?.id; + // const fileType = type === "facilityWithBoundary" ? "facility" : type === "userWithBoundary" ? "user" : type; + const fileType = + type === "facilityWithBoundary" ? "facility" : type === "userWithBoundary" ? "user" : type === "boundary" ? "boundaryWithTarget" : type; + return { + // ...i, + filestoreId: id, + resourceId: resourceId, + filename: fileName, + type: fileType, + }; + }) + .map(({ id, ...rest }) => rest); + setUploadedFile(fileData); + const validate = await validateExcel(file[0]); + }; + + const onFileDelete = (file, index) => { + setUploadedFile((prev) => prev.filter((i) => i.id !== file.id)); + setIsError(false); + setIsSuccess(false); + setIsValidation(false); + setApiError(null); + // setShowToast(null); + }; + + const onFileDownload = (file) => { + if (file && file?.url) { + // Splitting filename before .xlsx or .xls + const fileNameWithoutExtension = file?.filename.split(/\.(xlsx|xls)/)[0]; + downloadExcelWithCustomName({ fileStoreId: file?.filestoreId, customName: fileNameWithoutExtension }); + } + }; + useEffect(() => { + const fetchData = async () => { + if (!errorsType[type] && uploadedFile?.length > 0) { + setShowToast({ key: "info", label: t("HCM_VALIDATION_IN_PROGRESS") }); + setIsValidation(true); + setIsError(true); + + try { + const temp = await Digit.Hooks.campaign.useResourceData(uploadedFile, params?.hierarchyType, type, tenantId, id); + if (temp?.isError) { + const errorMessage = temp?.error.replaceAll(":", "-"); + setShowToast({ key: "error", label: errorMessage, transitionTime: 5000000 }); + setIsError(true); + setApiError(errorMessage); + setIsValidation(false); + return; + } + if (temp?.status === "completed") { + setIsValidation(false); + if (temp?.additionalDetails?.sheetErrors.length === 0) { + setShowToast({ key: "success", label: t("HCM_VALIDATION_COMPLETED") }); + if (temp?.id) { + setResourceId(temp?.id); + } + if (!errorsType[type]) { + setIsError(false); + setIsSuccess(true); + return; + // setIsValidation(false); + } + return; + } else { + const processedFileStore = temp?.processedFilestoreId; + if (!processedFileStore) { + setShowToast({ key: "error", label: t("HCM_VALIDATION_FAILED") }); + // setIsValidation(true); + return; + } else { + setShowToast({ key: "warning", label: t("HCM_CHECK_FILE_AGAIN") }); + const { data: { fileStoreIds: fileUrl } = {} } = await Digit.UploadServices.Filefetch([processedFileStore], tenantId); + const fileData = fileUrl + .map((i) => { + const urlParts = i?.url?.split("/"); + const id = fileUrl?.[0]?.id; + // const fileName = fileName; + const fileType = + type === "facilityWithBoundary" + ? "facility" + : type === "userWithBoundary" + ? "user" + : type === "boundary" + ? "boundaryWithTarget" + : type; + return { + ...i, + filestoreId: id, + filename: fileName, + type: fileType, + resourceId: temp?.id, + }; + }) + .map(({ id, ...rest }) => rest); + onFileDelete(uploadedFile); + setUploadedFile(fileData); + setIsError(true); + } + } + } else { + setIsValidation(false); + setShowToast({ key: "error", label: t("HCM_VALIDATION_FAILED") }); + const processedFileStore = temp?.processedFilestoreId; + if (!processedFileStore) { + setShowToast({ key: "error", label: t("HCM_VALIDATION_FAILED") }); + return; + } else { + setShowToast({ key: "warning", label: t("HCM_CHECK_FILE_AGAIN") }); + setIsError(true); + const { data: { fileStoreIds: fileUrl } = {} } = await Digit.UploadServices.Filefetch([processedFileStore], tenantId); + const fileData = fileUrl + .map((i) => { + const urlParts = i?.url?.split("/"); + const id = fileUrl?.[0]?.id; + // const fileName = file?.[0]?.name; + const fileType = + type === "facilityWithBoundary" + ? "facility" + : type === "userWithBoundary" + ? "user" + : type === "boundary" + ? "boundaryWithTarget" + : type; + return { + ...i, + filestoreId: id, + filename: fileName, + type: fileType, + }; + }) + .map(({ id, ...rest }) => rest); + onFileDelete(uploadedFile); + setUploadedFile(fileData); + setIsError(true); + } + } + } catch (error) {} + } + }; + + fetchData(); + }, [errorsType]); + + const Template = { + url: "/project-factory/v1/data/_download", + params: { + tenantId: tenantId, + type: type, + hierarchyType: params?.hierarchyType, + id: type === "boundary" ? params?.boundaryId : type === "facilityWithBoundary" ? params?.facilityId : params?.userId, + }, + }; + const mutation = Digit.Hooks.useCustomAPIMutationHook(Template); + + const downloadTemplate = async () => { + if (type === "boundary" && params?.isBoundaryLoading) { + setDownloadError(true); + setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_TRY_IN_SOME_TIME") }); + return; + } + if (type === "facilityWithBoundary" && params?.isFacilityLoading) { + setDownloadError(true); + setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_TRY_IN_SOME_TIME") }); + return; + } + if (type === "userWithBoundary" && params?.isUserLoading) { + setDownloadError(true); + setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_TRY_IN_SOME_TIME") }); + return; + } + if (!params?.boundaryId || !params?.facilityId || !params?.userId) { + setDownloadError(true); + setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_TRY_IN_SOME_TIME") }); + return; + } + await mutation.mutate( + { + params: { + tenantId: tenantId, + type: type, + hierarchyType: params?.hierarchyType, + id: type === "boundary" ? params?.boundaryId : type === "facilityWithBoundary" ? params?.facilityId : params?.userId, + }, + }, + { + onSuccess: async (result) => { + if (result?.GeneratedResource?.[0]?.status === "failed") { + setDownloadError(true); + setShowToast({ key: "error", label: t("ERROR_WHILE_DOWNLOADING") }); + return; + } + if (!result?.GeneratedResource?.[0]?.fileStoreid || result?.GeneratedResource?.length == 0) { + setDownloadError(true); + setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_TRY_IN_SOME_TIME") }); + return; + } + const filesArray = [result?.GeneratedResource?.[0]?.fileStoreid]; + const { data: { fileStoreIds: fileUrl } = {} } = await Digit.UploadServices.Filefetch(filesArray, tenantId); + const fileData = fileUrl?.map((i) => { + const urlParts = i?.url?.split("/"); + // const fileName = urlParts[urlParts?.length - 1]?.split("?")?.[0]; + const fileName = type === "boundary" ? "Target Template" : type === "facilityWithBoundary" ? "Facility Template" : "User Template"; + return { + ...i, + filename: fileName, + }; + }); + + if (fileData && fileData?.[0]?.url) { + setDownloadError(false); + if (fileData?.[0]?.id) { + downloadExcelWithCustomName({ fileStoreId: fileData?.[0]?.id, customName: fileData?.[0]?.filename }); + } + } else { + setDownloadError(true); + setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT") }); + } + }, + onError: (result) => { + setDownloadError(true); + setShowToast({ key: "error", label: t("ERROR_WHILE_DOWNLOADING") }); + }, + } + ); + }; + + // useEffect(() => { + // if (showToast) { + // setTimeout(closeToast, 5000); + // } + // }, [showToast]); + const closeToast = () => { + setShowToast(null); + }; + useEffect(() => { + if (showToast) { + const t = setTimeout(closeToast, 5000); + return () => clearTimeout(t); + } + }, [showToast]); + + return ( + <> + {isValidation && } + +
+
+ {type === "boundary" ? t("WBH_UPLOAD_TARGET") : type === "facilityWithBoundary" ? t("WBH_UPLOAD_FACILITY") : t("WBH_UPLOAD_USER")} +
+
+ {uploadedFile.length === 0 && ( +
+ {type === "boundary" ? t("HCM_BOUNDARY_MESSAGE") : type === "facilityWithBoundary" ? t("HCM_FACILITY_MESSAGE") : t("HCM_USER_MESSAGE")} +
+ )} + + {showInfoCard && ( + + {errorsType[type] && ( + + {errorsType[type].split(",").map((error, index) => ( + + {index > 0 &&
} + {error.trim()} +
+ ))} +
+ )} +
, + ]} + /> + )} + + ( +
+

{info?.header}

+
    + {info?.descriptions.map((desc, i) => ( +
  • +

    {i + 1}.

    +

    {desc.text}

    +
  • + ))} +
+
+ ))} + label={"Info"} + /> + {showToast && (uploadedFile?.length > 0 || downloadError) && ( + + )} + + ); +}; + +export default UploadData; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/XlsPreview.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/XlsPreview.js new file mode 100644 index 00000000000..a3a10a43830 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/XlsPreview.js @@ -0,0 +1,69 @@ +import { PopUp, SVG, DownloadIcon, Button } from "@egovernments/digit-ui-react-components"; +import React from "react"; +import DocViewer, { DocViewerRenderers } from "@cyntler/react-doc-viewer"; +import { useTranslation } from "react-i18next"; +import { PRIMARY_COLOR } from "../utils"; + +const ArrowBack = ({ className = "", height = "15", width = "15", styles = {} }) => { + return ( + + + + ); +}; +function XlsPreview({ file, ...props }) { + const { t } = useTranslation(); + const documents = file + ? [ + { + fileType: "xlsx", + fileName: file?.filename, + uri: file?.url, + }, + ] + : null; + + return ( + +
+
+
+ +
+
+ ); +} + +export default XlsPreview; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/DustbinIcon.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/DustbinIcon.js new file mode 100644 index 00000000000..b9191f6db26 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/DustbinIcon.js @@ -0,0 +1,10 @@ +import React from "react"; +import { PRIMARY_COLOR } from "../../utils"; +export const DustbinIcon = () => ( + + + +); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/XlsxFile.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/XlsxFile.js new file mode 100644 index 00000000000..82ecfa8f625 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/XlsxFile.js @@ -0,0 +1,32 @@ +import React from "react"; + +export const XlsxFile = ({ className = "", fill = "none", style = {} }) => ( + + + + + + + + + + + +); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/CampaignConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/CampaignConfig.js new file mode 100644 index 00000000000..7123c878251 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/CampaignConfig.js @@ -0,0 +1,264 @@ +export const CampaignConfig = (totalFormData, dataParams, isSubmitting) => { + return [ + { + form: [ + { + stepCount: "1", + key: "1", + name: "HCM_CAMPAIGN_TYPE", + body: [ + { + isMandatory: false, + key: "projectType", + type: "component", + skipAPICall: true, + component: "CampaignSelection", + withoutLabel: true, + disable: false, + customProps: { + module: "HCM", + sessionData: totalFormData, + isSubmitting: isSubmitting + }, + populators: { + name: "projectType", + }, + }, + ], + }, + { + stepCount: "1", + key: "2", + name: "HCM_CAMPAIGN_NAME", + body: [ + { + isMandatory: false, + key: "campaignName", + type: "component", + component: "CampaignName", + mandatoryOnAPI: true, + withoutLabel: true, + disable: false, + customProps: { + module: "HCM", + sessionData: totalFormData, + isSubmitting: isSubmitting + }, + populators: { + name: "campaignName", + required: true, + }, + }, + ], + }, + { + stepCount: "1", + key: "3", + name: "HCM_CAMPAIGN_DATE", + body: [ + { + isMandatory: false, + key: "campaignDates", + type: "component", + component: "CampaignDates", + withoutLabel: true, + disable: false, + customProps: { + module: "HCM", + sessionData: totalFormData, + isSubmitting: isSubmitting + }, + populators: { + name: "campaignDates", + // optionsKey: "code", + // error: "ES__REQUIRED", + required: true, + }, + }, + ], + }, + { + stepCount: "2", + key: "4", + name: "HCM_CAMPAIGN_CYCLE_CONFIGURE", + body: [ + { + isMandatory: false, + key: "cycleConfigure", + type: "component", + component: "CycleConfiguration", + withoutLabelFieldPair: true, + withoutLabel: true, + disable: false, + customProps: { + module: "HCM", + }, + populators: { + name: "cycleConfiguration", + sessionData: totalFormData, + // optionsKey: "code", + error: "ES__REQUIRED", + required: true, + }, + }, + ], + }, + { + stepCount: "2", + key: "5", + name: "HCM_CAMPAIGN_DELIVERY_DATA", + body: [ + { + isMandatory: false, + key: "deliveryRule", + type: "component", + component: "DeliveryRule", + withoutLabelFieldPair: true, + withoutLabel: true, + disable: false, + customProps: { + module: "HCM", + sessionData: totalFormData, + }, + populators: { + name: "deliveryRule", + // optionsKey: "code", + error: "ES__REQUIRED", + required: true, + }, + }, + ], + }, + { + stepCount: "3", + key: "6", + name: "HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA", + body: [ + { + isMandatory: false, + key: "boundaryType", + type: "component", + component: "SelectingBoundaries", + withoutLabelFieldPair: true, + withoutLabel: true, + disable: false, + customProps: { + module: "HCM", + sessionData: totalFormData, + dataParams: dataParams, + }, + populators: { + name: "boundaryType", + // optionsKey: "code", + error: "ES__REQUIRED", + required: true, + }, + }, + ], + }, + { + stepCount: "4", + key: "7", + name: "HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA", + body: [ + { + isMandatory: false, + key: "uploadBoundary", + type: "component", + component: "UploadData", + withoutLabel: true, + withoutLabelFieldPair: true, + disable: false, + customProps: { + module: "HCM", + sessionData: totalFormData, + type: "boundary", + }, + populators: { + name: "uploadBoundary", + // optionsKey: "code", + // error: "ES__REQUIRED", + required: true, + }, + }, + ], + }, + { + stepCount: "5", + key: "8", + name: "HCM_CAMPAIGN_UPLOAD_FACILITY_DATA", + body: [ + { + isMandatory: false, + key: "uploadFacility", + type: "component", + component: "UploadData", + withoutLabel: true, + withoutLabelFieldPair: true, + disable: false, + customProps: { + module: "HCM", + sessionData: totalFormData, + type: "facilityWithBoundary", + }, + populators: { + name: "uploadFacility", + required: true, + }, + }, + ], + }, + { + stepCount: "6", + key: "9", + name: "HCM_CAMPAIGN_UPLOAD_USER_DATA", + body: [ + { + isMandatory: false, + key: "uploadUser", + type: "component", + component: "UploadData", + withoutLabel: true, + withoutLabelFieldPair: true, + disable: false, + customProps: { + module: "HCM", + sessionData: totalFormData, + type: "userWithBoundary", + }, + populators: { + name: "uploadUser", + required: true, + }, + }, + ], + }, + { + stepCount: "7", + key: "10", + isLast: true, + body: [ + { + isMandatory: false, + key: "summary", + type: "component", + component: "CampaignSummary", + withoutLabel: true, + withoutLabelFieldPair: true, + disable: false, + customProps: { + module: "HCM", + }, + populators: { + name: "summary", + // optionsKey: "code", + // error: "ES__REQUIRED", + required: true, + }, + }, + ], + }, + ], + }, + ]; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/UICustomizations.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/UICustomizations.js new file mode 100644 index 00000000000..63954b2a810 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/UICustomizations.js @@ -0,0 +1,472 @@ +import { Link, useHistory } from "react-router-dom"; +import _ from "lodash"; +import React from "react"; + +//create functions here based on module name set in mdms(eg->SearchProjectConfig) +//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName] +// these functions will act as middlewares +// var Digit = window.Digit || {}; + +const businessServiceMap = {}; + +const inboxModuleNameMap = {}; + +export const UICustomizations = { + MyCampaignConfigOngoing: { + preProcess: (data, additionalDetails) => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + data.body = { RequestInfo: data.body.RequestInfo }; + const { limit, offset } = data?.state?.tableForm || {}; + const { campaignName, campaignType } = data?.state?.searchForm || {}; + data.body.CampaignDetails = { + tenantId: tenantId, + status: ["creating", "created"], + createdBy: Digit.UserService.getUser().info.uuid, + campaignsIncludeDates: true, + startDate: Date.now(), + endDate: Date.now(), + pagination: { + sortBy: "createdTime", + sortOrder: "desc", + limit: limit, + offset: offset, + }, + }; + if (campaignName) { + data.body.CampaignDetails.campaignName = campaignName; + } + if (campaignType) { + data.body.CampaignDetails.projectType = campaignType?.[0]?.code; + } + delete data.body.custom; + delete data.body.inbox; + delete data.params; + return data; + }, + populateCampaignTypeReqCriteria: () => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + + return { + url: "/egov-mdms-service/v1/_search", + params: { tenantId }, + body: { + MdmsCriteria: { + tenantId: tenantId, + moduleDetails: [ + { + moduleName: "HCM-PROJECT-TYPES", + masterDetails: [ + { + name: "projectTypes", + }, + ], + }, + ], + }, + }, + changeQueryName: "setWorkflowStatus", + config: { + enabled: true, + select: (data) => { + return data?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes; + }, + }, + }; + }, + getCustomActionLabel: (obj, row) => { + return ""; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + switch (key) { + case "CAMPAIGN_NAME": + return ( + + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + ); + + case "CAMPAIGN_START_DATE": + return Digit.DateUtils.ConvertEpochToDate(value); + case "CAMPAIGN_END_DATE": + return Digit.DateUtils.ConvertEpochToDate(value); + default: + return "case_not_found"; + } + }, + onCardClick: (obj) => { + return `view-test-results?tenantId=${obj?.apiResponse?.businessObject?.tenantId}&id=${obj?.apiResponse?.businessObject?.testId}&from=TQM_BREAD_INBOX`; + }, + onCardActionClick: (obj) => { + return `view-test-results?tenantId=${obj?.apiResponse?.businessObject?.tenantId}&id=${obj?.apiResponse?.businessObject?.testId}&from=TQM_BREAD_INBOX`; + }, + getCustomActionLabel: (obj, row) => { + return "TQM_VIEW_TEST_DETAILS"; + }, + }, + MyCampaignConfigCompleted: { + preProcess: (data, additionalDetails) => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + data.body = { RequestInfo: data.body.RequestInfo }; + const { limit, offset } = data?.state?.tableForm || {}; + const { campaignName, campaignType } = data?.state?.searchForm || {}; + data.body.CampaignDetails = { + tenantId: tenantId, + status: ["creating", "created"], + endDate: Date.now() - 24 * 60 * 60 * 1000, + createdBy: Digit.UserService.getUser().info.uuid, + pagination: { + sortBy: "createdTime", + sortOrder: "desc", + limit: limit, + offset: offset, + }, + }; + if (campaignName) { + data.body.CampaignDetails.campaignName = campaignName; + } + if (campaignType) { + data.body.CampaignDetails.projectType = campaignType?.[0]?.code; + } + delete data.body.custom; + delete data.body.inbox; + delete data.params; + return data; + }, + populateCampaignTypeReqCriteria: () => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + + return { + url: "/egov-mdms-service/v1/_search", + params: { tenantId }, + body: { + MdmsCriteria: { + tenantId: tenantId, + moduleDetails: [ + { + moduleName: "HCM-PROJECT-TYPES", + masterDetails: [ + { + name: "projectTypes", + }, + ], + }, + ], + }, + }, + changeQueryName: "setWorkflowStatus", + config: { + enabled: true, + select: (data) => { + return data?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes; + }, + }, + }; + }, + getCustomActionLabel: (obj, row) => { + return ""; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + switch (key) { + case "CAMPAIGN_NAME": + return ( + + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + ); + + case "CAMPAIGN_START_DATE": + return Digit.DateUtils.ConvertEpochToDate(value); + case "CAMPAIGN_END_DATE": + return Digit.DateUtils.ConvertEpochToDate(value); + default: + return "case_not_found"; + } + }, + onCardClick: (obj) => { + return `view-test-results?tenantId=${obj?.apiResponse?.businessObject?.tenantId}&id=${obj?.apiResponse?.businessObject?.testId}&from=TQM_BREAD_INBOX`; + }, + onCardActionClick: (obj) => { + return `view-test-results?tenantId=${obj?.apiResponse?.businessObject?.tenantId}&id=${obj?.apiResponse?.businessObject?.testId}&from=TQM_BREAD_INBOX`; + }, + getCustomActionLabel: (obj, row) => { + return "TQM_VIEW_TEST_DETAILS"; + }, + }, + MyCampaignConfigUpcoming: { + preProcess: (data, additionalDetails) => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + data.body = { RequestInfo: data.body.RequestInfo }; + const { limit, offset } = data?.state?.tableForm || {}; + const { campaignName, campaignType } = data?.state?.searchForm || {}; + data.body.CampaignDetails = { + tenantId: tenantId, + status: ["creating", "created"], + createdBy: Digit.UserService.getUser().info.uuid, + campaignsIncludeDates: false, + startDate: Date.now() + 24 * 60 * 60 * 1000, + pagination: { + sortBy: "createdTime", + sortOrder: "desc", + limit: limit, + offset: offset, + }, + }; + if (campaignName) { + data.body.CampaignDetails.campaignName = campaignName; + } + if (campaignType) { + data.body.CampaignDetails.projectType = campaignType?.[0]?.code; + } + delete data.body.custom; + delete data.body.inbox; + delete data.params; + return data; + }, + populateCampaignTypeReqCriteria: () => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + + return { + url: "/egov-mdms-service/v1/_search", + params: { tenantId }, + body: { + MdmsCriteria: { + tenantId: tenantId, + moduleDetails: [ + { + moduleName: "HCM-PROJECT-TYPES", + masterDetails: [ + { + name: "projectTypes", + }, + ], + }, + ], + }, + }, + changeQueryName: "setWorkflowStatus", + config: { + enabled: true, + select: (data) => { + return data?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes; + }, + }, + }; + }, + getCustomActionLabel: (obj, row) => { + return ""; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + switch (key) { + case "CAMPAIGN_NAME": + return ( + + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + ); + + case "CAMPAIGN_START_DATE": + return Digit.DateUtils.ConvertEpochToDate(value); + case "CAMPAIGN_END_DATE": + return Digit.DateUtils.ConvertEpochToDate(value); + default: + return "case_not_found"; + } + }, + onCardClick: (obj) => { + return `view-test-results?tenantId=${obj?.apiResponse?.businessObject?.tenantId}&id=${obj?.apiResponse?.businessObject?.testId}&from=TQM_BREAD_INBOX`; + }, + onCardActionClick: (obj) => { + return `view-test-results?tenantId=${obj?.apiResponse?.businessObject?.tenantId}&id=${obj?.apiResponse?.businessObject?.testId}&from=TQM_BREAD_INBOX`; + }, + getCustomActionLabel: (obj, row) => { + return "TQM_VIEW_TEST_DETAILS"; + }, + }, + MyCampaignConfigDrafts: { + preProcess: (data, additionalDetails) => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + data.body = { RequestInfo: data.body.RequestInfo }; + const { limit, offset } = data?.state?.tableForm || {}; + const { campaignName, campaignType } = data?.state?.searchForm || {}; + data.body.CampaignDetails = { + tenantId: tenantId, + status: ["drafted"], + createdBy: Digit.UserService.getUser().info.uuid, + pagination: { + sortBy: "createdTime", + sortOrder: "desc", + limit: limit, + offset: offset, + }, + }; + if (campaignName) { + data.body.CampaignDetails.campaignName = campaignName; + } + if (campaignType) { + data.body.CampaignDetails.projectType = campaignType?.[0]?.code; + } + delete data.body.custom; + delete data.body.custom; + delete data.body.inbox; + delete data.params; + return data; + }, + populateCampaignTypeReqCriteria: () => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + + return { + url: "/egov-mdms-service/v1/_search", + params: { tenantId }, + body: { + MdmsCriteria: { + tenantId: tenantId, + moduleDetails: [ + { + moduleName: "HCM-PROJECT-TYPES", + masterDetails: [ + { + name: "projectTypes", + }, + ], + }, + ], + }, + }, + changeQueryName: "setWorkflowStatus", + config: { + enabled: true, + select: (data) => { + return data?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes; + }, + }, + }; + }, + getCustomActionLabel: (obj, row) => { + return ""; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + switch (key) { + case "CAMPAIGN_NAME": + return ( + + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + ); + + case "CAMPAIGN_START_DATE": + return Digit.DateUtils.ConvertEpochToDate(value); + case "CAMPAIGN_END_DATE": + return Digit.DateUtils.ConvertEpochToDate(value); + default: + return "case_not_found"; + } + }, + onCardClick: (obj) => { + return `view-test-results?tenantId=${obj?.apiResponse?.businessObject?.tenantId}&id=${obj?.apiResponse?.businessObject?.testId}&from=TQM_BREAD_INBOX`; + }, + onCardActionClick: (obj) => { + return `view-test-results?tenantId=${obj?.apiResponse?.businessObject?.tenantId}&id=${obj?.apiResponse?.businessObject?.testId}&from=TQM_BREAD_INBOX`; + }, + getCustomActionLabel: (obj, row) => { + return "TQM_VIEW_TEST_DETAILS"; + }, + }, + MyCampaignConfigFailed: { + preProcess: (data, additionalDetails) => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + data.body = { RequestInfo: data.body.RequestInfo }; + const { limit, offset } = data?.state?.tableForm || {}; + const { campaignName, campaignType } = data?.state?.searchForm || {}; + data.body.CampaignDetails = { + tenantId: tenantId, + status: ["failed"], + createdBy: Digit.UserService.getUser().info.uuid, + pagination: { + sortBy: "createdTime", + sortOrder: "desc", + limit: limit, + offset: offset, + }, + }; + if (campaignName) { + data.body.CampaignDetails.campaignName = campaignName; + } + if (campaignType) { + data.body.CampaignDetails.projectType = campaignType?.[0]?.code; + } + delete data.body.custom; + delete data.body.inbox; + delete data.params; + return data; + }, + populateCampaignTypeReqCriteria: () => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + + return { + url: "/egov-mdms-service/v1/_search", + params: { tenantId }, + body: { + MdmsCriteria: { + tenantId: tenantId, + moduleDetails: [ + { + moduleName: "HCM-PROJECT-TYPES", + masterDetails: [ + { + name: "projectTypes", + }, + ], + }, + ], + }, + }, + changeQueryName: "setWorkflowStatus", + config: { + enabled: true, + select: (data) => { + return data?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes; + }, + }, + }; + }, + getCustomActionLabel: (obj, row) => { + return ""; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + switch (key) { + case "CAMPAIGN_NAME": + return ( + + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + ); + + case "CAMPAIGN_START_DATE": + return Digit.DateUtils.ConvertEpochToDate(value); + case "CAMPAIGN_END_DATE": + return Digit.DateUtils.ConvertEpochToDate(value); + default: + return "case_not_found"; + } + }, + onCardClick: (obj) => { + // return `view-test-results?tenantId=${obj?.apiResponse?.businessObject?.tenantId}&id=${obj?.apiResponse?.businessObject?.testId}&from=TQM_BREAD_INBOX`; + }, + onCardActionClick: (obj) => { + // return `view-test-results?tenantId=${obj?.apiResponse?.businessObject?.tenantId}&id=${obj?.apiResponse?.businessObject?.testId}&from=TQM_BREAD_INBOX`; + }, + getCustomActionLabel: (obj, row) => { + return "TQM_VIEW_TEST_DETAILS"; + }, + }, +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/addProductConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/addProductConfig.js new file mode 100644 index 00000000000..a13b5bc9c0e --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/addProductConfig.js @@ -0,0 +1,19 @@ +export const addProductConfig = [ + { + body: [ + { + type: "component", + component: "AddProductField", + withoutLabel: true, + key: "addProduct", + validation: {}, + populators: { + validation: {}, + }, + customProps: { + module: "Campaign", + }, + }, + ], + }, +]; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/attributeConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/attributeConfig.js new file mode 100644 index 00000000000..75864d62ab5 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/attributeConfig.js @@ -0,0 +1,23 @@ +//migrated to mdms +export const attributeConfig = [ + { + key: 1, + code: "Age", + i18nKey: "CAMPAIGN_ATTRIBUTE_AGE", + }, + { + key: 2, + code: "Height", + i18nKey: "CAMPAIGN_ATTRIBUTE_HEIGHT", + }, + { + key: 3, + code: "Weight", + i18nKey: "CAMPAIGN_ATTRIBUTE_WEIGHT", + }, + { + key: 4, + code: "Gender", + i18nKey: "CAMPAIGN_ATTRIBUTE_GENDER", + }, +]; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/deliveryConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/deliveryConfig.js new file mode 100644 index 00000000000..ef889dcfd5b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/deliveryConfig.js @@ -0,0 +1,198 @@ +//migrated to mdms +export const deliveryConfig = [ + { + projectType: "LLIN-mz", + attrAddDisable: true, + deliveryAddDisable: true, + customAttribute: true, + cycleConfig: { + cycle: 1, + deliveries: 1, + }, + deliveryConfig: [ + { + attributeConfig: [ + { + key: 1, + label: "Custom", + attrType: "text", + attrValue: "CAMPAIGN_BEDNET_INDIVIDUAL_LABEL", + }, + { + key: 2, + label: "Custom", + attrType: "text", + attrValue: "CAMPAIGN_BEDNET_HOUSEHOLD_LABEL", + }, + ], + productConfig: [ + { + key: 1, + count: 1, + value: "PVAR-2024-05-03-000305", + name: "SP - 250mg", + }, + ], + }, + ], + }, + { + projectType: "MR-DN", + attrAddDisable: false, + deliveryAddDisable: false, + customAttribute: true, + cycleConfig: { + cycle: 3, + deliveries: 3, + }, + deliveryConfig: [ + { + delivery: 1, + conditionConfig: [ + { + attributeConfig: [ + { + key: 1, + label: "Custom", + attrType: "dropdown", + attrValue: "Age", + operatorValue: "IN_BETWEEN", + fromValue: 3, + toValue: 11, + }, + ], + productConfig: [ + { + key: 1, + count: 1, + value: "PVAR-2024-01-24-000079", + name: "AQ - 75mg", + }, + { + key: 1, + count: 1, + value: "PVAR-2024-05-03-000305", + name: "SP - 250mg", + }, + ], + }, + { + attributeConfig: [ + { + key: 1, + label: "Custom", + attrType: "dropdown", + attrValue: "Age", + operatorValue: "IN_BETWEEN", + fromValue: 12, + toValue: 59, + }, + ], + productConfig: [ + { + key: 1, + count: 1, + value: "PVAR-2024-01-24-000078", + name: "AQ - 150mg", + }, + ], + }, + ], + }, + { + delivery: 2, + conditionConfig: [ + { + attributeConfig: [ + { + key: 1, + label: "Custom", + attrType: "dropdown", + attrValue: "Age", + operatorValue: "IN_BETWEEN", + fromValue: 3, + toValue: 11, + }, + ], + productConfig: [ + { + key: 1, + count: 1, + value: "PVAR-2024-01-24-000079", + name: "AQ - 75mg", + }, + ], + }, + { + attributeConfig: [ + { + key: 1, + label: "Custom", + attrType: "dropdown", + attrValue: "Age", + operatorValue: "IN_BETWEEN", + fromValue: 12, + toValue: 59, + }, + ], + productConfig: [ + { + key: 1, + count: 1, + value: "PVAR-2024-01-24-000078", + name: "AQ - 150mg", + }, + ], + }, + ], + }, + { + delivery: 3, + conditionConfig: [ + { + attributeConfig: [ + { + key: 1, + label: "Custom", + attrType: "dropdown", + attrValue: "Age", + operatorValue: "IN_BETWEEN", + fromValue: 3, + toValue: 11, + }, + ], + productConfig: [ + { + key: 1, + count: 1, + value: "PVAR-2024-01-24-000079", + name: "AQ - 75mg", + }, + ], + }, + { + attributeConfig: [ + { + key: 1, + label: "Custom", + attrType: "dropdown", + attrValue: "Age", + operatorValue: "IN_BETWEEN", + fromValue: 12, + toValue: 59, + }, + ], + productConfig: [ + { + key: 1, + count: 1, + value: "PVAR-2024-01-24-000078", + name: "AQ - 150mg", + }, + ], + }, + ], + }, + ], + }, +]; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/headerConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/headerConfig.js new file mode 100644 index 00000000000..66ef03113f1 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/headerConfig.js @@ -0,0 +1,20 @@ +export const headerConfig = { + boundary: [ + "HCM_ADMIN_CONSOLE_BOUNDARY_CODE", "HCM_ADMIN_CONSOLE_TARGET_AT_THE_SELECTED_BOUNDARY_LEVEL" + ], + facilityWithBoundary: [ + "HCM_ADMIN_CONSOLE_FACILITY_CODE", + "HCM_ADMIN_CONSOLE_FACILITY_NAME", + "HCM_ADMIN_CONSOLE_FACILITY_TYPE", + "HCM_ADMIN_CONSOLE_FACILITY_STATUS", + "HCM_ADMIN_CONSOLE_FACILITY_CAPACITY", + "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY" + ], + User: [ + "HCM_ADMIN_CONSOLE_USER_NAME", + "HCM_ADMIN_CONSOLE_USER_PHONE_NUMBER", + "HCM_ADMIN_CONSOLE_USER_ROLE", + "HCM_ADMIN_CONSOLE_USER_EMPLOYMENT_TYPE", + "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY" + ] +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/mailConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/mailConfig.js new file mode 100644 index 00000000000..7bd788d976c --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/mailConfig.js @@ -0,0 +1,5 @@ +export const mailConfig = + { + mailId: "L1team@email.com" + }; + \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/myCampaignConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/myCampaignConfig.js new file mode 100644 index 00000000000..4152a57759e --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/myCampaignConfig.js @@ -0,0 +1,667 @@ +/* The above code defines a JavaScript object `myCampaignConfig` which contains configurations for +different types of campaigns - ongoing, completed, and drafts. Each campaign type has its own search +configuration with fields like campaign name, type, start date, end date, etc. The configurations +also include API details for fetching data, UI styles, search result columns, pagination settings, +and more. The object is exported for use in other parts of the codebase. */ +export const myCampaignConfig = { + tenantId: "mz", + moduleName: "commonCampaignUiConfig", + showTab: true, + myCampaignConfig: [ + { + label: "CAMPAIGN_ONGOING", + type: "search", + apiDetails: { + serviceName: "/project-factory/v1/project-type/search", + requestParam: {}, + requestBody: {}, + minParametersForSearchForm: 0, + minParametersForFilterForm: 0, + masterName: "commonUiConfig", + moduleName: "MyCampaignConfigOngoing", + tableFormJsonPath: "requestBody.inbox", + filterFormJsonPath: "requestBody.custom", + searchFormJsonPath: "requestBody.custom", + }, + sections: { + search: { + uiConfig: { + headerLabel: "ES_COMMON_SEARCH", + type: "search", + typeMobile: "filter", + searchWrapperStyles: { + flexDirection: "column-reverse", + marginTop: "1.4rem", + alignItems: "center", + justifyContent: "end", + gridColumn: "3", + }, + headerStyle: null, + primaryLabel: "Search", + secondaryLabel: "ES_COMMON_CLEAR_SEARCH", + minReqFields: 0, + defaultValues: { + name: "", + type: "", + }, + fields: [ + { + label: "CAMPAIGN_SEARCH_NAME", + type: "text", + isMandatory: false, + disable: false, + populators: { + name: "campaignName", + error: "TQM_ERR_VALID_CAMPAIGN_NAME", + style: { + marginBottom: "0px", + }, + }, + }, + { + label: "CAMPAIGN_SEARCH_TYPE", + type: "apidropdown", + isMandatory: false, + disable: false, + populators: { + optionsCustomStyle: { + top: "2.3rem", + }, + name: "campaignType", + optionsKey: "code", + allowMultiSelect: false, + masterName: "commonUiConfig", + moduleName: "MyCampaignConfigOngoing", + customfn: "populateCampaignTypeReqCriteria", + }, + }, + ], + }, + label: "", + labelMobile: "ES_COMMON_SEARCH", + children: {}, + show: true, + }, + searchResult: { + uiConfig: { + columns: [ + { + label: "CAMPAIGN_NAME", + jsonPath: "campaignName", + additionalCustomization: true, + }, + { + label: "CAMPAIGN_TYPE", + jsonPath: "projectType", + prefix: "CAMPAIGN_PROJECT_", + translate: true, + }, + { + label: "CAMPAIGN_BENEFICIARY_TYPE", + jsonPath: "additionalDetails.beneficiaryType", + prefix: "", + translate: true, + }, + { + label: "CAMPAIGN_START_DATE", + jsonPath: "startDate", + additionalCustomization: true, + // disableSortBy: true, + }, + { + label: "CAMPAIGN_END_DATE", + jsonPath: "endDate", + additionalCustomization: true, + // disableSortBy: true, + }, + ], + enableGlobalSearch: false, + enableColumnSort: true, + resultsJsonPath: "CampaignDetails", + // customDefaultPagination: { + // limit: 5, + // offset: 0, + // }, + // customPageSizesArray: [5, 10, 15, 20], + tableClassName: "table campaign-table", + }, + children: {}, + show: true, + }, + links: { + show: false, + }, + filter: { + show: false, + }, + }, + additionalSections: {}, + persistFormData: true, + showAsRemovableTagsInMobile: true, + }, + { + label: "CAMPAIGN_COMPLETED", + type: "search", + apiDetails: { + serviceName: "/project-factory/v1/project-type/search", + requestParam: {}, + requestBody: {}, + minParametersForSearchForm: 0, + minParametersForFilterForm: 0, + masterName: "commonUiConfig", + moduleName: "MyCampaignConfigCompleted", + tableFormJsonPath: "requestBody.inbox", + filterFormJsonPath: "requestBody.custom", + searchFormJsonPath: "requestBody.custom", + }, + sections: { + search: { + uiConfig: { + headerLabel: "ES_COMMON_SEARCH", + type: "search", + typeMobile: "filter", + searchWrapperStyles: { + flexDirection: "column-reverse", + marginTop: "1.4rem", + alignItems: "center", + justifyContent: "end", + gridColumn: "3", + }, + headerStyle: null, + primaryLabel: "Search", + secondaryLabel: "ES_COMMON_CLEAR_SEARCH", + minReqFields: 0, + defaultValues: { + name: "", + type: "", + }, + fields: [ + { + label: "CAMPAIGN_SEARCH_NAME", + type: "text", + isMandatory: false, + disable: false, + populators: { + name: "campaignName", + error: "TQM_ERR_VALID_CAMPAIGN_NAME", + style: { + marginBottom: "0px", + }, + }, + }, + { + label: "CAMPAIGN_SEARCH_TYPE", + type: "apidropdown", + isMandatory: false, + disable: false, + populators: { + optionsCustomStyle: { + top: "2.3rem", + }, + name: "campaignType", + optionsKey: "code", + allowMultiSelect: false, + masterName: "commonUiConfig", + moduleName: "MyCampaignConfigCompleted", + customfn: "populateCampaignTypeReqCriteria", + }, + }, + ], + }, + label: "", + labelMobile: "ES_COMMON_SEARCH", + children: {}, + show: true, + }, + searchResult: { + uiConfig: { + columns: [ + { + label: "CAMPAIGN_NAME", + jsonPath: "campaignName", + additionalCustomization: true, + }, + { + label: "CAMPAIGN_TYPE", + jsonPath: "projectType", + prefix: "CAMPAIGN_PROJECT_", + translate: true, + }, + { + label: "CAMPAIGN_BENEFICIARY_TYPE", + jsonPath: "additionalDetails.beneficiaryType", + prefix: "", + translate: true, + }, + { + label: "CAMPAIGN_START_DATE", + jsonPath: "startDate", + additionalCustomization: true, + // disableSortBy: true, + }, + { + label: "CAMPAIGN_END_DATE", + jsonPath: "endDate", + additionalCustomization: true, + // disableSortBy: true, + }, + ], + enableGlobalSearch: false, + enableColumnSort: true, + resultsJsonPath: "CampaignDetails", + // customDefaultPagination: { + // limit: 5, + // offset: 0, + // }, + // customPageSizesArray: [5, 10, 15, 20], + tableClassName: "table campaign-table", + }, + children: {}, + show: true, + }, + links: { + show: false, + }, + filter: { + show: false, + }, + }, + additionalSections: {}, + persistFormData: true, + showAsRemovableTagsInMobile: true, + }, + { + label: "CAMPAIGN_UPCOMING", + type: "search", + apiDetails: { + serviceName: "/project-factory/v1/project-type/search", + requestParam: {}, + requestBody: {}, + minParametersForSearchForm: 0, + minParametersForFilterForm: 0, + masterName: "commonUiConfig", + moduleName: "MyCampaignConfigUpcoming", + tableFormJsonPath: "requestBody.inbox", + filterFormJsonPath: "requestBody.custom", + searchFormJsonPath: "requestBody.custom", + }, + sections: { + search: { + uiConfig: { + headerLabel: "ES_COMMON_SEARCH", + type: "search", + typeMobile: "filter", + searchWrapperStyles: { + flexDirection: "column-reverse", + marginTop: "1.4rem", + alignItems: "center", + justifyContent: "end", + gridColumn: "3", + }, + headerStyle: null, + primaryLabel: "Search", + secondaryLabel: "ES_COMMON_CLEAR_SEARCH", + minReqFields: 0, + defaultValues: { + name: "", + type: "", + }, + fields: [ + { + label: "CAMPAIGN_SEARCH_NAME", + type: "text", + isMandatory: false, + disable: false, + populators: { + name: "campaignName", + error: "TQM_ERR_VALID_CAMPAIGN_NAME", + style: { + marginBottom: "0px", + }, + }, + }, + { + label: "CAMPAIGN_SEARCH_TYPE", + type: "apidropdown", + isMandatory: false, + disable: false, + populators: { + optionsCustomStyle: { + top: "2.3rem", + }, + name: "campaignType", + optionsKey: "code", + allowMultiSelect: false, + masterName: "commonUiConfig", + moduleName: "MyCampaignConfigUpcoming", + customfn: "populateCampaignTypeReqCriteria", + }, + }, + ], + }, + label: "", + labelMobile: "ES_COMMON_SEARCH", + children: {}, + show: true, + }, + searchResult: { + uiConfig: { + columns: [ + { + label: "CAMPAIGN_NAME", + jsonPath: "campaignName", + additionalCustomization: true, + }, + { + label: "CAMPAIGN_TYPE", + jsonPath: "projectType", + prefix: "CAMPAIGN_PROJECT_", + translate: true, + }, + { + label: "CAMPAIGN_BENEFICIARY_TYPE", + jsonPath: "additionalDetails.beneficiaryType", + prefix: "", + translate: true, + }, + { + label: "CAMPAIGN_START_DATE", + jsonPath: "startDate", + additionalCustomization: true, + // disableSortBy: true, + }, + { + label: "CAMPAIGN_END_DATE", + jsonPath: "endDate", + additionalCustomization: true, + // disableSortBy: true, + }, + ], + enableGlobalSearch: false, + enableColumnSort: true, + resultsJsonPath: "CampaignDetails", + // customDefaultPagination: { + // limit: 5, + // offset: 0, + // }, + // customPageSizesArray: [5, 10, 15, 20], + tableClassName: "table campaign-table", + }, + children: {}, + show: true, + }, + links: { + show: false, + }, + filter: { + show: false, + }, + }, + additionalSections: {}, + persistFormData: true, + showAsRemovableTagsInMobile: true, + }, + { + label: "CAMPAIGN_DRAFTS", + type: "search", + apiDetails: { + serviceName: "/project-factory/v1/project-type/search", + requestParam: {}, + requestBody: {}, + minParametersForSearchForm: 0, + minParametersForFilterForm: 0, + masterName: "commonUiConfig", + moduleName: "MyCampaignConfigDrafts", + tableFormJsonPath: "requestBody.inbox", + filterFormJsonPath: "requestBody.custom", + searchFormJsonPath: "requestBody.custom", + }, + sections: { + search: { + uiConfig: { + headerLabel: "ES_COMMON_SEARCH", + type: "search", + typeMobile: "filter", + searchWrapperStyles: { + flexDirection: "column-reverse", + marginTop: "1.4rem", + alignItems: "center", + justifyContent: "end", + gridColumn: "3", + }, + headerStyle: null, + primaryLabel: "Search", + secondaryLabel: "ES_COMMON_CLEAR_SEARCH", + minReqFields: 0, + defaultValues: { + campaignName: "", + campaignType: "", + }, + fields: [ + { + label: "CAMPAIGN_SEARCH_NAME", + type: "text", + isMandatory: false, + disable: false, + populators: { + name: "campaignName", + error: "TQM_ERR_VALID_CAMPAIGN_NAME", + style: { + marginBottom: "0px", + }, + }, + }, + { + label: "CAMPAIGN_SEARCH_TYPE", + type: "apidropdown", + isMandatory: false, + disable: false, + populators: { + optionsCustomStyle: { + top: "2.3rem", + }, + name: "campaignType", + optionsKey: "code", + allowMultiSelect: false, + masterName: "commonUiConfig", + moduleName: "MyCampaignConfigDrafts", + customfn: "populateCampaignTypeReqCriteria", + }, + }, + ], + }, + label: "", + labelMobile: "ES_COMMON_SEARCH", + children: {}, + show: true, + }, + searchResult: { + uiConfig: { + columns: [ + { + label: "CAMPAIGN_NAME", + jsonPath: "campaignName", + additionalCustomization: true, + }, + { + label: "CAMPAIGN_TYPE", + jsonPath: "projectType", + prefix: "CAMPAIGN_PROJECT_", + translate: true, + }, + { + label: "CAMPAIGN_BENEFICIARY_TYPE", + jsonPath: "additionalDetails.beneficiaryType", + prefix: "", + translate: true, + }, + { + label: "CAMPAIGN_START_DATE", + jsonPath: "startDate", + additionalCustomization: true, + // disableSortBy: true, + }, + { + label: "CAMPAIGN_END_DATE", + jsonPath: "endDate", + additionalCustomization: true, + // disableSortBy: true, + }, + ], + enableGlobalSearch: false, + enableColumnSort: true, + resultsJsonPath: "CampaignDetails", + // customDefaultPagination: { + // limit: 5, + // offset: 0, + // }, + // customPageSizesArray: [5, 10, 15, 20], + tableClassName: "table campaign-table", + }, + children: {}, + show: true, + }, + links: { + show: false, + }, + filter: { + show: false, + }, + }, + additionalSections: {}, + persistFormData: true, + showAsRemovableTagsInMobile: true, + }, + { + label: "CAMPAIGN_FAILED", + type: "search", + apiDetails: { + serviceName: "/project-factory/v1/project-type/search", + requestParam: {}, + requestBody: {}, + minParametersForSearchForm: 0, + minParametersForFilterForm: 0, + masterName: "commonUiConfig", + moduleName: "MyCampaignConfigFailed", + tableFormJsonPath: "requestBody.inbox", + filterFormJsonPath: "requestBody.custom", + searchFormJsonPath: "requestBody.custom", + }, + sections: { + search: { + uiConfig: { + headerLabel: "ES_COMMON_SEARCH", + type: "search", + typeMobile: "filter", + searchWrapperStyles: { + flexDirection: "column-reverse", + marginTop: "1.4rem", + alignItems: "center", + justifyContent: "end", + gridColumn: "3", + }, + headerStyle: null, + primaryLabel: "Search", + secondaryLabel: "ES_COMMON_CLEAR_SEARCH", + minReqFields: 0, + defaultValues: { + name: "", + type: "", + }, + fields: [ + { + label: "CAMPAIGN_SEARCH_NAME", + type: "text", + isMandatory: false, + disable: false, + populators: { + name: "campaignName", + error: "TQM_ERR_VALID_CAMPAIGN_NAME", + style: { + marginBottom: "0px", + }, + }, + }, + { + label: "CAMPAIGN_SEARCH_TYPE", + type: "apidropdown", + isMandatory: false, + disable: false, + populators: { + optionsCustomStyle: { + top: "2.3rem", + }, + name: "campaignType", + optionsKey: "code", + allowMultiSelect: false, + masterName: "commonUiConfig", + moduleName: "MyCampaignConfigCompleted", + customfn: "populateCampaignTypeReqCriteria", + }, + }, + ], + }, + label: "", + labelMobile: "ES_COMMON_SEARCH", + children: {}, + show: true, + }, + searchResult: { + uiConfig: { + columns: [ + { + label: "CAMPAIGN_NAME", + jsonPath: "campaignName", + additionalCustomization: true, + }, + { + label: "CAMPAIGN_TYPE", + jsonPath: "projectType", + prefix: "CAMPAIGN_PROJECT_", + translate: true, + }, + { + label: "CAMPAIGN_BENEFICIARY_TYPE", + jsonPath: "additionalDetails.beneficiaryType", + prefix: "", + translate: true, + }, + { + label: "CAMPAIGN_START_DATE", + jsonPath: "startDate", + additionalCustomization: true, + // disableSortBy: true, + }, + { + label: "CAMPAIGN_END_DATE", + jsonPath: "endDate", + additionalCustomization: true, + // disableSortBy: true, + }, + ], + enableGlobalSearch: false, + enableColumnSort: true, + resultsJsonPath: "CampaignDetails", + // customDefaultPagination: { + // limit: 5, + // offset: 0, + // }, + // customPageSizesArray: [5, 10, 15, 20], + tableClassName: "table campaign-table", + }, + children: {}, + show: true, + }, + links: { + show: false, + }, + filter: { + show: false, + }, + }, + additionalSections: {}, + persistFormData: true, + showAsRemovableTagsInMobile: true, + }, + ], +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/operatorConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/operatorConfig.js new file mode 100644 index 00000000000..94ffd6c4e56 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/operatorConfig.js @@ -0,0 +1,27 @@ +//migrated to mdms +export const operatorConfig = [ + { + key: 1, + code: "LESS_THAN", + }, + { + key: 2, + code: "GREATER_THAN", + }, + { + key: 3, + code: "IN_BETWEEN", + }, + { + key: 4, + code: "EQUAL_TO", + }, + { + key: 5, + code: "GREATER_THAN_EQUAL_TO", + }, + { + key: 6, + code: "LESSER_THAN_EQUAL_TO", + }, +]; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/previewConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/previewConfig.js new file mode 100644 index 00000000000..1e33ecd8e41 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/previewConfig.js @@ -0,0 +1,124 @@ +export const previewConfig = { + HCM_CAMPAIGN_DATE: { + campaignDates: { + startDate: "2024-04-01", + endDate: "2024-04-26", + }, + }, + HCM_CAMPAIGN_TYPE: { + projectType: { + id: "84e28a7b-8c6d-4505-a7ef-5d714e0361f6", + name: "mz project type configuration for LLIN Campaigns", + code: "LLIN-mz", + group: "MALARIA", + beneficiaryType: "HOUSEHOLD", + eligibilityCriteria: ["All households are eligible.", "Prison inmates are eligible."], + dashboardUrls: { + NATIONAL_SUPERVISOR: "/digit-ui/employee/dss/landing/national-health-dashboard", + PROVINCIAL_SUPERVISOR: "/digit-ui/employee/dss/dashboard/provincial-health-dashboard", + DISTRICT_SUPERVISOR: "/digit-ui/employee/dss/dashboard/district-health-dashboard", + }, + taskProcedure: [ + "1 bednet is to be distributed per 2 household members.", + "If there are 4 household members, 2 bednets should be distributed.", + "If there are 5 household members, 3 bednets should be distributed.", + ], + resources: [ + { + productVariantId: "PVAR-2024-02-13-000211", + isBaseUnitVariant: false, + }, + ], + }, + }, + HCM_CAMPAIGN_NAME: { + campaignName: "sdkfkdhsdjkhkjsdh", + }, + HCM_CAMPAIGN_CYCLE_CONFIGURE: { + cycleConfigure: { + cycleConfgureDate: { + cycle: 2, + deliveries: 1, + }, + cycleData: [ + { + key: 1, + fromDate: "2001-12-12", + toDate: "2002-11-11", + }, + { + key: 2, + fromDate: "2002-01-12", + toDate: "2011-11-11", + }, + ], + }, + }, + HCM_CAMPAIGN_DELIVERY_DATA: { + deliveryRule: [ + { + cycleIndex: "1", + active: false, + deliveries: [ + { + deliveryIndex: "1", + active: true, + deliveryRules: [ + { + ruleKey: 1, + delivery: {}, + attributes: [ + { + key: 1, + attribute: { + key: 1, + code: "Age", + }, + operator: { + key: 1, + code: "LESS_THAN", + }, + value: "576", + }, + ], + products: [], + }, + ], + }, + ], + }, + { + cycleIndex: "2", + active: true, + deliveries: [ + { + deliveryIndex: "1", + active: true, + deliveryRules: [ + { + ruleKey: 1, + delivery: {}, + attributes: [ + { + key: 1, + attribute: { + key: 1, + code: "Age", + }, + operator: { + key: 2, + code: "GREATER_THAN", + }, + value: "65", + }, + ], + products: [], + }, + ], + }, + ], + }, + ], + }, + undefined: {}, +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/productType.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/productType.js new file mode 100644 index 00000000000..449b55450b1 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/productType.js @@ -0,0 +1,15 @@ +//migrated to mdms +export const productType = [ + { + key: 1, + code: "BEDNET", + }, + { + key: 2, + code: "TABLET", + }, + { + key: 3, + code: "DRUG", + }, +]; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/schemaConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/schemaConfig.js new file mode 100644 index 00000000000..48611ca7a41 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/schemaConfig.js @@ -0,0 +1,80 @@ +export const schemaConfig = { + Boundary: { + $schema: "http://json-schema.org/draft-07/schema#", + title: "BoundaryTemplateSchema", + type: "object", + properties: { + "Boundary Code": { + type: "string", + minLength: 1, + }, + "Target at the Selected Boundary level": { + type: "integer", + minimum: 1, + maximum: 100000000, + }, + }, + required: ["Boundary Code"], + }, + facilityWithBoundary: { + $schema: "http://json-schema.org/draft-07/schema#", + title: "FacilityTemplateSchema", + type: "object", + properties: { + "Facility Name": { + type: "string", + maxLength: 2000, + minLength: 1, + }, + "Facility Type": { + type: "string", + enum: ["Warehouse", "Health Facility"], + }, + "Facility Status": { + type: "string", + enum: ["Temporary", "Permanent"], + }, + Capacity: { + type: "integer", + minimum: 1, + maximum: 100000000, + multipleOf: 1, + }, + "Boundary Code": { + type: "string", + minLength: 1, + }, + }, + required: ["Facility Name", "Facility Type", "Facility Status", "Capacity", "Boundary Code"], + }, + User: { + $schema: "http://json-schema.org/draft-07/schema#", + title: "UserTemplateSchema", + type: "object", + properties: { + "Name of the Person (Mandatory)": { + type: "string", + maxLength: 128, + minLength: 1, + }, + "Phone Number": { + type: "integer", + minimum: 100000000, + maximum: 9999999999, + }, + "Role (Mandatory)": { + type: "string", + }, + "Employment Type (Mandatory)": { + type: "string", + enum: ["Temporary", "Permanent"], + }, + "Capacity": { + "type": "number", + "minimum": 1, + "maximum": 100000000 + } + }, + required: ["Name of the Person (Mandatory)", "Phone Number (Mandatory)", "Role (Mandatory)", "Employment Type (Mandatory)"], + }, +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/index.js new file mode 100644 index 00000000000..bf836251add --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/index.js @@ -0,0 +1,45 @@ +import utils from "../utils"; +import { useSearchCampaign } from "./services/useSearchCampaign"; +import useCreateCampaign from "./useCreateCampaign"; +import { useProductList } from "./useProductList"; +import useUpdateCampaign from "./useUpdateCampaign"; +import { useGenerateIdCampaign } from "./useGenerateIdCampaign"; +import { useResourceData } from "./useResourceData"; +import useCreateProductVariant from "./useCreateProductVariant"; +import useCreateProduct from "./useCreateProduct"; + +const UserService = {}; + +const workbench = {}; + +const contracts = {}; + +const campaign = { + useProductList, + useCreateCampaign, + useSearchCampaign, + useUpdateCampaign, + useGenerateIdCampaign, + useResourceData, + useCreateProduct, + useCreateProductVariant, +}; + +const Hooks = { + campaign, +}; + +const Utils = { + browser: { + sample: () => {}, + }, + workbench: { + ...utils, + }, +}; + +export const CustomisedHooks = { + Hooks, + UserService, + Utils, +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/createCampaignService.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/createCampaignService.js new file mode 100644 index 00000000000..d78f2255133 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/createCampaignService.js @@ -0,0 +1,19 @@ +const createCampaignService = async (req, tenantId) => { + try { + const response = await Digit.CustomService.getResponse({ + url: "/project-factory/v1/project-type/create", + body: { + CampaignDetails: req, + }, + }); + return response; + } catch (error) { + if (!error?.response?.data?.Errors[0].description) { + throw new Error(error?.response?.data?.Errors[0].code); + } else { + throw new Error(error?.response?.data?.Errors[0].description); + } + } +}; + +export default createCampaignService; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/updateCampaignService.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/updateCampaignService.js new file mode 100644 index 00000000000..3fae8e281ac --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/updateCampaignService.js @@ -0,0 +1,20 @@ +const updateCampaignService = async (req, tenantId) => { + try { + const response = await Digit.CustomService.getResponse({ + url: "/project-factory/v1/project-type/update", + body: { + CampaignDetails: req, + }, + }); + return response; + } catch (error) { + // throw new Error(error?.response?.data?.Errors[0].message); + if (!error?.response?.data?.Errors[0].description) { + throw new Error(error?.response?.data?.Errors[0].code); + } else { + throw new Error(error?.response?.data?.Errors[0].description); + } + } +}; + +export default updateCampaignService; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/useSearchCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/useSearchCampaign.js new file mode 100644 index 00000000000..dbc5fc52040 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/useSearchCampaign.js @@ -0,0 +1,21 @@ +import { useQuery } from "react-query"; + +const searchCampaignService = async ({ tenantId, filter, pagination }) => { + const response = await Digit.CustomService.getResponse({ + url: "/project-factory/v1/project-type/search", + body: { + CampaignDetails: { + tenantId: tenantId, + ...filter, + pagination: { + ...pagination, + }, + }, + }, + }); + return response?.CampaignDetails; +}; + +export const useSearchCampaign = ({ tenantId, filter, pagination, config = {} }) => { + return useQuery(["SEARCH_CAMPAIGN", tenantId, filter, pagination], () => searchCampaignService({ tenantId, filter, pagination }), config); +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateCampaign.js new file mode 100644 index 00000000000..cf01fe94ef4 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateCampaign.js @@ -0,0 +1,10 @@ +import { useMutation } from "react-query"; +import createCampaignService from "./services/createCampaignService"; + +const useCreateCampaign = (tenantId) => { + return useMutation((reqData) => { + return createCampaignService(reqData, tenantId); + }); +}; + +export default useCreateCampaign; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProduct.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProduct.js new file mode 100644 index 00000000000..70954c9802d --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProduct.js @@ -0,0 +1,24 @@ +import { useMutation } from "react-query"; + +const createProductService = async (req, tenantId) => { + try { + const response = await Digit.CustomService.getResponse({ + url: "/product/v1/_create", + body: { + Product: req, + apiOperation: "CREATE", + }, + }); + return response; + } catch (error) { + throw new Error(error?.response?.data?.Errors?.[0].description); + } +}; + +const useCreateProduct = (tenantId) => { + return useMutation((reqData) => { + return createProductService(reqData, tenantId); + }); +}; + +export default useCreateProduct; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProductVariant.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProductVariant.js new file mode 100644 index 00000000000..4063f6dc24c --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProductVariant.js @@ -0,0 +1,24 @@ +import { useMutation } from "react-query"; + +const createProductVariantService = async (req, tenantId) => { + try { + const response = await Digit.CustomService.getResponse({ + url: "/product/variant/v1/_create", + body: { + ProductVariant: req, + apiOperation: "CREATE", + }, + }); + return response; + } catch (error) { + throw new Error(error?.response?.data?.Errors?.[0].description); + } +}; + +const useCreateProductVariant = (tenantId) => { + return useMutation((reqData) => { + return createProductVariantService(reqData, tenantId); + }); +}; + +export default useCreateProductVariant; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useGenerateIdCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useGenerateIdCampaign.js new file mode 100644 index 00000000000..f315dda5ff8 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useGenerateIdCampaign.js @@ -0,0 +1,26 @@ +export const useGenerateIdCampaign = ({ type, hierarchyType, filters, campaignId, config = {} }) => { + const updatedFilters = filters?.map(({ type, ...rest }) => ({ + ...rest, + boundaryType: type, + })); + const reqCriteria = { + url: `/project-factory/v1/data/_generate`, + changeQueryName: `${type}${hierarchyType}${filters}`, + params: { + tenantId: Digit.ULBService.getCurrentTenantId(), + type: type, + forceUpdate: true, + hierarchyType: hierarchyType, + campaignId: campaignId, + }, + body: type === "boundary" ? (updatedFilters === undefined ? { Filters: null } : { Filters: { boundaries: updatedFilters } }) : {}, + config: { + ...config, + cacheTime: 0, + staleTime: 0, + }, + }; + const { data: Data, refetch, isLoading } = Digit.Hooks.useCustomAPIHook(reqCriteria); + + return { isLoading: isLoading, data: Data?.GeneratedResource?.[0]?.id, refetch }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useProductList.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useProductList.js new file mode 100644 index 00000000000..cb102a128e7 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useProductList.js @@ -0,0 +1,53 @@ +export const useProductList = (tenantId) => { + const reqCriteriaVariant = { + url: `/product/variant/v1/_search`, + params: { tenantId: tenantId, limit: 1000, offset: 0 }, + body: { + ProductVariant: {}, + }, + config: { + enabled: true, + select: (data) => { + return data?.ProductVariant; + }, + }, + }; + + const { isLoading, data: productVariant, isFetching } = Digit.Hooks.useCustomAPIHook(reqCriteriaVariant); + + const reqCriteriaProduct = { + url: `/product/v1/_search`, + params: { tenantId: tenantId, limit: 1000, offset: 0 }, + body: { + Product: { + id: productVariant?.map((i) => i?.productId), + }, + }, + config: { + enabled: productVariant && !isLoading ? true : false, + select: (data) => { + return data?.Product; + }, + }, + }; + + const { isLoading: isProductLoading, data: product } = Digit.Hooks.useCustomAPIHook(reqCriteriaProduct); + + let productList; + if (productVariant && product) { + productList = productVariant + ?.map((item) => { + const target = product?.find((j) => j.id === item.productId); + if (!target?.name || !item?.variation) { + return null; + } + return { + ...item, + displayName: `${target?.name} - ${item?.variation}`, + }; + }) + ?.filter((i) => i !== null); + } + + return productList; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useResourceData.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useResourceData.js new file mode 100644 index 00000000000..dafe3151d64 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useResourceData.js @@ -0,0 +1,71 @@ +export const useResourceData = async (data, hierarchyType, type, tenantId, id) => { + let Type; + let Error = { + isError: false, + error: {}, + }; + let response; + if (type === "facilityWithBoundary") { + Type = "facility"; + } else if (type === "userWithBoundary") { + Type = "user"; + } else { + Type = "boundaryWithTarget"; + } + try { + const responseTemp = await Digit.CustomService.getResponse({ + url: "/project-factory/v1/data/_create", + body: { + ResourceDetails: { + type: Type, + hierarchyType: hierarchyType, + tenantId: Digit.ULBService.getCurrentTenantId(), + fileStoreId: data?.[0]?.filestoreId, + action: "validate", + campaignId: id, + additionalDetails: {}, + }, + }, + }); + response = responseTemp; + } catch (error) { + if (error?.response && error?.response?.data) { + const errorMessage = error?.response?.data?.Errors?.[0]?.message; + const errorDescription = error?.response?.data?.Errors?.[0]?.description; + if (errorDescription) { + Error.error = `${errorMessage} : ${errorDescription}`; + Error.isError = true; + return Error; + } else { + Error = errorMessage; + Error.isError = true; + return Error; + } + } + } + + let searchResponse; + let status = "validation-started"; + + // Retry until a response is received + while (status !== "failed" && status !== "invalid" && status !== "completed") { + searchResponse = await Digit.CustomService.getResponse({ + url: "/project-factory/v1/data/_search", + body: { + SearchCriteria: { + id: [response?.ResourceDetails?.id], + tenantId: tenantId, + type: Type, + }, + }, + }); + status = searchResponse?.ResourceDetails?.[0]?.status; + if (status !== "failed" && status !== "invalid" && status !== "completed") { + await new Promise((resolve) => setTimeout(resolve, 10000)); + } + } + if (Error.isError) { + return Error; + } + return searchResponse?.ResourceDetails?.[0]; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useUpdateCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useUpdateCampaign.js new file mode 100644 index 00000000000..7123ace38c8 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useUpdateCampaign.js @@ -0,0 +1,10 @@ +import { useMutation } from "react-query"; +import updateCampaignService from "./services/updateCampaignService"; + +const useUpdateCampaign = (tenantId) => { + return useMutation((reqData) => { + return updateCampaignService(reqData, tenantId); + }); +}; + +export default useUpdateCampaign; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/AddProduct.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/AddProduct.js new file mode 100644 index 00000000000..14a772d40dc --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/AddProduct.js @@ -0,0 +1,161 @@ +import { Loader, FormComposerV2, Header } from "@egovernments/digit-ui-react-components"; +import React, { useState, useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import { useHistory, useLocation } from "react-router-dom"; +import { addProductConfig } from "../../configs/addProductConfig"; +import { Toast } from "@egovernments/digit-ui-components"; + +function AddProduct() { + const { t } = useTranslation(); + const history = useHistory(); + const tenantId = Digit.ULBService.getCurrentTenantId(); + const [showToast, setShowToast] = useState(null); + const { state } = useLocation(); + const { mutate: createProduct } = Digit.Hooks.campaign.useCreateProduct(tenantId); + const { mutate: createProductVariant } = Digit.Hooks.campaign.useCreateProductVariant(tenantId); + + const checkValid = (formData) => { + const target = formData?.["addProduct"]; + let isValid = false; + if (target) { + isValid = target?.some((i) => !i.name || !i.type || !i.variant); + return !isValid; + } else { + return isValid; + } + }; + const closeToast = () => { + setShowToast(null); + }; + + useEffect(() => { + if (showToast) { + setTimeout(closeToast, 5000); + } + }, [showToast]); + + const onSubmit = async (formData) => { + const isValid = checkValid(formData); + const invalidName = formData?.addProduct + ?.map((i) => { + if (i?.name?.length > 2 && i?.name?.length < 101) { + return true; + } else { + return false; + } + }) + ?.includes(false); + + const invalidVariant = formData?.addProduct + ?.map((i) => { + if (i?.variant?.length > 2 && i?.variant?.length < 101) { + return true; + } else { + return false; + } + }) + ?.includes(false); + + if (!isValid) { + setShowToast({ key: "error", label: "CAMPAIGN_ADD_PRODUCT_MANDATORY_ERROR", isError: true }); + return; + } + + if (invalidName) { + setShowToast({ key: "error", label: "CAMPAIGN_PRODUCT_NAME_ERROR", isError: true }); + return; + } + + if (invalidVariant) { + setShowToast({ key: "error", label: "CAMPAIGN_PRODUCT_VARIANT_ERROR", isError: true }); + return; + } + + const payloadData = formData?.["addProduct"]?.map((i) => ({ + tenantId: tenantId, + type: i?.type?.code, + name: i?.name, + })); + + await createProduct(payloadData, { + onError: (error, variables) => { + console.log(error); + setShowToast({ key: "error", label: error, isError: true }); + }, + onSuccess: async (data) => { + const resData = data?.Product; + const variantPayload = resData.map((i) => { + const target = formData?.["addProduct"]?.find((f) => f.name === i.name); + if (target) { + return { + tenantId: tenantId, + productId: i?.id, + variation: target?.variant, + sku: target?.variant, + }; + } + return; + }); + await createProductVariant(variantPayload, { + onError: (error, variables) => { + console.log(error); + setShowToast({ key: "error", label: error, isError: true }); + }, + onSuccess: async (data) => { + history.push(`/${window.contextPath}/employee/campaign/response?isSuccess=${true}`, { + message: "ES_PRODUCT_CREATE_SUCCESS_RESPONSE", + preText: "ES_PRODUCT_CREATE_SUCCESS_RESPONSE_PRE_TEXT", + boldText: "ES_PRODUCT_CREATE_SUCCESS_RESPONSE_BOLD_TEXT", + postText: "ES_PRODUCT_CREATE_SUCCESS_RESPONSE_POST_TEXT", + actionLabel: "ES_PRODUCT_RESPONSE_ACTION", + actionLink: `/${window.contextPath}/employee/campaign/setup-campaign${state?.urlParams}`, + }); + }, + }); + }, + }); + return; + }; + const onFormValueChange = (setValue, formData, formState, reset, setError, clearErrors, trigger, getValues) => { + return; + }; + + const onSecondayActionClick = () => { + history.push(`/${window.contextPath}/employee/campaign/setup-campaign${state?.urlParams}`); + }; + + return ( +
+ { + return { + ...config, + }; + })} + onSubmit={onSubmit} + fieldStyle={{ marginRight: 0 }} + noBreakLine={true} + cardClassName={"page-padding-fix"} + onFormValueChange={onFormValueChange} + actionClassName={"actionBarClass"} + showSecondaryLabel={true} + secondaryLabel={t("HCM_BACK")} + onSecondayActionClick={onSecondayActionClick} + /> + + {showToast && ( + setShowToast(false)} + /> + )} +
+ ); +} + +export default AddProduct; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/CycleConfiguration.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/CycleConfiguration.js new file mode 100644 index 00000000000..59882ee75e6 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/CycleConfiguration.js @@ -0,0 +1,217 @@ +import React, { useReducer, Fragment, useEffect, useState } from "react"; +import { CardText, LabelFieldPair, Card, CardLabel, CardSubHeader, Paragraph, Header } from "@egovernments/digit-ui-react-components"; +import { useTranslation } from "react-i18next"; +import { TextInput } from "@egovernments/digit-ui-components"; +import { deliveryConfig } from "../../configs/deliveryConfig"; + +const initialState = (saved, filteredDeliveryConfig) => { + const data = { + cycleConfgureDate: { + cycle: saved?.cycleConfgureDate?.cycle + ? saved?.cycleConfgureDate?.cycle + : filteredDeliveryConfig?.cycleConfig + ? filteredDeliveryConfig?.cycleConfig?.cycle + : 1, + deliveries: saved?.cycleConfgureDate?.deliveries + ? saved?.cycleConfgureDate?.deliveries + : filteredDeliveryConfig?.cycleConfig + ? filteredDeliveryConfig?.cycleConfig?.deliveries + : 1, + }, + cycleData: saved?.cycleData ? [...saved?.cycleData] : [], + }; + // onSelect("cycleConfigure", state); + return data; +}; + +const reducer = (state, action) => { + switch (action.type) { + case "RELOAD": + return initialState(action.saved, action.filteredDeliveryConfig); + case "UPDATE_CYCLE": + return { ...state, cycleConfgureDate: { ...state.cycleConfgureDate, cycle: action.payload } }; + case "UPDATE_DELIVERY": + return { ...state, cycleConfgureDate: { ...state.cycleConfgureDate, deliveries: action.payload } }; + case "SELECT_TO_DATE": + return { + ...state, + cycleData: updateCycleData(state.cycleData, action.index, { toDate: action.payload }), + // cycleData: state.cycleData.map((item) => (item.key === action.index ? { ...item, toDate: action.payload } : item)), + }; + case "SELECT_FROM_DATE": + return { + ...state, + cycleData: updateCycleData(state.cycleData, action.index, { fromDate: action.payload }), + // cycleData: state.cycleData.map((item) => (item.key === action.index ? { ...item, fromDate: action.payload } : item)), + }; + default: + return state; + } +}; + +const updateCycleData = (cycleData, index, update) => { + const existingItem = cycleData.find((item) => item.key === index); + + if (!existingItem) { + // If the item with the specified key doesn't exist, add a new item + return [...cycleData, { key: index, ...update }]; + } + + // If the item exists, update it + return cycleData.map((item) => (item.key === index ? { ...item, ...update } : item)); +}; + +function CycleConfiguration({ onSelect, formData, control, ...props }) { + const tenantId = Digit.ULBService.getCurrentTenantId(); + const selectedProjectType = window.Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA")?.HCM_CAMPAIGN_TYPE?.projectType?.code; + const { isLoading: deliveryConfigLoading, data: filteredDeliveryConfig } = Digit.Hooks.useCustomMDMS( + tenantId, + "HCM-ADMIN-CONSOLE", + [{ name: "deliveryConfig" }], + { + select: (data) => { + const temp = data?.["HCM-ADMIN-CONSOLE"]?.deliveryConfig; + // return temp?.find((i) => i?.projectType === selectedProjectType); + return deliveryConfig?.find((i) => i?.projectType === selectedProjectType); + }, + } + ); + const saved = Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA")?.HCM_CAMPAIGN_CYCLE_CONFIGURE?.cycleConfigure; + const tempSession = Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA"); + const [state, dispatch] = useReducer(reducer, initialState(saved, filteredDeliveryConfig)); + const { cycleConfgureDate, cycleData } = state; + const { t } = useTranslation(); + const [dateRange, setDateRange] = useState({ + startDate: tempSession?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate, + endDate: tempSession?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate, + }); + const [executionCount, setExecutionCount] = useState(0); + + useEffect(() => { + if (!deliveryConfigLoading) { + dispatch({ + type: "RELOAD", + saved: saved, + filteredDeliveryConfig: filteredDeliveryConfig, + }); + } + }, [filteredDeliveryConfig, deliveryConfigLoading]); + useEffect(() => { + onSelect("cycleConfigure", state); + }, [state]); + + useEffect(() => { + if (executionCount < 5) { + onSelect("cycleConfigure", state); + setExecutionCount((prevCount) => prevCount + 1); + } + }); + + const updateCycle = (d) => { + if (d === 0 || d > 5) return; + if (Number(d?.target?.value) === 0 || Number(d?.target?.value) > 5) return; + // if (d?.target?.value.trim() === "") return; + dispatch({ type: "UPDATE_CYCLE", payload: d?.target?.value ? Number(d?.target?.value) : d?.target?.value === "" ? d.target.value : d }); + }; + + const updateDelivery = (d) => { + if (d === 0 || d > 5) return; + if (Number(d?.target?.value) === 0 || Number(d?.target?.value) > 5) return; + // if (d?.target?.value.trim() === "") return; + dispatch({ type: "UPDATE_DELIVERY", payload: d?.target?.value ? Number(d?.target?.value) : d }); + }; + + const selectToDate = (index, d) => { + dispatch({ type: "SELECT_TO_DATE", index, payload: d }); + }; + + const selectFromDate = (index, d) => { + dispatch({ type: "SELECT_FROM_DATE", index, payload: d }); + }; + + return ( + <> +
+ {t( + `CAMPAIGN_PROJECT_${ + tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.code + ? tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.code?.toUpperCase() + : tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.toUpperCase() + }` + )} +
+ + + + {t( + `CAMPAIGN_CYCLE_CONFIGURE_HEADING_${ + tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.code + ? tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.code?.toUpperCase() + : tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.toUpperCase() + }` + )} + + + + {t(`CAMPAIGN_NO_OF_CYCLE`)} + * + + updateCycle(d)} /> + {/* updateCycle(d)} /> */} + + + + {t(`CAMPAIGN_NO_OF_DELIVERY`)} + * + + updateDelivery(d)} /> + {/* updateDelivery(d)} /> */} + + + + {t(`CAMPAIGN_ADD_START_END_DATE_TEXT`)} + {[...Array(cycleConfgureDate.cycle)].map((_, index) => ( + + + {t(`CAMPAIGN_CYCLE`)} {index + 1} + +
+ j.key === index + 1)?.fromDate} + min={ + index > 0 && cycleData?.find((j) => j.key === index)?.toDate + ? new Date(new Date(cycleData?.find((j) => j.key === index)?.toDate)?.getTime() + 86400000)?.toISOString()?.split("T")?.[0] + : dateRange?.startDate + } + max={dateRange?.endDate} + onChange={(d) => selectFromDate(index + 1, d)} + /> + j.key === index + 1)?.toDate} + min={ + cycleData?.find((j) => j.key === index + 1)?.fromDate + ? new Date(new Date(cycleData?.find((j) => j.key === index + 1)?.fromDate)?.getTime() + 86400000)?.toISOString()?.split("T")?.[0] + : null + } + max={dateRange?.endDate} + onChange={(d) => selectToDate(index + 1, d)} + /> +
+
+ ))} +
+ + ); +} + +export default CycleConfiguration; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js new file mode 100644 index 00000000000..9e906e3ae2d --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js @@ -0,0 +1,46 @@ +import React, { useMemo, useState, useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import { Button, Header, InboxSearchComposer, Loader } from "@egovernments/digit-ui-react-components"; +import { useLocation } from "react-router-dom"; +import { myCampaignConfig } from "../../configs/myCampaignConfig"; + +/** + * The `MyCampaign` function is a React component that displays a header with a campaign search title + * and an inbox search composer with tabs for different configurations. + * @returns The `MyCampaign` component is returning a React fragment containing a Header component with + * a title fetched using the `useTranslation` hook, and a div with a className of + * "inbox-search-wrapper" that contains an `InboxSearchComposer` component. The `InboxSearchComposer` + * component is being passed props such as `configs`, `showTab`, `tabData`, and `onTabChange + */ +const MyCampaign = () => { + const { t } = useTranslation(); + const location = useLocation(); + const moduleName = Digit?.Utils?.getConfigModuleName() || "commonCampaignUiConfig"; + const tenant = Digit.ULBService.getStateId(); + const tenantId = Digit.ULBService.getCurrentTenantId(); + const [config, setConfig] = useState(myCampaignConfig?.myCampaignConfig?.[0]); + const [tabData, setTabData] = useState( + myCampaignConfig?.myCampaignConfig?.map((configItem, index) => ({ key: index, label: configItem.label, active: index === 0 ? true : false })) + ); + + const onTabChange = (n) => { + setTabData((prev) => prev.map((i, c) => ({ ...i, active: c === n ? true : false }))); + setConfig(myCampaignConfig?.myCampaignConfig?.[n]); + }; + + useEffect(() => { + window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA"); + window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_UPLOAD_ID"); + }, []); + + return ( + +
{t("CAMPAIGN_SEARCH_TITLE")}
+
+ +
+
+ ); +}; + +export default MyCampaign; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/Response.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/Response.js new file mode 100644 index 00000000000..8e981b17965 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/Response.js @@ -0,0 +1,65 @@ +import React, { useState, Fragment } from "react"; +import { Link, useHistory, useLocation } from "react-router-dom"; +import { useTranslation } from "react-i18next"; +import { ActionBar, SubmitBar } from "@egovernments/digit-ui-react-components"; +import { PanelCard } from "@egovernments/digit-ui-components"; + +const Response = () => { + const { t } = useTranslation(); + const history = useHistory(); + const queryStrings = Digit.Hooks.useQueryParams(); + const [campaignId, setCampaignId] = useState(queryStrings?.campaignId); + const [isResponseSuccess, setIsResponseSuccess] = useState( + queryStrings?.isSuccess === "true" ? true : queryStrings?.isSuccess === "false" ? false : true + ); + const { state } = useLocation(); + const isMobile = window.Digit.Utils.browser.isMobile(); + + const navigate = (page) => { + switch (page) { + case "contracts-inbox": { + history.push(`/${window.contextPath}/employee/tqm/summary`); + } + } + }; + + const children = [ +
+ {state?.boldText ? ( +

+ {t(state?.preText)} + {t(state?.boldText)} + {t(state?.postText)} +

+ ) : ( + t(state?.text, { CAMPAIGN_ID: campaignId }) + )} +
, + ]; + + return ( + <> + + {isMobile ? ( + + + + ) : ( + + + + + + )} + + ); +}; + +export default Response; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js new file mode 100644 index 00000000000..1b19ef6537e --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js @@ -0,0 +1,1270 @@ +import { Loader, FormComposerV2, Header, MultiUploadWrapper, Button, Close, LogoutIcon } from "@egovernments/digit-ui-react-components"; +import React, { useState, useEffect, useMemo } from "react"; +import { useTranslation } from "react-i18next"; +import { useHistory, useParams } from "react-router-dom"; +import { CampaignConfig } from "../../configs/CampaignConfig"; +import { QueryClient, useQueryClient } from "react-query"; +import { Stepper, Toast } from "@egovernments/digit-ui-components"; +import _ from "lodash"; + +/** + * The `SetupCampaign` function in JavaScript handles the setup and management of campaign details, + * including form data handling, validation, and submission. + * @returns The `SetupCampaign` component is being returned. It consists of a form setup for creating + * or updating a campaign with multiple steps like campaign details, delivery details, boundary + * details, targets, facility details, user details, and review details. The form data is validated at + * each step, and the user can navigate between steps using a stepper component. The form submission + * triggers API calls to create or update the campaign + */ + +function loopAndReturn(dataa) { + let newArray = []; + const data = dataa?.map((i) => ({ ...i, operator: { code: i?.operator }, attribute: { code: i?.attribute } })); + + data.forEach((item) => { + // Check if an object with the same attribute already exists in the newArray + const existingIndex = newArray.findIndex((element) => element.attribute.code === item.attribute.code); + if (existingIndex !== -1) { + // If an existing item is found, replace it with the new object + const existingItem = newArray[existingIndex]; + newArray[existingIndex] = { + attribute: existingItem.attribute, + operator: { code: "IN_BETWEEN" }, + toValue: existingItem.value && item.value ? Math.min(existingItem.value, item.value) : null, + fromValue: existingItem.value && item.value ? Math.max(existingItem.value, item.value) : null, + }; + } + // else if (item?.operator?.code === "EQUAL_TO" && item?.attribute?.code === "Gender") { + // newArray.push({ + // ...item, + // value: item?.value + // ? { + // code: item?.value, + // } + // : null, + // }); + // } + else { + // If no existing item with the same attribute is found, push the current item + // if (item?.operator?.code === "EQUAL_TO" && item?.attribute?.code === "Gender") { + // newArray.push({ + // ...item, + // value: { + // code: item?.value, + // }, + // }); + // } else { + newArray.push(item); + // } + } + }); + + const withKey = newArray.map((i, c) => ({ key: c + 1, ...i })); + return withKey; +} + +function cycleDataRemap(data) { + if (!data) return null; + const uniqueCycleObjects = Object.values( + data?.reduce((acc, obj) => { + acc[obj?.cycleNumber] = acc[obj?.cycleNumber] || obj; + return acc; + }, {}) + ); + return uniqueCycleObjects.map((i, n) => { + return { + key: i.cycleNumber, + fromDate: i?.startDate ? new Date(i?.startDate)?.toISOString()?.split("T")?.[0] : null, + toDate: i?.endDate ? new Date(i?.endDate)?.toISOString()?.split("T")?.[0] : null, + }; + }); +} + +// function reverseDeliveryRemap(data) { +// if (!data) return null; +// const reversedData = []; +// let currentCycleIndex = null; +// let currentDeliveryIndex = null; +// let currentCycle = null; +// let currentDelivery = null; + +// data.forEach((item, index) => { +// if (currentCycleIndex !== item.cycleNumber) { +// currentCycleIndex = item.cycleNumber; +// currentCycle = { +// cycleIndex: currentCycleIndex.toString(), +// active: index === 0, // Set active to true only for the first index +// deliveries: [], +// }; +// reversedData.push(currentCycle); +// } + +// if (currentDeliveryIndex !== item.deliveryNumber) { +// currentDeliveryIndex = item.deliveryNumber; +// currentDelivery = { +// deliveryIndex: currentDeliveryIndex.toString(), +// active: item?.deliveryNumber === 1, // Set active to true only for the first index +// deliveryRules: [], +// }; +// currentCycle.deliveries.push(currentDelivery); +// } + +// currentDelivery.deliveryRules.push({ +// ruleKey: currentDelivery.deliveryRules.length + 1, +// delivery: {}, +// attributes: loopAndReturn(item.conditions), +// products: [...item.products], +// }); +// }); + +// return reversedData; +// } + +function reverseDeliveryRemap(data) { + if (!data) return null; + const reversedData = []; + let currentCycleIndex = null; + let currentCycle = null; + + data.forEach((item, index) => { + if (currentCycleIndex !== item.cycleNumber) { + currentCycleIndex = item.cycleNumber; + currentCycle = { + cycleIndex: currentCycleIndex.toString(), + active: index === 0, // Initialize active to false + deliveries: [], + }; + reversedData.push(currentCycle); + } + + const deliveryIndex = item.deliveryNumber.toString(); + + let delivery = currentCycle.deliveries.find((delivery) => delivery.deliveryIndex === deliveryIndex); + + if (!delivery) { + delivery = { + deliveryIndex: deliveryIndex, + active: item.deliveryNumber === 1, // Set active to true only for the first delivery + deliveryRules: [], + }; + currentCycle.deliveries.push(delivery); + } + + delivery.deliveryRules.push({ + ruleKey: item.deliveryRuleNumber, + delivery: {}, + attributes: loopAndReturn(item.conditions), + products: [...item.products], + }); + }); + + return reversedData; +} + +function groupByType(data) { + if (!data) return null; + const result = {}; + + data.forEach((item) => { + if (result[item.type]) { + result[item.type].push(item); + } else { + result[item.type] = [item]; + } + }); + + return { + TenantBoundary: { + boundary: result, + }, + }; +} + +function groupByTypeRemap(data) { + if (!data) return null; + + const result = {}; + + data.forEach((item) => { + const type = item?.type; + const boundaryType = item?.type; + const parentCode = item?.parent; + const obj = { + parentCode, + boundaryTypeData: { + TenantBoundary: [ + { + boundary: [{ ...item, boundaryType }], + }, + ], + }, + }; + + if (result[type]) { + result[type][0].boundaryTypeData.TenantBoundary[0].boundary.push(item); + } else { + result[type] = [obj]; + } + }); + + return result; +} + +// Example usage: +// updateUrlParams({ id: 'sdjkhsdjkhdshfsdjkh', anotherParam: 'value' }); +function updateUrlParams(params) { + const url = new URL(window.location.href); + Object.entries(params).forEach(([key, value]) => { + url.searchParams.set(key, value); + }); + window.history.replaceState({}, "", url); +} + +const SetupCampaign = ({ hierarchyType }) => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + const { t } = useTranslation(); + const history = useHistory(); + const [currentStep, setCurrentStep] = useState(0); + const [totalFormData, setTotalFormData] = useState({}); + const [isSubmitting, setIsSubmitting] = useState(false); + const [campaignConfig, setCampaignConfig] = useState(CampaignConfig(totalFormData, null, isSubmitting)); + const [shouldUpdate, setShouldUpdate] = useState(false); + const [params, setParams, clearParams] = Digit.Hooks.useSessionStorage("HCM_CAMPAIGN_MANAGER_FORM_DATA", {}); + const [dataParams, setDataParams] = Digit.Hooks.useSessionStorage("HCM_CAMPAIGN_MANAGER_UPLOAD_ID", {}); + const [showToast, setShowToast] = useState(null); + const { mutate } = Digit.Hooks.campaign.useCreateCampaign(tenantId); + const { mutate: updateCampaign } = Digit.Hooks.campaign.useUpdateCampaign(tenantId); + const searchParams = new URLSearchParams(location.search); + const id = searchParams.get("id"); + const isPreview = searchParams.get("preview"); + const isSummary = searchParams.get("summary"); + const noAction = searchParams.get("action"); + const isDraft = searchParams.get("draft"); + const isSkip = searchParams.get("skip"); + const [isDraftCreated, setIsDraftCreated] = useState(false); + const filteredBoundaryData = params?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData; + const client = useQueryClient(); + // const hierarchyType2 = params?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.hierarchy?.hierarchyType + const [currentKey, setCurrentKey] = useState(() => { + const keyParam = searchParams.get("key"); + return keyParam ? parseInt(keyParam) : 1; + }); + + // const [lowest, setLowest] = useState(null); + const [fetchBoundary, setFetchBoundary] = useState(() => Boolean(searchParams.get("fetchBoundary"))); + const [fetchUpload, setFetchUpload] = useState(false); + const [enabled, setEnabled] = useState(false); + const { data: hierarchyConfig } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "hierarchyConfig" }]); + // const hierarchyType = hierarchyConfig?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.hierarchy; + + // const lowestHierarchy = hierarchyConfig?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.lowestHierarchy; + const lowestHierarchy = useMemo(() => hierarchyConfig?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.lowestHierarchy, [hierarchyConfig]); + + const reqCriteria = { + url: `/boundary-service/boundary-hierarchy-definition/_search`, + changeQueryName: `${hierarchyType}`, + body: { + BoundaryTypeHierarchySearchCriteria: { + tenantId: tenantId, + limit: 2, + offset: 0, + hierarchyType: hierarchyType, + }, + }, + }; + + const { data: hierarchyDefinition } = Digit.Hooks.useCustomAPIHook(reqCriteria); + + // useEffect(() => { + // if (hierarchyDefinition) { + // setLowest( + // hierarchyDefinition?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.filter( + // (e) => !hierarchyDefinition?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.find((e1) => e1?.parentBoundaryType == e?.boundaryType) + // ) + // ); + // } + // }, [hierarchyDefinition]); + const { isLoading: draftLoading, data: draftData, error: draftError, refetch: draftRefetch } = Digit.Hooks.campaign.useSearchCampaign({ + tenantId: tenantId, + filter: { + ids: [id], + }, + config: { + enabled: id ? true : false, + select: (data) => { + return data?.[0]; + }, + }, + }); + + const { isLoading, data: projectType } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-PROJECT-TYPES", [{ name: "projectTypes" }]); + + useEffect(() => { + if (fetchUpload) { + setFetchUpload(false); + } + if (fetchBoundary && currentKey > 5) { + setFetchBoundary(false); + } + }, [fetchUpload, fetchBoundary]); + + useEffect(() => { + if (isPreview === "true") { + setIsDraftCreated(true); + setCurrentKey(10); + return; + } + if (isDraft === "true") { + setIsDraftCreated(true); + if (isSkip === "false") { + currentKey !== 1 ? null : setCurrentKey(1); + } else { + setCurrentKey(draftData?.additionalDetails?.key); + } + return; + } + }, [isPreview, isDraft, draftData]); + + useEffect(() => { + setTotalFormData(params); + }, [params]); + + //DATA STRUCTURE + useEffect(() => { + if (isLoading) return; + if (Object.keys(params).length !== 0) return; + if (!draftData) return; + const delivery = Array.isArray(draftData?.deliveryRules) ? draftData?.deliveryRules : []; + const filteredProjectType = projectType?.["HCM-PROJECT-TYPES"]?.projectTypes?.filter((i) => i?.code === draftData?.projectType); + const restructureFormData = { + HCM_CAMPAIGN_TYPE: { projectType: filteredProjectType?.[0] }, + HCM_CAMPAIGN_NAME: { + campaignName: draftData?.campaignName, + }, + HCM_CAMPAIGN_DATE: { + campaignDates: { + startDate: draftData?.startDate ? new Date(draftData?.startDate)?.toISOString()?.split("T")?.[0] : null, + endDate: draftData?.endDate ? new Date(draftData?.endDate)?.toISOString()?.split("T")?.[0] : null, + }, + }, + HCM_CAMPAIGN_CYCLE_CONFIGURE: { + cycleConfigure: { + cycleConfgureDate: draftData?.additionalDetails?.cycleData?.cycleConfgureDate + ? draftData?.additionalDetails?.cycleData?.cycleConfgureDate + : { + cycle: delivery?.map((obj) => obj?.cycleNumber)?.length > 0 ? Math.max(...delivery?.map((obj) => obj?.cycleNumber)) : 1, + deliveries: delivery?.map((obj) => obj?.deliveryNumber)?.length > 0 ? Math.max(...delivery?.map((obj) => obj?.deliveryNumber)) : 1, + }, + cycleData: draftData?.additionalDetails?.cycleData?.cycleData + ? draftData?.additionalDetails?.cycleData?.cycleData + : cycleDataRemap(delivery), + }, + }, + HCM_CAMPAIGN_DELIVERY_DATA: { + deliveryRule: reverseDeliveryRemap(delivery), + }, + HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA: { + boundaryType: { + boundaryData: groupByTypeRemap(draftData?.boundaries), + selectedData: draftData?.boundaries, + }, + }, + HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA: { + uploadBoundary: { uploadedFile: draftData?.resources?.filter((i) => i?.type === "boundaryWithTarget") }, + }, + HCM_CAMPAIGN_UPLOAD_FACILITY_DATA: { + uploadFacility: { uploadedFile: draftData?.resources?.filter((i) => i?.type === "facility") }, + }, + HCM_CAMPAIGN_UPLOAD_USER_DATA: { + uploadUser: { uploadedFile: draftData?.resources?.filter((i) => i?.type === "user") }, + }, + }; + setParams({ ...restructureFormData }); + }, [params, draftData, isLoading, projectType]); + + useEffect(() => { + setTimeout(() => { + setEnabled(fetchUpload || (fetchBoundary && currentKey > 6)); + }, 3000); + + // return () => clearTimeout(timeoutId); + }, [fetchUpload, fetchBoundary, currentKey]); + + const { data: facilityId, isLoading: isFacilityLoading, refetch: refetchFacility } = Digit.Hooks.campaign.useGenerateIdCampaign({ + type: "facilityWithBoundary", + hierarchyType: hierarchyType, + campaignId: id, + // config: { + // enabled: setTimeout(fetchUpload || (fetchBoundary && currentKey > 6)), + // }, + config: { + enabled: enabled, + }, + }); + + // useEffect(() => { + // if (filteredBoundaryData) { + // refetchBoundary(); + // } + // }, [filteredBoundaryData]); + + const { data: boundaryId, isLoading: isBoundaryLoading, refetch: refetchBoundary } = Digit.Hooks.campaign.useGenerateIdCampaign({ + type: "boundary", + hierarchyType: hierarchyType, + // filters: filteredBoundaryData, + campaignId: id, + // config: { + // enabled: fetchUpload || (fetchBoundary && currentKey > 6), + // }, + config: { + enabled: enabled, + }, + }); + + const { data: userId, isLoading: isUserLoading, refetch: refetchUser } = Digit.Hooks.campaign.useGenerateIdCampaign({ + type: "userWithBoundary", + hierarchyType: hierarchyType, + campaignId: id, + // config: { + // enabled: fetchUpload || (fetchBoundary && currentKey > 6), + // }, + config: { + enabled: enabled, + }, + }); + + useEffect(() => { + if (hierarchyDefinition?.BoundaryHierarchy?.[0]) { + setDataParams({ + ...dataParams, + facilityId: facilityId, + boundaryId: boundaryId, + userId: userId, + hierarchyType: hierarchyType, + hierarchy: hierarchyDefinition?.BoundaryHierarchy?.[0], + isBoundaryLoading, + isFacilityLoading, + isUserLoading, + }); + } + }, [isBoundaryLoading, isFacilityLoading, isUserLoading, facilityId, boundaryId, userId, hierarchyDefinition?.BoundaryHierarchy?.[0]]); // Only run if dataParams changes + + useEffect(() => { + setCampaignConfig(CampaignConfig(totalFormData, dataParams, isSubmitting)); + }, [totalFormData, dataParams, isSubmitting]); + + useEffect(() => { + setIsSubmitting(false); + if (currentKey === 10 && isSummary !== "true") { + updateUrlParams({ key: currentKey, summary: true }); + } else { + updateUrlParams({ key: currentKey, summary: false }); + } + }, [currentKey]); + + function restructureData(data) { + const dateData = totalFormData?.HCM_CAMPAIGN_CYCLE_CONFIGURE?.cycleConfigure?.cycleData; + const restructuredData = []; + + data.forEach((cycle) => { + cycle.deliveries.forEach((delivery, index) => { + delivery.deliveryRules.forEach((rule) => { + const restructuredRule = { + startDate: Digit.Utils.date.convertDateToEpoch(dateData?.find((i) => i.key == cycle.cycleIndex)?.fromDate), // Hardcoded for now + endDate: Digit.Utils.date.convertDateToEpoch(dateData?.find((i) => i?.key == cycle?.cycleIndex)?.toDate), // Hardcoded for now + cycleNumber: parseInt(cycle.cycleIndex), + deliveryNumber: parseInt(delivery.deliveryIndex), + deliveryRuleNumber: parseInt(rule.ruleKey), // New key added + products: [], + conditions: [], + }; + + rule.attributes.forEach((attribute) => { + if (attribute?.operator?.code === "IN_BETWEEN") { + restructuredRule.conditions.push({ + attribute: attribute?.attribute?.code + ? attribute?.attribute?.code + : typeof attribute?.attribute === "string" + ? attribute?.attribute + : null, + operator: "LESS_THAN", + value: attribute.fromValue ? Number(attribute.fromValue) : null, + }); + + restructuredRule.conditions.push({ + attribute: attribute?.attribute?.code + ? attribute?.attribute?.code + : typeof attribute?.attribute === "string" + ? attribute?.attribute + : null, + operator: "GREATER_THAN", + value: attribute.toValue ? Number(attribute.toValue) : null, + }); + } else { + restructuredRule.conditions.push({ + attribute: attribute?.attribute?.code + ? attribute?.attribute?.code + : typeof attribute?.attribute === "string" + ? attribute?.attribute + : null, + operator: attribute.operator ? attribute.operator.code : null, + value: + attribute?.attribute?.code === "Gender" && attribute?.value?.length > 0 + ? attribute?.value + : attribute?.value + ? Number(attribute?.value) + : null, + }); + } + }); + + rule.products.forEach((prod) => { + restructuredRule.products.push({ + value: prod?.value, + name: prod?.name, + count: prod?.count, + }); + }); + + restructuredData.push(restructuredRule); + }); + }); + }); + + return restructuredData; + } + + function resourceData(facilityData, boundaryData, userData) { + const resources = [facilityData, boundaryData, userData].filter((data) => data !== null && data !== undefined); + return resources; + } + + useEffect(async () => { + if (totalFormData?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule) { + const temp = restructureData(totalFormData?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule); + } + }, [shouldUpdate]); + + const compareIdentical = (draftData, payload) => { + return _.isEqual(draftData, payload); + }; + //API CALL + useEffect(async () => { + if (shouldUpdate === true) { + if (filteredConfig?.[0]?.form?.[0]?.body?.[0]?.skipAPICall && !id) { + return; + } else if (filteredConfig?.[0]?.form?.[0]?.isLast) { + const reqCreate = async () => { + let payloadData = { ...draftData }; + payloadData.hierarchyType = hierarchyType; + payloadData.startDate = totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate + ? Digit.Utils.date.convertDateToEpoch(totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate) + : null; + payloadData.endDate = totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate + ? Digit.Utils.date.convertDateToEpoch(totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate) + : null; + payloadData.tenantId = tenantId; + payloadData.action = "create"; + payloadData.campaignName = totalFormData?.HCM_CAMPAIGN_NAME?.campaignName; + if (totalFormData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData) { + payloadData.boundaries = totalFormData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData; + } + const temp = resourceData( + totalFormData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile?.[0], + totalFormData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile?.[0], + totalFormData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile?.[0] + ); + payloadData.resources = temp; + payloadData.projectType = totalFormData?.HCM_CAMPAIGN_TYPE?.projectType?.code; + payloadData.additionalDetails = { + beneficiaryType: totalFormData?.HCM_CAMPAIGN_TYPE?.projectType?.beneficiaryType, + key: currentKey, + }; + if (totalFormData?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule) { + const temp = restructureData(totalFormData?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule); + payloadData.deliveryRules = temp; + } + + // await mutate(payloadData, { + // onError: (error, variables) => {}, + // onSuccess: async (data) => { + // draftRefetch(); + // history.push( + // `/${window.contextPath}/employee/campaign/response?campaignId=${data?.CampaignDetails?.campaignNumber}&isSuccess=${true}`, + // { + // message: "ES_CAMPAIGN_CREATE_SUCCESS_RESPONSE", + // text: "ES_CAMPAIGN_CREATE_SUCCESS_RESPONSE_TEXT", + // } + // ); + // Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA"); + // }, + // }); + if (compareIdentical(draftData, payloadData) === false) { + await updateCampaign(payloadData, { + onError: (error, variables) => { + console.log(error); + setShowToast({ key: "error", label: error?.message ? error?.message : error }); + }, + onSuccess: async (data) => { + draftRefetch(); + history.push( + `/${window.contextPath}/employee/campaign/response?campaignId=${data?.CampaignDetails?.campaignNumber}&isSuccess=${true}`, + { + message: t("ES_CAMPAIGN_CREATE_SUCCESS_RESPONSE"), + text: t("ES_CAMPAIGN_CREATE_SUCCESS_RESPONSE_TEXT"), + info: t("ES_CAMPAIGN_SUCCESS_INFO_TEXT"), + actionLabel: t("HCM_CAMPAIGN_SUCCESS_RESPONSE_ACTION"), + actionLink: `/${window.contextPath}/employee/campaign/my-campaign`, + } + ); + Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA"); + }, + }); + } + }; + + reqCreate(); + } else if (!isDraftCreated && !id) { + const reqCreate = async () => { + let payloadData = {}; + payloadData.hierarchyType = hierarchyType; + if (totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate) { + payloadData.startDate = totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate + ? Digit.Utils.date.convertDateToEpoch(totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate) + : null; + } + if (totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate) { + payloadData.endDate = totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate + ? Digit.Utils.date.convertDateToEpoch(totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate) + : null; + } + payloadData.tenantId = tenantId; + payloadData.action = "draft"; + payloadData.campaignName = totalFormData?.HCM_CAMPAIGN_NAME?.campaignName; + if (totalFormData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData) { + payloadData.boundaries = totalFormData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData; + } + const temp = resourceData( + totalFormData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile?.[0], + totalFormData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile?.[0], + totalFormData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile?.[0] + ); + payloadData.resources = temp; + payloadData.projectType = totalFormData?.HCM_CAMPAIGN_TYPE?.projectType?.code; + payloadData.additionalDetails = { + beneficiaryType: totalFormData?.HCM_CAMPAIGN_TYPE?.projectType?.beneficiaryType, + key: currentKey, + }; + if (totalFormData?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule) { + const temp = restructureData(totalFormData?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule); + + payloadData.deliveryRules = temp; + } + + await mutate(payloadData, { + onError: (error, variables) => { + if (filteredConfig?.[0]?.form?.[0]?.body?.[0]?.mandatoryOnAPI) { + setShowToast({ key: "error", label: error?.message ? error?.message : error }); + } + }, + onSuccess: async (data) => { + updateUrlParams({ id: data?.CampaignDetails?.id }); + setIsDraftCreated(true); + draftRefetch(); + if (filteredConfig?.[0]?.form?.[0]?.body?.[0]?.mandatoryOnAPI) { + setCurrentKey(currentKey + 1); + } + }, + }); + }; + + reqCreate(); + } else { + const reqCreate = async () => { + let payloadData = { ...draftData }; + payloadData.hierarchyType = hierarchyType; + if (totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate) { + payloadData.startDate = totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate + ? Digit.Utils.date.convertDateToEpoch(totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.startDate) + : null; + } + if (totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate) { + payloadData.endDate = totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate + ? Digit.Utils.date.convertDateToEpoch(totalFormData?.HCM_CAMPAIGN_DATE?.campaignDates?.endDate) + : null; + } + payloadData.tenantId = tenantId; + payloadData.action = "draft"; + payloadData.campaignName = totalFormData?.HCM_CAMPAIGN_NAME?.campaignName; + if (totalFormData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData) { + payloadData.boundaries = totalFormData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData; + } + const temp = resourceData( + totalFormData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile?.[0], + totalFormData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile?.[0], + totalFormData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile?.[0] + ); + payloadData.resources = temp; + payloadData.projectType = totalFormData?.HCM_CAMPAIGN_TYPE?.projectType?.code; + payloadData.additionalDetails = { + beneficiaryType: totalFormData?.HCM_CAMPAIGN_TYPE?.projectType?.beneficiaryType, + key: currentKey, + }; + if (totalFormData?.HCM_CAMPAIGN_CYCLE_CONFIGURE?.cycleConfigure) { + payloadData.additionalDetails.cycleData = totalFormData?.HCM_CAMPAIGN_CYCLE_CONFIGURE?.cycleConfigure; + } + if (totalFormData?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule) { + const temp = restructureData(totalFormData?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule); + payloadData.deliveryRules = temp; + } + if (!payloadData?.startDate && !payloadData?.endDate) { + delete payloadData?.startDate; + delete payloadData?.endDate; + } + if (compareIdentical(draftData, payloadData) === false) { + await updateCampaign(payloadData, { + onError: (error, variables) => { + console.log(error); + if (filteredConfig?.[0]?.form?.[0]?.body?.[0]?.mandatoryOnAPI) { + setShowToast({ key: "error", label: error?.message ? error?.message : error }); + } + }, + onSuccess: async (data) => { + updateUrlParams({ id: data?.CampaignDetails?.id }); + draftRefetch(); + if (filteredConfig?.[0]?.form?.[0]?.body?.[0]?.mandatoryOnAPI) { + setCurrentKey(currentKey + 1); + } + }, + }); + } else { + setCurrentKey(currentKey + 1); + } + }; + + reqCreate(); + } + setShouldUpdate(false); + } + }, [shouldUpdate]); + + function validateCycleData(data) { + const { cycle, deliveries } = data?.cycleConfigure?.cycleConfgureDate; + const cycleData = data.cycleConfigure.cycleData; + + // Validate cycle and deliveries + if (cycle <= 0 || deliveries <= 0) { + return { error: true, message: "DELIVERY_CYCLE_EMPTY_ERROR" }; + } + + // Validate cycleData length + if (cycleData.length !== cycle) { + return { error: true, message: "DELIVERY_CYCLE_MISMATCH_LENGTH_ERROR" }; + } + + // Validate fromDate and startDate in cycleData + for (const item of cycleData) { + if (!item.fromDate || !item.toDate) { + return { error: true, message: "DELIVERY_CYCLE_DATE_ERROR" }; + } + } + + return false; + } + + function validateDeliveryRules(data) { + let isValid = true; + + // Iterate over deliveryRule array + data.deliveryRule.forEach((cycle) => { + cycle.deliveries.forEach((delivery) => { + delivery.deliveryRules.forEach((rule) => { + // Validate attributes and products length + if (rule.attributes.length === 0 || rule.products.length === 0) { + isValid = false; + return; + } + + rule.attributes.forEach((attribute) => { + // Check if attribute, operator, and value are empty + if (attribute.attribute === "" || attribute.operator === null || attribute.value === "") { + if (attribute?.operator?.code === "IN_BETWEEN" && attribute?.toValue !== "" && attribute?.fromValue !== "") { + isValid = true; + } else { + isValid = false; + } + } + }); + + rule.products.forEach((product) => { + // Check if count and value are empty + if (product.count === null || product.value === null) { + isValid = false; + } + }); + }); + }); + }); + + return isValid; + // ? "Delivery rules are valid" + // : "Attributes, operators, values, count, or value are not empty in delivery rules or attributes/products length is 0"; + } + + function checkAttributeValidity(data) { + for (const rule of data?.deliveryRule) { + for (const delivery of rule?.deliveries) { + for (const rule of delivery?.deliveryRules) { + for (const attribute of rule?.attributes) { + if ( + attribute?.operator && + attribute?.operator?.code === "IN_BETWEEN" && + attribute?.fromValue && + attribute?.toValue && + attribute?.fromValue !== "" && + attribute?.toValue !== "" && + Number(attribute?.toValue) >= Number(attribute?.fromValue) + ) { + // return `Error: Attribute "${attribute?.attribute?.code ? attribute?.attribute?.code : attribute?.attribute}" has invalid range (${ + // attribute.toValue + // } to ${attribute.fromValue})`; + return "CAMPAIGN_IN_BETWEEN_ERROR"; + } else if (attribute?.value === 0 || attribute?.value === "0") { + return "CAMPAIGN_VALUE_ZERO_ERROR"; + } + } + } + } + } + return false; + } + + // function validateBoundaryLevel(data) { + // // Extracting boundary types from hierarchy response + // const boundaryTypes = new Set(hierarchyDefinition?.BoundaryHierarchy?.[0]?.boundaryHierarchy.map((item) => item?.boundaryType)); + + // // Extracting unique boundary types from data + // const uniqueDataBoundaryTypes = new Set(data?.map((item) => item.type)); + + // // Checking if all unique boundary types from hierarchy response are present in data + // const allBoundaryTypesPresent = [...boundaryTypes].every((type) => uniqueDataBoundaryTypes.has(type)); + + // return allBoundaryTypesPresent; + // } + + function validateBoundaryLevel(data) { + // Extracting boundary hierarchy from hierarchy definition + const boundaryHierarchy = hierarchyDefinition?.BoundaryHierarchy?.[0]?.boundaryHierarchy || []; + + // Find the index of the lowest hierarchy + const lowestIndex = boundaryHierarchy.findIndex((item) => item?.boundaryType === lowestHierarchy); + + // Create a set of boundary types including only up to the lowest hierarchy + const boundaryTypes = new Set(boundaryHierarchy.filter((_, index) => index <= lowestIndex).map((item) => item?.boundaryType)); + + // Extracting unique boundary types from data + const uniqueDataBoundaryTypes = new Set(data?.map((item) => item.type)); + + // Checking if all boundary types from the filtered hierarchy are present in data + const allBoundaryTypesPresent = [...boundaryTypes].every((type) => uniqueDataBoundaryTypes.has(type)); + + return allBoundaryTypesPresent; + } + + // function recursiveParentFind(filteredData) { + // const parentChildrenMap = {}; + + // // Build the parent-children map + // filteredData?.forEach((item) => { + // if (item?.parent) { + // if (!parentChildrenMap[item?.parent]) { + // parentChildrenMap[item?.parent] = []; + // } + // parentChildrenMap[item?.parent].push(item.code); + // } + // }); + + // // Check for missing children + // const missingParents = filteredData?.filter((item) => item?.parent && !parentChildrenMap[item.code]); + // const extraParent = missingParents?.filter((i) => i?.type !== lowest?.[0]?.boundaryType); + + // return extraParent; + // } + + function recursiveParentFind(filteredData) { + const parentChildrenMap = {}; + + // Build the parent-children map + filteredData?.forEach((item) => { + if (item?.parent) { + if (!parentChildrenMap[item?.parent]) { + parentChildrenMap[item?.parent] = []; + } + parentChildrenMap[item?.parent].push(item.code); + } + }); + + // Check for missing children + const missingParents = filteredData?.filter((item) => item?.parent && !parentChildrenMap[item.code]); + const extraParent = missingParents?.filter((i) => i?.type !== lowestHierarchy); + + return extraParent; + } + + // validating the screen data on clicking next button + const handleValidate = (formData) => { + const key = Object.keys(formData)?.[0]; + switch (key) { + case "campaignName": + if (typeof formData?.campaignName !== "string" || !formData?.campaignName.trim()) { + setShowToast({ key: "error", label: "CAMPAIGN_NAME_MISSING_TYPE_ERROR" }); + return false; + } else if (formData.campaignName.length > 250) { + setShowToast({ key: "error", label: "CAMPAIGN_NAME_TOO_LONG_ERROR" }); + return false; + } else { + setShowToast(null); + return true; + } + case "projectType": + if (!formData?.projectType) { + setShowToast({ key: "error", label: "PROJECT_TYPE_UNDEFINED_ERROR" }); + return false; + } else { + setShowToast(null); + return true; + } + case "campaignDates": + const startDateObj = new Date(formData?.campaignDates?.startDate); + const endDateObj = new Date(formData?.campaignDates?.endDate); + if (!formData?.campaignDates?.startDate || !formData?.campaignDates?.endDate) { + setShowToast({ key: "error", label: `${t("HCM_CAMPAIGN_DATE_MISSING")}` }); + return false; + } else if (endDateObj.getTime() === startDateObj.getTime()) { + setShowToast({ key: "error", label: `${t("HCM_CAMPAIGN_END_DATE_EQUAL_START_DATE")}` }); + return false; + } else if (endDateObj.getTime() < startDateObj) { + setShowToast({ key: "error", label: `${t("HCM_CAMPAIGN_END_DATE_BEFORE_START_DATE")}` }); + return false; + } else { + setShowToast(null); + return true; + } + case "boundaryType": + if (formData?.boundaryType?.selectedData) { + const validateBoundary = validateBoundaryLevel(formData?.boundaryType?.selectedData); + const missedType = recursiveParentFind(formData?.boundaryType?.selectedData); + if (!validateBoundary) { + setShowToast({ key: "error", label: t("HCM_CAMPAIGN_ALL_THE_LEVELS_ARE_MANDATORY") }); + return false; + } else if (recursiveParentFind(formData?.boundaryType?.selectedData).length > 0) { + setShowToast({ + key: "error", + label: `${t(`HCM_CAMPAIGN_FOR`)} ${t(`${hierarchyType}_${missedType?.[0]?.type}`?.toUpperCase())} ${t(missedType?.[0]?.code)} ${t( + `HCM_CAMPAIGN_CHILD_NOT_PRESENT` + )}`, + }); + return false; + } + setShowToast(null); + setFetchUpload(true); + return true; + } else { + setShowToast({ key: "error", label: `${t("HCM_SELECT_BOUNDARY")}` }); + return false; + } + + case "uploadBoundary": + if (formData?.uploadBoundary?.isValidation) { + setShowToast({ key: "info", label: `${t("HCM_FILE_VALIDATION_PROGRESS")}`, transitionTime: 6000000000 }); + return false; + } else if (formData?.uploadBoundary?.isError) { + if (formData?.uploadBoundary?.apiError) { + setShowToast({ key: "error", label: formData?.uploadBoundary?.apiError, transitionTime: 6000000000 }); + } else setShowToast({ key: "error", label: `${t("HCM_FILE_VALIDATION")}` }); + return false; + } else { + setShowToast(null); + return true; + } + + case "uploadFacility": + if (formData?.uploadFacility?.isValidation) { + setShowToast({ key: "info", label: `${t("HCM_FILE_VALIDATION_PROGRESS")}`, transitionTime: 6000000000 }); + return false; + } else if (formData?.uploadFacility?.isError) { + if (formData?.uploadFacility?.apiError) { + setShowToast({ key: "error", label: formData?.uploadFacility?.apiError, transitionTime: 6000000000 }); + } else setShowToast({ key: "error", label: `${t("HCM_FILE_VALIDATION")}` }); + return false; + } else { + setShowToast(null); + return true; + } + case "uploadUser": + if (formData?.uploadUser?.isValidation) { + setShowToast({ key: "info", label: `${t("HCM_FILE_VALIDATION_PROGRESS")}`, transitionTime: 6000000000 }); + return false; + } else if (formData?.uploadUser?.isError) { + if (formData?.uploadUser?.apiError) { + setShowToast({ key: "error", label: formData?.uploadUser?.apiError, transitionTime: 6000000000 }); + } else setShowToast({ key: "error", label: `${t("HCM_FILE_VALIDATION")}` }); + return false; + } else { + setShowToast(null); + return true; + } + + case "cycleConfigure": + const cycleNumber = formData?.cycleConfigure?.cycleConfgureDate?.cycle; + const deliveryNumber = formData?.cycleConfigure?.cycleConfgureDate?.deliveries; + if (cycleNumber === "" || cycleNumber === 0 || deliveryNumber === "" || deliveryNumber === 0) { + setShowToast({ key: "error", label: "DELIVERY_CYCLE_ERROR" }); + return false; + } else { + setShowToast(null); + return true; + } + case "deliveryRule": + const isAttributeValid = checkAttributeValidity(formData); + if (isAttributeValid) { + setShowToast({ key: "error", label: isAttributeValid }); + return false; + } + setShowToast(null); + return; + case "summary": + const cycleConfigureData = totalFormData?.HCM_CAMPAIGN_CYCLE_CONFIGURE; + const isCycleError = validateCycleData(cycleConfigureData); + if (isCycleError?.error === true) { + setShowToast({ key: "error", label: isCycleError?.message }); + return false; + } + const deliveryCycleData = totalFormData?.HCM_CAMPAIGN_DELIVERY_DATA; + const isDeliveryError = validateDeliveryRules(deliveryCycleData); + const isTargetError = totalFormData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile?.[0]?.filestoreId ? false : true; + const isFacilityError = totalFormData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile?.[0]?.filestoreId ? false : true; + const isUserError = totalFormData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile?.[0]?.filestoreId ? false : true; + if (isDeliveryError === false) { + setShowToast({ key: "error", label: "DELIVERY_RULES_ERROR" }); + return false; + } + if (isTargetError) { + setShowToast({ key: "error", label: "TARGET_DETAILS_ERROR" }); + return false; + } + if (isFacilityError) { + setShowToast({ key: "error", label: "FACILITY_DETAILS_ERROR" }); + return false; + } + if (isUserError) { + setShowToast({ key: "error", label: "USER_DETAILS_ERROR" }); + return false; + } + setShowToast(null); + return true; + default: + break; + } + }; + + useEffect(() => { + if (showToast) { + setTimeout(closeToast, 10000); + } + }, [showToast]); + + const onSubmit = (formData, cc) => { + setIsSubmitting(true); + const checkValid = handleValidate(formData); + if (checkValid === false) { + return; + } + + const name = filteredConfig?.[0]?.form?.[0]?.name; + + if (name === "HCM_CAMPAIGN_TYPE" && totalFormData?.["HCM_CAMPAIGN_TYPE"]?.projectType?.code !== formData?.projectType?.code) { + setTotalFormData((prevData) => ({ + ...prevData, + [name]: formData, + ["HCM_CAMPAIGN_CYCLE_CONFIGURE"]: {}, + ["HCM_CAMPAIGN_DELIVERY_DATA"]: {}, + })); + //to set the data in the local storage + setParams({ + ...params, + [name]: { ...formData }, + ["HCM_CAMPAIGN_CYCLE_CONFIGURE"]: {}, + ["HCM_CAMPAIGN_DELIVERY_DATA"]: {}, + }); + } else if (name === "HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA" && formData?.boundaryType?.updateBoundary === true) { + setTotalFormData((prevData) => ({ + ...prevData, + [name]: formData, + ["HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA"]: {}, + ["HCM_CAMPAIGN_UPLOAD_FACILITY_DATA"]: {}, + ["HCM_CAMPAIGN_UPLOAD_USER_DATA"]: {}, + })); + //to set the data in the local storage + setParams({ + ...params, + [name]: { ...formData }, + ["HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA"]: {}, + ["HCM_CAMPAIGN_UPLOAD_FACILITY_DATA"]: {}, + ["HCM_CAMPAIGN_UPLOAD_USER_DATA"]: {}, + }); + } else { + setTotalFormData((prevData) => ({ + ...prevData, + [name]: formData, + })); + //to set the data in the local storage + setParams({ + ...params, + [name]: { ...formData }, + }); + } + + if ( + filteredConfig?.[0]?.form?.[0]?.isLast || + !filteredConfig[0].form[0].body[0].skipAPICall || + (filteredConfig[0].form[0].body[0].skipAPICall && id) + ) { + setShouldUpdate(true); + } + + if (!filteredConfig?.[0]?.form?.[0]?.isLast && !filteredConfig[0].form[0].body[0].mandatoryOnAPI) { + setCurrentKey(currentKey + 1); + } + if (isDraft === "true" && isSkip !== "false") { + updateUrlParams({ skip: "false" }); + } + return; + }; + + const onStepClick = (step) => { + if ((currentKey === 4 || currentKey === 5) && step > 1) { + return; + } + const filteredSteps = campaignConfig[0].form.filter((item) => item.stepCount === String(step + 1)); + + const key = parseInt(filteredSteps[0].key); + const name = filteredSteps[0].name; + + if (step === 6 && Object.keys(totalFormData).includes("HCM_CAMPAIGN_UPLOAD_USER_DATA")) { + setCurrentKey(10); + setCurrentStep(7); + } else if (step === 1 && totalFormData["HCM_CAMPAIGN_NAME"] && totalFormData["HCM_CAMPAIGN_DATE"]) { + setCurrentKey(4); + setCurrentStep(1); + } else if (!totalFormData["HCM_CAMPAIGN_NAME"] || !totalFormData["HCM_CAMPAIGN_DATE"]) { + // Do not set stepper and key + } else if (Object.keys(totalFormData).includes(name)) { + setCurrentKey(key); + setCurrentStep(step); + // Do not set stepper and key + } + }; + + const onSecondayActionClick = () => { + if (currentKey > 1) { + setShouldUpdate(false); + setCurrentKey(currentKey - 1); + } + }; + + // filtering the config on the basis of the screen or key + // const filteredConfig = campaignConfig + // .map((config) => { + // return { + // ...config, + // form: config?.form.filter((step) => parseInt(step.key) == currentKey), + // }; + // }) + // .filter((config) => config.form.length > 0); + + const filterCampaignConfig = (campaignConfig, currentKey) => { + return campaignConfig + .map((config) => { + return { + ...config, + form: config?.form.filter((step) => parseInt(step.key) === currentKey), + }; + }) + .filter((config) => config.form.length > 0); + }; + + const [filteredConfig, setFilteredConfig] = useState(filterCampaignConfig(campaignConfig, currentKey)); + + useEffect(() => { + setFilteredConfig(filterCampaignConfig(campaignConfig, currentKey)); + }, [campaignConfig, currentKey]); + + const config = filteredConfig?.[0]; + + // setting the current step when the key is changed on the basis of the config + useEffect(() => { + setCurrentStep(Number(filteredConfig?.[0]?.form?.[0]?.stepCount - 1)); + }, [currentKey, filteredConfig]); + + const closeToast = () => { + setShowToast(null); + }; + + if (isPreview === "true" && !draftData) { + return ; + } + + if (isDraft === "true" && !draftData) { + return ; + } + + return ( + + {noAction !== "false" && ( + + )} + { + return { + ...config, + body: config?.body.filter((a) => !a.hideInEmployee), + }; + })} + onSubmit={onSubmit} + showSecondaryLabel={currentKey > 1 ? true : false} + secondaryLabel={noAction === "false" ? null : t("HCM_BACK")} + actionClassName={"actionBarClass"} + className="setup-campaign" + cardClassName="setup-campaign-card" + noCardStyle={currentStep === 7 || currentStep === 0 ? false : true} + onSecondayActionClick={onSecondayActionClick} + label={noAction === "false" ? null : filteredConfig?.[0]?.form?.[0]?.isLast === true ? t("HCM_SUBMIT") : t("HCM_NEXT")} + /> + {showToast && ( + + )} + + ); +}; + +export default SetupCampaign; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/AddDeliverycontext.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/AddDeliverycontext.js new file mode 100644 index 00000000000..453e1fad4cb --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/AddDeliverycontext.js @@ -0,0 +1,766 @@ +import { + LabelFieldPair, + AddIcon, + CardLabel, + Dropdown, + // TextInput, + Button, + Card, + CardHeader, + Modal, + CloseSvg, +} from "@egovernments/digit-ui-react-components"; +import { SVG } from "@egovernments/digit-ui-react-components"; +import React, { Fragment, useContext, useEffect, useRef, useState } from "react"; +import { useTranslation } from "react-i18next"; +// import { attributeConfig } from "../../../configs/attributeConfig"; +// import { operatorConfig } from "../../../configs/operatorConfig"; +import RemoveableTagNew from "../../../components/RemovableTagNew"; +import AddProducts from "./AddProductscontext"; +import { CycleContext } from "."; +import { TextInput } from "@egovernments/digit-ui-components"; +import { PRIMARY_COLOR } from "../../../utils"; + +const DustbinIcon = () => ( + + + +); + +const makeSequential = (jsonArray, keyName) => { + return jsonArray.map((item, index) => ({ + ...item, + [keyName]: index + 1, + })); +}; + +const AddAttributeField = ({ + config, + deliveryRuleIndex, + delivery, + deliveryRules, + setDeliveryRules, + attribute, + setAttributes, + index, + onDelete, + attributeConfig, + operatorConfig, + genderConfig, +}) => { + const [val, setVal] = useState(""); + const [showAttribute, setShowAttribute] = useState(null); + const [showOperator, setShowOperator] = useState(null); + const [addedOption, setAddedOption] = useState(null); + const { t } = useTranslation(); + + useEffect(() => { + setAddedOption(delivery?.attributes?.map((i) => i?.attribute?.code)?.filter((i) => i)); + }, [delivery, deliveryRules]); + + const selectValue = (e) => { + let val = e.target.value; + val = val.replace(/[^\d.]/g, ""); + val = val.match(/^\d*\.?\d{0,2}/)[0] || ""; + // if (val.startsWith("-")) { + // val = val.slice(1); // Remove the negative sign + // } + if (isNaN(val) || [" ", "e", "E"].some((f) => val.includes(f))) { + val = val.slice(0, -1); + return; + } + // setAttributes((pre) => pre.map((item) => (item.key === attribute.key ? { ...item, value: e.target.value } : item))); + const updatedData = deliveryRules.map((item, index) => { + if (item.ruleKey === deliveryRuleIndex) { + item.attributes.find((i) => i.key === attribute.key).value = val; + } + return item; + }); + setDeliveryRules(updatedData); + }; + + const selectGender = (value) => { + // setAttributes((pre) => pre.map((item) => (item.key === attribute.key ? { ...item, value: e.target.value } : item))); + const updatedData = deliveryRules.map((item, index) => { + if (item.ruleKey === deliveryRuleIndex) { + item.attributes.find((i) => i.key === attribute.key).value = value?.code; + } + return item; + }); + setDeliveryRules(updatedData); + }; + + const selectToFromValue = (e, range) => { + let val = e.target.value; + val = val.replace(/[^\d.]/g, ""); + val = val.match(/^\d*\.?\d{0,2}/)[0] || ""; + // if (val.startsWith("-")) { + // val = val.slice(1); // Remove the negative sign + // } + + if (isNaN(val) || [" ", "e", "E"].some((f) => val.includes(f))) { + val = val.slice(0, -1); + return; + } + if (range === "to") { + const updatedData = deliveryRules.map((item, index) => { + if (item.ruleKey === deliveryRuleIndex) { + item.attributes.find((i) => i.key === attribute.key).toValue = val; + } + return item; + }); + setDeliveryRules(updatedData); + } else { + const updatedData = deliveryRules.map((item, index) => { + if (item.ruleKey === deliveryRuleIndex) { + item.attributes.find((i) => i.key === attribute.key).fromValue = val; + } + return item; + }); + setDeliveryRules(updatedData); + } + }; + + const selectAttribute = (value) => { + // setAttributes((pre) => pre.map((item) => (item.key === attribute.key ? { ...item, value: e.target.value } : item))); + const updatedData = deliveryRules.map((item, index) => { + if (item.ruleKey === deliveryRuleIndex) { + item.attributes.find((i) => i.key === attribute.key).attribute = value; + item.attributes.find((i) => i.key === attribute.key).value = ""; + item.attributes.find((i) => i.key === attribute.key).toValue = ""; + item.attributes.find((i) => i.key === attribute.key).fromValue = ""; + if (value.code === "Gender") { + item.attributes.find((i) => i.key === attribute.key).operator = { + code: "EQUAL_TO", + }; + } + } + return item; + }); + setShowAttribute(value); + setDeliveryRules(updatedData); + }; + + const selectOperator = (value) => { + // setAttributes((pre) => pre.map((item) => (item.key === attribute.key ? { ...item, value: e.target.value } : item))); + const updatedData = deliveryRules.map((item, index) => { + if (item.ruleKey === deliveryRuleIndex) { + item.attributes.find((i) => i.key === attribute.key).operator = value; + delete item.attributes.find((i) => i.key === attribute.key).toValue; + delete item.attributes.find((i) => i.key === attribute.key).fromValue; + } + return item; + }); + setShowOperator(value); + setDeliveryRules(updatedData); + }; + + return ( +
+ + + {t(`CAMPAIGN_ATTRIBUTE_LABEL`)} + + item?.code === attribute?.attribute?.code)} + disable={false} + isMandatory={true} + option={addedOption ? attributeConfig?.filter((item) => !addedOption.includes(item.code)) : attributeConfig} + select={(value) => selectAttribute(value)} + optionKey="i18nKey" + t={t} + /> + + + + {t(`CAMPAIGN_OPERATOR_LABEL`)} + + selectOperator(value)} + optionKey="code" + t={t} + /> + + + {attribute?.operator?.code === "IN_BETWEEN" ? ( +
+ + {t(`CAMPAIGN_FROM_LABEL`)} +
+
+ selectToFromValue(e, "to")} + disable={false} + /> +
+
+
+ + {t(`CAMPAIGN_TO_LABEL`)} +
+
+ selectToFromValue(e, "from")} + disable={false} + /> +
+
+
+
+ ) : ( + + {t(`CAMPAIGN_VALUE_LABEL`)} +
+ {attribute?.attribute?.code === "Gender" ? ( + selectGender(value)} + optionKey="code" + t={t} + /> + ) : ( + + )} +
+
+ )} + {delivery.attributes.length !== 1 && ( +
onDelete()} + style={{ + cursor: "pointer", + fontWeight: "600", + marginLeft: "1rem", + fontSize: "1rem", + color: PRIMARY_COLOR, + display: "flex", + gap: "0.5rem", + alignItems: "center", + marginTop: "1rem", + }} + > + + {t(`CAMPAIGN_DELETE_ROW_TEXT`)} +
+ )} +
+ ); +}; + +const AddCustomAttributeField = ({ + config, + deliveryRuleIndex, + delivery, + deliveryRules, + setDeliveryRules, + attribute, + setAttributes, + index, + onDelete, + operatorConfig, + genderConfig, +}) => { + const [val, setVal] = useState(""); + const [showAttribute, setShowAttribute] = useState(null); + const [showOperator, setShowOperator] = useState(null); + const [addedOption, setAddedOption] = useState(null); + const { t } = useTranslation(); + const { attrConfig } = useContext(CycleContext); + + useEffect(() => { + setAddedOption(delivery?.attributes?.map((i) => i?.attribute?.code)?.filter((i) => i)); + }, [delivery]); + + const selectValue = (e) => { + let val = e.target.value; + val = val.replace(/[^\d.]/g, ""); + val = val.match(/^\d*\.?\d{0,2}/)[0] || ""; + // if (val.startsWith("-")) { + // val = val.slice(1); // Remove the negative sign + // } + if (isNaN(val) || [" ", "e", "E"].some((f) => val.includes(f))) { + val = val.slice(0, -1); + } + // setAttributes((pre) => pre.map((item) => (item.key === attribute.key ? { ...item, value: e.target.value } : item))); + const updatedData = deliveryRules.map((item, index) => { + if (item.ruleKey === deliveryRuleIndex) { + item.attributes.find((i) => i.key === attribute.key).value = val; + } + return item; + }); + setDeliveryRules(updatedData); + }; + + const selectOperator = (value) => { + // setAttributes((pre) => pre.map((item) => (item.key === attribute.key ? { ...item, value: e.target.value } : item))); + const updatedData = deliveryRules.map((item, index) => { + if (item.ruleKey === deliveryRuleIndex) { + item.attributes.find((i) => i.key === attribute.key).operator = value; + } + return item; + }); + setShowOperator(value); + setDeliveryRules(updatedData); + }; + + const selectToFromValue = (e, range) => { + let val = e.target.value; + val = val.replace(/[^\d.]/g, ""); + val = val.match(/^\d*\.?\d{0,2}/)[0] || ""; + // if (val.startsWith("-")) { + // val = val.slice(1); // Remove the negative sign + // } + if (isNaN(val) || [" ", "e", "E"].some((f) => val.includes(f))) { + val = val.slice(0, -1); + return; + } + if (range === "to") { + const updatedData = deliveryRules.map((item, index) => { + if (item.ruleKey === deliveryRuleIndex) { + item.attributes.find((i) => i.key === attribute.key).toValue = val; + } + return item; + }); + setDeliveryRules(updatedData); + } else { + const updatedData = deliveryRules.map((item, index) => { + if (item.ruleKey === deliveryRuleIndex) { + item.attributes.find((i) => i.key === attribute.key).fromValue = val; + } + return item; + }); + setDeliveryRules(updatedData); + } + }; + + return ( +
+ + + {t(`CAMPAIGN_ATTRIBUTE_LABEL`)} + +
+ +
+ {/* !addedOption.includes(item.code)) : attributeConfig} + select={(value) => selectAttribute(value)} + optionKey="code" + t={t} + /> */} +
+ + + {t(`CAMPAIGN_OPERATOR_LABEL`)} + + selectOperator(value)} + optionKey="code" + t={t} + /> + + {attribute?.operator?.code === "IN_BETWEEN" ? ( +
+ + {t(`CAMPAIGN_FROM_LABEL`)} +
+
+ selectToFromValue(e, "to")} + disable={false} + /> +
+
+
+ + {t(`CAMPAIGN_TO_LABEL`)} +
+
+ selectToFromValue(e, "from")} + disable={false} + /> +
+
+
+
+ ) : ( + + {t(`CAMPAIGN_VALUE_LABEL`)} +
+ {attribute?.attribute?.code === "Gender" ? ( + selectGender(value)} + optionKey="code" + t={t} + /> + ) : ( + + )} +
+
+ )} +
+ ); +}; + +const AddAttributeWrapper = ({ targetedData, deliveryRuleIndex, delivery, deliveryRules, setDeliveryRules, index, key }) => { + const { campaignData, dispatchCampaignData, filteredDeliveryConfig } = useContext(CycleContext); + const { t } = useTranslation(); + const tenantId = Digit.ULBService.getCurrentTenantId(); + const { isLoading: attributeConfigLoading, data: attributeConfig } = Digit.Hooks.useCustomMDMS( + tenantId, + "HCM-ADMIN-CONSOLE", + [{ name: "attributeConfig" }], + { + select: (data) => { + return data?.["HCM-ADMIN-CONSOLE"]?.attributeConfig; + }, + } + ); + const { isLoading: operatorConfigLoading, data: operatorConfig } = Digit.Hooks.useCustomMDMS( + tenantId, + "HCM-ADMIN-CONSOLE", + [{ name: "operatorConfig" }], + { + select: (data) => { + return data?.["HCM-ADMIN-CONSOLE"]?.operatorConfig; + }, + } + ); + const { isLoading: genderConfigLoading, data: genderConfig } = Digit.Hooks.useCustomMDMS(tenantId, "common-masters", [{ name: "GenderType" }], { + select: (data) => { + return data?.["common-masters"]?.GenderType?.filter((i) => i.active !== false); + }, + }); + const [attributes, setAttributes] = useState([{ key: 1, deliveryRuleIndex, attribute: "", operator: "", value: "" }]); + const reviseIndexKeys = () => { + setAttributes((prev) => prev.map((unit, index) => ({ ...unit, key: index + 1 }))); + }; + + const addMoreAttribute = () => { + setDeliveryRules((prev) => + prev.map((item, index) => + index + 1 === deliveryRuleIndex + ? { + ...item, + attributes: [...item.attributes, { key: item.attributes.length + 1, attribute: "", operator: "", value: "" }], + } + : item + ) + ); + }; + + const deleteAttribute = (_, d) => { + // setAttributes((prev) => prev.filter((i) => i.key !== item.key)); + const newData = deliveryRules.map((item) => { + if (item.ruleKey === deliveryRuleIndex) { + // If ruleKey matches, remove the specified attribute from attributes array + const updatedAttributes = item.attributes.filter((attribute) => attribute.key !== _.key); + + // Reassign keys in sequential order + const updatedAttributesSequential = makeSequential(updatedAttributes, "key"); + + return { + ...item, + attributes: updatedAttributesSequential, + }; + } + return item; + }); + setDeliveryRules(newData); + }; + + return ( + + {filteredDeliveryConfig?.customAttribute && filteredDeliveryConfig?.projectType === "LLIN-mz" + ? delivery.attributes.map((item, index) => ( + deleteAttribute(item, deliveryRuleIndex)} + operatorConfig={operatorConfig} + genderConfig={genderConfig} + /> + )) + : delivery.attributes.map((item, index) => ( + deleteAttribute(item, deliveryRuleIndex)} + attributeConfig={attributeConfig} + operatorConfig={operatorConfig} + genderConfig={genderConfig} + /> + ))} + {!filteredDeliveryConfig?.attrAddDisable && delivery.attributes.length !== attributeConfig?.length && ( + + ))} + + ); +}; + +const TabContent = ({ activeSubTab, subTabCount = 3, onSubTabChange, project }) => { + const { campaignData, dispatchCampaignData } = useContext(CycleContext); + const { t } = useTranslation(); + + return ( + + +
+ {t(`CAMPAIGN_TAB_TEXT`)} + {t(`CAMPAIGN_TAB_SUB_TEXT_${project?.code ? project?.code?.toUpperCase() : project?.toUpperCase()}`)} +
+ {/* Add content specific to each tab as needed */} +
+ ); +}; + +const SubTabs = ({ onSubTabChange }) => { + const { campaignData, dispatchCampaignData } = useContext(CycleContext); + const { t } = useTranslation(); + + return ( +
+ {campaignData + .find((i) => i.active === true) + .deliveries.map((_, index) => ( + + ))} +
+ ); +}; + +const MultiTab = ({ tabCount = 3, subTabCount = 2 }) => { + const [activeTab, setActiveTab] = useState(0); + const [activeSubTab, setActiveSubTab] = useState(0); + const { campaignData, dispatchCampaignData } = useContext(CycleContext); + const { t } = useTranslation(); + const tempSession = Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA"); + const handleTabChange = (tabIndex, index) => { + dispatchCampaignData({ + type: "TAB_CHANGE_UPDATE", + payload: { tabIndex: tabIndex, index: index }, // Your updated campaign data + }); + setActiveTab(index); + setActiveSubTab(0); // Reset sub-tab when changing the main tab + }; + + const handleSubTabChange = (subTabIndex, itemIndex) => { + dispatchCampaignData({ + type: "SUBTAB_CHANGE_UPDATE", + payload: { subTabIndex: subTabIndex }, // Your updated campaign data + }); + }; + + return ( + <> +
+ {t( + `CAMPAIGN_PROJECT_${ + tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.code + ? tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.code?.toUpperCase() + : tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.toUpperCase() + }` + )} +
+ +
+
+ +
+ + +
+ + ); +}; + +export default MultiTab; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/index.js new file mode 100644 index 00000000000..4a6726fa6e3 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/index.js @@ -0,0 +1,519 @@ +import React, { createContext, useContext, useEffect, useReducer, useState } from "react"; +import MultiTab from "./MultiTabcontext"; +import { Loader } from "@egovernments/digit-ui-react-components"; +// import { deliveryConfig } from "../../../configs/deliveryConfig"; + +const CycleContext = createContext(); + +function makeSequential(jsonArray, keyName) { + return jsonArray.map((item, index) => ({ + ...item, + [keyName]: index + 1, + })); +} + +function DeliverySetup({ onSelect, config, formData, control, tabCount = 2, subTabCount = 3, ...props }) { + // Campaign Tab Skeleton function + const [cycleData, setCycleData] = useState(config?.customProps?.sessionData?.["HCM_CAMPAIGN_CYCLE_CONFIGURE"]?.cycleConfigure); + const saved = window.Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA")?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule; + const selectedProjectType = window.Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA")?.HCM_CAMPAIGN_TYPE?.projectType?.code; + const tenantId = Digit.ULBService.getCurrentTenantId(); + const { isLoading: deliveryConfigLoading, data: filteredDeliveryConfig } = Digit.Hooks.useCustomMDMS( + tenantId, + "HCM-ADMIN-CONSOLE", + [{ name: "deliveryConfig" }], + { + select: (data) => { + const temp = data?.["HCM-ADMIN-CONSOLE"]?.deliveryConfig; + return temp?.find((i) => i?.projectType === selectedProjectType); + // return deliveryConfig?.find((i) => i?.projectType === selectedProjectType); + }, + } + ); + // const [filteredDeliveryConfig, setFilteredDeliveryConfig] = useState(deliveryConfig?.find((i) => i?.projectType === selectedProjectType)); + // useEffect(() => { + // if (!deliveryConfigLoading) { + // const temp = deliveryConfig?.find((i) => i?.projectType === selectedProjectType); + // setFilteredDeliveryConfig(temp); + // } + // }, [deliveryConfigLoading, filteredDeliveryConfig]); + // const filteredDeliveryConfig = deliveryConfig.find((i) => i.projectType === selectedProjectType); + useEffect(() => { + setCycleData(config?.customProps?.sessionData?.["HCM_CAMPAIGN_CYCLE_CONFIGURE"]?.cycleConfigure); + }, [config?.customProps?.sessionData?.["HCM_CAMPAIGN_CYCLE_CONFIGURE"]?.cycleConfigure]); + + const generateTabsData = (tabs, subTabs) => { + if (!saved) { + return [...Array(tabs)].map((_, tabIndex) => ({ + cycleIndex: `${tabIndex + 1}`, + active: tabIndex === 0 ? true : false, + deliveries: [...Array(subTabs || 1)].map((_, subTabIndex) => ({ + deliveryIndex: `${subTabIndex + 1}`, + active: subTabIndex === 0 ? true : false, + deliveryRules: + filteredDeliveryConfig?.projectType === "LLIN-mz" + ? filteredDeliveryConfig?.deliveryConfig?.map((item, index) => { + return { + ruleKey: index + 1, + delivery: {}, + attributes: item?.attributeConfig + ? item?.attributeConfig?.map((i, c) => { + if (i?.operatorValue === "IN_BETWEEN") { + return { + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + toValue: i?.fromValue, + fromValue: i?.toValue, + }; + } + return { + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + value: i?.value, + }; + }) + : [{ key: 1, attribute: null, operator: null, value: "" }], + // products: [], + products: item?.productConfig + ? item?.productConfig?.map((i, c) => ({ + ...i, + })) + : [], + }; + }) + : filteredDeliveryConfig && filteredDeliveryConfig?.deliveryConfig?.[subTabIndex] + ? filteredDeliveryConfig?.deliveryConfig?.[subTabIndex]?.conditionConfig?.map((item, index) => { + if (item) { + return { + ruleKey: index + 1, + delivery: {}, + attributes: item?.attributeConfig + ? item?.attributeConfig?.map((i, c) => { + if (i?.operatorValue === "IN_BETWEEN") { + return { + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + toValue: i?.fromValue, + fromValue: i?.toValue, + }; + } + return { + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + value: i?.value, + }; + }) + : [{ key: 1, attribute: null, operator: null, value: "" }], + // products: [], + products: item?.productConfig + ? item?.productConfig?.map((i, c) => ({ + ...i, + })) + : [], + }; + } else { + return { + ruleKey: index + 1, + delivery: {}, + attributes: [{ key: 1, attribute: null, operator: null, value: "" }], + products: [], + }; + } + }) + : [ + { + ruleKey: 1, + delivery: {}, + attributes: + filteredDeliveryConfig && filteredDeliveryConfig?.attributeConfig + ? filteredDeliveryConfig?.attributeConfig?.map((i, c) => ({ + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + value: i?.value, + })) + : // : filteredDeliveryConfig?.projectType === "LLIN-mz" + // ? filteredDeliveryConfig?.attributeConfig?.map((i, c) => ({ key: c + 1, attribute: i.attrValue, operator: null, value: "" })) + [{ key: 1, attribute: null, operator: null, value: "" }], + products: [], + }, + ], + })), + })); + } + // if no change + if (saved && saved?.length == tabs && saved?.[0]?.deliveries?.length === subTabs) { + return [...saved]; + } + // if cycle number decrease + if (saved?.length > tabs) { + // const temp = saved; + saved.splice(tabs); + // return temp; + } + // if cycle number increase + if (tabs > saved?.length) { + // const temp = saved; + for (let i = saved.length + 1; i <= tabs; i++) { + const newIndex = i.toString(); + saved.push({ + cycleIndex: newIndex, + active: false, + deliveries: [...Array(subTabs || 1)].map((_, subTabIndex) => ({ + deliveryIndex: `${subTabIndex + 1}`, + active: subTabIndex === 0, + deliveryRules: + filteredDeliveryConfig?.projectType === "LLIN-mz" + ? filteredDeliveryConfig?.deliveryConfig?.map((item, index) => { + return { + ruleKey: index + 1, + delivery: {}, + attributes: item?.attributeConfig + ? item?.attributeConfig?.map((i, c) => { + if (i?.operatorValue === "IN_BETWEEN") { + return { + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + toValue: i?.fromValue, + fromValue: i?.toValue, + }; + } + return { + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + value: i?.value, + }; + }) + : [{ key: 1, attribute: null, operator: null, value: "" }], + // products: [], + products: item?.productConfig + ? item?.productConfig?.map((i, c) => ({ + ...i, + })) + : [], + }; + }) + : filteredDeliveryConfig && filteredDeliveryConfig?.deliveryConfig?.[subTabIndex]?.conditionConfig + ? filteredDeliveryConfig?.deliveryConfig?.[subTabIndex]?.conditionConfig?.map((item, index) => { + if (item) { + return { + ruleKey: index + 1, + delivery: {}, + attributes: item?.attributeConfig + ? item?.attributeConfig?.map((i, c) => { + if (i?.operatorValue === "IN_BETWEEN") { + return { + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + toValue: i?.fromValue, + fromValue: i?.toValue, + }; + } + return { + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + value: i?.value, + }; + }) + : [{ key: 1, attribute: null, operator: null, value: "" }], + // products: [], + products: item?.productConfig + ? item?.productConfig?.map((i, c) => ({ + ...i, + })) + : [], + }; + } else { + return { + ruleKey: index + 1, + delivery: {}, + attributes: [{ key: 1, attribute: null, operator: null, value: "" }], + products: [], + }; + } + }) + : [ + { + ruleKey: 1, + delivery: {}, + attributes: + // filteredDeliveryConfig?.projectType === "MR-DN" + // ? filteredDeliveryConfig?.attributeConfig?.map((i, c) => ({ + // key: c + 1, + // attribute: { code: i?.attrValue }, + // operator: { code: i?.operatorValue }, + // value: i?.value, + // })) + // : filteredDeliveryConfig?.projectType === "LLIN-mz" + // ? filteredDeliveryConfig?.attributeConfig?.map((i, c) => ({ + // key: c + 1, + // attribute: i.attrValue, + // operator: null, + // value: "", + // })) + // : + [{ key: 1, attribute: null, operator: null, value: "" }], + // products: [], + products: [], + }, + ], + })), + }); + } + // return temp; + } + // if delivery number decrease + + saved.forEach((cycle) => { + // Remove deliveries if there are more deliveries than the specified number + if (cycle.deliveries.length > subTabs) { + cycle.deliveries.splice(subTabs); + } + + // Add deliveries if there are fewer deliveries than the specified number + if (subTabs > cycle.deliveries.length) { + for (let i = cycle.deliveries.length + 1; i <= subTabs; i++) { + const newIndex = i.toString(); + cycle.deliveries.push({ + deliveryIndex: newIndex, + active: false, + deliveryRules: + filteredDeliveryConfig?.projectType === "LLIN-mz" + ? filteredDeliveryConfig?.deliveryConfig?.map((item, index) => { + return { + ruleKey: index + 1, + delivery: {}, + attributes: item?.attributeConfig + ? item?.attributeConfig?.map((i, c) => { + if (i?.operatorValue === "IN_BETWEEN") { + return { + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + toValue: i?.fromValue, + fromValue: i?.toValue, + }; + } + return { + key: c + 1, + attribute: { code: i?.attrValue }, + operator: { code: i?.operatorValue }, + value: i?.value, + }; + }) + : [{ key: 1, attribute: null, operator: null, value: "" }], + // products: [], + products: item?.productConfig + ? item?.productConfig?.map((i, c) => ({ + ...i, + })) + : [], + }; + }) + : [ + { + ruleKey: 1, + delivery: {}, + attributes: [{ key: 1, attribute: null, operator: null, value: "" }], + products: [], + }, + ], + }); + } + } + }); + + return saved; + // if delivery number increase + + //if no above case + }; + + // Reducer function + const campaignDataReducer = (state, action) => { + switch (action.type) { + case "GENERATE_CAMPAIGN_DATA": + return generateTabsData(action.cycle, action.deliveries); + case "UPDATE_CAMPAIGN_DATA": + const changeUpdate = state.map((i) => { + if (i.active) { + const activeDelivery = i.deliveries.find((j) => j.active === true); + if (activeDelivery) { + return { + ...i, + deliveries: i.deliveries.map((j) => ({ + ...j, + deliveryRules: j.active ? action.payload.currentDeliveryRules : j.deliveryRules, + })), + }; + } + } + return i; + }); + return changeUpdate; + case "TAB_CHANGE_UPDATE": + const temp = state.map((i) => ({ + ...i, + active: i.cycleIndex == action.payload.tabIndex ? true : false, + })); + return temp; + // return action.payload; + case "SUBTAB_CHANGE_UPDATE": + const tempSub = state.map((camp, index) => { + if (camp.active === true) { + return { + ...camp, + deliveries: camp.deliveries.map((deliver) => ({ + ...deliver, + active: deliver.deliveryIndex == action.payload.subTabIndex ? true : false, + })), + }; + } + return camp; + }); + return tempSub; + case "ADD_DELIVERY_RULE": + const updatedDeliveryRules = [ + ...action.payload.currentDeliveryRules, + { + ruleKey: action.payload.currentDeliveryRules.length + 1, + delivery: {}, + attributes: [{ key: 1, attribute: null, operator: null, value: "" }], + products: [], + }, + ]; + const updatedData = state.map((i) => { + if (i.active) { + const activeDelivery = i.deliveries.find((j) => j.active); + if (activeDelivery) { + return { + ...i, + deliveries: i.deliveries.map((j) => ({ + ...j, + deliveryRules: j.active ? updatedDeliveryRules : j.deliveryRules, + })), + }; + } + } + return i; + }); + return updatedData; + case "REMOVE_DELIVERY_RULE": + const updatedDeleted = state.map((i) => { + if (i.active) { + const activeDelivery = i.deliveries.find((j) => j.active); + const w = makeSequential( + activeDelivery.deliveryRules.filter((j) => j.ruleKey != action.payload.item.ruleKey), + "ruleKey" + ); + if (activeDelivery) { + return { + ...i, + deliveries: i.deliveries.map((j) => ({ + ...j, + deliveryRules: j.active ? w : j.deliveryRules, + })), + }; + } + } + return i; + }); + return updatedDeleted; + case "UPDATE_DELIVERY_RULE": + return action.payload; + case "ADD_ATTRIBUTE": + return action.payload; + case "REMOVE_ATTRIBUTE": + return action.payload; + case "UPDATE_ATTRIBUTE": + return action.payload; + case "ADD_PRODUCT": + const prodTemp = action.payload.productData.map((i) => ({ ...i, value: i?.value?.id, name: i?.value?.displayName })); + const updatedState = state.map((cycle) => { + if (cycle.active) { + const updatedDeliveries = cycle.deliveries.map((dd) => { + if (dd.active) { + const updatedRules = dd.deliveryRules.map((rule) => { + if (rule.ruleKey === action.payload.delivery.ruleKey) { + return { + ...rule, + products: [...rule.products, ...prodTemp], + }; + } + return rule; + }); + return { + ...dd, + deliveryRules: updatedRules, + }; + } + return dd; + }); + return { + ...cycle, + deliveries: updatedDeliveries, + }; + } + return cycle; + }); + return updatedState; + case "REMOVE_PRODUCT": + return action.payload; + case "UPDATE_PRODUCT": + return action.payload; + default: + return state; + } + }; + + const [campaignData, dispatchCampaignData] = useReducer( + campaignDataReducer, + generateTabsData(cycleData?.cycleConfgureDate?.cycle, cycleData?.cycleConfgureDate?.deliveries) + ); + const [executionCount, setExecutionCount] = useState(0); + + useEffect(() => { + dispatchCampaignData({ + type: "GENERATE_CAMPAIGN_DATA", + cycle: cycleData?.cycleConfgureDate?.cycle, + deliveries: cycleData?.cycleConfgureDate?.deliveries, + }); + }, [cycleData]); + + useEffect(() => { + onSelect("deliveryRule", campaignData); + }, [campaignData]); + + useEffect(() => { + if (executionCount < 5) { + onSelect("deliveryRule", campaignData); + setExecutionCount((prevCount) => prevCount + 1); + } + }); + + if (deliveryConfigLoading) { + return ; + } + return ( + + + + ); +} + +export default DeliverySetup; +export { CycleContext }; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/index.js new file mode 100644 index 00000000000..2353f85fc50 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/index.js @@ -0,0 +1,102 @@ +import React, { useEffect } from "react"; +import { Switch, useLocation } from "react-router-dom"; +import { useTranslation } from "react-i18next"; +import { PrivateRoute, AppContainer, BreadCrumb } from "@egovernments/digit-ui-react-components"; +// import CampaignHeader from "../../components/CampaignHeader"; +import SetupCampaign from "./SetupCampaign"; +import SelectingBoundaries from "../../components/SelectingBoundaries"; + +/** + * The CampaignBreadCrumb function generates breadcrumb navigation for a campaign setup page in a React + * application. + * @returns The CampaignBreadCrumb component is returning a BreadCrumb component with the specified + * crumbs array and spanStyle prop. The crumbs array contains two objects with path, content, and show + * properties for each breadcrumb item. The spanStyle prop is set to { maxWidth: "min-content" }. + */ +const CampaignBreadCrumb = ({ location, defaultPath }) => { + const { t } = useTranslation(); + const search = useLocation().search; + const pathVar = location.pathname.replace(defaultPath + "/", "").split("?")?.[0]; + + const crumbs = [ + { + path: `/${window?.contextPath}/employee`, + content: t("CAMPAIGN_HOME"), + show: true, + }, + { + path: pathVar === "my-campaign" ? "" : `/${window?.contextPath}/employee/campaign/my-campaign`, + content: t("MY_CAMPAIGN"), + show: pathVar === "my-campaign" ? true : false, + }, + { + path: pathVar === "setup-campaign" ? "" : `/${window?.contextPath}/employee/campaign/setup-campaign`, + content: t("CREATE_NEW_CAMPAIGN"), + show: pathVar === "setup-campaign" ? true : false, + }, + ]; + + return ; +}; + +/** + * The `App` function in JavaScript defines a component that handles different routes and renders + * corresponding components based on the path provided. + * @returns The `App` component is returning a JSX structure that includes a `div` with a className of + * "wbh-header-container" containing a `CampaignBreadCrumb` component and a `Switch` component. Inside + * the `Switch` component, there are several `PrivateRoute` components with different paths and + * corresponding components such as `UploadBoundaryData`, `CycleConfiguration`, `DeliveryRule`, ` + */ +const App = ({ path, BOUNDARY_HIERARCHY_TYPE }) => { + const location = useLocation(); + const UploadBoundaryData = Digit?.ComponentRegistryService?.getComponent("UploadBoundaryData"); + const CycleConfiguration = Digit?.ComponentRegistryService?.getComponent("CycleConfiguration"); + const DeliveryRule = Digit?.ComponentRegistryService?.getComponent("DeliveryRule"); + const MyCampaign = Digit?.ComponentRegistryService?.getComponent("MyCampaign"); + const CampaignSummary = Digit?.ComponentRegistryService?.getComponent("CampaignSummary"); + const Response = Digit?.ComponentRegistryService?.getComponent("Response"); + const AddProduct = Digit?.ComponentRegistryService?.getComponent("AddProduct"); + + useEffect(() => { + if (window.location.pathname !== "/workbench-ui/employee/campaign/setup-campaign") { + window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA"); + window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_UPLOAD_ID"); + } + if (window.location.pathname === "/workbench-ui/employee/campaign/response") { + window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA"); + window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_UPLOAD_ID"); + } + return () => { + if (window.location.pathname !== "/workbench-ui/employee/campaign/setup-campaign") { + window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA"); + window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_UPLOAD_ID"); + } + }; + }, []); + return ( + +
+ {window?.location?.pathname === "/workbench-ui/employee/campaign/add-product" || + window?.location?.pathname === "/workbench-ui/employee/campaign/response" ? null : ( + + )} + {/* */} +
+ + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + +
+ ); +}; + +export default App; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/TourSteps.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/TourSteps.js new file mode 100644 index 00000000000..5ab880c52cf --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/TourSteps.js @@ -0,0 +1,144 @@ +export const TourSteps = { + '/workbench-ui/employee/workbench/manage-master-data':[ + { + content: + 'Welcome to Manage Master Data screen. Here you can search and update any master data that is configured for the logged in user tenant', + target: '.manage-master-wrapper', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + }, + { + content: + 'Select any module name where the master is present', + target: '.wbh-mdms-module-name', + disableBeacon: true, + placement: 'center', + title:"Manage Master Data" + }, + + { + content: + 'Select any master name where the master is present', + target: '.wbh-mdms-master-name', + disableBeacon: true, + placement: 'center', + title:"Manage Master Data" + }, + ], + '/workbench-ui/employee/workbench/mdms-search-v2':[ + { + content: + 'Welcome to the master data search screen. Here you can search the master data added under this master', + target: '.search-wrapper', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + }, + { + content: + 'Select any field value and enter the text by which data can be filtered', + target: '.label-field-pair', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + }, + { + content: + 'Filter the master data by clicking on this search by selecting any field and exact value', + target: '.search-button-wrapper', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + }, + { + content: + 'To add new master data under this master click on the Add Master Data button', + target: '.mdms-add-btn', + disableBeacon: true, + placement: 'auto', + title:"Manage Master Data" + }, + + ], + '/workbench-ui/employee/workbench/mdms-add-v2':[ + { + content: + 'Welcome to the master data search screen. Here you can search the master data added under this master', + target: '.field-string', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + }, + { + content: + 'select the Reference master data', + target: '.form-select ', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + }, + { + content: + 'Fill all the details by clicking on the Add Master Data', + target: '.submit-bar', + disableBeacon: true, + placement: 'auto', + title:"Manage Master Data" + }, + + ], + '/workbench-ui/employee/workbench/mdms-view':[ + { + content: + 'Welcome to the master data search screen. Here you can search the master data added under this master', + target: '.action-bar-wrap', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + }, + { + content: + 'select the Reference master data', + target: '.menu-wrap', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + } + ], + '/workbench-ui/employee/workbench/localisation-search':[ + { + content: + 'Welcome to the master data search screen. Here you can search the master data added under this master', + target: '.search-wrapper', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + }, + { + content: + 'Select any field value and enter the text by which data can be filtered', + target: '.label-field-pair', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + }, + { + content: + 'Filter the master data by clicking on this search by selecting any field and exact value', + target: '.search-button-wrapper', + disableBeacon: true, + placement: 'bottom', + title:"Manage Master Data" + }, + { + content: + 'To add new master data under this master click on the Add Master Data button', + target: '.mdms-add-btn', + disableBeacon: true, + placement: 'auto', + title:"Manage Master Data" + }, + + ], +} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/downloadExcel.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/downloadExcel.js new file mode 100644 index 00000000000..978ea2bfd74 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/downloadExcel.js @@ -0,0 +1,46 @@ +import axios from "axios"; + +/* Fetching sheet as json object from the API , converting them into blob and downloading it. + * Way to use the function. Just import the funtion downloadExcelWithCustomName and pass the filestoreid and customName you want to download the file. + * Rest this function will take care for you and download it in your system. + * + * Eg. -> + * const handleDownload = (id, name) => { + * downloadExcelWithCustomName({fileStoreId: id, customName: name}); + * } + * + */ + +export const downloadExcelWithCustomName = ({ fileStoreId = null, customName = null }) => { + const downloadExcel = (blob, fileName) => { + const link = document.createElement("a"); + link.href = URL.createObjectURL(blob); + link.download = fileName + ".xlsx"; + document.body.append(link); + link.click(); + link.remove(); + setTimeout(() => URL.revokeObjectURL(link.href), 7000); + }; + + if (fileStoreId) { + axios + .get("/filestore/v1/files/id", { + responseType: "arraybuffer", + headers: { + "Content-Type": "application/json", + Accept: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + "auth-token": Digit.UserService.getUser()?.["access_token"], + }, + params: { + tenantId: Digit.ULBService.getCurrentTenantId(), + fileStoreId: fileStoreId, + }, + }) + .then(async (res) => { + downloadExcel( + new Blob([res.data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }), + customName ? customName : "download" + ); + }); + } +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/index.js new file mode 100644 index 00000000000..5e308bf82f7 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/index.js @@ -0,0 +1,6 @@ +import _ from "lodash"; +import { downloadExcelWithCustomName } from "./downloadExcel"; + +export default {}; +export { downloadExcelWithCustomName }; +export const PRIMARY_COLOR = "#C84C0E"; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/AttendanceActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/AttendanceActionModal.js new file mode 100644 index 00000000000..a2c50215207 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/AttendanceActionModal.js @@ -0,0 +1,133 @@ +import React, { useState, useEffect } from "react"; +import _ from "lodash"; +import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; +import { configAttendanceApproveModal, configAttendanceRejectModal, configAttendanceCheckModal } from "../config"; + + +const Heading = (props) => { + return

{props.label}

; +}; + +const Close = () => ( + + + + +); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); +}; + +const AttendanceActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode,applicationDetails,workflowDetails, saveAttendanceState}) => { + const [config, setConfig] = useState({}); + + const userUuid = Digit.UserService.getUser()?.info.uuid; + const { isLoading, data:employeeData } = Digit.Hooks.hrms.useHRMSSearch( + { uuids : userUuid }, tenantId + ); + + const empData = employeeData?.Employees[0] + const empDepartment = empData?.assignments?.[0].department + const empDesignation = empData?.assignments?.[0].designation + const empName = empData?.user?.name + + useEffect(() => { + const selectedAction = action?.action + switch(selectedAction) { + case "VERIFY": + submitBasedOnAction(action, 'Verify muster roll') + break; + case "REJECT": + setConfig( + configAttendanceRejectModal({ + t, + action, + empDepartment, + empDesignation, + empName + }) + ) + break; + case "APPROVE": + setConfig( + configAttendanceApproveModal({ + t, + action + }) + ) + break; + case "RESUBMIT": + submitBasedOnAction(action, 'Resubmit muster roll') + break; + case "SAVE": + submitBasedOnAction(action, 'Verify muster roll') + break; + default: + break + } + }, [employeeData]); + + function onSubmit (data) { + submitBasedOnAction(action, data?.comments) + } + + const submitBasedOnAction = (action, comments) => { + let musterRoll = { tenantId, id: applicationDetails?.applicationDetails?.[0]?.applicationData?.id} + let workflow = { action: action?.action, comments: (comments || `${action?.action} done`), assignees: [] } + + const selectedAction = action?.action + switch(selectedAction) { + case "SAVE": + musterRoll.individualEntries = saveAttendanceState?.updatePayload + workflow.action = 'VERIFY' + break; + case "RESUBMIT": + musterRoll.additionalDetails = { computeAttendance : true } + break; + default: + break; + } + const dataTobeSubmitted = {musterRoll, workflow} + submitAction(dataTobeSubmitted) + } + + const cardStyle = () => { + if(config.label.heading === "Processing Details") { + return { + "padding" : "0px" + } + } + return {} + } + + return action && config?.form ? ( + } + headerBarEnd={} + actionCancelLabel={t(config.label.cancel)} + actionCancelOnSubmit={closeModal} + actionSaveLabel={t(config.label.submit)} + actionSaveOnSubmit={() => {}} + formId="modal-action" + > + + + ) : ( + + ); +} + +export default AttendanceActionModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAActionModal.js new file mode 100644 index 00000000000..269bbefa1dd --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAActionModal.js @@ -0,0 +1,283 @@ +import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; +import React, { useState, useEffect } from "react"; +import { useQueryClient } from "react-query"; +import { configBPAApproverApplication } from "../config"; +import * as predefinedConfig from "../config"; + +const Heading = (props) => { + return

{props.label}

; +}; + +const Close = () => ( + + + + +); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); +}; + +const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationDetails, applicationData, businessService, moduleCode,workflowDetails }) => { + const mutation1 = Digit.Hooks.obps.useObpsAPI( + applicationData?.landInfo?.address?.city ? applicationData?.landInfo?.address?.city : tenantId, + false + ); + const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( + tenantId, + { + roles: workflowDetails?.data?.initialActionState?.nextActions?.filter(ele=>ele?.action==action?.action)?.[0]?.assigneeRoles?.map(role=>({code:role})), + isActive: true, + }, + { enabled: !action?.isTerminateState } + ); + + const queryClient = useQueryClient(); + const [config, setConfig] = useState({}); + const [defaultValues, setDefaultValues] = useState({}); + const [approvers, setApprovers] = useState([]); + const [selectedApprover, setSelectedApprover] = useState({}); + const [file, setFile] = useState(null); + const [uploadedFile, setUploadedFile] = useState(null); + const [error, setError] = useState(null); + const [selectedFinancialYear, setSelectedFinancialYear] = useState(null); + const mobileView = Digit.Utils.browser.isMobile() ? true : false; + + useEffect(() => { + setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); + }, [approverData]); + + function selectFile(e) { + setFile(e.target.files[0]); + } + + useEffect(() => { + (async () => { + setError(null); + if (file) { + const allowedFileTypesRegex = /(.*?)(jpg|jpeg|png|image|pdf)$/i + if (file.size >= 5242880) { + setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); + } else if (file?.type && !allowedFileTypesRegex.test(file?.type)) { + setError(t(`NOT_SUPPORTED_FILE_TYPE`)) + } else { + try { + const response = await Digit.UploadServices.Filestorage("OBPS", file, Digit.ULBService.getStateId() || tenantId?.split(".")[0]); + if (response?.data?.files?.length > 0) { + setUploadedFile(response?.data?.files[0]?.fileStoreId); + } else { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } catch (err) { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } + } + })(); + }, [file]); + + const getInspectionDocs = (docs) => { + let refinedDocs = []; + docs && docs.map((doc,ind) => { + refinedDocs.push({ + "documentType":(doc.documentType+"_"+doc.documentType.split("_")[1]).replaceAll("_","."), + "fileStoreId":doc.fileStoreId, + "fileStore":doc.fileStoreId, + "fileName":"", + "dropDownValues": { + "value": (doc.documentType+"_"+doc.documentType.split("_")[1]).replaceAll("_","."), + } + }) + }) + return refinedDocs; + } + + const getQuestion = (data) => { + let refinedQues = []; + var i; + for(i=0; i { + let formdata = [], inspectionOb = []; + + if (data?.additionalDetails?.fieldinspection_pending?.length > 0) { + inspectionOb = data?.additionalDetails?.fieldinspection_pending + } + + if(data.status == "FIELDINSPECTION_INPROGRESS") { + formdata = JSON.parse(sessionStorage.getItem("INSPECTION_DATA")); + formdata?.length > 0 && formdata.map((ob,ind) => { + inspectionOb.push({ + docs: getInspectionDocs(ob.Documents), + date: ob.InspectionDate, + questions: getQuestion(ob), + time: ob?.InspectionTime, + }) + }) + inspectionOb = inspectionOb.filter((ob) => ob.docs && ob.docs.length>0); + } else { + sessionStorage.removeItem("INSPECTION_DATA") + } + + let fieldinspection_pending = [ ...inspectionOb]; + return fieldinspection_pending; + } + + const getDocuments = (applicationData) => { + let documentsformdata = JSON.parse(sessionStorage.getItem("BPA_DOCUMENTS")); + let documentList = []; + documentsformdata.map(doc => { + if(doc?.uploadedDocuments?.[0]?.values?.length > 0) documentList = [...documentList, ...doc?.uploadedDocuments?.[0]?.values]; + if(doc?.newUploadedDocs?.length > 0) documentList = [...documentList, ...doc?.newUploadedDocs] + }); + return documentList; + } + + const getPendingApprovals = () => { + const approvals = Digit.SessionStorage.get("OBPS_APPROVAL_CHECKS"); + const newApprovals = Digit.SessionStorage.get("OBPS_NEW_APPROVALS"); + let result = approvals?.reduce((acc, approval) => approval?.checked ? acc.push(approval?.label) && acc : acc, []); + result = result?.concat(newApprovals !== null?newApprovals.filter(ob => ob.label !== "").map(approval => approval?.label):[]); + return result; + } + + function submit(data) { + let workflow = { action: action?.action, comments: data?.comments, businessService, moduleName: moduleCode }; + applicationData = { + ...applicationData, + documents: getDocuments(applicationData), + additionalDetails: {...applicationData?.additionalDetails, fieldinspection_pending:getfeildInspection(applicationData), pendingapproval: getPendingApprovals() }, + workflow:{ + action: action?.action, + comment: data?.comments?.length > 0 ? data?.comments : null, + comments: data?.comments?.length > 0 ? data?.comments : null, + assignee: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], + assignes: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], + varificationDocuments: uploadedFile + ? [ + { + documentType: action?.action + " DOC", + fileName: file?.name, + fileStoreId: uploadedFile, + }, + ] + : null, + }, + action: action?.action, + comment: data?.comments, + assignee: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], + wfDocuments: uploadedFile + ? [ + { + documentType: action?.action + " DOC", + fileName: file?.name, + fileStoreId: uploadedFile, + }, + ] + : null, + }; + + const nocDetails = applicationDetails?.nocData?.map(noc => { + const uploadedDocuments = Digit.SessionStorage.get(noc?.nocType) || []; + return { + Noc: { + ...noc, + documents: [ + ...(noc?.documents?noc?.documents:[]), + ...(uploadedDocuments?uploadedDocuments:[]) + ] + } + } + }) + + let nocData = []; + if (nocDetails) { + nocDetails.map(noc => { + if ( + noc?.Noc?.applicationStatus?.toUpperCase() != "APPROVED" && + noc?.Noc?.applicationStatus?.toUpperCase() != "AUTO_APPROVED" && + noc?.Noc?.applicationStatus?.toUpperCase() != "REJECTED" && + noc?.Noc?.applicationStatus?.toUpperCase() != "AUTO_REJECTED" && + noc?.Noc?.applicationStatus?.toUpperCase() != "VOIDED" + ) { + nocData.push(noc); + } + }) + } + + submitAction({ + BPA:applicationData + }, nocData?.length > 0 ? nocData : false, {isStakeholder: false, bpa: true}); + } + + + useEffect(() => { + if (action) { + setConfig( + configBPAApproverApplication({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + businessService, + assigneeLabel: "WF_ASSIGNEE_NAME_LABEL", + error + }) + ); + } + }, [action, approvers, selectedFinancialYear, uploadedFile, error]); + + return action && config.form ? ( + } + headerBarEnd={} + actionCancelLabel={t(config.label.cancel)} + actionCancelOnSubmit={closeModal} + actionSaveLabel={t(config.label.submit)} + actionSaveOnSubmit={() => { }} + formId="modal-action" + isOBPSFlow={true} + popupStyles={mobileView?{width:"720px"}:{}} + style={!mobileView?{minHeight: "45px", height: "auto", width:"107px",paddingLeft:"0px",paddingRight:"0px"}:{minHeight: "45px", height: "auto",width:"44%"}} + popupModuleMianStyles={mobileView?{paddingLeft:"5px"}: {}} + > + {PTALoading ? ( + + ) : ( + + )} + + ) : ( + + ); +}; + +export default ActionModal; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAREGActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAREGActionModal.js new file mode 100644 index 00000000000..dc0bfe07776 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAREGActionModal.js @@ -0,0 +1,153 @@ +import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; +import React, { useState, useEffect } from "react"; +import { configBPAREGApproverApplication } from "../config"; +import * as predefinedConfig from "../config"; + +const Heading = (props) => { + return

{props.label}

; +}; + +const Close = () => ( + + + + +); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); +}; + +const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode }) => { + const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( + tenantId, + { + roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), + isActive: true, + }, + { enabled: !action?.isTerminateState } + ); + + const [config, setConfig] = useState({}); + const [defaultValues, setDefaultValues] = useState({}); + const [approvers, setApprovers] = useState([]); + const [selectedApprover, setSelectedApprover] = useState({}); + const [file, setFile] = useState(null); + const [uploadedFile, setUploadedFile] = useState(null); + const [error, setError] = useState(null); + const mobileView = Digit.Utils.browser.isMobile() ? true : false; + + useEffect(() => { + setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); + }, [approverData]); + + function selectFile(e) { + setFile(e.target.files[0]); + } + + useEffect(() => { + (async () => { + setError(null); + if (file) { + const allowedFileTypesRegex = /(.*?)(jpg|jpeg|png|image|pdf)$/i + if (file.size >= 5242880) { + setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); + } else if (file?.type && !allowedFileTypesRegex.test(file?.type)) { + setError(t(`NOT_SUPPORTED_FILE_TYPE`)) + } else { + try { + const response = await Digit.UploadServices.Filestorage("OBPS", file, Digit.ULBService.getStateId() || tenantId?.split(".")[0]); + if (response?.data?.files?.length > 0) { + setUploadedFile(response?.data?.files[0]?.fileStoreId); + } else { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } catch (err) { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } + } + })(); + }, [file]); + + function submit(data) { + let workflow = { action: action?.action, comments: data?.comments, businessService, moduleName: moduleCode }; + applicationData = { + ...applicationData, + action: action?.action, + comment: data?.comments, + assignee: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], + wfDocuments: uploadedFile + ? [ + { + documentType: action?.action + " DOC", + fileName: file?.name, + fileStoreId: uploadedFile, + }, + ] + : null, + }; + submitAction({ + Licenses: [applicationData], + }, false, {isStakeholder: true, bpa: false}); + } + + useEffect(() => { + if (action) { + setConfig( + configBPAREGApproverApplication({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + businessService, + error + }) + ); + } + }, [action, approvers, uploadedFile, error]); + + return action && config.form ? ( + } + headerBarEnd={} + actionCancelLabel={t(config.label.cancel)} + actionCancelOnSubmit={closeModal} + actionSaveLabel={t(config.label.submit)} + actionSaveOnSubmit={() => { }} + formId="modal-action" + isOBPSFlow={true} + popupStyles={mobileView?{width:"720px"}:{}} + style={!mobileView?{height: "45px", width:"107px",paddingLeft:"0px",paddingRight:"0px"}:{height:"45px",width:"44%"}} + popupModuleMianStyles={mobileView?{paddingLeft:"5px"}: {}} + > + {PTALoading ? ( + + ) : ( + + )} + + ) : ( + + ); +}; + +export default ActionModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/ExpenditureActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/ExpenditureActionModal.js new file mode 100644 index 00000000000..95393b5ae05 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/ExpenditureActionModal.js @@ -0,0 +1,190 @@ +import { Loader, Modal, FormComposer, WorkflowModal } from "@egovernments/digit-ui-react-components"; +import React, { useState, useEffect, Fragment } from "react"; +import { configViewBillApproveModal, configViewBillRejectModal, configViewBillCheckModal } from "../config"; +import _ from "lodash"; + +const Heading = (props) => { + return

{props.label}

; +}; + +const Close = () => ( + + + + +); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); +}; + +const ExpenditureActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode,applicationDetails,workflowDetails }) => { + + let { loiNumber, estimateNumber } = Digit.Hooks.useQueryParams(); + const [config, setConfig] = useState({}); + const [defaultValues, setDefaultValues] = useState({}); + const [approvers, setApprovers] = useState([]); + const [selectedApprover, setSelectedApprover] = useState({}); + + const [department, setDepartment] = useState([]); + const [selectedDept,setSelectedDept] = useState({}) + + const [designation, setDesignation] = useState([]); + const [selectedDesignation,setSelectedDesignation] = useState({}) + + const mdmsConfig = { + moduleName: "common-masters", + department : { + masterName: "Department", + localePrefix: "COMMON_MASTERS_DEPARTMENT", + }, + designation : { + masterName: "Designation", + localePrefix: "COMMON_MASTERS_DESIGNATION", + } + } + + const { isLoading: mdmsLoading, data: mdmsData,isSuccess:mdmsSuccess } = Digit.Hooks.useCustomMDMS( + Digit.ULBService.getStateId(), + mdmsConfig?.moduleName, + [{name : mdmsConfig?.designation?.masterName}, {name : mdmsConfig?.department?.masterName}, {name : mdmsConfig?.rejectReasons?.masterName}], + { + select: (data) => { + let designationData = _.get(data, `${mdmsConfig?.moduleName}.${mdmsConfig?.designation?.masterName}`, []); + designationData = designationData.filter((opt) => opt?.active).map((opt) => ({ ...opt, name: `${mdmsConfig?.designation?.localePrefix}_${opt.code}` })); + designationData?.map(designation => {designation.i18nKey = designation?.name}) + + let departmentData = _.get(data, `${mdmsConfig?.moduleName}.${mdmsConfig?.department?.masterName}`, []); + departmentData = departmentData.filter((opt) => opt?.active).map((opt) => ({ ...opt, name: `${mdmsConfig?.department?.localePrefix}_${opt.code}` })); + departmentData?.map(department => { department.i18nKey = department?.name}) + + return {designationData, departmentData}; + }, + enabled: mdmsConfig?.moduleName ? true : false, + } + ); + useEffect(() => { + setDepartment(mdmsData?.departmentData) + setDesignation(mdmsData?.designationData) + }, [mdmsData]); + + + + const { isLoading: approverLoading, isError, error, data: employeeDatav1 } = Digit.Hooks.hrms.useHRMSSearch({ designations: selectedDesignation?.code, departments: selectedDept?.code, roles: action?.assigneeRoles?.toString(), isActive: true }, Digit.ULBService.getCurrentTenantId(), null, null, { enabled: action?.action === "CHECK" || action?.action === "TECHNICALSANCATION"}); + + + employeeDatav1?.Employees.map(emp => emp.nameOfEmp = emp?.user?.name || "NA") + + useEffect(() => { + setApprovers(employeeDatav1?.Employees?.length > 0 ? employeeDatav1?.Employees.filter(emp => emp?.nameOfEmp !== "NA") : []) + }, [employeeDatav1]) + + useEffect(() => { + + if(action?.action?.includes("CHECK")){ + setConfig( + configViewBillCheckModal({ + t, + action, + businessService, + approvers, + selectedApprover, + setSelectedApprover, + designation, + selectedDesignation, + setSelectedDesignation, + department, + selectedDept, + setSelectedDept, + approverLoading + }) + ) + }else if(action?.action?.includes("APPROVE")){ + setConfig( + configViewBillApproveModal({ + t, + action + }) + ) + } + else if(action?.action?.includes("REJECT")){ + setConfig( + configViewBillRejectModal({ + t, + action, + }) + ) + } + }, [approvers,designation,department]); + + const dummy_exp_response = { + CHECK : { + header: "Bill Forwarded Successfully", + id: "Bill/2021-22/09/0001", + info: "Bill ID", + message: "Bill has been successfully created and forwarded for approval.", + responseData:{}, + requestData:{}, + links : [] + }, + REJECT : { + header: "Bill Rejected Successfully", + id: "Bill/2021-22/09/0001", + info: "Bill ID", + message: "Bill has been Rejected.", + responseData:{}, + requestData:{}, + links : [] + }, + APPROVE : { + header: "Bill Approved Successfully", + id: "Bill/2021-22/09/0001", + info: "Bill ID", + message: "Bill has been approved", + responseData:{}, + requestData:{}, + links : [] + } + } + + + function submit (_data) { + const workflow = { + action: action?.action, + comment: _data?.comments, + response : dummy_exp_response, + type : "bills", + assignees: selectedApprover?.uuid ? [selectedApprover?.uuid] : undefined + } + submitAction({workflow}); + } + + const cardStyle = () => { + if(config.label.heading === "Processing Details") { + return { + "padding" : "0px" + } + } + return {} + } + + return ( + <> + { + action && config?.form ? + + : + mdmsLoading ? + : null + } + ) +} + +export default ExpenditureActionModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/FSMActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/FSMActionModal.js new file mode 100644 index 00000000000..af0e0e8e701 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/FSMActionModal.js @@ -0,0 +1,298 @@ +import { Loader, Modal, FormComposer, Toast } from "@egovernments/digit-ui-react-components"; +import React, { useState, useEffect } from "react"; +import { useQueryClient } from "react-query"; + +import { configAssignDso, configCompleteApplication, configReassignDSO, configAcceptDso, configRejectApplication } from "../config"; + +const Heading = (props) => { + return

{props.label}

; +}; + +const Close = () => ( + + + + +); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); +}; + +const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData }) => { + const { data: dsoData, isLoading: isDsoLoading, isSuccess: isDsoSuccess, error: dsoError } = Digit.Hooks.fsm.useDsoSearch(tenantId); + const { isLoading, isSuccess, isError, data: applicationData, error } = Digit.Hooks.fsm.useSearch( + tenantId, + { applicationNos: id }, + { + staleTime: Infinity, + select: (details) => { + let { additionalDetails } = details; + + const parseTillObject = (str) => { + if (typeof str === "object") return str; + else return parseTillObject(JSON.parse(str)); + }; + + additionalDetails = parseTillObject(additionalDetails); + return { ...details, additionalDetails }; + }, + } + ); + const client = useQueryClient(); + const stateCode = Digit.ULBService.getStateId(); + const { data: vehicleList, isLoading: isVehicleData, isSuccess: isVehicleDataLoaded } = Digit.Hooks.fsm.useMDMS( + stateCode, + "Vehicle", + "VehicleType", + { staleTime: Infinity } + ); + const [dsoList, setDsoList] = useState([]); + const [vehicleNoList, setVehicleNoList] = useState([]); + const [config, setConfig] = useState({}); + const [dso, setDSO] = useState(null); + const [vehicleNo, setVehicleNo] = useState(null); + const [vehicleMenu, setVehicleMenu] = useState([]); + const [vehicle, setVehicle] = useState(null); + const [defaultValues, setDefautValue] = useState({ + capacity: vehicle?.capacity, + wasteCollected: vehicle?.capacity, + }); + // const [toastError, setToastError] = useState(false); + const { data: Reason, isLoading: isReasonLoading } = Digit.Hooks.fsm.useMDMS(stateCode, "FSM", "Reason", { staleTime: Infinity }, [ + "ReassignReason", + "RejectionReason", + "DeclineReason", + "CancelReason", + ]); + + const [reassignReason, selectReassignReason] = useState(null); + const [rejectionReason, setRejectionReason] = useState(null); + const [declineReason, setDeclineReason] = useState(null); + const [cancelReason, selectCancelReason] = useState(null); + + const [formValve, setFormValve] = useState(false); + + useEffect(() => { + if (isSuccess && isVehicleDataLoaded) { + const [vehicle] = vehicleList.filter((item) => item.code === applicationData.vehicleType); + setVehicleMenu([vehicle]); + setVehicle(vehicle); + setDefautValue({ + capacity: vehicle?.capacity, + wasteCollected: vehicle?.capacity, + }); + } + }, [isVehicleDataLoaded, isSuccess]); + + useEffect(() => { + if (vehicle && isDsoSuccess) { + const dsoList = dsoData.filter((dso) => dso.vehicles.find((dsoVehicle) => dsoVehicle.type === vehicle.code)); + setDsoList(dsoList); + } + }, [vehicle, isDsoSuccess]); + + useEffect(() => { + if (isSuccess && isDsoSuccess && applicationData.dsoId) { + const [dso] = dsoData.filter((dso) => dso.id === applicationData.dsoId); + const vehicleNoList = dso.vehicles.filter((vehicle) => vehicle.type === applicationData.vehicleType); + setVehicleNoList(vehicleNoList); + } + }, [isSuccess, isDsoSuccess]); + + useEffect(() => { + reassignReason || (actionData && actionData[0] && actionData[0].comment?.length > 0) ? setFormValve(true) : setFormValve(false); + }, [reassignReason]); + + useEffect(() => { + setFormValve(rejectionReason ? true : false); + }, [rejectionReason]); + + useEffect(() => { + setFormValve(declineReason ? true : false); + }, [declineReason]); + + useEffect(() => { + setFormValve(cancelReason ? true : false); + }, [cancelReason]); + + function selectDSO(dsoDetails) { + setDSO(dsoDetails); + } + + function selectVehicleNo(vehicleNo) { + setVehicleNo(vehicleNo); + } + + function selectVehicle(value) { + setVehicle(value); + setDefautValue({ + capacity: value?.capacity, + wasteCollected: value?.capacity, + }); + } + + function addCommentToWorkflow(state, workflow, data) { + workflow.comments = data.comments ? state.code + "~" + data.comments : state.code; + } + + function submit(data) { + const workflow = { action: action }; + + if (dso) applicationData.dsoId = dso.id; + if (vehicleNo && action === "ACCEPT") applicationData.vehicleId = vehicleNo.id; + if (vehicleNo && action === "DSO_ACCEPT") applicationData.vehicleId = vehicleNo.id; + if (vehicle && action === "ASSIGN") applicationData.vehicleType = vehicle.code; + if (data.date) applicationData.possibleServiceDate = new Date(`${data.date}`).getTime(); + if (data.desluged) applicationData.completedOn = new Date(data.desluged).getTime(); + if (data.wasteCollected) applicationData.wasteCollected = data.wasteCollected; + if (reassignReason) addCommentToWorkflow(reassignReason, workflow, data); + if (rejectionReason) addCommentToWorkflow(rejectionReason, workflow, data); + if (declineReason) addCommentToWorkflow(declineReason, workflow, data); + if (cancelReason) addCommentToWorkflow(cancelReason, workflow, data); + + submitAction({ fsm: applicationData, workflow }); + } + useEffect(() => { + switch (action) { + case "DSO_ACCEPT": + case "ACCEPT": + setFormValve(vehicleNo ? true : false); + return setConfig( + configAcceptDso({ + t, + dsoData, + dso, + vehicle, + vehicleNo, + vehicleNoList, + selectVehicleNo, + action, + }) + ); + + case "ASSIGN": + case "GENERATE_DEMAND": + case "FSM_GENERATE_DEMAND": + setFormValve(dso && vehicle ? true : false); + return setConfig( + configAssignDso({ + t, + dsoData, + dso, + selectDSO, + vehicleMenu, + vehicle, + selectVehicle, + action, + }) + ); + case "REASSIGN": + case "REASSING": + case "FSM_REASSING": + dso && vehicle && (reassignReason || (actionData && actionData[0] && actionData[0].comment?.length > 0)) + ? setFormValve(true) + : setFormValve(false); + return setConfig( + configReassignDSO({ + t, + dsoData, + dso, + selectDSO, + vehicleMenu, + vehicle, + selectVehicle, + reassignReasonMenu: Reason?.ReassignReason, + reassignReason, + selectReassignReason, + action, + showReassignReason: actionData && actionData[0] && actionData[0].comment?.length > 0 ? false : true, + }) + ); + case "COMPLETE": + case "COMPLETED": + setFormValve(true); + return setConfig(configCompleteApplication({ t, vehicle, applicationCreatedTime: applicationData?.auditDetails?.createdTime, action })); + case "SUBMIT": + case "FSM_SUBMIT": + return history.push(`/${window?.contextPath}/employee/fsm/modify-application/` + applicationNumber); + case "DECLINE": + case "DSO_REJECT": + //declinereason + setFormValve(declineReason ? true : false); + return setConfig( + configRejectApplication({ + t, + rejectMenu: Reason?.DeclineReason, + setReason: setDeclineReason, + reason: declineReason, + action, + }) + ); + case "REJECT": + case "SENDBACK": + // rejectionReason + setFormValve(rejectionReason ? true : false); + return setConfig( + configRejectApplication({ + t, + rejectMenu: Reason?.RejectionReason, + setReason: setRejectionReason, + reason: rejectionReason, + action, + }) + ); + case "CANCEL": + ///cancellreason + setFormValve(cancelReason ? true : false); + return setConfig( + configRejectApplication({ + t, + rejectMenu: Reason?.CancelReason, + setReason: selectCancelReason, + reason: cancelReason, + action, + }) + ); + + case "PAY": + case "ADDITIONAL_PAY_REQUEST": + case "FSM_PAY": + return history.push(`/${window?.contextPath}/employee/payment/collect/FSM.TRIP_CHARGES/${applicationNumber}`); + default: + break; + } + }, [action, isDsoLoading, dso, vehicleMenu, rejectionReason, vehicleNo, vehicleNoList, Reason]); + + return action && config.form && !isDsoLoading && !isReasonLoading && isVehicleDataLoaded ? ( + } + headerBarEnd={} + actionCancelLabel={t(config.label.cancel)} + actionCancelOnSubmit={closeModal} + actionSaveLabel={t(config.label.submit)} + actionSaveOnSubmit={() => {}} + formId="modal-action" + isDisabled={!formValve} + > + + {/* {toastError && } */} + + ) : ( + + ); +}; + +export default ActionModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/NOCActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/NOCActionModal.js new file mode 100644 index 00000000000..09266ca1b7b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/NOCActionModal.js @@ -0,0 +1,169 @@ +import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; +import React, { useState, useEffect } from "react"; +import { useQueryClient } from "react-query"; +import { useHistory } from "react-router-dom"; +import { configNOCApproverApplication } from "../config"; +import * as predefinedConfig from "../config"; + +const Heading = (props) => { + return

{props.label}

; +}; + +const Close = () => ( + + + + +); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); +}; + +const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode }) => { + + const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( + tenantId, + { + roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), + isActive: true, + }, + { enabled: !action?.isTerminateState } + ); + + const queryClient = useQueryClient(); + const [config, setConfig] = useState({}); + const [defaultValues, setDefaultValues] = useState({}); + const [approvers, setApprovers] = useState([]); + const [selectedApprover, setSelectedApprover] = useState({}); + const [file, setFile] = useState(null); + const [uploadedFile, setUploadedFile] = useState(null); + const [error, setError] = useState(null); + const mobileView = Digit.Utils.browser.isMobile() ? true : false; + const history = useHistory(); + + useEffect(() => { + setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); + }, [approverData]); + + function selectFile(e) { + setFile(e.target.files[0]); + } + + useEffect(() => { + (async () => { + setError(null); + if (file) { + const allowedFileTypesRegex = /(.*?)(jpg|jpeg|png|image|pdf)$/i + if (file.size >= 5242880) { + setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); + } else if (file?.type && !allowedFileTypesRegex.test(file?.type)) { + setError(t(`NOT_SUPPORTED_FILE_TYPE`)) + } else { + try { + const response = await Digit.UploadServices.Filestorage("NOC", file, Digit.ULBService.getStateId() || tenantId?.split(".")[0]); + if (response?.data?.files?.length > 0) { + setUploadedFile(response?.data?.files[0]?.fileStoreId); + } else { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } catch (err) { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } + } + })(); + }, [file]); + + + function submit(data) { + let enteredDocs = JSON.parse(sessionStorage.getItem("NewNOCDocs")); + let newDocs = applicationData?.documents?.length > 0 ? [...applicationData?.documents] : []; + enteredDocs.map((d,index) => { + newDocs.push(d); + }) + applicationData = { + ...applicationData, + workflow:{ + action: action?.action, + comment: data?.comments ? data?.comments : null, + assignee: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], + documents: uploadedFile + ? [ + { + documentType: action?.action + " DOC", + fileName: file?.name, + fileStoreId: uploadedFile, + }, + ] + : null, + }, + documents: newDocs, + }; + + + submitAction({ + Noc: applicationData, + }, false, {isNoc: true}); + } + + useEffect(() => { + if (action) { + setConfig( + configNOCApproverApplication({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + businessService, + assigneeLabel: "WF_ASSIGNEE_NAME_LABEL", + error + }) + ); + } + }, [action, approvers, uploadedFile, error]); + + return action && config.form ? ( + } + headerBarEnd={} + actionCancelLabel={t(config.label.cancel)} + actionCancelOnSubmit={closeModal} + actionSaveLabel={t(config.label.submit)} + actionSaveOnSubmit={() => { }} + formId="modal-action" + isOBPSFlow={true} + popupStyles={mobileView?{width:"720px"}:{}} + style={!mobileView?{height: "45px", width:"107px",paddingLeft:"0px",paddingRight:"0px"}:{height:"45px",width:"44%"}} + popupModuleMianStyles={mobileView?{paddingLeft:"5px"}: {}} + > + {PTALoading ? ( + + ) : ( + + )} + + ) : ( + + ); +}; + +export default ActionModal; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/PTActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/PTActionModal.js new file mode 100644 index 00000000000..37b3d996177 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/PTActionModal.js @@ -0,0 +1,190 @@ +import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; +import React, { useState, useEffect } from "react"; + +import { configPTApproverApplication, configPTAssessProperty } from "../config"; +import * as predefinedConfig from "../config"; + +const Heading = (props) => { + return

{props.label}

; +}; + +const Close = () => ( + + + + +); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); +}; + +const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode }) => { + const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( + tenantId, + { + roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), + isActive: true, + }, + { enabled: !action?.isTerminateState } + ); + const { isLoading: financialYearsLoading, data: financialYearsData } = Digit.Hooks.pt.useMDMS( + tenantId, + businessService, + "FINANCIAL_YEARLS", + {}, + { + details: { + tenantId: Digit.ULBService.getStateId(), + moduleDetails: [{ moduleName: "egf-master", masterDetails: [{ name: "FinancialYear", filter: "[?(@.module == 'PT')]" }] }], + }, + } + ); + + const [config, setConfig] = useState({}); + const [defaultValues, setDefaultValues] = useState({}); + const [approvers, setApprovers] = useState([]); + const [selectedApprover, setSelectedApprover] = useState(null); + const [file, setFile] = useState(null); + const [uploadedFile, setUploadedFile] = useState(null); + const [error, setError] = useState(null); + const [financialYears, setFinancialYears] = useState([]); + const [selectedFinancialYear, setSelectedFinancialYear] = useState(null); + const [disableActionSubmit, setDisableActionSubmit] = useState(false); + + useEffect(() => { + if (financialYearsData && financialYearsData["egf-master"]) { + setFinancialYears(financialYearsData["egf-master"]?.["FinancialYear"]); + } + }, [financialYearsData]); + + useEffect(() => { + setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); + }, [approverData]); + + function selectFile(e) { + setFile(e.target.files[0]); + } + + useEffect(() => { + (async () => { + setError(null); + if (file) { + if (file.size >= 5242880) { + setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); + } else { + try { + const response = await Digit.UploadServices.Filestorage("PT", file, Digit.ULBService.getStateId()); + if (response?.data?.files?.length > 0) { + setUploadedFile(response?.data?.files[0]?.fileStoreId); + } else { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } catch (err) { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } + } + })(); + }, [file]); + + function submit(data) { + if (!action?.showFinancialYearsModal) { + let workflow = { action: action?.action, comment: data?.comments, businessService, moduleName: moduleCode }; + workflow["assignes"] = action?.isTerminateState || !selectedApprover ? [] : [selectedApprover]; + if (uploadedFile) + workflow["documents"] = [ + { + documentType: action?.action + " DOC", + fileName: file?.name, + fileStoreId: uploadedFile, + }, + ]; + + submitAction({ + Property: { + ...applicationData, + workflow, + }, + }); + } else { + submitAction({ + customFunctionToExecute: action?.customFunctionToExecute, + Assessment: { + financialYear: selectedFinancialYear?.name, + propertyId: applicationData?.propertyId, + tenantId, + source: applicationData?.source, + channel: applicationData?.channel, + assessmentDate: Date.now(), + }, + }); + } + } + + useEffect(() => { + if (action) { + if (action?.showFinancialYearsModal) { + setConfig( + configPTAssessProperty({ + t, + action, + financialYears, + selectedFinancialYear, + setSelectedFinancialYear, + }) + ); + } else { + setConfig( + configPTApproverApplication({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + businessService, + }) + ); + } + } + }, [action, approvers, financialYears, selectedFinancialYear, uploadedFile]); + + return action && config.form ? ( + } + headerBarEnd={} + actionCancelLabel={t(config.label.cancel)} + actionCancelOnSubmit={closeModal} + actionSaveLabel={t(config.label.submit)} + actionSaveOnSubmit={() => {}} + isDisabled={!action.showFinancialYearsModal ? PTALoading || (action?.docUploadRequired && !uploadedFile) : !selectedFinancialYear} + formId="modal-action" + > + {financialYearsLoading ? ( + + ) : ( + + )} + + ) : ( + + ); +}; + +export default ActionModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/TLActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/TLActionModal.js new file mode 100644 index 00000000000..f11658a987a --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/TLActionModal.js @@ -0,0 +1,166 @@ +import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; +import React, { useState, useEffect } from "react"; + +import { configTLApproverApplication } from "../config"; +import * as predefinedConfig from "../config"; + +const Heading = (props) => { + return

{props.label}

; +}; + +const Close = () => ( + + + + +); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); +}; + +const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode }) => { + const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( + tenantId, + { + roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), + isActive: true, + }, + { enabled: !action?.isTerminateState } + ); + const { isLoading: financialYearsLoading, data: financialYearsData } = Digit.Hooks.pt.useMDMS( + tenantId, + businessService, + "FINANCIAL_YEARLS", + {}, + { + details: { + tenantId: Digit.ULBService.getStateId(), + moduleDetails: [{ moduleName: "egf-master", masterDetails: [{ name: "FinancialYear", filter: "[?(@.module == 'TL')]" }] }], + }, + } + ); + + const [config, setConfig] = useState({}); + const [defaultValues, setDefaultValues] = useState({}); + const [approvers, setApprovers] = useState([]); + const [selectedApprover, setSelectedApprover] = useState({}); + const [file, setFile] = useState(null); + const [uploadedFile, setUploadedFile] = useState(null); + const [error, setError] = useState(null); + const [financialYears, setFinancialYears] = useState([]); + const [selectedFinancialYear, setSelectedFinancialYear] = useState(null); + + useEffect(() => { + if (financialYearsData && financialYearsData["egf-master"]) { + setFinancialYears(financialYearsData["egf-master"]?.["FinancialYear"]); + } + }, [financialYearsData]); + + useEffect(() => { + setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); + }, [approverData]); + + function selectFile(e) { + setFile(e.target.files[0]); + } + + useEffect(() => { + (async () => { + setError(null); + if (file) { + if (file.size >= 5242880) { + setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); + } else { + try { + const response = await Digit.UploadServices.Filestorage("PT", file, Digit.ULBService.getStateId()); + if (response?.data?.files?.length > 0) { + setUploadedFile(response?.data?.files[0]?.fileStoreId); + } else { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } catch (err) { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } + } + })(); + }, [file]); + + function submit(data) { + let workflow = { action: action?.action, comments: data?.comments, businessService, moduleName: moduleCode }; + applicationData = { + ...applicationData, + action: action?.action, + comment: data?.comments, + assignee: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], + // assignee: action?.isTerminateState ? [] : [selectedApprover?.uuid], + wfDocuments: uploadedFile + ? [ + { + documentType: action?.action + " DOC", + fileName: file?.name, + fileStoreId: uploadedFile, + }, + ] + : null, + }; + submitAction({ + Licenses: [applicationData], + }); + } + + useEffect(() => { + if (action) { + setConfig( + configTLApproverApplication({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + businessService, + }) + ); + } + }, [action, approvers, financialYears, selectedFinancialYear, uploadedFile]); + + return action && config.form ? ( + } + headerBarEnd={} + actionCancelLabel={t(config.label.cancel)} + actionCancelOnSubmit={closeModal} + actionSaveLabel={t(config.label.submit)} + actionSaveOnSubmit={() => {}} + // isDisabled={!action.showFinancialYearsModal ? PTALoading || (!action?.isTerminateState && !selectedApprover?.uuid) : !selectedFinancialYear} + formId="modal-action" + > + {financialYearsLoading ? ( + + ) : ( + + )} + + ) : ( + + ); +}; + +export default ActionModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WNSActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WNSActionModal.js new file mode 100644 index 00000000000..eb64a09804b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WNSActionModal.js @@ -0,0 +1,261 @@ +import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; +import React, { useState, useEffect } from "react"; +import { configWSApproverApplication, configWSDisConnectApplication } from "../config"; +import * as predefinedConfig from "../config"; +import cloneDeep from "lodash/cloneDeep"; + + +const Heading = (props) => { + return

{props.label}

; +}; + +const Close = () => ( + + + + +); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); +}; + +const convertDateToEpochNew = (dateString, dayStartOrEnd = "dayend") => { + //example input format : "2018-10-02" + try { + const parts = dateString.match(/(\d{4})-(\d{1,2})-(\d{1,2})/); + const DateObj = new Date(Date.UTC(parts[1], parts[3] - 1, parts[2])); + + DateObj.setMinutes(DateObj.getMinutes() + DateObj.getTimezoneOffset()); + if (dayStartOrEnd === "dayend") { + DateObj.setHours(DateObj.getHours() + 24); + DateObj.setSeconds(DateObj.getSeconds() - 1); + } + return DateObj.getTime(); + } catch (e) { + return dateString; + } +}; + +const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode }) => { + const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( + tenantId, + { + roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), + isActive: true, + }, + { enabled: !action?.isTerminateState } + ); + + const [config, setConfig] = useState({}); + const [defaultValues, setDefaultValues] = useState({}); + const [approvers, setApprovers] = useState([]); + const [selectedApprover, setSelectedApprover] = useState({}); + const [file, setFile] = useState(null); + const [uploadedFile, setUploadedFile] = useState(null); + const [error, setError] = useState(null); + + useEffect(() => { + setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); + }, [approverData]); + + function selectFile(e) { + setFile(e.target.files[0]); + } + + useEffect(() => { + (async () => { + setError(null); + if (file) { + const allowedFileTypesRegex = /(.*?)(jpg|jpeg|png|image|pdf)$/i + if (file.size >= 5242880) { + setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); + } else if (file?.type && !allowedFileTypesRegex.test(file?.type)) { + setError(t(`NOT_SUPPORTED_FILE_TYPE`)) + } else { + try { + const response = await Digit.UploadServices.Filestorage("WS", file, Digit.ULBService.getCurrentTenantId()); + if (response?.data?.files?.length > 0) { + setUploadedFile(response?.data?.files[0]?.fileStoreId); + } else { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } catch (err) { + console.error("Modal -> err ", err); + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } + } + })(); + }, [file]); + + function submit(data) { + if(applicationData?.isBillAmend){ + const comments = data?.comments ? data.comments : null + + const additionalDetails = { ...applicationData?.billAmendmentDetails?.additionalDetails, comments } + const amendment = { + ...applicationData?.billAmendmentDetails, + workflow:{ + businessId:applicationData?.billAmendmentDetails?.amendmentId, + action:action?.action, + tenantId:tenantId, + businessService:"BS.AMENDMENT", + moduleName:"BS" + }, + additionalDetails, + comment: data?.comments || "", + wfDocuments: uploadedFile + ? [ + { + documentType: action?.action + " DOC", + fileName: file?.name, + fileStoreId: uploadedFile, + }, + ] + : null, + processInstance: { + action: action?.action, + assignes: !selectedApprover?.uuid ? [] : [{ uuid: selectedApprover?.uuid }], + comment: data?.comments || "", + documents: uploadedFile + ? [ + { + documentType: action?.action + " DOC", + fileName: file?.name, + fileStoreId: uploadedFile, + }, + ] + : [] + } + } + //amendment?.additionalDetails?.comments = comments + submitAction({AmendmentUpdate:amendment}) + return + } + let workflow = { action: action?.action, comments: data?.comments, businessService, moduleName: moduleCode }; + applicationData = { + ...applicationData, + action: action?.action, + comment: data?.comments || "", + assignee: !selectedApprover?.uuid ? [] : [selectedApprover?.uuid], + assignes: !selectedApprover?.uuid ? [] : [{ uuid: selectedApprover?.uuid }], + wfDocuments: uploadedFile + ? [ + { + documentType: action?.action + " DOC", + fileName: file?.name, + fileStoreId: uploadedFile, + }, + ] + : null, + processInstance: { + ...applicationData?.processInstance, + action: action?.action, + assignes: !selectedApprover?.uuid ? [] : [{ uuid: selectedApprover?.uuid }], + comment: data?.comments || "", + documents: uploadedFile + ? [ + { + documentType: action?.action + " DOC", + fileName: file?.name, + fileStoreId: uploadedFile, + }, + ] + : [] + } + }; + + if (data?.date) { + const connectionExecutionDate = cloneDeep(data?.date); + applicationData.connectionExecutionDate = convertDateToEpochNew(connectionExecutionDate) + } + if (applicationData?.processInstance?.businessService == "DisconnectWSConnection" || applicationData?.processInstance?.businessService == "DisconnectSWConnection"){ + applicationData?.serviceType == "WATER" ? + submitAction({ WaterConnection: applicationData, disconnectRequest: true }) : + submitAction({ SewerageConnection: applicationData, disconnectRequest: true }) + } else { + const adhocRebateData = sessionStorage.getItem("Digit.ADHOC_ADD_REBATE_DATA"); + const parsedAdhocRebateData = adhocRebateData ? JSON.parse(adhocRebateData) : ""; + if (parsedAdhocRebateData?.value?.adhocPenalty) applicationData.additionalDetails.adhocPenalty = parseInt(parsedAdhocRebateData?.value?.adhocPenalty) || ""; + if (parsedAdhocRebateData?.value?.adhocPenaltyComment) applicationData.additionalDetails.adhocPenaltyComment = parsedAdhocRebateData?.value?.adhocPenaltyComment || ""; + if (parsedAdhocRebateData?.value?.adhocPenaltyReason) applicationData.additionalDetails.adhocPenaltyReason = parsedAdhocRebateData?.value?.adhocPenaltyReason || ""; + if (parsedAdhocRebateData?.value?.adhocRebate) applicationData.additionalDetails.adhocRebate = parseInt(parsedAdhocRebateData?.value?.adhocRebate) || ""; + if (parsedAdhocRebateData?.value?.adhocRebateComment) applicationData.additionalDetails.adhocRebateComment = parsedAdhocRebateData?.value?.adhocRebateComment || ""; + if (parsedAdhocRebateData?.value?.adhocRebateReason) applicationData.additionalDetails.adhocRebateReason = parsedAdhocRebateData?.value?.adhocRebateReason || ""; + applicationData?.serviceType == "WATER" ? submitAction({ WaterConnection: applicationData }) : submitAction({ SewerageConnection: applicationData }); + } + } + + useEffect(() => { + if (applicationData?.processInstance?.businessService == "DisconnectWSConnection" || applicationData?.processInstance?.businessService == "DisconnectSWConnection") { + if (action) { + setConfig( + configWSDisConnectApplication({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + businessService, + error + }) + ); + } + } else { + if (action) { + setConfig( + configWSApproverApplication({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + businessService, + error + }) + ); + } + } + }, [action, approvers, uploadedFile, error]); + + return action && config.form ? ( + } + headerBarEnd={} + actionCancelLabel={t(config.label.cancel)} + actionCancelOnSubmit={closeModal} + actionSaveLabel={t(config.label.submit)} + actionSaveOnSubmit={() => { }} + formId="modal-action" + > + {PTALoading ? ( + + ) : ( + + )} + + ) : ( + + ); +}; + +export default ActionModal; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WorksActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WorksActionModal.js new file mode 100644 index 00000000000..dd19cf33a1e --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WorksActionModal.js @@ -0,0 +1,262 @@ +import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; +import React, { useState, useEffect } from "react"; +import { configApproveModal, configRejectModal, configCheckModal } from "../config"; + +import cloneDeep from "lodash/cloneDeep"; + + +const Heading = (props) => { + return

{props.label}

; +}; + +const Close = () => ( + + + + +); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); +}; + +const convertDateToEpochNew = (dateString, dayStartOrEnd = "dayend") => { + //example input format : "2018-10-02" + try { + const parts = dateString.match(/(\d{4})-(\d{1,2})-(\d{1,2})/); + const DateObj = new Date(Date.UTC(parts[1], parts[3] - 1, parts[2])); + + DateObj.setMinutes(DateObj.getMinutes() + DateObj.getTimezoneOffset()); + if (dayStartOrEnd === "dayend") { + DateObj.setHours(DateObj.getHours() + 24); + DateObj.setSeconds(DateObj.getSeconds() - 1); + } + return DateObj.getTime(); + } catch (e) { + return dateString; + } +}; + + +const WorksActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode,applicationDetails,workflowDetails }) => { + //here according to the action selected render appropriate modal + + // const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( + // tenantId, + // { + // roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), + // isActive: true, + // }, + // { enabled: !action?.isTerminateState } + // ); + let { loiNumber, estimateNumber } = Digit.Hooks.useQueryParams(); + const [config, setConfig] = useState({}); + const [approvers, setApprovers] = useState([]); + const [selectedApprover, setSelectedApprover] = useState({}); + + const [department, setDepartment] = useState([]); + const [selectedDept,setSelectedDept] = useState({}) + + const [rejectionReason, setRejectionReason] = useState([]); + const [selectedReason,setSelectedReason] = useState([]) + + const [designation, setDesignation] = useState([]); + const [selectedDesignation,setSelectedDesignation] = useState({}) + + //get approverDept,designation,approver(hrms),rejectionReason + + const rejectReasons = [ + { + name: "Estimate Details are incorrect" + }, + { + name: "Financial Details are incorrect" + }, + { + name: "Agreement Details are incorrect" + }, + { + name: "Vendor Details are incorrect" + }, + { + name: "Attachments provided are wrong" + }, + { + name: "Others" + }, + ] + + const { isLoading: mdmsLoading, data: mdmsData,isSuccess:mdmsSuccess } = Digit.Hooks.useCustomMDMS( + Digit.ULBService.getCurrentTenantId(), + "common-masters", + [ + { + "name": "Designation" + }, + { + "name": "Department" + } + ] + ); + + mdmsData?.["common-masters"]?.Designation?.map(designation => { + designation.i18nKey = `ES_COMMON_DESIGNATION_${designation?.name}` + }) + + mdmsData?.["common-masters"]?.Department?.map(department => { + department.i18nKey = `ES_COMMON_${department?.code}` + }) + // const { data: approverData, isLoading: approverLoading } = Digit.Hooks.useEmployeeSearch( + // tenantId, + // { + // roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), + // isActive: true, + // }, + // { enabled: !action?.isTerminateState } + // ); + + + // const { isLoading: approverLoading, isError,isSuccess:approverSuccess, error, data: employeeDatav1 } = Digit.Hooks.hrms.useHRMSSearch({ Designation: selectedDesignation?.code, Department: selectedDept?.code }, Digit.ULBService.getCurrentTenantId(), null, null, { enabled: !!(selectedDept?.code && selectedDesignation?.code) }); + // employeeDatav1?.Employees.map(emp => emp.nameOfEmp = emp.user.name) + + + // useEffect(() => { + + // setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); + // }, [approverData]); + + useEffect(() => { + + //setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); + //setApprovers(employeeDatav1?.Employees?.length > 0 ? employeeDatav1?.Employees : []) + setDepartment(mdmsData?.["common-masters"]?.Department) + setDesignation(mdmsData?.["common-masters"]?.Designation) + setRejectionReason(rejectReasons) + }, [mdmsData]); + + + + const { isLoading: approverLoading, isError, error, data: employeeDatav1 } = Digit.Hooks.hrms.useHRMSSearch({ designations: selectedDesignation?.code, departments: selectedDept?.code, roles: action?.assigneeRoles?.toString(), isActive: true }, Digit.ULBService.getCurrentTenantId(), null, null, { enabled: action?.action === "CHECK" || action?.action === "TECHNICALSANCATION"}); + + + employeeDatav1?.Employees.map(emp => emp.nameOfEmp = emp?.user?.name || "NA") + + useEffect(() => { + setApprovers(employeeDatav1?.Employees?.length > 0 ? employeeDatav1?.Employees.filter(emp => emp?.nameOfEmp !== "NA") : []) + }, [employeeDatav1]) + + + // if (employeeDatav1?.Employees?.length > 0) { + // setApprovers(employeeDatav1?.Employees) + // } + + useEffect(() => { + + if(action?.action?.includes("CHECK") || action?.action?.includes("TECHNICALSANCATION")){ + setConfig( + configCheckModal({ + t, + action, + businessService, + approvers, + selectedApprover, + setSelectedApprover, + designation, + selectedDesignation, + setSelectedDesignation, + department, + selectedDept, + setSelectedDept, + approverLoading + }) + ) + }else if(action?.action?.includes("APPROVE") || action?.action?.includes("ADMINSANCTION")){ + setConfig( + configApproveModal({ + t, + action + }) + ) + } + else if(action?.action?.includes("REJECT")){ + setConfig( + configRejectModal({ + t, + action, + rejectReasons, + selectedReason, + setSelectedReason, + loiNumber, + department, + estimateNumber + }) + ) + } + }, [approvers,designation,department]); + + + function submit (_data) { + //make the update object here and call submitAction + //if the action is reject then you need to make a search call and get creater's uuid + const workflow = { + action: action?.action, + comment: _data?.comments, + assignees: selectedApprover?.uuid ? [selectedApprover?.uuid] : undefined + } + + if(action?.action.includes("REJECT")) { + workflow.assignee = [applicationData?.auditDetails?.createdBy] + } + + Object.keys(workflow).forEach(key => { + if (workflow[key] === undefined) { + delete workflow[key]; + } + }); + {estimateNumber ? submitAction({estimate:applicationData,workflow}) : + submitAction({letterOfIndent:applicationData,workflow})} + + } + + // if(mdmsLoading || approverLoading ) { + // return + // } + + + + + + return action && config?.form ? ( + } + headerBarEnd={} + actionCancelLabel={t(config.label.cancel)} + actionCancelOnSubmit={closeModal} + actionSaveLabel={t(config.label.submit)} + actionSaveOnSubmit={() => { }} + formId="modal-action" + > + {mdmsLoading ? ( + + ) : ( + + )} + + ) : ( + + ); +} + +export default WorksActionModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/index.js new file mode 100644 index 00000000000..56465790b8b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/index.js @@ -0,0 +1,49 @@ +import React, { useState, useEffect } from "react"; +import FSMActionModal from "./FSMActionModal"; +import PTActionModal from "./PTActionModal"; +import TLActionModal from "./TLActionModal"; +import BPAREGActionModal from "./BPAREGActionModal"; +import BPAActionModal from "./BPAActionModal"; +import NOCActionModal from "./NOCActionModal"; +import WNSActionModal from "./WNSActionModal"; +import WorksActionModal from "./WorksActionModal"; +import AttendanceActionModal from "./AttendanceActionModal"; +import ExpenditureActionModal from "./ExpenditureActionModal"; + +const ActionModal = (props) => { + if (props?.businessService.includes("PT")) { + return ; + } + + if (props?.businessService.includes("NewTL") || props?.businessService.includes("TL") || props?.businessService.includes("EDITRENEWAL") || props?.businessService.includes("DIRECTRENEWAL")) { + return ; + } + + if (props?.moduleCode.includes("BPAREG")) { + return ; + } + + if (props?.moduleCode.includes("BPA")) { + return ; + } + + if (props?.moduleCode.includes("NOC")) { + return ; + } + + if (props?.moduleCode.includes("WS")) { + return ; + } + if (props?.moduleCode.includes("works")) { + return ; + } + if (props?.moduleCode.includes("AttendenceMgmt")) { + return ; + } + if (props?.moduleCode.includes("Expenditure")) { + return ; + } + +}; + +export default ActionModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsActionBar.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsActionBar.js new file mode 100644 index 00000000000..7ad3a0f95ce --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsActionBar.js @@ -0,0 +1,80 @@ +import React, {useEffect, useRef} from "react"; +import { useTranslation } from "react-i18next"; +import { SubmitBar, ActionBar, Menu } from "@egovernments/digit-ui-react-components"; + +function ApplicationDetailsActionBar({ workflowDetails, displayMenu, onActionSelect, setDisplayMenu, businessService, forcedActionPrefix,ActionBarStyle={},MenuStyle={}, saveAttendanceState }) { + const { t } = useTranslation(); + let user = Digit.UserService.getUser(); + const menuRef = useRef(); + if (window.location.href.includes("/obps") || window.location.href.includes("/noc")) { + const userInfos = sessionStorage.getItem("Digit.citizen.userRequestObject"); + const userInfo = userInfos ? JSON.parse(userInfos) : {}; + user = userInfo?.value; + } + const userRoles = user?.info?.roles?.map((e) => e.code); + let isSingleButton = false; + let isMenuBotton = false; + let actions = workflowDetails?.data?.actionState?.nextActions?.filter((e) => { + return userRoles.some((role) => e.roles?.includes(role)) || !e.roles; + }) || workflowDetails?.data?.nextActions?.filter((e) => { + return userRoles.some((role) => e.roles?.includes(role)) || !e.roles; + }); + + const closeMenu = () => { + setDisplayMenu(false); + } + Digit.Hooks.useClickOutside(menuRef, closeMenu, displayMenu ); + + if (((window.location.href.includes("/obps") || window.location.href.includes("/noc")) && actions?.length == 1) || (actions?.[0]?.redirectionUrl?.pathname.includes("/pt/property-details/")) && actions?.length == 1) { + isMenuBotton = false; + isSingleButton = true; + } else if (actions?.length > 0) { + isMenuBotton = true; + isSingleButton = false; + } + + if(saveAttendanceState?.displaySave) { + isMenuBotton = false; + isSingleButton = true; + actions = [ + { + action: "SAVE", + state: "UPDATED" + } + ] + } + + return ( + + {!workflowDetails?.isLoading && isMenuBotton && !isSingleButton && ( + + {displayMenu && (workflowDetails?.data?.actionState?.nextActions || workflowDetails?.data?.nextActions) ? ( + + ) : null} + setDisplayMenu(!displayMenu)} /> + + )} + {!workflowDetails?.isLoading && !isMenuBotton && isSingleButton && ( + + + + )} + + ); +} + +export default ApplicationDetailsActionBar; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsContent.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsContent.js new file mode 100644 index 00000000000..5596d7b694b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsContent.js @@ -0,0 +1,484 @@ +import { + BreakLine, + Card, + CardSectionHeader, + CardSubHeader, + CheckPoint, + CollapseAndExpandGroups, + ConnectingCheckPoints, + ViewImages, + Loader, + Row, + StatusTable, + Table, +} from "@egovernments/digit-ui-react-components"; +import { values } from "lodash"; +import React, { Fragment, useCallback, useReducer, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { Link } from "react-router-dom"; +import BPADocuments from "./BPADocuments"; +import InspectionReport from "./InspectionReport"; +import NOCDocuments from "./NOCDocuments"; +import PermissionCheck from "./PermissionCheck"; +import PropertyDocuments from "./PropertyDocuments"; +import PropertyEstimates from "./PropertyEstimates"; +import PropertyFloors from "./PropertyFloors"; +import PropertyOwners from "./PropertyOwners"; +import ScruntinyDetails from "./ScruntinyDetails"; +import SubOccupancyTable from "./SubOccupancyTable"; +import TLCaption from "./TLCaption"; +import TLTradeAccessories from "./TLTradeAccessories"; +import TLTradeUnits from "./TLTradeUnits"; +//import WSAdditonalDetails from "./WSAdditonalDetails"; +import WSFeeEstimation from "./WSFeeEstimation"; +//import WSInfoLabel from "../../../ws/src/pageComponents/WSInfoLabel"; +import DocumentsPreview from "./DocumentsPreview"; +import InfoDetails from "./InfoDetails"; +import ViewBreakup from "./ViewBreakup"; +import SubWorkTableDetails from "./SubWorkTableDetails"; + + + +function ApplicationDetailsContent({ + applicationDetails, + workflowDetails, + isDataLoading, + applicationData, + businessService, + timelineStatusPrefix, + showTimeLine = true, + statusAttribute = "status", + paymentsList, + oldValue, + isInfoLabel = false, + noBoxShadow = false, + sectionHeadStyle = false, + modify, + setSaveAttendanceState +}) { + const { t } = useTranslation(); + const [localSearchParams, setLocalSearchParams] = useState(() => ({})); + + + const handleDateRangeChange = useCallback((data) => { + setLocalSearchParams(() => ({ ...data })); + }, []); + + function OpenImage(imageSource, index, thumbnailsToShow) { + window.open(thumbnailsToShow?.fullImage?.[0], "_blank"); + } + + const convertEpochToDateDMY = (dateEpoch) => { + if (dateEpoch == null || dateEpoch == undefined || dateEpoch == "") { + return "NA"; + } + const dateFromApi = new Date(dateEpoch); + let month = dateFromApi.getMonth() + 1; + let day = dateFromApi.getDate(); + let year = dateFromApi.getFullYear(); + month = (month > 9 ? "" : "0") + month; + day = (day > 9 ? "" : "0") + day; + return `${day}/${month}/${year}`; + }; + const getTimelineCaptions = (checkpoint) => { + if (checkpoint.state === "OPEN" || (checkpoint.status === "INITIATED" && !window.location.href.includes("/obps/"))) { + const caption = { + date: convertEpochToDateDMY(applicationData?.auditDetails?.createdTime), + source: applicationData?.channel || "", + }; + return ; + } else if (window.location.href.includes("/obps/") || window.location.href.includes("/noc/") || window.location.href.includes("/ws/")) { + //From BE side assigneeMobileNumber is masked/unmasked with connectionHoldersMobileNumber and not assigneeMobileNumber + const privacy = { uuid: checkpoint?.assignes?.[0]?.uuid, fieldName: ["connectionHoldersMobileNumber"], model: "WaterConnectionOwner" }; + const caption = { + date: checkpoint?.auditDetails?.lastModified, + name: checkpoint?.assignes?.[0]?.name, + mobileNumber: + applicationData?.processInstance?.assignes?.[0]?.uuid === checkpoint?.assignes?.[0]?.uuid && + applicationData?.processInstance?.assignes?.[0]?.mobileNumber + ? applicationData?.processInstance?.assignes?.[0]?.mobileNumber + : checkpoint?.assignes?.[0]?.mobileNumber, + comment: t(checkpoint?.comment), + wfComment: checkpoint.wfComment, + thumbnailsToShow: checkpoint?.thumbnailsToShow, + }; + return ; + } else { + const caption = { + date: `${Digit.DateUtils?.ConvertTimestampToDate(checkpoint.auditDetails.lastModifiedEpoch)} ${Digit.DateUtils?.ConvertEpochToTimeInHours( + checkpoint.auditDetails.lastModifiedEpoch + )} ${Digit.DateUtils?.getDayfromTimeStamp(checkpoint.auditDetails.lastModifiedEpoch)}`, + // name: checkpoint?.assigner?.name, + name: checkpoint?.assignes?.[0]?.name, + // mobileNumber: checkpoint?.assigner?.mobileNumber, + wfComment: checkpoint?.wfComment, + mobileNumber: checkpoint?.assignes?.[0]?.mobileNumber, + }; + + return ; + } + }; + + const getTranslatedValues = (dataValue, isNotTranslated) => { + if (dataValue) { + return !isNotTranslated ? t(dataValue) : dataValue; + } else { + return t("NA"); + } + }; + + const checkLocation = + window.location.href.includes("employee/tl") || window.location.href.includes("employee/obps") || window.location.href.includes("employee/noc"); + const isNocLocation = window.location.href.includes("employee/noc"); + const isBPALocation = window.location.href.includes("employee/obps"); + let isWS = window.location.href.includes("employee/ws") || window.location.href.includes("employee/works")|| window.location.href.includes("employee/project") || window.location.href.includes("employee/estimate") ; + + + + const getRowStyles = (tab="") => { + + if (window.location.href.includes("employee/obps") || window.location.href.includes("employee/noc")) { + return { justifyContent: "space-between", fontSize: "16px", lineHeight: "19px", color: "#0B0C0C" }; + } else if (checkLocation) { + return { justifyContent: "space-between", fontSize: "16px", lineHeight: "19px", color: "#0B0C0C" }; + } + else if ( tab==="fieldSurvey") { + return { + justifyContent: "space-between", flexDirection:"column" + } + } + else { + return {}; + } + + }; + const getTextStyles = (tab="") => { + if ( tab==="fieldSurvey" ) { + return { + marginTop:"1rem", + marginBottom:"1rem" + } + } + else { + return {}; + } + + }; + const getLabelStyles = (tab = "") => { + if ( tab === "fieldSurvey") { + return { + width:"100%" + } + } + else { + return {}; + } + + }; + + const getTableStyles = () => { + if (window.location.href.includes("employee/obps") || window.location.href.includes("employee/noc")) { + return { position: "relative", marginTop: "19px" }; + } else if (checkLocation) { + return { position: "relative", marginTop: "19px" }; + } else { + return {}; + } + }; + + const getMainDivStyles = () => { + if ( + window.location.href.includes("employee/obps") || + window.location.href.includes("employee/noc") || + window.location.href.includes("employee/ws") || + window.location.href.includes("employee/works") || + window.location.href.includes("employee/contracts") + ) { + return { lineHeight: "19px", maxWidth: "950px", minWidth: "280px" }; + } else if (checkLocation) { + return { lineHeight: "19px", maxWidth: "600px", minWidth: "280px" }; + } else { + return {}; + } + }; + + const getTextValue = (value) => { + if (value?.skip) return value.value; + else if (value?.isUnit) return value?.value ? `${getTranslatedValues(value?.value, value?.isNotTranslated)} ${t(value?.isUnit)}` : t("N/A"); + else if (value?.value === "Approved") return { `${getTranslatedValues(value?.value, value?.isNotTranslated)}`} + else if (value?.value === "Rejected") return {t(value?.value)} + else return value?.value ? getTranslatedValues(value?.value, value?.isNotTranslated) : t("N/A"); + }; + + const getClickInfoDetails = () => { + if (window.location.href.includes("disconnection") || window.location.href.includes("application")) { + return "WS_DISCONNECTION_CLICK_ON_INFO_LABEL"; + } else { + return "WS_CLICK_ON_INFO_LABEL"; + } + }; + + const getClickInfoDetails1 = () => { + if (window.location.href.includes("disconnection") || window.location.href.includes("application")) { + return "WS_DISCONNECTION_CLICK_ON_INFO1_LABEL"; + } else { + return ""; + } + }; + + const getCardStyles = () => { + let styles = { position: "relative" } + if (noBoxShadow) styles = { ...styles, boxShadow: "none" }; + return styles; + }; + + return ( + + + {isInfoLabel ? ( + + ) : null} + {applicationDetails?.applicationDetails?.map((detail, index) => ( + + +
+ {index === 0 && !detail.asSectionHeader ? ( + {t(detail.title)} + ) : ( + + + {isNocLocation ? `${t(detail.title)}` : t(detail.title)} + {detail?.Component ? : null} + + + )} + {/* TODO, Later will move to classes */} + {/* Here Render the table for adjustment amount details detail.isTable is true for that table*/} + {/* {detail?.isTable && ( + + + {detail?.headers.map((header) => ( + + ))} + + + {detail?.tableRows.map((row,index)=>{ + if(index===detail?.tableRows.length - 1){ + return <> +
+ + {row.map(element => )} + + + } + return + {row.map(element => )} + })} +
{t(header)}
{t(element)}
{t(element)}
+ )} */} + {detail?.isTable && } + + + {detail?.title && + !detail?.title.includes("NOC") && + detail?.values?.map((value, index) => { + if (value.map === true && value.value !== "N/A") { + return } />; + } + if (value?.isLink == true) { + return ( + + + + {t(value?.title)} + + +
+ ) : isNocLocation || isBPALocation ? ( + `${t(value.title)}` + ) : ( + t(value.title) + ) + } + text={ +
+ + + {value?.value} + + +
+ } + last={index === detail?.values?.length - 1} + caption={value.caption} + className="border-none" + rowContainerStyle={getRowStyles()} + /> + ); + } + return ( + { }} />: getTextValue(value)} + last={index === detail?.values?.length - 1} + caption={value.caption} + className="border-none" + /* privacy object set to the Row Component */ + privacy={value?.privacy} + // TODO, Later will move to classes + rowContainerStyle={getRowStyles(detail?.tab)} + textStyle={getTextStyles(detail?.tab)} + labelStyle={getLabelStyles(detail?.tab)} + /> + ); + })} + + + + + {detail?.additionalDetails?.table + ? detail?.additionalDetails?.table?.weekTable?.tableHeader && ( + <> + + {t(detail?.additionalDetails?.table?.weekTable?.tableHeader)} + + + ) + : null} + + {detail?.additionalDetails?.inspectionReport && ( + + )} + {applicationDetails?.applicationData?.additionalDetails?.fieldinspection_pending?.length > 0 && detail?.additionalDetails?.fiReport && ( + + )} + {/* {detail?.additionalDetails?.FIdocuments && detail?.additionalDetails?.values?.map((doc,index) => ( +
+ {doc.isNotDuplicate &&
+ + + +
+
+
} +
+ )) } */} + {detail?.additionalDetails?.floors && } + {detail?.additionalDetails?.owners && } + {detail?.additionalDetails?.units && } + {detail?.additionalDetails?.accessories && } + {detail?.additionalDetails?.permissions && workflowDetails?.data?.nextActions?.length > 0 && ( + + )} + {detail?.additionalDetails?.obpsDocuments && ( + + )} + {detail?.additionalDetails?.noc && ( + + )} + {detail?.additionalDetails?.scruntinyDetails && } + {detail?.additionalDetails?.buildingExtractionDetails && } + {detail?.additionalDetails?.subOccupancyTableDetails && ( + + )} + {detail?.additionalDetails?.documentsWithUrl && } + {detail?.additionalDetails?.documents && } + {detail?.additionalDetails?.taxHeadEstimatesCalculation && ( + + )} + {/* {detail?.isWaterConnectionDetails && } */} + {detail?.additionalDetails?.redirectUrl && ( +
+ + + {detail?.additionalDetails?.redirectUrl?.title} + + +
+ )} + {detail?.additionalDetails?.estimationDetails && } + {detail?.additionalDetails?.estimationDetails && } +
+
+ ))} + {showTimeLine && workflowDetails?.data?.timeline?.length > 0 && ( + + {workflowDetails?.breakLineRequired === undefined ? : workflowDetails?.breakLineRequired ? : null} + {(workflowDetails?.isLoading || isDataLoading) && } + {!workflowDetails?.isLoading && !isDataLoading && ( + + + {/* {t("ES_APPLICATION_DETAILS_APPLICATION_TIMELINE")} */} + {t("WORKS_WORKFLOW_HISTORY")} + + {workflowDetails?.data?.timeline && workflowDetails?.data?.timeline?.length === 1 ? ( + + ) : ( + + {workflowDetails?.data?.timeline && + workflowDetails?.data?.timeline.map((checkpoint, index, arr) => { + return ( + + + + ); + })} + + )} + + )} + + )} +
+
+ ); +} + +export default ApplicationDetailsContent; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsToast.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsToast.js new file mode 100644 index 00000000000..9540495f32a --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsToast.js @@ -0,0 +1,74 @@ +import React from "react"; +import { Toast } from "@egovernments/digit-ui-react-components"; + +function ApplicationDetailsToast({ t, showToast, closeToast, businessService }) { + if (businessService?.includes("NewTL") || businessService?.includes("TL") || businessService?.includes("EDITRENEWAL")) { + let label = ""; + switch (showToast?.action?.action) { + case "SENDBACK": + label = showToast?.key === "error" ? showToast?.error?.message : t("TL_SENDBACK_CHECKLIST_MESSAGE_HEAD"); + break; + case "FORWARD": + label = showToast?.key === "error" ? showToast?.error?.message : t("TL_FORWARD_SUCCESS_MESSAGE_MAIN"); + break; + case "APPROVE": + label = showToast?.key === "error" ? showToast?.error?.message : t("TL_APPROVAL_CHECKLIST_MESSAGE_HEAD"); + break; + case "SENDBACKTOCITIZEN": + label = showToast?.key === "error" ? showToast?.error?.message : t("TL_SENDBACK_TOCITIZEN_CHECKLIST_MESSAGE_HEAD"); + break; + case "REJECT": + label = showToast?.key === "error" ? showToast?.error?.message : t("TL_APPROVAL_REJ_MESSAGE_HEAD"); + break; + case "RESUBMIT": + label = showToast?.key === "error" ? showToast?.error?.message : t("TL_APPLICATION_RESUBMIT_SUCCESS_MESSAGE_MAIN"); + break; + case "CANCEL": + label = showToast?.key === "error" ? showToast?.error?.message : t("TL_TL_CANCELLED_MESSAGE_HEAD"); + break; + default: + label = showToast?.key === "error" ? showToast?.error?.message : t(`ES_${businessService}_${showToast?.action?.action}_UPDATE_SUCCESS`); + } + return {showToast && }; + } else if (businessService?.includes("BPA") || businessService?.includes("BPA_LOW") || businessService?.includes("BPA_OC")) { + const getMessage = (messages = []) => { + let returnValue = messages[0]; + if(messages?.length == 2) returnValue = businessService?.includes("BPA_OC") ? t(messages[1]) : t(messages [0]); + else returnValue = t(messages[0]); + return returnValue; + } + let label = ""; + switch (showToast?.action?.action) { + case "REVOCATE": + label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_APPROVAL_REVOCATED_MESSAGE_HEAD", "BPA_APPROVAL_OC_REVOCATED_MESSAGE_HEAD"]); + break; + case "VERIFY_AND_FORWARD": + label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_FORWARD_SUCCESS_MESSAGE_MAIN"]); + break; + case "SEND_BACK_TO_CITIZEN": + label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_SENDBACK_SUCCESS_MESSAGE_MAIN"]); + break; + case "APPROVE": + label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_APPROVAL_CHECKLIST_MESSAGE_HEAD"]); + break; + case "REJECT": + label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_APPROVAL_REJECTED_MESSAGE_HEAD", "BPA_OC_APPROVAL_REJECTED_MESSAGE_HEAD"]); + break; + case "FORWARD": + label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_FORWARD_SUCCESS_MESSAGE_MAIN"]); + break; + case "SEND_BACK_FOR_DOCUMENT_VERIFICATION": + case "SEND_BACK_FOR_FIELD_INSPECTION": + label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_SENDBACK_SUCCESS_MESSAGE_MAIN"]); + break; + default: + label = showToast?.key === "error" ? showToast?.error?.message : t(`ES_${businessService}_${showToast?.action?.action}_UPDATE_SUCCESS`); + } + return {showToast && }; + } else { + const label = showToast?.key === "error" ? showToast?.error?.message : `ES_${businessService}_${showToast?.action?.action}_UPDATE_SUCCESS`; + return {showToast && }; + } +} + +export default ApplicationDetailsToast; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsWarningPopup.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsWarningPopup.js new file mode 100644 index 00000000000..e95b9e038cd --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsWarningPopup.js @@ -0,0 +1,54 @@ +import { Card, ButtonSelector, CardText, CardSubHeader, Modal, CardSectionHeader, Row } from "@egovernments/digit-ui-react-components"; +import React from "react"; +import { useTranslation } from "react-i18next"; + +const Close = () => ( + + + + + ); + +const CloseBtn = (props) => { + return ( +
+ +
+ ); + }; + +function ApplicationDetailsWarningPopup({ action,workflowDetails,businessService,isWarningPop,closeWarningPopup }) { +const { t } = useTranslation(); +const isMobile = window.Digit.Utils.browser.isMobile(); +return ( + + {t("PT_DUES_ARE_PENDING")}} + headerBarEnd={ + { + closeWarningPopup(); + }} + /> + } + hideSubmit={true} + isDisabled={false} + popupStyles={isMobile ? {} : { width: "29%", marginTop: "auto" }} + > + +
+

{t("PT_YOU_HAVE")} ₹{action?.AmountDueForPay} {t("PT_DUE_WARNING_MSG2")}

+
+ +
+ + window.location.assign(`${window.location.origin}${action?.redirectionUrl?.pathname}`)} style={{ marginLeft: "10px" }} /> +
+
+
+ ) +
+) +} + +export default ApplicationDetailsWarningPopup; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/BPADocuments.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/BPADocuments.js new file mode 100644 index 00000000000..9a1febe081b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/BPADocuments.js @@ -0,0 +1,234 @@ +import React, { useEffect, useState } from "react"; +import { + CardLabel, + Dropdown, + LabelFieldPair, + MultiUploadWrapper, + CardSubHeader +} from "@egovernments/digit-ui-react-components"; +import DocumentsPreview from "./DocumentsPreview"; + +const BPADocuments = ({ t, formData, applicationData, docs, bpaActionsDetails }) => { + const applicationStatus = applicationData?.status || ""; + const actions = bpaActionsDetails?.data?.nextActions || []; + const stateId = Digit.ULBService.getStateId(); + const [documents, setDocuments] = useState(formData?.documents?.documents || []); + const [error, setError] = useState(null); + const [bpaTaxDocuments, setBpaTaxDocuments] = useState([]); + const [enableSubmit, setEnableSubmit] = useState(true) + const [checkRequiredFields, setCheckRequiredFields] = useState(false); + const [checkEnablingDocs, setCheckEnablingDocs] = useState(false); + + const { isLoading: bpaDocsLoading, data: bpaDocs } = Digit.Hooks.obps.useMDMS(stateId, "BPA", ["DocTypeMapping"]); + const { isLoading: commonDocsLoading, data: commonDocs } = Digit.Hooks.obps.useMDMS(stateId, "common-masters", ["DocumentType"]); + + useEffect(() => { + let filtredBpaDocs = []; + if (bpaDocs?.BPA?.DocTypeMapping) { + // filtredBpaDocs = bpaDocs?.BPA?.DocTypeMapping?.filter(data => (data.WFState == "INPROGRESS")) + filtredBpaDocs = bpaDocs?.BPA?.DocTypeMapping?.filter(data => (data.WFState == applicationData?.status ? applicationData?.status : "INPROGRESS" && data.RiskType == applicationData?.riskType && data.ServiceType == applicationData?.additionalDetails?.serviceType && data.applicationType == applicationData?.additionalDetails?.applicationType)) + } + let documentsList = []; + filtredBpaDocs?.[0]?.docTypes?.forEach(doc => { + let code = doc.code; doc.dropdownData = []; doc.uploadedDocuments = []; + commonDocs?.["common-masters"]?.DocumentType?.forEach(value => { + let values = value.code.slice(0, code.length); + if (code === values) { + doc.hasDropdown = true; + value.i18nKey = value.code; + doc.dropdownData.push(value); + } + }); + doc.uploadedDocuments[0] = {}; + doc.uploadedDocuments[0].values = []; + docs?.[0]?.values?.map(upDocs => { + if (code === `${upDocs?.documentType?.split('.')[0]}.${upDocs?.documentType?.split('.')[1]}`) { + doc.uploadedDocuments[0].values.push(upDocs) + } + }) + documentsList.push(doc); + }); + sessionStorage.setItem("BPA_DOCUMENTS", JSON.stringify(documentsList)); + setBpaTaxDocuments(documentsList); + + }, [!bpaDocsLoading, !commonDocsLoading]); + + useEffect(() => { + let count = 0; + bpaTaxDocuments.map(doc => { + let isRequired = false; + documents.map(data => { + if (doc.required && doc.code == `${data.documentType.split('.')[0]}.${data.documentType.split('.')[1]}`) { + isRequired = true; + } + }); + if (!isRequired && doc.required) { + count = count + 1; + } + }); + if ((count == "0" || count == 0) && documents.length > 0) setEnableSubmit(false); + else setEnableSubmit(true); + }, [documents, checkRequiredFields]) + + useEffect(() => { + if ( applicationStatus === "DOC_VERIFICATION_INPROGRESS" && actions?.length > 0 ) setCheckEnablingDocs(true); + else setCheckEnablingDocs(false); + }, [applicationData, bpaActionsDetails]) + + return ( +
+ {bpaTaxDocuments?.map((document, index) => { + return ( +
+ +
+ ); + })} +
+ ); +} + +function SelectDocument({ + t, + document: doc, + setDocuments, + error, + setError, + documents, + setCheckRequiredFields, + index, + applicationStatus, + actions, + bpaTaxDocuments, + checkEnablingDocs +}) { + + const filteredDocument = documents?.filter((item) => item?.documentType?.includes(doc?.code))[0]; + const tenantId = Digit.ULBService.getStateId(); + const [selectedDocument, setSelectedDocument] = useState( + filteredDocument + ? { ...filteredDocument, active: true, code: filteredDocument?.documentType, i18nKey: filteredDocument?.documentType } + : doc?.dropdownData?.length === 1 + ? doc?.dropdownData[0] + : {} + ); + const [file, setFile] = useState(null); + const [uploadedFile, setUploadedFile] = useState(() => filteredDocument?.fileStoreId || null); + const [selectArrayFiles, SetSelectArrayFiles] = useState([]); + const handleSelectDocument = (value) => setSelectedDocument(value); + const allowedFileTypes = /(.*?)(jpg|jpeg|png|image|pdf)$/i; + + function selectfiles(e) { + e && setFile(e.file); + } + + + useEffect(() => { + if (selectedDocument?.code) { + setDocuments((prev) => { + const filteredDocumentsByDocumentType = prev?.filter((item) => item?.documentType !== selectedDocument?.code); + if (uploadedFile?.length === 0 || uploadedFile === null) return filteredDocumentsByDocumentType; + const filteredDocumentsByFileStoreId = filteredDocumentsByDocumentType?.filter((item) => item?.fileStoreId !== uploadedFile); + return [ + ...filteredDocumentsByFileStoreId, + { + documentType: selectedDocument?.code, + fileStoreId: uploadedFile, + documentUid: uploadedFile, + fileName: file?.name || "", + id: documents ? documents.find(x => x.documentType === selectedDocument?.code)?.id : undefined, + }, + ]; + }); + } + }, [uploadedFile, selectedDocument]); + + useEffect(() => { + (async () => { + if (selectArrayFiles.length > 0) { + sessionStorage.removeItem("BPA_DOCUMENTS"); + doc.newUploadedDocs = []; + selectArrayFiles.map(newDoc => { + if (selectedDocument?.code) { + doc.newUploadedDocs.push({ + documentType: selectedDocument?.code, + fileStoreId: newDoc?.fileStoreId?.fileStoreId, + documentUid: newDoc?.fileStoreId?.fileStoreId, + tenantId: newDoc?.fileStoreId?.tenantId + }); + } + }) + bpaTaxDocuments[index] = doc; + sessionStorage.setItem("BPA_DOCUMENTS", JSON.stringify(bpaTaxDocuments)); + } + })(); + }, [selectArrayFiles, selectedDocument]); + + useEffect(() => { + (async () => { + + })(); + }, [file]); + + const getData = (index, state) => { + let data = Object.fromEntries(state); + let newArr = Object.values(data); + if (Object.keys(data).length !== 0) SetSelectArrayFiles(newArr); + selectfiles(newArr[newArr.length - 1]); + } + + return ( +
+ {`${t(doc?.code)}`} + {doc?.uploadedDocuments?.length && } + { + checkEnablingDocs ? +
+ + {doc?.required ? `${t(doc?.code)}* ` : `${t(doc?.code)}`} + + + + +
+ getData(index, e)} + t={t} + allowedFileTypesRegex={allowedFileTypes} + allowedMaxSizeInMB={5} + acceptFiles= "image/*, .pdf, .png, .jpeg, .jpg" + /> +
+
+
: null + } +
+ ); +} + +export default BPADocuments; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/DocumentsPreview.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/DocumentsPreview.js new file mode 100644 index 00000000000..dfd57683def --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/DocumentsPreview.js @@ -0,0 +1,49 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import { CardSubHeader, PDFSvg } from "@egovernments/digit-ui-react-components"; + +function DocumentsPreview({ documents, svgStyles = {}, isSendBackFlow = false, isHrLine = false, titleStyles }) { + const { t } = useTranslation(); + const isStakeholderApplication = window.location.href.includes("stakeholder"); + + return ( +
+ {!isStakeholderApplication && documents?.map((document, index) => ( + + {document?.title ? {t(document?.title)} : null} +
+ {document?.values && document?.values.length > 0 ? document?.values?.map((value, index) => ( + +
+ +
+

{t(value?.title)}

+ {isSendBackFlow ? value?.documentType?.includes("NOC") ?

{t(value?.documentType.split(".")[1])}

:

{t(value?.documentType)}

: ""} +
+ )) : !(window.location.href.includes("citizen")) &&

{t("BPA_NO_DOCUMENTS_UPLOADED_LABEL")}

} +
+ {isHrLine && documents?.length != index + 1 ?
: null} +
+ ))} + {isStakeholderApplication && documents?.map((document, index) => ( + + {document?.title ? {t(document?.title)} : null} +
+ {document?.values && document?.values.length > 0 ? document?.values?.map((value, index) => ( + +
+

{t(value?.title)}

+ {value?.docInfo ?
{`${t(value?.docInfo)}`}
: null} + +

{`${t(value?.title)}`}

+
+
+ )) : !(window.location.href.includes("citizen")) &&

{t("BPA_NO_DOCUMENTS_UPLOADED_LABEL")}

} +
+
+ ))} +
+ ); +} + +export default DocumentsPreview; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InfoDetails.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InfoDetails.js new file mode 100644 index 00000000000..12e2f64fac6 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InfoDetails.js @@ -0,0 +1,34 @@ +import React from "react"; +import { InfoBannerIcon } from "@egovernments/digit-ui-react-components"; + +const EyeSvgINdex = ({ style }) => { + return + + + + + +} +const InfoDetails = ({ t, userType = false, infoBannerLabel = "", infoClickLable = "", infoClickInfoLabel = "", infoClickInfoLabel1 = "" }) => { + userType = userType || Digit.SessionStorage.get("userType"); + return ( + +
+
+
+ +

{t(infoBannerLabel)}

+
+ {`${t(infoClickLable)} `} + + {` ${t(infoClickInfoLabel)}`} +
+ {` ${t(infoClickInfoLabel1)}`} +
+
+
+
+ ); +}; + +export default InfoDetails; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InspectionReport.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InspectionReport.js new file mode 100644 index 00000000000..a824b05a435 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InspectionReport.js @@ -0,0 +1,49 @@ +import { StatusTable, Row, CardHeader, CardSectionHeader } from "@egovernments/digit-ui-react-components"; +import React from "react"; +import { useTranslation } from "react-i18next"; +import DocumentsPreview from "./DocumentsPreview"; + +const getDocuments = (fiDocuments) => { + const returnDocuments = [{ + title: "BPA_DOCUMENT_DETAILS_LABEL", + values: fiDocuments?.map(doc => ({ + title: doc?.documentType?.replaceAll('.', '_'), + documentType: doc?.documentType, + documentUid: doc?.documentUid, + fileStoreId: doc?.fileStoreId, + id: doc?.id, + url: doc?.url + })) + }]; + return returnDocuments; +}; + +function InspectionReport({ fiReport, isCitizen=false }) { + const { t } = useTranslation(); + + return ( + +
+ {isCitizen?{`${t(`BPA_FI_REPORT`)}`}: + {`${t(`BPA_FI_REPORT`)}`}} + {fiReport.map((fiData, index) => +
+ + {fiReport?.length == 1 ? `${t(`BPA_FI_REPORT`)}` : `${t(`BPA_FI_REPORT`)} - ${index + 1}`} + + + {fiData?.questions?.length && + fiData?.questions?.map((qstn) => +
+ + +
)} + +
+
)} +
+
+ ); +} + +export default InspectionReport; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/NOCDocuments.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/NOCDocuments.js new file mode 100644 index 00000000000..1581744f756 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/NOCDocuments.js @@ -0,0 +1,202 @@ +import React, { useEffect, useState } from "react"; +import { + CardLabel, + MultiUploadWrapper, + StatusTable, + Row, + LabelFieldPair +} from "@egovernments/digit-ui-react-components"; +import DocumentsPreview from "./DocumentsPreview"; + +function SelectDocument({ + t, + document: doc, + setNocDocuments, + setError, + nocDocuments +}) { + const filteredDocument = nocDocuments?.filter((item) => item?.documentType?.includes(doc?.code))[0]; + const tenantId = Digit.ULBService.getStateId(); + const [selectedDocument, setSelectedDocument] = useState(); + const [file, setFile] = useState(null); + const [uploadedFile, setUploadedFile] = useState(() => filteredDocument?.fileStoreId || null); + const handleSelectDocument = (value) => setSelectedDocument(value); + const allowedFileTypes = /(.*?)(jpg|jpeg|png|image|pdf)$/i; + + function selectfile(e) { + e && setFile(e.file); + } + + useEffect(() => { + if (doc?.dropdownData?.[0]?.code) { + setNocDocuments((prev) => { + const filteredDocumentsByDocumentType = prev?.filter((item) => item?.documentType !== doc?.dropdownData?.[0]?.code); + + if (uploadedFile?.length === 0 || uploadedFile === null) { + return filteredDocumentsByDocumentType; + } + + const filteredDocumentsByFileStoreId = filteredDocumentsByDocumentType?.filter((item) => item?.fileStoreId !== uploadedFile); + return [ + ...filteredDocumentsByFileStoreId, + { + documentType: doc?.dropdownData?.[0].code, + fileStoreId: uploadedFile, + documentUid: uploadedFile, + fileName: file?.name || "", + }, + ]; + }); + } + }, [uploadedFile]); + + + useEffect(() => { + (async () => { + setError(null); + if (file) { + const allowedFileTypesRegex = /(.*?)(jpg|jpeg|png|image|pdf)$/i + if (file.size >= 5242880) { + setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); + } else if (file?.type && !allowedFileTypesRegex.test(file?.type)) { + setError(t(`NOT_SUPPORTED_FILE_TYPE`)) + } else { + try { + setUploadedFile(null); + const response = await Digit.UploadServices.Filestorage("PT", file, Digit.ULBService.getStateId()); + if (response?.data?.files?.length > 0) { + setUploadedFile(response?.data?.files[0]?.fileStoreId); + } else { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } catch (err) { + setError(t("CS_FILE_UPLOAD_ERROR")); + } + } + } + })(); + }, [file]); + + const getData =(state) => { + let data = Object.fromEntries(state); + let newArr = Object.values(data); + selectfile(newArr[newArr.length-1]); + } + + return ( +
+ + {doc?.required ? `${t("TL_BUTTON_UPLOAD FILE")}*` : `${t("TL_BUTTON_UPLOAD FILE")}`} +
+ getData(e)} + t={t} + allowedFileTypesRegex={allowedFileTypes} + allowedMaxSizeInMB={5} + acceptFiles="image/*, .pdf, .png, .jpeg, .jpg" + /> +
+
+
+ ); +} +const NOCDocuments = ({ t, noc, docs, isNoc, applicationData,NOCdata, bpaActionsDetails }) => { + const tenantId = Digit.ULBService.getStateId(); + const stateId = Digit.ULBService.getStateId(); + const bpaApplicationStatus = applicationData?.status || ""; + const actions = bpaActionsDetails?.data?.nextActions || []; + const { isLoading: nocDocsLoading, data: nocDocs } = Digit.Hooks.obps.useMDMS(stateId, "NOC", ["DocumentTypeMapping"], { enabled: isNoc }); + const { isLoading: bpaDocsLoading, data: bpaDocs } = Digit.Hooks.obps.useMDMS(stateId, "BPA", ["DocTypeMapping"], { enabled: !isNoc }); + const { isLoading: commonDocsLoading, data: commonDocs } = Digit.Hooks.obps.useMDMS(stateId, "common-masters", ["DocumentType"]); + const [commonDocMaping, setCommonDocMaping] = useState([]); + const [nocTaxDocuments, setNocTaxDocuments] = useState([]); + const [checkEnablingDocs, setCheckEnablingDocs] = useState(false); + const [nocDocuments, setNocDocuments] = Digit.Hooks.useSessionStorage(noc?.nocType, []); + const [error, setError] = useState(null); + const isEmployee = window.location.href.includes("/employee/") + + useEffect(() => { + setCommonDocMaping(commonDocs?.["common-masters"]?.DocumentType); + }, [commonDocs]); + + useEffect(() => { + let documents = []; + let filteredData + if (isNoc) { + filteredData = nocDocs?.NOC?.DocumentTypeMapping?.filter((data => { + return data?.applicationType === noc?.applicationType && data?.nocType === noc?.nocType + })); + } + else { + filteredData = bpaDocs?.BPA?.DocTypeMapping?.filter(data => (data.WFState == applicationData?.status && data.RiskType == applicationData?.riskType && data.ServiceType == applicationData?.additionalDetails?.serviceType && data.applicationType == applicationData?.additionalDetails?.applicationType)) + } + if (filteredData?.[0]?.docTypes?.[0]) { + filteredData[0].docTypes[0].nocType = filteredData[0].nocType; + filteredData[0].docTypes[0].additionalDetails = { + submissionDetails: noc?.additionalDetails, + applicationStatus: noc?.applicationStatus, + appNumberLink: noc?.applicationNo, + nocNo: noc?.nocNo + } + documents.push(filteredData[0].docTypes[0]); + } + let documentsList = []; + if (documents && documents.length > 0) { + documents.map((doc) => { + let code = doc.documentType; + let nocType = doc.nocType; + doc.dropdownData = []; + commonDocMaping?.forEach((value) => { + let values = value.code.slice(0, code?.length); + if (code === values) { + doc.hasDropdown = true; + doc.dropdownData.push(value); + } + }); + documentsList.push(doc); + }); + setNocTaxDocuments(documentsList); + } + }, [nocDocs, commonDocMaping]); + + useEffect(() => { + if (bpaApplicationStatus === 'NOC_VERIFICATION_INPROGRESS' && actions?.length > 0) setCheckEnablingDocs(true); + else setCheckEnablingDocs(false); + }, [applicationData, bpaActionsDetails]) + + return ( +
+ + + {NOCdata && NOCdata.map((noc,index) => { + if (noc?.value) { + if (noc?.field == "STATUS") { + return + } else { + return + } + } + })} + + + {checkEnablingDocs && nocTaxDocuments?.map((document, index) => { + return ( + + ); + })} +
+ ); +} + +export default NOCDocuments; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PermissionCheck.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PermissionCheck.js new file mode 100644 index 00000000000..89007789722 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PermissionCheck.js @@ -0,0 +1,87 @@ +import { CheckBox, LinkButton, TextInput,Close, CardSubHeader } from "@egovernments/digit-ui-react-components"; +import React, { useEffect, useState } from "react"; + +const PermissionCheck = ({ permissions, t }) => { + const [approvalChecks, setApprovalChecks, clearApprovals] = Digit.Hooks.useSessionStorage("OBPS_APPROVAL_CHECKS", permissions?.map(permission => ({ label: permission, checked: false }))); //useState(() => permissions?.map(permission => ({ label: permission, checked: false }))) + const [newApprovals, setNewApprovals, clearNewApprovals] = Digit.Hooks.useSessionStorage('OBPS_NEW_APPROVALS', []); + + useEffect(() => { + return () => { + Digit.SessionStorage.del("OBPS_NEW_APPROVALS"); + Digit.SessionStorage.del("OBPS_APPROVAL_CHECKS"); + } + }, []) + + const handleAdd = () => { + setNewApprovals([...newApprovals, { label: '' }]); + } + + const handleRemove = (index) => { + const values = [...newApprovals]; + values.splice(index, 1); + setNewApprovals([...values]); + } + + const handleChange = (event, index) => { + setNewApprovals(() => { + return newApprovals?.map((approval, id) => { + if (index === id) { + return { + label: event?.target?.value, + } + } + return approval; + }) + }) + } + + const handleCheck = (event, label, index) => { + const isChecked = event.target.checked; + setApprovalChecks(() => { + return approvalChecks?.map((approval, id) => { + if (index === id) { + return { + ...approval, + checked: isChecked + } + } + return approval; + }) + }) + } + + return ( +
+ {t("BPA_PERMIT_CONDITIONS")} + {approvalChecks?.map((permission, index) => ( + handleCheck(event, permission?.label, index))} + isLabelFirst={true} + index={index} + /> + ))} + {newApprovals?.map((approval, index) => ( +
handleChange(event, index)} textInputStyle={{maxWidth: "830px", width: "830px"}} placeholder={"Enter permit conditions.........."} /> + { + + + +
+ } + style={{ }} + onClick={(e) => handleRemove(index)} + />} +
+ ))} + + + ) +} + +export default PermissionCheck; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyDocuments.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyDocuments.js new file mode 100644 index 00000000000..ea8cd1eb104 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyDocuments.js @@ -0,0 +1,83 @@ +import React, { useState, useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import { CardSubHeader, PDFSvg } from "@egovernments/digit-ui-react-components"; + +// const PDFSvg = ({ width = 34, height = 34, style, viewBox = "0 0 34 34" }) => ( +// +// +// +// ); + +function PropertyDocuments({ documents, svgStyles = {}, isSendBackFlow=false }) { + const { t } = useTranslation(); + const [filesArray, setFilesArray] = useState(() => [] ); + const tenantId = Digit.ULBService.getCurrentTenantId(); + const [pdfFiles, setPdfFiles] = useState({}); + + useEffect(() => { + let acc = []; + documents?.forEach((element, index, array) => { + acc = [...acc, ...(element.values?element.values:[])]; + }); + setFilesArray(acc?.map((value) => value?.fileStoreId)); + }, [documents]); + + useEffect(() => { + if (filesArray?.length && documents?.[0]?.BS === "BillAmend") { + Digit.UploadServices.Filefetch(filesArray, Digit.ULBService.getCurrentTenantId()).then((res) => { + setPdfFiles(res?.data); + }); + } + else if(filesArray?.length) + { + Digit.UploadServices.Filefetch(filesArray, Digit.ULBService.getStateId()).then((res) => { + setPdfFiles(res?.data); + }); + } + + }, [filesArray]); + + const checkLocation = window.location.href.includes("employee/tl") || window.location.href.includes("/obps") || window.location.href.includes("employee/ws"); + const isStakeholderApplication = window.location.href.includes("stakeholder"); + + return ( +
+ {!isStakeholderApplication && documents?.map((document, index) => ( + + {document?.title ? {t(document?.title)}: null} +
+ {document?.values && document?.values.length>0 ? document?.values?.map((value, index) => ( + +
+ +
+

{t(value?.title)}

+ {isSendBackFlow? value?.documentType?.includes("NOC")?

{t(value?.documentType.split(".")[1])}

:

{t(value?.documentType)}

:""} +
+ )):!(window.location.href.includes("citizen"))&&

{t("BPA_NO_DOCUMENTS_UPLOADED_LABEL")}

} +
+
+ ))} + {isStakeholderApplication && documents?.map((document, index) => ( + + {document?.title ? {t(document?.title)} : null} +
+ {document?.values && document?.values.length>0 ? document?.values?.map((value, index) => ( + +
+

{t(value?.title)}

+ {value?.docInfo ?
{`${t(value?.docInfo)}`}
: null} + + {/*
{decodeURIComponent(pdfFiles[value.fileStoreId]?.split(",")[0].split("?")[0].split("/").pop().slice(13))}
*/} +

{`${t(value?.title)}`}

+
+
+ )):!(window.location.href.includes("citizen"))&&

{t("BPA_NO_DOCUMENTS_UPLOADED_LABEL")}

} +
+
+ ))} +
+ ); +} + +export default PropertyDocuments; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyEstimates.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyEstimates.js new file mode 100644 index 00000000000..c4cde76709f --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyEstimates.js @@ -0,0 +1,39 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import { StatusTable, Row, BreakLine } from "@egovernments/digit-ui-react-components"; + +function PropertyEstimates({ taxHeadEstimatesCalculation }) { + const { taxHeadEstimates } = taxHeadEstimatesCalculation; + const { t } = useTranslation(); + + return ( +
+ + + + {taxHeadEstimates?.map((estimate, index) => { + return ( + + ); + })} + + + +
+ ); +} + +export default PropertyEstimates; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyFloors.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyFloors.js new file mode 100644 index 00000000000..4f33bbdcff4 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyFloors.js @@ -0,0 +1,49 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import { CardSubHeader, StatusTable, Row, CardSectionHeader } from "@egovernments/digit-ui-react-components"; + +function PropertyFloors({ floors }) { + const { t } = useTranslation(); + + return ( + + {floors.map((floor) => ( +
+ {t(floor?.title)} + {floor?.values?.map((value, index) => { + return ( + + + {t(value.title)} + + +
+ {value?.values?.map((value, index) => { + if (value.map === true && value.value !== "N/A") { + return } />; + } + return ( + + ); + })} +
+
+
+ ); + })} +
+ ))} +
+ ); +} + +export default PropertyFloors; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyOwners.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyOwners.js new file mode 100644 index 00000000000..dac9f41c79b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyOwners.js @@ -0,0 +1,94 @@ +import { CardSubHeader, Row, StatusTable } from "@egovernments/digit-ui-react-components"; +import React from "react"; +import { useTranslation } from "react-i18next"; + +function PropertyOwners({ owners }) { + const { t } = useTranslation(); + + const checkLocation = true; + const checkOwnerLength = owners?.length || 1; + let cardStyles = { marginTop: "19px" }; + let statusTableStyles = { position: "relative", padding: "8px" }; + let rowContainerStyle = { justifyContent: "space-between", fontSize: "16px", lineHeight: "19px", color: "#0B0C0C" }; + if (checkLocation && Number(checkOwnerLength) > 1) { + cardStyles = { + marginTop: "19px", + background: "#FAFAFA", + border: "1px solid #D6D5D4", + borderRadius: "4px", + padding: "8px", + lineHeight: "19px", + maxWidth: "600px", + minWidth: "280px", + }; + } else if (checkLocation && !(Number(checkOwnerLength) > 1)) { + cardStyles = { marginTop: "19px", lineHeight: "19px", maxWidth: "600px", minWidth: "280px" }; + statusTableStyles = { position: "relative", marginTop: "19px" }; + } + + if (window.location.href.includes("obps")) { + cardStyles = { ...cardStyles, maxWidth: "950px" }; + cardStyles = { ...cardStyles, maxWidth: "950px" }; + rowContainerStyle = {}; + } + + return ( + + {owners.map((owner, index) => ( +
+ {/* TODO, Later will move to classes */} + 1 + ? { marginBottom: "8px", paddingBottom: "9px", color: "#0B0C0C", fontSize: "16px", lineHeight: "19px" } + : { marginBottom: "8px", color: "#505A5F", fontSize: "24px" } + } + > + {checkLocation && Number(checkOwnerLength) > 1 ? `${t(owner?.title)} ${index + 1}` : t(owner?.title)} + + + +
+ {owner?.values?.map((value, index) => { + if (value.map === true && value.value !== "N/A") { + return } />; + } + return ( + + + + ); + })} +
+
+
+ ))} +
+ ); +} + +export default PropertyOwners; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/Reason.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/Reason.js new file mode 100644 index 00000000000..0f226935c5b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/Reason.js @@ -0,0 +1,10 @@ +import React from "react"; + +const Reason = ({ headComment, otherComment }) => ( +
+

{headComment}

+

{otherComment}

+
+); + +export default Reason; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ScruntinyDetails.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ScruntinyDetails.js new file mode 100644 index 00000000000..bde27623ba8 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ScruntinyDetails.js @@ -0,0 +1,46 @@ +import { StatusTable, Row, PDFSvg, CardLabel, CardSubHeader } from "@egovernments/digit-ui-react-components"; +import React, { Fragment } from "react"; +import { useTranslation } from "react-i18next"; + +const ScruntinyDetails = ({ scrutinyDetails, paymentsList=[] }) => { + const { t } = useTranslation(); + let count = 0; + const getTextValues = (data) => { + if (data?.value && data?.isTransLate) return {t(data?.value)}; + else if (data?.value && data?.isTransLate) return t(data?.value); + else if (data?.value) return data?.value; + else t("NA"); + } + return ( + + {!scrutinyDetails?.isChecklist &&
+ +
+ {scrutinyDetails?.values?.map((value, index) => { + if (value?.isUnit) return + else if (value?.isHeader && !value?.isUnit) return {t(value?.title)} + else if (value?.isSubTitle && !value?.isUnit) return {t(value?.title)} + else return + })} + {scrutinyDetails?.permit?.map((value,ind) => { + return {value?.title} + })} +
+
+ {scrutinyDetails?.scruntinyDetails?.map((report, index) => { + return ( + + + +

{t(report?.text)}

+
+ ) + })} +
+
+
} +
+ ) +} + +export default ScruntinyDetails; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubOccupancyTable.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubOccupancyTable.js new file mode 100644 index 00000000000..e266bed6be2 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubOccupancyTable.js @@ -0,0 +1,126 @@ +import React, { Fragment, useMemo } from "react"; +import { Table, StatusTable, Row, CardSubHeader, CardSectionHeader } from "@egovernments/digit-ui-react-components"; +import { useTranslation } from "react-i18next"; + +const SubOccupancyTable = ({ edcrDetails, applicationData }) => { + const { t } = useTranslation(); + const isMobile = window.Digit.Utils.browser.isMobile(); + + const tableHeader = [ + { + name: "BPA_TABLE_COL_FLOOR", + id: "Floor", + }, + { + name: "BPA_TABLE_COL_LEVEL", + id: "Level", + }, + { + name: "BPA_TABLE_COL_OCCUPANCY", + id: "Occupancy", + }, + { + name: "BPA_TABLE_COL_BUILDUPAREA", + id: "BuildupArea", + }, + { + name: "BPA_TABLE_COL_FLOORAREA", + id: "FloorArea", + }, + { + name: "BPA_TABLE_COL_CARPETAREA", + id: "CarpetArea", + } + ] + + const accessData = (plot) => { + const name = plot; + return (originalRow, rowIndex, columns) => { + return originalRow[name]; + } + } + + + const tableColumns = useMemo( + () => { + return tableHeader.map((ob) => ({ + Header: t(`${ob.name}`), + accessor: accessData(ob.id), + id: ob.id + })); + }); + + function getFloorData(block) { + let floors = []; + block?.building?.floors.map((ob) => { + floors.push({ + Floor: t(`BPA_FLOOR_NAME_${ob.number}`), + Level: ob.number, + Occupancy: t(`${ob.occupancies?.[0]?.type}`), + BuildupArea: ob.occupancies?.[0]?.builtUpArea, + FloorArea: ob.occupancies?.[0]?.floorArea || 0, + CarpetArea: ob.occupancies?.[0]?.CarpetArea || 0, + key: t(`BPA_FLOOR_NAME_${ob.number}`), + }); + }); + return floors; + } + + const stringReplaceAll = (str = "", searcher = "", replaceWith = "") => { + if (searcher == "") return str; + while (str.includes(searcher)) { + str = str.replace(searcher, replaceWith); + } + return str; + }; + + function getSubOccupancyValues(index) { + let values = applicationData?.landInfo?.unit; + let returnValue = ""; + if (values?.length > 0) { + let splitArray = values[index]?.usageCategory?.split(','); + if (splitArray?.length) { + const returnValueArray = splitArray.map(data => data ? `${t(`BPA_SUBOCCUPANCYTYPE_${stringReplaceAll(data?.toUpperCase(), "-", "_")}`)}` : "NA"); + returnValue = returnValueArray.join(', ') + } + } + return returnValue ? returnValue : "NA"; + } + + return ( + +
+ + {edcrDetails?.values?.map((value, index) => { + if (value?.isHeader) return {t(value?.title)} + else return + })} + + + {edcrDetails?.subOccupancyTableDetails?.[0]?.value?.planDetail?.blocks.map((block, index) => ( +
0 ? {marginBottom: "30px", background: "#FAFAFA", border: "1px solid #D6D5D4", padding: "8px", borderRadius: "4px", maxWidth: "950px", minWidth: "280px"} : {marginBottom: "30px"}}> + {t("BPA_BLOCK_SUBHEADER")} {index + 1} + + + +
+ { return { style: {} } }} + /> + + ))} + + + ) +} + +export default SubOccupancyTable; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubWorkTableDetails.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubWorkTableDetails.js new file mode 100644 index 00000000000..08b89e68419 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubWorkTableDetails.js @@ -0,0 +1,77 @@ +import { EditIcon } from '@egovernments/digit-ui-react-components'; +import React from 'react' +import { useTranslation } from "react-i18next"; +import { useHistory } from 'react-router-dom'; + +const SubWorkTableDetails = ({data}) => { + const { t } = useTranslation(); + const history = useHistory(); + const getStyles = (index) => { + let obj = {} + switch (index) { + case 1: + obj = { "width": "1vw" } + break; + case 2: + obj = { "width": "60vw" } + break; + case 3: + obj = { "width": "20vw" } + break; + case 4: + obj = { "width": "10vw" } + break; + default: + obj = { "width": "1vw" } + break; + } + return obj + } + const renderHeader = (headers) => { + return headers?.map((key, index) => { + return + }) + } + + const renderBody = (rows) => { + return rows?.map((row, index) => { + return + + + {row[1] === t("WORKS_TOTAL_AMT") + ? + : } + {row[3] && } + {/* */} + + }) + } + + return ( +
{t(key)}
{row[0]} { row[1] === t("WORKS_TOTAL_AMT") ?
{row[1]}
:
{row[1]}
}
{row[2]}
{row[2]}
+
history.push( + { + pathname: `/digit-ui/employee/contracts/create-contract?estimateNumber=${data?.state?.estimateNumber}&task=${data?.state?.estimateDetails[index]?.name}&subEstimate=${data?.state?.estimateDetails[index]?.estimateDetailNumber}`, + state:{index, data} + } + )}> + {row[3]} +
+
{showDelete() && removeRow(row)}>}
+ + {renderHeader(data?.headers)} + + + {renderBody(data?.tableRows)} + {/* + + + + + */} + +
+ ) +} + +export default SubWorkTableDetails \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLCaption.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLCaption.js new file mode 100644 index 00000000000..e5fbcde20cd --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLCaption.js @@ -0,0 +1,34 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import { TelePhone, DisplayPhotos, UnMaskComponent } from "@egovernments/digit-ui-react-components"; +import Reason from "./Reason"; + +const TLCaption = ({ data,OpenImage,privacy={}}) => { + + const { t } = useTranslation(); + return ( +
+ {data.date &&

{data.date}

} +

{data.name}

+ {data.mobileNumber && + +

    

+ +
} + {data.source &&

{t("ES_APPLICATION_DETAILS_APPLICATION_CHANNEL_" + data.source.toUpperCase())}

} + {data.comment && } + {data?.wfComment ?
{data?.wfComment?.map( e => +
+

{t("WF_COMMON_COMMENTS")}

+

{e}

+
+ )}
: null} + {data?.thumbnailsToShow?.thumbs?.length > 0 ?
+

{t("CS_COMMON_ATTACHMENTS")}

+ {OpenImage(src, index,data?.thumbnailsToShow)}} /> +
: null} +
+ ); +}; + +export default TLCaption; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeAccessories.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeAccessories.js new file mode 100644 index 00000000000..536a2ce3eca --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeAccessories.js @@ -0,0 +1,52 @@ + +import React from "react"; +import { useTranslation } from "react-i18next"; +import { CardSubHeader, StatusTable, Row, CardSectionHeader } from "@egovernments/digit-ui-react-components"; + +function TLTradeAccessories({ units }) { + const { t } = useTranslation(); + return ( + + {units.map((unit, index) => ( + // TODO, Later will move to classes +
+ {`${t(unit?.title)} ${index + 1}`} + + +
+ {unit?.values?.map((value, index) => { + if (value.map === true && value.value !== "N/A") { + return } />; + } + return ( + + ); + })} +
+
+
+ ))} +
+ ); +} + +export default TLTradeAccessories; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeUnits.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeUnits.js new file mode 100644 index 00000000000..bf1c1fbc780 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeUnits.js @@ -0,0 +1,51 @@ +import React from "react"; +import { useTranslation } from "react-i18next"; +import { CardSubHeader, StatusTable, Row, CardSectionHeader } from "@egovernments/digit-ui-react-components"; + +function TLTradeUnits({ units }) { + const { t } = useTranslation(); + return ( + + {units.map((unit, index) => ( + // TODO, Later will move to classes +
+ {`${t(unit?.title)} ${index + 1}`} + + +
+ {unit?.values?.map((value, index) => { + if (value.map === true && value.value !== "N/A") { + return } />; + } + return ( + + ); + })} +
+
+
+ ))} +
+ ); +} + +export default TLTradeUnits; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ViewBreakup.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ViewBreakup.js new file mode 100644 index 00000000000..5608aeb2d2a --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ViewBreakup.js @@ -0,0 +1,73 @@ +import React, { useState, Fragment } from "react"; +import { useTranslation } from "react-i18next"; +import { CardSectionHeader, Modal, Row, StatusTable } from "@egovernments/digit-ui-react-components"; + +const ViewBreakup = ({ wsAdditionalDetails, workflowDetails }) => { + const { t } = useTranslation(); + const [popup, showPopUp] = useState(false); + const [breakUpData, setBreakUpData] = useState({}); + + const Heading = (props) => { + return

{props.label}

; + }; + + const Close = () => ( + + + + + ); + + const CloseBtn = (props) => { + return ( +
+ +
+ ); + }; + + const onPopupOpen = () => { + let breakupData = wsAdditionalDetails.additionalDetails.data || {}; + const sessionBillData = sessionStorage.getItem("Digit.ADHOC_BILL_ADD_REBATE_DATA"); + const sessionBillFormData = sessionBillData ? JSON.parse(sessionBillData) : {}; + if (sessionBillFormData?.value?.totalAmount) breakupData = sessionBillFormData?.value; + setBreakUpData(breakupData); + showPopUp(true); + } + + return ( + +
+ {wsAdditionalDetails?.additionalDetails?.isViewBreakup ?
onPopupOpen()} style={{ marginTop: "12px" }}> + {t("WS_PAYMENT_VIEW_BREAKUP")} +
: null + } + {popup && + } + headerBarEnd={ { showPopUp(false); }} />} + hideSubmit={true} + popupStyles={{ overflowY: "auto" }} //maxHeight: "calc(100% - 90px)" + headerBarMainStyle={{ marginBottom: "0px" }} + popupModuleMianStyles={{ paddingTop: "0px" }} + > + { + {t("WS_APPLICATION_FEE_HEADER")} + {breakUpData?.billSlabData?.FEE?.map(data => ₹{Number(data?.amount) || 0}} textStyle={{ textAlign: "right" }} />)} +
+ ₹{Number(breakUpData?.fee) || 0}} textStyle={{ textAlign: "right", fontWeight: "700", fontSize: "24px" }} /> + {t("WS_SERVICE_FEE_HEADER")} + {breakUpData?.billSlabData?.CHARGES?.map(data => ₹{Number(data?.amount) || 0}} textStyle={{ textAlign: "right" }} />)} +
+ ₹{Number(breakUpData?.charge) || 0}} textStyle={{ textAlign: "right", fontWeight: "700", fontSize: "24px" }} /> + {breakUpData?.billSlabData?.TAX?.map(data => ₹{Number(data?.amount) || 0}} textStyle={{ textAlign: "right" }} />)} +
+ ₹{Number(breakUpData?.totalAmount) || 0}} textStyle={{ textAlign: "right", fontWeight: "700", fontSize: "24px" }} /> +
} +
} +
+
+ ) +} + +export default ViewBreakup; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSAdditonalDetails.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSAdditonalDetails.js new file mode 100644 index 00000000000..06814062d96 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSAdditonalDetails.js @@ -0,0 +1,399 @@ +import { StatusTable, Row, CardSubHeader } from "@egovernments/digit-ui-react-components"; +import React, { Fragment } from "react"; +import { useTranslation } from "react-i18next"; +import { getQueryStringParams } from "../../../ws/src/utils"; + +const cardSubHeaderStyles = () => { + // return { fontSize: "24px", padding: "0px", margin: "0px", color: "#505A5F" }; + return { fontSize: "24px", marginBottom: "16px", marginTop: "32px" }; +}; + +const cardDivStyles = () => { + return { + border: "1px solid #D6D5D4", + background: "#FAFAFA", + borderRadius: "4px", + padding: "10px 10px 0px 10px", + marginBottom: "10px", + display: "flex", + }; +}; + +const convertEpochToDate = (dateEpoch) => { + if (dateEpoch) { + const dateFromApi = new Date(dateEpoch); + let month = dateFromApi.getMonth() + 1; + let day = dateFromApi.getDate(); + let year = dateFromApi.getFullYear(); + month = (month > 9 ? "" : "0") + month; + day = (day > 9 ? "" : "0") + day; + return `${day}/${month}/${year}`; + } else { + return null; + } +}; + +const WSAdditonalDetails = ({ wsAdditionalDetails, oldValue }) => { + const { t } = useTranslation(); + let filters = getQueryStringParams(location.search); + const serviceType = filters?.service; + const isModify = filters?.mode; + + const oldValueData = oldValue?.[1]; + + const stringReplaceAll = (str = "", searcher = "", replaceWith = "") => { + if (searcher == "") return str; + while (str.includes(searcher)) { + str = str.replace(searcher, replaceWith); + } + return str; + }; + + const renderSWConnectionDetails = () => { + return ( +
+ {oldValueData?.connectionType ? ( + + ) : ( +
{"NA"}
+ )} + + {oldValueData?.noOfWaterClosets ? ( + + ) : ( +
{"NA"}
+ )} + {oldValueData?.noOfToilets ? ( + + ) : ( +
{"NA"}
+ )} +
+ ); + }; + + const renderWSConnectionDetails = () => { + return ( +
+ {oldValueData?.connectionType && ( )} + {oldValueData?.noOfTaps && ( )} + {oldValueData?.waterSource && ( )} + {oldValueData?.pipeSize && ( )} + {oldValueData?.waterSource && ( )} +
+ ); + }; + + const renderSWPlumberDetails = () => { + return ( +
+ {oldValueData?.additionalDetails?.detailsProvidedBy !== wsAdditionalDetails?.additionalDetails?.plumberDetails[0]?.value && + oldValueData?.additionalDetails?.detailsProvidedBy !== null ? ( + + ) : ( +
{"NA"}
+ )} + {oldValueData?.plumberInfo ? ( + + ) : ( +
{"NA"}
+ )} + {oldValueData?.plumberInfo ? ( + + ) : ( +
{"NA"}
+ )} + {oldValueData?.plumberInfo ? ( + + ) : ( +
{"NA"}
+ )} +
+ ); + }; + + const renderWSPlumberDetails = () => { + return ( +
+ {oldValueData?.additionalDetails?.detailsProvidedBy !== wsAdditionalDetails?.additionalDetails?.plumberDetails[0]?.value ? ( + + ) : ( +
{"NA"}
+ )} +
+ ); + }; + + const renderSWRoadCuttingDetails = () => { + { + oldValueData?.roadCuttingInfo?.map((info) => { + return ( +
+ + +
+ ); + }); + } + }; + + const renderSWActivationDetails = () => { + return ( +
+ {oldValueData?.connectionExecutionDate ? ( + + ) : ( +
{"NA"}
+ )} +
+ ); + }; + + const renderWSActivationDetails = () => { + return ( +
+ {oldValueData?.meterId && ( )} + {oldValueData?.additionalDetails?.initialMeterReading && ( )} + {oldValueData?.meterInstallationDate && ( )} + {oldValueData?.connectionExecutionDate && ( )} +
+ ); + }; + + var { connectionDetails, plumberDetails, roadCuttingDetails, activationDetails } = wsAdditionalDetails?.additionalDetails || {connectionDetails:[], plumberDetails: []}; + + // binding old values with new values + if(isModify === "MODIFY"){ + + connectionDetails = connectionDetails?.map((value) => { + if(value.title == "WS_SERV_DETAIL_CONN_TYPE" && oldValueData?.connectionType) value["oldValue"] = [ + { value:value?.value, className:"newValue", style:{ display:"inline"} }, + { + value:`${t("WS_OLD_LABEL_NAME")} ${oldValueData?.connectionType}`, + className:"oldValue", style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"} + }]; + if(value.title == "WS_SERV_DETAIL_NO_OF_TAPS" && oldValueData?.noOfTaps) value["oldValue"] = [ + {value:value?.value,className:"newValue", style:{ display:"inline"}}, + {value:`${t("WS_OLD_LABEL_NAME")} ${oldValueData?.noOfTaps}`, style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"},className:"oldValue"} + ]; + if(value.title == "WS_SERV_DETAIL_WATER_SOURCE" && oldValueData?.waterSource) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${t(oldValueData?.waterSource?.toUpperCase()?.split(".")[0])}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + if(value.title == "WS_PIPE_SIZE_IN_INCHES_LABEL" && oldValueData?.pipeSize) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.pipeSize}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + if(value.title == "WS_SERV_DETAIL_WATER_SUB_SOURCE" && oldValueData?.waterSource) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${t(oldValueData?.waterSource?.toUpperCase()?.split(".")[1])}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + if(value.title == "WS_NUMBER_WATER_CLOSETS_LABEL" && oldValueData?.noOfWaterClosets) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.noOfWaterClosets}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + if(value.title == "WS_SERV_DETAIL_NO_OF_TOILETS" && oldValueData?.noOfWaterClosets) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.noOfWaterClosets}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + + return value; + }) + + plumberDetails = plumberDetails?.map((value) => { + if(value.title == "WS_ADDN_DETAILS_PLUMBER_PROVIDED_BY" && oldValueData?.additionalDetails?.detailsProvidedBy && oldValueData?.additionalDetails?.detailsProvidedBy !== value.value ) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.additionalDetails?.detailsProvidedBy}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + if(value.title == "WS_ADDN_DETAILS_PLUMBER_LICENCE_NO_LABEL" && oldValueData?.plumberInfo[0]?.licenseNo ) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.plumberInfo[0]?.licenseNo}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + if(value.title == "WS_ADDN_DETAILS_PLUMBER_NAME_LABEL" && oldValueData?.plumberInfo[0]?.name ) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.plumberInfo[0]?.name}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + if(value.title == "WS_PLUMBER_MOBILE_NO_LABEL" && oldValueData?.plumberInfo[0]?.mobileNumber ) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.plumberInfo[0]?.mobileNumber}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + return value; + }) + + roadCuttingDetails = roadCuttingDetails?.map((roadDetail) => { + const roadDetailValues = roadDetail?.values?.map((value) => { + if(value.title == "WS_ADDN_DETAIL_ROAD_TYPE" && oldValueData?.roadCuttingInfo[0]?.roadType) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.roadCuttingInfo[0]?.roadType}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + if(value.title == "WS_ROAD_CUTTING_AREA_LABEL" && oldValueData?.roadCuttingInfo[0]?.roadCuttingArea) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.roadCuttingInfo[0]?.roadCuttingArea}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + return value; + }) + return ({...roadDetail,values:roadDetailValues}); + }) + + activationDetails = activationDetails?.map((value) => { + if(value.title == "WS_SERV_DETAIL_CONN_EXECUTION_DATE" && oldValueData?.connectionExecutionDate) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${convertEpochToDate(oldValueData?.connectionExecutionDate)}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + + if(value.title == "WS_SERV_DETAIL_METER_ID" && oldValueData?.meterId) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.meterId}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + + if(value.title == "WS_INITIAL_METER_READING_LABEL" && oldValueData?.initialMeterReading) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.initialMeterReading}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + + if(value.title == "WS_INSTALLATION_DATE_LABEL" && oldValueData?.meterInstallationDate) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${convertEpochToDate(oldValueData?.meterInstallationDate)}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + if(value.title == "WS_SERV_DETAIL_CONN_EXECUTION_DATE" && oldValueData?.connectionExecutionDate) value["oldValue"] = [ + {value:value?.value, className:"newValue", style:{ display:"inline"}}, + { + value: `${t("WS_OLD_LABEL_NAME")} ${convertEpochToDate(oldValueData?.connectionExecutionDate)}`, + style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" + } + ]; + return value; + }) + }; + + return ( + +
+ {wsAdditionalDetails?.additionalDetails?.connectionDetails && ( + + {t("WS_COMMON_CONNECTION_DETAIL")} +
+
+ {connectionDetails?.map((value, index) => { + return ( +
+ +
+ ); + })} +
+
+
+ )} + {wsAdditionalDetails?.additionalDetails?.plumberDetails && ( + + {t("WS_COMMON_PLUMBER_DETAILS")} +
+
+ + {plumberDetails?.map((value, index) => { + return ; + })} +
+
+
+ )} + {wsAdditionalDetails?.additionalDetails?.roadCuttingDetails && ( + + {t("WS_ROAD_CUTTING_DETAILS")} +
+
+ {roadCuttingDetails?.map((value) => { + return ( +
1 + ? { + border: "1px solid #D6D5D4", + background: "#FAFAFA", + borderRadius: "4px", + padding: "10px 10px 0px 10px", + margin: "5px 0px", + } + : {} + } + > + {value?.values?.map((roadValue) => ( + + ))} +
+ ); + })} +
+
+
+ )} + {wsAdditionalDetails?.additionalDetails?.activationDetails && ( + + {t("WS_ACTIVATION_DETAILS")} +
+
+ {activationDetails?.map((value, index) => { + return ( + + ); + })} +
+
+
+ )} +
+
+ ); +}; + +export default WSAdditonalDetails; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSFeeEstimation.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSFeeEstimation.js new file mode 100644 index 00000000000..9a4fe591f9d --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSFeeEstimation.js @@ -0,0 +1,346 @@ +import React, { useState, Fragment, useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import { Card, CardSectionHeader, CardLabel } from "@egovernments/digit-ui-react-components"; +import { Modal, Dropdown, Row, StatusTable, TextInput, Toast } from "@egovernments/digit-ui-react-components"; +import cloneDeep from "lodash/cloneDeep"; + +const Penality_menu = [ + { + title: "PT_PENDING_DUES_FROM_EARLIER", + value: "Pending dues from earlier", + }, + { + title: "PT_MISCALCULATION_OF_EARLIER_ASSESSMENT", + value: "Miscalculation of earlier Assessment", + }, + { + title: "PT_ONE_TIME_PENALITY", + value: "One time penality", + }, + { + title: "PT_OTHERS", + value: "Others", + }, +] +const Rebate_menu = [ + { + title: "PT_ADVANCED_PAID_BY_CITIZEN_EARLIER", + value: "Advanced Paid By Citizen Earlier", + }, + { + title: "PT_REBATE_PROVIDED_BY_COMMISSIONER_EO", + value: "Rebate provided by commissioner/EO", + }, + { + title: "PT_ADDITIONAL_AMOUNT_CHARGED_FROM_THE_CITIZEN", + value: "Additional amount charged from the citizen", + }, + { + title: "PT_OTHERS", + value: "Others", + }, +]; + + +const WSFeeEstimation = ({ wsAdditionalDetails, workflowDetails }) => { + const { t } = useTranslation(); + const [sessionFormData, setSessionFormData, clearSessionFormData] = Digit.Hooks.useSessionStorage("ADHOC_ADD_REBATE_DATA", {}); + const [sessionBillFormData, setSessionBillFormData, clearBillSessionFormData] = Digit.Hooks.useSessionStorage("ADHOC_BILL_ADD_REBATE_DATA", {}); + const isPaid = wsAdditionalDetails?.additionalDetails?.isPaid ? true : false; + const [popup, showPopUp] = useState(false); + const [fields, setFields] = useState(sessionFormData ? sessionFormData : {}); + const [showToast, setShowToast] = useState(null); + const [billDetails, setBillDetails] = useState(wsAdditionalDetails.additionalDetails.data ? wsAdditionalDetails.additionalDetails.data : {}); + const [values, setValues] = useState(wsAdditionalDetails.additionalDetails.values ? wsAdditionalDetails.additionalDetails.values : []); + + const stateCode = Digit.ULBService.getStateId(); + const { isMdmsLoading, data: mdmsRes } = Digit.Hooks.ws.useMDMS(stateCode, "BillingService", ["TaxHeadMaster"]); + + useEffect(() => { + const data = { ...wsAdditionalDetails?.additionalDetails?.appDetails?.additionalDetails }; + setSessionFormData(data); + setFields(data); + if (sessionFormData?.billDetails?.length > 0) { + const values = [ + { title: "WS_APPLICATION_FEE_HEADER", value: sessionFormData?.billDetails?.[0]?.fee }, + { title: "WS_SERVICE_FEE_HEADER", value: sessionFormData?.billDetails?.[0]?.charge }, + { title: "WS_TAX_HEADER", value: sessionFormData?.billDetails?.[0]?.taxAmount }, + ]; + setValues(values); + setBillDetails(sessionFormData?.billDetails?.[0]); + } + }, []); + + let validation = {}; + + const Heading = (props) => { + return

{props.label}

; + }; + + const Close = () => ( + + + + + ); + + const CloseBtn = (props) => { + return ( +
+ +
+ ); + }; + + const closeToast = () => { + setShowToast(false); + }; + + const addAdhocRebatePenality = (e) => { + const adhocAmount = fields?.adhocPenalty ? Number(fields?.adhocPenalty) : 0; + const rebateAmount = fields?.adhocRebate ? Number(fields?.adhocRebate) : 0; + if (adhocAmount || rebateAmount) { + + const totalAmount = wsAdditionalDetails?.additionalDetails?.data?.totalAmount; + const demandId = wsAdditionalDetails?.additionalDetails?.data?.billDetails?.[0]?.demandId; + + if (rebateAmount > totalAmount) { + setShowToast({ isError: false, isWarning: true, key: "error", message: t("ERR_WS_REBATE_GREATER_THAN_AMOUNT") }); + } else { + const applicationNo = wsAdditionalDetails?.additionalDetails?.appDetails?.applicationNo; + const tenantId = wsAdditionalDetails?.additionalDetails?.appDetails?.tenantId; + const appAdditionalDetails = { ...wsAdditionalDetails?.additionalDetails?.appDetails?.additionalDetails, ...fields } + wsAdditionalDetails.additionalDetails.appDetails.additionalDetails = appAdditionalDetails; + + const data = { + CalculationCriteria: + wsAdditionalDetails?.additionalDetails?.appDetails?.service == "WATER" + ? [ + { + applicationNo: applicationNo, + tenantId: tenantId, + waterConnection: wsAdditionalDetails.additionalDetails.appDetails, + }, + ] + : [ + { + applicationNo: applicationNo, + tenantId: tenantId, + sewerageConnection: wsAdditionalDetails.additionalDetails.appDetails, + }, + ], + isconnectionCalculation: false, + }; + + let businessService = wsAdditionalDetails?.additionalDetails?.appDetails?.service == "WATER" ? "WS" : "SW"; + Digit.WSService.wsCalculationEstimate(data, businessService) + .then((result, err) => { + if (result?.Calculation?.[0]?.taxHeadEstimates?.length > 0) { + result?.Calculation?.[0]?.taxHeadEstimates?.forEach(data => data.amount = data.estimateAmount); + } + + result.Calculation[0].billSlabData = _.groupBy(result?.Calculation?.[0]?.taxHeadEstimates, 'category'); + const values = [ + { title: "WS_APPLICATION_FEE_HEADER", value: result.Calculation?.[0]?.fee }, + { title: "WS_SERVICE_FEE_HEADER", value: result.Calculation?.[0]?.charge }, + { title: "WS_TAX_HEADER", value: result.Calculation?.[0]?.taxAmount }, + ]; + setSessionBillFormData(cloneDeep(result.Calculation[0])); + setBillDetails(result?.Calculation?.[0]); + setValues(values); + fields.billDetails = result?.Calculation; + setSessionFormData(fields); + showPopUp(false); + }) + .catch((e) => { + setShowToast({ isError: true, isWarning: false, key: "error", message: e?.response?.data?.Errors[0]?.message ? t(`${e?.response?.data?.Errors[0]?.code}`) : t("PT_COMMON_ADD_REBATE_PENALITY") }); + }); + } + } else { + setShowToast({ isError: false, isWarning: true, key: "warning", message: t("ERR_WS_ENTER_ATLEAST_ONE_FIELD") }); + } + } + + const selectedValuesData = (value, isDropDownValue = false, e) => { + let values = { ...fields }; + if (isDropDownValue) { + values[`${value}_data`] = e; + values[value] = e.title; + if (e.title == "PT_OTHERS" && value == "adhocPenaltyReason") values[`adhocPenaltyComment`] = ""; + if (e.title == "PT_OTHERS" && value == "adhocRebateReason") values[`adhocRebateComment`] = ""; + } else { + values[value] = e.target.value; + } + setFields(values); + } + + return ( + +
+ {values && + +
+ {values?.map((value, index) => { + return + })} +
+
+
+ + +
+
} + { + wsAdditionalDetails?.additionalDetails?.isAdhocRebate ?
{ + showPopUp(true) + }} + > + {t("WS_PAYMENT_ADD_REBATE_PENALTY")} +
: null + } + {popup && + } + headerBarEnd={ + { + setFields(sessionFormData); + showPopUp(false); + }} />} + actionCancelLabel={t("PT_CANCEL")} + actionCancelOnSubmit={() => { + setFields(sessionFormData); + showPopUp(false); + }} + actionSaveLabel={t("PT_ADD")} + actionSaveOnSubmit={(e) => addAdhocRebatePenality(e)} + hideSubmit={false} + popupStyles={{ overflowY: "auto" }} + > + { +
+ + {t("PT_AD_PENALTY")} + + {t("PT_TX_HEADS")} + +
+ selectedValuesData("adhocPenaltyReason", true, e)} + selected={fields?.adhocPenaltyReason_data || ""} + isPropertyAssess={true} + name={"adhocPenaltyReason_data"} + t={t} + /> +
+ {fields?.adhocPenaltyReason_data?.title === "PT_OTHERS" &&
+ {t("PT_REASON")} +
+ selectedValuesData("adhocPenaltyComment", false, e)} + {...(validation = { + isRequired: true, + pattern: "^[a-zA-Z-.`' ]*$", + type: "text", + title: t("TL_NAME_ERROR_MESSAGE"), + })} + /> +
+
} + {t("PT_HEAD_AMT")} +
+ selectedValuesData("adhocPenalty", false, e)} + {...(validation = { + isRequired: true, + pattern: "^[1-9]+[0-9]*$", + title: t("ERR_DEFAULT_INPUT_FIELD_MSG"), + })} + /> + +
+
+ + {t("PT_AD_REBATE")} + {t("PT_TX_HEADS")} +
+ selectedValuesData("adhocRebateReason", true, e)} + selected={fields?.adhocRebateReason_data || ""} + name={"adhocRebateReason_data"} + isPropertyAssess={true} + t={t} + /> +
+ {fields?.adhocRebateReason_data?.title === "PT_OTHERS" &&
+ {t("PT_REASON")} + selectedValuesData("adhocRebateComment", false, e)} + {...(validation = { + isRequired: true, + pattern: "^[a-zA-Z-.`' ]*$", + type: "text", + title: t("TL_NAME_ERROR_MESSAGE"), + })} + /> +
} + {t("PT_HEAD_AMT")} +
+ selectedValuesData("adhocRebate", false, e)} + {...(validation = { + isRequired: true, + pattern: "^[1-9]+[0-9]*$", + title: t("ERR_DEFAULT_INPUT_FIELD_MSG"), + })} + /> +
+
+
+ }
} + {showToast && + } +
+
+ ) +} + +export default WSFeeEstimation; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WeekDateRange.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WeekDateRange.js new file mode 100644 index 00000000000..75069dd741f --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WeekDateRange.js @@ -0,0 +1,30 @@ +import React, { useCallback, useState } from "react"; +import { useTranslation } from "react-i18next"; + +const WeekDateRange = (props) => { + const [localSearchParams, setLocalSearchParams] = useState(() => ({})); + const { t } = useTranslation(); + const handleChange = useCallback((data) => { + setLocalSearchParams(() => ({ ...data })); + }, []); + + return ( +
+
+

{props.title}

+
+ +
+
+
+ ); +}; + +export default WeekDateRange; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AcceptDso.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AcceptDso.js new file mode 100644 index 00000000000..e870f2e9a67 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AcceptDso.js @@ -0,0 +1,45 @@ +import React from "react"; +import { Dropdown } from "@egovernments/digit-ui-react-components"; + +export const configAcceptDso = ({ t, dsoData, dso, selectVehicleNo, vehicleNoList, vehicleNo, vehicle, action }) => { + return { + label: { + heading: `ES_FSM_ACTION_TITLE_${action}`, + submit: `CS_COMMON_${action}`, + cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + label: t("ES_FSM_ACTION_VEHICLE_REGISTRATION_NO"), + isMandatory: true, + type: "dropdown", + populators: ( + + ), + }, + { + label: t("ES_FSM_ACTION_VEHICLE_CAPACITY_IN_LTRS"), + isMandatory: true, + type: "text", + populators: { + name: "capacity", + validation: { + required: true, + }, + }, + disable: true, + }, + ], + }, + ], + }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AssignDso.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AssignDso.js new file mode 100644 index 00000000000..418caf1e4bc --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AssignDso.js @@ -0,0 +1,115 @@ +import React from "react"; +import { DatePicker, Dropdown, CardLabelError } from "@egovernments/digit-ui-react-components"; + +function todayDate() { + var today = new Date(); + var dd = today.getDate(); + var mm = today.getMonth() + 1; + var yyyy = today.getFullYear(); + + if (dd < 10) { + dd = "0" + dd; + } + + if (mm < 10) { + mm = "0" + mm; + } + + return yyyy + "-" + mm + "-" + dd; +} + +function getFilteredDsoData(dsoData, vehicle) { + return dsoData?.filter((e) => e.vehicles?.find((veh) => veh?.type == vehicle?.code)); +} + +export const configAssignDso = ({ t, dsoData, dso, selectDSO, vehicleMenu, vehicle, selectVehicle, action }) => { + return { + label: { + heading: `ES_FSM_ACTION_TITLE_${action}`, + submit: `CS_COMMON_${action}`, + cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + label: t("ES_FSM_ACTION_VEHICLE_TYPE"), + isMandatory: true, + type: "dropdown", + populators: ( + + ), + }, + { + label: t("ES_FSM_ACTION_DSO_NAME"), + isMandatory: true, + type: "dropdown", + populators: ( + + {getFilteredDsoData(dsoData, vehicle) && !getFilteredDsoData(dsoData, vehicle).length ? ( + {t("ES_COMMON_NO_DSO_AVAILABLE_WITH_SUCH_VEHICLE")} + ) : null} + + + ), + }, + { + label: t("ES_FSM_ACTION_VEHICLE_CAPACITY_IN_LTRS"), + isMandatory: true, + type: "text", + populators: { + name: "capacity", + validation: { + required: true, + }, + }, + disable: true, + }, + // { + // label: t("ES_FSM_ACTION_SERVICE_DATE"), + // isMandatory: true, + // type: "date", + // populators: { + // name: "date", + // validation: { + // required: true, + // }, + // min: Digit.Utils.date.getDate(), + // defaultValue: Digit.Utils.date.getDate(), + // }, + // }, + { + label: t("ES_FSM_ACTION_SERVICE_DATE"), + isMandatory: true, + type: "custom", + populators: { + name: "date", + validation: { + required: true, + }, + customProps: { min: Digit.Utils.date.getDate() }, + defaultValue: Digit.Utils.date.getDate(), + component: (props, customProps) => , + }, + }, + ], + }, + ], + }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAApproverApplication.js new file mode 100644 index 00000000000..ca66865bb77 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAApproverApplication.js @@ -0,0 +1,77 @@ +import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; +import React from "react"; + +export const configBPAApproverApplication = ({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + assigneeLabel, + businessService, + error +}) => { + let isRejectOrRevocate = false; + if(action?.action == "REVOCATE" || action?.action == "REJECT" || action.action == "SKIP_PAYMENT" || action?.action == "SEND_BACK_TO_CITIZEN" || action?.action == "APPROVE") { + isRejectOrRevocate = true; + } + + let isCommentRequired = false; + if(action?.action == "REVOCATE" || action?.action == "REJECT") { + isCommentRequired = true; + } + + return { + label: { + heading: `WF_${action?.action}_APPLICATION`, + submit: `WF_${businessService}_${action?.action}`, + cancel: "BPA_CITIZEN_CANCEL_BUTTON", + }, + form: [ + { + body: [ + { + label: action.isTerminateState || isRejectOrRevocate ? null : t(assigneeLabel || `WF_ROLE_${action.assigneeRoles?.[0]}`), + type: "dropdown", + populators: action.isTerminateState || isRejectOrRevocate ? null : ( + + ), + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + isMandatory: isCommentRequired, + populators: { + name: "comments", + }, + }, + { + label: `${t("WF_APPROVAL_UPLOAD_HEAD")}`, + populators: ( + { + setUploadedFile(null); + }} + message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} + accept= "image/*, .pdf, .png, .jpeg, .jpg" + iserror={error} + /> + ), + }, + ], + }, + ], + }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAREGApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAREGApproverApplication.js new file mode 100644 index 00000000000..0bdba14bc5b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAREGApproverApplication.js @@ -0,0 +1,71 @@ +import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; +import React from "react"; + +export const configBPAREGApproverApplication = ({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + assigneeLabel, + businessService, + error +}) => { + let checkCondtions = true; + if (action?.action == "SENDBACKTOCITIZEN") checkCondtions = false; + if (action.isTerminateState) checkCondtions = false; + + return { + label: { + heading: `WF_${action?.action}_APPLICATION`, + submit: `WF_${businessService?.toUpperCase()}_${action?.action}`, + cancel: "WF_EMPLOYEE_BPAREG_CANCEL", + }, + form: [ + { + body: [ + { + label: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_LABEL"), + placeholder: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + type: "dropdown", + populators: !checkCondtions ? null : ( + + ), + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + { + label: t("BPA_APPROVAL_CHECKLIST_BUTTON_UP_FILE"), + populators: ( + { + setUploadedFile(null); + }} + message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} + accept= "image/*, .pdf, .png, .jpeg, .jpg" + iserror={error} + /> + ) + }, + ], + }, + ], + }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/CompleteApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/CompleteApplication.js new file mode 100644 index 00000000000..a4c7c96b2fd --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/CompleteApplication.js @@ -0,0 +1,46 @@ +import React from "react"; +import { DatePicker } from "@egovernments/digit-ui-react-components"; + +export const configCompleteApplication = ({ t, vehicle, applicationCreatedTime = 0, action }) => ({ + label: { + heading: `ES_FSM_ACTION_TITLE_${action}`, + submit: `CS_COMMON_${action}`, + cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + label: t("ES_FSM_ACTION_DESLUGED_DATE_LABEL"), + isMandatory: true, + type: "custom", + populators: { + name: "desluged", + validation: { + required: true, + }, + defaultValue: Digit.Utils.date.getDate(), + customProps: { + min: Digit.Utils.date.getDate(applicationCreatedTime), + max: Digit.Utils.date.getDate(), + }, + component: (props, customProps) => , + }, + }, + { + label: t("ES_FSM_ACTION_WASTE_VOLUME_LABEL"), + type: "text", + isMandatory: true, + populators: { + name: "wasteCollected", + validation: { + required: true, + validate: (value) => parseInt(value) <= parseInt(vehicle.capacity), + }, + error: `${t("ES_FSM_ACTION_INVALID_WASTE_VOLUME")} ${vehicle?.capacity} ${t("CS_COMMON_LITRES")}`, + }, + }, + ], + }, + ], +}); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/NOCApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/NOCApproverApplication.js new file mode 100644 index 00000000000..12922b0575e --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/NOCApproverApplication.js @@ -0,0 +1,79 @@ +import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; +import React from "react"; + +export const configNOCApproverApplication = ({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + assigneeLabel, + businessService, + error +}) => { + + let isCommentRequired = false; + if(action?.action == "REVOCATE" || action?.action == "REJECT") { + isCommentRequired = true; + } + + let isRejectOrRevocate = false; + if(action?.action == "APPROVE" || action?.action == "REJECT" || action.action == "AUTO_APPROVE" || action.action == "AUTO_REJECT") { + isRejectOrRevocate = true; + } + + return { + label: { + heading: `WF_${action?.action}_APPLICATION`, + submit: `WF_${businessService}_${action?.action}`, + cancel: "CORE_LOGOUTPOPUP_CANCEL", + }, + form: [ + { + body: [ + { + label: action.isTerminateState || isRejectOrRevocate ? null : t(assigneeLabel || `WF_ROLE_${action.assigneeRoles?.[0]}`), + type: "dropdown", + populators: action.isTerminateState || isRejectOrRevocate ? null : ( + + ), + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + isMandatory: isCommentRequired, + populators: { + name: "comments", + }, + }, + { + label: `${t("WF_APPROVAL_UPLOAD_HEAD")}`, + populators: ( + { + setUploadedFile(null); + }} + showHint={true} + message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} + accept= "image/*, .pdf, .png, .jpeg, .jpg" + iserror={error} + /> + ), + }, + ], + }, + ], + }; +}; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTApproverApplication.js new file mode 100644 index 00000000000..afcc6a19be2 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTApproverApplication.js @@ -0,0 +1,66 @@ +import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; +import React from "react"; + +export const configPTApproverApplication = ({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + assigneeLabel, + businessService, +}) => { + return { + label: { + heading: `WF_${action?.action}_APPLICATION`, + submit: `WF_${businessService}_${action?.action}`, + cancel: "ES_PT_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + label: action.isTerminateState || action?.action === "SENDBACKTOCITIZEN" ? null : t(assigneeLabel || `WF_ROLE_${action.assigneeRoles?.[0]}`), + // isMandatory: !action.isTerminateState, + type: "dropdown", + populators: action.isTerminateState || action?.action === "SENDBACKTOCITIZEN" ? null : ( + + ), + }, + { + label: t("ES_PT_ACTION_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + { + label: `${t("ES_PT_ATTACH_FILE")}${action.docUploadRequired ? " *" : ""}`, + populators: ( + { + setUploadedFile(null); + }} + showHint={true} + hintText={t("PT_ATTACH_RESTRICTIONS_SIZE")} + message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`ES_PT_ACTION_NO_FILEUPLOADED`)} + /> + ), + }, + ], + }, + ], + }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTAssessProperty.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTAssessProperty.js new file mode 100644 index 00000000000..dd04037aab6 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTAssessProperty.js @@ -0,0 +1,26 @@ +import React from "react"; +import { RadioButtons } from "@egovernments/digit-ui-react-components"; + +export const configPTAssessProperty = ({ t, action, financialYears, selectedFinancialYear, setSelectedFinancialYear }) => { + return { + label: { + heading: `WF_${action.action}_APPLICATION`, + submit: `WF_PT.CREATE_${action.action}`, + cancel: "ES_PT_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + label: t("ES_PT_FINANCIAL_YEARS"), + isMandatory: true, + type: "radio", + populators: ( + + ), + }, + ], + }, + ], + }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/ReassignDso.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/ReassignDso.js new file mode 100644 index 00000000000..132a5bc6a7c --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/ReassignDso.js @@ -0,0 +1,101 @@ +import React from "react"; +import { Dropdown } from "@egovernments/digit-ui-react-components"; + +function getFilteredDsoData(dsoData, vehicle) { + return dsoData?.filter((e) => e.vehicles?.find((veh) => veh?.type == vehicle?.code)); +} + +export const configReassignDSO = ({ + t, + dsoData, + dso, + selectDSO, + vehicleMenu, + vehicle, + selectVehicle, + reassignReasonMenu, + reassignReason, + selectReassignReason, + action, + showReassignReason, +}) => ({ + label: { + heading: `ES_FSM_ACTION_TITLE_${action}`, + submit: `CS_COMMON_${action}`, + cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + ...(showReassignReason + ? [ + { + label: t("ES_FSM_ACTION_REASSIGN_REASON"), + type: "dropdown", + isMandatory: true, + populators: ( + + ), + }, + ] + : []), + { + label: t("ES_FSM_ACTION_VEHICLE_TYPE"), + isMandatory: vehicle ? false : true, + type: "dropdown", + populators: ( + + ), + }, + { + label: t("ES_FSM_ACTION_DSO_NAME"), + isMandatory: true, + type: "dropdown", + populators: ( + + ), + }, + { + label: t("ES_FSM_ACTION_VEHICLE_CAPACITY_IN_LTRS"), + type: "text", + populators: { + name: "capacity", + validation: { + required: true, + }, + }, + disable: true, + }, + { + label: t("ES_FSM_ACTION_SERVICE_DATE"), + isMandatory: true, + type: "date", + populators: { + name: "date", + validation: { + required: true, + }, + min: Digit.Utils.date.getDate(), + defaultValue: Digit.Utils.date.getDate(), + }, + }, + ], + }, + ], +}); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/RejectApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/RejectApplication.js new file mode 100644 index 00000000000..a18bdaf1110 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/RejectApplication.js @@ -0,0 +1,31 @@ +import React from "react"; +import { Dropdown } from "@egovernments/digit-ui-react-components"; + +export const configRejectApplication = ({ t, rejectMenu, setReason, reason, action }) => { + return { + label: { + heading: `ES_FSM_ACTION_TITLE_${action}`, + submit: `CS_COMMON_${action}`, + cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + label: t(`ES_FSM_ACTION_${action.toUpperCase()}_REASON`), + type: "dropdown", + populators: , + isMandatory: true, + }, + { + label: t("ES_FSM_ACTION_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ], + }, + ], + }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/TLApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/TLApproverApplication.js new file mode 100644 index 00000000000..23b20e5be2b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/TLApproverApplication.js @@ -0,0 +1,83 @@ +import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; +import React from "react"; + +export const configTLApproverApplication = ({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + assigneeLabel, + businessService, +}) => { + let checkCondtions = true; + if (action?.action == "SENDBACKTOCITIZEN" || action?.action == "APPROVE") checkCondtions = false; + if (action.isTerminateState) checkCondtions = false; + + return { + label: { + heading: `WF_${action?.action}_APPLICATION`, + submit: `WF_${businessService?.toUpperCase()}_${action?.action}`, + cancel: "WF_EMPLOYEE_NEWTL_CANCEL", + }, + form: [ + { + body: [ + { + label: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_LABEL"), + placeholder: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + // isMandatory: false, + type: "dropdown", + populators: !checkCondtions ? null : ( + + ), + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + { + label: t("TL_APPROVAL_CHECKLIST_BUTTON_UP_FILE"), + populators: ( + { + setUploadedFile(null); + }} + message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} + /> + ) + }, + // { + // label: action.docUploadRequired ? t("ES_PT_UPLOAD_FILE") : null, + // populators: action.docUploadRequired ? ( + // { + // setUploadedFile(null); + // }} + // message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`ES_PT_ACTION_NO_FILEUPLOADED`)} + // /> + // ) : null, + // }, + ], + }, + ], + }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSApproverApplication.js new file mode 100644 index 00000000000..2f5f2d45a6a --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSApproverApplication.js @@ -0,0 +1,73 @@ +import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; +import React from "react"; + +export const configWSApproverApplication = ({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + assigneeLabel, + businessService, + error +}) => { + let checkCondtions = true; + if (action?.action?.includes("SEND_BACK") || action?.action == "APPROVE_FOR_CONNECTION") checkCondtions = false; + if (action.isTerminateState) checkCondtions = false; + + return { + label: { + heading: `WF_${action?.action}_APPLICATION`, + submit: `WF_${businessService?.toUpperCase()}_${action?.action}`, + cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + label: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_LABEL"), + placeholder: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + // isMandatory: false, + type: "dropdown", + populators: !checkCondtions ? null : ( + + ), + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + { + label: t("WS_APPROVAL_CHECKLIST_BUTTON_UP_FILE"), + populators: ( + { + setUploadedFile(null); + }} + message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} + error={error} + iserror={error} + /> + ) + }, + ], + }, + ], + }; +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSDisconnectApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSDisconnectApplication.js new file mode 100644 index 00000000000..5acdcebe041 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSDisconnectApplication.js @@ -0,0 +1,89 @@ +import { Dropdown, UploadFile, DatePicker } from "@egovernments/digit-ui-react-components"; +import React from "react"; + +export const configWSDisConnectApplication = ({ + t, + action, + approvers, + selectedApprover, + setSelectedApprover, + selectFile, + uploadedFile, + setUploadedFile, + assigneeLabel, + businessService, + error +}) => { + let checkCondtions = true, isDatePickerDisplay = false; + if (action?.action?.includes("SEND_BACK") || action?.action == "APPROVE_FOR_DISCONNECTION" || action?.action == "RESUBMIT_APPLICATION") checkCondtions = false; + if (action.isTerminateState) checkCondtions = false; + if (action?.action == "EXECUTE_DISCONNECTION" || action?.action == "DISCONNECTION_EXECUTED") isDatePickerDisplay = true; + + + return { + label: { + heading: `WF_${action?.action}_APPLICATION`, + submit: `WF_${businessService?.toUpperCase()}_${action?.action}`, + cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + label: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_LABEL"), + placeholder: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + // isMandatory: false, + type: "dropdown", + populators: !checkCondtions ? null : ( + + ), + }, + isDatePickerDisplay && { + label: t("ES_FSM_ACTION_SERVICE_DATE"), + isMandatory: isDatePickerDisplay ? true : false, + type: "custom", + populators: isDatePickerDisplay ? { + name: "date", + validation: { + required: true, + }, + // customProps: { max: Digit.Utils.date.getDate() }, + defaultValue: Digit.Utils.date.getDate(), + component: (props, customProps) => , + } : null, + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + { + label: t("WS_APPROVAL_CHECKLIST_BUTTON_UP_FILE"), + populators: ( + { + setUploadedFile(null); + }} + message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} + error={error} + iserror={error} + /> + ) + }, + ], + }, + ], + }; +}; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configApproveModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configApproveModal.js new file mode 100644 index 00000000000..03beb885925 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configApproveModal.js @@ -0,0 +1,53 @@ +import { Dropdown } from '@egovernments/digit-ui-react-components'; +import React, { useState } from 'react' + +const configApproveModal = ({ + t, + action +}) => { + if(action?.action === 'ADMINSANCTION'){ + return { + label: { + heading: `WORKS_APPROVE_ESTIMATE`, + submit: `WORKS_APPROVE_ESTIMATE`, + cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ] + } + ] + } + + }else + return { + label: { + heading: `WORKS_APPROVE_LOI`, + submit: `WORKS_APPROVE_LOI`, + cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ] + } + ] + } +} + +export default configApproveModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceApproveModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceApproveModal.js new file mode 100644 index 00000000000..06a29a26339 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceApproveModal.js @@ -0,0 +1,27 @@ + +const configAttendanceApproveModal = ({ t, action }) => { + if (action?.applicationStatus === "APPROVED") { + return { + label: { + heading: t("ATM_PROCESSINGMODAL_HEADER"), + submit: t("ATM_FORWARD_FOR_APPROVAL"), + cancel: t("CS_COMMON_CANCEL"), + }, + form: [ + { + body: [ + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ], + }, + ] + }; + } +}; + +export default configAttendanceApproveModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceCheckModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceCheckModal.js new file mode 100644 index 00000000000..374219cc6d4 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceCheckModal.js @@ -0,0 +1,93 @@ +const configAttendanceCheckModal = ({ + t, + action, + businessService, + approvers, + selectedApprover, + setSelectedApprover, + designation, + selectedDesignation, + setSelectedDesignation, + department, + selectedDept, + setSelectedDept, + approverLoading = false, +}) => { + let checkConditions = true; + if (action.isTerminateState) checkConditions = false; + + if (designation?.length === 0 || department?.length === 0) return {}; + + if (action?.applicationStatus === "ATTENDANCE_CHECKED") { + return { + label: { + heading: t("ATM_PROCESSINGMODAL_HEADER"), + submit: t("ATM_FORWARD_FOR_CHECK"), + cancel: t("WORKS_CANCEL"), + }, + form: [ + { + body: [ + { + isMandatory: true, + key: "department", + type: "radioordropdown", + label: !checkConditions ? null : t("ATM_APPROVER_DEPT"), + disable: false, + populators: { + name: "department", + optionsKey: "i18nKey", + error: "Department is required", + required: true, + options: department, + }, + }, + { + isMandatory: true, + key: "designation", + type: "radioordropdown", + label: !checkConditions ? null : t("ATM_APPROVER_DESIGNATION"), + disable: false, + populators: { + name: "designation", + optionsKey: "i18nKey", + error: "Designation is required", + required: true, + options: designation, + }, + }, + { + isMandatory: true, + key: "approvers", + type: "radioordropdown", + label: !checkConditions ? null : t("WORKS_APPROVER"), + disable: false, + populators: { + name: "approvers", + optionsKey: "nameOfEmp", + error: "Designation is required", + required: true, + options: approvers, + }, + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ], + }, + ], + defaultValues: { + department: "", + designation: "", + approvers: "", + comments: "", + }, + }; + } +}; + +export default configAttendanceCheckModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceRejectModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceRejectModal.js new file mode 100644 index 00000000000..c732127aac7 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceRejectModal.js @@ -0,0 +1,61 @@ +import { LabelFieldPair,CardLabel} from '@egovernments/digit-ui-react-components'; +import React from 'react' + +const configAttendanceRejectModal = ({ + t, + empDepartment, + empDesignation, + empName +}) => { + + const fieldLabelStyle = { + "display" : "grid", + "gridTemplateColumns" : "60% 1fr" + }; + + return { + label: { + heading: t("ATM_PROCESSINGMODAL_HEADER"), + submit: t("ATM_CONFIRM_REJECT"), + cancel: t("CS_COMMON_CANCEL"), + }, + form: [ + { + body: [ + { + withoutLabel:true, + populators: + {t("ATM_DEPARTMENT")} + {empDepartment} + , + }, + { + withoutLabel:true, + populators: + {t("ATM_DESIGNATION")} + {empDesignation} + , + }, + { + withoutLabel:true, + populators: + {t("ATM_REJECTED_BY")} + {empName} + , + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + key: "org_name", + populators: { + name: "comments", + }, + }, + ] + } + ] + } + +} + +export default configAttendanceRejectModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configCheckModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configCheckModal.js new file mode 100644 index 00000000000..c267eb9f32f --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configCheckModal.js @@ -0,0 +1,105 @@ +import { Dropdown,Loader } from '@egovernments/digit-ui-react-components'; +import React,{useState} from 'react' + +const configCheckModal = ({ + t, + action, + businessService, + approvers, + selectedApprover, + setSelectedApprover, + designation, + selectedDesignation, + setSelectedDesignation, + department, + selectedDept, + setSelectedDept, + approverLoading=false, +}) => { + + let checkConditions = true + if (action.isTerminateState) checkConditions = false; + + if(designation?.length===0 || department?.length===0) return {} + + return { + label: { + heading: `WORKS_CHECK_FORWARD`, + submit: `WORKS_FORWARD_FOR_APPROVAL`, + cancel: "WORKS_CANCEL", + }, + form: [ + { + body:[ + { + label: !checkConditions ? null : t("WORKS_APPROVER_DEPT"), + placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + isMandatory: true, + type: "goToDefaultCase", + populators: !checkConditions ? null : ( + { + setSelectedDept(val) + setSelectedApprover("") + //setValue() + }} + selected={selectedDept} + t={t} + /> + ), + }, + { + label: !checkConditions ? null : t("WORKS_APPROVER_DESIGNATION"), + //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + isMandatory: true, + type: "goToDefaultCase", + populators: !checkConditions ? null : ( + { + setSelectedDesignation(val) + setSelectedApprover("") + //resetting approver dropdown when dept/designation changes + }} + selected={selectedDesignation} + t={t} + /> + ), + }, + { + label: !checkConditions ? null : t("WORKS_APPROVER"), + //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + isMandatory: true, + type: "goToDefaultCase", + populators: !checkConditions ? null : ( + approverLoading ? : + ), + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ] + } + ] + } +} + +export default configCheckModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configRejectModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configRejectModal.js new file mode 100644 index 00000000000..ae4be5af3fd --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configRejectModal.js @@ -0,0 +1,127 @@ +import { Dropdown,LabelFieldPair,CardLabel} from '@egovernments/digit-ui-react-components'; +import React, { useState } from 'react' + +const configRejectModal = ({ + t, + action, + rejectReasons, + selectedReason, + setSelectedReason, + loiNumber, + department, + estimateNumber +}) => { + + let checkConditions = true + if (action.isTerminateState) checkConditions = false; + + if(rejectReasons?.length === 0) return {} + if(loiNumber){ + return { + label: { + heading: `WORKS_REJECT_LOI`, + submit: `WORKS_REJECT_LOI`, + //cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + withoutLabel:true, + populators: + {t("WORKS_DEPARTMENT")} + {"ENGG"} + , + }, + { + //label: t("WORKS_LOI_ID"), + //type: "text", + withoutLabel: true, + populators: + {t("WORKS_LOI_ID")} + {loiNumber} + + }, + { + label: !checkConditions ? null : t("WORKS_REJECT_REASON"), + //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + // isMandatory: false, + type: "goToDefaultCase", + populators: !checkConditions ? null : ( + + ), + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ] + } + ] + } + }else{ + return { + label: { + heading: `WORKS_REJECT_ESTIMATE`, + submit: `WORKS_REJECT_ESTIMATE`, + //cancel: "CS_COMMON_CANCEL", + }, + form: [ + { + body: [ + { + withoutLabel:true, + populators: + {t("WORKS_DEPARTMENT")} + {"ENGG"} + , + }, + { + //label: t("WORKS_LOI_ID"), + //type: "text", + withoutLabel: true, + populators: + {t("WORKS_ESTIMATE_ID")} + {estimateNumber} + + }, + { + label: !checkConditions ? null : t("WORKS_REJECT_REASON"), + //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + // isMandatory: false, + type: "goToDefaultCase", + populators: !checkConditions ? null : ( + + ), + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ] + } + ] + } + + } +} + +export default configRejectModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillApproveModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillApproveModal.js new file mode 100644 index 00000000000..cd01fdc4414 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillApproveModal.js @@ -0,0 +1,57 @@ +import React from 'react' +import { LabelFieldPair,CardLabel} from '@egovernments/digit-ui-react-components'; + +const configViewBillApprovalModal = ({ + t, +}) => { + const fieldLabelStyle = { + "display" : "grid", + "gridTemplateColumns" : "60% 1fr" + }; + return { + label: { + heading: t("EXP_PROCESSINGMODAL_HEADER"), + submit: t("EXP_FORWARD_FOR_APPROVAL"), + cancel: t("CS_COMMON_CANCEL"), + }, + form: [ + { + body: [ + { + withoutLabel:true, + populators: + {t("EXP_DEPARTMENT")} + Engineering + , + }, + { + withoutLabel:true, + populators: + {t("EXP_DESIGNATION")} + Junior Engineer + , + }, + { + withoutLabel:true, + populators: + {t("EXP_APPROVER")} + {"RASHMI"} + , + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ], + }, + ], + defaultValues: { + comments: "", + }, + }; +} + +export default configViewBillApprovalModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillCheckModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillCheckModal.js new file mode 100644 index 00000000000..53204b28e75 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillCheckModal.js @@ -0,0 +1,107 @@ +import { Dropdown, Loader } from '@egovernments/digit-ui-react-components'; +import React, { useState } from 'react' + +const configViewBillCheckModal = ({ + t, + approvers, + selectedApprover, + setSelectedApprover, + designation, + selectedDesignation, + setSelectedDesignation, + department, + selectedDept, + setSelectedDept, + approverLoading = false, +}) => { + + let checkConditions = true + + + if (designation?.length === 0 || department?.length === 0) return {} + + return { + label: { + heading: t("EXP_FORWARD_BILL_FOR_APPROVAL"), + submit: t("EXP_FORWARD_BILL_FOR_APPROVAL"), + cancel: t("CS_COMMON_CANCEL"), + }, + form: [ + { + body: [ + { + label: !checkConditions ? null : t("WORKS_APPROVER_DEPT"), + placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + isMandatory: true, + type: "goToDefaultCase", + populators: !checkConditions ? null : ( + { + setSelectedDept(val) + setSelectedApprover("") + //setValue() + }} + selected={selectedDept} + t={t} + /> + ), + }, + { + label: !checkConditions ? null : t("WORKS_APPROVER_DESIGNATION"), + //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + isMandatory: true, + type: "goToDefaultCase", + name: "designation", + populators: !checkConditions ? null : ( + { + setSelectedDesignation(val) + setSelectedApprover("") + //resetting approver dropdown when dept/designation changes + }} + selected={selectedDesignation} + t={t} + /> + ), + }, + { + label: !checkConditions ? null : t("WORKS_APPROVER"), + //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), + isMandatory: true, + type: "goToDefaultCase", + populators: !checkConditions ? null : ( + approverLoading ? : + ), + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ] + } + ] + } +} + +export default configViewBillCheckModal; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillRejectModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillRejectModal.js new file mode 100644 index 00000000000..716d6179d10 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillRejectModal.js @@ -0,0 +1,59 @@ +import React from 'react' +import { LabelFieldPair,CardLabel} from '@egovernments/digit-ui-react-components'; + +const configViewBillRejectModal = ({ + t, +}) => { + + const fieldLabelStyle = { + "display" : "grid", + "gridTemplateColumns" : "60% 1fr" + }; + + return { + label: { + heading: t("EXP_PROCESSINGMODAL_HEADER"), + submit: t("EXP_CONFIRM_REJECT"), + cancel: t("CS_COMMON_CANCEL"), + }, + form: [ + { + body: [ + { + withoutLabel:true, + populators: + {t("EXP_DEPARTMENT")} + Engineering + , + }, + { + withoutLabel:true, + populators: + {t("EXP_DESIGNATION")} + Junior Engineer + , + }, + { + withoutLabel:true, + populators: + {t("EXP_REJECTED_BY")} + {"RASHMI"} + , + }, + { + label: t("WF_COMMON_COMMENTS"), + type: "textarea", + populators: { + name: "comments", + }, + }, + ] + } + ], + defaultValues : { + comments : "", + } + } +} + +export default configViewBillRejectModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/index.js new file mode 100644 index 00000000000..a736b8ed3eb --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/index.js @@ -0,0 +1,47 @@ +import { configAssignDso } from "./AssignDso"; +import { configCompleteApplication } from "./CompleteApplication"; +import { configReassignDSO } from "./ReassignDso"; +import { configRejectApplication } from "./RejectApplication"; +import { configAcceptDso } from "./AcceptDso"; +import { configPTApproverApplication } from "./PTApproverApplication"; +import { configPTAssessProperty } from "./PTAssessProperty"; +import { configTLApproverApplication } from "./TLApproverApplication"; +import { configBPAREGApproverApplication } from "./BPAREGApproverApplication"; +import { configBPAApproverApplication } from "./BPAApproverApplication"; +import { configNOCApproverApplication } from "./NOCApproverApplication"; +import { configWSApproverApplication } from "./WSApproverApplication"; +import { configWSDisConnectApplication } from "./WSDisconnectApplication"; +import configCheckModal from "./configCheckModal" +import configApproveModal from "./configApproveModal" +import configRejectModal from "./configRejectModal" +import configAttendanceApproveModal from "./configAttendanceApproveModal"; +import configAttendanceCheckModal from "./configAttendanceCheckModal"; +import configAttendanceRejectModal from "./configAttendanceRejectModal"; +import configViewBillApproveModal from "./configViewBillApproveModal"; +import configViewBillCheckModal from "./configViewBillCheckModal"; +import configViewBillRejectModal from "./configViewBillRejectModal"; + +export { + configAttendanceRejectModal, + configAttendanceCheckModal, + configAttendanceApproveModal, + configCheckModal, + configApproveModal, + configRejectModal, + configAssignDso, + configCompleteApplication, + configReassignDSO, + configRejectApplication, + configAcceptDso, + configPTApproverApplication, + configPTAssessProperty, + configTLApproverApplication, + configBPAREGApproverApplication, + configBPAApproverApplication, + configNOCApproverApplication, + configWSApproverApplication, + configWSDisConnectApplication, + configViewBillRejectModal, + configViewBillCheckModal, + configViewBillApproveModal +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/index.js new file mode 100644 index 00000000000..feb622ab712 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/index.js @@ -0,0 +1,368 @@ +import React, { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { useQueryClient } from "react-query"; +import { format } from "date-fns"; + +import { Loader } from "@egovernments/digit-ui-react-components"; + +import ActionModal from "./Modal"; + +import { useHistory, useParams } from "react-router-dom"; +import ApplicationDetailsContent from "./components/ApplicationDetailsContent"; +import ApplicationDetailsToast from "./components/ApplicationDetailsToast"; +import ApplicationDetailsActionBar from "./components/ApplicationDetailsActionBar"; +import ApplicationDetailsWarningPopup from "./components/ApplicationDetailsWarningPopup"; + +const ApplicationDetails = (props) => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + const state = Digit.ULBService.getStateId(); + const { t } = useTranslation(); + const history = useHistory(); + let { id: applicationNumber } = useParams(); + const [displayMenu, setDisplayMenu] = useState(false); + const [selectedAction, setSelectedAction] = useState(null); + const [showModal, setShowModal] = useState(false); + const [isEnableLoader, setIsEnableLoader] = useState(false); + const [isWarningPop, setWarningPopUp] = useState(false); + const [modify, setModify] = useState(false); + const [saveAttendanceState, setSaveAttendanceState] = useState({ displaySave : false, updatePayload: []}) + + const { + applicationDetails, + showToast, + setShowToast, + isLoading, + isDataLoading, + applicationData, + mutate, + nocMutation, + workflowDetails, + businessService, + closeToast, + moduleCode, + timelineStatusPrefix, + forcedActionPrefix, + statusAttribute, + ActionBarStyle, + MenuStyle, + paymentsList, + showTimeLine = true, + oldValue, + isInfoLabel = false, + clearDataDetails, + noBoxShadow, + sectionHeadStyle, + showActionBar = true + } = props; + + useEffect(() => { + if (showToast) { + workflowDetails.revalidate(); + } + }, [showToast]); + + function onActionSelect(action) { + if (action) { + if(action?.isToast){ + setShowToast({ key: "error", error: { message: action?.toastMessage } }); + setTimeout(closeToast, 5000); + } + else if (action?.isWarningPopUp) { + setWarningPopUp(true); + } else if (action?.redirectionUrll) { + //here do the loi edit upon rejection + if (action?.redirectionUrll?.action === "EDIT_LOI_APPLICATION") { + history.push(`${action?.redirectionUrll?.pathname}`, { data: action?.redirectionUrll?.state }); + } + if (action?.redirectionUrll?.action === "EDIT_ESTIMATE_APPLICATION") { + history.push(`${action?.redirectionUrll?.pathname}`,{ data: action?.redirectionUrll?.state }); + } + + } else if (!action?.redirectionUrl) { + if(action?.action === 'EDIT') setModify(true) + else setShowModal(true); + } else { + history.push({ + pathname: action.redirectionUrl?.pathname, + state: { ...action.redirectionUrl?.state }, + }); + } + } + setSelectedAction(action); + setDisplayMenu(false); + } + + const queryClient = useQueryClient(); + + const closeModal = () => { + setSelectedAction(null); + setShowModal(false); + }; + + const closeWarningPopup = () => { + setWarningPopUp(false); + }; + + const getResponseHeader = (action) => { + + if(action?.includes("CHECK")){ + return t("WORKS_LOI_RESPONSE_FORWARD_HEADER") + } else if (action?.includes("APPROVE")){ + return t("WORKS_LOI_RESPONSE_APPROVE_HEADER") + }else if(action?.includes("REJECT")){ + return t("WORKS_LOI_RESPONSE_REJECT_HEADER") + } + } + + const getResponseMessage = (action,updatedLOI) => { + + if (action?.includes("CHECK")) { + return t("WORKS_LOI_RESPONSE_MESSAGE_CHECK", { loiNumber: updatedLOI?.letterOfIndentNumber,name:"Nipun",designation:"SE" }) + } else if (action?.includes("APPROVE")) { + return t("WORKS_LOI_RESPONSE_MESSAGE_APPROVE", { loiNumber: updatedLOI?.letterOfIndentNumber }) + } else if (action?.includes("REJECT")) { + return t("WORKS_LOI_RESPONSE_MESSAGE_REJECT", { loiNumber: updatedLOI?.letterOfIndentNumber }) + } + } + + const getEstimateResponseHeader = (action) => { + + if(action?.includes("CHECK")){ + return t("WORKS_ESTIMATE_RESPONSE_FORWARD_HEADER") + } else if (action?.includes("TECHNICALSANCATION")){ + return t("WORKS_ESTIMATE_RESPONSE_FORWARD_HEADER") + }else if (action?.includes("ADMINSANCTION")){ + return t("WORKS_ESTIMATE_RESPONSE_APPROVE_HEADER") + }else if(action?.includes("REJECT")){ + return t("WORKS_ESTIMATE_RESPONSE_REJECT_HEADER") + } + } + + const getEstimateResponseMessage = (action,updatedEstimate) => { + + if (action?.includes("CHECK")) { + return t("WORKS_ESTIMATE_RESPONSE_MESSAGE_CHECK", { estimateNumber: updatedEstimate?.estimateNumber,Name:"Super",Designation:"SE",Department:"Health" }) + } else if (action?.includes("TECHNICALSANCATION")) { + return t("WORKS_ESTIMATE_RESPONSE_MESSAGE_CHECK", { estimateNumber: updatedEstimate?.estimateNumber,Name:"Super",Designation:"SE",Department:"Health" }) + } else if (action?.includes("ADMINSANCTION")) { + return t("WORKS_ESTIMATE_RESPONSE_MESSAGE_APPROVE", { estimateNumber: updatedEstimate?.estimateNumber }) + } else if (action?.includes("REJECT")) { + return t("WORKS_ESTIMATE_RESPONSE_MESSAGE_REJECT", { estimateNumber: updatedEstimate?.estimateNumber }) + } + } + + const getAttendanceResponseHeaderAndMessage = (action) => { + let response = {} + if (action?.includes("VERIFY")) { + response.header = t("ATM_ATTENDANCE_VERIFIED") + response.message = t("ATM_ATTENDANCE_VERIFIED_SUCCESS") + } else if (action?.includes("REJECT")) { + response.header = t("ATM_ATTENDANCE_REJECTED") + response.message = t("ATM_ATTENDANCE_REJECTED_SUCCESS") + } else if (action?.includes("APPROVE")) { + response.header = t("ATM_ATTENDANCE_APPROVED") + response.message = t("ATM_ATTENDANCE_APPROVED_SUCCESS") + } + return response + } + + const submitAction = async (data, nocData = false, isOBPS = {}) => { + const performedAction = data?.workflow?.action + setIsEnableLoader(true); + if (mutate) { + setIsEnableLoader(true); + mutate(data, { + onError: (error, variables) => { + setIsEnableLoader(false); + setShowToast({ key: "error", error }); + setTimeout(closeToast, 5000); + }, + onSuccess: (data, variables) => { + setIsEnableLoader(false); + //just history.push to the response component from here and show relevant details + if(data?.letterOfIndents?.[0]){ + const updatedLOI = data?.letterOfIndents?.[0] + const state = { + header:getResponseHeader(performedAction,updatedLOI), + id: updatedLOI?.letterOfIndentNumber, + info: t("WORKS_LOI_ID"), + message: getResponseMessage(performedAction,updatedLOI), + links: [ + { + name: t("WORKS_CREATE_NEW_LOI"), + redirectUrl: `/${window.contextPath}/employee/works/create-loi`, + code: "", + svg: "CreateEstimateIcon", + isVisible:false, + type:"add" + }, + { + name: t("WORKS_GOTO_LOI_INBOX"), + redirectUrl: `/${window.contextPath}/employee/works/LOIInbox`, + code: "", + svg: "CreateEstimateIcon", + isVisible:true, + type:"inbox" + }, + ], + responseData:data, + requestData:variables + } + history.push(`/${window.contextPath}/employee/works/response`, state) + } + if(data?.estimates?.[0]){ + const updatedEstimate = data?.estimates?.[0] + const state = { + header:getEstimateResponseHeader(performedAction,updatedEstimate), + id: updatedEstimate?.estimateNumber, + info: t("WORKS_ESTIMATE_ID"), + message: getEstimateResponseMessage(performedAction,updatedEstimate), + links: [ + { + name: t("WORKS_CREATE_ESTIMATE"), + redirectUrl: `/${window.contextPath}/employee/works/create-estimate`, + code: "", + svg: "CreateEstimateIcon", + isVisible:false, + type:"add" + }, + { + name: t("WORKS_GOTO_ESTIMATE_INBOX"), + redirectUrl: `/${window.contextPath}/employee/works/inbox`, + code: "", + svg: "RefreshIcon", + isVisible:true, + type:"inbox" + }, + ], + responseData:data, + requestData:variables + } + history.push(`/${window.contextPath}/employee/works/response`, state) + } + if (isOBPS?.bpa) { + data.selectedAction = selectedAction; + history.replace(`/${window?.contextPath}/employee/obps/response`, { data: data }); + } + if (isOBPS?.isStakeholder) { + data.selectedAction = selectedAction; + history.push(`/${window?.contextPath}/employee/obps/stakeholder-response`, { data: data }); + } + if (isOBPS?.isNoc) { + history.push(`/${window?.contextPath}/employee/noc/response`, { data: data }); + } + if (data?.Amendments?.length > 0 ){ + //RAIN-6981 instead just show a toast here with appropriate message + //show toast here and return + //history.push("/${window?.contextPath}/employee/ws/response-bill-amend", { status: true, state: data?.Amendments?.[0] }) + + if(variables?.AmendmentUpdate?.workflow?.action.includes("SEND_BACK")){ + setShowToast({ key: "success", label: t("ES_MODIFYSWCONNECTION_SEND_BACK_UPDATE_SUCCESS")}) + } else if (variables?.AmendmentUpdate?.workflow?.action.includes("RE-SUBMIT")){ + setShowToast({ key: "success", label: t("ES_MODIFYSWCONNECTION_RE_SUBMIT_UPDATE_SUCCESS") }) + } else if (variables?.AmendmentUpdate?.workflow?.action.includes("APPROVE")){ + setShowToast({ key: "success", label: t("ES_MODIFYSWCONNECTION_APPROVE_UPDATE_SUCCESS") }) + } + else if (variables?.AmendmentUpdate?.workflow?.action.includes("REJECT")){ + setShowToast({ key: "success", label: t("ES_MODIFYWSCONNECTION_REJECT_UPDATE_SUCCESS") }) + } + return + } + if(data?.musterRolls?.[0]) { + const musterRoll = data?.musterRolls?.[0] + const response = getAttendanceResponseHeaderAndMessage(performedAction) + const state = { + header: response?.header, + message: response?.message, + info: t("ATM_REGISTER_ID_WEEK"), + id: `${musterRoll.registerId} | ${format(new Date(musterRoll.startDate), "dd/MM/yyyy")} - ${format(new Date(musterRoll.endDate), "dd/MM/yyyy")}`, + } + history.push(`/${window.contextPath}/employee/attendencemgmt/response`, state) + } + setShowToast({ key: "success", action: selectedAction }); + clearDataDetails && setTimeout(clearDataDetails, 3000); + setTimeout(closeToast, 5000); + queryClient.clear(); + queryClient.refetchQueries("APPLICATION_SEARCH"); + //push false status when reject + + }, + }); + } + + closeModal(); + }; + + if (isLoading || isEnableLoader) { + return ; + } + + return ( + + {!isLoading ? ( + + + {showModal ? ( + + ) : null} + {isWarningPop ? ( + + ) : null} + + {showActionBar && } + + ) : ( + + )} + + ); +}; + +export default ApplicationDetails; diff --git a/frontend/micro-ui/web/micro-ui-internals/publish-develop.sh b/frontend/micro-ui/web/micro-ui-internals/publish-develop.sh new file mode 100644 index 00000000000..4909658c697 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/publish-develop.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +BASEDIR="$(cd "$(dirname "$0")" && pwd)" + +msg() { + echo -e "\n\n\033[32;32m$1\033[0m" +} + + +# msg "Pre-building all packages" +# yarn build +# sleep 5 + +msg "Building and publishing css" +cd "$BASEDIR/packages/css" && rm -rf dist && yarn && npm publish --tag campaign-1.0 + + +# msg "Building and publishing libraries" +# cd "$BASEDIR/packages/modules/workbench-hcm" && rm -rf dist && yarn&& npm publish --tag workbench-1.0 + diff --git a/frontend/micro-ui/web/micro-ui-internals/publish.sh b/frontend/micro-ui/web/micro-ui-internals/publish.sh new file mode 100644 index 00000000000..4909658c697 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/publish.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +BASEDIR="$(cd "$(dirname "$0")" && pwd)" + +msg() { + echo -e "\n\n\033[32;32m$1\033[0m" +} + + +# msg "Pre-building all packages" +# yarn build +# sleep 5 + +msg "Building and publishing css" +cd "$BASEDIR/packages/css" && rm -rf dist && yarn && npm publish --tag campaign-1.0 + + +# msg "Building and publishing libraries" +# cd "$BASEDIR/packages/modules/workbench-hcm" && rm -rf dist && yarn&& npm publish --tag workbench-1.0 + diff --git a/frontend/micro-ui/web/micro-ui-internals/scripts/create.sh b/frontend/micro-ui/web/micro-ui-internals/scripts/create.sh new file mode 100755 index 00000000000..9de72331774 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/scripts/create.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +./scripts/run.sh core utilities diff --git a/frontend/micro-ui/web/micro-ui-internals/scripts/deploy.sh b/frontend/micro-ui/web/micro-ui-internals/scripts/deploy.sh new file mode 100755 index 00000000000..5b0c7b831ed --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/scripts/deploy.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +curl -v -X POST https://builds.digit.org/job/builds/job/digit-ui/buildWithParameters \ + --user saurabh-egov:114cbf3df675835931688b2d3f0014a1f7 \ + --data-urlencode json='{"parameter": [{"name":"BRANCH", "value":"origin/'$1'"}]}' + +# curl https://builds.digit.org/job/builds/job/digit-ui/lastBuild/api/json | grep --color result\":null + diff --git a/frontend/micro-ui/web/micro-ui-internals/scripts/jenkins.sh b/frontend/micro-ui/web/micro-ui-internals/scripts/jenkins.sh new file mode 100755 index 00000000000..a1711fec55b --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/scripts/jenkins.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +./scripts/deploy.sh dev \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/scripts/run.sh b/frontend/micro-ui/web/micro-ui-internals/scripts/run.sh new file mode 100755 index 00000000000..f00c59f13b8 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/scripts/run.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +MODULES=( "components" "core" "libraries" "example" ) + +RUNARGS=() +BUILDARGS=() + +for var in "$@" +do + BUILDARGS=( ${BUILDARGS[@]} build:"$var" ) + RUNARGS=( ${RUNARGS[@]} dev:"$var" ) +done + +a=0 +while [ "$a" -lt 3 ] +do + BUILD[$a]=build:${MODULES[$a]} + a=` expr $a + 1 ` +done + +echo "BUILDING MODULES:-" ${BUILD[*]} ${BUILDARGS[*]} +yarn run-p ${BUILD[*]} ${BUILDARGS[*]} + +b=0 +while [ "$b" -lt 4 ] +do + RUN[$b]=dev:${MODULES[$b]} + b=` expr $b + 1 ` +done + +echo "SERVING MODULES:-" ${RUN[*]} ${RUNARGS[*]} +yarn run-p ${RUN[*]} ${RUNARGS[*]} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/test.js b/frontend/micro-ui/web/micro-ui-internals/test.js new file mode 100644 index 00000000000..60c958d0bac --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/test.js @@ -0,0 +1,31 @@ +const middleWare_1 = (data, _break, _next) => { + data.a = "a"; + _next(data); +}; + + +const middleWare_2 = (data, _break, _next) => { + data.b = "b"; + // _break(); + _next(data); +}; + +const middleWare_3 = (data, _break, _next) => { + data.c = "c"; + _next(data); +}; + +let middleWares = [middleWare_1, middleWare_2, middleWare_3]; + +const callMiddlewares = () => { + let applyBreak = false; + let itr = -1; + let _break = () => (applyBreak = true); + let _next = (data) => { + if (!applyBreak && ++itr < middleWares.length) middleWares[itr](data, _break, _next); + else return; + }; + _next({}); +}; + +callMiddlewares(); diff --git a/frontend/micro-ui/web/package.json b/frontend/micro-ui/web/package.json new file mode 100644 index 00000000000..86a952fabe9 --- /dev/null +++ b/frontend/micro-ui/web/package.json @@ -0,0 +1,85 @@ +{ + "name": "micro-ui", + "version": "0.1.0", + "author": "Jagankumar ", + "license": "MIT", + "private": true, + "engines": { + "node": ">=14" + }, + "workspaces": [ + "micro-ui-internals/packages/libraries", + "micro-ui-internals/packages/react-components", + "micro-ui-internals/packages/modules/*" + ], + "homepage": "/digit-ui", + "dependencies": { + "@egovernments/digit-ui-libraries": "1.8.1-beta.4", + "@egovernments/digit-ui-module-workbench": "1.0.1-beta.16", + "@egovernments/digit-ui-module-core": "1.8.1-beta.23", + "@egovernments/digit-ui-module-hrms": "1.8.0-beta.2", + "@egovernments/digit-ui-react-components": "1.8.1-beta.23", + "@egovernments/digit-ui-components": "0.0.1-beta.25", + "@egovernments/digit-ui-module-dss": "1.8.0-beta", + "@egovernments/digit-ui-module-common": "1.8.0-beta", + "@egovernments/digit-ui-module-utilities": "1.0.0-beta", + "@egovernments/digit-ui-module-engagement": "1.5.20", + "babel-loader": "8.1.0", + "clean-webpack-plugin": "4.0.0", + "react": "17.0.2", + "react-dom": "17.0.2", + "jsonpath": "^1.1.1", + "react-router-dom": "5.3.0", + "react-scripts": "4.0.1", + "web-vitals": "1.1.2", + "terser-brunch": "^4.1.0", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "css-loader": "5.2.6", + "style-loader": "2.0.0", + "webpack-cli": "4.10.0" + }, + "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "7.21.0", + "http-proxy-middleware": "1.3.1", + "lodash": "4.17.21", + "microbundle-crl": "0.13.11", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "react-router-dom": "5.3.0", + "husky": "7.0.4", + "lint-staged": "12.3.7", + "npm-run-all": "4.1.5", + "prettier": "2.1.2" + }, + "scripts": { + "start": "react-scripts start", + "build": "GENERATE_SOURCEMAP=false SKIP_PREFLIGHT_CHECK=true react-scripts build", + "build:prepare": "./build.sh", + "build:libraries": "cd micro-ui-internals && yarn build", + "build:prod": "webpack --mode production", + "build:webpack": "yarn build:libraries &&cd .. && ls && cd ./web && ls && yarn build:prod", + "clean": "rm -rf node_modules" + }, + "eslintConfig": { + "extends": [ + "react-app" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} \ No newline at end of file diff --git a/frontend/micro-ui/web/public/index.html b/frontend/micro-ui/web/public/index.html new file mode 100644 index 00000000000..74ad3a6ee9b --- /dev/null +++ b/frontend/micro-ui/web/public/index.html @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + DIGIT + + + + + + +
+ + + + \ No newline at end of file diff --git a/frontend/micro-ui/web/public/robots.txt b/frontend/micro-ui/web/public/robots.txt new file mode 100644 index 00000000000..e9e57dc4d41 --- /dev/null +++ b/frontend/micro-ui/web/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/frontend/micro-ui/web/src/App.js b/frontend/micro-ui/web/src/App.js new file mode 100644 index 00000000000..d871f8e8f4c --- /dev/null +++ b/frontend/micro-ui/web/src/App.js @@ -0,0 +1,74 @@ +import React from "react"; +import { initLibraries } from "@egovernments/digit-ui-libraries"; +import { + paymentConfigs, + PaymentLinks, + PaymentModule, +} from "@egovernments/digit-ui-module-common"; +import { DigitUI,initCoreComponents } from "@egovernments/digit-ui-module-core"; +import { initDSSComponents } from "@egovernments/digit-ui-module-dss"; +import { initEngagementComponents } from "@egovernments/digit-ui-module-engagement"; +import { initHRMSComponents } from "@egovernments/digit-ui-module-hrms"; +import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities"; +import { UICustomizations } from "./Customisations/UICustomizations"; +import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench"; +// import { initWorkbenchHCMComponents } from "@egovernments/digit-ui-module-hcmworkbench"; + +window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); + +const enabledModules = [ + "DSS", + "NDSS", + "Utilities", + "HRMS", + "Engagement", + "Workbench", + "Microplanning" +]; + +const moduleReducers = (initData) => ({ + initData, +}); + +const initDigitUI = () => { + window.Digit.ComponentRegistryService.setupRegistry({ + PaymentModule, + ...paymentConfigs, + PaymentLinks, + }); + initCoreComponents(); + initDSSComponents(); + initHRMSComponents(); + initEngagementComponents(); + initUtilitiesComponents(); + initWorkbenchComponents(); + + window.Digit.Customizations = { + PGR: {}, + commonUiConfig: UICustomizations, + }; +}; + +initLibraries().then(() => { + initDigitUI(); +}); + +function App() { + window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); + const stateCode = + window.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || + process.env.REACT_APP_STATE_LEVEL_TENANT_ID; + if (!stateCode) { + return

stateCode is not defined

; + } + return ( + + ); +} + +export default App; diff --git a/frontend/micro-ui/web/src/ComponentRegistry.js b/frontend/micro-ui/web/src/ComponentRegistry.js new file mode 100644 index 00000000000..9bafce3dc89 --- /dev/null +++ b/frontend/micro-ui/web/src/ComponentRegistry.js @@ -0,0 +1,11 @@ +class Registry { + constructor(registry = {}) { + this._registry = registry; + } + + getComponent(id) { + return this._registry[id]; + } +} + +export default Registry; diff --git a/frontend/micro-ui/web/src/Customisations/UICustomizations.js b/frontend/micro-ui/web/src/Customisations/UICustomizations.js new file mode 100644 index 00000000000..6d17ab0d51b --- /dev/null +++ b/frontend/micro-ui/web/src/Customisations/UICustomizations.js @@ -0,0 +1,428 @@ +import { Link } from "react-router-dom"; +import _ from "lodash"; + +//create functions here based on module name set in mdms(eg->SearchProjectConfig) +//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName] +// these functions will act as middlewares +var Digit = window.Digit || {}; + + + +const businessServiceMap = { + + "muster roll": "MR" +}; + +const inboxModuleNameMap = { + "muster-roll-approval": "muster-roll-service", +}; + +export const UICustomizations = { + businessServiceMap, + updatePayload: (applicationDetails, data, action, businessService) => { + + if (businessService === businessServiceMap.estimate) { + const workflow = { + comment: data.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + estimate: applicationDetails, + workflow, + }; + } + if (businessService === businessServiceMap.contract) { + const workflow = { + comment: data?.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + contract: applicationDetails, + workflow, + }; + } + if (businessService === businessServiceMap?.["muster roll"]) { + const workflow = { + comment: data?.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + musterRoll: applicationDetails, + workflow, + }; + } + if(businessService === businessServiceMap?.["works.purchase"]){ + const workflow = { + comment: data.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + const additionalFieldsToSet = { + projectId:applicationDetails.additionalDetails.projectId, + invoiceDate:applicationDetails.billDate, + invoiceNumber:applicationDetails.referenceId.split('_')?.[1], + contractNumber:applicationDetails.referenceId.split('_')?.[0], + documents:applicationDetails.additionalDetails.documents + } + return { + bill: {...applicationDetails,...additionalFieldsToSet}, + workflow, + }; + } + }, + enableModalSubmit:(businessService,action,setModalSubmit,data)=>{ + if(businessService === businessServiceMap?.["muster roll"] && action.action==="APPROVE"){ + setModalSubmit(data?.acceptTerms) + } + }, + enableHrmsSearch: (businessService, action) => { + if (businessService === businessServiceMap.estimate) { + return action.action.includes("TECHNICALSANCTION") || action.action.includes("VERIFYANDFORWARD"); + } + if (businessService === businessServiceMap.contract) { + return action.action.includes("VERIFY_AND_FORWARD"); + } + if (businessService === businessServiceMap?.["muster roll"]) { + return action.action.includes("VERIFY"); + } + if(businessService === businessServiceMap?.["works.purchase"]){ + return action.action.includes("VERIFY_AND_FORWARD") + } + return false; + }, + getBusinessService: (moduleCode) => { + if (moduleCode?.includes("estimate")) { + return businessServiceMap?.estimate; + } else if (moduleCode?.includes("contract")) { + return businessServiceMap?.contract; + } else if (moduleCode?.includes("muster roll")) { + return businessServiceMap?.["muster roll"]; + } + else if (moduleCode?.includes("works.purchase")) { + return businessServiceMap?.["works.purchase"]; + } + else if (moduleCode?.includes("works.wages")) { + return businessServiceMap?.["works.wages"]; + } + else if (moduleCode?.includes("works.supervision")) { + return businessServiceMap?.["works.supervision"]; + } + else { + return businessServiceMap; + } + }, + getInboxModuleName: (moduleCode) => { + if (moduleCode?.includes("estimate")) { + return inboxModuleNameMap?.estimate; + } else if (moduleCode?.includes("contract")) { + return inboxModuleNameMap?.contracts; + } else if (moduleCode?.includes("attendence")) { + return inboxModuleNameMap?.attendencemgmt; + } else { + return inboxModuleNameMap; + } + }, + + AttendanceInboxConfig: { + preProcess: (data) => { + + //set tenantId + data.body.inbox.tenantId = Digit.ULBService.getCurrentTenantId(); + data.body.inbox.processSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); + + const musterRollNumber = data?.body?.inbox?.moduleSearchCriteria?.musterRollNumber?.trim(); + if(musterRollNumber) data.body.inbox.moduleSearchCriteria.musterRollNumber = musterRollNumber + + const attendanceRegisterName = data?.body?.inbox?.moduleSearchCriteria?.attendanceRegisterName?.trim(); + if(attendanceRegisterName) data.body.inbox.moduleSearchCriteria.attendanceRegisterName = attendanceRegisterName + + // deleting them for now(assignee-> need clarity from pintu,ward-> static for now,not implemented BE side) + const assignee = _.clone(data.body.inbox.moduleSearchCriteria.assignee); + delete data.body.inbox.moduleSearchCriteria.assignee; + if (assignee?.code === "ASSIGNED_TO_ME") { + data.body.inbox.moduleSearchCriteria.assignee = Digit.UserService.getUser().info.uuid; + } + + //cloning locality and workflow states to format them + // let locality = _.clone(data.body.inbox.moduleSearchCriteria.locality ? data.body.inbox.moduleSearchCriteria.locality : []); + + let selectedOrg = _.clone(data.body.inbox.moduleSearchCriteria.orgId ? data.body.inbox.moduleSearchCriteria.orgId : null); + delete data.body.inbox.moduleSearchCriteria.orgId; + if(selectedOrg) { + data.body.inbox.moduleSearchCriteria.orgId = selectedOrg?.[0]?.applicationNumber; + } + + // let selectedWard = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : null); + // delete data.body.inbox.moduleSearchCriteria.ward; + // if(selectedWard) { + // data.body.inbox.moduleSearchCriteria.ward = selectedWard?.[0]?.code; + // } + + let states = _.clone(data.body.inbox.moduleSearchCriteria.state ? data.body.inbox.moduleSearchCriteria.state : []); + let ward = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : []); + // delete data.body.inbox.moduleSearchCriteria.locality; + delete data.body.inbox.moduleSearchCriteria.state; + delete data.body.inbox.moduleSearchCriteria.ward; + + // locality = locality?.map((row) => row?.code); + states = Object.keys(states)?.filter((key) => states[key]); + ward = ward?.map((row) => row?.code); + + + // //adding formatted data to these keys + // if (locality.length > 0) data.body.inbox.moduleSearchCriteria.locality = locality; + if (states.length > 0) data.body.inbox.moduleSearchCriteria.status = states; + if (ward.length > 0) data.body.inbox.moduleSearchCriteria.ward = ward; + const projectType = _.clone(data.body.inbox.moduleSearchCriteria.projectType ? data.body.inbox.moduleSearchCriteria.projectType : {}); + if (projectType?.code) data.body.inbox.moduleSearchCriteria.projectType = projectType.code; + + //adding tenantId to moduleSearchCriteria + data.body.inbox.moduleSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); + + //setting limit and offset becoz somehow they are not getting set in muster inbox + data.body.inbox .limit = data.state.tableForm.limit + data.body.inbox.offset = data.state.tableForm.offset + delete data.state + return data; + }, + postProcess: (responseArray, uiConfig) => { + const statusOptions = responseArray?.statusMap + ?.filter((item) => item.applicationstatus) + ?.map((item) => ({ code: item.applicationstatus, i18nKey: `COMMON_MASTERS_${item.applicationstatus}` })); + if (uiConfig?.type === "filter") { + let fieldConfig = uiConfig?.fields?.filter((item) => item.type === "dropdown" && item.populators.name === "musterRollStatus"); + if (fieldConfig.length) { + fieldConfig[0].populators.options = statusOptions; + } + } + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + if (key === "ATM_MUSTER_ROLL_ID") { + return ( + + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + ); + } + if (key === "ATM_ATTENDANCE_WEEK") { + const week = `${Digit.DateUtils.ConvertTimestampToDate(value?.startDate, "dd/MM/yyyy")}-${Digit.DateUtils.ConvertTimestampToDate( + value?.endDate, + "dd/MM/yyyy" + )}`; + return
{week}
; + } + if (key === "ATM_NO_OF_INDIVIDUALS") { + return
{value?.length}
; + } + if(key === "ATM_AMOUNT_IN_RS"){ + return {value ? Digit.Utils.dss.formatterWithoutRound(value, "number") : t("ES_COMMON_NA")}; + } + if (key === "ATM_SLA") { + return parseInt(value) > 0 ? ( + {t(value) || ""} + ) : ( + {t(value) || ""} + ); + } + if (key === "COMMON_WORKFLOW_STATES") { + return {t(`WF_MUSTOR_${value}`)} + } + //added this in case we change the key and not updated here , it'll throw that nothing was returned from cell error if that case is not handled here. To prevent that error putting this default + return {t(`CASE_NOT_HANDLED`)} + }, + MobileDetailsOnClick: (row, tenantId) => { + let link; + Object.keys(row).map((key) => { + if (key === "ATM_MUSTER_ROLL_ID") + link = `/${window.contextPath}/employee/attendencemgmt/view-attendance?tenantId=${tenantId}&musterRollNumber=${row[key]}`; + }); + return link; + }, + populateReqCriteria: () => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + return { + url: "/org-services/organisation/v1/_search", + params: { limit: 50, offset: 0 }, + body: { + SearchCriteria: { + tenantId: tenantId, + functions : { + type : "CBO" + } + }, + }, + config: { + enabled: true, + select: (data) => { + return data?.organisations; + }, + }, + }; + }, + }, + SearchWageSeekerConfig: { + customValidationCheck: (data) => { + //checking both to and from date are present + const { createdFrom, createdTo } = data; + if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === "")) + return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; + + return false; + }, + preProcess: (data) => { + data.params = { ...data.params, tenantId: Digit.ULBService.getCurrentTenantId() }; + + let requestBody = { ...data.body.Individual }; + const pathConfig = { + name: "name.givenName", + }; + const dateConfig = { + createdFrom: "daystart", + createdTo: "dayend", + }; + const selectConfig = { + wardCode: "wardCode[0].code", + socialCategory: "socialCategory.code", + }; + const textConfig = ["name", "individualId"] + let Individual = Object.keys(requestBody) + .map((key) => { + if (selectConfig[key]) { + requestBody[key] = _.get(requestBody, selectConfig[key], null); + } else if (typeof requestBody[key] == "object") { + requestBody[key] = requestBody[key]?.code; + } else if (textConfig?.includes(key)) { + requestBody[key] = requestBody[key]?.trim() + } + return key; + }) + .filter((key) => requestBody[key]) + .reduce((acc, curr) => { + if (pathConfig[curr]) { + _.set(acc, pathConfig[curr], requestBody[curr]); + } else if (dateConfig[curr] && dateConfig[curr]?.includes("day")) { + _.set(acc, curr, Digit.Utils.date.convertDateToEpoch(requestBody[curr], dateConfig[curr])); + } else { + _.set(acc, curr, requestBody[curr]); + } + return acc; + }, {}); + + data.body.Individual = { ...Individual }; + return data; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + //here we can add multiple conditions + //like if a cell is link then we return link + //first we can identify which column it belongs to then we can return relevant result + switch (key) { + case "MASTERS_WAGESEEKER_ID": + return ( + + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + ); + + case "MASTERS_SOCIAL_CATEGORY": + return value ? {String(t(`MASTERS_${value}`))} : t("ES_COMMON_NA"); + + case "CORE_COMMON_PROFILE_CITY": + return value ? {String(t(Digit.Utils.locale.getCityLocale(value)))} : t("ES_COMMON_NA"); + + case "MASTERS_WARD": + return value ? ( + {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} + ) : ( + t("ES_COMMON_NA") + ); + + case "MASTERS_LOCALITY": + return value ? ( + {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} + ) : ( + t("ES_COMMON_NA") + ); + default: + return t("ES_COMMON_NA"); + } + }, + MobileDetailsOnClick: (row, tenantId) => { + let link; + Object.keys(row).map((key) => { + if (key === "MASTERS_WAGESEEKER_ID") + link = `/${window.contextPath}/employee/masters/view-wageseeker?tenantId=${tenantId}&wageseekerId=${row[key]}`; + }); + return link; + }, + additionalValidations: (type, data, keys) => { + if (type === "date") { + return data[keys.start] && data[keys.end] ? () => new Date(data[keys.start]).getTime() <= new Date(data[keys.end]).getTime() : true; + } + } + }, +}; diff --git a/frontend/micro-ui/web/src/Customisations/index.js b/frontend/micro-ui/web/src/Customisations/index.js new file mode 100644 index 00000000000..803b1e8763e --- /dev/null +++ b/frontend/micro-ui/web/src/Customisations/index.js @@ -0,0 +1,19 @@ +import { ptComponents } from "./pt"; +import { tlComponents } from "./tl"; + +var Digit = window.Digit || {}; + +const customisedComponent = { + ...ptComponents, + ...tlComponents +} + + + +export const initCustomisationComponents = () => { + Object.entries(customisedComponent).forEach(([key, value]) => { + Digit.ComponentRegistryService.setComponent(key, value); + }); +}; + + diff --git a/frontend/micro-ui/web/src/Customisations/pt/index.js b/frontend/micro-ui/web/src/Customisations/pt/index.js new file mode 100644 index 00000000000..0063fcd4774 --- /dev/null +++ b/frontend/micro-ui/web/src/Customisations/pt/index.js @@ -0,0 +1,13 @@ +import PropertyUsageType from "./pageComponents/PropertyUsageType"; +import PTVasikaDetails from "./pageComponents/PTVasikaDetails"; +import PTAllotmentDetails from "./pageComponents/PTAllotmentDetails"; +import PTBusinessDetails from "./pageComponents/PTBusinessDetails"; + + + +export const ptComponents = { + PropertyUsageType: PropertyUsageType, + PTVasikaDetail:PTVasikaDetails, + PTAllotmentDetails:PTAllotmentDetails, + PTBusinessDetails:PTBusinessDetails +}; diff --git a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTAllotmentDetails.js b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTAllotmentDetails.js new file mode 100644 index 00000000000..569aa45e409 --- /dev/null +++ b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTAllotmentDetails.js @@ -0,0 +1,64 @@ +import { CardLabel, CitizenInfoLabel, FormStep, LabelFieldPair, TextInput,CardLabelError } from "@egovernments/digit-ui-react-components"; +import React, { useState } from "react"; +var validation ={}; +const PTAllotmentDetails = ({ t, config, onSelect, value, userType, formData }) => { + + const [ + val, setValue + ] = useState(formData?.[config.key]?.alotmentDetails||""); + + const goNext = () => { + onSelect(config.key, {alotmentDetails:val}); + }; + + + if (userType === "employee") { + return ( + + + {t("PT_VASIKA_NO_LABEL") } +
+ setValue(e?.target?.value)} + // autoFocus={presentInModifyApplication} + /> +
+
+
+ ); + } + return ( + + +
+ {`${t("PT_VASIKA_ALLOTMENT_LABEL")}`} + setValue(e?.target?.value)} + + /> +
+
+ {} +
+ ); +}; + +export default PTAllotmentDetails; diff --git a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTBusinessDetails.js b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTBusinessDetails.js new file mode 100644 index 00000000000..3d28785e7e5 --- /dev/null +++ b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTBusinessDetails.js @@ -0,0 +1,68 @@ +import { CardLabel, CitizenInfoLabel, FormStep, LabelFieldPair, TextInput,CardLabelError } from "@egovernments/digit-ui-react-components"; +import React, { useState } from "react"; +var validation ={}; +const PTBusinessDetails = ({ t, config, onSelect, value, userType, formData }) => { + + + const [ + val, setValue + ] = useState(formData?.[config.key]?.businessDetails||""); + + const goNext = () => { + onSelect(config.key, {businessDetails:val}); + }; + + + if (userType === "employee") { + return ( + + + {t("PT_VASIKA_NO_LABEL") } +
+ setValue(e?.target?.value)} + // autoFocus={presentInModifyApplication} + /> +
+
+ +
+ ); + } + return ( + + + +
+ {`${t("PT_VASIKA_BUS_DETAILS_LABEL")}`} + setValue(e?.target?.value)} + + /> +
+ +
+ {} +
+ ); +}; + +export default PTBusinessDetails; diff --git a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTVasikaDetails.js b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTVasikaDetails.js new file mode 100644 index 00000000000..0e4b6895745 --- /dev/null +++ b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTVasikaDetails.js @@ -0,0 +1,79 @@ +import { CardLabel, CitizenInfoLabel, FormStep, LabelFieldPair, TextInput,CardLabelError } from "@egovernments/digit-ui-react-components"; +import React, { useState } from "react"; +var validation ={}; +const PTVasikaDetails = ({ t, config, onSelect, value, userType, formData }) => { + + + const [ + val, setValue + ] = useState(formData?.[config.key]?.vasikaNo||""); + const [ + other, setOther + ] = useState(formData?.[config.key]?.vasikaArea||""); + const goNext = () => { + onSelect(config.key, {vasikaNo:val,vasikaArea:other}); + }; + + + if (userType === "employee") { + return ( + + + {t("PT_VASIKA_NO_LABEL") } +
+ setValue(e?.target?.value)} + // autoFocus={presentInModifyApplication} + /> +
+
+ +
+ ); + } + return ( + + + +
+ {`${t("PT_VASIKA_NO_LABEL")}`} + setValue(e?.target?.value)} + + /> +
+ {`${t("PT_VASIKA_AREA_LABEL")}`} + setOther(e?.target?.value)} + /> +
+ {} +
+ ); +}; + +export default PTVasikaDetails; diff --git a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PropertyUsageType.js b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PropertyUsageType.js new file mode 100644 index 00000000000..deade4fc2ad --- /dev/null +++ b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PropertyUsageType.js @@ -0,0 +1,134 @@ +import { + CardLabel, CardLabelError, CitizenInfoLabel, Dropdown, FormStep, LabelFieldPair, RadioButtons +} from "@egovernments/digit-ui-react-components"; +import React, { useEffect, useState } from "react"; +import { useLocation } from "react-router-dom"; + +var Digit = window.Digit || {}; + +const PropertyUsageType = ({ t, config, onSelect, userType, formData, formState, setError, clearErrors, onBlur }) => { + const [usageCategoryMajor, setPropertyPurpose] = useState( + formData?.usageCategoryMajor && formData?.usageCategoryMajor?.code === "NONRESIDENTIAL.OTHERS" + ? { code: `${formData?.usageCategoryMajor?.code}`, i18nKey: `PROPERTYTAX_BILLING_SLAB_OTHERS` } + : formData?.usageCategoryMajor + ); + + const tenantId = Digit.ULBService.getCurrentTenantId(); + const stateId = tenantId.split(".")[0]; + const { data: Menu = { }, isLoading: menuLoading } = Digit.Hooks.pt.usePropertyMDMS(stateId, "PropertyTax", "UsageCategory") || { }; + let usagecat = []; + usagecat = Menu?.PropertyTax?.UsageCategory || []; + let i; + let menu = []; + + const { pathname } = useLocation(); + const presentInModifyApplication = pathname.includes("modify"); + + function usageCategoryMajorMenu(usagecat) { + if (userType === "employee") { + const catMenu = usagecat + ?.filter((e) => e?.code.split(".").length <= 2 && e.code !== "NONRESIDENTIAL") + ?.map((item) => { + const arr = item?.code.split("."); + if (arr.length == 2) return { i18nKey: "PROPERTYTAX_BILLING_SLAB_" + arr[1], code: item?.code }; + else return { i18nKey: "PROPERTYTAX_BILLING_SLAB_" + item?.code, code: item?.code }; + }); + return catMenu; + } else { + for (i = 0; i < 10; i++) { + if ( + Array.isArray(usagecat) && + usagecat.length > 0 && + usagecat[i].code.split(".")[0] == "NONRESIDENTIAL" && + usagecat[i].code.split(".").length == 2 + ) { + menu.push({ i18nKey: "PROPERTYTAX_BILLING_SLAB_" + usagecat[i].code.split(".")[1], code: usagecat[i].code }); + } + } + return menu; + } + } + + useEffect(() => { + if (!menuLoading && presentInModifyApplication && userType === "employee") { + const original = formData?.originalData?.usageCategory; + const selectedOption = usageCategoryMajorMenu(usagecat).filter((e) => e.code === original)[0]; + setPropertyPurpose(selectedOption); + } + }, [menuLoading]); + + const onSkip = () => onSelect(); + + + function selectPropertyPurpose(value) { + setPropertyPurpose(value); + } + + function goNext() { + if (usageCategoryMajor?.i18nKey === "PROPERTYTAX_BILLING_SLAB_OTHERS") { + usageCategoryMajor.i18nKey = "PROPERTYTAX_BILLING_SLAB_NONRESIDENTIAL"; + onSelect(config.key, usageCategoryMajor); + } else { + onSelect(config.key, usageCategoryMajor); + } + } + + useEffect(() => { + if (userType === "employee") { + if (!usageCategoryMajor) { + setError(config.key, { type: "required", message: t(`CORE_COMMON_REQUIRED_ERRMSG`) }); + } else { + clearErrors(config.key); + } + goNext(); + } + }, [usageCategoryMajor]); + + if (userType === "employee") { + return ( + + + {t("PT_ASSESMENT_INFO_USAGE_TYPE") + " *"} + { + selectPropertyPurpose(e); + }} + optionKey="i18nKey" + onBlur={onBlur} + t={t} + /> + + {formState.touched[config.key] ? ( + + {formState.errors?.[config.key]?.message} + + ) : null} + + ); + } + + return ( + + +
+ +
+
+ {} +
+ ); +}; + +export default PropertyUsageType; diff --git a/frontend/micro-ui/web/src/Customisations/tl/TLCustomisation.js b/frontend/micro-ui/web/src/Customisations/tl/TLCustomisation.js new file mode 100644 index 00000000000..642acc52090 --- /dev/null +++ b/frontend/micro-ui/web/src/Customisations/tl/TLCustomisation.js @@ -0,0 +1,5 @@ +export const TLCustomisations = { + customiseCreateFormData: (formData, licenceObject) => licenceObject, + customiseRenewalCreateFormData: (formData, licenceObject) => licenceObject, + customiseSendbackFormData: (formData, licenceObject) => licenceObject +} \ No newline at end of file diff --git a/frontend/micro-ui/web/src/Customisations/tl/index.js b/frontend/micro-ui/web/src/Customisations/tl/index.js new file mode 100644 index 00000000000..fe2ae4f4e6a --- /dev/null +++ b/frontend/micro-ui/web/src/Customisations/tl/index.js @@ -0,0 +1,7 @@ +import TLUsageType from "./pageComponents/PropertyUsageType"; + + + +export const tlComponents = { + TLPropertyUsageType: TLUsageType, +}; diff --git a/frontend/micro-ui/web/src/Customisations/tl/pageComponents/PropertyUsageType.js b/frontend/micro-ui/web/src/Customisations/tl/pageComponents/PropertyUsageType.js new file mode 100644 index 00000000000..5520a66fc5a --- /dev/null +++ b/frontend/micro-ui/web/src/Customisations/tl/pageComponents/PropertyUsageType.js @@ -0,0 +1,136 @@ +import { + CardLabel, CardLabelError, CitizenInfoLabel, Dropdown, FormStep, LabelFieldPair, RadioButtons +} from "@egovernments/digit-ui-react-components"; +import React, { useEffect, useState } from "react"; +import { useLocation } from "react-router-dom"; + +var Digit = window.Digit || {}; + +const TLUsageType = ({ t, config, onSelect, userType, formData, formState, setError, clearErrors, onBlur }) => { + const [usageCategoryMajor, setPropertyPurpose] = useState( + formData?.usageCategoryMajor && formData?.usageCategoryMajor?.code === "NONRESIDENTIAL.OTHERS" + ? { code: `${formData?.usageCategoryMajor?.code}`, i18nKey: `PROPERTYTAX_BILLING_SLAB_OTHERS` } + : formData?.usageCategoryMajor + ); + + const tenantId = Digit.ULBService.getCurrentTenantId(); + const stateId = tenantId.split(".")[0]; + const { data: Menu = { }, isLoading: menuLoading } = Digit.Hooks.pt.usePropertyMDMS(stateId, "PropertyTax", "UsageCategory") || { }; + let usagecat = []; + usagecat = Menu?.PropertyTax?.UsageCategory || []; + let i; + let menu = []; + + const { pathname } = useLocation(); + const presentInModifyApplication = pathname.includes("modify"); + + function usageCategoryMajorMenu(usagecat) { + if (userType === "employee") { + const catMenu = usagecat + ?.filter((e) => e?.code.split(".").length <= 2 && e.code !== "NONRESIDENTIAL") + ?.map((item) => { + const arr = item?.code.split("."); + if (arr.length == 2) return { i18nKey: "PROPERTYTAX_BILLING_SLAB_" + arr[1], code: item?.code }; + else return { i18nKey: "PROPERTYTAX_BILLING_SLAB_" + item?.code, code: item?.code }; + }); + return catMenu; + } else { + for (i = 0; i < 10; i++) { + if ( + Array.isArray(usagecat) && + usagecat.length > 0 && + usagecat[i].code.split(".")[0] == "NONRESIDENTIAL" && + usagecat[i].code.split(".").length == 2 + ) { + menu.push({ i18nKey: "PROPERTYTAX_BILLING_SLAB_" + usagecat[i].code.split(".")[1], code: usagecat[i].code }); + } + } + return menu; + } + } + + useEffect(() => { + if (!menuLoading && presentInModifyApplication && userType === "employee") { + const original = formData?.originalData?.usageCategory; + const selectedOption = usageCategoryMajorMenu(usagecat).filter((e) => e.code === original)[0]; + setPropertyPurpose(selectedOption); + } + }, [menuLoading]); + + const onSkip = () => onSelect(); + + + function selectPropertyPurpose(value) { + setPropertyPurpose(value); + } + + function goNext() { + if (usageCategoryMajor?.i18nKey === "PROPERTYTAX_BILLING_SLAB_OTHERS") { + usageCategoryMajor.i18nKey = "PROPERTYTAX_BILLING_SLAB_NONRESIDENTIAL"; + onSelect(config.key, usageCategoryMajor); + } else { + onSelect(config.key, usageCategoryMajor); + } + } + + useEffect(() => { + if (userType === "employee") { + if (!usageCategoryMajor) { + setError(config.key, { type: "required", message: t(`CORE_COMMON_REQUIRED_ERRMSG`) }); + } else { + clearErrors(config.key); + } + goNext(); + } + }, [usageCategoryMajor]); + + if (userType === "employee") { + return ( + + + {t("PT_ASSESMENT_INFO_USAGE_TYPE") + " *"} + { + selectPropertyPurpose(e); + }} + optionKey="i18nKey" + onBlur={onBlur} + t={t} + /> + + {formState.touched[config.key] ? ( + + {formState.errors?.[config.key]?.message} + + ) : null} + + ); + } + + return ( + + +
+ + + +
+
+ {} +
+ ); +}; + +export default TLUsageType; diff --git a/frontend/micro-ui/web/src/index.css b/frontend/micro-ui/web/src/index.css new file mode 100644 index 00000000000..e69de29bb2d diff --git a/frontend/micro-ui/web/src/index.js b/frontend/micro-ui/web/src/index.js new file mode 100644 index 00000000000..9f20bf1b506 --- /dev/null +++ b/frontend/micro-ui/web/src/index.js @@ -0,0 +1,62 @@ +import React from 'react'; +import ReactDOM from 'react-dom'; +import { initLibraries } from "@egovernments/digit-ui-libraries"; +import "./index.css"; +import App from './App'; +import { TLCustomisations } from './Customisations/tl/TLCustomisation'; + + +initLibraries(); + + +window.Digit.Customizations = { PGR: {} ,TL:TLCustomisations}; + +const user = window.Digit.SessionStorage.get("User"); + +if (!user || !user.access_token || !user.info) { + // login detection + + const parseValue = (value) => { + try { + return JSON.parse(value) + } catch (e) { + return value + } + } + + const getFromStorage = (key) => { + const value = window.localStorage.getItem(key); + return value && value !== "undefined" ? parseValue(value) : null; + } + + const token = getFromStorage("token") + + const citizenToken = getFromStorage("Citizen.token") + const citizenInfo = getFromStorage("Citizen.user-info") + const citizenTenantId = getFromStorage("Citizen.tenant-id") + + const employeeToken = getFromStorage("Employee.token") + const employeeInfo = getFromStorage("Employee.user-info") + const employeeTenantId = getFromStorage("Employee.tenant-id") + const userType = token === citizenToken ? "citizen" : "employee"; + + window.Digit.SessionStorage.set("user_type", userType); + window.Digit.SessionStorage.set("userType", userType); + + const getUserDetails = (access_token, info) => ({ token: access_token, access_token, info }) + + const userDetails = userType === "citizen" ? getUserDetails(citizenToken, citizenInfo) : getUserDetails(employeeToken, employeeInfo) + + window.Digit.SessionStorage.set("User", userDetails); + window.Digit.SessionStorage.set("Citizen.tenantId", citizenTenantId); + window.Digit.SessionStorage.set("Employee.tenantId", employeeTenantId); + // end +} + +ReactDOM.render( + + + , + document.getElementById('root') +); + diff --git a/frontend/micro-ui/web/src/setupProxy.js b/frontend/micro-ui/web/src/setupProxy.js new file mode 100644 index 00000000000..1b8eda94a19 --- /dev/null +++ b/frontend/micro-ui/web/src/setupProxy.js @@ -0,0 +1,30 @@ +const { createProxyMiddleware } = require("http-proxy-middleware"); +const createProxy = createProxyMiddleware({ + target: process.env.REACT_APP_PROXY_URL, + changeOrigin: true, +}); +module.exports = function (app) { + [ + "/egov-mdms-service", + "/egov-location", + "/localization", + "/egov-workflow-v2", + "/pgr-services", + "/filestore", + "/egov-hrms", + "/user-otp", + "/user", + "/fsm", + "/billing-service", + "/collection-services", + "/pdf-service", + "/pg-service", + "/vehicle", + "/vendor", + "/property-services", + "/fsm-calculator/v1/billingSlab/_search", + "/muster-roll" + ].forEach((location) => + app.use(location, createProxy) + ); +}; diff --git a/frontend/micro-ui/web/webpack.config.js b/frontend/micro-ui/web/webpack.config.js new file mode 100644 index 00000000000..5f3dc46967a --- /dev/null +++ b/frontend/micro-ui/web/webpack.config.js @@ -0,0 +1,43 @@ +const path = require("path"); +const HtmlWebpackPlugin = require("html-webpack-plugin"); +const { CleanWebpackPlugin } = require("clean-webpack-plugin"); +// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; + +module.exports = { + // mode: 'development', + entry: "./src/index.js", + devtool: "none", + module: { + rules: [ + { + test: /\.(js)$/, + use: ["babel-loader"], + }, + { + test: /\.css$/i, + use: ["style-loader", "css-loader"], + } + ], + }, + output: { + filename: "[name].bundle.js", + path: path.resolve(__dirname, "build"), + publicPath: "/digit-ui/", + }, + optimization: { + splitChunks: { + chunks: 'all', + minSize:20000, + maxSize:50000, + enforceSizeThreshold:50000, + minChunks:1, + maxAsyncRequests:30, + maxInitialRequests:30 + }, + }, + plugins: [ + new CleanWebpackPlugin(), + // new BundleAnalyzerPlugin(), + new HtmlWebpackPlugin({ inject: true, template: "public/index.html" }), + ], +}; \ No newline at end of file diff --git a/frontend/micro-ui/web/workbench/App.js b/frontend/micro-ui/web/workbench/App.js new file mode 100644 index 00000000000..93b15440c5e --- /dev/null +++ b/frontend/micro-ui/web/workbench/App.js @@ -0,0 +1,72 @@ +/** + * The above code initializes various Digit UI modules and components, sets up customizations, and + * renders the DigitUI component based on the enabled modules and state code. + * @returns The `App` component is being returned, which renders the `DigitUI` component with the + * specified props such as `stateCode`, `enabledModules`, `moduleReducers`, and `defaultLanding`. The + * `DigitUI` component is responsible for rendering the UI based on the provided configuration and + * modules. + */ +import React from "react"; +import { initLibraries } from "@egovernments/digit-ui-libraries"; +import { DigitUI } from "@egovernments/digit-ui-module-core"; +// import { initHRMSComponents } from "@egovernments/digit-ui-module-hrms"; +import { UICustomizations } from "./Customisations/UICustomizations"; +import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench"; +import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities"; +import { initWorkbenchHCMComponents } from "@egovernments/digit-ui-module-hcmworkbench"; +import { initCampaignComponents } from "@egovernments/digit-ui-module-campaign-manager" + +window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); + +const enabledModules = [ + "DSS", + "NDSS", + "Utilities", + // "HRMS", + "Engagement", + "Workbench", + "HCMWORKBENCH", + "Campaign" +]; + +const moduleReducers = (initData) => ({ + initData, +}); + +const initDigitUI = () => { + window.Digit.ComponentRegistryService.setupRegistry({}); + window.Digit.Customizations = { + PGR: {}, + commonUiConfig: UICustomizations, + }; + // initHRMSComponents(); + initUtilitiesComponents(); + initWorkbenchComponents(); + initWorkbenchHCMComponents(); + initCampaignComponents(); + +}; + +initLibraries().then(() => { + initDigitUI(); +}); + +function App() { + window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); + const stateCode = + window.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || + process.env.REACT_APP_STATE_LEVEL_TENANT_ID; + if (!stateCode) { + return

stateCode is not defined

; + } + return ( + + ); +} + +export default App; diff --git a/frontend/micro-ui/web/workbench/Dockerfile b/frontend/micro-ui/web/workbench/Dockerfile new file mode 100644 index 00000000000..31b3912759b --- /dev/null +++ b/frontend/micro-ui/web/workbench/Dockerfile @@ -0,0 +1,29 @@ +FROM egovio/alpine-node-builder-14:yarn AS build +#FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build +RUN apk update && apk upgrade +RUN apk add --no-cache git>2.30.0 +ARG WORK_DIR +WORKDIR /app +ENV NODE_OPTIONS "--max-old-space-size=4792" + +COPY ${WORK_DIR} . +RUN ls -lah + +#RUN node web/envs.js +RUN cd web/ \ + && node -e 'console.log(v8.getHeapStatistics().heap_size_limit/(1024*1024))' \ + && node -e 'console.log("core only")' \ + && cd workbench/ \ + && ./install-deps.sh \ + && cd ../ \ + && yarn install \ + && yarn build:webpack + +FROM nginx:mainline-alpine +#FROM ghcr.io/egovernments/nginx:mainline-alpine +ENV WORK_DIR=/var/web/workbench-ui + +RUN mkdir -p ${WORK_DIR} + +COPY --from=build /app/web/build ${WORK_DIR}/ +COPY --from=build /app/web/workbench/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/micro-ui/web/workbench/install-deps.sh b/frontend/micro-ui/web/workbench/install-deps.sh new file mode 100755 index 00000000000..54b8a4c3d7f --- /dev/null +++ b/frontend/micro-ui/web/workbench/install-deps.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +BRANCH="$(git branch --show-current)" + +echo "Main Branch: $BRANCH" + +INTERNALS="micro-ui-internals" +cd .. + +cp workbench/App.js src +cp workbench/package.json package.json +cp workbench/webpack.config.js webpack.config.js +cp workbench/inter-package.json $INTERNALS/package.json + +cp $INTERNALS/example/src/UICustomizations.js src/Customisations + +echo "UI :: workbench " && echo "Branch: $(git branch --show-current)" && echo "$(git log -1 --pretty=%B)" && echo "installing packages" + diff --git a/frontend/micro-ui/web/workbench/inter-package.json b/frontend/micro-ui/web/workbench/inter-package.json new file mode 100644 index 00000000000..9918418de74 --- /dev/null +++ b/frontend/micro-ui/web/workbench/inter-package.json @@ -0,0 +1,56 @@ +{ + "name": "egovernments", + "version": "1.0.0", + "main": "index.js", + "workspaces": [ + "example", + "packages/css", + "packages/modules/*" + ], + "author": "JaganKumar ", + "license": "MIT", + "private": true, + "engines": { + "node": ">=14" + }, + "scripts": { + "start": "SKIP_PREFLIGHT_CHECK=true run-s build start:dev", + "sprint": "SKIP_PREFLIGHT_CHECK=true run-s start:script", + "start:dev": "run-p dev:**", + "start:script": "./scripts/create.sh", + "dev:css": "cd packages/css && yarn start", + "publish:css": "cd packages/css && yarn publish --access public", + "dev:example": "cd example && yarn start", + "dev:campaign": "cd packages/modules/campaign-manager && yarn start", + "build": "run-p build:**", + "build:campaign": "cd packages/modules/campaign-manager && yarn build", + "deploy:jenkins": "./scripts/jenkins.sh", + "clean": "rm -rf node_modules" + }, + "resolutions": { + "**/@babel/runtime": "7.20.1", + "**/babel-preset-react-app": "10.0.0" + }, + "devDependencies": { + "husky": "7.0.4", + "lint-staged": "12.3.7", + "npm-run-all": "4.1.5", + "prettier": "2.1.2" + }, + "husky": {}, + "lint-staged": { + "*.{js,css,md}": "prettier --write" + }, + "dependencies": { + "lodash": "4.17.21", + "microbundle-crl": "0.13.11", + "@egovernments/digit-ui-react-components": "1.8.1-beta.16", + "@egovernments/digit-ui-components": "0.0.1-beta.20", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "react-router-dom": "5.3.0" + } +} diff --git a/frontend/micro-ui/web/workbench/nginx.conf b/frontend/micro-ui/web/workbench/nginx.conf new file mode 100644 index 00000000000..974ef82f241 --- /dev/null +++ b/frontend/micro-ui/web/workbench/nginx.conf @@ -0,0 +1,12 @@ +server +{ + listen 80; + underscores_in_headers on; + + location /workbench-ui + { + root /var/web; + index index.html index.htm; + try_files $uri $uri/ /workbench-ui/index.html; + } +} \ No newline at end of file diff --git a/frontend/micro-ui/web/workbench/package.json b/frontend/micro-ui/web/workbench/package.json new file mode 100644 index 00000000000..4a6b031c032 --- /dev/null +++ b/frontend/micro-ui/web/workbench/package.json @@ -0,0 +1,81 @@ +{ + "name": "micro-ui", + "version": "1.0.0", + "author": "Jagankumar ", + "license": "MIT", + "private": true, + "engines": { + "node": ">=14" + }, + "workspaces": [ + "micro-ui-internals/packages/modules/*" + ], + "homepage": "/workbench-ui", + "dependencies": { + "@egovernments/digit-ui-libraries": "1.8.1-beta.4", + "@egovernments/digit-ui-module-core": "1.8.1-beta.23", + "@egovernments/digit-ui-module-utilities": "1.0.1-beta.5", + "@egovernments/digit-ui-react-components": "1.8.1-beta.23", + "@egovernments/digit-ui-components": "0.0.1-beta.25", + "@egovernments/digit-ui-module-workbench": "1.0.1-beta.16", + "@egovernments/digit-ui-module-hcmworkbench":"0.0.38", + "@egovernments/digit-ui-module-campaign-manager": "0.0.1", + "babel-loader": "8.1.0", + "clean-webpack-plugin": "4.0.0", + "react": "17.0.2", + "react-dom": "17.0.2", + "jsonpath": "^1.1.1", + "react-router-dom": "5.3.0", + "react-scripts": "4.0.1", + "web-vitals": "1.1.2", + "terser-brunch": "^4.1.0", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "css-loader": "5.2.6", + "style-loader": "2.0.0", + "webpack-cli": "4.10.0" + }, + "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "7.21.0", + "http-proxy-middleware": "1.3.1", + "lodash": "4.17.21", + "microbundle-crl": "0.13.11", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "react-router-dom": "5.3.0", + "husky": "7.0.4", + "lint-staged": "12.3.7", + "npm-run-all": "4.1.5", + "prettier": "2.1.2" + }, + "scripts": { + "start": "react-scripts start", + "build": "GENERATE_SOURCEMAP=false SKIP_PREFLIGHT_CHECK=true react-scripts build", + "build:prepare": "./build.sh", + "build:libraries": "cd micro-ui-internals && yarn build", + "build:prod": "webpack --mode production", + "build:webpack": "yarn build:libraries &&cd .. && ls && cd ./web && ls && yarn build:prod", + "clean": "rm -rf node_modules" + }, + "eslintConfig": { + "extends": [ + "react-app" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} diff --git a/frontend/micro-ui/web/workbench/webpack.config.js b/frontend/micro-ui/web/workbench/webpack.config.js new file mode 100644 index 00000000000..c19e631fe01 --- /dev/null +++ b/frontend/micro-ui/web/workbench/webpack.config.js @@ -0,0 +1,44 @@ +const path = require("path"); +const HtmlWebpackPlugin = require("html-webpack-plugin"); +const { CleanWebpackPlugin } = require("clean-webpack-plugin"); +// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; + +module.exports = { + // mode: 'development', + entry: "./src/index.js", + devtool: "none", + module: { + rules: [ + { + test: /\.(js)$/, + exclude: /node_modules/, + use: ["babel-loader"], + }, + { + test: /\.css$/i, + use: ["style-loader", "css-loader"], + } + ], + }, + output: { + filename: "[name].bundle.js", + path: path.resolve(__dirname, "build"), + publicPath: "/workbench-ui/", + }, + optimization: { + splitChunks: { + chunks: 'all', + minSize:20000, + maxSize:50000, + enforceSizeThreshold:50000, + minChunks:1, + maxAsyncRequests:30, + maxInitialRequests:30 + }, + }, + plugins: [ + new CleanWebpackPlugin(), + // new BundleAnalyzerPlugin(), + new HtmlWebpackPlugin({ inject: true, template: "public/index.html" }), + ], +}; \ No newline at end of file diff --git a/health-services/project-factory/.gitignore b/health-services/project-factory/.gitignore new file mode 100644 index 00000000000..29554b428f0 --- /dev/null +++ b/health-services/project-factory/.gitignore @@ -0,0 +1,120 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +.vscode/ + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +dist/ +jspm_packages/ + +.bin/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 + +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.pnp.* \ No newline at end of file diff --git a/health-services/project-factory/CHANGELOG.md b/health-services/project-factory/CHANGELOG.md new file mode 100644 index 00000000000..55f990d91ba --- /dev/null +++ b/health-services/project-factory/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog +All notable changes to this module will be documented in this file. + +## 0.1.0 - 2024-05-28 +#### Base ProjectFactory service + 1. ProjectFactory Service manages campaigns: creation, updating, searching, and data generation. + 2. Project Mapping : In campaign creation full project mapping is done with staff, facility and resources along with proper target values. + 3. Create Data: Validates and creates resource details of type facility,user and boundary. + 4. Generate Data: Generates sheet data of type facility,user and boundary. + 5. Boundary and Resource Validation: Validates boundaries and resources during campaign creation and updating. diff --git a/health-services/project-factory/Dockerfile b/health-services/project-factory/Dockerfile new file mode 100644 index 00000000000..124ed02c197 --- /dev/null +++ b/health-services/project-factory/Dockerfile @@ -0,0 +1,34 @@ +# Use Node.js base image with version 16 +FROM node:20 AS build + +# Set working directory +WORKDIR /app + +# Set build arguments +ARG BRANCH_NAME +ARG ACTION_NUMBER +ARG COMMIT_ID + +# Set environment variables based on build arguments +ENV BRANCH_NAME=$BRANCH_NAME +ENV ACTION_NUMBER=$ACTION_NUMBER +ENV COMMIT_ID=$COMMIT_ID + +# Copy package.json and yarn.lock (if exists) +COPY package.json ./ + +# Install dependencies +RUN yarn install + +# Optionally, you can add a label with the commit ID +LABEL commit_id=$COMMIT_ID + +# Copy the rest of the application code +COPY . . + +# Expose the port your app runs on +EXPOSE 3000 + +CMD ["yarn", "prod"] + # Replace "app.js" with your entry point file + diff --git a/health-services/project-factory/LICENSE b/health-services/project-factory/LICENSE new file mode 100644 index 00000000000..a0f698ede23 --- /dev/null +++ b/health-services/project-factory/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Jagankumar E + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/health-services/project-factory/LOCALSETUP.md b/health-services/project-factory/LOCALSETUP.md new file mode 100644 index 00000000000..3417b07ccd7 --- /dev/null +++ b/health-services/project-factory/LOCALSETUP.md @@ -0,0 +1,32 @@ +# Local Setup + +To set up the ProjectFactory service in your local system, clone the [Digit Frontend repository](https://github.com/egovernments/DIGIT-Frontend). + +## Dependencies + +### Infra Dependency + +- [x] Postgres DB +- [ ] Redis +- [ ] Elasticsearch +- [x] Kafka + - [x] Consumer + - [x] Producer + +## Running Locally + +### Local setup +1. To setup the ProjectFactory service, clone the [Digit Frontend repository](https://github.com/egovernments/DIGIT-Frontend). +2. Install Node.js version 20 using nvm (Node Version Manager). +3. Update the configs in [utilities/project-factory/src/server/config/index.ts](utilities/project-factory/src/server/config/index.ts), change HOST to "http://localhost:8080/" and KAFKA_BROKER_HOST to "localhost:9092". +4. Also update DB config values as per your local system config. +5. Update all dependency service host either on any unified-env or port-forward. +6. Open the terminal and run the following command + + `cd utilities/project-factory/` + + `yarn install` (run this command only once when you clone the repo) + + `yarn dev` + +> Note: After running the above command, if a Kafka error occurs, ensure that Kafka and Zookeeper are running in the background. If a connection error with another microservice occurs, ensure that the URL mentioned in the external mapping of the data config is correct, or you can port-forward that particular service. diff --git a/health-services/project-factory/README.md b/health-services/project-factory/README.md new file mode 100644 index 00000000000..40aee6d33bc --- /dev/null +++ b/health-services/project-factory/README.md @@ -0,0 +1,84 @@ +# ProjectFactory-Service + +The Project Factory Service is responsible for managing project-type campaigns, including creating, updating, searching, and creating campaigns. + +### DB UML Diagram + +![image](https://github.com/egovernments/DIGIT-Frontend/assets/137176738/8c43998d-742b-4629-ae90-63ab2b18772b) +![image](https://github.com/egovernments/DIGIT-Frontend/assets/137176738/3ff9609d-771a-4c6e-a769-54766e7111f7) + + +### Service Dependencies + +#### Core services + +- egov-localization +- egov-filestore +- egov-persister +- egov-mdms +- egov-idgen +- egov-boundaryservice-v2 + +#### Health services +- health-project +- health-hrms +- health-facility + +### Swagger API Contract +Please refer to the below Swagger API contract, for ProjectFactory service to understand the structure of APIs and to have visualization of all internal APIs [Swagger API contract](https://editor.swagger.io/?url=https://raw.githubusercontent.com/jagankumar-egov/DIGIT-Specs/hcm-workbench/Domain%20Services/Health/project-factory.yaml) + + +## Service Details + +### Funcatinality +1. ProjectFactory Service manages campaigns: creation, updating, searching, and data generation. +2. Project Mapping : In campaign creation full project mapping is done with staff, facility and resources along with proper target values. +3. Create Data: Validates and creates resource details of type facility,user and boundary. +4. Generate Data: Generates sheet data of type facility,user and boundary. +5. Boundary and Resource Validation: Validates boundaries and resources during campaign creation and updating. + +### Feature +1. Functionality to create campaigns easily. +2. Uploading generated datas sheets to filestore and return filestore id for easy access. +3. Supports localisation. +4. Customizable Delivery Rules: Allows defining delivery rules for projects based on specific criteria. +5. Search and Filtering: Enables searching and filtering campaigns based on various parameters like status, date, and creator. +6. Batch Processing: Supports batch processing for creating and updating multiple campaigns simultaneously. + +### External Libraries Used +[xlsx](https://github.com/SheetJS/sheetjs):- For reading and writing Excel files. + +[ajv](https://github.com/ajv-validator/ajv):- For JSON schema validation. + +[lodash](https://github.com/lodash/lodash):- For utility functions like data manipulation and object iteration. + + +### Configuration + +- Persister config: [here](https://github.com/egovernments/configs/blob/UNIFIED-UAT/health/egov-persister/project-factory-persister.yml) +- Helm chart details: [here](https://github.com/egovernments/DIGIT-DevOps/blob/unified-env/deploy-as-code/helm/charts/health-services/project-factory/values.yaml) + +### API Endpoints + +- `/project-factory/v1/project-type/create`: Creates a new project type campaign. +- `/project-factory/v1/project-type/update`: Updates an existing project type campaign. +- `/project-factory/v1/project-type/search`: Searches for project type campaigns based on specified criteria. +- `/project-factory/v1/data/_create`: Creates or validates resource data (e.g., facility, user, boundary). +- `/project-factory/v1/data/_search`: Searches for resource data based on specified criteria. +- `/project-factory/v1/data/_generate`: Initiates the generation of new data based on provided parameters. +- `/project-factory/v1/data/_download`: Downloads resource data based on specified criteria. + + +### Kafka Consumers + +- start-campaign-mapping: This topic is used by the service to initiate the mapping process for campaigns. + +### Kafka Producers + +- save-project-campaign-details: This topic is used to save project campaign details after creation. +- update-project-campaign-details: This topic is used to update project campaign details. +- create-resource-details: This topic is used to create resource details. +- update-resource-details: This topic is used to update resource details. +- create-resource-activity: This topic is used to create resource activity creation. +- create-generated-resource-details: This topic is used to save details for generated resources. +- update-generated-resource-details: This topic is used to update details for generated resources. diff --git a/health-services/project-factory/migration/Dockerfile b/health-services/project-factory/migration/Dockerfile new file mode 100644 index 00000000000..c1a628186c9 --- /dev/null +++ b/health-services/project-factory/migration/Dockerfile @@ -0,0 +1,11 @@ +FROM egovio/flyway:4.1.2 + +COPY ./ddl /flyway/sql + +# COPY ./seed /flyway/seed + +COPY migrate.sh /usr/bin/migrate.sh + +RUN chmod +x /usr/bin/migrate.sh + +CMD ["/usr/bin/migrate.sh"] diff --git a/health-services/project-factory/migration/ddl/V20240315110400__resource_details_ddl.sql b/health-services/project-factory/migration/ddl/V20240315110400__resource_details_ddl.sql new file mode 100644 index 00000000000..aecfae20001 --- /dev/null +++ b/health-services/project-factory/migration/ddl/V20240315110400__resource_details_ddl.sql @@ -0,0 +1,46 @@ +CREATE TABLE eg_cm_resource_details ( + id varchar(128) PRIMARY KEY, + "status" varchar(128) NOT NULL, + tenantId varchar(128) NOT NULL, + fileStoreId varchar(128) NOT NULL, + processedFileStoreId varchar(128), + "action" varchar(128) NOT NULL, + "type" varchar(64) NOT NULL, + createdBy varchar(128) NOT NULL, + createdTime bigint NOT NULL, + lastModifiedBy varchar(128), + lastModifiedTime bigint, + additionalDetails jsonb +); + +CREATE TABLE eg_cm_resource_activity ( + id varchar(128) PRIMARY KEY, + retryCount integer, + "type" varchar(64), + "url" varchar(128), + requestPayload jsonb, + tenantId varchar(128) NOT NULL, + responsePayload jsonb, + "status" bigint, + createdBy varchar(128), + createdTime bigint, + lastModifiedBy varchar(128), + lastModifiedTime bigint, + additionalDetails jsonb, + resourceDetailsId varchar(128), + FOREIGN KEY (resourceDetailsId) REFERENCES eg_cm_resource_details(id) +); + +CREATE TABLE eg_cm_generated_resource_details ( + id varchar(128) PRIMARY KEY, + fileStoreId varchar(128), + "status" varchar(128), + "type" varchar(128), + tenantid varchar(128), + count bigint, + createdBy varchar(128), + createdTime bigint, + lastModifiedBy varchar(128), + lastModifiedTime bigint, + additionalDetails jsonb +); diff --git a/health-services/project-factory/migration/ddl/V20240315110513__campaign_details_ddl.sql b/health-services/project-factory/migration/ddl/V20240315110513__campaign_details_ddl.sql new file mode 100644 index 00000000000..1f6426149f5 --- /dev/null +++ b/health-services/project-factory/migration/ddl/V20240315110513__campaign_details_ddl.sql @@ -0,0 +1,16 @@ +CREATE TABLE eg_cm_campaign_details ( + id character varying(128) PRIMARY KEY, + tenantId character varying(64) NOT NULL, + "status" character varying(128) NOT NULL, + "action" character varying(64) NOT NULL, + campaignNumber character varying(128) NOT NULL, + hierarchyType character varying(128) NOT NULL, + boundaryCode character varying(64), + projectId character varying(128), + createdBy character varying(128) NOT NULL, + lastModifiedBy character varying(128), + createdTime bigint NOT NULL, + lastModifiedTime bigint, + additionalDetails jsonb, + campaignDetails jsonb +); diff --git a/health-services/project-factory/migration/ddl/V20240401154500__campaign_details_add_columns.sql b/health-services/project-factory/migration/ddl/V20240401154500__campaign_details_add_columns.sql new file mode 100644 index 00000000000..eaf0c681333 --- /dev/null +++ b/health-services/project-factory/migration/ddl/V20240401154500__campaign_details_add_columns.sql @@ -0,0 +1,3 @@ +ALTER TABLE eg_cm_campaign_details +ADD COLUMN campaignName character varying(128) UNIQUE, +ADD COLUMN projectType character varying(128); diff --git a/health-services/project-factory/migration/ddl/V20240402134500__campaign_details_alter_column.sql b/health-services/project-factory/migration/ddl/V20240402134500__campaign_details_alter_column.sql new file mode 100644 index 00000000000..7a49127c9dd --- /dev/null +++ b/health-services/project-factory/migration/ddl/V20240402134500__campaign_details_alter_column.sql @@ -0,0 +1,2 @@ +ALTER TABLE eg_cm_campaign_details +ALTER COLUMN hierarchyType DROP NOT NULL; diff --git a/health-services/project-factory/migration/ddl/V20240410154500__campaign_details_alter_column.sql b/health-services/project-factory/migration/ddl/V20240410154500__campaign_details_alter_column.sql new file mode 100644 index 00000000000..05dfea2b5c7 --- /dev/null +++ b/health-services/project-factory/migration/ddl/V20240410154500__campaign_details_alter_column.sql @@ -0,0 +1,3 @@ +ALTER TABLE eg_cm_campaign_details +ADD COLUMN startDate bigint, +ADD COLUMN endDate bigint; \ No newline at end of file diff --git a/health-services/project-factory/migration/ddl/V20240416170000__generate_add_column.sql b/health-services/project-factory/migration/ddl/V20240416170000__generate_add_column.sql new file mode 100644 index 00000000000..c96caaa0e5f --- /dev/null +++ b/health-services/project-factory/migration/ddl/V20240416170000__generate_add_column.sql @@ -0,0 +1,2 @@ +ALTER TABLE eg_cm_generated_resource_details +ADD COLUMN hierarchyType varchar(128); \ No newline at end of file diff --git a/health-services/project-factory/migration/ddl/V20240427174100__campaign_add_column.sql b/health-services/project-factory/migration/ddl/V20240427174100__campaign_add_column.sql new file mode 100644 index 00000000000..36707083732 --- /dev/null +++ b/health-services/project-factory/migration/ddl/V20240427174100__campaign_add_column.sql @@ -0,0 +1,2 @@ +ALTER TABLE eg_cm_campaign_details +ALTER COLUMN campaignName TYPE character varying(250); \ No newline at end of file diff --git a/health-services/project-factory/migration/ddl/V20240522143500__resource_details_alter_column.sql b/health-services/project-factory/migration/ddl/V20240522143500__resource_details_alter_column.sql new file mode 100644 index 00000000000..25fc10438f1 --- /dev/null +++ b/health-services/project-factory/migration/ddl/V20240522143500__resource_details_alter_column.sql @@ -0,0 +1,2 @@ +ALTER TABLE eg_cm_resource_details +ADD COLUMN campaignId character varying(128); \ No newline at end of file diff --git a/health-services/project-factory/migration/migrate.sh b/health-services/project-factory/migration/migrate.sh new file mode 100755 index 00000000000..af0d542cdf5 --- /dev/null +++ b/health-services/project-factory/migration/migrate.sh @@ -0,0 +1,4 @@ +#!/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 + diff --git a/health-services/project-factory/package-lock.json b/health-services/project-factory/package-lock.json new file mode 100644 index 00000000000..7009ff20067 --- /dev/null +++ b/health-services/project-factory/package-lock.json @@ -0,0 +1,9058 @@ +{ + "name": "project-factory", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "project-factory", + "version": "0.0.1", + "license": "MIT", + "dependencies": { + "axios": "1.6.8", + "body-parser": "1.20.2", + "compression": "1.7.4", + "express": "4.18.3", + "hash-sum": "2.0.0", + "helmet": "7.1.0", + "jsonpath": "1.1.1", + "kafka-node": "5.0.0", + "lodash": "4.17.21", + "morgan": "1.10.0", + "node-cache": "5.1.2", + "node-gyp": "^10.0.1", + "uuid": "9.0.1", + "winston": "3.12.0", + "xlsx": "0.18.5", + "xlsx-populate": "1.21.0", + "yup": "1.4.0" + }, + "devDependencies": { + "@types/compression": "1.7.5", + "@types/express": "4.17.21", + "@types/hash-sum": "^1.0.2", + "@types/helmet": "0.0.47", + "@types/jest": "29.5.12", + "@types/morgan": "1.9.9", + "@types/node": "20.11.29", + "@types/pg": "8.11.3", + "@types/uuid": "9.0.8", + "@types/xlsx": "0.0.36", + "eslint": "^7.16.0", + "jest": "29.7.0", + "pg": "8.11.3", + "ts-node-dev": "2.0.0", + "typescript": "5.4.2" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.24.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.4", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.4", + "@babel/parser": "^7.24.4", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/core/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.24.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.4", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.4", + "dev": true, + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", + "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz", + "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template/node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/traverse/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "license": "MIT", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@eslint/eslintrc/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@eslint/eslintrc/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", + "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/core": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", + "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/reporters": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.7.0", + "jest-config": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-resolve-dependencies": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "jest-watcher": "^29.7.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/environment": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", + "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.7.0", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", + "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", + "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", + "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/types": "^29.6.3", + "jest-mock": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", + "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^6.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", + "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", + "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", + "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.6.3", + "@jridgewell/trace-mapping": "^0.3.18", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@npmcli/agent": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", + "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", + "license": "ISC", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "license": "ISC", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", + "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.5", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", + "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/compression": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz", + "integrity": "sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/express": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", + "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.43", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", + "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*", + "@types/send": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-UP28RddqY8xcU0SCEp9YKutQICXpaAq9N8U2klqF5hegGha7KzTOL8EdhIIV3bOSGBzjEpN9bU/d+nNZBdJYVw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/helmet": { + "version": "0.0.47", + "resolved": "https://registry.npmjs.org/@types/helmet/-/helmet-0.0.47.tgz", + "integrity": "sha512-TcHA/djjdUtrMtq/QAayVLrsgjNNZ1Uhtz0KhfH01mrmjH44E54DA1A0HNbwW0H/NBFqV+tGMo85ACuEhMXcdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/http-errors": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", + "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.12", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", + "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/mime": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", + "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/morgan": { + "version": "1.9.9", + "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.9.tgz", + "integrity": "sha512-iRYSDKVaC6FkGSpEVVIvrRGw0DfJMiQzIn3qr2G5B3C//AWkulhXgaBd7tS9/J79GWSYMTHGs7PfI5b3Y8m+RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.11.29", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.29.tgz", + "integrity": "sha512-P99thMkD/1YkCvAtOd6/zGedKNA0p2fj4ZpjCzcNiSCBWgm3cNRTBfa/qjFnsKkkojxu4vVLtWpesnZ9+ap+gA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/pg": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.11.3.tgz", + "integrity": "sha512-xocw4LvpDcj/Ta7bN52tLZm34mso5SZ0Q8fVC0UtD8s85Itip3YHvBeYZhBmC0OThpdOujHsxXtRbEIRxqXPXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^4.0.1" + } + }, + "node_modules/@types/qs": { + "version": "6.9.14", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.14.tgz", + "integrity": "sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/range-parser": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", + "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/send": { + "version": "0.17.4", + "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", + "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/mime": "^1", + "@types/node": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.7", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", + "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-errors": "*", + "@types/node": "*", + "@types/send": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/strip-json-comments": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", + "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", + "license": "MIT" + }, + "node_modules/@types/uuid": { + "version": "9.0.8", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", + "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/xlsx": { + "version": "0.0.36", + "resolved": "https://registry.npmjs.org/@types/xlsx/-/xlsx-0.0.36.tgz", + "integrity": "sha512-mvfrKiKKMErQzLMF8ElYEH21qxWCZtN59pHhWGmWCWFJStYdMWjkDSAy6mGowFxHXaXZWe5/TW7pBUiWclIVOw==", + "deprecated": "This is a stub types definition for xlsx (https://github.com/sheetjs/js-xlsx). xlsx provides its own type definitions, so you don't need @types/xlsx installed!", + "dev": true, + "dependencies": { + "xlsx": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", + "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/adler-32": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", + "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/agent-base/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/agent-base/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "license": "ISC", + "optional": true + }, + "node_modules/are-we-there-yet": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", + "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", + "license": "ISC", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", + "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", + "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/transform": "^29.7.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.6.3", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", + "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", + "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "babel-plugin-jest-hoist": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/binary": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", + "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", + "license": "MIT", + "dependencies": { + "buffers": "~0.1.1", + "chainsaw": "~0.1.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", + "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", + "license": "MIT", + "dependencies": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "license": "MIT", + "optional": true, + "dependencies": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "node_modules/buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "license": "MIT", + "optional": true + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", + "license": "MIT", + "optional": true + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/buffermaker": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/buffermaker/-/buffermaker-1.2.1.tgz", + "integrity": "sha512-IdnyU2jDHU65U63JuVQNTHiWjPRH0CS3aYd/WPaEwyX84rFdukhOduAVb1jwUScmb5X0JWPw8NZOrhoLMiyAHQ==", + "license": "MIT", + "dependencies": { + "long": "1.1.2" + } + }, + "node_modules/buffers": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", + "integrity": "sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==", + "engines": { + "node": ">=0.2.0" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz", + "integrity": "sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw==", + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/cacache/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "license": "ISC", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001605", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz", + "integrity": "sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/cfb": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", + "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", + "license": "Apache-2.0", + "dependencies": { + "adler-32": "~1.3.0", + "crc-32": "~1.2.0" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/chainsaw": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", + "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", + "license": "MIT/X11", + "dependencies": { + "traverse": ">=0.3.0 <0.4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/codepage": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", + "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", + "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "license": "MIT", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/color/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "license": "MIT" + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "license": "MIT", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "license": "MIT", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC", + "optional": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "license": "MIT" + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "license": "Apache-2.0", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/create-jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", + "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "prompts": "^2.0.1" + }, + "bin": { + "create-jest": "bin/create-jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", + "license": "MIT", + "optional": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/dedent": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", + "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT", + "optional": true + }, + "node_modules/denque": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", + "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", + "license": "Apache-2.0", + "optional": true, + "bin": { + "detect-libc": "bin/detect-libc.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", + "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dynamic-dedupe": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", + "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.726", + "dev": true, + "license": "ISC" + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "license": "MIT" + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escodegen": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", + "license": "MIT", + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "license": "MIT", + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/escodegen/node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", + "license": "MIT", + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/eslint/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "license": "(MIT OR WTFPL)", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/expect": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", + "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/expect-utils": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "license": "Apache-2.0" + }, + "node_modules/express": { + "version": "4.18.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", + "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.5.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "license": "MIT" + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", + "license": "MIT" + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "license": "MIT", + "optional": true + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", + "license": "MIT" + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/frac": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", + "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "license": "MIT", + "optional": true + }, + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==", + "license": "ISC", + "optional": true, + "dependencies": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "license": "MIT", + "optional": true + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC", + "optional": true + }, + "node_modules/hash-sum": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", + "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==", + "license": "MIT" + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/helmet": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.1.0.tgz", + "integrity": "sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", + "license": "BSD-2-Clause" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/http-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" + }, + "node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "license": "ISC", + "optional": true + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-address/node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "license": "BSD-3-Clause" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", + "license": "MIT", + "optional": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "license": "MIT" + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz", + "integrity": "sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/istanbul-lib-source-maps/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/istanbul-reports": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", + "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/types": "^29.6.3", + "import-local": "^3.0.2", + "jest-cli": "^29.7.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", + "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "execa": "^5.0.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", + "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/expect": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^1.0.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.7.0", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.7.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-config": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", + "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-jest": "^29.7.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-runner": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-docblock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", + "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", + "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "jest-util": "^29.7.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-environment-node": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", + "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-mock": "^29.7.0", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", + "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.6.3", + "jest-util": "^29.7.0", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", + "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", + "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", + "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.6.3", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.7.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/jest-mock": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", + "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "jest-util": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", + "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", + "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", + "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-regex-util": "^29.6.3", + "jest-snapshot": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", + "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/console": "^29.7.0", + "@jest/environment": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.7.0", + "jest-environment-node": "^29.7.0", + "jest-haste-map": "^29.7.0", + "jest-leak-detector": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-resolve": "^29.7.0", + "jest-runtime": "^29.7.0", + "jest-util": "^29.7.0", + "jest-watcher": "^29.7.0", + "jest-worker": "^29.7.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", + "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/environment": "^29.7.0", + "@jest/fake-timers": "^29.7.0", + "@jest/globals": "^29.7.0", + "@jest/source-map": "^29.6.3", + "@jest/test-result": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-mock": "^29.7.0", + "jest-regex-util": "^29.6.3", + "jest-resolve": "^29.7.0", + "jest-snapshot": "^29.7.0", + "jest-util": "^29.7.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", + "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.7.0", + "@jest/transform": "^29.7.0", + "@jest/types": "^29.6.3", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.7.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.7.0", + "jest-get-type": "^29.6.3", + "jest-matcher-utils": "^29.7.0", + "jest-message-util": "^29.7.0", + "jest-util": "^29.7.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.7.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-watcher": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", + "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.7.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "license": "MIT" + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonpath": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.1.1.tgz", + "integrity": "sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==", + "license": "MIT", + "dependencies": { + "esprima": "1.2.2", + "static-eval": "2.0.2", + "underscore": "1.12.1" + } + }, + "node_modules/jsonpath/node_modules/esprima": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz", + "integrity": "sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/kafka-node": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/kafka-node/-/kafka-node-5.0.0.tgz", + "integrity": "sha512-dD2ga5gLcQhsq1yNoQdy1MU4x4z7YnXM5bcG9SdQuiNr5KKuAmXixH1Mggwdah5o7EfholFbcNDPSVA6BIfaug==", + "license": "MIT", + "dependencies": { + "async": "^2.6.2", + "binary": "~0.3.0", + "bl": "^2.2.0", + "buffer-crc32": "~0.2.5", + "buffermaker": "~1.2.0", + "debug": "^2.1.3", + "denque": "^1.3.0", + "lodash": "^4.17.4", + "minimatch": "^3.0.2", + "nested-error-stacks": "^2.0.0", + "optional": "^0.1.3", + "retry": "^0.10.1", + "uuid": "^3.0.0" + }, + "engines": { + "node": ">=8.5.1" + }, + "optionalDependencies": { + "snappy": "^6.0.1" + } + }, + "node_modules/kafka-node/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "license": "MIT", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", + "license": "MIT" + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/logform": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", + "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", + "license": "MIT", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/logform/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/long": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/long/-/long-1.1.2.tgz", + "integrity": "sha512-pjR3OP1X2VVQhCQlrq3s8UxugQsuoucwMOn9Yj/kN/61HMc+lDFJS5bvpNEHneZ9NVaSm8gNWxZvtGS7lqHb3Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/make-fetch-happen": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", + "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", + "license": "ISC", + "dependencies": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", + "license": "MIT" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "devOptional": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "license": "MIT", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "optional": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "license": "MIT", + "dependencies": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/morgan/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/nan": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz", + "integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==", + "license": "MIT", + "optional": true + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "license": "MIT", + "optional": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/nested-error-stacks": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz", + "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==", + "license": "MIT" + }, + "node_modules/node-abi": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", + "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", + "license": "MIT", + "optional": true, + "dependencies": { + "semver": "^5.4.1" + } + }, + "node_modules/node-abi/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/node-cache": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", + "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", + "license": "MIT", + "dependencies": { + "clone": "2.x" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/node-gyp": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.1.0.tgz", + "integrity": "sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA==", + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/node-gyp/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/node-gyp/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true, + "license": "MIT" + }, + "node_modules/noop-logger": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", + "integrity": "sha512-6kM8CLXvuW5crTxsAtva2YLrRrDaiTIkIePWs9moLHqbFWT94WpNFjwS/5dfLfECg5i/lkmw3aoqVidxt23TEQ==", + "license": "MIT", + "optional": true + }, + "node_modules/nopt": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", + "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", + "license": "ISC", + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "license": "ISC", + "optional": true, + "dependencies": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "license": "MIT", + "dependencies": { + "fn.name": "1.x.x" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optional": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/optional/-/optional-0.1.4.tgz", + "integrity": "sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw==", + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "license": "ISC", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "license": "MIT" + }, + "node_modules/pg": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", + "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.6.2", + "pg-pool": "^3.6.1", + "pg-protocol": "^1.6.0", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.1.1" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", + "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.4.tgz", + "integrity": "sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==", + "dev": true, + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-numeric": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", + "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=4" + } + }, + "node_modules/pg-pool": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.2.tgz", + "integrity": "sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.1.tgz", + "integrity": "sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==", + "dev": true, + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.2.tgz", + "integrity": "sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==", + "dev": true, + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "pg-numeric": "1.0.2", + "postgres-array": "~3.0.1", + "postgres-bytea": "~3.0.0", + "postgres-date": "~2.1.0", + "postgres-interval": "^3.0.0", + "postgres-range": "^1.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pg/node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pg/node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/pg/node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pg/node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pg/node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postgres-array": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz", + "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/postgres-bytea": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", + "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "obuf": "~1.1.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postgres-date": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz", + "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/postgres-interval": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", + "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/postgres-range": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz", + "integrity": "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/prebuild-install": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.0.tgz", + "integrity": "sha512-aaLVANlj4HgZweKttFNUVNRxDukytuIuxeK2boIMHjagNJCiVKWFsKF4tCE3ql3GbrD2tExPQ7/pwtEJcHNZeg==", + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^1.0.3", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "napi-build-utils": "^1.0.1", + "node-abi": "^2.7.0", + "noop-logger": "^0.1.1", + "npmlog": "^4.0.1", + "os-homedir": "^1.0.1", + "pump": "^2.0.1", + "rc": "^1.2.7", + "simple-get": "^2.7.0", + "tar-fs": "^1.13.0", + "tunnel-agent": "^0.6.0", + "which-pm-runs": "^1.0.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/promise-retry/node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/property-expr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", + "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==", + "license": "MIT" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "license": "MIT", + "optional": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "optional": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/retry": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", + "integrity": "sha512-ZXUSQYTHdl3uS7IuCehYfMzKyIDBNoAuUblvy5oGO5UJSUTmStUUVPXbA9Qxd173Bgre53yCQczQuHgRWAdvJQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/safe-stable-stringify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", + "license": "ISC" + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "license": "MIT", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC", + "optional": true + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, + "node_modules/simple-get": { + "version": "2.8.2", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz", + "integrity": "sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw==", + "license": "MIT", + "optional": true, + "dependencies": { + "decompress-response": "^3.3.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/simple-swizzle/node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", + "license": "MIT" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true, + "license": "MIT" + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/snappy": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/snappy/-/snappy-6.3.5.tgz", + "integrity": "sha512-lonrUtdp1b1uDn1dbwgQbBsb5BbaiLeKq+AGwOk2No+en+VvJThwmtztwulEQsLinRF681pBqib0NUZaizKLIA==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "bindings": "^1.3.1", + "nan": "^2.14.1", + "prebuild-install": "5.3.0" + } + }, + "node_modules/socks": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz", + "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==", + "license": "MIT", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", + "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/socks-proxy-agent/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socks-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "license": "MIT" + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "devOptional": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/ssf": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", + "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", + "license": "Apache-2.0", + "dependencies": { + "frac": "~1.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/ssri": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", + "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/static-eval": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz", + "integrity": "sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg==", + "license": "MIT", + "dependencies": { + "escodegen": "^1.8.1" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", + "license": "MIT", + "optional": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/table": { + "version": "6.8.2", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", + "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/table/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-fs": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", + "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", + "license": "MIT", + "optional": true, + "dependencies": { + "chownr": "^1.0.1", + "mkdirp": "^0.5.1", + "pump": "^1.0.0", + "tar-stream": "^1.1.2" + } + }, + "node_modules/tar-fs/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "license": "ISC", + "optional": true + }, + "node_modules/tar-fs/node_modules/pump": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", + "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", + "license": "MIT", + "optional": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "license": "MIT", + "optional": true, + "dependencies": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/tar-stream/node_modules/bl": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", + "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", + "license": "MIT", + "optional": true, + "dependencies": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC" + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", + "license": "MIT" + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tiny-case": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", + "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==", + "license": "MIT" + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", + "license": "MIT", + "optional": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/toposort": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", + "license": "MIT" + }, + "node_modules/traverse": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", + "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", + "license": "MIT/X11" + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "license": "MIT", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node-dev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz", + "integrity": "sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.1", + "dynamic-dedupe": "^0.3.0", + "minimist": "^1.2.6", + "mkdirp": "^1.0.4", + "resolve": "^1.0.0", + "rimraf": "^2.6.1", + "source-map-support": "^0.5.12", + "tree-kill": "^1.2.2", + "ts-node": "^10.4.0", + "tsconfig": "^7.0.0" + }, + "bin": { + "ts-node-dev": "lib/bin.js", + "tsnd": "lib/bin.js" + }, + "engines": { + "node": ">=0.8.0" + }, + "peerDependencies": { + "node-notifier": "*", + "typescript": "*" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/ts-node-dev/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-node-dev/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/ts-node/node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/tsconfig": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", + "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/strip-bom": "^3.0.0", + "@types/strip-json-comments": "0.0.30", + "strip-bom": "^3.0.0", + "strip-json-comments": "^2.0.0" + } + }, + "node_modules/tsconfig/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/tsconfig/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typescript": { + "version": "5.4.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", + "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/underscore": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", + "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==", + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true, + "license": "MIT" + }, + "node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "license": "ISC", + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", + "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/v8-to-istanbul": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", + "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", + "dev": true, + "license": "ISC", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^2.0.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-pm-runs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", + "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/winston": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.12.0.tgz", + "integrity": "sha512-OwbxKaOlESDi01mC9rkM0dQqQt2I8DAUMRLZ/HpbwvDXm85IryEHgoogy5fziQy38PntgZsLlhAYHz//UPHZ5w==", + "license": "MIT", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.7.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", + "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==", + "license": "MIT", + "dependencies": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/winston/node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "license": "MIT" + }, + "node_modules/winston/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/wmf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", + "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", + "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", + "license": "Apache-2.0", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "devOptional": true, + "license": "ISC" + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/xlsx": { + "version": "0.18.5", + "resolved": "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz", + "integrity": "sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ==", + "dependencies": { + "adler-32": "~1.3.0", + "cfb": "~1.2.1", + "codepage": "~1.15.0", + "crc-32": "~1.2.1", + "ssf": "~0.11.2", + "wmf": "~1.0.1", + "word": "~0.3.0" + }, + "bin": { + "xlsx": "bin/xlsx.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/xlsx-populate": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/xlsx-populate/-/xlsx-populate-1.21.0.tgz", + "integrity": "sha512-8v2Gm8BehXo6LU7KT802QoXTPkYY1SKk5V8g/UuYZnNB3JzXqud/P99Pxr2yXeKyt+sKlCatmidz6jQNie1hRw==", + "license": "MIT", + "dependencies": { + "cfb": "^1.1.3", + "jszip": "^3.2.2", + "lodash": "^4.17.15", + "sax": "^1.2.4" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yup": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/yup/-/yup-1.4.0.tgz", + "integrity": "sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg==", + "license": "MIT", + "dependencies": { + "property-expr": "^2.0.5", + "tiny-case": "^1.0.3", + "toposort": "^2.0.2", + "type-fest": "^2.19.0" + } + }, + "node_modules/yup/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/health-services/project-factory/package.json b/health-services/project-factory/package.json new file mode 100644 index 00000000000..5e7a3d20727 --- /dev/null +++ b/health-services/project-factory/package.json @@ -0,0 +1,60 @@ +{ + "name": "project-factory", + "version": "0.1.0", + "main": "src/server/index.ts", + "author": "Jagankumar ", + "description": "Backend For Frontend service", + "license": "MIT", + "private": true, + "scripts": { + "build": "yarn run build-ts", + "build-ts": "tsc", + "clean": "rm -rf ./dist", + "serve": "node dist/index.js", + "start": "yarn run dev", + "test": "jest", + "dev": "ts-node-dev --respawn src/server/index.ts", + "prod": "yarn build && yarn serve", + "watch-ts": "tsc --watch" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/egovernments/DIGIT-Frontend.git" + }, + "dependencies": { + "axios": "1.6.8", + "body-parser": "1.20.2", + "compression": "1.7.4", + "express": "4.18.3", + "hash-sum": "2.0.0", + "helmet": "7.1.0", + "jsonpath": "1.1.1", + "kafka-node": "5.0.0", + "lodash": "4.17.21", + "morgan": "1.10.0", + "node-cache": "5.1.2", + "node-gyp": "^10.0.1", + "uuid": "9.0.1", + "winston": "3.12.0", + "xlsx": "0.18.5", + "xlsx-populate": "1.21.0", + "yup": "1.4.0" + }, + "devDependencies": { + "@types/compression": "1.7.5", + "@types/express": "4.17.21", + "@types/hash-sum": "^1.0.2", + "@types/helmet": "0.0.47", + "@types/jest": "29.5.12", + "@types/morgan": "1.9.9", + "@types/node": "20.11.29", + "@types/pg": "8.11.3", + "@types/uuid": "9.0.8", + "@types/xlsx": "0.0.36", + "eslint": "^7.16.0", + "jest": "29.7.0", + "pg": "8.11.3", + "ts-node-dev": "2.0.0", + "typescript": "5.4.2" + } +} \ No newline at end of file diff --git a/health-services/project-factory/postman_collection.json b/health-services/project-factory/postman_collection.json new file mode 100644 index 00000000000..5780448766a --- /dev/null +++ b/health-services/project-factory/postman_collection.json @@ -0,0 +1,899 @@ +{ + "info": { + "_postman_id": "4faeccce-fc50-4dfb-8fef-d973aca136c4", + "name": "Project factory", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "18845214" + }, + "item": [ + { + "name": "facility data generate(template generate)", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "content-type": true + } + }, + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-dev.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json", + "disabled": true + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" + }, + { + "key": "origin", + "value": "https://unified-dev.digit.org" + }, + { + "key": "referer", + "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" + }, + { + "key": "sec-ch-ua", + "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"Linux\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "same-origin" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"b902a184-4582-41f8-8144-99930548631d\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1716457221446|en_MZ\",\n \"plainAccessRequest\": {}\n}\n}" + }, + "url": { + "raw": "https://unified-uat.digit.org/project-factory/v1/data/_generate?tenantId=mz&type=boundary&forceUpdate=true&hierarchyType=ADMIN&campaignId=3b331cd6-c0e9-4fd4-9d15-9212ba51706c", + "protocol": "https", + "host": [ + "unified-uat", + "digit", + "org" + ], + "path": [ + "project-factory", + "v1", + "data", + "_generate" + ], + "query": [ + { + "key": "tenantId", + "value": "mz" + }, + { + "key": "type", + "value": "boundary" + }, + { + "key": "forceUpdate", + "value": "true" + }, + { + "key": "hierarchyType", + "value": "ADMIN" + }, + { + "key": "campaignId", + "value": "3b331cd6-c0e9-4fd4-9d15-9212ba51706c" + } + ] + } + }, + "response": [] + }, + { + "name": "boundary data generate(template generate)", + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-uat.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1ho6v1de2.1ho6v2ouk.ot.21.qu; _ga_H9YC8FEN6F=GS1.1.1709630860.87.1.1709630957.60.0.0; PGADMIN_LANGUAGE=en" + }, + { + "key": "origin", + "value": "https://unified-uat.digit.org" + }, + { + "key": "referer", + "value": "https://unified-uat.digit.org/workbench-ui/employee/campaign/setup-campaign?key=7&preview=false&id=2c948509-4245-4df7-b46b-9cabd5cdb577" + }, + { + "key": "sec-ch-ua", + "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"Linux\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "same-origin" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\"Filters\":null,\"RequestInfo\":{\"apiId\":\"Rainmaker\",\"authToken\":\"f364ac54-8e9a-49ec-8aff-a3df278bd68d\",\"userInfo\":{\"id\":1052,\"uuid\":\"8b110055-330f-4e7b-b4c0-f618f29b9d47\",\"userName\":\"UATMZ\",\"name\":\"UATMZ\",\"mobileNumber\":\"8998988112\",\"emailId\":null,\"locale\":null,\"type\":\"EMPLOYEE\",\"roles\":[{\"name\":\"System Administrator\",\"code\":\"SYSTEM_ADMINISTRATOR\",\"tenantId\":\"mz\"},{\"name\":\"Campaign Manager\",\"code\":\"CAMPAIGN_MANAGER\",\"tenantId\":\"mz\"},{\"name\":\"Localisation admin\",\"code\":\"LOC_ADMIN\",\"tenantId\":\"mz\"},{\"name\":\"MDMS ADMIN\",\"code\":\"MDMS_ADMIN\",\"tenantId\":\"mz\"}],\"active\":true,\"tenantId\":\"mz\",\"permanentCity\":null},\"msgId\":\"1716892389916|en_IN\",\"plainAccessRequest\":{}}}" + }, + "url": { + "raw": "https://unified-uat.digit.org/project-factory/v1/data/_generate?tenantId=mz&type=boundary&forceUpdate=true&hierarchyType=ADMIN&campaignId=2c948509-4245-4df7-b46b-9cabd5cdb577", + "protocol": "https", + "host": [ + "unified-uat", + "digit", + "org" + ], + "path": [ + "project-factory", + "v1", + "data", + "_generate" + ], + "query": [ + { + "key": "tenantId", + "value": "mz" + }, + { + "key": "type", + "value": "boundary" + }, + { + "key": "forceUpdate", + "value": "true" + }, + { + "key": "hierarchyType", + "value": "ADMIN" + }, + { + "key": "campaignId", + "value": "2c948509-4245-4df7-b46b-9cabd5cdb577" + } + ] + } + }, + "response": [] + }, + { + "name": "User generate data(template generate)", + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-uat.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1ho6v1de2.1ho6v2ouk.ot.21.qu; _ga_H9YC8FEN6F=GS1.1.1709630860.87.1.1709630957.60.0.0; PGADMIN_LANGUAGE=en" + }, + { + "key": "origin", + "value": "https://unified-uat.digit.org" + }, + { + "key": "referer", + "value": "https://unified-uat.digit.org/workbench-ui/employee/campaign/setup-campaign?key=7&preview=false&id=2c948509-4245-4df7-b46b-9cabd5cdb577" + }, + { + "key": "sec-ch-ua", + "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"Linux\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "same-origin" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\"RequestInfo\":{\"apiId\":\"Rainmaker\",\"authToken\":\"f364ac54-8e9a-49ec-8aff-a3df278bd68d\",\"userInfo\":{\"id\":1052,\"uuid\":\"8b110055-330f-4e7b-b4c0-f618f29b9d47\",\"userName\":\"UATMZ\",\"name\":\"UATMZ\",\"mobileNumber\":\"8998988112\",\"emailId\":null,\"locale\":null,\"type\":\"EMPLOYEE\",\"roles\":[{\"name\":\"System Administrator\",\"code\":\"SYSTEM_ADMINISTRATOR\",\"tenantId\":\"mz\"},{\"name\":\"Campaign Manager\",\"code\":\"CAMPAIGN_MANAGER\",\"tenantId\":\"mz\"},{\"name\":\"Localisation admin\",\"code\":\"LOC_ADMIN\",\"tenantId\":\"mz\"},{\"name\":\"MDMS ADMIN\",\"code\":\"MDMS_ADMIN\",\"tenantId\":\"mz\"}],\"active\":true,\"tenantId\":\"mz\",\"permanentCity\":null},\"msgId\":\"1716892389917|en_IN\",\"plainAccessRequest\":{}}}" + }, + "url": { + "raw": "https://unified-uat.digit.org/project-factory/v1/data/_generate?tenantId=mz&type=userWithBoundary&forceUpdate=true&hierarchyType=ADMIN&campaignId=2c948509-4245-4df7-b46b-9cabd5cdb577", + "protocol": "https", + "host": [ + "unified-uat", + "digit", + "org" + ], + "path": [ + "project-factory", + "v1", + "data", + "_generate" + ], + "query": [ + { + "key": "tenantId", + "value": "mz" + }, + { + "key": "type", + "value": "userWithBoundary" + }, + { + "key": "forceUpdate", + "value": "true" + }, + { + "key": "hierarchyType", + "value": "ADMIN" + }, + { + "key": "campaignId", + "value": "2c948509-4245-4df7-b46b-9cabd5cdb577" + } + ] + } + }, + "response": [] + }, + { + "name": "data download", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "content-type": true + } + }, + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-dev.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json", + "disabled": true + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" + }, + { + "key": "origin", + "value": "https://unified-dev.digit.org" + }, + { + "key": "referer", + "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" + }, + { + "key": "sec-ch-ua", + "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"Linux\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "same-origin" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"b902a184-4582-41f8-8144-99930548631d\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1716457221446|en_MZ\",\n \"plainAccessRequest\": {}\n}\n}" + }, + "url": { + "raw": "https://unified-uat.digit.org/project-factory/v1/data/_download?tenantId=mz&hierarchyType=ADMIN&id=9a857a1b-ea6f-49ac-aaca-354de76f7cf3&type=boundary", + "protocol": "https", + "host": [ + "unified-uat", + "digit", + "org" + ], + "path": [ + "project-factory", + "v1", + "data", + "_download" + ], + "query": [ + { + "key": "tenantId", + "value": "mz" + }, + { + "key": "hierarchyType", + "value": "ADMIN" + }, + { + "key": "forecUpdate", + "value": "true", + "disabled": true + }, + { + "key": "id", + "value": "9a857a1b-ea6f-49ac-aaca-354de76f7cf3" + }, + { + "key": "type", + "value": "boundary" + } + ] + } + }, + "response": [] + }, + { + "name": "data create", + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-dev.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json" + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" + }, + { + "key": "origin", + "value": "https://unified-dev.digit.org" + }, + { + "key": "referer", + "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" + }, + { + "key": "sec-ch-ua", + "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"Linux\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "same-origin" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\":{\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"3dcb7be0-fa76-440f-959c-30c7839ca1d0\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1715753883629|en_MZ\",\n \"plainAccessRequest\": {}\n},\n \"ResourceDetails\": {\n \"type\": \"facility\",\n // \"type\": \"facility|user|boundary\",\n \"tenantId\": \"mz\",\n // empty facility\n // \"fileStoreId\": \"cf37fb7a-f07e-44da-9f11-c06841ffdd44\",\n // worng\n // \"fileStoreId\": \"823110ca-55a1-434b-83d4-138e9e262661\",\n // right\n // \"fileStoreId\":\"252e68d4-44f8-4088-814c-ba0046f7da0f\",\n // right user\n // \"fileStoreId\":\"589fc456-70ab-422f-9c9a-b92ea3304f54\",\n //rightt with 5000 rows\n // \"fileStoreId\": \"0b47f2b3-840a-40b5-af8d-2273b836fd79\",\n //rightt with 200 rows\n // \"fileStoreId\":\"078a35f3-6db9-497b-bed5-d58e0ae3800a\",\n \"fileStoreId\":\"ae72d4a2-1a3a-431c-b30a-699983cf9468\",\n \"action\": \"validate\",\n \"hierarchyType\": \"ADMIN\",\n \"additionalDetails\": {}\n }\n}" + }, + "url": { + "raw": "http://localhost:8080/project-factory/v1/data/_create", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "project-factory", + "v1", + "data", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "data search", + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-dev.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json" + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" + }, + { + "key": "origin", + "value": "https://unified-dev.digit.org" + }, + { + "key": "referer", + "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" + }, + { + "key": "sec-ch-ua", + "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"Linux\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "same-origin" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"49109c15-ca23-4399-931c-3df81c114302\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1713364121714|en_MZ\",\n \"plainAccessRequest\": {}\n},\n \"SearchCriteria\": {\n \"id\": [\n \"636faa32-661c-42bb-b955-837111f63773\"\n ],\n \"tenantId\": \"mz\",\n \"type\": \"facility\",\n \"status\": \"completed\"\n }\n}" + }, + "url": { + "raw": "http://localhost:8080/project-factory/v1/data/_search", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "project-factory", + "v1", + "data", + "_search" + ], + "query": [ + { + "key": "tenantId", + "value": "", + "disabled": true + } + ] + } + }, + "response": [] + }, + { + "name": "campaign create", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "content-type": true + } + }, + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-dev.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json" + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" + }, + { + "key": "origin", + "value": "https://unified-dev.digit.org" + }, + { + "key": "referer", + "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" + }, + { + "key": "sec-ch-ua", + "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"Linux\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "same-origin" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"0cc530cb-aeb7-4735-a89b-ed5b0607518d\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1713593588138|en_MZ\",\n \"plainAccessRequest\": {}\n},\n \"CampaignDetails\": {\n // \"id\":\"f9f9b96a-d8aa-427b-a755-25bcc22ef60f\",\n \"hierarchyType\": \"ADMIN\",\n \"tenantId\": \"mz\",\n \"campaignName\": \"testName860\",\n \"action\": \"create\",\n // \"action\": \"create\",\n \"startDate\": 1765497222002,\n \"endDate\": 1767497225002,\n // \"projectId\":\"74c57591-13cc-4e21-97d3-2b6c87e7fc98\",\n \"boundaries\": [\n {\n \"code\": \"f5F6xAskA05\",\n \"type\": \"Provincia\",\n \"isRoot\": false\n },\n {\n \"code\": \"mz\",\n \"type\": \"Country\",\n \"isRoot\": true,\n \"includeAllChildren\": true\n }\n ],\n \"resources\": [\n {\n \"filestoreId\": \"252e68d4-44f8-4088-814c-ba0046f7da0f\",\n \"type\": \"facility\",\n \"filename\": \"hkjsss.xlsx\"\n },\n {\n \"filestoreId\":\"49280d90-31f2-4911-8d1e-0482cc6bf70c\",\n \"type\": \"user\",\n \"filename\": \"hkjsss.xlsx\"\n }\n // {\n // \"filestoreId\": \"d96c0248-dcfd-414c-8f8c-635dad0a89f1\",\n // \"type\": \"boundary\",\n // \"filename\": \"s.xlsx\"\n // }\n ],\n \"projectType\": \"LLIN-mz\",\n \"deliveryRules\": [\n {\n \"startDate\": 1666497225000,\n \"endDate\": 1666497225000,\n \"cycleNumber\": 0,\n \"deliveryNumber\": 0,\n \"deliveryRuleNumber\": 0,\n \"products\": [\n \"string\"\n ],\n \"conditions\": [\n {\n \"attribute\": \"string\",\n \"operator\": \"string\",\n \"value\": 0\n }\n ]\n }\n // {\n // \"startDate\": 1667497225001,\n // \"endDate\": 1668897225001,\n // \"cycleNumber\": 0,\n // \"deliveryNumber\": 0,\n // \"deliveryRuleNumber\": 0,\n // \"products\": [\n // \"string\"\n // ],\n // \"conditions\": [\n // {\n // \"attribute\": \"string\",\n // \"operator\": \"string\",\n // \"value\": 0\n // }\n // ]\n // }\n ],\n \"additionalDetails\": {\n \"beneficiaryType\": \"HOUSEHOLD\"\n }\n }\n}" + }, + "url": { + "raw": "http://localhost:8080/project-factory/v1/project-type/create", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "project-factory", + "v1", + "project-type", + "create" + ] + } + }, + "response": [] + }, + { + "name": "update campaign", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "content-type": true + } + }, + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-dev.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json" + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" + }, + { + "key": "origin", + "value": "https://unified-dev.digit.org" + }, + { + "key": "referer", + "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" + }, + { + "key": "sec-ch-ua", + "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"Linux\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "same-origin" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + }, + { + "key": "Content-Type", + "value": "application/json", + "type": "text" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"44cb5589-8dc2-4182-b5a4-afdb692ce831\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1713364121714|en_MZ\",\n \"plainAccessRequest\": {}\n },\n \"CampaignDetails\": {\n \"id\": \"f9ea7046-75f2-4ac3-837d-caf14fdcdcca\",\n \"tenantId\": \"mz\",\n \"status\": \"drafted\",\n \"action\": \"draft\",\n \"campaignNumber\": \"CMP-2024-05-02-000855\",\n \"campaignName\": \"weartux\",\n \"projectType\": \"MR-DN\",\n \"hierarchyType\": \"ADMIN\",\n \"boundaryCode\": \"\",\n \"projectId\": null,\n \"startDate\": 0,\n \"endDate\": 0,\n \"createdBy\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"lastModifiedBy\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"createdTime\": 1714654527543,\n \"lastModifiedTime\": 1714654527544,\n \"additionalDetails\": {\n \"key\": 2,\n \"beneficiaryType\": \"INDIVIDUAL\"\n },\n \"campaignDetails\": {\n \"resources\": []\n }\n }\n}\n// \"boundaries\": [\n// {\n// \"code\": \"f5F6xAskA05\",\n// \"type\": \"Provincia\",\n// \"isRoot\": false\n// },\n// {\n// \"code\": \"mz\",\n// \"type\": \"Country\",\n// \"isRoot\": true,\n// \"includeAllChildren\": true\n// }\n// ]," + }, + "url": { + "raw": "https://unified-qa.digit.org/project-factory/v1/project-type/update", + "protocol": "https", + "host": [ + "unified-qa", + "digit", + "org" + ], + "path": [ + "project-factory", + "v1", + "project-type", + "update" + ] + } + }, + "response": [] + }, + { + "name": "campaign search", + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-dev.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json" + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" + }, + { + "key": "origin", + "value": "https://unified-dev.digit.org" + }, + { + "key": "referer", + "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" + }, + { + "key": "sec-ch-ua", + "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"Linux\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "same-origin" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"b2985fc2-9980-4fba-adcf-3248e3a66490\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1713364121714|en_MZ\",\n \"plainAccessRequest\": {}\n },\n \"CampaignDetails\": {\n \"ids\": [\n \"7cfc93f2-9c4c-4415-9417-e61d2203bdd8\"\n ],\n \"tenantId\": \"mz\",\n // \"startDate\": 1665497224000,\n // \"endDate\": 1665929226005,\n // \"projectType\": \"default1\",\n // \"campaignName\": \"test1Name803\",\n // \"status\": \"started\",\n // \"createdBy\": \"string\",\n // \"campaignNumber\": \"string\",\n \"pagination\": {\n \"sortBy\": \"createdTime\",\n \"sortOrder\": \"desc\",\n \"limit\": 15,\n \"offset\": 0\n }\n // \"createdTime\":1665929226005\n }\n}" + }, + "url": { + "raw": "http://localhost:8080/project-factory/v1/project-type/search", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "project-factory", + "v1", + "project-type", + "search" + ] + } + }, + "response": [] + } + ] +} diff --git a/health-services/project-factory/src/server/api/campaignApis.ts b/health-services/project-factory/src/server/api/campaignApis.ts new file mode 100644 index 00000000000..a0b81cc69b5 --- /dev/null +++ b/health-services/project-factory/src/server/api/campaignApis.ts @@ -0,0 +1,791 @@ +import config from "../config"; +import { v4 as uuidv4 } from 'uuid'; +import { httpRequest } from "../utils/request"; +import { getFormattedStringForDebug, logger } from "../utils/logger"; +import createAndSearch from '../config/createAndSearch'; +import { getDataFromSheet, matchData, generateActivityMessage, throwError, translateSchema, replicateRequest } from "../utils/genericUtils"; +import { immediateValidationForTargetSheet, validateSheetData, validateTargetSheetData } from '../validators/campaignValidators'; +import { callMdmsSchema, getCampaignNumber, getWorkbook } from "./genericApis"; +import { boundaryBulkUpload, convertToTypeData, generateHierarchy, generateProcessedFileAndPersist, getLocalizedName, reorderBoundariesOfDataAndValidate } from "../utils/campaignUtils"; +const _ = require('lodash'); +import * as XLSX from 'xlsx'; +import { produceModifiedMessages } from "../kafka/Listener"; +import { userRoles } from "../config/constants"; +import { createDataService } from "../service/dataManageService"; +import { searchProjectTypeCampaignService } from "../service/campaignManageService"; + + + +/** + * Enriches the campaign data with unique IDs and generates campaign numbers. + * @param requestBody The request body containing the campaign data. + */ +async function enrichCampaign(requestBody: any) { + // Enrich campaign data with unique IDs and generate campaign numbers + if (requestBody?.Campaign) { + requestBody.Campaign.id = uuidv4(); + requestBody.Campaign.campaignNo = await getCampaignNumber(requestBody, config.values.idgen.format, config.values.idgen.idName, requestBody?.Campaign?.tenantId); + for (const campaignDetails of requestBody?.Campaign?.CampaignDetails) { + campaignDetails.id = uuidv4(); + } + } +} + +async function getAllFacilitiesInLoop(searchedFacilities: any[], facilitySearchParams: any, facilitySearchBody: any) { + await new Promise(resolve => setTimeout(resolve, 3000)); // Wait for 3 seconds + const response = await httpRequest(config.host.facilityHost + config.paths.facilitySearch, facilitySearchBody, facilitySearchParams); + + if (Array.isArray(response?.Facilities)) { + searchedFacilities.push(...response?.Facilities); + return response.Facilities.length >= 50; // Return true if there are more facilities to fetch, false otherwise + } else { + throwError("FACILITY", 500, "FACILITY_SEARCH_FAILED"); + return false; + } +} + +/** + * Retrieves all facilities for a given tenant ID. + * @param tenantId The ID of the tenant. + * @param requestBody The request body containing additional parameters. + * @returns An array of facilities. + */ +async function getAllFacilities(tenantId: string, requestBody: any) { + // Retrieve all facilities for the given tenant ID + const facilitySearchBody = { + RequestInfo: requestBody?.RequestInfo, + Facility: { isPermanent: true } + }; + + const facilitySearchParams = { + limit: 50, + offset: 0, + tenantId: tenantId?.split('.')?.[0] + }; + + const searchedFacilities: any[] = []; + let searchAgain = true; + + while (searchAgain) { + searchAgain = await getAllFacilitiesInLoop(searchedFacilities, facilitySearchParams, facilitySearchBody); + facilitySearchParams.offset += 50; + } + + return searchedFacilities; +} + +/** + * Retrieves facilities by their IDs. + * @param tenantId The ID of the tenant. + * @param ids An array of facility IDs. + * @param requestBody The request body containing additional parameters. + * @returns An array of facilities. + */ +async function getFacilitiesViaIds(tenantId: string, ids: any[], requestBody: any) { + // Retrieve facilities by their IDs + const facilitySearchBody: any = { + RequestInfo: requestBody?.RequestInfo, + Facility: {} + }; + + const facilitySearchParams = { + limit: 50, + offset: 0, + tenantId: tenantId?.split('.')?.[0] + }; + + const searchedFacilities: any[] = []; + + // Split ids into chunks of 50 + for (let i = 0; i < ids.length; i += 50) { + const chunkIds = ids.slice(i, i + 50); + facilitySearchBody.Facility.id = chunkIds; + logger.info("facilitySearchBody : " + JSON.stringify(facilitySearchBody)); + await getAllFacilitiesInLoop(searchedFacilities, facilitySearchParams, facilitySearchBody); + } + + return searchedFacilities; +} + +/** + * Retrieves parameters based on elements. + * @param elements An array of elements. + * @param request The HTTP request object. + * @returns Parameters extracted from elements. + */ +function getParamsViaElements(elements: any, request: any) { + // Extract parameters based on elements + var params: any = {}; + if (!elements) { + return params; + } + for (const element of elements) { + if (element?.isInParams) { + if (element?.value) { + _.set(params, element?.keyPath, element?.value); + } + else if (element?.getValueViaPath) { + _.set(params, element?.keyPath, _.get(request.body, element?.getValueViaPath)) + } + } + } + return params +} + +/** + * Changes request body based on elements. + * @param elements An array of elements. + * @param requestBody The request body to be modified. + */ +function changeBodyViaElements(elements: any, requestBody: any) { + // Modify request body based on elements + if (!elements) { + return; + } + for (const element of elements) { + if (element?.isInBody) { + if (element?.value) { + _.set(requestBody, element?.keyPath, element?.value); + } + else if (element?.getValueViaPath) { + _.set(requestBody, element?.keyPath, _.get(requestBody, element?.getValueViaPath)) + } + else { + _.set(requestBody, element?.keyPath, {}) + } + } + } +} + +function changeBodyViaSearchFromSheet(elements: any, request: any, dataFromSheet: any) { + if (!elements) { + return; + } + for (const element of elements) { + const arrayToSearch = [] + for (const data of dataFromSheet) { + if (data[element.sheetColumnName]) { + arrayToSearch.push(data[element.sheetColumnName]); + } + } + _.set(request.body, element?.searchPath, arrayToSearch); + } +} + +function updateErrorsForUser(newCreatedData: any[], newSearchedData: any[], errors: any[], createAndSearchConfig: any, userNameAndPassword: any[]) { + newCreatedData.forEach((createdElement: any) => { + let foundMatch = false; + for (const searchedElement of newSearchedData) { + if (searchedElement?.code === createdElement?.code) { + foundMatch = true; + newSearchedData.splice(newSearchedData.indexOf(searchedElement), 1); + errors.push({ status: "CREATED", rowNumber: createdElement["!row#number!"], isUniqueIdentifier: true, uniqueIdentifier: _.get(searchedElement, createAndSearchConfig.uniqueIdentifier, ""), errorDetails: "" }) + userNameAndPassword.push({ + userName: searchedElement?.user?.userName, + password: "eGov@123", + rowNumber: createdElement["!row#number!"] + }) + break; + } + } + if (!foundMatch) { + errors.push({ status: "NOT_CREATED", rowNumber: createdElement["!row#number!"], errorDetails: `Can't confirm creation of this data` }) + logger.info("Can't confirm creation of this data of row number : " + createdElement["!row#number!"]); + } + }); +} + +function updateErrors(newCreatedData: any[], newSearchedData: any[], errors: any[], createAndSearchConfig: any) { + newCreatedData.forEach((createdElement: any) => { + let foundMatch = false; + for (const searchedElement of newSearchedData) { + let match = true; + for (const key in createdElement) { + // console.log(key, createdElement[key], searchedElement[key], " ssssssssssssssssssssssssssssssssss"); + if (createdElement.hasOwnProperty(key) && !searchedElement.hasOwnProperty(key) && key != '!row#number!') { + match = false; + break; + } + if (createdElement[key] !== searchedElement[key] && key != '!row#number!') { + match = false; + break; + } + } + if (match) { + foundMatch = true; + newSearchedData.splice(newSearchedData.indexOf(searchedElement), 1); + errors.push({ status: "CREATED", rowNumber: createdElement["!row#number!"], isUniqueIdentifier: true, uniqueIdentifier: _.get(searchedElement, createAndSearchConfig.uniqueIdentifier, ""), errorDetails: "" }) + break; + } + } + if (!foundMatch) { + errors.push({ status: "NOT_CREATED", rowNumber: createdElement["!row#number!"], errorDetails: `Can't confirm creation of this data` }) + logger.info("Can't confirm creation of this data of row number : " + createdElement["!row#number!"]); + } + }); +} + + +function matchCreatedAndSearchedData(createdData: any[], searchedData: any[], request: any, createAndSearchConfig: any, activities: any) { + const newCreatedData = JSON.parse(JSON.stringify(createdData)); + const newSearchedData = JSON.parse(JSON.stringify(searchedData)); + const uid = createAndSearchConfig.uniqueIdentifier; + newCreatedData.forEach((element: any) => { + delete element[uid]; + }) + var errors: any[] = [] + if (request?.body?.ResourceDetails?.type != "user") { + if (request?.body?.ResourceDetails?.type == "facility") { + newCreatedData?.forEach((element: any) => { + delete element.address + }) + } + updateErrors(newCreatedData, newSearchedData, errors, createAndSearchConfig); + } + else { + var userNameAndPassword: any = [] + updateErrorsForUser(newCreatedData, newSearchedData, errors, createAndSearchConfig, userNameAndPassword); + request.body.userNameAndPassword = userNameAndPassword + } + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; + request.body.Activities = activities +} + +function matchUserValidation(createdData: any[], searchedData: any[], request: any, createAndSearchConfig: any) { + var count = 0; + const errors = [] + const codeSet = new Set(searchedData.map(item => item?.code)); + const numberSet = new Set(searchedData.map(item => item?.user?.mobileNumber)); + for (const data of createdData) { + if (codeSet.has(data.code) && numberSet.has(data?.user?.mobileNumber)) { + errors.push({ status: "INVALID", rowNumber: data["!row#number!"], errorDetails: `User with mobileNumber ${data?.user?.mobileNumber} and userName ${data.code} already exists` }) + count++; + } + else if (codeSet.has(data.code)) { + errors.push({ status: "INVALID", rowNumber: data["!row#number!"], errorDetails: `User with userName ${data.code} already exists` }) + count++; + } + else if (numberSet.has(data?.user?.mobileNumber)) { + errors.push({ status: "INVALID", rowNumber: data["!row#number!"], errorDetails: `User with mobileNumber ${data?.user?.mobileNumber} already exists` }) + count++; + } + } + if (count) { + request.body.ResourceDetails.status = "invalid" + } + logger.info("Invalid resources count : " + count); + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; +} +function matchViaUserIdAndCreationTime(createdData: any[], searchedData: any[], request: any, creationTime: any, createAndSearchConfig: any, activities: any) { + var matchingSearchData = []; + const userUuid = request?.body?.RequestInfo?.userInfo?.uuid + var count = 0; + if (request?.body?.ResourceDetails?.type != "user") { + for (const data of searchedData) { + if (data?.auditDetails?.createdBy == userUuid && data?.auditDetails?.createdTime >= creationTime) { + matchingSearchData.push(data); + count++; + } + } + } + else { + const codeSet = new Set(createdData.map(item => item.code)); + for (const data of searchedData) { + if (codeSet.has(data.code)) { + matchingSearchData.push(data); + count++; + } + } + } + if (count < createdData.length) { + request.body.ResourceDetails.status = "PERSISTER_ERROR" + } + matchCreatedAndSearchedData(createdData, matchingSearchData, request, createAndSearchConfig, activities); + logger.info("New created resources count : " + count); +} + +async function processSearch(createAndSearchConfig: any, request: any, params: any) { + setSearchLimits(createAndSearchConfig, request, params); + const arraysToMatch = await performSearch(createAndSearchConfig, request, params); + + return arraysToMatch; +} + +function setSearchLimits(createAndSearchConfig: any, request: any, params: any) { + setLimitOrOffset(createAndSearchConfig?.searchDetails?.searchLimit, params, request.body); + setLimitOrOffset(createAndSearchConfig?.searchDetails?.searchOffset, params, request.body); +} + +function setLimitOrOffset(limitOrOffsetConfig: any, params: any, requestBody: any) { + if (limitOrOffsetConfig) { + if (limitOrOffsetConfig?.isInParams) { + _.set(params, limitOrOffsetConfig?.keyPath, parseInt(limitOrOffsetConfig?.value)); + } + if (limitOrOffsetConfig?.isInBody) { + _.set(requestBody, limitOrOffsetConfig?.keyPath, parseInt(limitOrOffsetConfig?.value)); + } + } +} + +async function performSearch(createAndSearchConfig: any, request: any, params: any) { + const arraysToMatch: any[] = []; + let searchAgain = true; + + while (searchAgain) { + const searcRequestBody = { + RequestInfo: request?.body?.RequestInfo + } + changeBodyViaElements(createAndSearchConfig?.searchDetails?.searchElements, searcRequestBody) + const response = await httpRequest(createAndSearchConfig?.searchDetails?.url, searcRequestBody, params); + const resultArray = _.get(response, createAndSearchConfig?.searchDetails?.searchPath); + if (resultArray && Array.isArray(resultArray)) { + arraysToMatch.push(...resultArray); + if (resultArray.length < parseInt(createAndSearchConfig?.searchDetails?.searchLimit?.value)) { + searchAgain = false; + } + } else { + searchAgain = false; + } + updateOffset(createAndSearchConfig, params, request.body); + await new Promise(resolve => setTimeout(resolve, 5000)); + } + return arraysToMatch; +} + +function updateOffset(createAndSearchConfig: any, params: any, requestBody: any) { + const offsetConfig = createAndSearchConfig?.searchDetails?.searchOffset + const limit = createAndSearchConfig?.searchDetails?.searchLimit?.value + if (offsetConfig) { + if (offsetConfig?.isInParams) { + _.set(params, offsetConfig?.keyPath, parseInt(_.get(params, offsetConfig?.keyPath) + parseInt(limit))); + } + if (offsetConfig?.isInBody) { + _.set(requestBody, offsetConfig?.keyPath, parseInt(_.get(requestBody, offsetConfig?.keyPath) + parseInt(limit))); + } + } +} + + +async function processSearchAndValidation(request: any, createAndSearchConfig: any, dataFromSheet: any[]) { + if (request?.body?.dataToSearch?.length > 0) { + const params: any = getParamsViaElements(createAndSearchConfig?.searchDetails?.searchElements, request); + changeBodyViaElements(createAndSearchConfig?.searchDetails?.searchElements, request) + changeBodyViaSearchFromSheet(createAndSearchConfig?.requiresToSearchFromSheet, request, dataFromSheet) + const arraysToMatch = await processSearch(createAndSearchConfig, request, params) + matchData(request, request.body.dataToSearch, arraysToMatch, createAndSearchConfig) + } + if (request?.body?.ResourceDetails?.type == "user") { + await enrichEmployees(request?.body?.dataToCreate, request) + const params: any = getParamsViaElements(createAndSearchConfig?.searchDetails?.searchElements, request); + const arraysToMatch = await processSearch(createAndSearchConfig, request, params) + matchUserValidation(request.body.dataToCreate, arraysToMatch, request, createAndSearchConfig) + } +} + + + +// Confirms the creation of resources by matching created and searched data. +async function confirmCreation(createAndSearchConfig: any, request: any, dataToCreate: any[], creationTime: any, activities: any) { + // Confirm creation of resources by matching data // wait for 5 seconds + const params: any = getParamsViaElements(createAndSearchConfig?.searchDetails?.searchElements, request); + const arraysToMatch = await processSearch(createAndSearchConfig, request, params) + matchViaUserIdAndCreationTime(dataToCreate, arraysToMatch, request, creationTime, createAndSearchConfig, activities) +} + +async function processValidateAfterSchema(dataFromSheet: any, request: any, createAndSearchConfig: any, localizationMap?: { [key: string]: string }) { + try { + const typeData = await convertToTypeData(request, dataFromSheet, createAndSearchConfig, request.body, localizationMap) + request.body.dataToSearch = typeData.searchData; + request.body.dataToCreate = typeData.createData; + await processSearchAndValidation(request, createAndSearchConfig, dataFromSheet) + await reorderBoundariesOfDataAndValidate(request, localizationMap) + await generateProcessedFileAndPersist(request, localizationMap); + } catch (error) { + await handleResouceDetailsError(request, error); + } +} + +async function processValidate(request: any, localizationMap?: { [key: string]: string }) { + const type: string = request.body.ResourceDetails.type; + const tenantId = request.body.ResourceDetails.tenantId; + const createAndSearchConfig = createAndSearch[type] + const dataFromSheet = await getDataFromSheet(request, request?.body?.ResourceDetails?.fileStoreId, request?.body?.ResourceDetails?.tenantId, createAndSearchConfig, null, localizationMap) + if (type == 'boundaryWithTarget') { + immediateValidationForTargetSheet(dataFromSheet, localizationMap); + validateTargetSheetData(dataFromSheet, request, createAndSearchConfig?.boundaryValidation, localizationMap); + } + + else { + let schema: any; + if (type == "facility" || type == "user") { + const mdmsResponse = await callMdmsSchema(request, config?.values?.moduleName, type, tenantId); + schema = mdmsResponse + } + const translatedSchema = await translateSchema(schema, localizationMap); + await validateSheetData(dataFromSheet, request, translatedSchema, createAndSearchConfig?.boundaryValidation, localizationMap) + processValidateAfterSchema(dataFromSheet, request, createAndSearchConfig, localizationMap) + } +} + +function convertUserRoles(employees: any[], request: any) { + for (const employee of employees) { + if (employee?.user?.roles) { + var newRoles: any[] = [] + const rolesArray = employee.user.roles.split(',').map((role: any) => role.trim()); + for (const role of rolesArray) { + newRoles.push({ name: role, code: userRoles[role], tenantId: request?.body?.ResourceDetails?.tenantId }) + } + employee.user.roles = newRoles + } + } +} + +function generateHash(input: string): string { + const prime = 31; // Prime number + let hash = 0; + for (let i = 0; i < input.length; i++) { + hash = (hash * prime + input.charCodeAt(i)) % 100000; // Limit hash to 5 digits + } + return hash.toString().padStart(6, '0'); +} + +function enrichUserNameAndPassword(employees: any[]) { + const epochTime = Date.now(); + employees.forEach((employee) => { + const { user, "!row#number!": rowNumber } = employee; + const nameInitials = user.name.split(' ').map((name: any) => name.charAt(0)).join(''); + const generatedCode = `${nameInitials}${generateHash(`${epochTime}`)}${rowNumber}`; + user.userName = generatedCode; + user.password = "eGov@123"; + employee.code = generatedCode + }); +} + +async function enrichJurisdictions(employee: any, request: any) { + employee.jurisdictions = [ + { + tenantId: request?.body?.ResourceDetails?.tenantId, + boundaryType: config.values.userMainBoundaryType, + boundary: config.values.userMainBoundary, + hierarchy: request?.body?.ResourceDetails?.hierarchyType, + roles: employee?.user?.roles + } + ] +} + +async function enrichEmployees(employees: any[], request: any) { + convertUserRoles(employees, request) + for (const employee of employees) { + enrichUserNameAndPassword(employees) + await enrichJurisdictions(employee, request) + if (employee?.user) { + employee.user.tenantId = request?.body?.ResourceDetails?.tenantId + employee.user.dob = 0 + } + } +} + +async function performAndSaveResourceActivity(request: any, createAndSearchConfig: any, params: any, type: any, localizationMap?: { [key: string]: string }) { + logger.info(type + " create data : " + JSON.stringify(request?.body?.dataToCreate)); + logger.info(type + " bulk create url : " + createAndSearchConfig?.createBulkDetails?.url, params); + if (createAndSearchConfig?.createBulkDetails?.limit) { + const limit = createAndSearchConfig?.createBulkDetails?.limit; + const dataToCreate = request?.body?.dataToCreate; + const chunks = Math.ceil(dataToCreate.length / limit); // Calculate number of chunks + var creationTime = Date.now(); + var activities = []; + for (let i = 0; i < chunks; i++) { + const start = i * limit; + const end = (i + 1) * limit; + const chunkData = dataToCreate.slice(start, end); // Get a chunk of data + const newRequestBody: any = { + RequestInfo: request?.body?.RequestInfo, + } + _.set(newRequestBody, createAndSearchConfig?.createBulkDetails?.createPath, chunkData); + var gotFailed = true, retryCount = 7; + while (gotFailed && retryCount > 0) { + try { + creationTime = Date.now(); + retryCount = retryCount - 1; + gotFailed = false; + if (type == "facility") { + for (const facility of newRequestBody.Facilities) { + facility.address = {} + } + logger.info("Facility create data : " + JSON.stringify(newRequestBody)); + var responsePayload = await httpRequest(createAndSearchConfig?.createBulkDetails?.url, newRequestBody, params, "post", undefined, undefined, true); + } + else if (type == "user") { + var responsePayload = await httpRequest(createAndSearchConfig?.createBulkDetails?.url, newRequestBody, params, "post", undefined, undefined, true); + } + } catch (error) { + var e = error; + gotFailed = true; + } + logger.info("Creation got failed, Waiting for 30 seconds to retry.. retryCounts left : " + retryCount) + await new Promise(resolve => setTimeout(resolve, 30000)); + } + if (gotFailed) { + throw e; + } + var activity = await generateActivityMessage(request?.body?.ResourceDetails?.tenantId, request.body, newRequestBody, responsePayload, type, createAndSearchConfig?.createBulkDetails?.url, responsePayload?.statusCode) + logger.info("Activity : " + JSON.stringify(activity)); + activities.push(activity); + await new Promise(resolve => setTimeout(resolve, 10000)); + } + await confirmCreation(createAndSearchConfig, request, dataToCreate, creationTime, activities); + } + await generateProcessedFileAndPersist(request, localizationMap); +} + +/** + * Processes generic requests such as create or validate. + * @param request The HTTP request object. + */ +async function processGenericRequest(request: any, localizationMap?: { [key: string]: string }) { + // Process generic requests + if (request?.body?.ResourceDetails?.action == "create") { + await processCreate(request, localizationMap) + } + else { + await processValidate(request, localizationMap) + } +} + +async function handleResouceDetailsError(request: any, error: any) { + logger.error("Error while processing after validation : " + error) + if (request?.body?.ResourceDetails) { + request.body.ResourceDetails.status = "failed"; + request.body.ResourceDetails.additionalDetails = { + ...request?.body?.ResourceDetails?.additionalDetails, + error: JSON.stringify({ + status: error.status || '', + code: error.code || '', + description: error.description || '', + message: error.message || '' + }) + }; + produceModifiedMessages(request?.body, config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC); + } + if (request?.body?.Activities && Array.isArray(request?.body?.Activities && request?.body?.Activities.length > 0)) { + await new Promise(resolve => setTimeout(resolve, 2000)); + produceModifiedMessages(request?.body, config?.kafka?.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC); + } +} + +async function processAfterValidation(dataFromSheet: any, createAndSearchConfig: any, request: any, localizationMap?: { [key: string]: string }) { + try { + const typeData = await convertToTypeData(request, dataFromSheet, createAndSearchConfig, request.body, localizationMap) + request.body.dataToCreate = typeData.createData; + request.body.dataToSearch = typeData.searchData; + await processSearchAndValidation(request, createAndSearchConfig, dataFromSheet) + await reorderBoundariesOfDataAndValidate(request, localizationMap) + if (createAndSearchConfig?.createBulkDetails && request.body.ResourceDetails.status != "invalid") { + _.set(request.body, createAndSearchConfig?.createBulkDetails?.createPath, request?.body?.dataToCreate); + const params: any = getParamsViaElements(createAndSearchConfig?.createBulkDetails?.createElements, request); + changeBodyViaElements(createAndSearchConfig?.createBulkDetails?.createElements, request) + await performAndSaveResourceActivity(request, createAndSearchConfig, params, request.body.ResourceDetails.type, localizationMap); + } + else if (request.body.ResourceDetails.status == "invalid") { + await generateProcessedFileAndPersist(request, localizationMap); + } + } catch (error: any) { + await handleResouceDetailsError(request, error) + } +} + +/** + * Processes the creation of resources. + * @param request The HTTP request object. + */ +async function processCreate(request: any, localizationMap?: any) { + // Process creation of resources + const type: string = request.body.ResourceDetails.type; + const tenantId = request?.body?.ResourceDetails?.tenantId; + if (type == "boundary") { + boundaryBulkUpload(request, localizationMap); + } + else { + const createAndSearchConfig = createAndSearch[type] + const dataFromSheet = await getDataFromSheet(request, request?.body?.ResourceDetails?.fileStoreId, request?.body?.ResourceDetails?.tenantId, createAndSearchConfig, undefined, localizationMap) + let schema: any; + if (type == "facility" || type == "user") { + const mdmsResponse = await callMdmsSchema(request, config?.values?.moduleName, type, tenantId); + schema = mdmsResponse + } + const translatedSchema = await translateSchema(schema, localizationMap); + await validateSheetData(dataFromSheet, request, translatedSchema, createAndSearchConfig?.boundaryValidation, localizationMap) + processAfterValidation(dataFromSheet, createAndSearchConfig, request, localizationMap) + } +} + +/** + * Creates resources for a project campaign. + * @param request The HTTP request object. + */ +async function createProjectCampaignResourcData(request: any) { + // Create resources for a project campaign + if (request?.body?.CampaignDetails?.action == "create" && request?.body?.CampaignDetails?.resources) { + for (const resource of request?.body?.CampaignDetails?.resources) { + if (resource.type != "boundaryWithTarget") { + const resourceDetails = { + type: resource.type, + fileStoreId: resource.filestoreId, + tenantId: request?.body?.CampaignDetails?.tenantId, + action: "create", + hierarchyType: request?.body?.CampaignDetails?.hierarchyType, + additionalDetails: {}, + campaignId: request?.body?.CampaignDetails?.id + }; + logger.info(`Creating the resources for type ${resource.type}`) + logger.debug("resourceDetails " + getFormattedStringForDebug(resourceDetails)) + const createRequestBody = { + RequestInfo: request.body.RequestInfo, + ResourceDetails: resourceDetails + } + const req = replicateRequest(request, createRequestBody) + const res: any = await createDataService(req) + if (res?.id) { + resource.createResourceId = res?.id + } + } + } + } +} + +async function confirmProjectParentCreation(request: any, projectId: any) { + const searchBody = { + RequestInfo: request.body.RequestInfo, + Projects: [ + { + id: projectId, + tenantId: request.body.CampaignDetails.tenantId + } + ] + } + const params = { + tenantId: request.body.CampaignDetails.tenantId, + offset: 0, + limit: 5 + } + var projectFound = false; + var retry = 6; + while (!projectFound && retry >= 0) { + const response = await httpRequest(config.host.projectHost + config.paths.projectSearch, searchBody, params); + if (response?.Project?.[0]) { + projectFound = true; + } + else { + logger.info("Project not found. Waiting for 1 seconds"); + retry = retry - 1 + await new Promise(resolve => setTimeout(resolve, 1000)); + } + } + if (!projectFound) { + throwError("PROJECT", 500, "PROJECT_CONFIRMATION_FAILED", "Project confirmation failed, for the project with id " + projectId); + } +} + +async function projectCreate(projectCreateBody: any, request: any) { + logger.info("Project creation url " + config.host.projectHost + config.paths.projectCreate) + logger.debug("Project creation body " + getFormattedStringForDebug(projectCreateBody)) + const projectCreateResponse = await httpRequest(config.host.projectHost + config.paths.projectCreate, projectCreateBody); + logger.debug("Project creation response" + getFormattedStringForDebug(projectCreateResponse)) + if (projectCreateResponse?.Project[0]?.id) { + logger.info("Project created successfully with id " + JSON.stringify(projectCreateResponse?.Project[0]?.id)) + logger.info(`for boundary type ${projectCreateResponse?.Project[0]?.address?.boundaryType} and code ${projectCreateResponse?.Project[0]?.address?.boundary}`) + request.body.boundaryProjectMapping[projectCreateBody?.Projects?.[0]?.address?.boundary].projectId = projectCreateResponse?.Project[0]?.id + } + else { + throwError("PROJECT", 500, "PROJECT_CREATION_FAILED", "Project creation failed, for the request: " + JSON.stringify(projectCreateBody)); + } +} + +function generateHierarchyList(data: any[], parentChain: any = []) { + let result: any[] = []; + + // Iterate over each boundary in the current level + for (let boundary of data) { + let currentChain = [...parentChain, boundary.code]; + + // Add the current chain to the result + result.push(currentChain.join(',')); + + // If there are children, recursively call the function + if (boundary.children && boundary.children.length > 0) { + let childResults = generateHierarchyList(boundary.children, currentChain); + result = result.concat(childResults); + } + } + return result; + +} + +const getHierarchy = async (request: any, tenantId: string, hierarchyType: string) => { + const url = `${config.host.boundaryHost}${config.paths.boundaryHierarchy}`; + + // Create request body + const requestBody = { + "RequestInfo": request?.body?.RequestInfo, + "BoundaryTypeHierarchySearchCriteria": { + "tenantId": tenantId, + "limit": 5, + "offset": 0, + "hierarchyType": hierarchyType + } + }; + + const response = await httpRequest(url, requestBody); + const boundaryList = response?.BoundaryHierarchy?.[0].boundaryHierarchy; + return generateHierarchy(boundaryList); +}; + +const getHeadersOfBoundarySheet = async (fileUrl: string, sheetName: string, getRow = false, localizationMap?: any) => { + const localizedBoundarySheetName = getLocalizedName(sheetName, localizationMap) + const workbook: any = await getWorkbook(fileUrl, localizedBoundarySheetName); + const columnsToValidate = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName], { + header: 1, + })[0] as (any)[]; + + // Filter out empty items and return the result + for (let i = 0; i < columnsToValidate.length; i++) { + if (typeof columnsToValidate[i] !== 'string') { + columnsToValidate[i] = undefined; + } + } + return columnsToValidate; +} +async function getFiltersFromCampaignSearchResponse(request: any) { + logger.info(`searching for campaign details to get the filters for boundary generation`); + const requestInfo = { "RequestInfo": request?.body?.RequestInfo }; + const campaignDetails = { "CampaignDetails": { tenantId: request?.query?.tenantId, "ids": [request?.query?.campaignId] } } + const requestBody = { ...requestInfo, ...campaignDetails }; + const req: any = replicateRequest(request, requestBody) + const projectTypeSearchResponse: any = await searchProjectTypeCampaignService(req); + const boundaries = projectTypeSearchResponse?.CampaignDetails?.[0]?.boundaries?.map((ele: any) => ({ ...ele, boundaryType: ele?.type })); + if (!boundaries) { + logger.info(`no boundaries found so considering the complete hierarchy`); + return { Filters: null }; + } + logger.info(`boundaries found for filtering`); + return { Filters: { boundaries: boundaries } }; +} + +export { + enrichCampaign, + getAllFacilities, + getFacilitiesViaIds, + confirmCreation, + getParamsViaElements, + changeBodyViaElements, + processGenericRequest, + createProjectCampaignResourcData, + processCreate, + projectCreate, + generateHierarchyList, + getHierarchy, + getHeadersOfBoundarySheet, + handleResouceDetailsError, + getFiltersFromCampaignSearchResponse, + confirmProjectParentCreation +}; diff --git a/health-services/project-factory/src/server/api/genericApis.ts b/health-services/project-factory/src/server/api/genericApis.ts new file mode 100644 index 00000000000..675842e9beb --- /dev/null +++ b/health-services/project-factory/src/server/api/genericApis.ts @@ -0,0 +1,1105 @@ +// Import necessary modules and libraries +import * as XLSX from "xlsx"; // Import XLSX library for Excel file processing +import config from "../config"; // Import configuration settings +import FormData from "form-data"; // Import FormData for handling multipart/form-data requests +import { httpRequest } from "../utils/request"; // Import httpRequest function for making HTTP requests +import { getFormattedStringForDebug, logger } from "../utils/logger"; // Import logger for logging +import { correctParentValues, findMapValue, generateActivityMessage, getBoundaryRelationshipData, getDataSheetReady, getLocalizedHeaders, sortCampaignDetails, throwError } from "../utils/genericUtils"; // Import utility functions +import { validateProjectFacilityResponse, validateProjectResourceResponse, validateStaffResponse } from "../validators/genericValidator"; // Import validation functions +import { extractCodesFromBoundaryRelationshipResponse, generateFilteredBoundaryData, getLocalizedName } from '../utils/campaignUtils'; // Import utility functions +import { getFiltersFromCampaignSearchResponse, getHierarchy } from './campaignApis'; +import { validateMappingId } from '../utils/campaignMappingUtils'; +import { campaignStatuses } from '../config/constants'; +import { getBoundaryTabName } from '../utils/boundaryUtils'; +const _ = require('lodash'); // Import lodash library + +// Function to retrieve workbook from Excel file URL and sheet name +const getWorkbook = async (fileUrl: string, sheetName: string) => { + // Define headers for HTTP request + const headers = { + "Content-Type": "application/json", + Accept: "application/pdf", + }; + + // Make HTTP request to retrieve Excel file as arraybuffer + const responseFile = await httpRequest( + fileUrl, + null, + {}, + "get", + "arraybuffer", + headers + ); + + // Read Excel file into workbook + const workbook = XLSX.read(responseFile, { type: "buffer" }); + // Check if the specified sheet exists in the workbook + if (!workbook.Sheets.hasOwnProperty(sheetName)) { + throwError( + "FILE", + 400, + "INVALID_SHEETNAME", + `Sheet with name "${sheetName}" is not present in the file.` + ); + } + + // Return the workbook + return workbook; +}; + +//Function to get Workbook with different tabs (for type target) +const getTargetWorkbook = async (fileUrl: string, localizationMap?: any) => { + // Define headers for HTTP request + const headers = { + "Content-Type": "application/json", + Accept: "application/pdf", + }; + + // Make HTTP request to retrieve Excel file as arraybuffer + const responseFile = await httpRequest( + fileUrl, + null, + {}, + "get", + "arraybuffer", + headers + ); + + // Read Excel file into workbook + const workbook = XLSX.read(responseFile, { type: "buffer" }); + const mainSheet = workbook.SheetNames[1]; + const localizedMainSheet = getLocalizedName(mainSheet, localizationMap); + if (!workbook.Sheets.hasOwnProperty(mainSheet)) { + throwError( + "FILE", + 400, + "INVALID_SHEETNAME", + `Sheet with name "${localizedMainSheet}" is not present in the file.` + ); + } + + // Return the workbook + return workbook; +}; + +function isNumeric(value: any) { + return /^-?\d+(\.\d+)?$/.test(value); +} + +// Function to retrieve data from a specific sheet in an Excel file +const getSheetData = async ( + fileUrl: string, + sheetName: string, + getRow = false, + createAndSearchConfig?: any, + localizationMap?: { [key: string]: string } +) => { + // Retrieve workbook using the getWorkbook function + const localizedSheetName = getLocalizedName(sheetName, localizationMap); + const workbook: any = await getWorkbook(fileUrl, localizedSheetName); + + // If parsing array configuration is provided, validate first row of each column + if ( + createAndSearchConfig && + createAndSearchConfig.parseArrayConfig && + createAndSearchConfig.parseArrayConfig.parseLogic + ) { + const parseLogic = createAndSearchConfig.parseArrayConfig.parseLogic; + // Iterate over each column configuration + for (const columnConfig of parseLogic) { + const { sheetColumn } = columnConfig; + const expectedColumnName = columnConfig.sheetColumnName; + var localizedColumnName; + localizedColumnName = getLocalizedName( + expectedColumnName, + localizationMap + ); + // Get the value of the first row in the current column + if (sheetColumn && localizedColumnName) { + const firstRowValue = + workbook.Sheets[localizedSheetName][`${sheetColumn}1`]?.v; + // Validate the first row of the current column + if (firstRowValue !== localizedColumnName) { + throwError( + "FILE", + 400, + "INVALID_COLUMNS", + `Invalid format: Expected '${localizedColumnName}' in the first row of column ${sheetColumn}.` + ); + } + } + } + } + + // Convert sheet data to JSON format + const sheetData = XLSX.utils.sheet_to_json( + workbook.Sheets[localizedSheetName], + { blankrows: true, raw: false } + ); + var jsonData = sheetData.map((row: any, index: number) => { + const rowData: any = {}; + if (Object.keys(row).length > 0) { + Object.keys(row).forEach((key) => { + // Check if the value is a numerical string + rowData[key] = isNumeric(row[key]) + ? Number(row[key]) + : row[key] === undefined || row[key] === "" + ? "" + : row[key]; + }); + if (getRow) rowData["!row#number!"] = index + 1; + return rowData; + } + }); + + jsonData = jsonData.filter((element) => element !== undefined); + return jsonData; +}; + +const getTargetSheetData = async ( + fileUrl: string, + getRow = false, + getSheetName = false, + localizationMap?: any +) => { + const workbook: any = await getTargetWorkbook(fileUrl, localizationMap); + const sheetNames = workbook.SheetNames; + const localizedSheetNames = getLocalizedHeaders(sheetNames, localizationMap); + + const workbookData: { [key: string]: any[] } = {}; // Object to store data from each sheet + + for (const sheetName of localizedSheetNames) { + const sheetData = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName], { + blankrows: true, raw: false + }); + var jsonData = sheetData.map((row: any, index: number) => { + const rowData: any = {}; + if (Object.keys(row).length > 0) { + Object.keys(row).forEach((key) => { + // Check if the value is a numerical string + rowData[key] = isNumeric(row[key]) + ? Number(row[key]) + : row[key] === undefined || row[key] === "" + ? "" + : row[key]; + }); + if (getRow) rowData["!row#number!"] = index + 1; + if (getSheetName) rowData["!sheet#name!"] = sheetName; + return rowData; + } + }); + jsonData = jsonData.filter((element) => element !== undefined); + workbookData[sheetName] = jsonData; // Store sheet data in the object + // logger.info(`Sheet Data (${sheetName}): ${JSON.stringify(jsonData)}`); + } + // Return data from all sheets + return workbookData; +}; + +// Function to search MDMS for specific unique identifiers +const searchMDMS: any = async ( + uniqueIdentifiers: any[], + schemaCode: string, + requestinfo: any, + response: any +) => { + // Check if unique identifiers are provided + if (!uniqueIdentifiers) { + return; + } + + // Construct API URL for MDMS search + const apiUrl = config.host.mdms + config.paths.mdms_search; + + // Construct request data for MDMS search + const data = { + MdmsCriteria: { + tenantId: requestinfo?.userInfo?.tenantId, + uniqueIdentifiers: uniqueIdentifiers, + schemaCode: schemaCode, + }, + RequestInfo: requestinfo, + }; + + // Make HTTP request to MDMS API + const result = await httpRequest( + apiUrl, + data, + undefined, + undefined, + undefined + ); + + // Log search result + logger.info("Template search Result : " + JSON.stringify(result)); + + // Return search result + return result; +}; + +// Function to generate a campaign number +const getCampaignNumber: any = async ( + requestBody: any, + idFormat: String, + idName: string, + tenantId: string +) => { + // Construct request data + const data = { + RequestInfo: requestBody?.RequestInfo, + idRequests: [ + { + idName: idName, + tenantId: tenantId, + format: idFormat, + }, + ], + }; + + // Construct URL for ID generation service + const idGenUrl = config.host.idGenHost + config.paths.idGen; + + // Make HTTP request to ID generation service + const result = await httpRequest( + idGenUrl, + data, + undefined, + undefined, + undefined, + undefined + ); + + // Return generated campaign number + if (result?.idResponses?.[0]?.id) { + return result?.idResponses?.[0]?.id; + } + + // Throw error if ID generation fails + throwError("COMMON", 500, "IDGEN_ERROR"); +}; + +// Function to generate a resource number +const getResouceNumber: any = async ( + RequestInfo: any, + idFormat: String, + idName: string +) => { + // Construct request data + const data = { + RequestInfo, + idRequests: [ + { + idName: idName, + tenantId: RequestInfo?.userInfo?.tenantId, + format: idFormat, + }, + ], + }; + + // Construct URL for ID generation service + const idGenUrl = config.host.idGenHost + config.paths.idGen; + + try { + // Make HTTP request to ID generation service + const result = await httpRequest( + idGenUrl, + data, + undefined, + undefined, + undefined, + undefined + ); + + // Return generated resource number + if (result?.idResponses?.[0]?.id) { + return result?.idResponses?.[0]?.id; + } + + // Return null if ID generation fails + return result; + } catch (error: any) { + // Log error if ID generation fails + logger.error("Error: " + error); + + // Return error + return error; + } +}; + +// Function to get schema definition based on code and request info +const getSchema: any = async (code: string, RequestInfo: any) => { + const data = { + RequestInfo, + SchemaDefCriteria: { + tenantId: RequestInfo?.userInfo?.tenantId, + limit: 200, + codes: [code], + }, + }; + const mdmsSearchUrl = config.host.mdms + config.paths.mdmsSchema; + + try { + const result = await httpRequest( + mdmsSearchUrl, + data, + undefined, + undefined, + undefined, + undefined + ); + return result?.SchemaDefinitions?.[0]?.definition; + } catch (error: any) { + logger.error("Error: " + error); + return error; + } +}; + +// Function to get count from response data +const getCount: any = async ( + responseData: any, + request: any, + response: any +) => { + try { + // Extract host and URL from response data + const host = responseData?.host; + const url = responseData?.searchConfig?.countUrl; + + // Extract request information + const requestInfo = { RequestInfo: request?.body?.RequestInfo }; + + // Make HTTP request to get count + const result = await httpRequest( + host + url, + requestInfo, + undefined, + undefined, + undefined, + undefined + ); + + // Extract count from result using lodash + const count = _.get(result, responseData?.searchConfig?.countPath); + + return count; // Return the count + } catch (error: any) { + // Log and throw error if any + logger.error("Error: " + error); + throw error; + } +}; + +// Function to create Excel sheet and upload it +async function createAndUploadFile( + updatedWorkbook: XLSX.WorkBook, + request: any, + tenantId?: any +) { + // Write the updated workbook to a buffer + const buffer = XLSX.write(updatedWorkbook, { + bookType: "xlsx", + type: "buffer", + }); + + // Create form data for file upload + const formData = new FormData(); + formData.append("file", buffer, "filename.xlsx"); + formData.append( + "tenantId", + tenantId ? tenantId : request?.body?.RequestInfo?.userInfo?.tenantId + ); + formData.append("module", "HCM-ADMIN-CONSOLE-SERVER"); + + // Make HTTP request to upload file + var fileCreationResult = await httpRequest( + config.host.filestore + config.paths.filestore, + formData, + undefined, + undefined, + undefined, + { + "Content-Type": "multipart/form-data", + "auth-token": request?.body?.RequestInfo?.authToken, + } + ); + + // Extract response data + const responseData = fileCreationResult?.files; + if (!responseData) { + throwError( + "COMMON", + 500, + "INTERNAL_SERVER_ERROR", + "Error while uploading excel file" + ); + } + + return responseData; // Return the response data +} + +// Function to generate a list of hierarchy codes +function generateHierarchyList(data: any[], parentChain: any = []) { + let result: any[] = []; + + // Iterate over each boundary in the current level + for (let boundary of data) { + let currentChain = [...parentChain, boundary.code]; + + // Add the current chain to the result + result.push(currentChain.join(",")); + + // If there are children, recursively call the function + if (boundary.children.length > 0) { + let childResults = generateHierarchyList(boundary.children, currentChain); + result = result.concat(childResults); + } + } + return result; // Return the hierarchy list +} + +// Function to generate hierarchy from boundaries +function generateHierarchy(boundaries: any[]) { + // Create an object to store boundary types and their parents + const parentMap: any = {}; + + // Populate the object with boundary types and their parents + for (const boundary of boundaries) { + parentMap[boundary.boundaryType] = boundary.parentBoundaryType; + } + + // Traverse the hierarchy to generate the hierarchy list + const hierarchyList = []; + for (const boundaryType in parentMap) { + if (Object.prototype.hasOwnProperty.call(parentMap, boundaryType)) { + const parentBoundaryType = parentMap[boundaryType]; + if (parentBoundaryType === null) { + // This boundary type has no parent, add it to the hierarchy list + hierarchyList.push(boundaryType); + // Traverse its children recursively + traverseChildren(boundaryType, parentMap, hierarchyList); + } + } + } + return hierarchyList; // Return the hierarchy list +} + +// Recursive function to traverse children and generate hierarchy +function traverseChildren(parent: any, parentMap: any, hierarchyList: any[]) { + for (const boundaryType in parentMap) { + if (Object.prototype.hasOwnProperty.call(parentMap, boundaryType)) { + const parentBoundaryType = parentMap[boundaryType]; + if (parentBoundaryType === parent) { + // This boundary type has the current parent, add it to the hierarchy list + hierarchyList.push(boundaryType); + // Traverse its children recursively + traverseChildren(boundaryType, parentMap, hierarchyList); + } + } + } +} + +// Function to create an Excel sheet +async function createExcelSheet( + data: any, + headers: any, + sheetName: string = "Sheet1" +) { + // Create a new Excel workbook + const workbook = XLSX.utils.book_new(); + + // Combine headers and data into sheet data + const sheetData = [headers, ...data]; + const ws = XLSX.utils.aoa_to_sheet(sheetData); + + // Define column widths (in pixels) + const columnWidths = headers.map(() => ({ width: 30 })); + + // Apply column widths to the sheet + ws["!cols"] = columnWidths; + + // Append sheet to the workbook + XLSX.utils.book_append_sheet(workbook, ws, sheetName); + + return { wb: workbook, ws: ws, sheetName: sheetName }; // Return the workbook, worksheet, and sheet name +} + +// Function to handle getting boundary codes +async function getAutoGeneratedBoundaryCodesHandler(boundaryList: any, childParentMap: Map<{ key: string; value: string; }, { key: string; value: string; } | null>, elementCodesMap: any, countMap: any, request: any) { + try { + // Get updated element codes map + logger.info("Auto Generation of Boundary code begins for the user uploaded sheet") + const updatedelementCodesMap = await getAutoGeneratedBoundaryCodes(boundaryList, childParentMap, elementCodesMap, countMap, request); + return updatedelementCodesMap; // Return the updated element codes map + } catch (error) { + // Log and propagate the error + console.error("Error in getBoundaryCodesHandler:", error); + throw error; + } +} + +/** + * Function to generate auto-generated boundary codes based on boundary list, child-parent mapping, + * element codes map, count map, and request information. + * @param boundaryList List of boundary data + * @param childParentMap Map of child-parent relationships + * @param elementCodesMap Map of element codes + * @param countMap Map of counts for each element + * @param request HTTP request object + * @returns Updated element codes map + */ +async function getAutoGeneratedBoundaryCodes(boundaryList: any, childParentMap: any, elementCodesMap: any, countMap: any, request: any) { + // Initialize an array to store column data + const columnsData: { key: string, value: string }[][] = []; + // Extract unique elements from each column + for (const row of boundaryList) { + row.forEach((element: any, index: any) => { + if (!columnsData[index]) { + columnsData[index] = []; + } + const existingElement = columnsData[index].find((existing: any) => _.isEqual(existing, element)); + if (!existingElement) { + columnsData[index].push(element); + } + }); + } + + // Iterate over columns to generate boundary codes + for (let i = 0; i < columnsData.length; i++) { + const column = columnsData[i]; + for (const element of column) { + if (!findMapValue(elementCodesMap, element)) { + const parentCode = findMapValue(childParentMap, element) + if (parentCode !== undefined && parentCode !== null) { + countMap.set(parentCode, (findMapValue(countMap, parentCode) || 0) + 1); + let code; + const grandParentCode = findMapValue(childParentMap, parentCode); + if (grandParentCode != null && grandParentCode != undefined) { + const parentBoundaryCode = findMapValue(elementCodesMap, parentCode) + const lastUnderscoreIndex = parentBoundaryCode.lastIndexOf('_'); + const parentBoundaryCodeTrimmed = lastUnderscoreIndex !== -1 ? parentBoundaryCode.substring(0, lastUnderscoreIndex) : parentBoundaryCode; + code = generateElementCode(countMap.get(parentCode), parentBoundaryCodeTrimmed, element.value); + } else { + code = generateElementCode(countMap.get(parentCode), findMapValue(elementCodesMap, parentCode), element.value); + } + elementCodesMap.set(element, code); // Store the code of the element in the map + } else { + // Generate default code if parent code is not found + elementCodesMap.set(element, (request?.body?.ResourceDetails?.hierarchyType + "_").toUpperCase() + element.value.toString().substring(0, 2).toUpperCase()); + } + } else { + continue; + } + } + } + return elementCodesMap; // Return the updated element codes map +} + +/** + * Function to generate an element code based on sequence, parent code, and element. + * @param sequence Sequence number + * @param parentCode Parent code + * @param element Element + * @returns Generated element code + */ +function generateElementCode(sequence: any, parentCode: any, element: any) { + // Pad single-digit numbers with leading zero + let paddedSequence = sequence.toString().padStart(2, "0"); + const code = parentCode.toUpperCase() + + "_" + + paddedSequence + + "_" + + element.toUpperCase(); + return ( + code.trim() + ); +} + +/** + * Asynchronously retrieves boundary sheet data based on the provided request. + * @param request The HTTP request object. + * @returns Boundary sheet data. + */ +async function getBoundarySheetData( + request: any, + localizationMap?: { [key: string]: string } +) { + // Retrieve boundary data based on the request parameters + const params = { + ...request?.query, + includeChildren: true, + }; + const hierarchyType = request?.query?.hierarchyType; + logger.info( + `processing boundary data generation for hierarchyType : ${hierarchyType}` + ); + const boundaryData = await getBoundaryRelationshipData(request, params); + if (!boundaryData || boundaryData.length === 0) { + logger.info(`boundary data not found for hierarchyType : ${hierarchyType}`); + const hierarchy = await getHierarchy( + request, + request?.query?.tenantId, + hierarchyType + ); + const modifiedHierarchy = hierarchy.map((ele) => + `${hierarchyType}_${ele}`.toUpperCase() + ); + const localizedHeaders = getLocalizedHeaders( + modifiedHierarchy, + localizationMap + ); + // create empty sheet if no boundary present in system + const localizedBoundaryTab = getLocalizedName( + getBoundaryTabName(), + localizationMap + ); + logger.info(`generated a empty template for boundary`); + return await createExcelSheet( + boundaryData, + localizedHeaders, + localizedBoundaryTab + ); + } else { + // logger.info("boundaryData for sheet " + JSON.stringify(boundaryData)) + const responseFromCampaignSearch = + await getFiltersFromCampaignSearchResponse(request); + if (responseFromCampaignSearch?.Filters != null) { + const filteredBoundaryData = await generateFilteredBoundaryData( + request, + responseFromCampaignSearch + ); + return await getDataSheetReady( + filteredBoundaryData, + request, + localizationMap + ); + } else { + return await getDataSheetReady(boundaryData, request, localizationMap); + } + } +} +async function createStaff(resouceBody: any) { + // Create staff + const staffCreateUrl = + `${config.host.projectHost}` + `${config.paths.staffCreate}`; + logger.info("Project Staff Creation url " + staffCreateUrl); + logger.debug( + "Project Staff Creation body " + getFormattedStringForDebug(resouceBody) + ); + const staffResponse = await httpRequest( + staffCreateUrl, + resouceBody, + undefined, + "post", + undefined, + undefined + ); + logger.info("Project Staff mapping created"); + logger.debug( + "Project Staff mapping response " + + getFormattedStringForDebug(staffResponse) + ); + validateStaffResponse(staffResponse); +} + +/** + * Asynchronously creates project resources based on the provided resource body. + * @param resouceBody The resource body. + */ +async function createProjectResource(resouceBody: any) { + // Create project resources + const projectResourceCreateUrl = + `${config.host.projectHost}` + `${config.paths.projectResourceCreate}`; + logger.info("Project Resource Creation url " + projectResourceCreateUrl); + logger.debug( + "Project Resource Creation body " + getFormattedStringForDebug(resouceBody) + ); + const projectResourceResponse = await httpRequest( + projectResourceCreateUrl, + resouceBody, + undefined, + "post", + undefined, + undefined + ); + logger.debug("Project Resource Created"); + logger.debug( + "Project Resource Creation response :: " + + getFormattedStringForDebug(projectResourceResponse) + ); + validateProjectResourceResponse(projectResourceResponse); +} + +/** + * Asynchronously creates project facilities based on the provided resource body. + * @param resouceBody The resource body. + */ +async function createProjectFacility(resouceBody: any) { + // Create project facilities + const projectFacilityCreateUrl = + `${config.host.projectHost}` + `${config.paths.projectFacilityCreate}`; + logger.info("Project Facility Creation url " + projectFacilityCreateUrl); + logger.debug( + "Project Facility Creation body " + getFormattedStringForDebug(resouceBody) + ); + const projectFacilityResponse = await httpRequest( + projectFacilityCreateUrl, + resouceBody, + undefined, + "post", + undefined, + undefined + ); + logger.info("Project Facility Created"); + logger.debug( + "Project Facility Creation response" + + getFormattedStringForDebug(projectFacilityResponse) + ); + validateProjectFacilityResponse(projectFacilityResponse); +} + +/** + * Asynchronously creates related entities such as staff, resources, and facilities based on the provided resources, tenant ID, project ID, start date, end date, and resource body. + * @param resources List of resources. + * @param tenantId The tenant ID. + * @param projectId The project ID. + * @param startDate The start date. + * @param endDate The end date. + * @param resouceBody The resource body. + */ +async function createRelatedEntity( + resources: any, + tenantId: any, + projectId: any, + startDate: any, + endDate: any, + resouceBody: any +) { + // Create related entities + for (const resource of resources) { + const type = resource?.type; + for (const resourceId of resource?.resourceIds) { + if (type == "staff") { + const ProjectStaff = { + tenantId: tenantId.split(".")?.[0], + projectId, + userId: resourceId, + startDate, + endDate, + }; + resouceBody.ProjectStaff = ProjectStaff; + await createStaff(resouceBody); + } else if (type == "resource") { + const ProjectResource = { + // FIXME : Tenant Id should not be splitted + tenantId: tenantId.split(".")?.[0], + projectId, + resource: { + productVariantId: resourceId, + type: "DRUG", + isBaseUnitVariant: false, + }, + startDate, + endDate, + }; + resouceBody.ProjectResource = ProjectResource; + await createProjectResource(resouceBody); + } else if (type == "facility") { + const ProjectFacility = { + // FIXME : Tenant Id should not be splitted + tenantId: tenantId.split(".")?.[0], + projectId, + facilityId: resourceId, + }; + resouceBody.ProjectFacility = ProjectFacility; + await createProjectFacility(resouceBody); + } + } + } +} + +/** + * Asynchronously creates related resources based on the provided request body. + * @param requestBody The request body. + */ +async function createRelatedResouce(requestBody: any) { + const id = requestBody?.Campaign?.id; + const campaignDetails = await validateMappingId(requestBody, id); + if (campaignDetails?.status == campaignStatuses.inprogress) { + logger.info("Campaign Already In Progress and Mapped"); + } else { + sortCampaignDetails(requestBody?.Campaign?.CampaignDetails); + correctParentValues(requestBody?.Campaign?.CampaignDetails); + // Create related resources + const { tenantId } = requestBody?.Campaign; + + for (const campaignDetails of requestBody?.Campaign?.CampaignDetails) { + const resouceBody: any = { + RequestInfo: requestBody.RequestInfo, + }; + var { projectId, startDate, endDate, resources } = campaignDetails; + startDate = parseInt(startDate); + endDate = parseInt(endDate); + await createRelatedEntity( + resources, + tenantId, + projectId, + startDate, + endDate, + resouceBody + ); + } + } +} + +/** + * Asynchronously creates boundary entities based on the provided request and boundary map. + * @param request The HTTP request object. + * @param boundaryMap Map of boundary names to codes. + */ +async function createBoundaryEntities(request: any, boundaryMap: Map) { + try { + const updatedBoundaryMap: Array<{ key: string, value: string }> = Array.from(boundaryMap).map(([key, value]) => ({ key: key.value, value: value })); + // Create boundary entities + const requestBody = { "RequestInfo": request.body.RequestInfo } as { RequestInfo: any; Boundary?: any }; + const boundaries: any[] = []; + const codesFromResponse: any = []; + const boundaryCodes: any[] = []; + Array.from(boundaryMap.entries()).forEach(([, boundaryCode]) => { + boundaryCodes.push(boundaryCode); + }); + const boundaryEntitiesCreated: any[] = []; + const boundaryEntityCreateChunkSize = 200; + const chunkSize = 20; + const boundaryCodeChunks = []; + for (let i = 0; i < boundaryCodes.length; i += chunkSize) { + boundaryCodeChunks.push(boundaryCodes.slice(i, i + chunkSize)); + } + + for (const chunk of boundaryCodeChunks) { + const string = chunk.join(', '); + const boundaryEntityResponse = await httpRequest(config.host.boundaryHost + config.paths.boundaryServiceSearch, request.body, { tenantId: request?.body?.ResourceDetails?.tenantId, codes: string }); + const boundaryCodesFromResponse = boundaryEntityResponse.Boundary.flatMap((boundary: any) => boundary.code.toString()); + codesFromResponse.push(...boundaryCodesFromResponse); + } + + const codeSet = new Set(codesFromResponse);// Creating a set and filling it with the codes from the response + for (const { key: boundaryName, value: boundaryCode } of updatedBoundaryMap) { + if (!codeSet.has(boundaryCode.toString())) { + const boundary = { + tenantId: request?.body?.ResourceDetails?.tenantId, + code: boundaryCode, + geometry: null, + additionalDetails: { + name: boundaryName + } + }; + boundaries.push(boundary); + } + }; + if (!(boundaries.length === 0)) { + for (let i = 0; i < boundaries.length; i += boundaryEntityCreateChunkSize) { + requestBody.Boundary = boundaries.slice(i, i + boundaryEntityCreateChunkSize); + const response = await httpRequest(`${config.host.boundaryHost}boundary-service/boundary/_create`, requestBody, {}, 'POST',); + boundaryEntitiesCreated.push(response) + } + logger.info('Boundary entities created'); + logger.debug('Boundary entities response: ' + getFormattedStringForDebug(boundaryEntitiesCreated)); + } + else { + // throwError("COMMON", 400, "VALIDATION_ERROR", "Boundary entity already present in the system"); + logger.info("Boundary Entities are already in the system") + } + } catch (error) { + throwError("COMMMON", 500, "INTERNAL_SERVER_ERROR", "Error while Boundary Entity Creation") + } +} + +async function confirmBoundaryParentCreation(request: any, code: any) { + if (code) { + const searchBody = { + RequestInfo: request.body.RequestInfo, + } + const params = { + hierarchyType: request?.body?.ResourceDetails?.hierarchyType, + tenantId: request?.body?.ResourceDetails?.tenantId, + codes: code + } + var retry = 6; + var boundaryFound = false; + while (!boundaryFound && retry >= 0) { + const response = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, searchBody, params); + if (response?.TenantBoundary?.[0].boundary?.[0]) { + boundaryFound = true; + } + else { + logger.info("Boundary not found. Waiting for 1 seconds"); + retry = retry - 1 + await new Promise(resolve => setTimeout(resolve, 1000)); + } + } + if (!boundaryFound) { + throwError("BOUNDARY", 500, "INTERNAL_SERVER_ERROR", "Boundary creation failed, for the boundary with code " + code); + } + } +} + +/** + * Asynchronously creates boundary relationships based on the provided request, boundary type map, and modified child-parent map. + * @param request The HTTP request object. + * @param boundaryTypeMap Map of boundary codes to types. + * @param modifiedChildParentMap Modified child-parent map. + */ +async function createBoundaryRelationship(request: any, boundaryMap: Map<{ key: string, value: string }, string>, modifiedChildParentMap: Map) { + try { + + const updatedBoundaryMap: Array<{ key: string, value: string }> = Array.from(boundaryMap).map(([key, value]) => ({ key: value, value: key.key })); + + let activityMessage: any[] = []; + const requestBody = { "RequestInfo": request.body.RequestInfo } as { RequestInfo: any; BoundaryRelationship?: any }; + const url = `${config.host.boundaryHost}${config.paths.boundaryRelationship}`; + const params = { + "type": request?.body?.ResourceDetails?.type, + "tenantId": request?.body?.ResourceDetails?.tenantId, + "boundaryType": null, + "codes": null, + "includeChildren": true, + "hierarchyType": request?.body?.ResourceDetails?.hierarchyType + }; + + const boundaryRelationshipResponse = await httpRequest(url, request.body, params); + const boundaryData = boundaryRelationshipResponse?.TenantBoundary?.[0]?.boundary; + const allCodes = extractCodesFromBoundaryRelationshipResponse(boundaryData); + + let flag = 1; + + for (const { key: boundaryCode, value: boundaryType } of updatedBoundaryMap) { + if (!allCodes.has(boundaryCode)) { + const boundary = { + tenantId: request?.body?.ResourceDetails?.tenantId, + boundaryType: boundaryType, + code: boundaryCode, + hierarchyType: request?.body?.ResourceDetails?.hierarchyType, + parent: modifiedChildParentMap.get(boundaryCode) || null + }; + + flag = 0; + requestBody.BoundaryRelationship = boundary; + // Introducing a delay of 1 second + // await new Promise(resolve => setTimeout(resolve, config.boundary.boundaryRelationShipDelay)); + await confirmBoundaryParentCreation(request, modifiedChildParentMap.get(boundaryCode) || null); + try { + const response = await httpRequest(`${config.host.boundaryHost}${config.paths.boundaryRelationshipCreate}`, requestBody, {}, 'POST', undefined, undefined, true); + + if (!response.TenantBoundary || !Array.isArray(response.TenantBoundary) || response.TenantBoundary.length === 0) { + throwError("BOUNDARY", 500, "BOUNDARY_RELATIONSHIP_CREATE_ERROR"); + } + logger.info(`Boundary relationship created for boundaryType :: ${boundaryType} & boundaryCode :: ${boundaryCode} `); + + const newRequestBody = JSON.parse(JSON.stringify(request.body)); + activityMessage.push(await generateActivityMessage(request?.body?.ResourceDetails?.tenantId, request.body, newRequestBody, response, request?.body?.ResourceDetails?.type, url, response?.statusCode)); + } catch (error) { + // Log the error and rethrow to be caught by the outer try...catch block + logger.error(`Error creating boundary relationship for boundaryType :: ${boundaryType} & boundaryCode :: ${boundaryCode} :: `, error); + throw error; + } + } + }; + + if (flag === 1) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Boundary already present in the system"); + } + + request.body = { + ...request.body, + Activities: activityMessage + }; + } catch (error: any) { + const errorCode = error.code || "INTERNAL_SERVER_ERROR"; + const errorMessage = error.description || "Error while boundary relationship create"; + logger.error(`Error in createBoundaryRelationship: ${errorMessage}`, error); + throwError("COMMON", 500, errorCode, errorMessage); + } +} + + + +async function callMdmsData( + request: any, + moduleName: string, + masterName: string, + tenantId: string +) { + const { RequestInfo = {} } = request?.body || {}; + const requestBody = { + RequestInfo, + MdmsCriteria: { + tenantId: tenantId, + moduleDetails: [ + { + moduleName: moduleName, + masterDetails: [ + { + name: masterName, + }, + ], + }, + ], + }, + }; + const url = config.host.mdms + config.paths.mdms_v1_search; + const response = await httpRequest(url, requestBody, { tenantId: tenantId }); + return response; +} + +async function callMdmsSchema( + request: any, + moduleName: string, + masterName: string, + tenantId: string +) { + const { RequestInfo = {} } = request?.body || {}; + const requestBody = { + RequestInfo, + SchemaDefCriteria: { + tenantId: tenantId, + limit: 5, + codes: [`${moduleName}.${masterName}`] + } + }; + const url = config.host.mdmsV2 + config.paths.mdmsV2SchemaSearch; + const response = await httpRequest(url, requestBody); + if (!response?.SchemaDefinitions?.[0]?.definition) { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Error occured during schema search"); + } + return response?.SchemaDefinitions?.[0]?.definition; +} + +async function getMDMSV1Data(request: any, moduleName: string, masterName: string, tenantId: string) { + const resp = await callMdmsData(request, moduleName, masterName, tenantId); + return resp; +} + +export { + getAutoGeneratedBoundaryCodes, + getAutoGeneratedBoundaryCodesHandler, + createBoundaryEntities, + createBoundaryRelationship, + getWorkbook, + getSheetData, + searchMDMS, + getCampaignNumber, + getSchema, + getResouceNumber, + getCount, + getBoundarySheetData, + createAndUploadFile, + createRelatedResouce, + createExcelSheet, + generateHierarchy, + generateHierarchyList, + getTargetWorkbook, + getTargetSheetData, + callMdmsData, + getMDMSV1Data, + callMdmsSchema +} diff --git a/health-services/project-factory/src/server/app.ts b/health-services/project-factory/src/server/app.ts new file mode 100644 index 00000000000..eda6d092ebf --- /dev/null +++ b/health-services/project-factory/src/server/app.ts @@ -0,0 +1,51 @@ +import express from 'express'; +import * as bodyParser from 'body-parser'; +import config from './config'; +import { requestMiddleware } from './utils/middlewares'; +import { errorLogger, errorResponder, invalidPathHandler } from './utils/genericUtils'; + +class App { + public app: express.Application; + public port: number; + + constructor(controllers: any, port: any) { + this.app = express(); + this.port = port; + + this.initializeMiddlewares(); + this.initializeControllers(controllers); + this.app.use(invalidPathHandler); + } + + private initializeMiddlewares() { + this.app.use(bodyParser.json()); + this.app.use(requestMiddleware); + + // this.app.use(cacheMiddleware); + // Attach the first Error handling Middleware + // function defined above (which logs the error) + this.app.use(errorLogger); + + // Attach the second Error handling Middleware + // function defined above (which sends back the response) + this.app.use(errorResponder); + + // Attach the fallback Middleware + // function which sends back the response for invalid paths) + } + + private initializeControllers(controllers: any) { + controllers.forEach((controller: any) => { + this.app.use(config.app?.contextPath, controller.router); + }); + } + + public listen() { + this.app.listen(this.port, () => { + console.log(`App listening on the port ${this.port}`); + }); + } +} + +export default App; + diff --git a/health-services/project-factory/src/server/config/constants.ts b/health-services/project-factory/src/server/config/constants.ts new file mode 100644 index 00000000000..7e4c5841a03 --- /dev/null +++ b/health-services/project-factory/src/server/config/constants.ts @@ -0,0 +1,130 @@ +import Error from "./error.interface" + +export const CONSTANTS: any = { + ERROR_CODES: { + COMMON: { + UNKNOWN_ERROR: "Unknown error. Check logs", + IDGEN_ERROR: "Error during generating campaign number", + VALIDATION_ERROR: "Validation error", + INTERNAL_SERVER_ERROR: "Internal server error", + INVALID_PAGINATION: "Invalid pagination", + }, + FILE: { + INVALID_FILE: "No download URL returned for the given fileStoreId", + INVALID_SHEETNAME: "Invalid sheet name", + STATUS_FILE_CREATION_ERROR: "Error in creating status file", + FETCHING_SHEET_ERROR: "Error occured while fetching sheet data", + INVALID_FILE_ERROR: "Invalid file", + DOWNLOAD_URL_NOT_FOUND: "Not any download URL returned for the given fileStoreId", + INVALID_FILE_FORMAT: "The uploaded file is not a valid excel file (xlsx or xls).", + INVALID_COLUMNS: "Columns are invalid" + }, + FACILITY: { + FACILITY_SEARCH_FAILED: "Search failed for facility. Check logs", + }, + CAMPAIGN: { + CAMPAIGN_SEARCH_ERROR: "Error in campaign search", + CAMPAIGNNAME_MISMATCH: "CampaignName is not matching", + CAMPAIGN_NOT_FOUND: "Campaign not found", + GENERATION_REQUIRE: "First generate then download", + RESOURCE_CREATION_ERROR: "Some error occured during resource creation", + CAMPAIGN_NAME_ERROR: "Campaign name already exists" + }, + BOUNDARY: { + BOUNDARY_DATA_NOT_FOUND: "No boundary data found in the system.", + BOUNDARY_HIERARCHY_INSERT_ERROR: "Insert boundary hierarchy level wise", + BOUNDARY_SEARCH_ERROR: "Error in boundary search. Check boundary codes", + BOUNDARY_NOT_FOUND: "Boundary not found", + BOUNDARY_SHEET_HEADER_ERROR: "Boundary sheet header error", + BOUNDARY_ENTITY_CREATE_ERROR: "Some error occured during boundary entity creation", + BOUNDARY_RELATIONSHIP_CREATE_ERROR: "Some error occured during boundary relationship creation", + BOUNDARY_TARGET_ERROR: "Target either not present or invalid value", + BOUNDARY_CONFIRMATION_FAILED: "Error in boundary creation and persistence" + }, + PROJECT: { + PROJECT_CREATION_FAILED: "Error occured in project creation", + PROJECT_SEARCH_ERROR: "Error occured during project search , check projectId", + PROJECT_UPDATE_ERROR: "Error occured during project update , check projectId", + PROJECT_CREATION_ERROR: "Some error occured during project creation", + PROJECT_CONFIRMATION_FAILED: "Error occured in project creation and peristence", + }, + MDMS: { + INVALID_README_CONFIG: "Invalid readme config" + } + } +} + +export const headingMapping: any = { + "userWithBoundary": "USERWITHBOUNDARY_README_MAINHEADER", + "facilityWithBoundary": "FACILITYWITHBOUNDARY_README_MAINHEADER", + "boundary": "BOUNDARY_README_MAINHEADER" +} + +const unknownError = "Unknown Error. Check Logs"; + + +// Retrieves the error message associated with the given error key. +const getMessage = (key: any) => { + // Retrieve the error codes from the CONSTANTS object + const errors = CONSTANTS.ERROR_CODES; + + // Iterate over each module and error key to find the matching error message + for (const moduleKey in errors) { + for (const errorKey in errors[moduleKey]) { + if (key === errorKey) { + return errors[moduleKey][errorKey]; + } + } + } + + // Return 'unknownError' if the error key is not found + return unknownError; +} + +export const userRoles: any = { + "Registrar": "REGISTRAR", + "Distributor": "DISTRIBUTOR", + "Supervisor": "SUPERVISOR", + "Help Desk": "HELPDESK_USER", + "Monitor Local": "MONITOR_LOCAL", + "Logistical officer": "LOGISTICAL_OFFICER", +} + +export const campaignStatuses: any = { + drafted: "drafted", + started: "creating", + inprogress: "created", + failed: "failed" +} + +export const resourceDataStatuses: any = { + failed: "failed", + completed: "completed", + invalid: "invalid", + started: "validation-started", + accepted: "data-accepted" +} + +export const generatedResourceStatuses: any = { + inprogress: "inprogress", + failed: "failed", + completed: "completed", + expired: "expired" +} + + +// Retrieves the error object containing the error code, message, and notFound flag. +export const getErrorCodes = (module: string, key: string): Error => { + // Retrieve the error message from the CONSTANTS object + const message = CONSTANTS.ERROR_CODES?.[module]?.[key] || getMessage(key) + + // Determine the error code based on whether the message is 'unknownError' or not + const code = message == unknownError ? "UNKNOWN_ERROR" : key + + // Return the error object + return { + code: code, + notFound: true, + message: message + } +} diff --git a/health-services/project-factory/src/server/config/createAndSearch.ts b/health-services/project-factory/src/server/config/createAndSearch.ts new file mode 100644 index 00000000000..6220ae39bd5 --- /dev/null +++ b/health-services/project-factory/src/server/config/createAndSearch.ts @@ -0,0 +1,260 @@ +import config from "."; +const createAndSearch: any = { + "facility": { + requiresToSearchFromSheet: [ + { + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CODE", + searchPath: "Facility.id" + } + ], + boundaryValidation: { + column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY" + }, + sheetSchema: { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "FacilityTemplateSchema", + "type": "object", + "properties": { + "Facility Name": { + "type": "string", + "maxLength": 2000, + "minLength": 1 + }, + "Facility Type": { + // "type": "string", + "enum": ["Warehouse", "Health Facility"] + }, + "Facility Status": { + // "type": "string", + "enum": ["Temporary", "Permanent"] + }, + "Capacity": { + "type": "number", + "minimum": 1, + "maximum": 100000000 + } + }, + "required": [ + "Facility Name", + "Facility Type", + "Facility Status", + "Capacity" + ], + "unique": [ + "Facility Name" + ] + }, + uniqueIdentifier: "id", + uniqueIdentifierColumn: "A", + uniqueIdentifierColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CODE", + matchEachKey: true, + parseArrayConfig: { + sheetName: "HCM_ADMIN_CONSOLE_FACILITIES", + parseLogic: [ + { + sheetColumn: "A", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CODE", + resultantPath: "id", + type: "string" + }, + { + sheetColumn: "B", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_NAME", + resultantPath: "name", + type: "string" + }, + { + sheetColumn: "C", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_TYPE", + resultantPath: "usage", + type: "string" + }, + { + sheetColumn: "D", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_STATUS", + resultantPath: "isPermanent", + type: "boolean", + conversionCondition: { + "Permanent": "true", + "Temporary": "" + } + }, + { + sheetColumn: "E", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CAPACITY", + resultantPath: "storageCapacity", + type: "number" + }, + { + sheetColumn: "F", + sheetColumnName: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY" + } + ], + tenantId: { + getValueViaPath: "ResourceDetails.tenantId", + resultantPath: "tenantId" + } + }, + createBulkDetails: { + limit: 50, + createPath: "Facilities", + url: config.host.facilityHost + "facility/v1/bulk/_create" + }, + searchDetails: { + searchElements: [ + { + keyPath: "tenantId", + getValueViaPath: "ResourceDetails.tenantId", + isInParams: true, + isInBody: false, + }, + { + keyPath: "Facility", + isInParams: false, + isInBody: true, + } + ], + searchLimit: { + keyPath: "limit", + value: "200", + isInParams: true, + isInBody: false, + }, + searchOffset: { + keyPath: "offset", + value: "0", + isInParams: true, + isInBody: false, + }, + url: config.host.facilityHost + "facility/v1/_search", + searchPath: "Facilities" + } + }, + "boundary": { + parseArrayConfig: { + sheetName: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE", + } + }, + "user": { + boundaryValidation: { + column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY" + }, + sheetSchema: { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "UserTemplateSchema", + "type": "object", + "properties": { + "Name of the Person (Mandatory)": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "Phone Number (Mandatory)": { + "type": "integer", + "minimum": 100000000, + "maximum": 9999999999 + }, + "Role (Mandatory)": { + "type": "string", + "enum": ["Registrar", "Distributor", "Supervisor", "Help Desk", "Monitor Local", "Logistical officer"] + }, + "Employment Type (Mandatory)": { + "enum": ["Temporary", "Permanent"] + } + }, + "required": [ + "Name of the Person (Mandatory)", + "Phone Number (Mandatory)", + "Role (Mandatory)", + "Employment Type (Mandatory)" + ], + "unique": [ + "Phone Number (Mandatory)" + ] + }, + parseArrayConfig: { + sheetName: "HCM_ADMIN_CONSOLE_USER_LIST", + parseLogic: [ + { + sheetColumn: "A", + sheetColumnName: "HCM_ADMIN_CONSOLE_USER_NAME", + resultantPath: "user.name", + type: "string" + }, + { + sheetColumn: "B", + sheetColumnName: "HCM_ADMIN_CONSOLE_USER_PHONE_NUMBER", + resultantPath: "user.mobileNumber", + type: "string" + }, + { + sheetColumn: "C", + sheetColumnName: "HCM_ADMIN_CONSOLE_USER_ROLE", + resultantPath: "user.roles", + type: "string" + }, + { + sheetColumn: "D", + sheetColumnName: "HCM_ADMIN_CONSOLE_USER_EMPLOYMENT_TYPE", + resultantPath: "employeeType", + conversionCondition: { + "Permanent": "PERMANENT", + "Temporary": "TEMPORARY" + } + }, + { + sheetColumn: "E", + sheetColumnName: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY", + resultantPath: "jurisdictions", + type: "string" + } + ], + tenantId: { + getValueViaPath: "ResourceDetails.tenantId", + resultantPath: "tenantId" + } + }, + uniqueIdentifier: "user.userServiceUuid", + uniqueIdentifierColumn: "H", + uniqueIdentifierColumnName: "UserService Uuids", + createBulkDetails: { + limit: 50, + createPath: "Employees", + url: config.host.hrmsHost + config.paths.hrmsEmployeeCreate + }, + searchDetails: { + searchElements: [ + { + keyPath: "tenantId", + getValueViaPath: "ResourceDetails.tenantId", + isInParams: true, + isInBody: false, + } + ], + searchLimit: { + keyPath: "limit", + value: "200", + isInParams: true, + isInBody: false, + }, + searchOffset: { + keyPath: "offset", + value: "0", + isInParams: true, + isInBody: false, + }, + url: config.host.hrmsHost + config.paths.hrmsEmployeeSearch, + searchPath: "Employees" + } + }, + "boundaryWithTarget": { + parseArrayConfig: { + sheetName: "HCM_ADMIN_CONSOLE_BOUNDARY_DATA", + }, + boundaryValidation: { + column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE" + } + } +} + +export default createAndSearch; diff --git a/health-services/project-factory/src/server/config/dbPoolConfig.ts b/health-services/project-factory/src/server/config/dbPoolConfig.ts new file mode 100644 index 00000000000..45360d7355c --- /dev/null +++ b/health-services/project-factory/src/server/config/dbPoolConfig.ts @@ -0,0 +1,13 @@ +import { Pool } from 'pg'; +import config from '.'; + +const pool = new Pool({ + user: config.DB_CONFIG.DB_USER, + host: config.DB_CONFIG.DB_HOST, + database: config.DB_CONFIG.DB_NAME, + password: config.DB_CONFIG.DB_PASSWORD, + port: parseInt(config.DB_CONFIG.DB_PORT) +}); + +export default pool; + diff --git a/health-services/project-factory/src/server/config/error.interface.ts b/health-services/project-factory/src/server/config/error.interface.ts new file mode 100644 index 00000000000..73cabf70404 --- /dev/null +++ b/health-services/project-factory/src/server/config/error.interface.ts @@ -0,0 +1,7 @@ +interface Error { + code: string; + notFound: boolean; + message: string; +} + +export default Error; diff --git a/health-services/project-factory/src/server/config/generateQuery.ts b/health-services/project-factory/src/server/config/generateQuery.ts new file mode 100644 index 00000000000..25bb7f4036e --- /dev/null +++ b/health-services/project-factory/src/server/config/generateQuery.ts @@ -0,0 +1,145 @@ +export const generateQuerySchema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "hierarchyType": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "tenantId": { + "type": "string", + "maxLength": 64, + "minLength": 1 + }, + "campaignName": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "action": { + "type": "string", + "enum": ["create", "draft"], + "maxLength": 64, + "minLength": 1 + }, + "startDate": { + "type": "integer" + }, + "endDate": { + "type": "integer" + }, + "boundaries": { + "type": "array", + "items": { + "type": "object", + "properties": { + "code": { + "type": "string", + "maxLength": 64, + "minLength": 1 + }, + "type": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "isRoot": { + "type": "boolean" + }, + "includeAllChildren": { + "type": "boolean" + } + }, + "required": ["code", "type"] + } + }, + "resources": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filestoreId": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "type": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "filename": { + "type": "string", + "maxLength": 128, + "minLength": 1 + } + }, + "required": ["filestoreId", "type"] + } + }, + "projectType": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "deliveryRules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "startDate": { + "type": "integer" + }, + "endDate": { + "type": "integer" + }, + "cycleNumber": { + "type": "integer" + }, + "deliveryNumber": { + "type": "integer" + }, + "deliveryRuleNumber": { + "type": "integer" + }, + "products": { + "type": "array", + "items": { + "type": "string", + "maxLength": 128, + "minLength": 1 + } + }, + "conditions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "attribute": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "operator": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "value": { + "type": "integer" + } + }, + "required": ["attribute", "operator", "value"] + } + } + }, + "required": ["startDate", "endDate", "cycleNumber", "deliveryNumber", "deliveryRuleNumber", "products", "conditions"] + } + }, + "additionalDetails": { + "type": "object" + } + }, + "required": ["hierarchyType", "tenantId", "campaignName", "action", "startDate", "endDate", "projectType", "deliveryRules", "additionalDetails"] +}; diff --git a/health-services/project-factory/src/server/config/index.ts b/health-services/project-factory/src/server/config/index.ts new file mode 100644 index 00000000000..1e37267a1df --- /dev/null +++ b/health-services/project-factory/src/server/config/index.ts @@ -0,0 +1,129 @@ +// config.js +// Importing necessary module +import { getErrorCodes } from "./constants"; +// Defining the HOST variable +const HOST = process.env.EGOV_HOST || + "https://unified-dev.digit.org/"; +// Checking if HOST is set, if not, exiting the process +if (!HOST) { + console.log("You need to set the HOST variable"); + process.exit(1); +} +// Configuration object containing various environment variables +const config = { + boundary: { + boundaryCode: process.env.BOUNDARY_CODE_HEADER_NAME || "HCM_ADMIN_CONSOLE_BOUNDARY_CODE", + boundaryTab: process.env.BOUNDARY_TAB_NAME || "HCM_ADMIN_CONSOLE_BOUNDARY_DATA", + // Default criteria for generating different tabs + generateDifferentTabsOnBasisOf: process.env.SPLIT_BOUNDARIES_ON || "ADMIN_DISTRITO", + // default configurable number of data of boundary type on which generate different tabs + numberOfBoundaryDataOnWhichWeSplit: process.env.SPLIT_BOUNDARIES_ON_LENGTH || "2", + boundaryRelationShipDelay: 3500 + }, + facility: { + facilityTab: process.env.FACILITY_TAB_NAME || "HCM_ADMIN_CONSOLE_FACILITIES", + facilitySchemaMasterName: process.env.FACILITY_SCHEMA_MASTER || "facilitySchema", + }, + user: { + userTab: process.env.USER_TAB_NAME || "HCM_ADMIN_CONSOLE_USER_LIST", + userSchemaMasterName: process.env.USER_SCHEMA_MASTER || "userSchema", + }, + kafka: { + // Kafka topics + KAFKA_SAVE_PROJECT_CAMPAIGN_DETAILS_TOPIC: process.env.KAFKA_SAVE_PROJECT_CAMPAIGN_DETAILS_TOPIC || "save-project-campaign-details", + KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC: process.env.KAFKA_SAVE_PROJECT_CAMPAIGN_DETAILS_TOPIC || "update-project-campaign-details", + KAFKA_START_CAMPAIGN_MAPPING_TOPIC: process.env.KAFKA_START_CAMPAIGN_MAPPING_TOPIC || "start-campaign-mapping", + KAFKA_UPDATE_CAMPAIGN_DETAILS_TOPIC: process.env.KAFKA_UPDATE_CAMPAIGN_DETAILS_TOPIC || "update-campaign-details", + KAFKA_CREATE_RESOURCE_DETAILS_TOPIC: process.env.KAFKA_CREATE_RESOURCE_DETAILS_TOPIC || "create-resource-details", + KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC: process.env.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC || "update-resource-details", + KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC: process.env.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC || "create-resource-activity", + KAFKA_UPDATE_GENERATED_RESOURCE_DETAILS_TOPIC: process.env.KAFKA_UPDATE_GENERATED_RESOURCE_DETAILS_TOPIC || "update-generated-resource-details", + KAFKA_CREATE_GENERATED_RESOURCE_DETAILS_TOPIC: process.env.KAFKA_CREATE_GENERATED_RESOURCE_DETAILS_TOPIC || "create-generated-resource-details", + }, + + // Database configuration + DB_CONFIG: { + DB_USER: process.env.DB_USER || "postgres", + DB_HOST: process.env.DB_HOST?.split(':')[0] || "localhost", + DB_NAME: process.env.DB_NAME || "postgres", + DB_PASSWORD: process.env.DB_PASSWORD || "postgres", + DB_PORT: process.env.DB_PORT || "5432", + }, + // Application configuration + app: { + port: parseInt(process.env.APP_PORT || "8080") || 8080, + host: HOST, + contextPath: process.env.CONTEXT_PATH || "/project-factory", + logLevel: process.env.APP_LOG_LEVEL || "debug", + debugLogCharLimit: process.env.APP_MAX_DEBUG_CHAR ? Number(process.env.APP_MAX_DEBUG_CHAR) : 1000 + }, + localisation: { + defaultLocale: process.env.LOCALE || "en_MZ", + boundaryPrefix: "rainmaker-boundary", + localizationModule: process.env.LOCALIZATION_MODULE || "rainmaker-hcm-admin-schemas", + }, + // Host configuration + host: { + serverHost: HOST, + // Kafka broker host + KAFKA_BROKER_HOST: process.env.KAFKA_BROKER_HOST || "kafka-v2.kafka-cluster:9092", + mdms: process.env.EGOV_MDMS_HOST || "https://unified-dev.digit.org/", + mdmsV2: process.env.EGOV_MDMS_V2_HOST || "https://unified-dev.digit.org/", + filestore: process.env.EGOV_FILESTORE_SERVICE_HOST || "https://unified-dev.digit.org/", + projectFactoryBff: "http://localhost:8080/", + idGenHost: process.env.EGOV_IDGEN_HOST || "https://unified-dev.digit.org/", + facilityHost: process.env.EGOV_FACILITY_HOST || "https://unified-dev.digit.org/", + boundaryHost: process.env.EGOV_BOUNDARY_HOST || "https://unified-dev.digit.org/", + projectHost: process.env.EGOV_PROJECT_HOST || "https://unified-dev.digit.org/", + userHost: process.env.EGOV_USER_HOST || "https://unified-dev.digit.org/", + productHost: process.env.EGOV_PRODUCT_HOST || "https://unified-dev.digit.org/", + hrmsHost: process.env.EGOV_HRMS_HOST || "https://unified-dev.digit.org/", + localizationHost: process.env.EGOV_LOCALIZATION_HOST || "https://unified-dev.digit.org/" + }, + // Paths for different services + paths: { + filestore: process.env.FILE_STORE_SERVICE_END_POINT || "filestore/v1/files", + mdms_search: process.env.EGOV_MDMS_SEARCH_ENDPOINT || "egov-mdms-service/v2/_search", + mdms_v1_search: process.env.EGOV_MDMS_V1_SEARCH_ENDPOINT || "egov-mdms-service/v1/_search", + idGen: process.env.EGOV_IDGEN_PATH || "egov-idgen/id/_generate", + mdmsSchema: process.env.EGOV_MDMS_SCHEMA_PATH || "egov-mdms-service/schema/v1/_search", + boundaryRelationship: process.env.EGOV_BOUNDARY_RELATIONSHIP_SEARCHPATH || "boundary-service/boundary-relationships/_search", + boundaryServiceSearch: process.env.EGOV_BOUNDARY_SERVICE_SEARCHPATH || "boundary-service/boundary/_search", + boundaryHierarchy: process.env.EGOV_BOUNDARY_HIERARCHY_SEARCHPATH || "boundary-service/boundary-hierarchy-definition/_search", + projectCreate: process.env.HEALTH_PROJECT_CREATE_PATH || "health-project/v1/_create", + projectUpdate: process.env.HEALTH_PROJECT_UPDATE_PATH || "health-project/v1/_update", + projectSearch: process.env.HEALTH_PROJECT_SEARCH_PATH || "health-project/v1/_search", + staffCreate: process.env.EGOV_PROJECT_STAFF_CREATE_PATH || "health-project/staff/v1/_create", + projectResourceCreate: process.env.EGOV_PROJECT_RESOURCE_CREATE_PATH || "health-project/resource/v1/_create", + projectFacilityCreate: process.env.EGOV_PROJECT_RESOURCE_FACILITY_PATH || "health-project/facility/v1/_create", + userSearch: process.env.EGOV_USER_SEARCH_PATH || "user/_search", + facilitySearch: process.env.EGOV_FACILITY_SEARCH_PATH || "facility/v1/_search", + productVariantSearch: process.env.EGOV_PRODUCT_VARIANT_SEARCH_PATH || "product/variant/v1/_search", + boundaryEntity: process.env.EGOV_BOUNDARY_ENTITY_SEARCHPATH || "boundary-service/boundary/_search", + facilityBulkCreate: process.env.EGOV_FACILITY_BULK_CREATE || "facility/v1/bulk/_create", + hrmsEmployeeCreate: process.env.EGOV_HRMS_EMPLOYEE_CREATE_PATH || "health-hrms/employees/_create", + hrmsEmployeeSearch: process.env.EGOV_HRMS_EMPLOYEE_SEARCH_PATH || "health-hrms/employees/_search", + localizationSearch: process.env.EGOV_LOCALIZATION_SEARCH || "localization/messages/v1/_search", + localizationCreate: "localization/messages/v1/_upsert", + projectTypeSearch: "project-factory/v1/project-type/search", + boundaryRelationshipCreate: "boundary-service/boundary-relationships/_create", + mdmsV2SchemaSearch: "mdms-v2/schema/v1/_search" + }, + // Values configuration + values: { + //module name + moduleName: process.env.MODULE_NAME || "HCM-ADMIN-CONSOLE", + readMeTab: "Read Me", + userMainBoundary: "mz", + userMainBoundaryType: "Country", + idgen: { + format: process.env.CMP_IDGEN_FORMAT || "CMP-[cy:yyyy-MM-dd]-[SEQ_EG_CMP_ID]", + idName: process.env.CMP_IDGEN_IDNAME || "campaign.number" + }, + matchFacilityData: false, + retryCount: process.env.CREATE_RESOURCE_RETRY_COUNT || "3" + } +}; +// Exporting getErrorCodes function and config object +export { getErrorCodes }; +export default config; \ No newline at end of file diff --git a/health-services/project-factory/src/server/config/models/SearchCriteria.ts b/health-services/project-factory/src/server/config/models/SearchCriteria.ts new file mode 100644 index 00000000000..54d30a7d0e1 --- /dev/null +++ b/health-services/project-factory/src/server/config/models/SearchCriteria.ts @@ -0,0 +1,26 @@ +export const searchCriteriaSchema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "id": { + "type": "array", + "items": { + "type": "string" + } + }, + "tenantId": { + "type": "string", + "minLength": 1 + }, + "type": { + "type": "string" + }, + "status": { + "type": "string" + } + }, + "required": ["tenantId"], + "additionalProperties": false +} + + diff --git a/health-services/project-factory/src/server/config/models/campaignDetails.ts b/health-services/project-factory/src/server/config/models/campaignDetails.ts new file mode 100644 index 00000000000..417ee034ef6 --- /dev/null +++ b/health-services/project-factory/src/server/config/models/campaignDetails.ts @@ -0,0 +1,102 @@ +export const campaignDetailsSchema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "hierarchyType": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "tenantId": { + "type": "string", + "maxLength": 64, + "minLength": 1 + }, + "campaignName": { + "type": "string", + "maxLength": 250, + "minLength": 2 + }, + "action": { + "type": "string", + "enum": ["create", "draft"], + "maxLength": 64, + "minLength": 1 + }, + "startDate": { + "type": "integer" + }, + "endDate": { + "type": "integer" + }, + "boundaries": { + "type": "array", + "items": { + "type": "object", + "properties": { + "code": { + "type": "string", + "maxLength": 64, + "minLength": 1 + }, + "type": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "isRoot": { + "type": "boolean" + }, + "includeAllChildren": { + "type": "boolean" + } + }, + "required": ["code", "type"] + } + }, + "resources": { + "type": "array", + "maxItems": 3, + "items": { + "type": "object", + "properties": { + "filestoreId": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "type": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "filename": { + "type": "string", + "maxLength": 128, + "minLength": 1, + "pattern": "^.+\\.(xlsx|xls)$" + }, + "resourceId": { + "type": "string", + "maxLength": 128, + "minLength": 1 + } + }, + "required": ["filestoreId", "type", "filename", "resourceId"] + } + }, + "projectType": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "deliveryRules": { + "type": "array", + "minItems": 1 + }, + "additionalDetails": { + "type": "object" + } + }, + "required": ["hierarchyType", "tenantId", "campaignName", "action", "startDate", "endDate", "projectType", "deliveryRules", "additionalDetails"] +}; diff --git a/health-services/project-factory/src/server/config/models/campaignDetailsDraftSchema.ts b/health-services/project-factory/src/server/config/models/campaignDetailsDraftSchema.ts new file mode 100644 index 00000000000..873d2b5d034 --- /dev/null +++ b/health-services/project-factory/src/server/config/models/campaignDetailsDraftSchema.ts @@ -0,0 +1,98 @@ +export const campaignDetailsDraftSchema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "hierarchyType": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "tenantId": { + "type": "string", + "maxLength": 64, + "minLength": 1 + }, + "campaignName": { + "type": "string", + "maxLength": 250, + "minLength": 2 + }, + "action": { + "type": "string", + "enum": ["create", "draft"], + "maxLength": 64, + "minLength": 1 + }, + "startDate": { + "type": "integer" + }, + "endDate": { + "type": "integer" + }, + "boundaries": { + "type": "array", + "items": { + "type": "object", + "properties": { + "code": { + "type": "string", + "maxLength": 64, + "minLength": 1 + }, + "type": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "isRoot": { + "type": "boolean" + }, + "includeAllChildren": { + "type": "boolean" + } + } + } + }, + "resources": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filestoreId": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "type": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "filename": { + "type": "string", + "maxLength": 128, + "minLength": 1, + "pattern": "^.+\\.(xlsx|xls)$" + }, + "resourceId": { + "type": "string", + "maxLength": 128, + "minLength": 1 + } + }, + } + }, + "projectType": { + "type": "string", + "maxLength": 128, + "minLength": 1 + }, + "deliveryRules": { + "type": "array" + }, + "additionalDetails": { + "type": "object" + } + }, + "required": ["tenantId", "campaignName", "hierarchyType"] +}; diff --git a/health-services/project-factory/src/server/config/models/createRequestSchema.ts b/health-services/project-factory/src/server/config/models/createRequestSchema.ts new file mode 100644 index 00000000000..ed56e706d16 --- /dev/null +++ b/health-services/project-factory/src/server/config/models/createRequestSchema.ts @@ -0,0 +1,39 @@ +export const createRequestSchema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["boundary", "facility", "user", "boundaryWithTarget"] + }, + "tenantId": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "fileStoreId": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "action": { + "type": "string", + "enum": ["create", "validate"] + }, + "hierarchyType": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "campaignId": { + "type": "string", + "minLength": 1, + "maxLength": 128 + }, + "additionalDetails": { + "type": "object" + } + }, + "required": ["type", "tenantId", "fileStoreId", "action", "hierarchyType"], + "additionalProperties": false +} \ No newline at end of file diff --git a/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts b/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts new file mode 100644 index 00000000000..b47e714dac5 --- /dev/null +++ b/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts @@ -0,0 +1,35 @@ +export const downloadRequestSchema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "maxLength": 128, + "minLength": 1, + }, + "type": { + "type": "string", + "maxLength": 128, + "minLength": 1, + "enum": [ + "facility", + "user", + "boundary", + "facilityWithBoundary", + "userWithBoundary" + ] + }, + "hierarchyType": { + "type": "string", + "maxLength": 128, + "minLength": 1, + }, + "id": { + "type": "string", + "maxlength": 128, + "minLength": 1, + } + }, + "required": ["tenantId", "type", "hierarchyType"], + "additionalProperties": false +} \ No newline at end of file diff --git a/health-services/project-factory/src/server/config/models/generateRequestSchema.ts b/health-services/project-factory/src/server/config/models/generateRequestSchema.ts new file mode 100644 index 00000000000..cc1df4b70e6 --- /dev/null +++ b/health-services/project-factory/src/server/config/models/generateRequestSchema.ts @@ -0,0 +1,37 @@ +export const generateRequestSchema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "maxLength": 128, + "minLength": 1, + }, + "type": { + "type": "string", + "maxLength": 128, + "minLength": 1, + "enum": [ + "facility", + "user", + "boundary", + "facilityWithBoundary", + "userWithBoundary" + ] + }, + "hierarchyType": { + "type": "string", + "maxLength": 128, + "minLength": 1, + }, + "forceUpdate": { + "type": "string", + "enum": ["true", "false"] + }, + "campaignId": { + "type": "string" + } + }, + "required": ["tenantId", "type", "hierarchyType", "campaignId"], + "additionalProperties": false +} diff --git a/health-services/project-factory/src/server/config/models/searchCampaignDetails.ts b/health-services/project-factory/src/server/config/models/searchCampaignDetails.ts new file mode 100644 index 00000000000..155e8babbc4 --- /dev/null +++ b/health-services/project-factory/src/server/config/models/searchCampaignDetails.ts @@ -0,0 +1,74 @@ +export const searchCampaignDetailsSchema = { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "ids": { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + }, + "tenantId": { + "type": "string", + "minLength": 1 + }, + "startDate": { + "type": "integer", + "minimum": 0 + }, + "endDate": { + "type": "integer", + "minimum": 0 + }, + "campaignsIncludeDates": { + "type": "boolean" + }, + "projectType": { + "type": "string" + }, + "campaignName": { + "type": "string", + "minLength": 1 + }, + "status": { + "oneOf": [ + { "type": "string" }, + { + "type": "array", + "items": { "type": "string" }, + "minItems": 1 + } + ] + }, + "createdBy": { + "type": "string" + }, + "campaignNumber": { + "type": "string" + }, + "pagination": { + "type": "object", + "properties": { + "sortBy": { + "type": "string" + }, + "sortOrder": { + "type": "string", + "enum": ["asc", "desc"] + }, + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 100 + }, + "offset": { + "type": "integer", + "minimum": 0 + } + } + } + }, + "required": ["tenantId"], + "additionalProperties": false +} diff --git a/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts b/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts new file mode 100644 index 00000000000..384735fb683 --- /dev/null +++ b/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts @@ -0,0 +1,118 @@ +import * as express from "express"; +import { createCampaignService, createProjectTypeCampaignService, searchProjectTypeCampaignService, updateProjectTypeCampaignService } from "../../service/campaignManageService"; +import { logger } from "../../utils/logger"; +import { errorResponder, sendResponse } from "../../utils/genericUtils"; + + + +// Define the MeasurementController class +class campaignManageController { + // Define class properties + public path = "/v1/project-type"; + public router = express.Router(); + public dayInMilliSecond = 86400000; + + // Constructor to initialize routes + constructor() { + this.intializeRoutes(); + } + + // Initialize routes for MeasurementController + public intializeRoutes() { + this.router.post(`${this.path}/create`, this.createProjectTypeCampaign); + this.router.post(`${this.path}/update`, this.updateProjectTypeCampaign); + this.router.post(`${this.path}/search`, this.searchProjectTypeCampaign); + this.router.post(`${this.path}/createCampaign`, this.createCampaign); + } + /** + * Handles the creation of a project type campaign. + * @param request The Express request object. + * @param response The Express response object. + */ + createProjectTypeCampaign = async ( + request: express.Request, + response: express.Response + ) => { + try { + logger.info("RECEIVED A PROJECT TYPE CREATE REQUEST"); + const CampaignDetails = await createProjectTypeCampaignService(request); + return sendResponse(response, { CampaignDetails }, request); + } catch (e: any) { + console.log(e) + logger.error(String(e)) + // Handle errors and send error response + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + }; + + /** + * Handles the update of a project type campaign. + * @param request The Express request object. + * @param response The Express response object. + */ + updateProjectTypeCampaign = async ( + request: express.Request, + response: express.Response + ) => { + try { + logger.info("RECEIVED A PROJECT TYPE UPDATE REQUEST"); + const CampaignDetails = await updateProjectTypeCampaignService(request); + return sendResponse(response, { CampaignDetails }, request); + } catch (e: any) { + console.log(e) + logger.error(String(e)) + // Handle errors and send error response + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + }; + + /** + * Handles the search for project type campaigns. + * @param request The Express request object. + * @param response The Express response object. + */ + searchProjectTypeCampaign = async ( + request: express.Request, + response: express.Response + ) => { + try { + logger.info("RECEIVED A PROJECT TYPE SEARCH REQUEST"); + const responseBody = await searchProjectTypeCampaignService(request); + // Send response with campaign details and total count + return sendResponse(response, responseBody, request); + } catch (e: any) { + console.log(e) + logger.error(String(e)) + // Handle errors and send error response + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + }; + + /** + * Handles the creation of a campaign. + * @param request The Express request object. + * @param response The Express response object. + */ + createCampaign = async ( + request: express.Request, + response: express.Response + ) => { + try { + logger.info("RECEIVED A CAMPAIGN CREATE REQUEST"); + const Campaign = await createCampaignService(request?.body); + // Send response with campaign details + return sendResponse(response, { Campaign }, request); + } + catch (e: any) { + console.log(e) + logger.error(String(e)) + // Handle errors and send error response + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + }; + +}; +export default campaignManageController; + + + diff --git a/health-services/project-factory/src/server/controllers/dataManage/dataManage.controller.ts b/health-services/project-factory/src/server/controllers/dataManage/dataManage.controller.ts new file mode 100644 index 00000000000..1ad8b70ae6e --- /dev/null +++ b/health-services/project-factory/src/server/controllers/dataManage/dataManage.controller.ts @@ -0,0 +1,107 @@ +import * as express from "express"; +import { createDataService, downloadDataService, generateDataService, searchDataService } from "../../service/dataManageService"; +import { errorResponder, sendResponse } from "../../utils/genericUtils"; +import { logger } from "../../utils/logger"; + + + + + + + +// Define the MeasurementController class +class dataManageController { + // Define class properties + public path = "/v1/data"; + public router = express.Router(); + public dayInMilliSecond = 86400000; + + // Constructor to initialize routes + constructor() { + this.intializeRoutes(); + } + + // Initialize routes for MeasurementController + public intializeRoutes() { + this.router.post(`${this.path}/_generate`, this.generateData); + this.router.post(`${this.path}/_download`, this.downloadData) + this.router.post(`${this.path}/_create`, this.createData); + this.router.post(`${this.path}/_search`, this.searchData); + } + /** +* Generates data based on the request and sends the response. +* @param request The Express request object. +* @param response The Express response object. +*/ + generateData = async (request: express.Request, response: express.Response) => { + try { + logger.info(`RECEIVED A DATA GENERATE REQUEST FOR TYPE :: ${request?.query?.type}`); + const GeneratedResource = await generateDataService(request); + return sendResponse(response, { GeneratedResource }, request); + } catch (e: any) { + console.log(e) + logger.error(String(e)) + // Handle errors and send error response + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + }; + + /** + * Downloads data based on the request and sends the response. + * @param request The Express request object. + * @param response The Express response object. + */ + downloadData = async (request: express.Request, response: express.Response) => { + try { + logger.info(`RECEIVED A DATA DOWNLOAD REQUEST FOR TYPE :: ${request?.query?.type}`); + const GeneratedResource = await downloadDataService(request); + return sendResponse(response, { GeneratedResource }, request); + } catch (e: any) { + console.log(e) + logger.error(String(e)); + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + } + + /** + * Creates data based on the request and sends the response. + * @param request The Express request object. + * @param response The Express response object. + */ + createData = async (request: any, response: any) => { + try { + logger.info(`RECEIVED A DATA CREATE REQUEST FOR TYPE :: ${request?.body?.ResourceDetails?.type}`); + const ResourceDetails = await createDataService(request); + // Send response with resource details + return sendResponse(response, { ResourceDetails }, request); + } catch (e: any) { + console.log(e) + logger.error(String(e)) + // Handle errors and send error response + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + } + + /** + * Searches for data based on the request and sends the response. + * @param request The Express request object. + * @param response The Express response object. + */ + searchData = async (request: any, response: any) => { + try { + logger.info(`RECEIVED A DATA SEARCH REQUEST FOR TYPE :: ${request?.body?.SearchCriteria?.type}`); + const ResourceDetails = await searchDataService(request) + return sendResponse(response, { ResourceDetails }, request); + } catch (e: any) { + console.log(e) + logger.error(String(e)) + // Handle errors and send error response + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + } + +}; +export default dataManageController; + + + diff --git a/health-services/project-factory/src/server/controllers/index.ts b/health-services/project-factory/src/server/controllers/index.ts new file mode 100644 index 00000000000..85e544ed9be --- /dev/null +++ b/health-services/project-factory/src/server/controllers/index.ts @@ -0,0 +1,12 @@ +import { listener } from "../kafka/Listener"; +import campaignManageController from "./campaignManage/campaignManage.controller"; +import dataManageController from "./dataManage/dataManage.controller"; + +listener(); + +const controllers = [ + new campaignManageController(), + new dataManageController() +] + +export default controllers; \ No newline at end of file diff --git a/health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts b/health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts new file mode 100644 index 00000000000..3591c1c016c --- /dev/null +++ b/health-services/project-factory/src/server/controllers/localisationController/localisation.controller.ts @@ -0,0 +1,118 @@ +import * as express from "express"; +import { logger } from "../../utils/logger"; +import { httpRequest } from "../../utils/request"; +import config from "../../config/index"; +import { convertLocalisationResponseToMap } from "../../utils/localisationUtils"; + +let cachedResponse = {}; + +class Localisation { + public path = "/localization/messages/v1"; + public router = express.Router(); + public dayInMilliSecond = 86400000; + private cachedResponse: any = {}; // Property to store the cached response + private localizationHost; + // Hold the single instance of the class + private static instance: Localisation; + constructor() { + this.localizationHost = config.host.localizationHost + } + // Public method to provide access to the single instance + public static getInstance(): Localisation { + if (!Localisation.instance) { + Localisation.instance = new Localisation(); + } + return Localisation.instance; + } + + // private getLocalisationMap = (): any => { + // //{ + // return Object.values(this.cachedResponse).reduce((acc: any, curr: any) => { + // acc = { ...acc, ...curr }; + // return acc; + // }, {}); // + // }; + // search localization + public getLocalisedData: any = async ( + module: string, + locale: string, + tenantId: string + ) => { + logger.info( + `Checks Localisation message is available in cache for module ${module}, locale ${locale}, tenantId ${tenantId}` + ); + if (!this?.cachedResponse?.[`${module}-${locale}`]) { + logger.info(`Not found in cache`); + await this.fetchLocalisationMessage(module, locale, tenantId); + } + logger.info(`Found in cache`); + return this?.cachedResponse?.[`${module}-${locale}`]; + }; + // fetch localization messages + private fetchLocalisationMessage = async ( + module: string, + locale: string, + tenantId: string + ) => { + logger.info( + `Received Localisation fetch for module ${module}, locale ${locale}, tenantId ${tenantId}` + ); + const params = { + tenantId, + locale, + module, + }; + const url = this.localizationHost + config.paths.localizationSearch; + const localisationResponse = await httpRequest(url, {}, params); + logger.info( + `Fetched Localisation Message for module ${module}, locale ${locale}, tenantId ${tenantId} with count ${localisationResponse?.messages?.length}` + ); + this.cachedResponse = { + ...cachedResponse, + ...this.cachedResponse, + [`${module}-${locale}`]: { + ...convertLocalisationResponseToMap(localisationResponse?.messages), + }, + }; + logger.info( + `Cached Localisation Message, now available modules in cache are : ${JSON.stringify( + Object.keys(this.cachedResponse) + )}` + ); + cachedResponse = { ...this.cachedResponse }; + }; + + /** + * Create localisation entries by sending a POST request to the localization host. + * @param messages - Array of localisation messages to be created. + * @param request - Request object containing necessary information. + */ + public createLocalisation = async ( + messages: any[] = [], + tenantId: string, + request: any = {} + ) => { + try { + // Extract RequestInfo from request body + const { RequestInfo } = request.body; + // Construct request body with RequestInfo and localisation messages + const requestBody = { RequestInfo, messages, tenantId }; + // Construct URL for localization create endpoint + const url = + this.localizationHost + config.paths.localizationCreate; + // Log the start of the localisation messages creation process + logger.info("Creating the localisation messages"); + // Send HTTP POST request to create localisation messages + + await httpRequest(url, requestBody); + // Log the completion of the localisation messages creation process + logger.info("Localisation messages created successfully"); + } catch (e: any) { + // Log and handle any errors that occur during the process + console.log(e); + logger.error(String(e)); + } + }; +} + +export default Localisation; diff --git a/health-services/project-factory/src/server/index.ts b/health-services/project-factory/src/server/index.ts new file mode 100644 index 00000000000..0278a389aaa --- /dev/null +++ b/health-services/project-factory/src/server/index.ts @@ -0,0 +1,10 @@ +import App from './app'; +import controllers from './controllers'; +import config from "./config"; + +const app = new App( + controllers, + config.app.port, +); + +app.listen(); diff --git a/health-services/project-factory/src/server/kafka/Listener.ts b/health-services/project-factory/src/server/kafka/Listener.ts new file mode 100644 index 00000000000..21c6a3d2eef --- /dev/null +++ b/health-services/project-factory/src/server/kafka/Listener.ts @@ -0,0 +1,96 @@ +import { Consumer, KafkaClient, Message } from 'kafka-node'; +import config from '../config'; +import { getFormattedStringForDebug, logger } from '../utils/logger'; // Importing logger utility for logging +import { producer } from './Producer'; // Importing producer from the Producer module +import { processCampaignMapping } from '../utils/campaignMappingUtils'; +import { enrichAndPersistCampaignWithError } from '../utils/campaignUtils'; + + + +// Replace with the correct Kafka broker(s) and topic name +const kafkaConfig = { + kafkaHost: config?.host?.KAFKA_BROKER_HOST, // Use the correct broker address and port + groupId: 'project-factory', + autoCommit: true, + autoCommitIntervalMs: 5000, + fromOffset: 'latest', +}; + +const topicName = config?.kafka?.KAFKA_START_CAMPAIGN_MAPPING_TOPIC; + +// Create a Kafka client +const kafkaClient = new KafkaClient(kafkaConfig); + +// Create a Kafka consumer +const consumer = new Consumer(kafkaClient, [{ topic: topicName, partition: 0 }], { autoCommit: true }); + + +// Exported listener function +export function listener() { + // Set up a message event handler + consumer.on('message', async (message: Message) => { + try { + // Parse the message value as an array of objects + const messageObject: any = JSON.parse(message.value?.toString() || '{}'); + try { + // await processCampaignMapping(messageObject); + logger.info("Received a messageObject for campaign mapping : "); + logger.debug("Message Object of campaign mapping :: " + getFormattedStringForDebug(messageObject)); + await processCampaignMapping(messageObject); + } catch (error: any) { + console.log(error) + logger.error(error) + enrichAndPersistCampaignWithError(messageObject, error) + } + logger.info(`KAFKA :: LISTENER :: Received a message`); + logger.debug(`KAFKA :: LISTENER :: message ${getFormattedStringForDebug(messageObject)}`); + } catch (error) { + logger.info('KAFKA :: LISTENER :: Some Error Occurred '); // Log successful message production + logger.error(`KAFKA :: LISTENER :: Error : ${JSON.stringify(error)}`); // Log producer error + console.log(error) + } + }); + + // Set up error event handlers + consumer.on('error', (err) => { + console.error(`Consumer Error: ${err}`); + }); + + consumer.on('offsetOutOfRange', (err) => { + console.error(`Offset out of range error: ${err}`); + }); +} + + +/** + * Produces modified messages to a specified Kafka topic. + * @param modifiedMessages An array of modified messages to be produced. + * @param topic The Kafka topic to which the messages will be produced. + * @returns A promise that resolves when the messages are successfully produced. + */ +async function produceModifiedMessages(modifiedMessages: any[], topic: any) { + logger.info(`KAFKA :: PRODUCER :: a message sent to topic ${topic}`); + logger.debug(`KAFKA :: PRODUCER :: message ${getFormattedStringForDebug(modifiedMessages)}`); + return new Promise((resolve, reject) => { + const payloads = [ + { + topic: topic, + messages: JSON.stringify(modifiedMessages), // Convert modified messages to JSON string + }, + ]; + + // Send payloads to the Kafka producer + producer.send(payloads, (err) => { + if (err) { + logger.info('KAFKA :: PRODUCER :: Some Error Occurred '); // Log successful message production + logger.error(`KAFKA :: PRODUCER :: Error : ${JSON.stringify(err)}`); // Log producer error + reject(err); // Reject promise if there's an error + } else { + logger.info('KAFKA :: PRODUCER :: message sent successfully '); // Log successful message production + resolve(); // Resolve promise if messages are successfully produced + } + }); + }); +} + +export { produceModifiedMessages } // Export the produceModifiedMessages function for external use \ No newline at end of file diff --git a/health-services/project-factory/src/server/kafka/Producer.ts b/health-services/project-factory/src/server/kafka/Producer.ts new file mode 100644 index 00000000000..b728b48a2ca --- /dev/null +++ b/health-services/project-factory/src/server/kafka/Producer.ts @@ -0,0 +1,25 @@ +import config from '../config'; // Importing configuration settings +import { Producer, KafkaClient } from 'kafka-node'; // Importing Producer and KafkaClient from 'kafka-node' library +import { logger } from "../utils/logger"; + +// Creating a new Kafka client instance using the configured Kafka broker host +const kafkaClient = new KafkaClient({ + kafkaHost: config?.host?.KAFKA_BROKER_HOST, // Configuring Kafka broker host + connectRetryOptions: { retries: 1 }, // Configuring connection retry options +}); + +// Creating a new Kafka producer instance using the Kafka client +const producer = new Producer(kafkaClient, { partitionerType: 2 }); // Using partitioner type 2 + +// Event listener for 'ready' event, indicating that the producer is ready to send messages +producer.on('ready', () => { + logger.info('Producer is ready'); // Log message indicating producer is ready +}); + +// Event listener for 'error' event, indicating that the producer encountered an error +producer.on('error', (err) => { + logger.error('Producer is in error state'); // Log message indicating producer is in error state + console.error(err.stack || err); // Log the error stack or message +}); + +export { producer }; // Exporting the producer instance for external use diff --git a/health-services/project-factory/src/server/service/campaignManageService.ts b/health-services/project-factory/src/server/service/campaignManageService.ts new file mode 100644 index 00000000000..3d3652bb441 --- /dev/null +++ b/health-services/project-factory/src/server/service/campaignManageService.ts @@ -0,0 +1,62 @@ +import express from "express"; +import { processBasedOnAction, searchProjectCampaignResourcData } from "../utils/campaignUtils"; +import { logger } from "../utils/logger"; +import { validateProjectCampaignRequest, validateSearchProjectCampaignRequest } from "../validators/campaignValidators"; +import { validateCampaignRequest } from "../validators/genericValidator"; +import { createRelatedResouce } from "../api/genericApis"; +import { enrichCampaign } from "../api/campaignApis"; + +async function createProjectTypeCampaignService(request: express.Request) { + // Validate the request for creating a project type campaign + await validateProjectCampaignRequest(request, "create"); + logger.info("VALIDATED THE PROJECT TYPE CREATE REQUEST"); + + // Process the action based on the request type + await processBasedOnAction(request, "create"); + return request?.body?.CampaignDetails; +} + +async function updateProjectTypeCampaignService(request: express.Request) { + + await validateProjectCampaignRequest(request, "update"); + logger.info("VALIDATED THE PROJECT TYPE UPDATE REQUEST"); + + // Process the action based on the request type + await processBasedOnAction(request, "update"); + return request?.body?.CampaignDetails; +} + +async function searchProjectTypeCampaignService( + request: express.Request, +) { + // Validate the search request for project type campaigns + await validateSearchProjectCampaignRequest(request); + logger.info("VALIDATED THE PROJECT TYPE SEARCH REQUEST"); + + // Search for project campaign resource data + await searchProjectCampaignResourcData(request); + const responseBody: any = { CampaignDetails: request?.body?.CampaignDetails, totalCount: request?.body?.totalCount } + return responseBody; +}; + +async function createCampaignService( + requestBody: any +) { + await validateCampaignRequest(requestBody) + logger.info("VALIDATED THE CAMPAIGN CREATE REQUEST"); + + // Create related resource + await createRelatedResouce(requestBody) + + // Enrich the campaign + await enrichCampaign(requestBody) + return requestBody?.Campaign +}; + + +export { + createProjectTypeCampaignService, + updateProjectTypeCampaignService, + searchProjectTypeCampaignService, + createCampaignService +} \ No newline at end of file diff --git a/health-services/project-factory/src/server/service/dataManageService.ts b/health-services/project-factory/src/server/service/dataManageService.ts new file mode 100644 index 00000000000..51541056d1c --- /dev/null +++ b/health-services/project-factory/src/server/service/dataManageService.ts @@ -0,0 +1,87 @@ +import express from "express"; +import { processGenericRequest } from "../api/campaignApis"; +import { createAndUploadFile, getBoundarySheetData } from "../api/genericApis"; +import { processDataSearchRequest } from "../utils/campaignUtils"; +import { enrichResourceDetails, getLocalizedMessagesHandler, getResponseFromDb, processGenerate, throwError } from "../utils/genericUtils"; +import { logger } from "../utils/logger"; +import { validateCreateRequest, validateDownloadRequest, validateSearchRequest } from "../validators/campaignValidators"; +import { validateGenerateRequest } from "../validators/genericValidator"; +import { getLocalisationModuleName } from "../utils/localisationUtils"; + +const generateDataService = async (request: express.Request) => { + // Validate the generate request + await validateGenerateRequest(request); + logger.info("VALIDATED THE DATA GENERATE REQUEST"); + await processGenerate(request); + // Send response with generated resource details + return request?.body?.generatedResource; +}; + + +const downloadDataService = async (request: express.Request) => { + await validateDownloadRequest(request); + logger.info("VALIDATED THE DATA DOWNLOAD REQUEST"); + + const type = request.query.type; + // Get response data from the database + const responseData = await getResponseFromDb(request); + // Check if response data is available + if (!responseData || responseData.length === 0 && !request?.query?.id) { + logger.error("No data of type " + type + " with status Completed or with given id presnt in db ") + // Throw error if data is not found + throwError("CAMPAIGN", 500, "GENERATION_REQUIRE"); + } + return responseData; +} + +const getBoundaryDataService = async ( + request: express.Request +) => { + const { hierarchyType } = request?.query; + const localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler(request, request?.query?.tenantId, getLocalisationModuleName(hierarchyType)); + const localizationMapModule = await getLocalizedMessagesHandler(request, request?.query?.tenantId); + const localizationMap = { ...localizationMapHierarchy, ...localizationMapModule }; + // const localizationMap = await getLocalizedMessagesHandler(request, request?.body?.ResourceDetails?.tenantId || request?.query?.tenantId || 'mz'); + // Retrieve boundary sheet data + const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); + // Create and upload file + const BoundaryFileDetails: any = await createAndUploadFile(boundarySheetData?.wb, request); + // Return boundary file details + logger.info("RETURNS THE BOUNDARY RESPONSE"); + return BoundaryFileDetails; +}; + + +const createDataService = async (request: any) => { + // Validate the create request + await validateCreateRequest(request); + logger.info("VALIDATED THE DATA CREATE REQUEST"); + + + const localizationMap = await getLocalizedMessagesHandler(request, request?.body?.ResourceDetails?.tenantId); + + // Enrich resource details + await enrichResourceDetails(request); + + // Process the generic request + await processGenericRequest(request, localizationMap); + return request?.body?.ResourceDetails; +} + +const searchDataService = async (request: any) => { + // Validate the search request + await validateSearchRequest(request); + logger.info("VALIDATED THE DATA GENERATE REQUEST"); + // Process the data search request + await processDataSearchRequest(request); + // Send response with resource details + return request?.body?.ResourceDetails; +} + +export { + generateDataService, + downloadDataService, + getBoundaryDataService, + createDataService, + searchDataService +} \ No newline at end of file diff --git a/health-services/project-factory/src/server/utils/Pagination.ts b/health-services/project-factory/src/server/utils/Pagination.ts new file mode 100644 index 00000000000..29cdf043cb7 --- /dev/null +++ b/health-services/project-factory/src/server/utils/Pagination.ts @@ -0,0 +1,6 @@ +export interface Pagination { + offset?: number; + limit?: number; + sortBy?: string; + sortOrder?: 'ASC' | 'DESC'; +} diff --git a/health-services/project-factory/src/server/utils/boundaryUtils.ts b/health-services/project-factory/src/server/utils/boundaryUtils.ts new file mode 100644 index 00000000000..40aa4f437ed --- /dev/null +++ b/health-services/project-factory/src/server/utils/boundaryUtils.ts @@ -0,0 +1,15 @@ +import config from "../config/index"; + + + +export const getBoundaryColumnName = () => { + // Construct Boundary column name from the config + return config?.boundary?.boundaryCode; +}; + +// Function to generate localisation module name based on hierarchy type +export const getBoundaryTabName = () => { + // Construct Boundary tab name from the config + return config?.boundary?.boundaryTab; +}; + diff --git a/health-services/project-factory/src/server/utils/campaignMappingUtils.ts b/health-services/project-factory/src/server/utils/campaignMappingUtils.ts new file mode 100644 index 00000000000..b349ec60524 --- /dev/null +++ b/health-services/project-factory/src/server/utils/campaignMappingUtils.ts @@ -0,0 +1,234 @@ +import createAndSearch from "../config/createAndSearch"; +import config from "../config"; +import { getDataFromSheet, throwError } from "./genericUtils"; +import { logger } from "./logger"; +import { httpRequest } from "./request"; +import { produceModifiedMessages } from "../kafka/Listener"; +import { getLocalizedName } from "./campaignUtils"; +import { campaignStatuses, resourceDataStatuses } from "../config/constants"; +import { createCampaignService } from "../service/campaignManageService"; + + +async function createBoundaryWithProjectMapping(projects: any, boundaryWithProject: any) { + for (const project of projects) { + if (project?.address?.boundary) { + boundaryWithProject[project?.address?.boundary] = project?.id + } + if (project?.descendants && Array.isArray(project?.descendants) && project?.descendants?.length > 0) { + await createBoundaryWithProjectMapping(project?.descendants, boundaryWithProject) + } + } +} + +function getPvarIds(messageObject: any) { + const deliveryRules = messageObject?.CampaignDetails?.deliveryRules; + const uniquePvarIds = new Set(); // Create a Set to store unique pvar IDs + if (deliveryRules) { + for (const deliveryRule of deliveryRules) { + const products = deliveryRule?.products; + if (products) { + for (const product of products) { + uniquePvarIds.add(product?.value); // Add pvar ID to the Set + } + } + } + } + return Array.from(uniquePvarIds); // Convert Set to array before returning +} + +async function enrichBoundaryCodes(resources: any[], messageObject: any, boundaryCodes: any, sheetName: any) { + const localizationMap: any = messageObject?.localizationMap + for (const resource of resources) { + const processedFilestoreId = resource?.processedFilestoreId; + if (processedFilestoreId) { + const dataFromSheet: any = await getDataFromSheet(messageObject, processedFilestoreId, messageObject?.Campaign?.tenantId, undefined, sheetName[resource?.type], localizationMap); + for (const data of dataFromSheet) { + const uniqueCodeColumn = getLocalizedName(createAndSearch?.[resource?.type]?.uniqueIdentifierColumnName, localizationMap) + const code = data[uniqueCodeColumn]; + // Extract boundary codes + const boundaryCode = data[getLocalizedName(createAndSearch?.[resource?.type]?.boundaryValidation?.column, localizationMap)]; + if (boundaryCode) { + // Split boundary codes if they have comma separated values + const boundaryCodesArray = boundaryCode.split(','); + boundaryCodesArray.forEach((bc: string) => { + // Trim any leading or trailing spaces + const trimmedBC = bc.trim(); + if (!boundaryCodes[resource?.type]) { + boundaryCodes[resource?.type] = {}; + } + if (!boundaryCodes[resource?.type][trimmedBC]) { + boundaryCodes[resource?.type][trimmedBC] = []; + } + boundaryCodes[resource?.type][trimmedBC].push(code); + }); + } + } + } + } +} + + +async function enrichBoundaryWithProject(messageObject: any, boundaryWithProject: any, boundaryCodes: any) { + const projectSearchBody = { + RequestInfo: messageObject?.RequestInfo, + Projects: [{ + id: messageObject?.Campaign?.rootProjectId, + tenantId: messageObject?.Campaign?.tenantId + }], + apiOperation: "SEARCH" + } + const params = { + tenantId: messageObject?.Campaign?.tenantId, + offset: 0, + limit: 100, + includeDescendants: true + } + logger.info("projectSearchBody : " + JSON.stringify(projectSearchBody)); + logger.info("params : " + JSON.stringify(params)); + logger.info("boundaryCodes : " + JSON.stringify(boundaryCodes)); + const response = await httpRequest(config.host.projectHost + "health-project/v1/_search", projectSearchBody, params); + await createBoundaryWithProjectMapping(response?.Project, boundaryWithProject); + logger.info("boundaryWithProject mapping : " + JSON.stringify(boundaryWithProject)); + logger.info("boundaryCodes mapping : " + JSON.stringify(boundaryCodes)); +} + +async function getProjectMappingBody(messageObject: any, boundaryWithProject: any, boundaryCodes: any) { + const Campaign: any = { + id: messageObject?.Campaign?.id, + tenantId: messageObject?.Campaign?.tenantId, + CampaignDetails: [] + } + for (const key of Object.keys(boundaryWithProject)) { + if (boundaryWithProject[key]) { + const resources: any[] = []; + const pvarIds = getPvarIds(messageObject); + if (pvarIds) { + resources.push({ + type: "resource", + resourceIds: pvarIds + }) + } + for (const type of Object.keys(boundaryCodes)) { + if (boundaryCodes[type][key]) { + resources.push({ + type: type == "user" ? "staff" : type, + resourceIds: [...boundaryCodes[type][key]] + }) + } + } + Campaign.CampaignDetails.push({ + projectId: boundaryWithProject[key], + resources: resources + }) + } + } + return { + RequestInfo: messageObject?.RequestInfo, + Campaign: Campaign + } +} + +async function fetchAndMap(resources: any[], messageObject: any) { + const localizationMap = messageObject?.localizationMap; + const sheetName: any = { + "user": getLocalizedName(createAndSearch?.user?.parseArrayConfig?.sheetName, localizationMap), + "facility": getLocalizedName(createAndSearch?.facility?.parseArrayConfig?.sheetName, localizationMap) + } + // Object to store boundary codes + const boundaryCodes: any = {}; + + await enrichBoundaryCodes(resources, messageObject, boundaryCodes, sheetName); + var boundaryWithProject: any = {}; + await enrichBoundaryWithProject(messageObject, boundaryWithProject, boundaryCodes); + const projectMappingBody = await getProjectMappingBody(messageObject, boundaryWithProject, boundaryCodes); + logger.info("projectMappingBody : " + JSON.stringify(projectMappingBody)); + const projectMappingResponse: any = await createCampaignService(projectMappingBody); + logger.info("Project Mapping Response : " + JSON.stringify(projectMappingResponse)); + if (projectMappingResponse) { + logger.info("Campaign Mapping done") + messageObject.CampaignDetails.status = campaignStatuses.inprogress + produceModifiedMessages(messageObject, config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC) + } +} + +async function searchResourceDetailsById(resourceDetailId: string, messageObject: any) { + var searchBody = { + RequestInfo: messageObject?.RequestInfo, + SearchCriteria: { + id: [resourceDetailId], + tenantId: messageObject?.Campaign?.tenantId + } + } + const response: any = await httpRequest(config.host.projectFactoryBff + "project-factory/v1/data/_search", searchBody); + return response?.ResourceDetails?.[0]; +} + +async function validateMappingId(messageObject: any, id: string) { + const searchBody = { + RequestInfo: messageObject?.RequestInfo, + CampaignDetails: { + ids: [id], + tenantId: messageObject?.Campaign?.tenantId, + } + } + const response: any = await httpRequest(config.host.projectFactoryBff + "project-factory/v1/project-type/search", searchBody); + logger.info("searchBody for campaign search : " + JSON.stringify(searchBody)); + if (!response?.CampaignDetails?.[0]) { + throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "Campaign with id " + id + " does not exist"); + } + return response?.CampaignDetails?.[0]; +} + +async function processCampaignMapping(messageObject: any) { + const resourceDetailsIds = messageObject?.Campaign?.resourceDetailsIds + const id = messageObject?.Campaign?.id + if (!id) { + throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "Campaign id is missing"); + } + const campaignDetails = await validateMappingId(messageObject, id); + if (campaignDetails?.status == campaignStatuses.inprogress) { + logger.info("Campaign Already In Progress and Mapped"); + } + else { + var completedResources: any = [] + var resources = []; + for (const resourceDetailId of resourceDetailsIds) { + var retry = 30; + while (retry--) { + const response = await searchResourceDetailsById(resourceDetailId, messageObject); + logger.info(`response for resourceDetailId ${resourceDetailId} : ` + JSON.stringify(response)); + if (response?.status == "invalid") { + logger.error(`resource with id ${resourceDetailId} is invalid`); + throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "resource with id " + resourceDetailId + " is invalid"); + break; + } + else if (response?.status == resourceDataStatuses.failed) { + logger.error(`resource with id ${resourceDetailId} is ${resourceDataStatuses.failed}`); + throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", `resource with id ${resourceDetailId} is ${resourceDataStatuses.failed} : with errorlog ${response?.additionalDetails?.error}`); + break; + } + else if (response?.status == resourceDataStatuses.completed) { + completedResources.push(resourceDetailId); + resources.push(response); + break; + } + else { + await new Promise(resolve => setTimeout(resolve, 20000)); + } + } + } + var uncompletedResourceIds = resourceDetailsIds?.filter((x: any) => !completedResources.includes(x)); + logger.info("uncompletedResourceIds " + JSON.stringify(uncompletedResourceIds)); + logger.info("completedResources " + JSON.stringify(completedResources)); + if (uncompletedResourceIds?.length > 0) { + throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "resource with id " + JSON.stringify(uncompletedResourceIds) + " is not validated after long wait. Check file"); + } + await fetchAndMap(resources, messageObject); + } +} + + +export { + processCampaignMapping, + validateMappingId +} diff --git a/health-services/project-factory/src/server/utils/campaignUtils.ts b/health-services/project-factory/src/server/utils/campaignUtils.ts new file mode 100644 index 00000000000..461e55c985e --- /dev/null +++ b/health-services/project-factory/src/server/utils/campaignUtils.ts @@ -0,0 +1,1599 @@ + +import { httpRequest } from "./request"; +import config from "../config/index"; +import { v4 as uuidv4 } from 'uuid'; +import { produceModifiedMessages } from '../kafka/Listener' +import { confirmProjectParentCreation, createProjectCampaignResourcData, getHierarchy, handleResouceDetailsError, projectCreate } from "../api/campaignApis"; +import { getCampaignNumber, createAndUploadFile, getSheetData, createExcelSheet, getAutoGeneratedBoundaryCodesHandler, getTargetSheetData, createBoundaryEntities, createBoundaryRelationship, getMDMSV1Data } from "../api/genericApis"; +import { getFormattedStringForDebug, logger } from "./logger"; +import createAndSearch from "../config/createAndSearch"; +import * as XLSX from 'xlsx'; +import { createReadMeSheet, findMapValue, getBoundaryRelationshipData, getLocalizedHeaders, getLocalizedMessagesHandler, modifyBoundaryData, modifyDataBasedOnDifferentTab, replicateRequest, throwError } from "./genericUtils"; +import { enrichProjectDetailsFromCampaignDetails } from "./transforms/projectTypeUtils"; +import { executeQuery } from "./db"; +import { campaignDetailsTransformer, genericResourceTransformer } from "./transforms/searchResponseConstructor"; +import { transformAndCreateLocalisation } from "./transforms/localisationMessageConstructor"; +import { campaignStatuses, headingMapping, resourceDataStatuses } from "../config/constants"; +import { getBoundaryColumnName, getBoundaryTabName } from "./boundaryUtils"; +import { searchProjectTypeCampaignService } from "../service/campaignManageService"; +import { validateBoundaryOfResouces } from "../validators/campaignValidators"; +const _ = require('lodash'); + + +function updateRange(range: any, desiredSheet: any) { + let maxColumnIndex = 0; + + // Iterate through each row to find the last column with data + for (let row = range.s.r; row <= range.e.r; row++) { + for (let col = range.s.c; col <= range.e.c; col++) { + const cellAddress = XLSX.utils.encode_cell({ r: row, c: col }); + if (desiredSheet[cellAddress]) { + maxColumnIndex = Math.max(maxColumnIndex, col); + } + } + } + + // Update the end column of the range with the maximum column index found + range.e.c = maxColumnIndex +} + +function findColumns(desiredSheet: any): { statusColumn: string, errorDetailsColumn: string } { + var range = XLSX.utils.decode_range(desiredSheet['!ref']); + + // Check if the status column already exists in the first row + var statusColumn: any; + for (let col = range.s.c; col <= range.e.c; col++) { + const cellAddress = XLSX.utils.encode_cell({ r: range.s.r, c: col }); + if (desiredSheet[cellAddress] && desiredSheet[cellAddress].v === '#status#') { + statusColumn = String.fromCharCode(65 + col); + for (let row = range.s.r; row <= range.e.r; row++) { + const cellAddress = XLSX.utils.encode_cell({ r: row, c: statusColumn.charCodeAt(0) - 65 }); + delete desiredSheet[cellAddress]; + } + break; + } + } + // Check if the errorDetails column already exists in the first row + var errorDetailsColumn: any; + for (let col = range.s.c; col <= range.e.c; col++) { + const cellAddress = XLSX.utils.encode_cell({ r: range.s.r, c: col }); + if (desiredSheet[cellAddress] && desiredSheet[cellAddress].v === '#errorDetails#') { + errorDetailsColumn = String.fromCharCode(65 + col); + for (let row = range.s.r; row <= range.e.r; row++) { + const cellAddress = XLSX.utils.encode_cell({ r: row, c: errorDetailsColumn.charCodeAt(0) - 65 }); + delete desiredSheet[cellAddress]; + } + break; + } + } + updateRange(range, desiredSheet); + logger.info("Updated Range : " + JSON.stringify(range)) + // If the status column doesn't exist, calculate the next available column + const emptyColumnIndex = range.e.c + 1; + statusColumn = String.fromCharCode(65 + emptyColumnIndex); + desiredSheet[statusColumn + '1'] = { v: '#status#', t: 's', r: '#status#', h: '#status#', w: '#status#' }; + + // Calculate errorDetails column one column to the right of status column + errorDetailsColumn = String.fromCharCode(statusColumn.charCodeAt(0) + 1); + desiredSheet[errorDetailsColumn + '1'] = { v: '#errorDetails#', t: 's', r: '#errorDetails#', h: '#errorDetails#', w: '#errorDetails#' }; + return { statusColumn, errorDetailsColumn }; +} + +function processErrorData(request: any, createAndSearchConfig: any, workbook: any, sheetName: any, localizationMap?: { [key: string]: string }) { + const desiredSheet: any = workbook.Sheets[sheetName]; + const errorData = request.body.sheetErrorDetails; + const userNameAndPassword = request.body.userNameAndPassword; + const columns = findColumns(desiredSheet); + const statusColumn = columns.statusColumn; + const errorDetailsColumn = columns.errorDetailsColumn; + var additionalDetailsErrors: any[] = [] + if (errorData) { + errorData.forEach((error: any) => { + const rowIndex = error.rowNumber; + const statusCell = statusColumn + (rowIndex + 1); + const errorDetailsCell = errorDetailsColumn + (rowIndex + 1); + desiredSheet[statusCell] = { v: error.status, t: 's', r: '#status#', h: error.status, w: error.status }; + desiredSheet[errorDetailsCell] = { v: error.errorDetails, t: 's', r: '#errorDetails#', h: error.errorDetails, w: error.errorDetails }; + if ((error?.status) && !(error?.status == "CREATED" || error?.status == "VALID")) { + additionalDetailsErrors.push(error) + } + }); + } + if (errorData) { + const uniqueIdentifierFirstRowCell = createAndSearchConfig?.uniqueIdentifierColumn + 1 + const columnName = getLocalizedName(createAndSearchConfig?.uniqueIdentifierColumnName, localizationMap); + desiredSheet[uniqueIdentifierFirstRowCell] = { v: columnName, t: 's', r: '#uniqueIdentifier#', h: columnName, w: columnName }; + errorData.forEach((error: any) => { + const rowIndex = error.rowNumber; + if (error.isUniqueIdentifier) { + const uniqueIdentifierCell = createAndSearchConfig.uniqueIdentifierColumn + (rowIndex + 1); + desiredSheet[uniqueIdentifierCell] = { v: error.uniqueIdentifier, t: 's', r: '#uniqueIdentifier#', h: error.uniqueIdentifier, w: error.uniqueIdentifier }; + } + }); + } + request.body.additionalDetailsErrors = additionalDetailsErrors + // lastcolumn = max of createAndSearchConfig?.uniqueIdentifierColumn and errorDetailsColumn + let lastColumn: string = errorDetailsColumn; + + if (createAndSearchConfig?.uniqueIdentifierColumn !== undefined) { + // Compare strings lexicographically + lastColumn = createAndSearchConfig?.uniqueIdentifierColumn > errorDetailsColumn ? + createAndSearchConfig?.uniqueIdentifierColumn : + errorDetailsColumn; + } + if (userNameAndPassword) { + const userNameFirstCell = "I" + 1; + const passwordFirstCell = "J" + 1; + desiredSheet[userNameFirstCell] = { v: "UserName", t: 's', r: 'UserName', h: "UserName", w: "UserName" }; + desiredSheet[passwordFirstCell] = { v: "Password", t: 's', r: 'Password', h: "Password", w: "Password" }; + userNameAndPassword.forEach((data: any) => { + const rowIndex = data.rowNumber; + const userNameCell = "I" + (rowIndex + 1); + const passWordCell = "J" + (rowIndex + 1); + desiredSheet[userNameCell] = { v: data?.userName, t: 's', r: 'UserName', h: data?.userName, w: data?.userName }; + desiredSheet[passWordCell] = { v: data?.password, t: 's', r: 'Password', h: data?.password, w: data?.password }; + }); + lastColumn = "J"; + delete request.body.userNameAndPassword; + } + desiredSheet['!ref'] = desiredSheet['!ref'].replace(/:[A-Z]+/, ':' + lastColumn); + workbook.Sheets[sheetName] = desiredSheet; +} + +function processErrorDataForTargets(request: any, createAndSearchConfig: any, workbook: any, sheetName: any) { + const desiredSheet: any = workbook.Sheets[sheetName]; + const columns = findColumns(desiredSheet); + const statusColumn = columns.statusColumn; + const errorDetailsColumn = columns.errorDetailsColumn; + + const errorData = request.body.sheetErrorDetails.filter((error: any) => error.sheetName === sheetName); + var additionalDetailsErrors: any[] = [] + + if (errorData) { + errorData.forEach((error: any) => { + const rowIndex = error.rowNumber; + if (error.isUniqueIdentifier) { + const uniqueIdentifierCell = createAndSearchConfig.uniqueIdentifierColumn + (rowIndex + 1); + desiredSheet[uniqueIdentifierCell] = { v: error.uniqueIdentifier, t: 's', r: '#uniqueIdentifier#', h: error.uniqueIdentifier, w: error.uniqueIdentifier }; + } + + const statusCell = statusColumn + (rowIndex + 1); + const errorDetailsCell = errorDetailsColumn + (rowIndex + 1); + desiredSheet[statusCell] = { v: error.status, t: 's', r: '#status#', h: error.status, w: error.status }; + desiredSheet[errorDetailsCell] = { v: error.errorDetails, t: 's', r: '#errorDetails#', h: error.errorDetails, w: error.errorDetails }; + if (!(error?.status == "CREATED" || error?.status == "VALID")) { + additionalDetailsErrors.push(error) + } + }); + } + request.body.additionalDetailsErrors = additionalDetailsErrors + desiredSheet['!ref'] = desiredSheet['!ref'].replace(/:[A-Z]+/, ':' + errorDetailsColumn); + workbook.Sheets[sheetName] = desiredSheet; +} + +async function updateStatusFile(request: any, localizationMap?: { [key: string]: string }) { + const fileStoreId = request?.body?.ResourceDetails?.fileStoreId; + const tenantId = request?.body?.ResourceDetails?.tenantId; + const createAndSearchConfig = createAndSearch[request?.body?.ResourceDetails?.type]; + const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: tenantId, fileStoreIds: fileStoreId }, "get"); + + if (!fileResponse?.fileStoreIds?.[0]?.url) { + throwError("FILE", 500, "INVALID_FILE"); + } + + const headers = { + 'Content-Type': 'application/json', + Accept: 'application/pdf', + }; + + const fileUrl = fileResponse?.fileStoreIds?.[0]?.url; + const sheetName = createAndSearchConfig?.parseArrayConfig?.sheetName; + const localizedSheetName = getLocalizedName(sheetName, localizationMap) + const responseFile = await httpRequest(fileUrl, null, {}, 'get', 'arraybuffer', headers); + const workbook = XLSX.read(responseFile, { type: 'buffer' }); + // Check if the specified sheet exists in the workbook + if (!workbook.Sheets.hasOwnProperty(localizedSheetName)) { + throwError("FILE", 400, "INVALID_SHEETNAME", `Sheet with name "${localizedSheetName}" is not present in the file.`); + } + processErrorData(request, createAndSearchConfig, workbook, localizedSheetName, localizationMap); + const sheet = workbook.Sheets[localizedSheetName]; + const columnWidths = Array(12).fill({ width: 30 }); + sheet['!cols'] = columnWidths; + const responseData = await createAndUploadFile(workbook, request); + logger.info('File updated successfully:' + JSON.stringify(responseData)); + if (responseData?.[0]?.fileStoreId) { + request.body.ResourceDetails.processedFileStoreId = responseData?.[0]?.fileStoreId; + } + else { + throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); + } +} +async function updateStatusFileForTargets(request: any, localizationMap?: { [key: string]: string }) { + const fileStoreId = request?.body?.ResourceDetails?.fileStoreId; + const tenantId = request?.body?.ResourceDetails?.tenantId; + const createAndSearchConfig = createAndSearch[request?.body?.ResourceDetails?.type]; + const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: tenantId, fileStoreIds: fileStoreId }, "get"); + + if (!fileResponse?.fileStoreIds?.[0]?.url) { + throwError("FILE", 500, "INVALID_FILE"); + } + + const headers = { + 'Content-Type': 'application/json', + Accept: 'application/pdf', + }; + + const fileUrl = fileResponse?.fileStoreIds?.[0]?.url; + const responseFile = await httpRequest(fileUrl, null, {}, 'get', 'arraybuffer', headers); + const workbook = XLSX.read(responseFile, { type: 'buffer' }); + const sheetNames = workbook.SheetNames; + const localizedSheetNames = getLocalizedHeaders(sheetNames, localizationMap) + localizedSheetNames.forEach((sheetName: any) => { + if (sheetName != getLocalizedName(config?.boundary?.boundaryTab, localizationMap) && sheetName != getLocalizedName(config.values.readMeTab, localizationMap)) { + processErrorDataForTargets(request, createAndSearchConfig, workbook, sheetName); + } + }); + + + + + const responseData = await createAndUploadFile(workbook, request); + logger.info('File updated successfully:' + JSON.stringify(responseData)); + if (responseData?.[0]?.fileStoreId) { + request.body.ResourceDetails.processedFileStoreId = responseData?.[0]?.fileStoreId; + } + else { + throwError("FILE", 500, "STATUS_FILE_CREATION_ERROR"); + } +} + + +function convertToType(dataToSet: any, type: any) { + switch (type) { + case "string": + return String(dataToSet); + case "number": + return Number(dataToSet); + case "boolean": + // Convert to boolean assuming any truthy value should be true and falsy should be false + return Boolean(dataToSet); + // Add more cases if needed for other types + default: + // If type is not recognized, keep dataToSet as it is + return dataToSet; + } +} + +function setTenantId( + resultantElement: any, + requestBody: any, + createAndSearchConfig: any +) { + if (createAndSearchConfig?.parseArrayConfig?.tenantId) { + const tenantId = _.get(requestBody, createAndSearchConfig?.parseArrayConfig?.tenantId?.getValueViaPath); + _.set(resultantElement, createAndSearchConfig?.parseArrayConfig?.tenantId?.resultantPath, tenantId); + } + +} + + +async function processData(request: any, dataFromSheet: any[], createAndSearchConfig: any, localizationMap?: { [key: string]: string }) { + const parseLogic = createAndSearchConfig?.parseArrayConfig?.parseLogic; + const requiresToSearchFromSheet = createAndSearchConfig?.requiresToSearchFromSheet; + var createData = [], searchData = []; + for (const data of dataFromSheet) { + const resultantElement: any = {}; + for (const element of parseLogic) { + if (element?.resultantPath) { + const localizedSheetColumnName = getLocalizedName(element.sheetColumnName, localizationMap); + let dataToSet = _.get(data, localizedSheetColumnName); + if (element.conversionCondition) { + dataToSet = element.conversionCondition[dataToSet]; + } + if (element.type) { + dataToSet = convertToType(dataToSet, element.type); + } + _.set(resultantElement, element.resultantPath, dataToSet); + } + } + resultantElement["!row#number!"] = data["!row#number!"]; + var addToCreate = true; + if (requiresToSearchFromSheet) { + for (const key of requiresToSearchFromSheet) { + const localizedSheetColumnName = getLocalizedName(key.sheetColumnName, localizationMap); + if (data[localizedSheetColumnName]) { + searchData.push(resultantElement) + addToCreate = false; + break; + } + } + } + if (addToCreate) { + createData.push(resultantElement) + } + } + return { searchData, createData }; +} + +function setTenantIdAndSegregate(processedData: any, createAndSearchConfig: any, requestBody: any) { + for (const resultantElement of processedData.createData) { + setTenantId(resultantElement, requestBody, createAndSearchConfig); + } + for (const resultantElement of processedData.searchData) { + setTenantId(resultantElement, requestBody, createAndSearchConfig); + } + return processedData; +} + +// Original function divided into two parts +async function convertToTypeData(request: any, dataFromSheet: any[], createAndSearchConfig: any, requestBody: any, localizationMap?: { [key: string]: string }) { + const processedData = await processData(request, dataFromSheet, createAndSearchConfig, localizationMap); + return setTenantIdAndSegregate(processedData, createAndSearchConfig, requestBody); +} + +function updateActivityResourceId(request: any) { + if (request?.body?.Activities && Array.isArray(request?.body?.Activities)) { + for (const activity of request?.body?.Activities) { + activity.resourceDetailsId = request?.body?.ResourceDetails?.id + } + } +} + +async function generateProcessedFileAndPersist(request: any, localizationMap?: { [key: string]: string }) { + if (request.body.ResourceDetails.type == 'boundaryWithTarget') { + await updateStatusFileForTargets(request, localizationMap); + } else { + if (request.body.ResourceDetails.type !== "boundary") { + await updateStatusFile(request, localizationMap); + } + } + updateActivityResourceId(request); + request.body.ResourceDetails = { + ...request?.body?.ResourceDetails, + status: request.body.ResourceDetails.status != resourceDataStatuses.invalid ? resourceDataStatuses.completed : resourceDataStatuses.invalid, + auditDetails: { + ...request?.body?.ResourceDetails?.auditDetails, + lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, + lastModifiedTime: Date.now() + }, + additionalDetails: { ...request?.body?.ResourceDetails?.additionalDetails, sheetErrors: request?.body?.additionalDetailsErrors } || {} + }; + produceModifiedMessages(request?.body, config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC); + logger.info("ResourceDetails to persist : " + JSON.stringify(request?.body?.ResourceDetails)); + if (request?.body?.Activities && Array.isArray(request?.body?.Activities && request?.body?.Activities.length > 0)) { + logger.info("Activities to persist : " + JSON.stringify(request?.body?.Activities)); + await new Promise(resolve => setTimeout(resolve, 2000)); + produceModifiedMessages(request?.body, config?.kafka?.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC); + } +} + +function getRootBoundaryCode(boundaries: any[] = []) { + for (const boundary of boundaries) { + if (boundary.isRoot) { + return boundary.code; + } + } + return ""; +} + +function enrichRootProjectId(requestBody: any) { + var rootBoundary; + for (const boundary of requestBody?.CampaignDetails?.boundaries) { + if (boundary?.isRoot) { + rootBoundary = boundary?.code + break; + } + } + if (rootBoundary) { + requestBody.CampaignDetails.projectId = requestBody?.boundaryProjectMapping?.[rootBoundary]?.projectId || null + } + requestBody.CampaignDetails.projectId = requestBody.CampaignDetails.projectId || null +} + +async function enrichAndPersistCampaignWithError(requestBody: any, error: any) { + requestBody.CampaignDetails = requestBody?.CampaignDetails || {} + const action = requestBody?.CampaignDetails?.action; + requestBody.CampaignDetails.campaignNumber = requestBody?.CampaignDetails?.campaignNumber || null + requestBody.CampaignDetails.campaignDetails = requestBody?.CampaignDetails?.campaignDetails || { deliveryRules: requestBody?.CampaignDetails?.deliveryRules, resources: requestBody?.CampaignDetails?.resources || [], boundaries: requestBody?.CampaignDetails?.boundaries || [] }; + requestBody.CampaignDetails.status = campaignStatuses?.failed; + requestBody.CampaignDetails.boundaryCode = getRootBoundaryCode(requestBody?.CampaignDetails?.boundaries) || null + requestBody.CampaignDetails.projectType = requestBody?.CampaignDetails?.projectType || null; + requestBody.CampaignDetails.hierarchyType = requestBody?.CampaignDetails?.hierarchyType || null; + requestBody.CampaignDetails.additionalDetails = requestBody?.CampaignDetails?.additionalDetails || {}; + requestBody.CampaignDetails.startDate = requestBody?.CampaignDetails?.startDate || null + requestBody.CampaignDetails.endDate = requestBody?.CampaignDetails?.endDate || null + requestBody.CampaignDetails.auditDetails = { + createdBy: requestBody?.RequestInfo?.userInfo?.uuid, + createdTime: Date.now(), + lastModifiedBy: requestBody?.RequestInfo?.userInfo?.uuid, + lastModifiedTime: Date.now(), + } + if (action == "create" && !requestBody?.CampaignDetails?.projectId) { + enrichRootProjectId(requestBody); + } + else if (!requestBody?.CampaignDetails?.projectId) { + requestBody.CampaignDetails.projectId = null + } + requestBody.CampaignDetails.additionalDetails = { + ...requestBody?.CampaignDetails?.additionalDetails, + error: String((error?.message + " : " + error?.description) || error) + } + const topic = config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC + produceModifiedMessages(requestBody, topic); + delete requestBody.CampaignDetails.campaignDetails +} + +async function enrichAndPersistCampaignForCreate(request: any, firstPersist: boolean = false) { + const action = request?.body?.CampaignDetails?.action; + if (firstPersist) { + request.body.CampaignDetails.campaignNumber = await getCampaignNumber(request.body, "CMP-[cy:yyyy-MM-dd]-[SEQ_EG_CMP_ID]", "campaign.number", request?.body?.CampaignDetails?.tenantId); + } + request.body.CampaignDetails.campaignDetails = { deliveryRules: request?.body?.CampaignDetails?.deliveryRules || [], resources: request?.body?.CampaignDetails?.resources || [], boundaries: request?.body?.CampaignDetails?.boundaries || [] }; + request.body.CampaignDetails.status = action == "create" ? campaignStatuses.started : campaignStatuses.drafted; + request.body.CampaignDetails.boundaryCode = getRootBoundaryCode(request.body.CampaignDetails.boundaries) + request.body.CampaignDetails.projectType = request?.body?.CampaignDetails?.projectType || null; + request.body.CampaignDetails.hierarchyType = request?.body?.CampaignDetails?.hierarchyType || null; + request.body.CampaignDetails.additionalDetails = request?.body?.CampaignDetails?.additionalDetails || {}; + request.body.CampaignDetails.startDate = request?.body?.CampaignDetails?.startDate || null + request.body.CampaignDetails.endDate = request?.body?.CampaignDetails?.endDate || null + request.body.CampaignDetails.auditDetails = { + createdBy: request?.body?.RequestInfo?.userInfo?.uuid, + createdTime: Date.now(), + lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, + lastModifiedTime: Date.now(), + } + if (action == "create" && !request?.body?.CampaignDetails?.projectId && !firstPersist) { + enrichRootProjectId(request.body); + } + else { + request.body.CampaignDetails.projectId = null + } + const topic = firstPersist ? config?.kafka?.KAFKA_SAVE_PROJECT_CAMPAIGN_DETAILS_TOPIC : config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC + delete request.body.CampaignDetails.codesTargetMapping + produceModifiedMessages(request?.body, topic); + delete request.body.CampaignDetails.campaignDetails +} + +function enrichInnerCampaignDetails(request: any, updatedInnerCampaignDetails: any) { + updatedInnerCampaignDetails.resources = request?.body?.CampaignDetails?.resources || [] + updatedInnerCampaignDetails.deliveryRules = request?.body?.CampaignDetails?.deliveryRules || [] + updatedInnerCampaignDetails.boundaries = request?.body?.CampaignDetails?.boundaries || [] +} + +async function enrichAndPersistCampaignForUpdate(request: any, firstPersist: boolean = false) { + const action = request?.body?.CampaignDetails?.action; + const ExistingCampaignDetails = request?.body?.ExistingCampaignDetails; + var updatedInnerCampaignDetails = {} + enrichInnerCampaignDetails(request, updatedInnerCampaignDetails) + request.body.CampaignDetails.campaignNumber = ExistingCampaignDetails?.campaignNumber + request.body.CampaignDetails.campaignDetails = updatedInnerCampaignDetails + request.body.CampaignDetails.status = action == "create" ? campaignStatuses.started : campaignStatuses.drafted; + const boundaryCode = !(request?.body?.CampaignDetails?.projectId) ? getRootBoundaryCode(request.body.CampaignDetails.boundaries) : (request?.body?.CampaignDetails?.boundaryCode || ExistingCampaignDetails?.boundaryCode) + request.body.CampaignDetails.boundaryCode = boundaryCode + request.body.CampaignDetails.startDate = request?.body?.CampaignDetails?.startDate || ExistingCampaignDetails?.startDate || null + request.body.CampaignDetails.endDate = request?.body?.CampaignDetails?.endDate || ExistingCampaignDetails?.endDate || null + request.body.CampaignDetails.projectType = request?.body?.CampaignDetails?.projectType ? request?.body?.CampaignDetails?.projectType : ExistingCampaignDetails?.projectType + request.body.CampaignDetails.hierarchyType = request?.body?.CampaignDetails?.hierarchyType ? request?.body?.CampaignDetails?.hierarchyType : ExistingCampaignDetails?.hierarchyType + request.body.CampaignDetails.additionalDetails = request?.body?.CampaignDetails?.additionalDetails ? request?.body?.CampaignDetails?.additionalDetails : ExistingCampaignDetails?.additionalDetails + request.body.CampaignDetails.auditDetails = { + createdBy: ExistingCampaignDetails?.createdBy, + createdTime: ExistingCampaignDetails?.createdTime, + lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, + lastModifiedTime: Date.now(), + } + if (action == "create" && !request?.body?.CampaignDetails?.projectId) { + enrichRootProjectId(request.body); + } + else { + request.body.CampaignDetails.projectId = request?.body?.CampaignDetails?.projectId || ExistingCampaignDetails?.projectId || null + } + delete request.body.CampaignDetails.codesTargetMapping + produceModifiedMessages(request?.body, config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC); + delete request.body.ExistingCampaignDetails + delete request.body.CampaignDetails.campaignDetails +} + +function getCreateResourceIds(resources: any[]) { + return resources + .filter((resource: any) => typeof resource.createResourceId === 'string' && resource.createResourceId.trim() !== '') + .map((resource: any) => { + const resourceId = resource.createResourceId; + return resourceId; + }); +} + +async function persistForCampaignProjectMapping(request: any, createResourceDetailsIds: any, localizationMap?: any) { + if (createResourceDetailsIds && request?.body?.CampaignDetails?.projectId) { + var requestBody: any = { + RequestInfo: request?.body?.RequestInfo, + Campaign: {} + } + requestBody.Campaign.id = request?.body?.CampaignDetails?.id + requestBody.Campaign.hierarchyType = request?.body?.CampaignDetails?.hierarchyType + requestBody.Campaign.tenantId = request?.body?.CampaignDetails?.tenantId + requestBody.Campaign.campaignName = request?.body?.CampaignDetails?.campaignName + requestBody.Campaign.boundaryCode = request?.body?.CampaignDetails?.boundaryCode + requestBody.Campaign.startDate = request?.body?.CampaignDetails?.startDate + requestBody.Campaign.endDate = request?.body?.CampaignDetails?.endDate + requestBody.Campaign.projectType = request?.body?.CampaignDetails?.projectType + requestBody.Campaign.additionalDetails = request?.body?.CampaignDetails?.additionalDetails + requestBody.Campaign.deliveryRules = request?.body?.CampaignDetails?.deliveryRules + requestBody.Campaign.rootProjectId = request?.body?.CampaignDetails?.projectId + requestBody.Campaign.resourceDetailsIds = createResourceDetailsIds + requestBody.CampaignDetails = request?.body?.CampaignDetails + var updatedInnerCampaignDetails = {} + enrichInnerCampaignDetails(request, updatedInnerCampaignDetails) + requestBody.CampaignDetails = request?.body?.CampaignDetails + requestBody.CampaignDetails.campaignDetails = updatedInnerCampaignDetails + requestBody.localizationMap = localizationMap + logger.info("Persisting CampaignProjectMapping : " + JSON.stringify(requestBody)); + produceModifiedMessages(requestBody, config?.kafka?.KAFKA_START_CAMPAIGN_MAPPING_TOPIC); + } +} + +function removeBoundariesFromRequest(request: any) { + if (request?.body?.CampaignDetails?.boundaries && Array.isArray(request?.body?.CampaignDetails?.boundaries) && request?.body?.CampaignDetails?.boundaries?.length > 0) { + request.body.CampaignDetails.boundaries = request?.body?.CampaignDetails?.boundaries?.filter((boundary: any) => !boundary?.insertedAfter) + } +} + + +async function enrichAndPersistProjectCampaignRequest(request: any, actionInUrl: any, firstPersist: boolean = false, localizationMap?: any) { + var createResourceDetailsIds: any[] = [] + if (request?.body?.CampaignDetails?.resources && Array.isArray(request?.body?.CampaignDetails?.resources) && request?.body?.CampaignDetails?.resources?.length > 0 && request?.body?.CampaignDetails?.action == "create") { + createResourceDetailsIds = getCreateResourceIds(request?.body?.CampaignDetails?.resources); + } + removeBoundariesFromRequest(request); + if (actionInUrl == "create") { + await enrichAndPersistCampaignForCreate(request, firstPersist) + } + else if (actionInUrl == "update") { + await enrichAndPersistCampaignForUpdate(request, firstPersist) + } + if (request?.body?.CampaignDetails?.action == "create") { + await persistForCampaignProjectMapping(request, createResourceDetailsIds, localizationMap); + } +} + +function getChildParentMap(modifiedBoundaryData: any) { + const childParentMap: Map<{ key: string, value: string }, { key: string, value: string } | null> = new Map(); + + modifiedBoundaryData.forEach((row: any) => { + for (let j = row.length - 1; j >= 0; j--) { + const child = row[j]; + const parent = j - 1 >= 0 ? row[j - 1] : null; + const childIdentifier = { key: child.key, value: child.value }; // Unique identifier for the child + const parentIdentifier = parent ? { key: parent.key, value: parent.value } : null; // Unique identifier for the parent, set to null if parent doesn't exist + + + // Check if the mapping already exists in the childParentMap + const existingMapping = Array.from(childParentMap.entries()).find(([existingChild, existingParent]) => + _.isEqual(existingChild, childIdentifier) && _.isEqual(existingParent, parentIdentifier) + ); + + // If the mapping doesn't exist, add it to the childParentMap + if (!existingMapping) { + childParentMap.set(childIdentifier, parentIdentifier); + } + } + }); + return childParentMap; +} + + + + + + +function getCodeMappingsOfExistingBoundaryCodes(withBoundaryCode: any[]) { + const countMap = new Map<{ key: string, value: string }, number>(); + const mappingMap = new Map<{ key: string, value: string }, string>(); + + withBoundaryCode.forEach((row: any[]) => { + const len = row.length; + if (len >= 3) { + let grandParentFound = false; + const grandParent = row[len - 3]; + if (findMapValue(mappingMap, grandParent)) { + const countMapArray = Array.from(countMap.entries()); + for (const [key, value] of countMapArray) { + if (_.isEqual(key, grandParent)) { + countMap.set(key, value + 1); + grandParentFound = true; + break; + } + } + if (grandParentFound == false) { + countMap.set(grandParent, 1); + } + } + } + mappingMap.set(row[len - 2], row[len - 1].value); + }); + return { mappingMap, countMap }; +} + + +function addBoundaryCodeToData(withBoundaryCode: any[], withoutBoundaryCode: any[], boundaryMap: Map) { + const boundaryDataWithBoundaryCode = withBoundaryCode; + const modifiedBoundaryDataWithBoundaryCode = boundaryDataWithBoundaryCode.map((array) => { + return array.map((obj: any) => { + if (obj.key === 'Boundary Code') { + return obj.value; + } else { + return obj; + } + }); + }); + + const boundaryDataForWithoutBoundaryCode = withoutBoundaryCode.map((row: any[]) => { + const boundaryName = row[row.length - 1]; // Get the last element of the row + const boundaryCode = findMapValue(boundaryMap, boundaryName); // Fetch corresponding boundary code from map + return [...row, boundaryCode]; // Append boundary code to the row and return updated row + }); + const boundaryDataForSheet = [...modifiedBoundaryDataWithBoundaryCode, ...boundaryDataForWithoutBoundaryCode]; + return boundaryDataForSheet; +} + +function prepareDataForExcel(boundaryDataForSheet: any, hierarchy: any[], boundaryMap: any) { + const data = boundaryDataForSheet.map((boundary: any[]) => { + const boundaryCode = boundary.pop(); + const boundaryValues = boundary.map(obj => obj.value); + const rowData = boundaryValues.concat(Array(Math.max(0, hierarchy.length - boundary.length)).fill('')); + const boundaryCodeIndex = hierarchy.length; + rowData[boundaryCodeIndex] = boundaryCode; + return rowData; + }); + return data; +} +function extractCodesFromBoundaryRelationshipResponse(boundaries: any[]): any { + const codes = new Set(); + for (const boundary of boundaries) { + codes.add(boundary.code); // Add code to the Set + if (boundary.children && boundary.children.length > 0) { + const childCodes = extractCodesFromBoundaryRelationshipResponse(boundary.children); // Recursively get child codes + childCodes.forEach((code: any) => codes.add(code)); // Add child codes to the Set + } + } + return codes; +} + + +async function getTotalCount(request: any) { + const CampaignDetails = request.body.CampaignDetails; + const { tenantId, pagination, ids, ...searchFields } = CampaignDetails; + let conditions = []; + let values = [tenantId]; + let index = 2; + const campaignsIncludeDates = searchFields?.campaignsIncludeDates + + for (const field in searchFields) { + if (searchFields[field] !== undefined && field != 'campaignsIncludeDates') { + if (field === 'startDate') { + const startDateSign = campaignsIncludeDates ? '<=' : '>='; + conditions.push(`startDate ${startDateSign} $${index}`); + values.push(searchFields[field]); + index++; + } else if (field === 'endDate') { + const endDateSign = campaignsIncludeDates ? '>=' : '<='; + conditions.push(`endDate ${endDateSign} $${index}`); + values.push(searchFields[field]); + index++; + } else if (field === 'campaignName') { + conditions.push(`${field} ILIKE '%' || $${index} || '%'`); + values.push(searchFields[field]); + index++; + } else if (field != 'status') { + conditions.push(`${field} = $${index}`); + values.push(searchFields[field]); + index++; + } + } + } + + let query = ` + SELECT count(*) + FROM health.eg_cm_campaign_details + WHERE tenantId = $1 + `; + + if (ids && ids.length > 0) { + const idParams = ids.map((id: any, i: any) => `$${index + i}`); + query += ` AND id IN (${idParams.join(', ')})`; + values.push(...ids); + index = index + ids.length; + } + var status = searchFields?.status; + if (status) { + if (typeof status === 'string') { + status = [status]; // Convert string to array + } + const statusParams = status.map((param: any, i: any) => `$${index + i}`); // Increment index for each parameter + query += ` AND status IN (${statusParams.join(', ')})`; + values.push(...status); + } + + if (conditions.length > 0) { + query += ` AND ${conditions.join(' AND ')}`; + } + const queryResult = await executeQuery(query, values); + const totalCount = parseInt(queryResult.rows[0].count, 10); + request.body.totalCount = totalCount; +} + + + + +async function searchProjectCampaignResourcData(request: any) { + const CampaignDetails = request.body.CampaignDetails; + const { tenantId, pagination, ids, ...searchFields } = CampaignDetails; + const queryData = buildSearchQuery(tenantId, pagination, ids, searchFields); + await getTotalCount(request) + const responseData: any[] = await executeSearchQuery(queryData.query, queryData.values); + // TODO @ashish check the below code looks like duplicate + for (const data of responseData) { + data.resources = data?.campaignDetails?.resources + data.boundaries = data?.campaignDetails?.boundaries + data.deliveryRules = data?.campaignDetails?.deliveryRules; + delete data.campaignDetails; + data.auditDetails = { + createdBy: data?.createdBy, + lastModifiedBy: data?.lastModifiedBy, + createdTime: data?.createdTime, + lastModifiedTime: data?.lastModifiedTime + } + delete data.createdBy; + delete data.lastModifiedBy; + delete data.createdTime; + delete data.lastModifiedTime; + } + request.body.CampaignDetails = responseData; +} + +function buildSearchQuery(tenantId: string, pagination: any, ids: string[], searchFields: any): { query: string, values: any[] } { + let conditions = []; + let values = [tenantId]; + let index = 2; + const campaignsIncludeDates = searchFields?.campaignsIncludeDates + + for (const field in searchFields) { + if (searchFields[field] !== undefined && field != 'campaignsIncludeDates') { + if (field === 'startDate') { + const startDateSign = campaignsIncludeDates ? '<=' : '>='; + conditions.push(`startDate ${startDateSign} $${index}`); + values.push(searchFields[field]); + index++; + } else if (field === 'endDate') { + const endDateSign = campaignsIncludeDates ? '>=' : '<='; + conditions.push(`endDate ${endDateSign} $${index}`); + values.push(searchFields[field]); + index++; + } else if (field === 'campaignName') { + conditions.push(`${field} ILIKE '%' || $${index} || '%'`); + values.push(searchFields[field]); + index++; + } else if (field != 'status') { + conditions.push(`${field} = $${index}`); + values.push(searchFields[field]); + index++; + } + } + } + + let query = ` + SELECT * + FROM health.eg_cm_campaign_details + WHERE tenantId = $1 + `; + + if (ids && ids.length > 0) { + const idParams = ids.map((id: any, i: any) => `$${index + i}`); + query += ` AND id IN (${idParams.join(', ')})`; + values.push(...ids); + index = index + ids.length; + } + + var status = searchFields?.status; + if (status) { + if (typeof status === 'string') { + status = [status]; // Convert string to array + } + const statusParams = status.map((param: any, i: any) => `$${index + i}`); // Increment index for each parameter + query += ` AND status IN (${statusParams.join(', ')})`; + values.push(...status); + } + + if (conditions.length > 0) { + query += ` AND ${conditions.join(' AND ')}`; + } + + if (pagination) { + query += '\n'; + + if (pagination.sortBy) { + query += `ORDER BY ${pagination.sortBy}`; + if (pagination.sortOrder) { + query += ` ${pagination.sortOrder.toUpperCase()}`; + } + query += '\n'; + } + + if (pagination.limit !== undefined) { + query += `LIMIT ${pagination.limit}`; + if (pagination.offset !== undefined) { + query += ` OFFSET ${pagination.offset}`; + } + query += '\n'; + } + } + + return { query, values }; +} + + + +async function executeSearchQuery(query: string, values: any[]) { + const queryResult = await executeQuery(query, values); + return campaignDetailsTransformer(queryResult?.rows); +} + +async function processDataSearchRequest(request: any) { + const { SearchCriteria } = request.body; + const query = buildWhereClauseForDataSearch(SearchCriteria); + const queryResult = await executeQuery(query.query, query.values); + request.body.ResourceDetails = genericResourceTransformer(queryResult?.rows);; +} + +function buildWhereClauseForDataSearch(SearchCriteria: any): { query: string; values: any[] } { + const { id, tenantId, type, status } = SearchCriteria; + let conditions = []; + let values = []; + + if (id && id.length > 0) { + conditions.push(`id = ANY($${values.length + 1})`); + values.push(id); + } + + if (tenantId) { + conditions.push(`tenantId = $${values.length + 1}`); + values.push(tenantId); + } + + if (type) { + conditions.push(`type = $${values.length + 1}`); + values.push(type); + } + + if (status) { + conditions.push(`status = $${values.length + 1}`); + values.push(status); + } + + const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''; + + return { + query: ` + SELECT * + FROM health.eg_cm_resource_details + ${whereClause};`, values + }; +} + +function mapBoundariesParent(boundaryResponse: any, request: any, parent: any) { + if (!boundaryResponse) return; + request.body.boundaryProjectMapping[boundaryResponse.code] = { + parent: parent || null, + projectId: null + } + if (boundaryResponse?.children && Array.isArray(boundaryResponse?.children) && boundaryResponse?.children?.length > 0) { + for (const child of boundaryResponse.children) { + mapBoundariesParent(child, request, boundaryResponse.code); + } + } +} + +function mapTargets(boundaryResponses: any, codesTargetMapping: any) { + if (!boundaryResponses || !codesTargetMapping) return; + + for (const boundaryResponse of boundaryResponses) { + const mapBoundary = (boundary: any) => { + if (!boundary.children || boundary.children.length === 0) { + const targetValue = codesTargetMapping[boundary.code]; + return targetValue ? targetValue : 0; + } + + let totalTargetValue = 0; + for (const child of boundary.children) { + const childTargetValue = mapBoundary(child); + totalTargetValue += childTargetValue; + } + codesTargetMapping[boundary.code] = totalTargetValue; + return totalTargetValue; + }; + mapBoundary(boundaryResponse); + } +} + + +async function processBoundary(boundaryResponse: any, boundaries: any, includeAllChildren: any, boundaryCodes: any, boundaryChildren: any) { + if (!boundaryResponse) return; + if (!boundaryCodes.has(boundaryResponse.code)) { + boundaries.push({ code: boundaryResponse?.code, type: boundaryResponse?.boundaryType, insertedAfter: true }); + boundaryCodes.add(boundaryResponse?.code); + } + if (includeAllChildren && boundaryResponse?.children && Array.isArray(boundaryResponse?.children) && boundaryResponse?.children?.length > 0) { + for (const child of boundaryResponse.children) { + processBoundary(child, boundaries, true, boundaryCodes, boundaryChildren); + } + } + else if (boundaryResponse?.children && Array.isArray(boundaryResponse?.children) && boundaryResponse?.children?.length > 0) { + for (const child of boundaryResponse.children) { + if (boundaryCodes.has(child.code) && boundaryChildren[child.code]) { + processBoundary(child, boundaries, true, boundaryCodes, boundaryChildren); + } + else if (boundaryCodes.has(child.code)) { + processBoundary(child, boundaries, false, boundaryCodes, boundaryChildren); + } + } + } +} + +async function addBoundaries(request: any, boundaryResponse: any, boundaryChildren: any) { + var { boundaries } = request?.body?.CampaignDetails; + var boundaryCodes = new Set(boundaries.map((boundary: any) => boundary.code)); + await processBoundary(boundaryResponse, boundaries, boundaryChildren[boundaryResponse?.code], boundaryCodes, boundaryChildren); + request.body.CampaignDetails.boundaries = boundaries +} + +async function addBoundariesForData(request: any, CampaignDetails: any) { + var { boundaries } = CampaignDetails; + const rootBoundary = getRootBoundaryCode(boundaries) + if (rootBoundary) { + const params = { + tenantId: request?.body?.ResourceDetails?.tenantId, + codes: rootBoundary, + hierarchyType: request?.body?.ResourceDetails?.hierarchyType, + includeChildren: true + } + const boundaryResponse = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, request.body, params); + if (boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]) { + var boundaryChildren = boundaries.reduce((acc: any, boundary: any) => { + acc[boundary.code] = boundary?.includeAllChildren; + return acc; + }, {}); + var boundaryCodes = new Set(boundaries.map((boundary: any) => boundary.code)); + await processBoundary(boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0], boundaries, boundaryChildren[boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]?.code], boundaryCodes, boundaryChildren); + CampaignDetails.boundaries = boundaries + } + else { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Some internal server error occured during boundary validation."); + } + } + else { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "There is no root boundary for this campaign."); + } +} + +function reorderBoundariesWithParentFirst(reorderedBoundaries: any[], boundaryProjectMapping: any) { + // Function to get the index of a boundary in the original boundaries array + function getIndex(code: any, boundaries: any[]) { + return reorderedBoundaries.findIndex((boundary: any) => boundary.code === code); + } + // Reorder boundaries so that parents come first + for (let i = 0; i < 2 * (reorderedBoundaries?.length); i++) { + for (const boundary of reorderedBoundaries) { + const parentCode = boundaryProjectMapping[boundary.code]?.parent; + if (parentCode) { + const parentIndex = getIndex(parentCode, reorderedBoundaries); + const boundaryIndex = getIndex(boundary.code, reorderedBoundaries); + + if (parentIndex !== -1 && boundaryIndex !== -1 && parentIndex > boundaryIndex) { + reorderedBoundaries.splice(parentIndex + 1, 0, reorderedBoundaries.splice(boundaryIndex, 1)[0]); + break; + } + } + } + } +} + +async function reorderBoundariesOfDataAndValidate(request: any, localizationMap?: any) { + if (request?.body?.ResourceDetails?.campaignId) { + const searchBody = { + RequestInfo: request?.body?.RequestInfo, + CampaignDetails: { + ids: [request?.body?.ResourceDetails?.campaignId], + tenantId: request?.body?.ResourceDetails?.tenantId + } + } + const req: any = replicateRequest(request, searchBody) + const response = await searchProjectTypeCampaignService(req) + if (response?.CampaignDetails?.[0]) { + const CampaignDetails = response?.CampaignDetails?.[0] + await addBoundariesForData(request, CampaignDetails) + logger.debug("Boundaries after addition " + getFormattedStringForDebug(CampaignDetails?.boundaries)); + await validateBoundaryOfResouces(CampaignDetails, request, localizationMap) + } + else { + throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND", "Campaign not found while Validating sheet boundaries"); + } + } +} + +async function reorderBoundaries(request: any, localizationMap?: any) { + var { boundaries } = request?.body?.CampaignDetails; + const rootBoundary = getRootBoundaryCode(boundaries) + request.body.boundaryProjectMapping = {} + if (rootBoundary) { + const params = { + tenantId: request?.body?.CampaignDetails?.tenantId, + codes: rootBoundary, + hierarchyType: request?.body?.CampaignDetails?.hierarchyType, + includeChildren: true + } + const boundaryResponse = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, request.body, params); + if (boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]) { + const codesTargetMapping = await getCodesTarget(request, localizationMap) + mapTargets(boundaryResponse?.TenantBoundary?.[0]?.boundary, codesTargetMapping) + request.body.CampaignDetails.codesTargetMapping = codesTargetMapping + logger.debug("codesTargetMapping mapping :: " + getFormattedStringForDebug(codesTargetMapping)); + mapBoundariesParent(boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0], request, null) + var boundaryChildren = boundaries.reduce((acc: any, boundary: any) => { + acc[boundary.code] = boundary?.includeAllChildren; + return acc; + }, {}); + await addBoundaries(request, boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0], boundaryChildren) + } + else { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Some internal server error occured during boundary validation."); + } + } + else { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "There is no root boundary for this campaign."); + } + logger.info("Boundaries for campaign creation in received") + logger.debug("Boundaries after addition " + getFormattedStringForDebug(request?.body?.CampaignDetails?.boundaries)); + reorderBoundariesWithParentFirst(request?.body?.CampaignDetails?.boundaries, request?.body?.boundaryProjectMapping) + logger.info("Reordered the Boundaries for mapping"); + logger.debug("Reordered Boundaries " + getFormattedStringForDebug(request?.body?.CampaignDetails?.boundaries)); +} + +function convertToProjectsArray(Projects: any, currentArray: any = []) { + for (const project of Projects) { + const descendants = project?.descendants + delete project?.descendants + currentArray.push(project); + if (descendants && Array.isArray(descendants) && descendants?.length > 0) { + convertToProjectsArray(descendants, currentArray) + } + } + return currentArray; +} + +async function getRelatedProjects(request: any) { + const { projectId, tenantId } = request?.body?.CampaignDetails; + const projectSearchBody = { + RequestInfo: request?.body?.RequestInfo, + Projects: [ + { + id: projectId, + tenantId: tenantId + } + ] + } + const projectSearchParams = { + tenantId: tenantId, + offset: 0, + limit: 1, + includeDescendants: true + } + logger.info("Project search params " + JSON.stringify(projectSearchParams)) + logger.info("Project search body " + JSON.stringify(projectSearchBody)) + logger.info("Project search url " + config?.host?.projectHost + config?.paths?.projectSearch) + const projectSearchResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectSearch, projectSearchBody, projectSearchParams); + if (projectSearchResponse?.Project && Array.isArray(projectSearchResponse?.Project) && projectSearchResponse?.Project?.length > 0) { + return convertToProjectsArray(projectSearchResponse?.Project) + } + else { + throwError("PROJECT", 500, "PROJECT_SEARCH_ERROR") + return [] + } +} + +async function updateProjectDates(request: any) { + const projects = await getRelatedProjects(request); + const { startDate, endDate } = request?.body?.CampaignDetails; + for (const project of projects) { + project.startDate = startDate || project.startDate; + project.endDate = endDate || project.endDate; + delete project?.address; + } + logger.info("Projects related to current Campaign : " + JSON.stringify(projects)); + const projectUpdateBody = { + RequestInfo: request?.body?.RequestInfo, + Projects: projects + } + const projectUpdateResponse = await httpRequest(config?.host?.projectHost + config?.paths?.projectUpdate, projectUpdateBody); + if (projectUpdateResponse?.Project && Array.isArray(projectUpdateResponse?.Project) && projectUpdateResponse?.Project?.length == projects?.length) { + logger.info("Project dates updated successfully") + } + else { + throwError("PROJECT", 500, "PROJECT_UPDATE_ERROR") + } +} + +async function getCodesTarget(request: any, localizationMap?: any) { + const { tenantId, resources } = request?.body?.CampaignDetails; + const boundaryWithTargetResource = resources?.filter((resource: any) => resource?.type == "boundaryWithTarget"); + const fileId = boundaryWithTargetResource[0]?.filestoreId + const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: tenantId, fileStoreIds: fileId }, "get"); + if (!fileResponse?.fileStoreIds?.[0]?.url) { + throwError("FILE", 500, "DOWNLOAD_URL_NOT_FOUND"); + } + const targetData = await getTargetSheetData(fileResponse?.fileStoreIds?.[0]?.url, true, true); + const boundaryTargetMapping: any = {}; + const codeColumnName = getLocalizedName(createAndSearch?.boundaryWithTarget?.boundaryValidation?.column, localizationMap) + // Iterate through each key in targetData + for (const key in targetData) { + // Iterate through each entry in the array under the current key + targetData[key].forEach(entry => { + // Check if the entry has both "Boundary Code" and "Target at the Selected Boundary level" + if (entry[codeColumnName] !== undefined && entry['Target at the Selected Boundary level'] !== undefined) { + // Add the mapping to the boundaryTargetMapping object + boundaryTargetMapping[entry[codeColumnName]] = entry['Target at the Selected Boundary level']; + } + }); + } + return boundaryTargetMapping; +} + +async function createProject(request: any, actionUrl: any, localizationMap?: any) { + logger.info("Create Projects started for the given Campaign") + var { tenantId, boundaries, projectType, projectId, startDate, endDate } = request?.body?.CampaignDetails; + if (boundaries && projectType && !projectId) { + const projectTypeResponse = await getMDMSV1Data({}, 'HCM-PROJECT-TYPES', "projectTypes", tenantId); + var Projects: any = enrichProjectDetailsFromCampaignDetails(request?.body?.CampaignDetails, projectTypeResponse); + const projectCreateBody = { + RequestInfo: request?.body?.RequestInfo, + Projects + } + await reorderBoundaries(request, localizationMap) + boundaries = request?.body?.CampaignDetails?.boundaries; + for (const boundary of boundaries) { + Projects[0].address = { tenantId: tenantId, boundary: boundary?.code, boundaryType: boundary?.type } + if (request?.body?.boundaryProjectMapping?.[boundary?.code]?.parent) { + const parent = request?.body?.boundaryProjectMapping?.[boundary?.code]?.parent + await confirmProjectParentCreation(request, request?.body?.boundaryProjectMapping?.[parent]?.projectId) + Projects[0].parent = request?.body?.boundaryProjectMapping?.[parent]?.projectId + } + else { + Projects[0].parent = null + } + Projects[0].referenceID = request?.body?.CampaignDetails?.id + Projects[0].targets = [ + { + beneficiaryType: request?.body?.CampaignDetails?.additionalDetails?.beneficiaryType, + totalNo: request?.body?.CampaignDetails?.codesTargetMapping[boundary?.code], + targetNo: request?.body?.CampaignDetails?.codesTargetMapping[boundary?.code] + } + ] + await projectCreate(projectCreateBody, request) + } + } + else if ((startDate || endDate) && projectId && actionUrl == "update") { + await updateProjectDates(request); + } +} + + +async function processAfterPersist(request: any, actionInUrl: any) { + try { + const localizationMap = await getLocalizedMessagesHandler(request, request?.body?.CampaignDetails?.tenantId); + if (request?.body?.CampaignDetails?.action == "create") { + await createProjectCampaignResourcData(request); + await createProject(request, actionInUrl, localizationMap) + await enrichAndPersistProjectCampaignRequest(request, actionInUrl, false, localizationMap) + } + else { + await enrichAndPersistProjectCampaignRequest(request, actionInUrl, false, localizationMap) + } + } catch (error: any) { + console.log(error) + logger.error(error) + enrichAndPersistCampaignWithError(request?.body, error) + } +} + +async function processBasedOnAction(request: any, actionInUrl: any) { + if (actionInUrl == "create") { + request.body.CampaignDetails.id = uuidv4() + } + await enrichAndPersistProjectCampaignRequest(request, actionInUrl, true) + processAfterPersist(request, actionInUrl) +} +async function appendSheetsToWorkbook(request: any, boundaryData: any[], differentTabsBasedOnLevel: any, localizationMap?: any) { + try { + logger.info("Received Boundary data for Processing file") + const uniqueDistrictsForMainSheet: string[] = []; + const workbook = XLSX.utils.book_new(); + const type = request?.query?.type + const headingInSheet = headingMapping?.[type] + const localisedHeading = getLocalizedName(headingInSheet, localizationMap) + await createReadMeSheet(request, workbook, localisedHeading, localizationMap); + const mainSheetData: any[] = []; + const headersForMainSheet = differentTabsBasedOnLevel ? Object.keys(boundaryData[0]).slice(0, Object.keys(boundaryData[0]).indexOf(differentTabsBasedOnLevel) + 1) : []; + const localizedHeadersForMainSheet = getLocalizedHeaders(headersForMainSheet, localizationMap); + const localizedBoundaryCode = getLocalizedName(getBoundaryColumnName(), localizationMap); + localizedHeadersForMainSheet.push(localizedBoundaryCode); + mainSheetData.push([...localizedHeadersForMainSheet]); + const districtLevelRowBoundaryCodeMap = new Map(); + for (const data of boundaryData) { + const modifiedData = modifyDataBasedOnDifferentTab(data, differentTabsBasedOnLevel, localizationMap); + const rowData = Object.values(modifiedData); + const districtIndex = modifiedData[differentTabsBasedOnLevel] !== '' ? rowData.indexOf(data[differentTabsBasedOnLevel]) : -1; + if (districtIndex == -1) { + mainSheetData.push(rowData); + } + else { + const districtLevelRow = rowData.slice(0, districtIndex + 1); + if (!uniqueDistrictsForMainSheet.includes(districtLevelRow.join('_'))) { + uniqueDistrictsForMainSheet.push(districtLevelRow.join('_')); + districtLevelRowBoundaryCodeMap.set(districtLevelRow.join('_'), data[getLocalizedName(getBoundaryColumnName(), localizationMap)]); + mainSheetData.push(rowData); + } + } + } + const mainSheet = XLSX.utils.aoa_to_sheet(mainSheetData); + const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap); + const columnWidths = Array(12).fill({ width: 30 }); + mainSheet['!cols'] = columnWidths; + XLSX.utils.book_append_sheet(workbook, mainSheet, localizedBoundaryTab); + for (const uniqueData of uniqueDistrictsForMainSheet) { + const uniqueDataFromLevelForDifferentTabs = uniqueData.slice(uniqueData.lastIndexOf('_') + 1); + const districtDataFiltered = boundaryData.filter(boundary => boundary[differentTabsBasedOnLevel] === uniqueDataFromLevelForDifferentTabs); + const modifiedFilteredData = modifyFilteredData(districtDataFiltered, districtLevelRowBoundaryCodeMap.get(uniqueData), localizationMap); + if (modifiedFilteredData?.[0]) { + const districtIndex = Object.keys(modifiedFilteredData[0]).indexOf(differentTabsBasedOnLevel); + const headers = Object.keys(modifiedFilteredData[0]).slice(districtIndex); + const modifiedHeaders = [...headers, "HCM_ADMIN_CONSOLE_TARGET"]; + const localizedHeaders = getLocalizedHeaders(modifiedHeaders, localizationMap); + const newSheetData = [localizedHeaders]; + + for (const data of modifiedFilteredData) { + const rowData = Object.values(data).slice(districtIndex).map(value => value === null ? '' : String(value)); // Replace null with empty string + newSheetData.push(rowData); + } + const ws = XLSX.utils.aoa_to_sheet(newSheetData); + const localizedDifferentTabsName = getLocalizedName(districtLevelRowBoundaryCodeMap.get(uniqueData), localizationMap); + ws['!cols'] = columnWidths; + XLSX.utils.book_append_sheet(workbook, ws, localizedDifferentTabsName); + } + } + logger.info("File processed successfully") + + return workbook; + } catch (error) { + throw Error("An error occurred while creating tabs based on district:"); + } +} +function modifyFilteredData(districtDataFiltered: any, targetBoundaryCode: any, localizationMap?: any): any { + + // Step 2: Slice the boundary code up to the last underscore + const slicedBoundaryCode = targetBoundaryCode.slice(0, targetBoundaryCode.lastIndexOf('_') + 1); + + // Step 3: Filter the rows that contain the sliced boundary code + const modifiedFilteredData = districtDataFiltered.filter((row: any, index: any) => { + // Extract the boundary code from the current row + const localizedBoundaryCode = getLocalizedName(getBoundaryColumnName(), localizationMap); + const boundaryCode = row[localizedBoundaryCode]; + // Check if the boundary code starts with the sliced boundary code + return boundaryCode.startsWith(slicedBoundaryCode); + }); + // Step 4: Return the modified filtered data + return modifiedFilteredData; +} + +async function generateFilteredBoundaryData(request: any, responseFromCampaignSearch: any) { + const rootBoundary: any = (responseFromCampaignSearch?.Filters?.boundaries).filter((boundary: any) => boundary.isRoot); + const params = { + ...request?.query, + includeChildren: true, + codes: rootBoundary?.[0]?.code + }; + const boundaryDataFromRootOnwards = await getBoundaryRelationshipData(request, params); + logger.info(`filtering the boundaries`); + const filteredBoundaryList = filterBoundaries(boundaryDataFromRootOnwards, responseFromCampaignSearch?.Filters) + logger.info(`filtered the boundaries based on given criteria`) + return filteredBoundaryList; +} + +function filterBoundaries(boundaryData: any[], filters: any): any { + function filterRecursive(boundary: any): any { + const boundaryFilters = filters && filters.boundaries; // Accessing boundaries array from filters object + const filter = boundaryFilters?.find((f: any) => f.code === boundary.code && f.boundaryType === boundary.boundaryType); + + if (!filter) { + return { + ...boundary, + children: boundary.children.map(filterRecursive) + }; + } + + if (!boundary.children.length) { + if (!filter.includeAllChildren) { + // throwError("COMMON", 400, "VALIDATION_ERROR", "Boundary cannot have includeAllChildren filter false if it does not have any children"); + logger.error("Boundary cannot have includeAllChildren filter false if it does not have any children"); + } + // If boundary has no children and includeAllChildren is true, return as is + return { + ...boundary, + children: [] + }; + } + + if (filter.includeAllChildren) { + // If includeAllChildren is true, return boundary with all children + return { + ...boundary, + children: boundary.children.map(filterRecursive) + }; + } + + const filteredChildren: any[] = []; + boundary.children.forEach((child: any) => { + const matchingFilter = boundaryFilters.find((f: any) => f.code === child.code && f.boundaryType === child.boundaryType); + if (matchingFilter) { + filteredChildren.push(filterRecursive(child)); + } + }); + return { + ...boundary, + children: filteredChildren + }; + } + const filteredData = boundaryData.map(filterRecursive); + return filteredData; +} + + +function generateHierarchy(boundaries: any[]) { + // Create an object to store boundary types and their parents + const parentMap: any = {}; + + // Populate the object with boundary types and their parents + for (const boundary of boundaries) { + parentMap[boundary.boundaryType] = boundary.parentBoundaryType; + } + + // Traverse the hierarchy to generate the hierarchy list + const hierarchyList = []; + for (const boundaryType in parentMap) { + if (Object.prototype.hasOwnProperty.call(parentMap, boundaryType)) { + const parentBoundaryType = parentMap[boundaryType]; + if (parentBoundaryType === null) { + // This boundary type has no parent, add it to the hierarchy list + hierarchyList.push(boundaryType); + // Traverse its children recursively + traverseChildren(boundaryType, parentMap, hierarchyList); + } + } + } + return hierarchyList; +} + +function traverseChildren(parent: any, parentMap: any, hierarchyList: any[]) { + for (const boundaryType in parentMap) { + if (Object.prototype.hasOwnProperty.call(parentMap, boundaryType)) { + const parentBoundaryType = parentMap[boundaryType]; + if (parentBoundaryType === parent) { + // This boundary type has the current parent, add it to the hierarchy list + hierarchyList.push(boundaryType); + // Traverse its children recursively + traverseChildren(boundaryType, parentMap, hierarchyList); + } + } + } +} + +function createBoundaryMap(boundaries: any[], boundaryMap: Map): void { + for (const boundary of boundaries) { + boundaryMap.set(boundary.code, boundary.boundaryType); + if (boundary.children.length > 0) { + createBoundaryMap(boundary.children, boundaryMap); + } + } +} + +async function boundaryBulkUpload(request: any, localizationMap?: any) { + try { + logger.info("Boundary Relationship Creation Starts"); + await autoGenerateBoundaryCodes(request, localizationMap); + await generateProcessedFileAndPersist(request); + } + catch (error: any) { + await handleResouceDetailsError(request, error) + } +} + +const autoGenerateBoundaryCodes = async (request: any, localizationMap?: any) => { + const { hierarchyType, tenantId } = request?.body?.ResourceDetails || {}; + const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId, fileStoreIds: request?.body?.ResourceDetails?.fileStoreId }, "get"); + const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap); + const boundaryData = await getSheetData(fileResponse?.fileStoreIds?.[0]?.url, localizedBoundaryTab, false, undefined, localizationMap); + const updatedBoundaryData = updateBoundaryData(boundaryData); + const hierarchy = await getHierarchy(request, tenantId, hierarchyType) || []; + const modifiedBoundaryData = modifyBoundaryDataHeaders(updatedBoundaryData, hierarchy, localizationMap); + const [withBoundaryCode, withoutBoundaryCode] = modifyBoundaryData(modifiedBoundaryData, localizationMap); + const { mappingMap, countMap } = getCodeMappingsOfExistingBoundaryCodes(withBoundaryCode); + const childParentMap = getChildParentMap(withoutBoundaryCode); + const boundaryMap = await getAutoGeneratedBoundaryCodesHandler(withoutBoundaryCode, childParentMap, mappingMap, countMap, request); + logger.info("Boundary Code Auto Generation Completed"); + await createBoundaryEntities(request, boundaryMap); + const modifiedChildParentMap = modifyChildParentMap(childParentMap, boundaryMap); + await createBoundaryRelationship(request, boundaryMap, modifiedChildParentMap); + const boundaryDataForSheet = addBoundaryCodeToData(withBoundaryCode, withoutBoundaryCode, boundaryMap); + logger.info("Initiated the localisation message creation for the uploaded boundary"); + transformAndCreateLocalisation(boundaryMap, request); + const modifiedHierarchy = hierarchy.map(ele => `${hierarchyType}_${ele}`.toUpperCase()) + const headers = [...modifiedHierarchy, config?.boundary?.boundaryCode]; + const data = prepareDataForExcel(boundaryDataForSheet, hierarchy, boundaryMap); + const localizedHeaders = getLocalizedHeaders(headers, localizationMap); + const boundarySheetData = await createExcelSheet(data, localizedHeaders, localizedBoundaryTab); + const boundaryFileDetails: any = await createAndUploadFile(boundarySheetData?.wb, request); + request.body.ResourceDetails.processedFileStoreId = boundaryFileDetails?.[0]?.fileStoreId; +} + + + +function updateBoundaryData(boundaryData: any[]): any[] { + const map: Map = new Map(); + const count: Map = new Map(); + + boundaryData.forEach((row) => { + const keys = Object.keys(row); + keys.forEach((key, index) => { + if (index > 0) { + const element = row[key]; + const previousKey = keys[index - 1]; + const previousElement = row[keys[index - 1]]; + const previousElementKey = `${previousKey}:${previousElement}`; + const elementKey = `${key}:${element}`; + + if (!map.has(elementKey)) { + map.set(elementKey, previousElementKey); + count.set(elementKey, 1); + } else { + const currentCount = count.get(elementKey)!; + if (map.get(elementKey) !== previousElementKey) { + map.set(elementKey, previousElementKey); + count.set(elementKey, currentCount + 1); + } + const uniqueCount = count.get(elementKey)!; + const uniqueElement = (uniqueCount > 1) ? `${element}-${(uniqueCount - 1).toString().padStart(2, '0')}` : `${element}`; + row[key] = uniqueElement; + } + } + }); + }); + return boundaryData; +} + +function modifyBoundaryDataHeaders(boundaryData: any[], hierarchy: any[], localizationMap?: any) { + const updatedData = boundaryData.map((obj: any) => { + const updatedObj: { [key: string]: string | undefined } = {}; // Updated object with modified keys + + let hierarchyIndex = 0; // Track the index of the hierarchy array + + for (const key in obj) { + if (key != getLocalizedName(config?.boundary?.boundaryCode, localizationMap)) { + if (Object.prototype.hasOwnProperty.call(obj, key)) { + const hierarchyKey = hierarchy[hierarchyIndex]; // Get the key from the hierarchy array + updatedObj[hierarchyKey] = obj[key]; // Map the key to the updated object + hierarchyIndex++; // Move to the next key in the hierarchy array + } + } + else { + updatedObj[key] = obj[key]; + } + } + + + return updatedObj; + }); + return updatedData; +} + +function modifyChildParentMap(childParentMap: Map, boundaryMap: Map): Map { + const modifiedMap: Map = new Map(); + + // Iterate over each entry in childParentMap + childParentMap.forEach((value, key) => { + // Get the modified key and value from boundaryMap + const modifiedKey = findMapValue(boundaryMap, key) || null; + const modifiedValue = value ? findMapValue(boundaryMap, value) : null; + + // Set the modified key-value pair in modifiedMap + modifiedMap.set(modifiedKey, modifiedValue); + }); + + return modifiedMap; +} + + +async function convertSheetToDifferentTabs(request: any, boundaryData: any, differentTabsBasedOnLevel: any, localizationMap?: any) { + // create different tabs on the level of hierarchy we want to + const updatedWorkbook = await appendSheetsToWorkbook(request, boundaryData, differentTabsBasedOnLevel, localizationMap); + // upload the excel and generate file store id + const boundaryDetails = await createAndUploadFile(updatedWorkbook, request); + return boundaryDetails; +} + +async function getBoundaryDataAfterGeneration(result: any, request: any, localizationMap?: any) { + const fileStoreId = result[0].fileStoreId; + const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: request?.query?.tenantId, fileStoreIds: fileStoreId }, "get"); + if (!fileResponse?.fileStoreIds?.[0]?.url) { + throwError("FILE", 400, "INVALID_FILE"); + } + const boundaryData = await getSheetData(fileResponse?.fileStoreIds?.[0]?.url, getBoundaryTabName(), false, undefined, localizationMap); + return boundaryData; +} + +function getLocalizedName(expectedName: string, localizationMap?: { [key: string]: string }) { + if (!localizationMap || !(expectedName in localizationMap)) { + return expectedName; + } + const localizedName = localizationMap[expectedName]; + return localizedName; +} + +async function getTargetBoundariesRelatedToCampaignId(request: any, localizationMap?: any) { + let CampaignDetails: any; + if (request?.body?.ResourceDetails?.campaignId) { + const searchBody = { + RequestInfo: request?.body?.RequestInfo, + CampaignDetails: { + ids: [request?.body?.ResourceDetails?.campaignId], + tenantId: request?.body?.ResourceDetails?.tenantId + } + } + const req: any = replicateRequest(request, searchBody) + const response = await searchProjectTypeCampaignService(req) + if (response?.CampaignDetails?.[0]) { + CampaignDetails = response?.CampaignDetails?.[0] + await addBoundariesForData(request, CampaignDetails) + } + else { + throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND", "Campaign not found while Validating sheet boundaries"); + } + } + return CampaignDetails?.boundaries; +} + + + + + +export { + generateProcessedFileAndPersist, + convertToTypeData, + getChildParentMap, + addBoundaryCodeToData, + prepareDataForExcel, + extractCodesFromBoundaryRelationshipResponse, + searchProjectCampaignResourcData, + processDataSearchRequest, + getCodeMappingsOfExistingBoundaryCodes, + processBasedOnAction, + appendSheetsToWorkbook, + generateFilteredBoundaryData, + generateHierarchy, + createBoundaryMap, + autoGenerateBoundaryCodes, + convertSheetToDifferentTabs, + getBoundaryDataAfterGeneration, + boundaryBulkUpload, + enrichAndPersistCampaignWithError, + getLocalizedName, + reorderBoundaries, + reorderBoundariesOfDataAndValidate, + getTargetBoundariesRelatedToCampaignId +} diff --git a/health-services/project-factory/src/server/utils/db/index.ts b/health-services/project-factory/src/server/utils/db/index.ts new file mode 100644 index 00000000000..d987e3eac0d --- /dev/null +++ b/health-services/project-factory/src/server/utils/db/index.ts @@ -0,0 +1,31 @@ +import pool from "../../config/dbPoolConfig"; +import { throwError } from "../genericUtils"; +import { getFormattedStringForDebug, logger } from "../logger"; + +/** + * Executes a database query asynchronously. + * + * @param {string} query - The SQL query to execute. + * @param {any} values - The values to be used in the query. + * @returns {Promise} - A Promise resolving to the query response. + * @throws - Throws an error if there is an issue with executing the query or closing the database connection. + */ +export const executeQuery = async ( + query: string, + values: any +): Promise => { + try { + logger.info(`DB QUERY :: STATEMENT :: ${query}`); + logger.info(`DB QUERY :: VALUES :: ${values}`); + const queryResponse = await pool.query(query, values); + logger.info( + `DB QUERY :: RESPONSE :: SUCCESS :: returns ${queryResponse?.rowCount} rows.` + ); + logger.debug( `DB QUERY :: RESPONSE :: SUCCESS :: Query Response ${getFormattedStringForDebug(queryResponse?.rows)}`); + return queryResponse; + } catch (error: any) { + logger.error(`Error fetching data from the database: ${error?.message}`); + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", error?.message); + throw error; + } +}; diff --git a/health-services/project-factory/src/server/utils/genericUtils.ts b/health-services/project-factory/src/server/utils/genericUtils.ts new file mode 100644 index 00000000000..1c09b105457 --- /dev/null +++ b/health-services/project-factory/src/server/utils/genericUtils.ts @@ -0,0 +1,973 @@ +import { NextFunction, Request, Response } from "express"; +import { httpRequest } from "./request"; +import config, { getErrorCodes } from "../config/index"; +import { v4 as uuidv4 } from 'uuid'; +import { produceModifiedMessages } from "../kafka/Listener"; +import { generateHierarchyList, getAllFacilities, getHierarchy } from "../api/campaignApis"; +import { getBoundarySheetData, getSheetData, createAndUploadFile, createExcelSheet, getTargetSheetData, callMdmsData, callMdmsSchema } from "../api/genericApis"; +import * as XLSX from 'xlsx'; +import FormData from 'form-data'; +import { logger } from "./logger"; +import { convertSheetToDifferentTabs, getBoundaryDataAfterGeneration, getLocalizedName } from "./campaignUtils"; +import Localisation from "../controllers/localisationController/localisation.controller"; +import { executeQuery } from "./db"; +import { generatedResourceTransformer } from "./transforms/searchResponseConstructor"; +import { generatedResourceStatuses, headingMapping, resourceDataStatuses } from "../config/constants"; +import { getLocaleFromRequest, getLocalisationModuleName } from "./localisationUtils"; +import { getBoundaryColumnName, getBoundaryTabName } from "./boundaryUtils"; +import { getBoundaryDataService } from "../service/dataManageService"; +const NodeCache = require("node-cache"); + +const updateGeneratedResourceTopic = config?.kafka?.KAFKA_UPDATE_GENERATED_RESOURCE_DETAILS_TOPIC; +const createGeneratedResourceTopic = config?.kafka?.KAFKA_CREATE_GENERATED_RESOURCE_DETAILS_TOPIC; + +/* + stdTTL: (default: 0) the standard ttl as number in seconds for every generated + cache element. 0 = unlimited + + checkperiod: (default: 600) The period in seconds, as a number, used for the automatic + delete check interval. 0 = no periodic check. + + 30 mins caching +*/ + +const appCache = new NodeCache({ stdTTL: 1800000, checkperiod: 300 }); + +/* +Send The Error Response back to client with proper response code +*/ +const throwErrorViaRequest = (message: any = "Internal Server Error") => { + if (message?.message || message?.code) { + let error: any = new Error(message?.message || message?.code); + error = Object.assign(error, { status: message?.status || 500 }); + logger.error("Error : " + error + " " + (message?.description || "")); + throw error; + } + else { + let error: any = new Error(message); + error = Object.assign(error, { status: 500 }); + logger.error("Error : " + error); + throw error; + } +}; + +function capitalizeFirstLetter(str: string | undefined) { + if (!str) return str; + return str.charAt(0).toUpperCase() + str.slice(1); +} + +const throwError = (module = "COMMON", status = 500, code = "UNKNOWN_ERROR", description: any = null) => { + const errorResult: any = getErrorCodes(module, code); + status = errorResult?.code == "UNKNOWN_ERROR" ? 500 : status; + let error: any = new Error(capitalizeFirstLetter(errorResult?.message)); + error = Object.assign(error, { status, code: errorResult?.code, description: capitalizeFirstLetter(description) }); + logger.error(error); + throw error; +}; + + +const replicateRequest = (originalRequest: Request, requestBody: any, requestQuery?: any) => { + const newRequest = { + ...originalRequest, + body: requestBody, + query: requestQuery || originalRequest.query + }; + return newRequest; +}; + + +/* +Error Object +*/ +const getErrorResponse = ( + code = "INTERNAL_SERVER_ERROR", + message = "Some Error Occured!!", + description: any = null +) => ({ + ResponseInfo: null, + Errors: [ + { + code: code, + message: message, + description: description, + params: null, + }, + ], +}); + +/* +Send The Response back to client with proper response code and response info +*/ +const sendResponse = ( + response: Response, + responseBody: any, + req: Request, + code: number = 200 +) => { + /* if (code != 304) { + appCache.set(req.headers.cachekey, { ...responseBody }); + } else { + logger.info("CACHED RESPONSE FOR :: " + req.headers.cachekey); + } + */ + logger.info("Send back the response to the client"); + response.status(code).send({ + ...getResponseInfo(code), + ...responseBody, + }); +}; + +/* +Sets the cahce response +*/ +const cacheResponse = (res: Response, key: string) => { + if (key != null) { + appCache.set(key, { ...res }); + logger.info("CACHED RESPONSE FOR :: " + key); + } +}; + +/* +gets the cahce response +*/ +const getCachedResponse = (key: string) => { + if (key != null) { + const data = appCache.get(key); + if (data) { + logger.info("CACHE STATUS :: " + JSON.stringify(appCache.getStats())); + logger.info("RETURNS THE CACHED RESPONSE FOR :: " + key); + return data; + } + } + return null; +}; + +/* +Response Object +*/ +const getResponseInfo = (code: Number) => ({ + ResponseInfo: { + apiId: "egov-bff", + ver: "0.0.1", + ts: new Date().getTime(), + status: "successful", + desc: code == 304 ? "cached-response" : "new-response", + }, +}); + +/* +Fallback Middleware function for returning 404 error for undefined paths +*/ +const invalidPathHandler = ( + request: any, + response: any, + next: NextFunction +) => { + response.status(404); + response.send(getErrorResponse("INVALID_PATH", "invalid path")); +}; + +/* +Error handling Middleware function for logging the error message +*/ +const errorLogger = ( + error: Error, + request: any, + response: any, + next: NextFunction +) => { + logger.error(error.stack); + logger.error(`error ${error.message}`); + next(error); // calling next middleware +}; + +/* +Error handling Middleware function reads the error message and sends back a response in JSON format +*/ +const errorResponder = ( + error: any, + request: any, + response: Response, + status: any = 500, + next: any = null +) => { + if (error?.status) { + status = error?.status; + } + const code = error?.code || (status === 500 ? "INTERNAL_SERVER_ERROR" : (status === 400 ? "BAD_REQUEST" : "UNKNOWN_ERROR")); + response.header("Content-Type", "application/json"); + const errorMessage = trimError(error.message || "Some Error Occurred!!"); + const errorDescription = error.description || null; + const errorResponse = getErrorResponse(code, errorMessage, errorDescription); + response.status(status).send(errorResponse); +}; + + +const trimError = (e: any) => { + if (typeof e === "string") { + e = e.trim(); + while (e.startsWith("Error:")) { + e = e.substring(6); + e = e.trim(); + } + } + return e; +} + +async function generateXlsxFromJson(request: any, response: any, simplifiedData: any) { + const ws = XLSX.utils.json_to_sheet(simplifiedData); + + // Create a new workbook + const wb = XLSX.utils.book_new(); + XLSX.utils.book_append_sheet(wb, ws, 'Sheet 1'); + const buffer = XLSX.write(wb, { bookType: 'xlsx', type: 'buffer' }); + const formData = new FormData(); + formData.append('file', buffer, 'filename.xlsx'); + formData.append('tenantId', request?.body?.RequestInfo?.userInfo?.tenantId); + formData.append('module', 'HCM-ADMIN-CONSOLE-PROCESS'); + + var fileCreationResult = await httpRequest(config.host.filestore + config.paths.filestore, formData, undefined, undefined, undefined, + { + 'Content-Type': 'multipart/form-data', + 'auth-token': request?.body?.RequestInfo?.authToken + } + ); + const responseData = fileCreationResult?.files; + logger.info("Response data after File Creation : " + JSON.stringify(responseData)); + return responseData; +} + +async function generateActivityMessage(tenantId: any, requestBody: any, requestPayload: any, responsePayload: any, type: any, url: any, status: any) { + const activityMessage = { + id: uuidv4(), + status: status, + retryCount: 0, + tenantId: tenantId, + type: type, + url: url, + requestPayload: requestPayload, + responsePayload: responsePayload, + auditDetails: { + createdBy: requestBody?.RequestInfo?.userInfo?.uuid, + lastModifiedBy: requestBody?.RequestInfo?.userInfo?.uuid, + createdTime: Date.now(), + lastModifiedTime: Date.now() + }, + additionalDetails: {}, + resourceDetailsId: null + } + return activityMessage; +} + +/* Fetches data from the database */ +async function getResponseFromDb(request: any) { + try { + const { type } = request.query; + const { tenantId, hierarchyType } = request.query; + const status = generatedResourceStatuses.completed; + let queryResult: any; + let queryString: string; + let queryValues: any[] = []; + + queryString = "SELECT * FROM health.eg_cm_generated_resource_details WHERE "; + // query for download with id + if (request?.query?.id) { + queryString += "id = $1 AND type = $2 AND hierarchytype = $3 AND tenantid = $4 "; + queryValues = [request.query.id, type, hierarchyType, tenantId]; + } + else { + if (type == 'boundary' && request?.body?.Filters !== undefined) { + queryString += "type = $1 AND hierarchytype = $2 AND tenantid = $3 AND status =$4 "; + if (request.body.Filters === null) { + queryString += " AND (additionaldetails->'Filters' IS NULL OR additionaldetails->'Filters' = 'null')"; + queryValues = [type, hierarchyType, tenantId, status]; + } else { + queryString += " AND additionaldetails->'Filters' @> $5::jsonb"; + queryValues = [type, hierarchyType, tenantId, status, request.body.Filters]; + } + } + else { + queryString += " type = $1 AND hierarchytype = $2 AND tenantid = $3 AND status = $4"; + queryValues = [type, hierarchyType, tenantId, status]; + } + } + queryResult = await executeQuery(queryString, queryValues); + return generatedResourceTransformer(queryResult?.rows); + } + catch (error: any) { + logger.error(`Error fetching data from the database: ${error.message}`); + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", error?.message); + return null; // Return null in case of an error + } +} + +async function getModifiedResponse(responseData: any) { + return responseData.map((item: any) => { + return { + ...item, + count: parseInt(item.count), + auditDetails: { + ...item.auditDetails, + lastModifiedTime: parseInt(item.auditDetails.lastModifiedTime), + createdTime: parseInt(item.auditDetails.createdTime) + } + }; + }); +} + +async function getNewEntryResponse(request: any) { + const { type } = request.query; + const additionalDetails = type === 'boundary' + ? { Filters: request?.body?.Filters ?? null } + : {}; + const newEntry = { + id: uuidv4(), + fileStoreid: null, + type: type, + status: generatedResourceStatuses.inprogress, + hierarchyType: request?.query?.hierarchyType, + tenantId: request?.query?.tenantId, + auditDetails: { + lastModifiedTime: Date.now(), + createdTime: Date.now(), + createdBy: request?.body?.RequestInfo?.userInfo.uuid, + lastModifiedBy: request?.body?.RequestInfo?.userInfo.uuid, + }, + additionalDetails: additionalDetails, + count: null + }; + return [newEntry]; +} +async function getOldEntryResponse(modifiedResponse: any[], request: any) { + return modifiedResponse.map((item: any) => { + const newItem = { ...item }; + newItem.status = generatedResourceStatuses.expired; + newItem.auditDetails.lastModifiedTime = Date.now(); + newItem.auditDetails.lastModifiedBy = request?.body?.RequestInfo?.userInfo?.uuid; + return newItem; + }); +} +async function getFinalUpdatedResponse(result: any, responseData: any, request: any) { + return responseData.map((item: any) => { + return { + ...item, + tenantId: request?.query?.tenantId, + count: parseInt(request?.body?.generatedResourceCount || null), + auditDetails: { + ...item.auditDetails, + lastModifiedTime: Date.now(), + createdTime: Date.now(), + lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid + }, + fileStoreid: result?.[0]?.fileStoreId, + status: resourceDataStatuses.completed + }; + }); +} + + + +async function fullProcessFlowForNewEntry(newEntryResponse: any, generatedResource: any, request: any) { + try { + const { type, hierarchyType } = request?.query; + generatedResource = { generatedResource: newEntryResponse } + // send message to create toppic + logger.info(`processing the generate request for type ${type}`) + produceModifiedMessages(generatedResource, createGeneratedResourceTopic); + const localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler(request, request?.query?.tenantId, getLocalisationModuleName(hierarchyType)); + const localizationMapModule = await getLocalizedMessagesHandler(request, request?.query?.tenantId); + const localizationMap = { ...localizationMapHierarchy, ...localizationMapModule }; + if (type === 'boundary') { + // get boundary data from boundary relationship search api + const result = await getBoundaryDataService(request); + let updatedResult = result; + // get boundary sheet data after being generated + const boundaryData = await getBoundaryDataAfterGeneration(result, request, localizationMap); + const differentTabsBasedOnLevel = getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap); + logger.info(`Boundaries are seperated based on hierarchy type ${differentTabsBasedOnLevel}`) + const isKeyOfThatTypePresent = boundaryData.some((data: any) => data.hasOwnProperty(differentTabsBasedOnLevel)); + const boundaryTypeOnWhichWeSplit = boundaryData.filter((data: any) => data[differentTabsBasedOnLevel] !== null && data[differentTabsBasedOnLevel] !== undefined); + if (isKeyOfThatTypePresent && boundaryTypeOnWhichWeSplit.length >= parseInt(config?.boundary?.numberOfBoundaryDataOnWhichWeSplit)) { + logger.info(`sinces the conditions are matched boundaries are getting splitted into different tabs`) + updatedResult = await convertSheetToDifferentTabs(request, boundaryData, differentTabsBasedOnLevel, localizationMap); + } + // final upodated response to be sent to update topic + const finalResponse = await getFinalUpdatedResponse(updatedResult, newEntryResponse, request); + const generatedResourceNew: any = { generatedResource: finalResponse } + // send to update topic + produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); + request.body.generatedResource = finalResponse; + } + else if (type == "facilityWithBoundary" || type == 'userWithBoundary') { + await processGenerateRequest(request, localizationMap); + const finalResponse = await getFinalUpdatedResponse(request?.body?.fileDetails, newEntryResponse, request); + const generatedResourceNew: any = { generatedResource: finalResponse } + produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); + request.body.generatedResource = finalResponse; + } + } catch (error: any) { + console.log(error) + handleGenerateError(newEntryResponse, generatedResource, error); + } +} + +function generateAuditDetails(request: any) { + const createdBy = request?.body?.RequestInfo?.userInfo?.uuid; + const lastModifiedBy = request?.body?.RequestInfo?.userInfo?.uuid; + const auditDetails = { + createdBy: createdBy, + lastModifiedBy: lastModifiedBy, + createdTime: Date.now(), + lastModifiedTime: Date.now() + } + return auditDetails; +} + + + +function sortCampaignDetails(campaignDetails: any) { + campaignDetails.sort((a: any, b: any) => { + // If a is a child of b, a should come after b + if (a.parentBoundaryCode === b.boundaryCode) return 1; + // If b is a child of a, a should come before b + if (a.boundaryCode === b.parentBoundaryCode) return -1; + // Otherwise, maintain the order + return 0; + }); + return campaignDetails; +} +// Function to correct the totals and target values of parents +function correctParentValues(campaignDetails: any) { + // Create a map to store parent-child relationships and their totals/targets + const parentMap: any = {}; + campaignDetails.forEach((detail: any) => { + if (!detail.parentBoundaryCode) return; // Skip if it's not a child + if (!parentMap[detail.parentBoundaryCode]) { + parentMap[detail.parentBoundaryCode] = { total: 0, target: 0 }; + } + parentMap[detail.parentBoundaryCode].total += detail.targets[0].total; + parentMap[detail.parentBoundaryCode].target += detail.targets[0].target; + }); + + // Update parent values with the calculated totals and targets + campaignDetails.forEach((detail: any) => { + if (!detail.parentBoundaryCode) return; // Skip if it's not a child + const parent = parentMap[detail.parentBoundaryCode]; + const target = detail.targets[0]; + target.total = parent.total; + target.target = parent.target; + }); + + return campaignDetails; +} + +async function createFacilitySheet(request: any, allFacilities: any[], localizationMap?: { [key: string]: string }) { + const tenantId = request?.query?.tenantId; + const schema = await callMdmsSchema(request, config?.values?.moduleName, "facility", tenantId); + const keys = schema?.required; + const headers = ["HCM_ADMIN_CONSOLE_FACILITY_CODE", ...keys] + const localizedHeaders = getLocalizedHeaders(headers, localizationMap); + + const facilities = allFacilities.map((facility: any) => { + return [ + facility?.id, + facility?.name, + facility?.usage, + facility?.isPermanent ? "Permanent" : "Temporary", + facility?.storageCapacity, + "" + ] + }) + logger.info("facilities : " + JSON.stringify(facilities)); + const localizedFacilityTab = getLocalizedName(config?.facility?.facilityTab, localizationMap); + const facilitySheetData: any = await createExcelSheet(facilities, localizedHeaders, localizedFacilityTab); + return facilitySheetData; +} + +async function createReadMeSheet(request: any, workbook: any, mainHeader: any, localizationMap?: any) { + const readMeConfig = await getReadMeConfig(request); + const maxCharsBeforeLineBreak = 100; // Set the maximum number of characters before line break + const datas = readMeConfig.texts.flatMap((text: any) => { + let stepText = ''; // Initialize step text for each text element + let stepCount = 1; // Initialize the step counter + const descriptions = text.descriptions.map((description: any) => { + let textWithLineBreaks = ''; + let remainingText = getLocalizedName(description.text, localizationMap); + while (remainingText.length > maxCharsBeforeLineBreak) { + let breakIndex = remainingText.lastIndexOf(' ', maxCharsBeforeLineBreak); + if (breakIndex === -1) breakIndex = maxCharsBeforeLineBreak; + textWithLineBreaks += remainingText.substring(0, breakIndex) + '\n'; + remainingText = remainingText.substring(breakIndex).trim(); + } + textWithLineBreaks += remainingText; + // If step is required, add step text before description + if (description.isStepRequired) { + stepText = `Step ${stepCount}: `; + stepCount++; + return stepText + textWithLineBreaks; + } + else { + return textWithLineBreaks; + } + }); + return [getLocalizedName(text.header, localizationMap), ...descriptions, "", "", "", ""]; + }); + + // Ensure mainHeader is an array + if (!Array.isArray(mainHeader)) { + mainHeader = [mainHeader]; + } + + const worksheet = XLSX.utils.aoa_to_sheet([mainHeader, "", "", ...datas.map((data: any) => [data])]); + + // Set the width of column A to 130 + const wscols = [{ wch: 130 }]; + worksheet['!cols'] = wscols; + const readMeSheetName = getLocalizedName("HCM_README_SHEETNAME", localizationMap); + XLSX.utils.book_append_sheet(workbook, worksheet, readMeSheetName); +} + + + + +function getLocalizedHeaders(headers: any, localizationMap?: { [key: string]: string }) { + const messages = headers.map((header: any) => (localizationMap ? localizationMap[header] || header : header)); + return messages; +} + + + +function modifyRequestForLocalisation(request: any, tenantId: string) { + const { RequestInfo } = request?.body; + const query = { + "tenantId": tenantId, + "locale": getLocaleFromRequest(request), + "module": config.localisation.localizationModule + }; + const updatedRequest = { ...request }; + updatedRequest.body = { RequestInfo }; + updatedRequest.query = query; + return updatedRequest; +} + +async function getReadMeConfig(request: any) { + const mdmsResponse = await callMdmsData(request, "HCM-ADMIN-CONSOLE", "ReadMeConfig", request?.query?.tenantId); + if (mdmsResponse?.MdmsRes?.["HCM-ADMIN-CONSOLE"]?.ReadMeConfig) { + const readMeConfigsArray = mdmsResponse?.MdmsRes?.["HCM-ADMIN-CONSOLE"]?.ReadMeConfig + for (const readMeConfig of readMeConfigsArray) { + if (readMeConfig?.type == request?.query?.type) { + return readMeConfig + } + } + throwError("MDMS", 500, "INVALID_README_CONFIG", `Readme config for type ${request?.query?.type} not found.`); + return {} + } + else { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", `Some error occured during readme config mdms search.`); + return {}; + } +} + +async function createFacilityAndBoundaryFile(facilitySheetData: any, boundarySheetData: any, request: any, localizationMap?: { [key: string]: string }) { + const workbook = XLSX.utils.book_new(); + // Add facility sheet to the workbook + const localizedFacilityTab = getLocalizedName(config?.facility?.facilityTab, localizationMap); + const type = request?.query?.type; + const headingInSheet = headingMapping?.[type] + const localisedHeading = getLocalizedName(headingInSheet, localizationMap) + await createReadMeSheet(request, workbook, localisedHeading, localizationMap); + XLSX.utils.book_append_sheet(workbook, facilitySheetData.ws, localizedFacilityTab); + // Add boundary sheet to the workbook + const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap) + XLSX.utils.book_append_sheet(workbook, boundarySheetData.ws, localizedBoundaryTab); + const fileDetails = await createAndUploadFile(workbook, request) + request.body.fileDetails = fileDetails; +} + +async function createUserAndBoundaryFile(userSheetData: any, boundarySheetData: any, request: any, localizationMap?: { [key: string]: string }) { + const workbook = XLSX.utils.book_new(); + const localizedUserTab = getLocalizedName(config?.user?.userTab, localizationMap); + const type = request?.query?.type; + const headingInSheet = headingMapping?.[type] + const localisedHeading = getLocalizedName(headingInSheet, localizationMap) + await createReadMeSheet(request, workbook, localisedHeading, localizationMap); + // Add facility sheet to the workbook + XLSX.utils.book_append_sheet(workbook, userSheetData.ws, localizedUserTab); + // Add boundary sheet to the workbook + const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap) + XLSX.utils.book_append_sheet(workbook, boundarySheetData.ws, localizedBoundaryTab); + const fileDetails = await createAndUploadFile(workbook, request) + request.body.fileDetails = fileDetails; +} + + +async function generateFacilityAndBoundarySheet(tenantId: string, request: any, localizationMap?: { [key: string]: string }) { + // Get facility and boundary data + logger.info("Generating facilities started"); + const allFacilities = await getAllFacilities(tenantId, request.body); + request.body.generatedResourceCount = allFacilities?.length; + logger.info(`Facilities generation completed and found ${allFacilities?.length} facilities`); + const facilitySheetData: any = await createFacilitySheet(request, allFacilities, localizationMap); + // request.body.Filters = { tenantId: tenantId, hierarchyType: request?.query?.hierarchyType, includeChildren: true } + const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); + await createFacilityAndBoundaryFile(facilitySheetData, boundarySheetData, request, localizationMap); +} +async function generateUserAndBoundarySheet(request: any, localizationMap?: { [key: string]: string }) { + const userData: any[] = []; + const tenantId = request?.query?.tenantId; + const schema = await callMdmsSchema(request, config?.values?.moduleName, "user", tenantId); + const headers = schema?.required; + const localizedHeaders = getLocalizedHeaders(headers, localizationMap); + const localizedUserTab = getLocalizedName(config?.user?.userTab, localizationMap); + logger.info("Generated an empty user template"); + const userSheetData = await createExcelSheet(userData, localizedHeaders, localizedUserTab); + const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); + await createUserAndBoundaryFile(userSheetData, boundarySheetData, request, localizationMap); +} +async function processGenerateRequest(request: any, localizationMap?: { [key: string]: string }) { + const { type, tenantId } = request.query + if (type == "facilityWithBoundary") { + await generateFacilityAndBoundarySheet(String(tenantId), request, localizationMap); + } + if (type == "userWithBoundary") { + await generateUserAndBoundarySheet(request, localizationMap); + } +} + +async function processGenerateForNew(request: any, generatedResource: any, newEntryResponse: any) { + request.body.generatedResource = newEntryResponse; + fullProcessFlowForNewEntry(newEntryResponse, generatedResource, request); + return request.body.generatedResource; +} + +function handleGenerateError(newEntryResponse: any, generatedResource: any, error: any) { + newEntryResponse.map((item: any) => { item.status = generatedResourceStatuses.failed, item.additionalDetails = { ...item.additionalDetails, error: error.message || String(error) } }) + generatedResource = { generatedResource: newEntryResponse }; + logger.error(String(error)); + produceModifiedMessages(generatedResource, updateGeneratedResourceTopic); +} + +async function updateAndPersistGenerateRequest(newEntryResponse: any, oldEntryResponse: any, responseData: any, request: any) { + const { forceUpdate } = request.query; + const forceUpdateBool: boolean = forceUpdate === 'true'; + let generatedResource: any; + if (forceUpdateBool && responseData.length > 0) { + generatedResource = { generatedResource: oldEntryResponse }; + // send message to update topic + produceModifiedMessages(generatedResource, updateGeneratedResourceTopic); + request.body.generatedResource = oldEntryResponse; + } + if (responseData.length === 0 || forceUpdateBool) { + processGenerateForNew(request, generatedResource, newEntryResponse) + } + else { + request.body.generatedResource = responseData + } +} +/* + +*/ +async function processGenerate(request: any) { + // fetch the data from db + const responseData = await getResponseFromDb(request); + // modify response from db + const modifiedResponse = await getModifiedResponse(responseData); + // generate new random id and make filestore id null + const newEntryResponse = await getNewEntryResponse(request); + // make old data status as expired + const oldEntryResponse = await getOldEntryResponse(modifiedResponse, request); + // generate data + await updateAndPersistGenerateRequest(newEntryResponse, oldEntryResponse, responseData, request); +} +/* +TODO add comments @nitish-egov + +*/ +async function enrichResourceDetails(request: any) { + request.body.ResourceDetails.id = uuidv4(); + request.body.ResourceDetails.processedFileStoreId = null; + if (request?.body?.ResourceDetails?.action == "create") { + request.body.ResourceDetails.status = resourceDataStatuses.accepted + } + else { + request.body.ResourceDetails.status = resourceDataStatuses.started + } + request.body.ResourceDetails.auditDetails = { + createdBy: request?.body?.RequestInfo?.userInfo?.uuid, + createdTime: Date.now(), + lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, + lastModifiedTime: Date.now() + } + produceModifiedMessages(request?.body, config?.kafka?.KAFKA_CREATE_RESOURCE_DETAILS_TOPIC); +} + +function getFacilityIds(data: any) { + return data.map((obj: any) => obj["id"]) +} + +function matchData(request: any, datas: any, searchedDatas: any, createAndSearchConfig: any) { + const uid = createAndSearchConfig.uniqueIdentifier; + const errors = [] + for (const data of datas) { + const searchData = searchedDatas.find((searchedData: any) => searchedData[uid] == data[uid]); + + if (!searchData) { + errors.push({ status: "INVALID", rowNumber: data["!row#number!"], errorDetails: `Data with ${uid} ${data[uid]} not found in searched data.` }) + } + else if (createAndSearchConfig?.matchEachKey) { + const keys = Object.keys(data); + var errorString = ""; + var errorFound = false; + for (const key of keys) { + if (searchData.hasOwnProperty(key) && searchData[key] !== data[key] && key != "!row#number!") { + errorString += `Value mismatch for key "${key}. Expected: "${data[key]}", Found: "${searchData[key]}"` + errorFound = true; + } + } + if (errorFound) { + errors.push({ status: "MISMATCHING", rowNumber: data["!row#number!"], errorDetails: errorString }) + } + else { + errors.push({ status: "VALID", rowNumber: data["!row#number!"], errorDetails: "" }) + } + } + else { + errors.push({ status: "VALID", rowNumber: data["!row#number!"], errorDetails: "" }) + } + } + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; +} + +function modifyBoundaryData(boundaryData: unknown[], localizationMap?: any) { + // Initialize arrays to store data + const withBoundaryCode: { key: string, value: string }[][] = []; + const withoutBoundaryCode: { key: string, value: string }[][] = []; + // Process each object in boundaryData + boundaryData.forEach((obj: any) => { + // Convert object entries to an array of {key, value} objects + const row: any = Object.entries(obj) + .filter(([key, value]) => value !== null && value !== undefined) + .map(([key, value]) => ({ key, value })); + + // Determine whether the object has a boundary code property + const hasBoundaryCode = obj.hasOwnProperty(getLocalizedName(config?.boundary?.boundaryCode, localizationMap)); + + // Push the row to the appropriate array based on whether it has a boundary code property + if (hasBoundaryCode) { + withBoundaryCode.push(row); + } else { + withoutBoundaryCode.push(row); + } + }); + + // Return the arrays + return [withBoundaryCode, withoutBoundaryCode]; +} + + + +async function getDataFromSheet(request: any, fileStoreId: any, tenantId: any, createAndSearchConfig: any, optionalSheetName?: any, localizationMap?: { [key: string]: string }) { + const type = request?.body?.ResourceDetails?.type; + const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: tenantId, fileStoreIds: fileStoreId }, "get"); + if (!fileResponse?.fileStoreIds?.[0]?.url) { + throwError("FILE", 500, "DOWNLOAD_URL_NOT_FOUND"); + } + if (type == 'boundaryWithTarget') { + return await getTargetSheetData(fileResponse?.fileStoreIds?.[0]?.url, true, true, localizationMap); + } + return await getSheetData(fileResponse?.fileStoreIds?.[0]?.url, createAndSearchConfig?.parseArrayConfig?.sheetName || optionalSheetName, true, createAndSearchConfig, localizationMap) +} + +async function getBoundaryRelationshipData(request: any, params: any) { + logger.info("Boundary relationship search initiated") + const url = `${config.host.boundaryHost}${config.paths.boundaryRelationship}`; + const boundaryRelationshipResponse = await httpRequest(url, request.body, params); + logger.info("Boundary relationship search response received") + return boundaryRelationshipResponse?.TenantBoundary?.[0]?.boundary; +} + +async function getDataSheetReady(boundaryData: any, request: any, localizationMap?: { [key: string]: string }) { + const type = request?.query?.type; + const boundaryType = boundaryData?.[0].boundaryType; + const boundaryList = generateHierarchyList(boundaryData) + if (!Array.isArray(boundaryList) || boundaryList.length === 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Boundary list is empty or not an array."); + } + + const hierarchy = await getHierarchy(request, request?.query?.tenantId, request?.query?.hierarchyType); + const startIndex = boundaryType ? hierarchy.indexOf(boundaryType) : -1; + const reducedHierarchy = startIndex !== -1 ? hierarchy.slice(startIndex) : hierarchy; + const modifiedReducedHierarchy = reducedHierarchy.map(ele => `${request?.query?.hierarchyType}_${ele}`.toUpperCase()) + const headers = (type !== "facilityWithBoundary" && type !== "userWithBoundary") + ? [ + ...modifiedReducedHierarchy, + getBoundaryColumnName(), + "Target at the Selected Boundary level" + ] + : [ + ...modifiedReducedHierarchy, + getBoundaryColumnName() + ]; + const localizedHeaders = getLocalizedHeaders(headers, localizationMap); + const data = boundaryList.map(boundary => { + const boundaryParts = boundary.split(','); + const boundaryCode = boundaryParts[boundaryParts.length - 1]; + const rowData = boundaryParts.concat(Array(Math.max(0, reducedHierarchy.length - boundaryParts.length)).fill('')); + // localize the boundary codes + const mappedRowData = rowData.map((cell: any, index: number) => + index === reducedHierarchy.length ? '' : cell !== '' ? getLocalizedName(cell, localizationMap) : '' + ); + const boundaryCodeIndex = reducedHierarchy.length; + mappedRowData[boundaryCodeIndex] = boundaryCode; + return mappedRowData; + }); + const sheetRowCount = data.length; + if (type != "facilityWithBoundary") { + request.body.generatedResourceCount = sheetRowCount; + } + const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap); + return await createExcelSheet(data, localizedHeaders, localizedBoundaryTab); +} + +function modifyTargetData(data: any) { + const dataArray: any[] = []; + Object.keys(data).forEach(key => { + data[key].forEach((item: any) => { + dataArray.push(item); + }); + }); + return dataArray; +} + +function calculateKeyIndex(obj: any, hierachy: any[], localizationMap?: any) { + const keys = Object.keys(obj); + const localizedBoundaryCode = getLocalizedName(getBoundaryColumnName(), localizationMap) + const boundaryCodeIndex = keys.indexOf(localizedBoundaryCode); + const keyBeforeBoundaryCode = keys[boundaryCodeIndex - 1]; + return hierachy.indexOf(keyBeforeBoundaryCode); +} + +function modifyDataBasedOnDifferentTab(boundaryData: any, differentTabsBasedOnLevel: any, localizationMap?: any) { + const newData: any = {}; + let boundaryCode: string | undefined; + + for (const key in boundaryData) { + newData[key] = boundaryData[key]; + if (key === differentTabsBasedOnLevel) { + break; + } + } + const localizedBoundaryCode = getLocalizedName(getBoundaryColumnName(), localizationMap); + boundaryCode = boundaryData[localizedBoundaryCode]; + if (boundaryCode !== undefined) { + newData[localizedBoundaryCode] = boundaryCode; + } + return newData; +} + +async function getLocalizedMessagesHandler(request: any, tenantId: any, module = config.localisation.localizationModule) { + const localisationcontroller = Localisation.getInstance(); + const locale = getLocaleFromRequest(request); + const localizationResponse = await localisationcontroller.getLocalisedData(module, locale, tenantId); + return localizationResponse; +} + + + +async function translateSchema(schema: any, localizationMap?: { [key: string]: string }) { + const translatedSchema = { + ...schema, + properties: Object.entries(schema?.properties || {}).reduce((acc, [key, value]) => { + const localizedMessage = getLocalizedName(key, localizationMap); + acc[localizedMessage] = value; + return acc; + }, {} as { [key: string]: any }), // Initialize with the correct type + required: (schema?.required || []).map((key: string) => getLocalizedName(key, localizationMap)), + unique: (schema?.unique || []).map((key: string) => getLocalizedName(key, localizationMap)) + }; + + return translatedSchema; +} + + +function findMapValue(map: Map, key: any): any | null { + let foundValue = null; + map.forEach((value, mapKey) => { + if (mapKey.key === key.key && mapKey.value === key.value) { + foundValue = value; + } + }); + return foundValue; +} + +function getDifferentDistrictTabs(boundaryData: any, differentTabsBasedOnLevel: any) { + const uniqueDistrictsForMainSheet: string[] = []; + const differentDistrictTabs: any[] = []; + for (const data of boundaryData) { + const rowData = Object.values(data); + const districtValue = data[differentTabsBasedOnLevel]; + const districtIndex = districtValue !== '' ? rowData.indexOf(districtValue) : -1; + + if (districtIndex != -1) { + const districtLevelRow = rowData.slice(0, districtIndex + 1); + const districtKey = districtLevelRow.join('_'); + + if (!uniqueDistrictsForMainSheet.includes(districtKey)) { + uniqueDistrictsForMainSheet.push(districtKey); + } + } + } + for (const uniqueData of uniqueDistrictsForMainSheet) { + differentDistrictTabs.push(uniqueData.slice(uniqueData.lastIndexOf('_') + 1)); + } + return differentDistrictTabs; +} + + + + +export { + errorResponder, + errorLogger, + invalidPathHandler, + getResponseInfo, + throwError, + throwErrorViaRequest, + sendResponse, + appCache, + cacheResponse, + getCachedResponse, + generateXlsxFromJson, + generateAuditDetails, + generateActivityMessage, + getResponseFromDb, + getModifiedResponse, + getNewEntryResponse, + getOldEntryResponse, + getFinalUpdatedResponse, + fullProcessFlowForNewEntry, + correctParentValues, + sortCampaignDetails, + processGenerateRequest, + processGenerate, + getFacilityIds, + getDataFromSheet, + matchData, + enrichResourceDetails, + modifyBoundaryData, + getBoundaryRelationshipData, + getDataSheetReady, + modifyTargetData, + calculateKeyIndex, + modifyDataBasedOnDifferentTab, + modifyRequestForLocalisation, + translateSchema, + getLocalizedMessagesHandler, + getLocalizedHeaders, + createReadMeSheet, + findMapValue, + replicateRequest, + getDifferentDistrictTabs +}; + + diff --git a/health-services/project-factory/src/server/utils/localisationUtils.ts b/health-services/project-factory/src/server/utils/localisationUtils.ts new file mode 100644 index 00000000000..0b1bd4804be --- /dev/null +++ b/health-services/project-factory/src/server/utils/localisationUtils.ts @@ -0,0 +1,38 @@ +import config from "../config/index"; + +// Function to extract locale from request object +export const getLocaleFromRequest = (request: any) => { + // Extract msgId from request body + const msgId = request?.body?.RequestInfo?.msgId; + // Split msgId by '|' delimiter and get the second part (index 1) + // If splitting fails or no second part is found, use default locale from config + return msgId.split("|")?.[1] || config?.localisation?.defaultLocale; +}; + +// Function to generate localisation module name based on hierarchy type +export const getLocalisationModuleName = (hierarchyType: any) => { + // Construct module name using boundary prefix from config and hierarchy type + // Convert module name to lowercase + return `${config.localisation.boundaryPrefix}-${getTransformedLocale(hierarchyType)}`?.toLowerCase(); +}; + +/** + * Transforms a label into a formatted locale string. + * @param label - The label to be transformed. + * @returns The transformed locale string. + */ +export const getTransformedLocale = (label: string) => { + // Trim leading and trailing whitespace from the label + label = label?.trim(); + // If label is not empty, convert to uppercase and replace special characters with underscores + return label && label.toUpperCase().replace(/[.:-\s\/]/g, "_"); + }; + + + export const convertLocalisationResponseToMap=(messages:any=[])=>{ + const localizationMap: any = {}; + messages.forEach((message: any) => { + localizationMap[message.code] = message.message; + }); + return localizationMap; + } \ No newline at end of file diff --git a/health-services/project-factory/src/server/utils/logger/index.ts b/health-services/project-factory/src/server/utils/logger/index.ts new file mode 100644 index 00000000000..f2cad55890b --- /dev/null +++ b/health-services/project-factory/src/server/utils/logger/index.ts @@ -0,0 +1,32 @@ +import { createLogger, format, transports } from "winston"; // Importing necessary modules from Winston library +import config from "../../config"; + +// Custom log format for Winston logger +const myFormat = format.printf(({ level, message, label, timestamp }) => { + return `${timestamp} [${label}] [${level}]: ${message}`; // Custom log message format +}); + +// Creating a logger instance with specified format and transports +const logger = createLogger({ + level: config.app.logLevel, // Set the minimum level to log, in this case, DEBUG + format: format.combine( + // Combining different log formats + format.label({ label: "BFF" }), // Adding label to logs + format.timestamp({ format: " YYYY-MM-DD HH:mm:ss.SSSZZ " }), // Adding timestamp to logs + format.simple(), // Simplifying log format + format.colorize(), // Adding color to logs for console output + myFormat // Using custom log format defined above + ), + transports: [new transports.Console()], // Using Console transport for logging +}); + +// Exporting the logger instance for external use +export { logger }; + +const DEFAULT_LOG_MESSAGE_COUNT = config.app.debugLogCharLimit; + +export const getFormattedStringForDebug = (obj: any) => { + const convertedMessage=JSON.stringify(obj); + return convertedMessage?.slice(0, DEFAULT_LOG_MESSAGE_COUNT) + + (convertedMessage?.length > DEFAULT_LOG_MESSAGE_COUNT ? "\n ---more" : ""); +} diff --git a/health-services/project-factory/src/server/utils/middlewares/asyncMiddleware.ts b/health-services/project-factory/src/server/utils/middlewares/asyncMiddleware.ts new file mode 100644 index 00000000000..12cb36c6516 --- /dev/null +++ b/health-services/project-factory/src/server/utils/middlewares/asyncMiddleware.ts @@ -0,0 +1,11 @@ +import { NextFunction, Request, Response } from "express"; // Importing necessary modules from Express + +// Defining a middleware function that wraps async route handlers +const asyncMiddleware = (fn: (req: Request, res: Response, next: NextFunction) => any) => + (req: Request, res: Response, next: NextFunction) => { + // Wrapping the asynchronous route handler in a Promise to handle errors + Promise.resolve(fn(req, res, next)) + .catch(next); // Catching any errors and passing them to the error handling middleware + }; + +export default asyncMiddleware; // Exporting the async middleware function for use in Express routes diff --git a/health-services/project-factory/src/server/utils/middlewares/cacheMiddleware.ts b/health-services/project-factory/src/server/utils/middlewares/cacheMiddleware.ts new file mode 100644 index 00000000000..192298615cd --- /dev/null +++ b/health-services/project-factory/src/server/utils/middlewares/cacheMiddleware.ts @@ -0,0 +1,31 @@ +// Importing necessary modules from genericUtils +import { errorResponder, appCache } from "../genericUtils"; + +// Importing necessary modules from Express +import { NextFunction, Request, Response } from "express"; + +// Variable to indicate whether caching is enabled or not +const cacheEnabled = false; + +// Middleware function to handle caching +const cacheMiddleware = (req: Request, res: Response, next: NextFunction) => { + try { + // Attempt to retrieve data from cache based on cache key in request headers + const cacheData = appCache.get(req.headers.cachekey); + + // Check if cache data exists and caching is enabled + if (cacheData && cacheEnabled) { + // If cache data exists and caching is enabled, send the cached data as response + res.send(cacheData); + } else { + // If cache data doesn't exist or caching is disabled, proceed to the next middleware/route handler + next(); + } + } catch (error) { + // If an error occurs during caching process, handle the error using errorResponder function + errorResponder(error, req, res, next); + } +}; + +// Exporting the cacheMiddleware function for use in Express middleware chain +export default cacheMiddleware; diff --git a/health-services/project-factory/src/server/utils/middlewares/index.ts b/health-services/project-factory/src/server/utils/middlewares/index.ts new file mode 100644 index 00000000000..8789bc0ef27 --- /dev/null +++ b/health-services/project-factory/src/server/utils/middlewares/index.ts @@ -0,0 +1,9 @@ +import asyncMiddleware from "./asyncMiddleware"; // Importing asyncMiddleware for handling asynchronous middleware functions +import cacheMiddleware from "./cacheMiddleware"; // Importing cacheMiddleware for caching mechanism +import requestMiddleware from "./requestMiddleware"; // Importing requestMiddleware for handling request-related middleware + +export { + asyncMiddleware, // Exporting asyncMiddleware for use in Express middleware chain + cacheMiddleware, // Exporting cacheMiddleware for use in Express middleware chain + requestMiddleware // Exporting requestMiddleware for use in Express middleware chain +} diff --git a/health-services/project-factory/src/server/utils/middlewares/requestMiddleware.ts b/health-services/project-factory/src/server/utils/middlewares/requestMiddleware.ts new file mode 100644 index 00000000000..a8bfd34a330 --- /dev/null +++ b/health-services/project-factory/src/server/utils/middlewares/requestMiddleware.ts @@ -0,0 +1,46 @@ +import { NextFunction, Request, Response } from "express"; // Importing necessary modules from Express +const { object, string } = require("yup"); // Importing object and string from yup for schema validation +import { errorResponder } from "../genericUtils"; // Importing errorResponder function from genericUtils +import { logger } from "../logger"; + +// Defining the request schema using yup +const requestSchema = object({ + apiId: string().nullable(), // Nullable string field for API ID + action: string().nullable(), // Nullable string field for action + msgId: string().required(), // Required string field for message ID + authToken: string().nullable(), // Nullable string field for authentication token + userInfo: object().nonNullable() // Non-nullable object field for user information +}); + +// Middleware function to validate request payload +const requestMiddleware = (req: Request, res: Response, next: NextFunction) => { + try { + logger.info(`RECEIVED A HTTP REQUEST :: URI :: ${req.url}`); + // Check if the content type is 'application/json' + const contentType = req.headers['content-type']; + if (!contentType || !contentType.split(';').map(part => part.trim()).includes('application/json')) { + // If content type is not 'application/json', throw Unsupported Media Type error + let e: any = new Error("Unsupported Media Type: Content-Type should be 'application/json'"); + e = Object.assign(e, { status: 415, code: "UNSUPPORTED_MEDIA_TYPE" }); + errorResponder(e, req, res, 415) + return; + } + // Check if tenantId is missing in RequestInfo.userInfo + if (!req?.body?.RequestInfo?.userInfo?.tenantId) { + // If tenantId is missing, throw Validation Error + let e: any = new Error("RequestInfo.userInfo.tenantId is missing"); + e = Object.assign(e, { status: 400, code: "VALIDATION_ERROR" }); + errorResponder(e, req, res, 400) + return; + } + // Validate request payload against the defined schema + requestSchema.validateSync(req.body.RequestInfo); + // If validation succeeds, proceed to the next middleware + next(); + } catch (error) { + // If an error occurs during validation process, handle the error using errorResponder function + errorResponder(error, req, res); + } +}; + +export default requestMiddleware; // Exporting the requestMiddleware function for use in Express middleware chain diff --git a/health-services/project-factory/src/server/utils/request.ts b/health-services/project-factory/src/server/utils/request.ts new file mode 100644 index 00000000000..3a41cef1e08 --- /dev/null +++ b/health-services/project-factory/src/server/utils/request.ts @@ -0,0 +1,146 @@ +import { Response } from "express"; // Importing necessary module Response from Express +import { getFormattedStringForDebug, logger } from "./logger"; // Importing logger from logger module +import { cacheResponse, getCachedResponse, throwErrorViaRequest } from "./genericUtils"; // Importing necessary functions from genericUtils module + +var Axios = require("axios").default; // Importing axios library +var get = require("lodash/get"); // Importing get function from lodash library + +// Axios interceptor to handle response errors +Axios.interceptors.response.use( + (res: Response) => { + return res; + }, + (err: any) => { + // If there is no response object in the error, create one with status 400 + if (err && !err.response) { + err.response = { + status: 400, + }; + } + // If there is a response but no data, create an error object with the error message + if (err && err.response && !err.response.data) { + err.response.data = { + Errors: [{ code: err.message }], + }; + } + throw err; // Throw the error + } +); + +// Default header for HTTP requests +export const defaultheader = { + "content-type": "application/json;charset=UTF-8", + accept: "application/json, text/plain, */*", +}; + +// Function to extract service name from URL +const getServiceName = (url = "") => url && url.slice && url.slice(url.lastIndexOf(url.split("/")[3])); + +const cacheEnabled = true; // Variable to indicate whether caching is enabled or not + +/** + * Used to Make API call through axios library + * + * @author jagankumar-egov + * + * @param {string} _url - The URL to make the HTTP request to + * @param {Object} _requestBody - The request body + * @param {Object} _params - The request parameters + * @param {string} _method - The HTTP method (default to post) + * @param {string} responseType - The response type + * @param {Object} headers - The request headers + * @param {any} sendStatusCode - Flag to determine whether to send status code along with response data + * @returns {Promise} - Returns the response data or throws an error + */ +const httpRequest = async ( + _url: string, + _requestBody: any, + _params: any = {}, + _method: string = "post", + responseType: string = "", + headers: any = defaultheader, + sendStatusCode: any = false +): Promise => { + try { + if (headers && headers.cachekey && cacheEnabled) { + const cacheData = getCachedResponse(headers.cachekey); // Get cached response data + if (cacheData) { + return cacheData; // Return cached data if available + } + logger.info( + "NO CACHE FOUND :: REQUEST :: " + + JSON.stringify(headers.cachekey) + ); + } + logger.info( + "INTER-SERVICE :: REQUEST :: " + + getServiceName(_url) + + " CRITERIA :: " + + JSON.stringify(_params) + ); + logger.debug("INTER-SERVICE :: REQUESTBODY :: " + getFormattedStringForDebug(_requestBody)) + // Make HTTP request using Axios + const response = await Axios({ + method: _method, + url: _url, + data: _requestBody, + params: _params, + headers: { ...defaultheader, ...headers }, + responseType, + }); + + const responseStatus = parseInt(get(response, "status"), 10); // Get response status + logger.info( + "INTER-SERVICE :: SUCCESS :: " + + getServiceName(_url) + + ":: CODE :: " + + responseStatus + ); + logger.debug("INTER-SERVICE :: RESPONSEBODY :: " +getFormattedStringForDebug(response.data)); + + // If response status is successful, cache the response data if caching is enabled + if (responseStatus === 200 || responseStatus === 201 || responseStatus === 202) { + if (headers && headers.cachekey) { + cacheResponse(response.data, headers.cachekey) + } + // Return response data with status code if sendStatusCode flag is false + if (!sendStatusCode) + return response.data; + else return { ...response.data, "statusCode": responseStatus } + } + } catch (error: any) { + var errorResponse = error?.response; // Get error response + // Log error details + logger.error( + "INTER-SERVICE :: FAILURE :: " + + getServiceName(_url) + + ":: CODE :: " + + errorResponse?.status + + ":: ERROR :: " + + errorResponse?.data?.Errors?.[0]?.code || error + + ":: DESCRIPTION :: " + + errorResponse?.data?.Errors?.[0]?.description + ); + logger.error("error occured while making request to " + + getServiceName(_url) + + ": error response :" + + (errorResponse ? parseInt(errorResponse?.status, 10) : error?.message)) + logger.error(":: ERROR STACK :: " + error?.stack || error); + // Throw error response via request if error response contains errors + if (errorResponse?.data?.Errors?.[0]) { + errorResponse.data.Errors[0].status = errorResponse?.data?.Errors?.[0]?.status || errorResponse?.status + throwErrorViaRequest(errorResponse?.data?.Errors?.[0]); + } + else { + // Throw error message via request + throwErrorViaRequest( + "error occured while making request to " + + getServiceName(_url) + + ": error response :" + + (errorResponse ? parseInt(errorResponse?.status, 10) : error?.message) + ); + } + } +}; + +export { httpRequest }; // Exporting the httpRequest function for use in other modules \ No newline at end of file diff --git a/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts b/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts new file mode 100644 index 00000000000..a2528ce515d --- /dev/null +++ b/health-services/project-factory/src/server/utils/transforms/localisationMessageConstructor.ts @@ -0,0 +1,46 @@ +import { + getLocaleFromRequest, + getLocalisationModuleName, +} from "../localisationUtils"; +import Localisation from "../../controllers/localisationController/localisation.controller"; +import { logger } from "../logger"; + +/** + * Transforms boundary map into localisation messages and creates localisation entries. + * @param boundaryMap - Map of boundary keys and codes. + * @param hierarchyType - Type of hierarchy for the localisation module. + * @param request - Request object containing necessary information. + */ +export const transformAndCreateLocalisation = ( + boundaryMap: any, + request: any +) => { + const { tenantId, hierarchyType } = request?.body?.ResourceDetails || {}; + + // Get localisation module name based on hierarchy type + const module = getLocalisationModuleName(hierarchyType); + + // Get locale from request object + const locale = getLocaleFromRequest(request); + + // Array to store localisation messages + const localisationMessages: any = []; + + // Iterate over boundary map to transform into localisation messagess + boundaryMap.forEach((code: string, boundary: any) => { // Add transformed message to localisation messages array + localisationMessages.push({ + code, + message: boundary.value, + module, + locale, + }); + + }) + + logger.info("localisation message transformed successfully from the boundary map") + // Instantiate localisation controller + const localisation = Localisation.getInstance(); + + // Call method to create localisation entries + localisation.createLocalisation(localisationMessages, tenantId,request); + }; diff --git a/health-services/project-factory/src/server/utils/transforms/projectTypeUtils.ts b/health-services/project-factory/src/server/utils/transforms/projectTypeUtils.ts new file mode 100644 index 00000000000..2853f252418 --- /dev/null +++ b/health-services/project-factory/src/server/utils/transforms/projectTypeUtils.ts @@ -0,0 +1,290 @@ +import { getFormattedStringForDebug, logger } from "../logger"; + +const MAX_AGE=100; +const MAX_AGE_IN_MONTHS=MAX_AGE*12; +/* +TODO: Update configObject with appropriate values. +This object contains configuration settings for delivery strategies and wait times. +*/ +const configObject: any = { + deliveryStrategy: { + default: "DIRECT", + other: "INDIRECT", + }, + mandatoryWaitSinceLastCycleInDays: { + default: null, + other: "30", + }, + mandatoryWaitSinceLastDeliveryInDays: { + default: null, + other: null, + }, +}; + +/* TODO: Update the logic to fetch the projecttype master */ +const defaultProjectType: any = { + /* + Define default project types with their respective properties. + Each project type represents a specific type of campaign. + */ + "MR-DN": { + id: "b1107f0c-7a91-4c76-afc2-a279d8a7b76a", + name: "configuration for Multi Round Campaigns", + code: "MR-DN", + group: "MALARIA", + beneficiaryType: "INDIVIDUAL", + resources: [], + observationStrategy: "DOT1", + validMinAge: 3, + validMaxAge: 60, + cycles: [], + }, + "LLIN-mz": { + id: "192a20d1-0edd-4108-925a-f37bf544d6c4", + name: "Project type configuration for IRS - Nampula Campaigns", + code: "LLIN-mz", + group: "IRS - Nampula", + beneficiaryType: "HOUSEHOLD", + eligibilityCriteria: ["All households are eligible."], + dashboardUrls: { + NATIONAL_SUPERVISOR: + "/digit-ui/employee/dss/landing/national-health-dashboard", + PROVINCIAL_SUPERVISOR: + "/digit-ui/employee/dss/dashboard/provincial-health-dashboard", + DISTRICT_SUPERVISOR: + "/digit-ui/employee/dss/dashboard/district-health-dashboard", + }, + taskProcedure: [ + "1 DDT is to be distributed per house.", + "1 Malathion is to be distributed per house.", + "1 Pyrethroid is to be distributed per house.", + ], + resources: [], + }, +}; + +/* +Map delivery rules to cycles based on delivery and cycle numbers. +*/ +const deliveryRulesToCyles = (delivery = []) => { + return delivery.reduce((acc: any, curr: any) => { + const deliveryNumber = curr.deliveryNumber; + if (!acc?.[curr?.cycleNumber]) { + const deliveryObj = { [deliveryNumber]: [{ ...curr }] }; + acc[curr.cycleNumber] = { + startDate: curr.startDate, + endDate: curr.endDate, + delivery: deliveryObj, + }; + } else { + const deliveryObj = { ...acc?.[curr?.cycleNumber]?.delivery }; + + if (acc?.[curr?.cycleNumber]?.delivery?.[deliveryNumber]) { + deliveryObj[deliveryNumber] = [ + ...deliveryObj?.[deliveryNumber], + { ...curr }, + ]; + } else { + deliveryObj[deliveryNumber] = [{ ...curr }]; + } + acc[curr.cycleNumber].delivery = { ...deliveryObj }; + } + return { ...acc }; + }, {}); +}; +/* +Convert delivery rules to a format suitable for processing. +*/ +const deliveriesConv = (deliveryObj: any = {}) => { + return Object.keys(deliveryObj).map((key, ind) => { + return { + id: key, + deliveryStrategy: + configObject.deliveryStrategy?.[ind == 0 ? "default" : "other"], + + mandatoryWaitSinceLastDeliveryInDays: + configObject.mandatoryWaitSinceLastDeliveryInDays?.["default"], + doseCriteria: deliveryObj?.[key]?.map((e: any) => { + return { + ProductVariants: deliveryObj?.[key].flatMap( + (elem: { products: any }) => + [...elem.products].map((ele, index) => ({ + isBaseUnitVariant: index == 0, + productVariantId: ele?.value, + quantity: ele?.count, + })) + ), + // cylce conditions hardcoded TODO update logic + condition: getRequiredCondition(e?.conditions), + }; + }), + }; + }); +}; +/* +Transform cycle conditions and delivery rules into a standardized format. +*/ +const transformDeliveryConditions = (cyclesObj: any = {}) => { + return Object.keys(cyclesObj).map((cycleKey, ind) => { + var tempObj = cyclesObj[cycleKey]; + + return { + endDate: tempObj?.endDate, + id: cycleKey, + mandatoryWaitSinceLastCycleInDays: + configObject.mandatoryWaitSinceLastCycleInDays?.[ + ind == 0 ? "default" : "other" + ], + startDate: tempObj?.startDate, + deliveries: deliveriesConv(tempObj?.delivery), + }; + }); +}; +/* +Convert campaign details to project details enriched with campaign information. +*/ +export const projectTypeConversion = ( + projectType: any = {}, + campaignObject: any = {} +) => { + const deliveryRules = campaignObject.deliveryRules; + const resources = deliveryRules.flatMap((e: { products: any }) => + [...e.products].map((ele, ind) => ({ + isBaseUnitVariant: ind == 0, + productVariantId: ele.value, + })) + ); + const minAndMaxAge = getMinAndMaxAge(); + var newProjectType = { + ...projectType, + validMinAge: minAndMaxAge?.min, + validMaxAge: minAndMaxAge?.max, + name: campaignObject.campaignName, + resources, + }; + /*Handled the logics for the SMC Project Type */ + if (projectType.code == "MR-DN") { + const cyclesObj = deliveryRulesToCyles(deliveryRules); + const cycles = transformDeliveryConditions(cyclesObj); + newProjectType["cycles"] = cycles; + } + logger.debug("transformed projectType : " + getFormattedStringForDebug(newProjectType)); + return newProjectType; +}; +/* +Enrich project details from campaign details. +*/ +export const enrichProjectDetailsFromCampaignDetails = ( + CampaignDetails: any = {}, + projectTypeObject: any = {} +) => { + var { tenantId, projectType, startDate, endDate, campaignName } = + CampaignDetails; + logger.info("projectTypeResponse" + JSON.stringify(projectTypeObject)); + const defaultProject = + defaultProjectType?.[projectType] || defaultProjectType?.["MR-DN"]; + return [ + { + tenantId, + projectType, + startDate, + endDate, + projectSubType: projectType, + department: defaultProject?.group, + description: defaultProject?.name, + projectTypeId: defaultProject?.id, + name: campaignName, + additionalDetails: { + projectType: projectTypeConversion(defaultProject, CampaignDetails), + }, + }, + ]; +}; + +// Function to get the key based on condition and attribute +const getConditionsKey = (condition: any, key: string) => { + // Get all keys of the condition object + const keys = Object.keys(condition); + + // Check if the key is present in the condition object + if (keys.filter((e) => e == key).length > 0) { + return `${ + key.includes("LESS_THAN") ? "<" + condition[key] : condition[key] + "<" + }`; + } else if (keys.filter((e) => e.includes(key)).length > 0) { + return `${ + key.includes("LESS_THAN") ? "<=" + condition[key] : condition[key] + "<=" + }`; + } else if (keys.includes("EQUAL_TO")) { + return `${condition[key]}=`; + } else { + return `${key.includes("LESS_THAN") ? `>${MAX_AGE_IN_MONTHS}` : "0<"}`; + } +}; + +// Function to get the condition based on attribute +const getCondition = (condition: any = {}, attribute: string) => { + if (attribute == "gender") { + return `${attribute}==${condition?.["EQUAL_TO"]=="MALE"?0:1}`; + } + // Call getConditionsKey function to get the condition for LESS_THAN and GREATER_THAN + return `${getConditionsKey( + condition, + "GREATER_THAN" + )}${attribute}and${attribute}${getConditionsKey(condition, "LESS_THAN")}`; +}; + +// Function to get the required condition +const getRequiredCondition = (conditions: any = []) => { + // Format the conditions into an object with attribute keys + const formattedCondition = conditions.reduce((acc: any, curr: any) => { + if (acc[curr.attribute.toLowerCase()]) { + acc[curr.attribute.toLowerCase()] = { + [curr.operator]: curr.value, + ...acc[curr.attribute.toLowerCase()], + }; + } else { + acc[curr.attribute?.toLowerCase()] = { + [curr.operator]: curr.value, + }; + } + return { ...acc }; + }, {}); + + // Sort keys of formattedCondition and get the first one + const sortedKeys = Object.keys(formattedCondition).slice().sort(); + // update the below logic to support multiple conditions currently hardcoded for age or 1 st condition + return getCondition(formattedCondition[sortedKeys[0]], sortedKeys[0]); +}; + +/* construct max and min age */ +const getMinAndMaxAge = (deliveries = []) => { + // Flatten the conditions arrays from all delivery objects and filter to keep only 'Age' attributes + const ageConditions = deliveries + .flatMap((e: any) => e?.conditions) + .filter((obj) => obj?.attribute == "Age"); + + // If no age conditions are found, return the default range + if (ageConditions.length === 0) { + return { min: 0, max: MAX_AGE_IN_MONTHS }; + } + + // Initialize min and max values + let min = Infinity; + let max = -Infinity; + + // Iterate through the ageConditions to find the actual min and max values + for (const condition of ageConditions) { + const value = condition?.value; + if (value !== undefined) { + if (value < min) min = value; + if (value > max) max = value; + } + } + + // Return the min and max values, with default fallbacks if no valid ages were found + return { + min: min !== Infinity ? min : 0, + max: max !== -Infinity ? max : MAX_AGE_IN_MONTHS, + }; +}; diff --git a/health-services/project-factory/src/server/utils/transforms/searchResponseConstructor.ts b/health-services/project-factory/src/server/utils/transforms/searchResponseConstructor.ts new file mode 100644 index 00000000000..3990dd1b2ea --- /dev/null +++ b/health-services/project-factory/src/server/utils/transforms/searchResponseConstructor.ts @@ -0,0 +1,92 @@ +/** + * Transforms generic resource data fetched from the database into a standardized format. + * + * @param {any[]} dbRows - The array of database rows to transform. + * @returns {Object[]} - An array of transformed resource objects. + */ +export const genericResourceTransformer = (dbRows: any[] = []) => { + return dbRows?.map((row: any) => ({ + id: row?.id, + tenantId: row?.tenantid, + status: row?.status, + action: row?.action, + fileStoreId: row?.filestoreid, + processedFilestoreId: row?.processedfilestoreid, + campaignId: row?.campaignid, + type: row?.type, + auditDetails: { + createdBy: row?.createdby, + lastModifiedBy: row?.lastmodifiedby, + createdTime: Number(row?.createdtime), + lastModifiedTime: row?.lastmodifiedtime + ? Number(row?.lastmodifiedtime) + : null, + }, + additionalDetails: row?.additionaldetails, + })); +}; + +/** + * Transforms campaign details fetched from the database into a standardized format. + * + * @param {any[]} dbRows - The array of database rows to transform. + * @returns {Object[]} - An array of transformed campaign detail objects. + */ +export const campaignDetailsTransformer = (dbRows: any[] = []) => { + return dbRows.map((row: any) => ({ + id: row?.id, + tenantId: row?.tenantid, + status: row?.status, + action: row?.action, + campaignNumber: row?.campaignnumber, + campaignName: row?.campaignname, + projectType: row?.projecttype, + hierarchyType: row?.hierarchytype, + boundaryCode: row?.boundarycode, + projectId: row?.projectid, + startDate: Number(row?.startdate), + endDate: Number(row?.enddate), + createdBy: row?.createdby, + lastModifiedBy: row?.lastmodifiedby, + createdTime: Number(row?.createdtime), + lastModifiedTime: row?.lastmodifiedtime + ? Number(row?.lastmodifiedtime) + : null, + campaignDetails: row?.campaigndetails, + additionalDetails: row?.additionaldetails, + })); +}; + +/** + * Transforms generated resource data fetched from the database into a standardized format. + * + * @param {any[]} dbRows - The array of database rows to transform. + * @returns {Object[]} - An array of transformed resource objects. + */ +export const generatedResourceTransformer = (dbRows: any[] = []) => { + return dbRows.map((item: any) => { + // Extract and structure audit details + item.auditDetails = { + lastModifiedTime: item.lastmodifiedtime, + createdTime: item.createdtime, + lastModifiedBy: item.lastmodifiedby, + createdBy: item.createdby, + }; + + // Rename and restructure properties + item.tenantId = item.tenantid; + item.additionalDetails = item.additionaldetails; + item.fileStoreid = item.filestoreid; + + // Remove unnecessary properties + delete item.additionaldetails; + delete item.lastmodifiedtime; + delete item.createdtime; + delete item.lastmodifiedby; + delete item.createdby; + delete item.filestoreid; + delete item.tenantid; + + return { ...item }; // Return the transformed object + }); +}; diff --git a/health-services/project-factory/src/server/validators/campaignValidators.ts b/health-services/project-factory/src/server/validators/campaignValidators.ts new file mode 100644 index 00000000000..584d1490059 --- /dev/null +++ b/health-services/project-factory/src/server/validators/campaignValidators.ts @@ -0,0 +1,1096 @@ +import createAndSearch from "../config/createAndSearch"; +import config from "../config"; +import { getFormattedStringForDebug, logger } from "../utils/logger"; +import { httpRequest } from "../utils/request"; +import { getHeadersOfBoundarySheet, getHierarchy, handleResouceDetailsError } from "../api/campaignApis"; +import { campaignDetailsSchema } from "../config/models/campaignDetails"; +import Ajv from "ajv"; +import { calculateKeyIndex, getDifferentDistrictTabs, getLocalizedHeaders, getLocalizedMessagesHandler, modifyTargetData, replicateRequest, throwError } from "../utils/genericUtils"; +import { createBoundaryMap, generateProcessedFileAndPersist, getLocalizedName, getTargetBoundariesRelatedToCampaignId } from "../utils/campaignUtils"; +import { validateBodyViaSchema, validateCampaignBodyViaSchema, validateHierarchyType } from "./genericValidator"; +import { searchCriteriaSchema } from "../config/models/SearchCriteria"; +import { searchCampaignDetailsSchema } from "../config/models/searchCampaignDetails"; +import { campaignDetailsDraftSchema } from "../config/models/campaignDetailsDraftSchema"; +import { downloadRequestSchema } from "../config/models/downloadRequestSchema"; +import { createRequestSchema } from "../config/models/createRequestSchema" +import { getSheetData, getTargetWorkbook } from "../api/genericApis"; +const _ = require('lodash'); +import * as XLSX from 'xlsx'; +import { searchDataService } from "../service/dataManageService"; +import { searchProjectTypeCampaignService } from "../service/campaignManageService"; +import { campaignStatuses, resourceDataStatuses } from "../config/constants"; +import { getBoundaryColumnName, getBoundaryTabName } from "../utils/boundaryUtils"; + + + + + +function processBoundary(responseBoundaries: any[], request: any, boundaryItems: any[], parentId?: string) { + const { tenantId, hierarchyType } = request.body.ResourceDetails; + boundaryItems.forEach((boundaryItem: any) => { + const { id, code, boundaryType, children } = boundaryItem; + responseBoundaries.push({ tenantId, hierarchyType, parentId, id, code, boundaryType }); + if (children.length > 0) { + processBoundary(responseBoundaries, request, children, id); + } + }); +} +async function fetchBoundariesInChunks(request: any) { + const { tenantId, hierarchyType } = request.body.ResourceDetails; + const boundaryEntitySearchParams: any = { + tenantId, hierarchyType, includeChildren: true + }; + const responseBoundaries: any[] = []; + var response = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, request.body, boundaryEntitySearchParams); + const TenantBoundary = response.TenantBoundary; + TenantBoundary.forEach((tenantBoundary: any) => { + const { boundary } = tenantBoundary; + processBoundary(responseBoundaries, request, boundary); + }); + return responseBoundaries; +} + +function processBoundaryfromCampaignDetails(responseBoundaries: any[], request: any, boundaryItems: any[]) { + boundaryItems.forEach((boundaryItem: any) => { + const { code, boundaryType, children } = boundaryItem; + responseBoundaries.push({ code, boundaryType }); + if (children.length > 0) { + processBoundaryfromCampaignDetails(responseBoundaries, request, children); + } + }); +} + +async function fetchBoundariesFromCampaignDetails(request: any) { + const { tenantId, hierarchyType } = request.body.CampaignDetails; + const boundaryEntitySearchParams: any = { + tenantId, hierarchyType, includeChildren: true + }; + const responseBoundaries: any[] = []; + var response = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, request.body, boundaryEntitySearchParams); + const TenantBoundary = response.TenantBoundary; + TenantBoundary.forEach((tenantBoundary: any) => { + const { boundary } = tenantBoundary; + processBoundaryfromCampaignDetails(responseBoundaries, request, boundary); + }); + return responseBoundaries; +} + +// Compares unique boundaries with response boundaries and throws error for missing codes. +function compareBoundariesWithUnique(uniqueBoundaries: any[], responseBoundaries: any[], request: any) { + // Extracts boundary codes from response boundaries + const responseBoundaryCodes = responseBoundaries.map(boundary => boundary.code.trim()); + + // Finds missing codes from unique boundaries + const missingCodes = uniqueBoundaries.filter(code => !responseBoundaryCodes.includes(code)); + + // Throws error if missing codes exist + if (missingCodes.length > 0) { + throwError( + "COMMON", + 400, + "VALIDATION_ERROR", + `Boundary codes ${missingCodes.join(', ')} do not exist in hierarchyType ${request?.body?.ResourceDetails?.hierarchyType}` + ); + } +} + +// Validates unique boundaries against the response boundaries. +async function validateUniqueBoundaries(uniqueBoundaries: any[], request: any) { + // Fetches response boundaries in chunks + const responseBoundaries = await fetchBoundariesInChunks(request); + + // Compares unique boundaries with response boundaries + compareBoundariesWithUnique(uniqueBoundaries, responseBoundaries, request); +} + + + + +async function validateBoundaryData(data: any[], request: any, boundaryColumn: any) { + const boundarySet = new Set(); // Create a Set to store unique boundaries + + data.forEach((element, index) => { + const boundaries = element[boundaryColumn]; + if (!boundaries) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary Code is required for element in rowNumber ${element['!row#number!'] + 1}`); + } + + const boundaryList = boundaries.split(",").map((boundary: any) => boundary.trim()); + if (boundaryList.length === 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", `At least 1 boundary is required for element in rowNumber ${element['!row#number!'] + 1}`); + } + + for (const boundary of boundaryList) { + if (!boundary) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary format is invalid in rowNumber ${element['!row#number!'] + 1}. Put it with one comma between boundary codes`); + } + boundarySet.add(boundary); // Add boundary to the set + } + }); + const uniqueBoundaries = Array.from(boundarySet); + await validateUniqueBoundaries(uniqueBoundaries, request); +} + +async function validateTargetBoundaryData(data: any[], request: any, boundaryColumn: any, errors: any[], localizationMap?: any) { + // const responseBoundaries = await fetchBoundariesInChunks(request); + const responseBoundaries = await getTargetBoundariesRelatedToCampaignId(request, localizationMap); + const responseBoundaryCodes = responseBoundaries.map((boundary: any) => boundary.code); + // Iterate through each array of objects + for (const key in data) { + const isNotBoundaryOrReadMeTab = key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap); + if (isNotBoundaryOrReadMeTab) { + if (Array.isArray(data[key])) { + const boundaryData = data[key]; + const boundarySet = new Set(); // Create a Set to store unique boundaries for given sheet + boundaryData.forEach((element: any, index: number) => { + const boundaries = element?.[boundaryColumn]; // Access "Boundary Code" property directly + if (!boundaries) { + errors.push({ status: "INVALID", rowNumber: element["!row#number!"], errorDetails: `Boundary Code is required for element at row ${element["!row#number!"] + 1} for sheet ${key}`, sheetName: key }) + } else { + if (typeof boundaries !== 'string') { + errors.push({ status: "INVALID", rowNumber: element["!row#number!"], errorDetails: `Boundary Code is not of type string at row ${element["!row#number!"] + 1} in boundary sheet ${key}`, sheetName: key }); + } else { + const boundaryList = boundaries.split(",").map((boundary: any) => boundary.trim()); + if (boundaryList.length === 0 || boundaryList.includes('')) { + errors.push({ status: "INVALID", rowNumber: element["!row#number!"], errorDetails: `No boundary code found for row ${element["!row#number!"] + 1} in boundary sheet ${key}`, sheetName: key }) + } + if (boundaryList.length > 1) { + errors.push({ status: "INVALID", rowNumber: element["!row#number!"], errorDetails: `More than one Boundary Code found at row ${element["!row#number!"] + 1} of sheet ${key}`, sheetName: key }) + } + if (boundaryList.length === 1) { + const boundaryCode = boundaryList[0]; + if (boundarySet.has(boundaryCode)) { + errors.push({ status: "INVALID", rowNumber: element["!row#number!"], errorDetails: `Duplicacy of boundary Code at row ${element["!row#number!"] + 1} of sheet ${key}`, sheetName: key }) + } + if (!responseBoundaryCodes.includes(boundaryCode)) { + errors.push({ status: "INVALID", rowNumber: element["!row#number!"], errorDetails: `Boundary Code at row ${element["!row#number!"] + 1} of sheet ${key} is not present in the selected boundaries`, sheetName: key }) + } + boundarySet.add(boundaryCode); + } + } + } + }); + } + } + } +} + + + +async function validateTargetsAtLowestLevelPresentOrNot(data: any[], request: any, errors: any[], localizationMap?: any) { + const hierarchy = await getHierarchy(request, request?.body?.ResourceDetails?.tenantId, request?.body?.ResourceDetails?.hierarchyType); + const modifiedHierarchy = hierarchy.map(ele => `${request?.body?.ResourceDetails?.hierarchyType}_${ele}`.toUpperCase()) + const localizedHierarchy = getLocalizedHeaders(modifiedHierarchy, localizationMap); + const dataToBeValidated = modifyTargetData(data); + let maxKeyIndex = -1; + dataToBeValidated.forEach(obj => { + const keyIndex = calculateKeyIndex(obj, localizedHierarchy, localizationMap); + if (keyIndex > maxKeyIndex) { + maxKeyIndex = keyIndex; + } + }) + const lowestLevelHierarchy = localizedHierarchy[maxKeyIndex]; + validateTargets(data, lowestLevelHierarchy, errors, localizationMap); +} +// +function validateTargets(data: any[], lowestLevelHierarchy: any, errors: any[], localizationMap?: any) { + for (const key in data) { + if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap)) { + if (Array.isArray(data[key])) { + const boundaryData = data[key]; + boundaryData.forEach((obj: any, index: number) => { + if (obj.hasOwnProperty(lowestLevelHierarchy) && obj[lowestLevelHierarchy]) { + const localizedTargetColumnName = getLocalizedName("ADMIN_CONSOLE_TARGET", localizationMap); + const target = obj[localizedTargetColumnName]; + if (target === undefined) { + errors.push({ + status: "INVALID", + rowNumber: obj["!row#number!"], + errorDetails: `Target value is missing at row ${obj['!row#number!'] + 1} in sheet ${key}. Please provide a numeric integer between 1 and 100000.`, + sheetName: key + }); + } else if (typeof target !== 'number') { + errors.push({ + status: "INVALID", + rowNumber: obj["!row#number!"], + errorDetails: `Target value at row ${obj['!row#number!'] + 1} in sheet ${key} is not a number. Target values must be numeric integers between 1 and 100000.`, + sheetName: key + }); + } else if (target <= 0 || target > 100000) { + errors.push({ + status: "INVALID", + rowNumber: obj["!row#number!"], + errorDetails: `Target value ${target} at row ${obj['!row#number!'] + 1} in sheet ${key} is out of range. Target values must be numeric integers between 1 and 100000.`, + sheetName: key + }); + } else if (!Number.isInteger(target)) { + errors.push({ + status: "INVALID", + rowNumber: obj["!row#number!"], + errorDetails: `Target value ${target} at row ${obj['!row#number!'] + 1} in sheet ${key} is not an integer. Target values must be whole numbers between 1 and 100000.`, + sheetName: key + }); + } + + } + }); + } + } + } +} + +async function validateUnique(schema: any, data: any[], request: any) { + const localizationMap = await getLocalizedMessagesHandler(request, request?.body?.ResourceDetails?.tenantId); + if (schema?.unique) { + const uniqueElements = schema.unique; + const errors = []; + + for (const element of uniqueElements) { + const uniqueMap = new Map(); + + // Iterate over each data object and check uniqueness + for (const item of data) { + const uniqueIdentifierColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName; + const localizedUniqueIdentifierColumnName = await getLocalizedName(uniqueIdentifierColumnName, localizationMap); + const value = item[element]; + const rowNum = item['!row#number!'] + 1; + if (!localizedUniqueIdentifierColumnName || !item[localizedUniqueIdentifierColumnName]) { + // Check if the value is already in the map + if (uniqueMap.has(value)) { + errors.push(`Duplicate value '${value}' found for '${element}' at row number ${rowNum}.`); + } + // Add the value to the map + uniqueMap.set(value, rowNum); + } + } + } + + if (errors.length > 0) { + // Throw an error or return the errors based on your requirement + throwError("FILE", 400, "INVALID_FILE_ERROR", errors.join(" ; ")); + } + } +} + +function validatePhoneNumber(datas: any[]) { + var digitErrorRows = []; + var missingNumberRows = []; + for (const data of datas) { + if (data["Phone Number (Mandatory)"]) { + var phoneNumber = data["Phone Number (Mandatory)"]; + phoneNumber = phoneNumber.toString().replace(/^0+/, ''); + if (phoneNumber.length != 10) { + digitErrorRows.push(data["!row#number!"] + 1); + } + } + else { + missingNumberRows.push(data["!row#number!"] + 1); + } + } + var isError = false; + var errorMessage = ""; + if (digitErrorRows.length > 0) { + isError = true; + errorMessage = "PhoneNumber should be of 10 digit on rows " + digitErrorRows.join(" , "); + } + if (missingNumberRows.length > 0) { + isError = true; + if (errorMessage.length > 0) { + errorMessage += " :: "; + } + errorMessage += "PhoneNumber is missing on rows " + missingNumberRows.join(" , "); + } + if (isError) { + throwError("COMMON", 400, "VALIDATION_ERROR", errorMessage); + } +} + +async function validateViaSchema(data: any, schema: any, request: any, localizationMap?: any) { + if (schema) { + const ajv = new Ajv(); + const validate = ajv.compile(schema); + const validationErrors: any[] = []; + const uniqueIdentifierColumnName = getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName, localizationMap) + if (request?.body?.ResourceDetails?.type == "user") { + validatePhoneNumber(data) + } + if (data?.length > 0) { + data.forEach((item: any) => { + if (!item?.[uniqueIdentifierColumnName]) + if (!validate(item)) { + validationErrors.push({ index: item?.["!row#number!"] + 1, errors: validate.errors }); + } + }); + await validateUnique(schema, data, request) + if (validationErrors.length > 0) { + const errorMessage = validationErrors.map(({ index, errors }) => { + const formattedErrors = errors.map((error: any) => { + let formattedError = `${error.dataPath}: ${error.message}`; + if (error.keyword === 'enum' && error.params && error.params.allowedValues) { + formattedError += `. Allowed values are: ${error.params.allowedValues.join(', ')}`; + } + return formattedError; + }).join(', '); + return `Data at row ${index}: ${formattedErrors}`; + }).join(' , '); + throwError("COMMON", 400, "VALIDATION_ERROR", errorMessage); + } else { + logger.info("All Data rows are valid."); + } + } + else { + throwError("FILE", 400, "INVALID_FILE_ERROR", "Data rows cannot be empty"); + } + } + else { + logger.info("skipping schema validation") + } +} + + + +async function validateSheetData(data: any, request: any, schema: any, boundaryValidation: any, localizationMap?: { [key: string]: string }) { + await validateViaSchema(data, schema, request, localizationMap); + if (boundaryValidation) { + const localisedBoundaryCode = getLocalizedName(boundaryValidation?.column, localizationMap) + await validateBoundaryData(data, request, localisedBoundaryCode); + } +} + +async function validateTargetSheetData(data: any, request: any, boundaryValidation: any, localizationMap?: any) { + try { + const errors: any[] = []; + if (boundaryValidation) { + const localizedBoundaryValidationColumn = getLocalizedName(boundaryValidation?.column, localizationMap) + await validateTargetBoundaryData(data, request, localizedBoundaryValidationColumn, errors, localizationMap); + await validateTargetsAtLowestLevelPresentOrNot(data, request, errors, localizationMap); + } + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; + if (request?.body?.sheetErrorDetails && Array.isArray(request?.body?.sheetErrorDetails) && request?.body?.sheetErrorDetails?.length > 0) { + request.body.ResourceDetails.status = resourceDataStatuses.invalid; + } + await generateProcessedFileAndPersist(request, localizationMap); + } + catch (error) { + await handleResouceDetailsError(request, error); + } +} + +function validateBooleanField(obj: any, fieldName: any, index: any) { + if (!obj.hasOwnProperty(fieldName)) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Object at index ${index} is missing field "${fieldName}".`); + } + + if (typeof obj[fieldName] !== 'boolean') { + throwError("COMMON", 400, "VALIDATION_ERROR", `Object at index ${index} has invalid type for field "${fieldName}". It should be a boolean.`); + } +} + +function validateStringField(obj: any, fieldName: any, index: any) { + if (!obj.hasOwnProperty(fieldName)) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Object at index ${index} is missing field "${fieldName}".`); + } + if (typeof obj[fieldName] !== 'string') { + throwError("COMMON", 400, "VALIDATION_ERROR", `Object at index ${index} has invalid type for field "${fieldName}". It should be a string.`); + } + if (obj[fieldName].length < 1) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Object at index ${index} has empty value for field "${fieldName}".`); + } + if (obj[fieldName].length > 128) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Object at index ${index} has value for field "${fieldName}" that exceeds the maximum length of 128 characters.`); + } +} + +function validateStorageCapacity(obj: any, index: any) { + if (!obj.hasOwnProperty('storageCapacity')) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Object at index ${index} is missing field "storageCapacity".`); + } + if (typeof obj.storageCapacity !== 'number') { + throwError("COMMON", 400, "VALIDATION_ERROR", `Object at index ${index} has invalid type for field "storageCapacity". It should be a number.`); + } +} + + +async function validateCampaignId(request: any) { + const { campaignId, tenantId, type } = request?.body?.ResourceDetails; + if (type == "boundary") { + return; + } + if (!campaignId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignId is missing"); + } + else { + const searchBody = { + CampaignDetails: { + ids: [campaignId], + tenantId: tenantId + } + } + const req: any = replicateRequest(request, searchBody); + const response = await searchProjectTypeCampaignService(req); + if (response?.CampaignDetails?.[0]) { + const campaign = response?.CampaignDetails?.[0] + if (!campaign?.boundaries) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Campaign with given campaignId does not have any boundaries"); + } + if (!Array.isArray(campaign?.boundaries)) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Boundaries of campaign with given campaignId is not an array"); + } + if (campaign?.boundaries?.length === 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Campaign with given campaignId does not have any boundaries"); + } + } + else { + throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND", "Campaign not found while validating campaignId"); + } + } +} + + +async function validateCreateRequest(request: any) { + if (!request?.body?.ResourceDetails || Object.keys(request.body.ResourceDetails).length === 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", "ResourceDetails is missing or empty or null"); + } + else { + // validate create request body + validateBodyViaSchema(createRequestSchema, request.body.ResourceDetails); + await validateCampaignId(request); + await validateHierarchyType(request, request?.body?.ResourceDetails?.hierarchyType, request?.body?.ResourceDetails?.tenantId); + if (request?.body?.ResourceDetails?.tenantId != request?.body?.RequestInfo?.userInfo?.tenantId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is not matching with userInfo"); + } + const fileUrl = await validateFile(request); + const localizationMap = await getLocalizedMessagesHandler(request, request?.body?.ResourceDetails?.tenantId); + if (request.body.ResourceDetails.type == 'boundary') { + await validateBoundarySheetData(request, fileUrl, localizationMap); + } + if (request?.body?.ResourceDetails?.type == 'boundaryWithTarget') { + const targetWorkbook: any = await getTargetWorkbook(fileUrl); + // const mainSheetName = targetWorkbook.SheetNames[1]; + // const sheetData = await getSheetData(fileUrl, mainSheetName, true, undefined, localizationMap); + const hierarchy = await getHierarchy(request, request?.body?.ResourceDetails?.tenantId, request?.body?.ResourceDetails?.hierarchyType); + const modifiedHierarchy = hierarchy.map(ele => `${request?.body?.ResourceDetails?.hierarchyType}_${ele}`.toUpperCase()); + const localizedHierarchy = getLocalizedHeaders(modifiedHierarchy, localizationMap); + const index = localizedHierarchy.indexOf(getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap)); + let expectedHeadersForTargetSheet = index !== -1 ? localizedHierarchy.slice(index) : throwError("COMMON", 400, "VALIDATION_ERROR", `${getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap)} level not present in the hierarchy`); + expectedHeadersForTargetSheet = [...expectedHeadersForTargetSheet, getLocalizedName(config?.boundary?.boundaryCode, localizationMap), getLocalizedName("HCM_ADMIN_CONSOLE_TARGET", localizationMap)] + // validateForRootElementExists(sheetData, hierachy, mainSheetName); + validateTabsWithTargetInTargetSheet(request, targetWorkbook, expectedHeadersForTargetSheet); + } + } +} + +function validateTabsWithTargetInTargetSheet(request: any, targetWorkbook: any, expectedHeadersForTargetSheet: any) { + for (let i = 2; i < targetWorkbook.SheetNames.length; i++) { + const sheetName = targetWorkbook?.SheetNames[i]; + const sheet = targetWorkbook?.Sheets[sheetName]; + // Convert the sheet to JSON to extract headers + let headersToValidate: any = XLSX.utils.sheet_to_json(sheet, { + header: 1, + })[0]; + headersToValidate = headersToValidate.map((header: any) => header.trim()); + if (!_.isEqual(expectedHeadersForTargetSheet, headersToValidate)) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Headers not according to the template in Target sheet ${sheetName}`) + } + } + +} + +async function validateBoundarySheetData(request: any, fileUrl: any, localizationMap?: any) { + const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap); + const headersOfBoundarySheet = await getHeadersOfBoundarySheet(fileUrl, localizedBoundaryTab, false, localizationMap); + const hierarchy = await getHierarchy(request, request?.body?.ResourceDetails?.tenantId, request?.body?.ResourceDetails?.hierarchyType); + const modifiedHierarchy = hierarchy.map(ele => `${request?.body?.ResourceDetails?.hierarchyType}_${ele}`.toUpperCase()) + const localizedHierarchy = getLocalizedHeaders(modifiedHierarchy, localizationMap); + await validateHeaders(localizedHierarchy, headersOfBoundarySheet, request, localizationMap) + const boundaryData = await getSheetData(fileUrl, localizedBoundaryTab, true, undefined, localizationMap); + //validate for whether root boundary level column should not be empty + validateForRootElementExists(boundaryData, localizedHierarchy, localizedBoundaryTab); + // validate for duplicate rows(array of objects) + validateForDupicateRows(boundaryData); +} + +function validateForRootElementExists(boundaryData: any[], hierachy: any[], sheetName: string) { + const root = hierachy[0]; + if (!(boundaryData.filter(e => e[root]).length == boundaryData.length)) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Invalid Boundary Sheet. Root level Boundary not present in every row of Sheet ${sheetName}`) + } +} +function validateForDupicateRows(boundaryData: any[]) { + const uniqueRows = _.uniqWith(boundaryData, (obj1: any, obj2: any) => { + // Exclude '!row#number!' property when comparing objects + const filteredObj1 = _.omit(obj1, ['!row#number!']); + const filteredObj2 = _.omit(obj2, ['!row#number!']); + return _.isEqual(filteredObj1, filteredObj2); + }); + const duplicateBoundaryRows = boundaryData.filter(e => !uniqueRows.includes(e)); + const duplicateRowNumbers = duplicateBoundaryRows.map(obj => obj['!row#number!'] + 1); + const rowNumbersSeparatedWithCommas = duplicateRowNumbers.join(', '); + if (duplicateRowNumbers.length > 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary Sheet has duplicate rows at rowNumber ${rowNumbersSeparatedWithCommas}`); + } +} + +async function validateFile(request: any) { + const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId: request?.body?.ResourceDetails?.tenantId, fileStoreIds: request?.body?.ResourceDetails?.fileStoreId }, "get"); + if (!fileResponse || !fileResponse.fileStoreIds || !fileResponse.fileStoreIds[0] || !fileResponse.fileStoreIds[0].url) { + throwError("FILE", 400, "INVALID_FILE"); + } + else { + return (fileResponse?.fileStoreIds?.[0]?.url); + } +} + +function validateFacilityCreateData(data: any) { + data.forEach((obj: any) => { + const originalIndex = obj.originalIndex; + + // Validate string fields + const stringFields = ['tenantId', 'name', 'usage']; + stringFields.forEach(field => { + validateStringField(obj, field, originalIndex); + }); + + // Validate storageCapacity + validateStorageCapacity(obj, originalIndex); + + // Validate isPermanent + validateBooleanField(obj, 'isPermanent', originalIndex); + }); + +} + +function throwMissingCodesError(missingCodes: any, hierarchyType: any) { + const missingCodesMessage = missingCodes.map((code: any) => + `'${code.code}' for type '${code.type}'` + ).join(', '); + throwError( + "COMMON", + 400, + "VALIDATION_ERROR", + `The following boundary codes (${missingCodesMessage}) do not exist for hierarchy type '${hierarchyType}'.` + ); +} + +async function validateCampaignBoundary(boundaries: any[], hierarchyType: any, tenantId: any, request: any): Promise { + const boundaryCodesToMatch = Array.from(new Set(boundaries.map((boundary: any) => ({ + code: boundary.code.trim(), + type: boundary.type.trim() + })))); + const responseBoundaries = await fetchBoundariesFromCampaignDetails(request); + const responseBoundaryCodes = responseBoundaries.map(boundary => ({ + code: boundary.code.trim(), + type: boundary.boundaryType.trim() + })); + logger.info("received boundary hiearchy response, checking for valid") + + logger.debug("responseBoundaryCodes " + getFormattedStringForDebug(responseBoundaryCodes)) + logger.debug("boundaryCodesToMatch " + getFormattedStringForDebug(boundaryCodesToMatch)) + function isEqual(obj1: any, obj2: any) { + return obj1.code === obj2.code && obj1.type === obj2.type; + } + + // Find missing codes + const missingCodes = boundaryCodesToMatch.filter(codeToMatch => + !responseBoundaryCodes.some(responseCode => isEqual(codeToMatch, responseCode)) + ); + + if (missingCodes.length > 0) { + throwMissingCodesError(missingCodes, hierarchyType) + } +} + +async function validateProjectCampaignBoundaries(boundaries: any[], hierarchyType: any, tenantId: any, request: any): Promise { + if (!request?.body?.CampaignDetails?.projectId) { + if (boundaries) { + if (!Array.isArray(boundaries)) { + throwError("COMMON", 400, "VALIDATION_ERROR", "boundaries should be an array"); + } + let rootBoundaryCount = 0; + for (const boundary of boundaries) { + if (!boundary.code) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Boundary code is required"); + } + if (!boundary.type) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Boundary type is required"); + } + + if (boundary.isRoot) { + rootBoundaryCount++; + } + } + if (rootBoundaryCount !== 1) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Exactly one boundary should have isRoot=true"); + } + await validateCampaignBoundary(boundaries, hierarchyType, tenantId, request); + } + else { + throwError("COMMON", 400, "VALIDATION_ERROR", "Missing boundaries array"); + } + } +} + +async function validateBoundariesForTabs(CampaignDetails: any, resource: any, request: any, localizedTab: any, localizationMap?: any) { + const { boundaries, tenantId } = CampaignDetails; + const boundaryCodes = new Set(boundaries.map((boundary: any) => boundary.code.trim())); + + // Fetch file response + const fileResponse = await httpRequest(config.host.filestore + config.paths.filestore + "/url", {}, { tenantId, fileStoreIds: resource.fileStoreId }, "get"); + const datas = await getSheetData(fileResponse?.fileStoreIds?.[0]?.url, localizedTab, true, undefined, localizationMap); + + const boundaryColumn = getLocalizedName(createAndSearch?.[resource.type]?.boundaryValidation?.column, localizationMap); + + // Initialize resource boundary codes as a set for uniqueness + const resourceBoundaryCodesArray: any[] = []; + datas.forEach((data: any) => { + const codes = data?.[boundaryColumn]?.split(',').map((code: string) => code.trim()) || []; + resourceBoundaryCodesArray.push({ boundaryCodes: codes, rowNumber: data?.['!row#number!'] }) + }); + + // Convert sets to arrays for comparison + const boundaryCodesArray = Array.from(boundaryCodes); + var errors = [] + // Check for missing boundary codes + for (const rowData of resourceBoundaryCodesArray) { + var missingBoundaries = rowData.boundaryCodes.filter((code: any) => !boundaryCodesArray.includes(code)); + if (missingBoundaries.length > 0) { + const errorString = `The following boundary codes are not present in selected boundaries : ${missingBoundaries.join(', ')}` + errors.push({ status: "BOUNDARYMISSING", rowNumber: rowData.rowNumber, errorDetails: errorString }) + } + } + if (errors?.length > 0) { + request.body.ResourceDetails.status = resourceDataStatuses.invalid + } + request.body.sheetErrorDetails = request?.body?.sheetErrorDetails ? [...request?.body?.sheetErrorDetails, ...errors] : errors; +} + +async function validateBoundaryOfResouces(CampaignDetails: any, request: any, localizationMap?: any) { + const resource = request?.body?.ResourceDetails + if (resource?.type == "user" || resource?.type == "facility") { + const localizedTab = getLocalizedName(createAndSearch?.[resource.type]?.parseArrayConfig?.sheetName, localizationMap); + await validateBoundariesForTabs(CampaignDetails, resource, request, localizedTab, localizationMap) + } +} + + +async function validateResources(resources: any, request: any) { + for (const resource of resources) { + if (resource?.resourceId) { + var searchBody = { + RequestInfo: request?.body?.RequestInfo, + SearchCriteria: { + id: [resource?.resourceId], + tenantId: request?.body?.CampaignDetails?.tenantId + } + } + const req: any = replicateRequest(request, searchBody); + const res: any = await searchDataService(req); + if (res?.[0]) { + if (!(res?.[0]?.status == resourceDataStatuses.completed && res?.[0]?.action == "validate")) { + logger.error(`Error during validation of type ${resource.type}, validation is not successful or not completed. Resource id : ${resource?.resourceId}`); + throwError("COMMON", 400, "VALIDATION_ERROR", `Error during validation of type ${resource.type}, validation is not successful or not completed.`); + } + if (res?.[0]?.fileStoreId != resource?.filestoreId) { + logger.error(`fileStoreId doesn't match for resource with Id ${resource?.resourceId}. Expected fileStoreId ${resource?.filestoreId} but received ${res?.[0]?.fileStoreId}`); + throwError("COMMON", 400, "VALIDATION_ERROR", `Uploaded file doesn't match for resource of type ${resource.type}.`) + } + } + else { + logger.error(`No resource data found for resource with Id ${resource?.resourceId}`); + throwError("COMMON", 400, "VALIDATION_ERROR", `No resource data found for validation of resource type ${resource.type}.`); + } + } + } +} + +async function validateProjectCampaignResources(resources: any, request: any) { + const requiredTypes = ["user", "facility", "boundaryWithTarget"]; + const typeCounts: any = { + "user": 0, + "facility": 0, + "boundaryWithTarget": 0 + }; + + const missingTypes: string[] = []; + + if (!resources || !Array.isArray(resources) || resources.length === 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", "resources should be a non-empty array"); + } + + for (const resource of resources) { + const { type } = resource; + if (!type || !requiredTypes.includes(type)) { + throwError( + "COMMON", + 400, + "VALIDATION_ERROR", + `Invalid resource type. Allowed types are: ${requiredTypes.join(', ')}` + ); + } + typeCounts[type]++; + } + + for (const type of requiredTypes) { + if (typeCounts[type] === 0) { + missingTypes.push(type); + } + } + + if (missingTypes.length > 0) { + const missingTypesMessage = `Missing resources of types: ${missingTypes.join(', ')}`; + throwError("COMMON", 400, "VALIDATION_ERROR", missingTypesMessage); + } + + if (request?.body?.CampaignDetails?.action === "create" && request?.body?.CampaignDetails?.resources) { + await validateResources(request.body.CampaignDetails.resources, request); + } +} + + + + +function validateProjectCampaignMissingFields(CampaignDetails: any) { + validateCampaignBodyViaSchema(campaignDetailsSchema, CampaignDetails) + const { startDate, endDate } = CampaignDetails; + if (startDate && endDate && (new Date(endDate).getTime() - new Date(startDate).getTime()) < (24 * 60 * 60 * 1000)) { + throwError("COMMON", 400, "VALIDATION_ERROR", "endDate must be at least one day after startDate"); + } + const today: any = Date.now(); + if (startDate <= today) { + throwError("COMMON", 400, "VALIDATION_ERROR", "startDate cannot be today or past date"); + } +} + +function validateDraftProjectCampaignMissingFields(CampaignDetails: any) { + validateCampaignBodyViaSchema(campaignDetailsDraftSchema, CampaignDetails) + const { startDate, endDate } = CampaignDetails; + if (startDate && endDate && (new Date(endDate).getTime() - new Date(startDate).getTime()) < (24 * 60 * 60 * 1000)) { + throwError("COMMON", 400, "VALIDATION_ERROR", "endDate must be at least one day after startDate"); + } + const today: any = Date.now(); + if (startDate <= today) { + throwError("COMMON", 400, "VALIDATION_ERROR", "startDate cannot be today or past date"); + } +} + +async function validateCampaignName(request: any, actionInUrl: any) { + const CampaignDetails = request.body.CampaignDetails; + const { campaignName, tenantId } = CampaignDetails; + if (!campaignName) { + throwError("COMMON", 400, "VALIDATION_ERROR", "campaignName is required"); + } + if (!tenantId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is required"); + } + if (campaignName.length >= 2) { + const searchBody = { + RequestInfo: request.body.RequestInfo, + CampaignDetails: { + tenantId: tenantId, + campaignName: campaignName + } + } + const req: any = replicateRequest(request, searchBody) + const searchResponse: any = await searchProjectTypeCampaignService(req) + if (Array.isArray(searchResponse?.CampaignDetails)) { + if (searchResponse?.CampaignDetails?.length > 0) { + const allCampaigns = searchResponse?.CampaignDetails; + logger.info(`campaignName to match : ${"'"}${campaignName}${"'"}`) + const campaignWithMatchingName: any = allCampaigns.find((campaign: any) => "'" + campaign?.campaignName + "'" == "'" + campaignName + "'") || null; + if (campaignWithMatchingName && actionInUrl == "create") { + throwError("CAMPAIGN", 400, "CAMPAIGN_NAME_ERROR"); + } + else if (campaignWithMatchingName && actionInUrl == "update" && campaignWithMatchingName?.id != CampaignDetails?.id) { + throwError("CAMPAIGN", 400, "CAMPAIGN_NAME_ERROR"); + } + } + } + else { + throwError("CAMPAIGN", 500, "CAMPAIGN_SEARCH_ERROR"); + } + } +} + +async function validateById(request: any) { + const { id, tenantId } = request?.body?.CampaignDetails + if (!id) { + throwError("COMMON", 400, "VALIDATION_ERROR", "id is required"); + } + const searchBody = { + RequestInfo: request.body.RequestInfo, + CampaignDetails: { + tenantId: tenantId, + ids: [id] + } + } + const req: any = replicateRequest(request, searchBody) + const searchResponse: any = await searchProjectTypeCampaignService(req) + if (Array.isArray(searchResponse?.CampaignDetails)) { + if (searchResponse?.CampaignDetails?.length > 0) { + logger.info("CampaignDetails : " + JSON.stringify(searchResponse?.CampaignDetails)); + request.body.ExistingCampaignDetails = searchResponse?.CampaignDetails[0]; + if (request.body.ExistingCampaignDetails?.campaignName != request?.body?.CampaignDetails?.campaignName && request.body.ExistingCampaignDetails?.status != campaignStatuses?.drafted) { + throwError("CAMPAIGN", 400, "CAMPAIGNNAME_MISMATCH", `CampaignName can only be updated in ${campaignStatuses?.drafted} state. CampaignName mismatch, Provided CampaignName = ${request?.body?.CampaignDetails?.campaignName} but Existing CampaignName = ${request.body.ExistingCampaignDetails?.campaignName}`); + } + } + else { + throwError("CAMPAIGN", 400, "CAMPAIGN_NOT_FOUND"); + } + } + else { + throwError("CAMPAIGN", 500, "CAMPAIGN_SEARCH_ERROR"); + } +} + +async function validateProjectType(request: any, projectType: any, tenantId: any) { + if (!projectType) { + throwError("COMMON", 400, "VALIDATION_ERROR", "projectType is required"); + } + else { + const searchBody = { + RequestInfo: request.body.RequestInfo, + "MdmsCriteria": { + "tenantId": tenantId, + "moduleDetails": [ + { + "moduleName": "HCM-PROJECT-TYPES", + "masterDetails": [ + { + "name": "projectTypes", + "filter": "*.code" + } + ] + } + ] + } + } + const params = { tenantId: tenantId } + const searchResponse: any = await httpRequest(config.host.mdms + "egov-mdms-service/v1/_search", searchBody, params); + if (searchResponse?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes && Array.isArray(searchResponse?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes)) { + const projectTypes = searchResponse?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes; + if (!projectTypes.includes(projectType)) { + throwError("COMMON", 400, "VALIDATION_ERROR", "projectType is not valid"); + } + } + else { + throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", "Error occured during projectType search"); + } + } +} + + + + +async function validateProjectCampaignRequest(request: any, actionInUrl: any) { + const CampaignDetails = request.body.CampaignDetails; + const { id, hierarchyType, action, tenantId, boundaries, resources, projectType } = CampaignDetails; + if (actionInUrl == "update") { + if (!id) { + throwError("COMMON", 400, "VALIDATION_ERROR", "id is required for update"); + } + } + if (!CampaignDetails) { + throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignDetails is required"); + } + if (!action) { + throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignDetails.action is required and must be either 'create' or 'draft'") + } + if (!(action == "create" || action == "draft")) { + throwError("COMMON", 400, "VALIDATION_ERROR", "action can only be create or draft"); + } + if (action == "create") { + validateProjectCampaignMissingFields(CampaignDetails); + await validateCampaignName(request, actionInUrl); + if (tenantId != request?.body?.RequestInfo?.userInfo?.tenantId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId is not matching with userInfo"); + } + await validateHierarchyType(request, hierarchyType, tenantId); + await validateProjectType(request, projectType, tenantId); + await validateProjectCampaignBoundaries(boundaries, hierarchyType, tenantId, request); + await validateProjectCampaignResources(resources, request); + } + else { + validateDraftProjectCampaignMissingFields(CampaignDetails); + await validateCampaignName(request, actionInUrl); + await validateHierarchyType(request, hierarchyType, tenantId); + await validateProjectType(request, projectType, tenantId); + } + if (actionInUrl == "update") { + await validateById(request); + } +} + +async function validateSearchProjectCampaignRequest(request: any) { + const CampaignDetails = request.body.CampaignDetails; + if (!CampaignDetails) { + throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignDetails is required"); + } + validateBodyViaSchema(searchCampaignDetailsSchema, CampaignDetails); + let count = 0; + let validFields = ["ids", "startDate", "endDate", "projectType", "campaignName", "status", "createdBy", "campaignNumber"]; + for (const key in CampaignDetails) { + if (key !== 'tenantId') { + if (validFields.includes(key)) { + count++; + } + } + } + if (count === 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", "At least one more field other than tenantID is required"); + } +} + +async function validateSearchRequest(request: any) { + const { SearchCriteria } = request.body; + if (!SearchCriteria) { + throwError("COMMON", 400, "VALIDATION_ERROR", "SearchCriteria is required"); + } + validateBodyViaSchema(searchCriteriaSchema, SearchCriteria); +} + + +async function validateFilters(request: any, boundaryData: any[]) { + // boundaries should be present under filters object + if (!request?.body?.Filters?.boundaries) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Invalid Filter Criteria: 'boundaries' should be present under filters "); + } + const boundaries = request?.body?.Filters?.boundaries; + // boundaries should be an array and not empty + if (!Array.isArray(boundaries) || boundaries?.length == 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Invalid Filter Criteria: 'boundaries' should be an array and should not be empty."); + } + + const boundaryMap = new Map(); + // map boundary code and type + createBoundaryMap(boundaryData, boundaryMap); + const hierarchy = await getHierarchy(request, request?.query?.tenantId, request?.query?.hierarchyType); + // validation of filters object + validateBoundariesOfFilters(boundaries, boundaryMap, hierarchy); + + const rootBoundaries = boundaries.filter((boundary: any) => boundary.isRoot); + + if (rootBoundaries.length !== 1) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Invalid Filter Criteria: Exactly one root boundary can be there, but found "${rootBoundaries.length}`); + } + + const boundaryTypeOfRoot = rootBoundaries[0]?.boundaryType; + + const boundariesOfTypeOfSameAsRoot = boundaries.filter((boundary: any) => boundary.boundaryType === boundaryTypeOfRoot); + + if (boundariesOfTypeOfSameAsRoot.length > 1) { + throwError("COMMON", 400, "VALIDATION_ERROR", `"Invalid Filter Criteria: Multiple boundaries of the same type as the root found. Only one is allowed.`); + } +} + +function validateBoundariesOfFilters(boundaries: any[], boundaryMap: Map, hierarchy: any) { + for (const boundary of boundaries) { + if (!boundary.code) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Boundary Code is null or empty or undefined in Filters of Request Body"); + } + if (!boundary.boundaryType) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Boundary Type is null or empty or undefined in Filters of Request Body"); + } + if (typeof boundary.isRoot !== 'boolean') { + throwError("COMMON", 400, "VALIDATION_ERROR", `isRoot can only be true or false. It is invalid for '${boundary.code}'`); + } + if (typeof boundary.includeAllChildren !== 'boolean') { + throwError("COMMON", 400, "VALIDATION_ERROR", `includeAllChildren can only be true or false. It is invalid for '${boundary.code}'`); + } + if (!boundaryMap.has(boundary?.code)) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary data with code '${boundary.code}' specified in 'Filters' of the request body was not found for the given hierarchy.`); + } + if (!hierarchy.includes(boundary?.boundaryType)) { + throwError("COMMON", 400, "VALIDATION_ERROR", `${boundary.boundaryType} boundary Type not found for given hierachy`); + } + if (boundaryMap.get(boundary.code) !== boundary.boundaryType) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary type mismatch for code '${boundary.code}' specified in 'Filters' of the request body. Expected type: ${boundaryMap.get(boundary.code)}, but found a different type.`); + } + } +} + + + + +async function validateHeaders(hierarchy: any[], headersOfBoundarySheet: any, request: any, localizationMap?: any) { + validateBoundarySheetHeaders(headersOfBoundarySheet, hierarchy, request, localizationMap); +} +function validateBoundarySheetHeaders(headersOfBoundarySheet: any[], hierarchy: any[], request: any, localizationMap?: any) { + const localizedBoundaryCode = getLocalizedName(getBoundaryColumnName(), localizationMap) + const boundaryCodeIndex = headersOfBoundarySheet.indexOf(localizedBoundaryCode); + const keysBeforeBoundaryCode = boundaryCodeIndex === -1 ? headersOfBoundarySheet : headersOfBoundarySheet.slice(0, boundaryCodeIndex); + if (keysBeforeBoundaryCode.some((key: any, index: any) => (key === undefined || key === null) || key !== hierarchy[index]) || keysBeforeBoundaryCode.length !== hierarchy.length) { + const errorMessage = `"Boundary Sheet Headers are not the same as the hierarchy present for the given tenant and hierarchy type: ${request?.body?.ResourceDetails?.hierarchyType}"`; + throwError("BOUNDARY", 400, "BOUNDARY_SHEET_HEADER_ERROR", errorMessage); + } +} + + +async function validateDownloadRequest(request: any) { + const { tenantId, hierarchyType } = request.query; + validateBodyViaSchema(downloadRequestSchema, request.query); + if (tenantId != request?.body?.RequestInfo?.userInfo?.tenantId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId in userInfo and query should be the same"); + } + await validateHierarchyType(request, hierarchyType, tenantId); +} + +function immediateValidationForTargetSheet(dataFromSheet: any, localizationMap: any) { + validateAllDistrictTabsPresentOrNot(dataFromSheet, localizationMap); + for (const key in dataFromSheet) { + if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap)) { + if (Object.prototype.hasOwnProperty.call(dataFromSheet, key)) { + const dataArray = (dataFromSheet as { [key: string]: any[] })[key]; + if (dataArray.length === 0) { + throwError("COMMON", 400, "VALIDATION_ERROR", `The Target Sheet ${key} you have uploaded is empty`) + } + const root = getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap); + for (const boundaryRow of dataArray) { + for (const columns in boundaryRow) { + if (columns.startsWith('__EMPTY')) { + throwError("COMMON", 400, "VALIDATION_ERROR", `Invalid column has some random data in Target Sheet ${key} at row number ${boundaryRow['!row#number!'] + 1}`); + } + } + if (!boundaryRow[root]) { + throwError("COMMON", 400, "VALIDATION_ERROR", ` ${root} column is empty in Target Sheet ${key} at row number ${boundaryRow['!row#number!'] + 1}`); + } + } + } + } + } +} + + +function validateAllDistrictTabsPresentOrNot(dataFromSheet: any, localizationMap?: any) { + let tabsIndex = 2; + const tabsOfDistrict = getDifferentDistrictTabs(dataFromSheet[getLocalizedName(config?.boundary?.boundaryTab, localizationMap)], getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap)); + const tabsFromTargetSheet = Object.keys(dataFromSheet); + for (let tab of tabsOfDistrict) { + if (tabsIndex >= tabsFromTargetSheet.length) { + throwError("COMMON", 400, "VALIDATION_ERROR", `District tab ${tab} not present in the Target Sheet Uploaded`); + } + if (tabsFromTargetSheet[tabsIndex] === tab) { + tabsIndex++; + } + else { + throwError("COMMON", 400, "VALIDATION_ERROR", `District tab ${tab} not present in the Target Sheet Uploaded`) + } + } +} + + +export { + fetchBoundariesInChunks, + validateSheetData, + validateCreateRequest, + validateFacilityCreateData, + validateProjectCampaignRequest, + validateSearchProjectCampaignRequest, + validateSearchRequest, + validateFilters, + validateHierarchyType, + validateBoundarySheetData, + validateDownloadRequest, + validateTargetSheetData, + immediateValidationForTargetSheet, + validateBoundaryOfResouces +} diff --git a/health-services/project-factory/src/server/validators/genericValidator.ts b/health-services/project-factory/src/server/validators/genericValidator.ts new file mode 100644 index 00000000000..940f446c625 --- /dev/null +++ b/health-services/project-factory/src/server/validators/genericValidator.ts @@ -0,0 +1,353 @@ +// Importing necessary modules +import * as express from "express"; +import { logger } from "../utils/logger"; +import Ajv from "ajv"; +import config from "../config/index"; +import { httpRequest } from "../utils/request"; +import { getBoundaryRelationshipData, throwError } from "../utils/genericUtils"; +import { validateFilters } from "./campaignValidators"; +import { generateRequestSchema } from "../config/models/generateRequestSchema"; + +// Function to validate data against a JSON schema +function validateDataWithSchema(data: any, schema: any): { isValid: boolean; error: Ajv.ErrorObject[] | null | undefined } { + const ajv = new Ajv(); + const validate = ajv.compile(schema); + const isValid: any = validate(data); + if (!isValid) { + logger.error(JSON.stringify(validate.errors)); + } + return { isValid, error: validate.errors }; +} +function validateCampaignBodyViaSchema(schema: any, objectData: any) { + const ajv = new Ajv(); + const validate = ajv.compile(schema); + const isValid = validate(objectData); + if (!isValid) { + const formattedError = validate?.errors?.map((error: any) => { + let formattedErrorMessage = ""; + if (error?.dataPath) { + // Replace slash with dot and remove leading dot if present + const dataPath = error.dataPath.replace(/\//g, '.').replace(/^\./, ''); + formattedErrorMessage = `${dataPath} ${error.message}`; + } + else { + formattedErrorMessage = `${error.message}` + } + if (error.keyword === 'enum' && error.params && error.params.allowedValues) { + formattedErrorMessage += `. Allowed values are: ${error.params.allowedValues.join(', ')}`; + } + if (error.keyword === 'additionalProperties' && error.params && error.params.additionalProperty) { + formattedErrorMessage += `, Additional property '${error.params.additionalProperty}' found.`; + } + // Capitalize the first letter of the error message + formattedErrorMessage = formattedErrorMessage.charAt(0).toUpperCase() + formattedErrorMessage.slice(1); + return formattedErrorMessage; + }).join("; "); + console.error(formattedError); + throwError("COMMON", 400, "VALIDATION_ERROR", formattedError); + } +} + +function validateBodyViaSchema(schema: any, objectData: any) { + const properties: any = { jsonPointers: true, allowUnknownAttributes: true } + const ajv = new Ajv(properties); + const validate = ajv.compile(schema); + const isValid = validate(objectData); + if (!isValid) { + const formattedError = validate?.errors?.map((error: any) => { + let formattedErrorMessage = ""; + if (error?.dataPath) { + // Replace slash with dot and remove leading dot if present + const dataPath = error.dataPath.replace(/\//g, '.').replace(/^\./, ''); + formattedErrorMessage = `${dataPath} ${error.message}`; + } + else { + formattedErrorMessage = `${error.message}` + } + if (error.keyword === 'enum' && error.params && error.params.allowedValues) { + formattedErrorMessage += `. Allowed values are: ${error.params.allowedValues.join(', ')}`; + } + if (error.keyword === 'additionalProperties' && error.params && error.params.additionalProperty) { + formattedErrorMessage += `, Additional property '${error.params.additionalProperty}' found.`; + } + // Capitalize the first letter of the error message + formattedErrorMessage = formattedErrorMessage.charAt(0).toUpperCase() + formattedErrorMessage.slice(1); + return formattedErrorMessage; + }).join("; "); + console.error(formattedError); + throwError("COMMON", 400, "VALIDATION_ERROR", formattedError); + } +} + + + + + + +// Function to validate boundaries in the request body +// function validateBoundaries(requestBody: any) { +// const { boundaryCode } = requestBody?.Campaign; +// if (!boundaryCode) { +// throwError("COMMON", 400, "VALIDATION_ERROR", "Enter BoundaryCode In Campaign"); +// } +// for (const campaignDetails of requestBody?.Campaign?.CampaignDetails) { +// const { boundaryCode: campaignBoundaryCode, parentBoundaryCode } = campaignDetails; +// if (!parentBoundaryCode && boundaryCode != campaignBoundaryCode) { +// throwError("COMMON", 400, "VALIDATION_ERROR", "Enter ParentBoundaryCode In CampaignDetails"); +// } +// if (!campaignBoundaryCode) { +// throwError("COMMON", 400, "VALIDATION_ERROR", "Enter BoundaryCode In CampaignDetails"); +// } +// } +// } + +// Function to validate the user ID +// async function validateUserId(resourceId: any, requestBody: any) { +// // Constructing the search body for user validation +// const userSearchBody = { +// RequestInfo: requestBody?.RequestInfo, +// tenantId: requestBody?.Campaign?.tenantId.split('.')?.[0], +// uuid: [resourceId] +// } + +// // Logging user search URL and request body +// logger.info("User search url : " + config.host.userHost + config.paths.userSearch); +// logger.info("userSearchBody : " + JSON.stringify(userSearchBody)); + +// // Performing the HTTP request to validate the user ID +// const response = await httpRequest(config.host.userHost + config.paths.userSearch, userSearchBody); + +// // Handling response errors if user ID is invalid +// if (!response?.user?.[0]?.uuid) { +// throwError("COMMON", 400, "VALIDATION_ERROR", "Invalid resourceId for resource type staff with id " + resourceId); +// } +// } + +// Function to validate the product variant ID +// async function validateProductVariantId(resourceId: any, requestBody: any) { +// // Constructing the search body for product variant validation +// const productVariantSearchBody = { +// RequestInfo: requestBody?.RequestInfo, +// ProductVariant: { id: [resourceId] } +// } +// const productVariantSearchParams = { +// limit: 10, +// offset: 0, +// tenantId: requestBody?.Campaign?.tenantId.split('.')?.[0] +// } + +// // Logging product variant search URL and request body +// logger.info("ProductVariant search url : " + config.host.productHost + config.paths.productVariantSearch); +// logger.info("productVariantSearchBody : " + JSON.stringify(productVariantSearchBody)); +// logger.info("productVariantSearchParams : " + JSON.stringify(productVariantSearchParams)); + +// // Performing the HTTP request to validate the product variant ID +// const response = await httpRequest(config.host.productHost + config.paths.productVariantSearch, productVariantSearchBody, productVariantSearchParams); + +// // Handling response errors if product variant ID is invalid +// if (!response?.ProductVariant?.[0]?.id) { +// throwError("COMMON", 400, "VALIDATION_ERROR", "Invalid resourceId for resource type resource with id " + resourceId); +// } +// } + +// Function to validate the project facility ID +// async function validateProjectFacilityId(resourceId: any, requestBody: any) { +// // Constructing the search body for project facility validation +// const facilitySearchBody = { +// RequestInfo: requestBody?.RequestInfo, +// Facility: { +// id: [resourceId] +// } +// } +// const facilitySearchParams = { +// limit: 10, +// offset: 0, +// tenantId: requestBody?.Campaign?.tenantId?.split('.')?.[0] +// } + +// // Logging facility search URL and request body +// logger.info("Facility search url : " + config.host.facilityHost + config.paths.facilitySearch); +// logger.info("facilitySearchBody : " + JSON.stringify(facilitySearchBody)); +// logger.info("facilitySearchParams : " + JSON.stringify(facilitySearchParams)); + +// // Performing the HTTP request to validate the project facility ID +// const response = await httpRequest(config.host.facilityHost + config.paths.facilitySearch, facilitySearchBody, facilitySearchParams); + +// // Handling response errors if project facility ID is invalid +// if (!response?.Facilities?.[0]?.id) { +// throwError("COMMON", 400, "VALIDATION_ERROR", "Invalid resourceId for resource type facility with id " + resourceId); +// } +// } + +// Function to validate the resource ID based on its type +// async function validateResourceId(type: any, resourceId: any, requestBody: any) { +// // Dispatching validation based on resource type +// // if (type == "staff") { +// // await validateUserId(resourceId, requestBody) +// // } +// // else if (type == "resource") { +// // await validateProductVariantId(resourceId, requestBody) +// // } +// // else if (type == "facility") { +// // await validateProjectFacilityId(resourceId, requestBody) +// // } +// // else { +// // throwError("COMMON", 400, "VALIDATION_ERROR", "Invalid resource type " + type); +// // } +// } +// Function to validate the resources associated with a campaign +async function validateProjectResource(requestBody: any) { + for (const campaignDetails of requestBody?.Campaign?.CampaignDetails) { + for (const resource of campaignDetails?.resources) { + const type = resource?.type; + for (const resourceId of resource?.resourceIds) { + // Check if resource type and ID are provided + if (!type) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Enter Type In Resources"); + } + if (!resourceId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Enter ResourceId In Resources"); + } + // Validate the resource ID based on its type + // await validateResourceId(type, resourceId, requestBody); + } + } + } +} + +// Function to validate the campaign details including resource validation +async function validateCampaign(requestBody: any) { + const id = requestBody?.Campaign?.id + if (!id) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Enter id of campaign for mapping"); + } + for (const campaignDetails of requestBody?.Campaign?.CampaignDetails) { + var { startDate, endDate } = campaignDetails; + startDate = parseInt(startDate); + endDate = parseInt(endDate); + + // Check if startDate and endDate are valid integers + // if (isNaN(startDate) || isNaN(endDate)) { + // throwError("COMMON", 400, "VALIDATION_ERROR", "Start date or end date is not a valid epoch timestamp"); + // } + } + await validateProjectResource(requestBody) +} + +// Function to validate the entire campaign request +async function validateCampaignRequest(requestBody: any) { + if (requestBody?.Campaign) { + if (!requestBody?.Campaign?.tenantId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Enter TenantId"); + } + // validateBoundaries(requestBody); + // const { projectType } = requestBody?.Campaign; + // if (!projectType) { + // throwError("COMMON", 400, "VALIDATION_ERROR", "Enter ProjectType"); + // } + await validateCampaign(requestBody); + } + else { + throwError("COMMON", 400, "VALIDATION_ERROR", "Campaign is required"); + } +} + +// Function to validate and update project response and its ID +function validatedProjectResponseAndUpdateId(projectResponse: any, projectBody: any, campaignDetails: any) { + if (projectBody?.Projects?.length != projectResponse?.Project?.length) { + throwError("PROJECT", 500, "PROJECT_CREATION_ERROR"); + } else { + for (const project of projectResponse?.Project) { + if (!project?.id) { + throwError("PROJECT", 500, "PROJECT_CREATION_ERROR"); + } else { + campaignDetails.projectId = project.id; + } + } + } +} + +// Function to validate project staff response +function validateStaffResponse(staffResponse: any) { + if (!staffResponse?.ProjectStaff?.id) { + throwError("CAMPAIGN", 500, "RESOURCE_CREATION_ERROR", "Project staff creation failed."); + } +} + +// Function to validate project resource response +function validateProjectResourceResponse(projectResouceResponse: any) { + if (!projectResouceResponse?.ProjectResource?.id) { + throwError("CAMPAIGN", 500, "RESOURCE_CREATION_ERROR", "Project Resource creation failed."); + } +} + +// Function to validate project facility response +function validateProjectFacilityResponse(projectFacilityResponse: any) { + if (!projectFacilityResponse?.ProjectFacility?.id) { + throwError("CAMPAIGN", 500, "RESOURCE_CREATION_ERROR", "Project Facility creation failed."); + } +} + +// Function to validate the hierarchy type +async function validateHierarchyType(request: any, hierarchyType: any, tenantId: any) { + const searchBody = { + RequestInfo: request?.body?.RequestInfo, + BoundaryTypeHierarchySearchCriteria: { + "tenantId": tenantId, + "limit": 5, + "offset": 0, + "hierarchyType": hierarchyType + } + } + const response = await httpRequest(config.host.boundaryHost + config.paths.boundaryHierarchy, searchBody); + if (response?.BoundaryHierarchy && Array.isArray(response?.BoundaryHierarchy) && response?.BoundaryHierarchy?.length > 0) { + logger.info(`hierarchyType : ${hierarchyType} :: got validated`); + } + else { + throwError(`CAMPAIGN`, 400, "VALIDATION_ERROR", `hierarchyType ${hierarchyType} not found`); + } +} + +// Function to validate the generation request +async function validateGenerateRequest(request: express.Request) { + const { tenantId, hierarchyType, forceUpdate } = request.query; + validateBodyViaSchema(generateRequestSchema, request.query); + if (tenantId != request?.body?.RequestInfo?.userInfo?.tenantId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "tenantId in userInfo and query should be the same"); + } + if (!forceUpdate) { + request.query.forceUpdate = "false"; + } + await validateHierarchyType(request, hierarchyType, tenantId); + /* removed the filter validation for boundary since boundary is fetched through the campaign id */ + // if (type == 'boundary') { + // await validateFiltersInRequestBody(request); + // } +} + +export async function validateFiltersInRequestBody(request: any) { + if (request?.body?.Filters === undefined) { + throwError("COMMON", 400, "VALIDATION_ERROR", "For type boundary Filters Object should be present in request body") + } + const params = { + ...request?.query, + includeChildren: true + }; + const boundaryData = await getBoundaryRelationshipData(request, params); + if (boundaryData && request?.body?.Filters != null) { + await validateFilters(request, boundaryData); + } +} + +export { + validateDataWithSchema, + validateBodyViaSchema, + validateCampaignRequest, + validatedProjectResponseAndUpdateId, + validateStaffResponse, + validateProjectFacilityResponse, + validateProjectResourceResponse, + validateGenerateRequest, + validateHierarchyType, + validateCampaignBodyViaSchema +}; \ No newline at end of file diff --git a/health-services/project-factory/src/tsconfig.json b/health-services/project-factory/src/tsconfig.json new file mode 100644 index 00000000000..6e8f96dc26c --- /dev/null +++ b/health-services/project-factory/src/tsconfig.json @@ -0,0 +1,66 @@ +{ + "compilerOptions": { + "skipLibCheck": true, + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./dist/", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + "strictNullChecks": true, /* Enable strict null checks. */ + "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + /* Additional Checks */ + "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + /* Module Resolution Options */ + "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + "typeRoots": ["node_modules/@types"], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + /* Source Map Options */ + // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + }, + "include": [ + "./**/*" + ], + "exclude": [ + "node_modules", + "**/*.test.ts" + ] +} \ No newline at end of file diff --git a/health-services/project-factory/tsconfig.json b/health-services/project-factory/tsconfig.json new file mode 100644 index 00000000000..5afabc37a6b --- /dev/null +++ b/health-services/project-factory/tsconfig.json @@ -0,0 +1,66 @@ +{ + "compilerOptions": { + "skipLibCheck": true, + /* Basic Options */ + // "incremental": true, /* Enable incremental compilation */ + "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ + "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */ + // "lib": [], /* Specify library files to be included in the compilation. */ + // "allowJs": true, /* Allow javascript files to be compiled. */ + // "checkJs": true, /* Report errors in .js files. */ + // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ + // "declaration": true, /* Generates corresponding '.d.ts' file. */ + // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ + // "sourceMap": true, /* Generates corresponding '.map' file. */ + // "outFile": "./", /* Concatenate and emit output to single file. */ + "outDir": "./dist/", /* Redirect output structure to the directory. */ + // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ + // "composite": true, /* Enable project compilation */ + // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ + // "removeComments": true, /* Do not emit comments to output. */ + // "noEmit": true, /* Do not emit outputs. */ + // "importHelpers": true, /* Import emit helpers from 'tslib'. */ + // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ + // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ + /* Strict Type-Checking Options */ + "strict": true, /* Enable all strict type-checking options. */ + "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ + "strictNullChecks": true, /* Enable strict null checks. */ + "strictFunctionTypes": true, /* Enable strict checking of function types. */ + // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ + // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ + // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ + "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ + /* Additional Checks */ + "noUnusedLocals": true, /* Report errors on unused locals. */ + // "noUnusedParameters": true, /* Report errors on unused parameters. */ + "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ + // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ + /* Module Resolution Options */ + "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ + "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ + // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ + // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ + "typeRoots": ["./node_modules/@types"], /* List of folders to include type definitions from. */ + // "types": [], /* Type declaration files to be included in compilation. */ + // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ + "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ + // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + /* Source Map Options */ + // "sourceRoot": "./", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ + // "mapRoot": "./", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ + // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ + /* Experimental Options */ + // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ + // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ + }, + "include": [ + "./src/**/*" + ], + "exclude": [ + "node_modules", + "**/*.test.ts" + ] +} \ No newline at end of file diff --git a/health-services/project-factory/yarn.lock b/health-services/project-factory/yarn.lock new file mode 100644 index 00000000000..f82b142e1d4 --- /dev/null +++ b/health-services/project-factory/yarn.lock @@ -0,0 +1,5138 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + +"@ampproject/remapping@^2.2.0": + version "2.3.0" + resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@7.12.11": + version "7.12.11" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz" + integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== + dependencies: + "@babel/highlight" "^7.10.4" + +"@babel/code-frame@^7.12.13": + version "7.24.2" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz" + integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== + dependencies: + "@babel/highlight" "^7.24.2" + picocolors "^1.0.0" + +"@babel/code-frame@^7.23.5": + version "7.24.2" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz" + integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== + dependencies: + "@babel/highlight" "^7.24.2" + picocolors "^1.0.0" + +"@babel/code-frame@^7.24.1": + version "7.24.2" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz" + integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== + dependencies: + "@babel/highlight" "^7.24.2" + picocolors "^1.0.0" + +"@babel/code-frame@^7.24.2": + version "7.24.2" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz" + integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== + dependencies: + "@babel/highlight" "^7.24.2" + picocolors "^1.0.0" + +"@babel/compat-data@^7.23.5": + version "7.24.4" + +"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9", "@babel/core@^7.8.0": + version "7.24.4" + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.24.2" + "@babel/generator" "^7.24.4" + "@babel/helper-compilation-targets" "^7.23.6" + "@babel/helper-module-transforms" "^7.23.3" + "@babel/helpers" "^7.24.4" + "@babel/parser" "^7.24.4" + "@babel/template" "^7.24.0" + "@babel/traverse" "^7.24.1" + "@babel/types" "^7.24.0" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.24.1", "@babel/generator@^7.24.4", "@babel/generator@^7.7.2": + version "7.24.4" + dependencies: + "@babel/types" "^7.24.0" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^2.5.1" + +"@babel/helper-compilation-targets@^7.23.6": + version "7.23.6" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz" + integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== + dependencies: + "@babel/compat-data" "^7.23.5" + "@babel/helper-validator-option" "^7.23.5" + browserslist "^4.22.2" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-environment-visitor@^7.22.20": + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== + +"@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== + dependencies: + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-imports@^7.22.15": + version "7.24.3" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz" + integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg== + dependencies: + "@babel/types" "^7.24.0" + +"@babel/helper-module-transforms@^7.23.3": + version "7.23.3" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz" + integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-module-imports" "^7.22.15" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.20" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.0", "@babel/helper-plugin-utils@^7.8.0": + version "7.24.0" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz" + integrity sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w== + +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-string-parser@^7.23.4": + version "7.24.1" + resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz" + integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== + +"@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== + +"@babel/helper-validator-option@^7.23.5": + version "7.23.5" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz" + integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== + +"@babel/helpers@^7.24.4": + version "7.24.4" + dependencies: + "@babel/template" "^7.24.0" + "@babel/traverse" "^7.24.1" + "@babel/types" "^7.24.0" + +"@babel/highlight@^7.10.4", "@babel/highlight@^7.24.2": + version "7.24.2" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz" + integrity sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0", "@babel/parser@^7.24.1", "@babel/parser@^7.24.4": + version "7.24.4" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.24.1" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz" + integrity sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.24.1" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz" + integrity sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw== + dependencies: + "@babel/helper-plugin-utils" "^7.24.0" + +"@babel/template@^7.22.15", "@babel/template@^7.24.0", "@babel/template@^7.3.3": + version "7.24.0" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz" + integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA== + dependencies: + "@babel/code-frame" "^7.23.5" + "@babel/parser" "^7.24.0" + "@babel/types" "^7.24.0" + +"@babel/traverse@^7.24.1": + version "7.24.1" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz" + integrity sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ== + dependencies: + "@babel/code-frame" "^7.24.1" + "@babel/generator" "^7.24.1" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.24.1" + "@babel/types" "^7.24.0" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.3.3": + version "7.24.0" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz" + integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w== + dependencies: + "@babel/helper-string-parser" "^7.23.4" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@colors/colors@^1.6.0", "@colors/colors@1.6.0": + version "1.6.0" + resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz" + integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@dabh/diagnostics@^2.0.2": + version "2.0.3" + resolved "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz" + integrity sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA== + dependencies: + colorspace "1.1.x" + enabled "2.0.x" + kuler "^2.0.0" + +"@eslint/eslintrc@^0.4.3": + version "0.4.3" + resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz" + integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== + dependencies: + ajv "^6.12.4" + debug "^4.1.1" + espree "^7.3.0" + globals "^13.9.0" + ignore "^4.0.6" + import-fresh "^3.2.1" + js-yaml "^3.13.1" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + +"@humanwhocodes/config-array@^0.5.0": + version "0.5.0" + resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz" + integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== + dependencies: + "@humanwhocodes/object-schema" "^1.2.0" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.0": + version "1.2.1" + resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": + version "0.1.3" + resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== + dependencies: + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== + dependencies: + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== + dependencies: + jest-get-type "^29.6.3" + +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== + dependencies: + expect "^29.7.0" + jest-snapshot "^29.7.0" + +"@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== + dependencies: + "@jest/types" "^29.6.3" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" + +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^6.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== + dependencies: + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== + dependencies: + "@jest/test-result" "^29.7.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + slash "^3.0.0" + +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== + dependencies: + "@jest/schemas" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@npmcli/agent@^2.0.0": + version "2.2.2" + resolved "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz" + integrity sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og== + dependencies: + agent-base "^7.1.0" + http-proxy-agent "^7.0.0" + https-proxy-agent "^7.0.1" + lru-cache "^10.0.1" + socks-proxy-agent "^8.0.3" + +"@npmcli/fs@^3.1.0": + version "3.1.0" + resolved "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz" + integrity sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w== + dependencies: + semver "^7.3.5" + +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + +"@sinonjs/commons@^3.0.0": + version "3.0.1" + resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== + dependencies: + "@sinonjs/commons" "^3.0.0" + +"@tsconfig/node10@^1.0.7": + version "1.0.11" + resolved "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + +"@types/babel__core@^7.1.14": + version "7.20.5" + resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.8" + resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz" + integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.20.5" + resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz" + integrity sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ== + dependencies: + "@babel/types" "^7.20.7" + +"@types/body-parser@*": + version "1.19.5" + resolved "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz" + integrity sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/compression@1.7.5": + version "1.7.5" + resolved "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz" + integrity sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg== + dependencies: + "@types/express" "*" + +"@types/connect@*": + version "3.4.38" + resolved "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz" + integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== + dependencies: + "@types/node" "*" + +"@types/express-serve-static-core@^4.17.33": + version "4.17.43" + resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz" + integrity sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express@*", "@types/express@4.17.21": + version "4.17.21" + resolved "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz" + integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/graceful-fs@^4.1.3": + version "4.1.9" + resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== + dependencies: + "@types/node" "*" + +"@types/hash-sum@^1.0.2": + version "1.0.2" + resolved "https://registry.npmjs.org/@types/hash-sum/-/hash-sum-1.0.2.tgz" + integrity sha512-UP28RddqY8xcU0SCEp9YKutQICXpaAq9N8U2klqF5hegGha7KzTOL8EdhIIV3bOSGBzjEpN9bU/d+nNZBdJYVw== + +"@types/helmet@0.0.47": + version "0.0.47" + resolved "https://registry.npmjs.org/@types/helmet/-/helmet-0.0.47.tgz" + integrity sha512-TcHA/djjdUtrMtq/QAayVLrsgjNNZ1Uhtz0KhfH01mrmjH44E54DA1A0HNbwW0H/NBFqV+tGMo85ACuEhMXcdg== + dependencies: + "@types/express" "*" + +"@types/http-errors@*": + version "2.0.4" + resolved "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz" + integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.6" + resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.4" + resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@29.5.12": + version "29.5.12" + resolved "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz" + integrity sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/mime@^1": + version "1.3.5" + resolved "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz" + integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== + +"@types/morgan@1.9.9": + version "1.9.9" + resolved "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.9.tgz" + integrity sha512-iRYSDKVaC6FkGSpEVVIvrRGw0DfJMiQzIn3qr2G5B3C//AWkulhXgaBd7tS9/J79GWSYMTHGs7PfI5b3Y8m+RQ== + dependencies: + "@types/node" "*" + +"@types/node@*", "@types/node@20.11.29": + version "20.11.29" + resolved "https://registry.npmjs.org/@types/node/-/node-20.11.29.tgz" + integrity sha512-P99thMkD/1YkCvAtOd6/zGedKNA0p2fj4ZpjCzcNiSCBWgm3cNRTBfa/qjFnsKkkojxu4vVLtWpesnZ9+ap+gA== + dependencies: + undici-types "~5.26.4" + +"@types/pg@8.11.3": + version "8.11.3" + resolved "https://registry.npmjs.org/@types/pg/-/pg-8.11.3.tgz" + integrity sha512-xocw4LvpDcj/Ta7bN52tLZm34mso5SZ0Q8fVC0UtD8s85Itip3YHvBeYZhBmC0OThpdOujHsxXtRbEIRxqXPXg== + dependencies: + "@types/node" "*" + pg-protocol "*" + pg-types "^4.0.1" + +"@types/qs@*": + version "6.9.14" + resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.14.tgz" + integrity sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA== + +"@types/range-parser@*": + version "1.2.7" + resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz" + integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== + +"@types/send@*": + version "0.17.4" + resolved "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz" + integrity sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/serve-static@*": + version "1.15.7" + resolved "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz" + integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== + dependencies: + "@types/http-errors" "*" + "@types/node" "*" + "@types/send" "*" + +"@types/stack-utils@^2.0.0": + version "2.0.3" + resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== + +"@types/strip-bom@^3.0.0": + version "3.0.0" + resolved "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz" + integrity sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ== + +"@types/strip-json-comments@0.0.30": + version "0.0.30" + resolved "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz" + integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ== + +"@types/triple-beam@^1.3.2": + version "1.3.5" + resolved "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz" + integrity sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw== + +"@types/uuid@9.0.8": + version "9.0.8" + resolved "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz" + integrity sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA== + +"@types/xlsx@0.0.36": + version "0.0.36" + resolved "https://registry.npmjs.org/@types/xlsx/-/xlsx-0.0.36.tgz" + integrity sha512-mvfrKiKKMErQzLMF8ElYEH21qxWCZtN59pHhWGmWCWFJStYdMWjkDSAy6mGowFxHXaXZWe5/TW7pBUiWclIVOw== + dependencies: + xlsx "*" + +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^17.0.8": + version "17.0.32" + resolved "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz" + integrity sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog== + dependencies: + "@types/yargs-parser" "*" + +abbrev@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz" + integrity sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ== + +accepts@~1.3.5, accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn-jsx@^5.3.1: + version "5.3.2" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^8.1.1: + version "8.3.2" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz" + integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== + +"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^7.4.0: + version "7.4.1" + resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + +acorn@^8.4.1: + version "8.11.3" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== + +adler-32@~1.3.0: + version "1.3.1" + resolved "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz" + integrity sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A== + +agent-base@^7.0.2, agent-base@^7.1.0, agent-base@^7.1.1: + version "7.1.1" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz" + integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== + dependencies: + debug "^4.3.4" + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv@^6.10.0, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.1: + version "8.12.0" + resolved "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +ansi-colors@^4.1.1: + version "4.1.3" + resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" + integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + +anymatch@^3.0.3, anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +are-we-there-yet@~1.1.2: + version "1.1.7" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz" + integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +async@^2.6.2: + version "2.6.4" + resolved "https://registry.npmjs.org/async/-/async-2.6.4.tgz" + integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== + dependencies: + lodash "^4.17.14" + +async@^3.2.3: + version "3.2.5" + resolved "https://registry.npmjs.org/async/-/async-3.2.5.tgz" + integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +axios@1.6.8: + version "1.6.8" + resolved "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz" + integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== + dependencies: + "@jest/transform" "^29.7.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.6.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== + dependencies: + babel-plugin-jest-hoist "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +basic-auth@~2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz" + integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== + dependencies: + safe-buffer "5.1.2" + +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + +binary@~0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz" + integrity sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg== + dependencies: + buffers "~0.1.1" + chainsaw "~0.1.0" + +bindings@^1.3.1: + version "1.5.0" + resolved "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bl@^1.0.0: + version "1.2.3" + resolved "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz" + integrity sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww== + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + +bl@^2.2.0: + version "2.2.1" + resolved "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz" + integrity sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g== + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + +body-parser@1.20.2: + version "1.20.2" + resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz" + integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== + dependencies: + bytes "3.1.2" + content-type "~1.0.5" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.2" + type-is "~1.6.18" + unpipe "1.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browserslist@^4.22.2, "browserslist@>= 4.21.0": + version "4.23.0" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz" + integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== + dependencies: + caniuse-lite "^1.0.30001587" + electron-to-chromium "^1.4.668" + node-releases "^2.0.14" + update-browserslist-db "^1.0.13" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + +buffer-crc32@~0.2.5: + version "0.2.13" + resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz" + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== + +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz" + integrity sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ== + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-writer@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz" + integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== + +buffermaker@~1.2.0: + version "1.2.1" + resolved "https://registry.npmjs.org/buffermaker/-/buffermaker-1.2.1.tgz" + integrity sha512-IdnyU2jDHU65U63JuVQNTHiWjPRH0CS3aYd/WPaEwyX84rFdukhOduAVb1jwUScmb5X0JWPw8NZOrhoLMiyAHQ== + dependencies: + long "1.1.2" + +buffers@~0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz" + integrity sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ== + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz" + integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +cacache@^18.0.0: + version "18.0.2" + resolved "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz" + integrity sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw== + dependencies: + "@npmcli/fs" "^3.1.0" + fs-minipass "^3.0.0" + glob "^10.2.2" + lru-cache "^10.0.1" + minipass "^7.0.3" + minipass-collect "^2.0.1" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + p-map "^4.0.0" + ssri "^10.0.0" + tar "^6.1.11" + unique-filename "^3.0.0" + +call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001587: + version "1.0.30001605" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz" + integrity sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ== + +cfb@^1.1.3, cfb@~1.2.1: + version "1.2.2" + resolved "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz" + integrity sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA== + dependencies: + adler-32 "~1.3.0" + crc-32 "~1.2.0" + +chainsaw@~0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz" + integrity sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ== + dependencies: + traverse ">=0.3.0 <0.4" + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +chokidar@^3.5.1: + version "3.6.0" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chownr@^1.0.1: + version "1.1.4" + resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + +chownr@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz" + integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== + +ci-info@^3.2.0: + version "3.9.0" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + +cjs-module-lexer@^1.0.0: + version "1.2.3" + resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz" + integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +clone@2.x: + version "2.1.2" + resolved "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz" + integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w== + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz" + integrity sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA== + +codepage@~1.15.0: + version "1.15.0" + resolved "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz" + integrity sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA== + +collect-v8-coverage@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz" + integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^1.9.3: + version "1.9.3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@^1.0.0, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-string@^1.6.0: + version "1.9.1" + resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz" + integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.1.3: + version "3.2.1" + resolved "https://registry.npmjs.org/color/-/color-3.2.1.tgz" + integrity sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA== + dependencies: + color-convert "^1.9.3" + color-string "^1.6.0" + +colorspace@1.1.x: + version "1.1.4" + resolved "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz" + integrity sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w== + dependencies: + color "^3.1.3" + text-hex "1.0.x" + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@1.7.4: + version "1.7.4" + resolved "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz" + integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4, content-type@~1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +crc-32@~1.2.0, crc-32@~1.2.1: + version "1.2.2" + resolved "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz" + integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== + +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@^2.1.3, debug@2.6.9: + version "2.6.9" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^4.0.1: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@^4.1.0: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@^4.1.1: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@^4.3.1: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@^4.3.4: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@4: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz" + integrity sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA== + dependencies: + mimic-response "^1.0.0" + +dedent@^1.0.0: + version "1.5.1" + resolved "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz" + integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + +deep-is@^0.1.3, deep-is@~0.1.3: + version "0.1.4" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge@^4.2.2: + version "4.3.1" + resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz" + integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== + +denque@^1.3.0: + version "1.5.1" + resolved "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz" + integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== + +depd@~2.0.0, depd@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz" + integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dynamic-dedupe@^0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz" + integrity sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ== + dependencies: + xtend "^4.0.0" + +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +electron-to-chromium@^1.4.668: + version "1.4.726" + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + +enabled@2.0.x: + version "2.0.0" + resolved "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz" + integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +encoding@^0.1.13: + version "0.1.13" + resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz" + integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== + dependencies: + iconv-lite "^0.6.2" + +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enquirer@^2.3.5: + version "2.4.1" + resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz" + integrity sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ== + dependencies: + ansi-colors "^4.1.1" + strip-ansi "^6.0.1" + +env-paths@^2.2.0: + version "2.2.1" + resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + +err-code@^2.0.2: + version "2.0.3" + resolved "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz" + integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +escalade@^3.1.1: + version "3.1.2" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz" + integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +escodegen@^1.8.1: + version "1.14.3" + resolved "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz" + integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== + dependencies: + esprima "^4.0.1" + estraverse "^4.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz" + integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== + dependencies: + eslint-visitor-keys "^1.1.0" + +eslint-visitor-keys@^1.1.0: + version "1.3.0" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint@^7.16.0: + version "7.32.0" + resolved "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz" + integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== + dependencies: + "@babel/code-frame" "7.12.11" + "@eslint/eslintrc" "^0.4.3" + "@humanwhocodes/config-array" "^0.5.0" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.0.1" + doctrine "^3.0.0" + enquirer "^2.3.5" + escape-string-regexp "^4.0.0" + eslint-scope "^5.1.1" + eslint-utils "^2.1.0" + eslint-visitor-keys "^2.0.0" + espree "^7.3.1" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^5.1.2" + globals "^13.6.0" + ignore "^4.0.6" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^3.13.1" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + progress "^2.0.0" + regexpp "^3.1.0" + semver "^7.2.1" + strip-ansi "^6.0.0" + strip-json-comments "^3.1.0" + table "^6.0.9" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^7.3.0, espree@^7.3.1: + version "7.3.1" + resolved "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz" + integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== + dependencies: + acorn "^7.4.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^1.3.0" + +esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esprima@1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz" + integrity sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A== + +esquery@^1.4.0: + version "1.5.0" + resolved "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1, estraverse@^4.2.0: + version "4.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0: + version "5.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expand-template@^2.0.3: + version "2.0.3" + resolved "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz" + integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== + +expect@^29.0.0, expect@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== + dependencies: + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + +exponential-backoff@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz" + integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw== + +express@4.18.3: + version "4.18.3" + resolved "https://registry.npmjs.org/express/-/express-4.18.3.tgz" + integrity sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.2" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.5.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + +fecha@^4.2.0: + version "4.2.3" + resolved "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz" + integrity sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw== + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.2.0" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + +flatted@^3.2.9: + version "3.3.1" + resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== + +fn.name@1.x.x: + version "1.1.0" + resolved "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz" + integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== + +follow-redirects@^1.15.6: + version "1.15.6" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz" + integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== + +foreground-child@^3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz" + integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +frac@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz" + integrity sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + +fs-minipass@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz" + integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== + dependencies: + minipass "^3.0.0" + +fs-minipass@^3.0.0: + version "3.0.3" + resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz" + integrity sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw== + dependencies: + minipass "^7.0.3" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz" + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz" + integrity sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg== + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +github-from-package@0.0.0: + version "0.0.0" + resolved "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz" + integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^10.2.2: + version "10.3.12" + resolved "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz" + integrity sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.3.6" + minimatch "^9.0.1" + minipass "^7.0.4" + path-scurry "^1.10.2" + +glob@^10.3.10: + version "10.3.12" + resolved "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz" + integrity sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^2.3.6" + minimatch "^9.0.1" + minipass "^7.0.4" + path-scurry "^1.10.2" + +glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^13.6.0, globals@^13.9.0: + version "13.24.0" + resolved "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graceful-fs@^4.2.6, graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + +has-proto@^1.0.1: + version "1.0.3" + resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz" + integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== + +hash-sum@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz" + integrity sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg== + +hasown@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +helmet@7.1.0: + version "7.1.0" + resolved "https://registry.npmjs.org/helmet/-/helmet-7.1.0.tgz" + integrity sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg== + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +http-cache-semantics@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +http-proxy-agent@^7.0.0: + version "7.0.2" + resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz" + integrity sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig== + dependencies: + agent-base "^7.1.0" + debug "^4.3.4" + +https-proxy-agent@^7.0.1: + version "7.0.4" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz" + integrity sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg== + dependencies: + agent-base "^7.0.2" + debug "4" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@^0.6.2: + version "0.6.3" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ignore@^4.0.6: + version "4.0.6" + resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz" + integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== + +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@^2.0.3, inherits@~2.0.3, inherits@2, inherits@2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@~1.3.0: + version "1.3.8" + resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + +ip-address@^9.0.5: + version "9.0.5" + resolved "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz" + integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g== + dependencies: + jsbn "1.1.0" + sprintf-js "^1.1.3" + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-core-module@^2.13.0: + version "2.13.1" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz" + integrity sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw== + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-lambda@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz" + integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isexe@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz" + integrity sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-instrument@^5.0.4: + version "5.2.1" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-instrument@^6.0.0: + version "6.0.2" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz" + integrity sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw== + dependencies: + "@babel/core" "^7.23.9" + "@babel/parser" "^7.23.9" + "@istanbuljs/schema" "^0.1.3" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.7" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz" + integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jackspeak@^2.3.6: + version "2.3.6" + resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz" + integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== + dependencies: + execa "^5.0.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + pretty-format "^29.7.0" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== + dependencies: + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + chalk "^4.0.0" + create-jest "^29.7.0" + exit "^0.1.2" + import-local "^3.0.2" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + yargs "^17.3.1" + +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== + dependencies: + detect-newline "^3.0.0" + +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== + dependencies: + "@jest/types" "^29.6.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== + dependencies: + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== + dependencies: + chalk "^4.0.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-util "^29.7.0" + +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== + +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== + dependencies: + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" + +jest-resolve@*, jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-pnp-resolver "^1.2.2" + jest-util "^29.7.0" + jest-validate "^29.7.0" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== + dependencies: + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.7.0" + graceful-fs "^4.2.9" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + natural-compare "^1.4.0" + pretty-format "^29.7.0" + semver "^7.5.3" + +jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== + dependencies: + "@jest/types" "^29.6.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.6.3" + leven "^3.1.0" + pretty-format "^29.7.0" + +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== + dependencies: + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.7.0" + string-length "^4.0.1" + +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== + dependencies: + "@types/node" "*" + jest-util "^29.7.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== + dependencies: + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" + import-local "^3.0.2" + jest-cli "^29.7.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +jsbn@1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz" + integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +jsonpath@1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/jsonpath/-/jsonpath-1.1.1.tgz" + integrity sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w== + dependencies: + esprima "1.2.2" + static-eval "2.0.2" + underscore "1.12.1" + +jszip@^3.2.2: + version "3.10.1" + resolved "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz" + integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g== + dependencies: + lie "~3.3.0" + pako "~1.0.2" + readable-stream "~2.3.6" + setimmediate "^1.0.5" + +kafka-node@5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/kafka-node/-/kafka-node-5.0.0.tgz" + integrity sha512-dD2ga5gLcQhsq1yNoQdy1MU4x4z7YnXM5bcG9SdQuiNr5KKuAmXixH1Mggwdah5o7EfholFbcNDPSVA6BIfaug== + dependencies: + async "^2.6.2" + binary "~0.3.0" + bl "^2.2.0" + buffer-crc32 "~0.2.5" + buffermaker "~1.2.0" + debug "^2.1.3" + denque "^1.3.0" + lodash "^4.17.4" + minimatch "^3.0.2" + nested-error-stacks "^2.0.0" + optional "^0.1.3" + retry "^0.10.1" + uuid "^3.0.0" + optionalDependencies: + snappy "^6.0.1" + +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +kuler@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz" + integrity sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A== + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" + integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lie@~3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz" + integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ== + dependencies: + immediate "~3.0.5" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz" + integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== + +lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.4, lodash@4.17.21: + version "4.17.21" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +logform@^2.3.2, logform@^2.4.0: + version "2.6.0" + resolved "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz" + integrity sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ== + dependencies: + "@colors/colors" "1.6.0" + "@types/triple-beam" "^1.3.2" + fecha "^4.2.0" + ms "^2.1.1" + safe-stable-stringify "^2.3.1" + triple-beam "^1.3.0" + +long@1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/long/-/long-1.1.2.tgz" + integrity sha512-pjR3OP1X2VVQhCQlrq3s8UxugQsuoucwMOn9Yj/kN/61HMc+lDFJS5bvpNEHneZ9NVaSm8gNWxZvtGS7lqHb3Q== + +lru-cache@^10.0.1: + version "10.2.0" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz" + integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== + +lru-cache@^10.2.0: + version "10.2.0" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz" + integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +make-fetch-happen@^13.0.0: + version "13.0.0" + resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz" + integrity sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A== + dependencies: + "@npmcli/agent" "^2.0.0" + cacache "^18.0.0" + http-cache-semantics "^4.1.1" + is-lambda "^1.0.1" + minipass "^7.0.2" + minipass-fetch "^3.0.0" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + negotiator "^0.6.3" + promise-retry "^2.0.1" + ssri "^10.0.0" + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +"mime-db@>= 1.43.0 < 2", mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-response@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + +minimatch@^3.0.2, minimatch@^3.0.4, minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^9.0.1: + version "9.0.4" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz" + integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.0, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +minipass-collect@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz" + integrity sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw== + dependencies: + minipass "^7.0.3" + +minipass-fetch@^3.0.0: + version "3.0.4" + resolved "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz" + integrity sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg== + dependencies: + minipass "^7.0.3" + minipass-sized "^1.0.3" + minizlib "^2.1.2" + optionalDependencies: + encoding "^0.1.13" + +minipass-flush@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz" + integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== + dependencies: + minipass "^3.0.0" + +minipass-pipeline@^1.2.4: + version "1.2.4" + resolved "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz" + integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== + dependencies: + minipass "^3.0.0" + +minipass-sized@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz" + integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== + dependencies: + minipass "^3.0.0" + +minipass@^3.0.0: + version "3.3.6" + resolved "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz" + integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== + dependencies: + yallist "^4.0.0" + +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3, minipass@^7.0.4: + version "7.0.4" + resolved "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz" + integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== + +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== + +minizlib@^2.1.1, minizlib@^2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz" + integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== + dependencies: + minipass "^3.0.0" + yallist "^4.0.0" + +mkdirp@^0.5.1: + version "0.5.6" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +mkdirp@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +morgan@1.10.0: + version "1.10.0" + resolved "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz" + integrity sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ== + dependencies: + basic-auth "~2.0.1" + debug "2.6.9" + depd "~2.0.0" + on-finished "~2.3.0" + on-headers "~1.0.2" + +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nan@^2.14.1: + version "2.19.0" + resolved "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz" + integrity sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw== + +napi-build-utils@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz" + integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +negotiator@^0.6.3, negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +nested-error-stacks@^2.0.0: + version "2.1.1" + resolved "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz" + integrity sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw== + +node-abi@^2.7.0: + version "2.30.1" + resolved "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz" + integrity sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w== + dependencies: + semver "^5.4.1" + +node-cache@5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz" + integrity sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg== + dependencies: + clone "2.x" + +node-gyp@^10.0.1: + version "10.1.0" + resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-10.1.0.tgz" + integrity sha512-B4J5M1cABxPc5PwfjhbV5hoy2DP9p8lFXASnEN6hugXOa61416tnTZ29x9sSwAd0o99XNIcpvDDy1swAExsVKA== + dependencies: + env-paths "^2.2.0" + exponential-backoff "^3.1.1" + glob "^10.3.10" + graceful-fs "^4.2.6" + make-fetch-happen "^13.0.0" + nopt "^7.0.0" + proc-log "^3.0.0" + semver "^7.3.5" + tar "^6.1.2" + which "^4.0.0" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.14: + version "2.0.14" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz" + integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== + +noop-logger@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz" + integrity sha512-6kM8CLXvuW5crTxsAtva2YLrRrDaiTIkIePWs9moLHqbFWT94WpNFjwS/5dfLfECg5i/lkmw3aoqVidxt23TEQ== + +nopt@^7.0.0: + version "7.2.0" + resolved "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz" + integrity sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA== + dependencies: + abbrev "^2.0.0" + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +npmlog@^4.0.1: + version "4.1.2" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz" + integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== + +object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.13.1: + version "1.13.1" + resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + +obuf@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz" + integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz" + integrity sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww== + dependencies: + ee-first "1.1.1" + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +one-time@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz" + integrity sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g== + dependencies: + fn.name "1.x.x" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +optional@^0.1.3: + version "0.1.4" + resolved "https://registry.npmjs.org/optional/-/optional-0.1.4.tgz" + integrity sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw== + +optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + +optionator@^0.9.1: + version "0.9.3" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + +os-homedir@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz" + integrity sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ== + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +packet-reader@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz" + integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== + +pako@~1.0.2: + version "1.0.11" + resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-scurry@^1.10.2: + version "1.10.2" + resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz" + integrity sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA== + dependencies: + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + +pg-cloudflare@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz" + integrity sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q== + +pg-connection-string@^2.6.2: + version "2.6.4" + resolved "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.4.tgz" + integrity sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA== + +pg-int8@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz" + integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== + +pg-numeric@1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz" + integrity sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw== + +pg-pool@^3.6.1: + version "3.6.2" + resolved "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.2.tgz" + integrity sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg== + +pg-protocol@*, pg-protocol@^1.6.0: + version "1.6.1" + resolved "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.1.tgz" + integrity sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg== + +pg-types@^2.1.0: + version "2.2.0" + resolved "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz" + integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== + dependencies: + pg-int8 "1.0.1" + postgres-array "~2.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.4" + postgres-interval "^1.1.0" + +pg-types@^4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/pg-types/-/pg-types-4.0.2.tgz" + integrity sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng== + dependencies: + pg-int8 "1.0.1" + pg-numeric "1.0.2" + postgres-array "~3.0.1" + postgres-bytea "~3.0.0" + postgres-date "~2.1.0" + postgres-interval "^3.0.0" + postgres-range "^1.1.1" + +pg@>=8.0, pg@8.11.3: + version "8.11.3" + resolved "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz" + integrity sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g== + dependencies: + buffer-writer "2.0.0" + packet-reader "1.0.0" + pg-connection-string "^2.6.2" + pg-pool "^3.6.1" + pg-protocol "^1.6.0" + pg-types "^2.1.0" + pgpass "1.x" + optionalDependencies: + pg-cloudflare "^1.1.1" + +pgpass@1.x: + version "1.0.5" + resolved "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz" + integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug== + dependencies: + split2 "^4.1.0" + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pirates@^4.0.4: + version "4.0.6" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +postgres-array@~2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz" + integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== + +postgres-array@~3.0.1: + version "3.0.2" + resolved "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz" + integrity sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog== + +postgres-bytea@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz" + integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w== + +postgres-bytea@~3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz" + integrity sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw== + dependencies: + obuf "~1.1.2" + +postgres-date@~1.0.4: + version "1.0.7" + resolved "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz" + integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== + +postgres-date@~2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz" + integrity sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA== + +postgres-interval@^1.1.0: + version "1.2.0" + resolved "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz" + integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== + dependencies: + xtend "^4.0.0" + +postgres-interval@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz" + integrity sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw== + +postgres-range@^1.1.1: + version "1.1.4" + resolved "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz" + integrity sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w== + +prebuild-install@5.3.0: + version "5.3.0" + resolved "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.0.tgz" + integrity sha512-aaLVANlj4HgZweKttFNUVNRxDukytuIuxeK2boIMHjagNJCiVKWFsKF4tCE3ql3GbrD2tExPQ7/pwtEJcHNZeg== + dependencies: + detect-libc "^1.0.3" + expand-template "^2.0.3" + github-from-package "0.0.0" + minimist "^1.2.0" + mkdirp "^0.5.1" + napi-build-utils "^1.0.1" + node-abi "^2.7.0" + noop-logger "^0.1.1" + npmlog "^4.0.1" + os-homedir "^1.0.1" + pump "^2.0.1" + rc "^1.2.7" + simple-get "^2.7.0" + tar-fs "^1.13.0" + tunnel-agent "^0.6.0" + which-pm-runs "^1.0.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" + integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== + +pretty-format@^29.0.0, pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +proc-log@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz" + integrity sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +progress@^2.0.0: + version "2.0.3" + resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + +promise-retry@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz" + integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== + dependencies: + err-code "^2.0.2" + retry "^0.12.0" + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +property-expr@^2.0.5: + version "2.0.6" + resolved "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz" + integrity sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA== + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +pump@^1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz" + integrity sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +pure-rand@^6.0.0: + version "6.1.0" + resolved "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz" + integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== + +qs@6.11.0: + version "6.11.0" + resolved "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.2: + version "2.5.2" + resolved "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz" + integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + +readable-stream@^2.0.6, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@~2.3.6: + version "2.3.8" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.4.0: + version "3.6.2" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +regexpp@^3.1.0: + version "3.2.0" + resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve.exports@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz" + integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== + +resolve@^1.0.0, resolve@^1.20.0: + version "1.22.8" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +retry@^0.10.1: + version "0.10.1" + resolved "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz" + integrity sha512-ZXUSQYTHdl3uS7IuCehYfMzKyIDBNoAuUblvy5oGO5UJSUTmStUUVPXbA9Qxd173Bgre53yCQczQuHgRWAdvJQ== + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz" + integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== + +rimraf@^2.6.1: + version "2.7.1" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1, safe-buffer@5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@5.2.1: + version "5.2.1" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-stable-stringify@^2.3.1: + version "2.4.3" + resolved "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz" + integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== + +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sax@^1.2.4: + version "1.3.0" + resolved "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz" + integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA== + +semver@^5.4.1: + version "5.7.2" + resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" + integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== + +semver@^6.3.0: + version "6.3.1" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.2.1, semver@^7.3.5, semver@^7.5.3, semver@^7.5.4: + version "7.6.0" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz" + integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== + dependencies: + lru-cache "^6.0.0" + +send@0.18.0: + version "0.18.0" + resolved "https://registry.npmjs.org/send/-/send-0.18.0.tgz" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" + integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== + +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4: + version "1.0.6" + resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + +signal-exit@^3.0.0, signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + +simple-concat@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz" + integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== + +simple-get@^2.7.0: + version "2.8.2" + resolved "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz" + integrity sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw== + dependencies: + decompress-response "^3.3.0" + once "^1.3.1" + simple-concat "^1.0.0" + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz" + integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg== + dependencies: + is-arrayish "^0.3.1" + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + +snappy@^6.0.1: + version "6.3.5" + resolved "https://registry.npmjs.org/snappy/-/snappy-6.3.5.tgz" + integrity sha512-lonrUtdp1b1uDn1dbwgQbBsb5BbaiLeKq+AGwOk2No+en+VvJThwmtztwulEQsLinRF681pBqib0NUZaizKLIA== + dependencies: + bindings "^1.3.1" + nan "^2.14.1" + prebuild-install "5.3.0" + +socks-proxy-agent@^8.0.3: + version "8.0.3" + resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz" + integrity sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A== + dependencies: + agent-base "^7.1.1" + debug "^4.3.4" + socks "^2.7.1" + +socks@^2.7.1: + version "2.8.1" + resolved "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz" + integrity sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ== + dependencies: + ip-address "^9.0.5" + smart-buffer "^4.2.0" + +source-map-support@^0.5.12, source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +split2@^4.1.0: + version "4.2.0" + resolved "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz" + integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== + +sprintf-js@^1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz" + integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +ssf@~0.11.2: + version "0.11.2" + resolved "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz" + integrity sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g== + dependencies: + frac "~1.1.2" + +ssri@^10.0.0: + version "10.0.5" + resolved "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz" + integrity sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A== + dependencies: + minipass "^7.0.3" + +stack-trace@0.0.x: + version "0.0.10" + resolved "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz" + integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +static-eval@2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz" + integrity sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg== + dependencies: + escodegen "^1.8.1" + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +string_decoder@^1.1.1, string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^1.0.1, "string-width@^1.0.2 || 2 || 3 || 4": + version "1.0.2" + resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz" + integrity sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw== + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^4.1.0: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^3.0.0: + version "3.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" + integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" + integrity sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg== + dependencies: + ansi-regex "^2.0.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" + integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" + integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +table@^6.0.9: + version "6.8.2" + resolved "https://registry.npmjs.org/table/-/table-6.8.2.tgz" + integrity sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA== + dependencies: + ajv "^8.0.1" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + +tar-fs@^1.13.0: + version "1.16.3" + resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz" + integrity sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw== + dependencies: + chownr "^1.0.1" + mkdirp "^0.5.1" + pump "^1.0.0" + tar-stream "^1.1.2" + +tar-stream@^1.1.2: + version "1.6.2" + resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz" + integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== + dependencies: + bl "^1.0.0" + buffer-alloc "^1.2.0" + end-of-stream "^1.0.0" + fs-constants "^1.0.0" + readable-stream "^2.3.0" + to-buffer "^1.1.1" + xtend "^4.0.0" + +tar@^6.1.11, tar@^6.1.2: + version "6.2.1" + resolved "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz" + integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^5.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +text-hex@1.0.x: + version "1.0.0" + resolved "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz" + integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +tiny-case@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz" + integrity sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q== + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-buffer@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz" + integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +toposort@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz" + integrity sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg== + +"traverse@>=0.3.0 <0.4": + version "0.3.9" + resolved "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz" + integrity sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ== + +tree-kill@^1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + +triple-beam@^1.3.0: + version "1.4.1" + resolved "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz" + integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== + +ts-node-dev@2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz" + integrity sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w== + dependencies: + chokidar "^3.5.1" + dynamic-dedupe "^0.3.0" + minimist "^1.2.6" + mkdirp "^1.0.4" + resolve "^1.0.0" + rimraf "^2.6.1" + source-map-support "^0.5.12" + tree-kill "^1.2.2" + ts-node "^10.4.0" + tsconfig "^7.0.0" + +ts-node@^10.4.0, ts-node@>=9.0.0: + version "10.9.2" + resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.1" + yn "3.1.1" + +tsconfig@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz" + integrity sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw== + dependencies: + "@types/strip-bom" "^3.0.0" + "@types/strip-json-comments" "0.0.30" + strip-bom "^3.0.0" + strip-json-comments "^2.0.0" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz" + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== + dependencies: + safe-buffer "^5.0.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" + integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg== + dependencies: + prelude-ls "~1.1.2" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^2.19.0: + version "2.19.0" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz" + integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typescript@*, typescript@>=2.7, typescript@5.4.2: + version "5.4.2" + resolved "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz" + integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ== + +underscore@1.12.1: + version "1.12.1" + resolved "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz" + integrity sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw== + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +unique-filename@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz" + integrity sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g== + dependencies: + unique-slug "^4.0.0" + +unique-slug@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz" + integrity sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ== + dependencies: + imurmurhash "^0.1.4" + +unpipe@~1.0.0, unpipe@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +update-browserslist-db@^1.0.13: + version "1.0.13" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz" + integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +uuid@^3.0.0: + version "3.4.0" + resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + +uuid@9.0.1: + version "9.0.1" + resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +v8-compile-cache@^2.0.3: + version "2.4.0" + resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz" + integrity sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw== + +v8-to-istanbul@^9.0.1: + version "9.2.0" + resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz" + integrity sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +which-pm-runs@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz" + integrity sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA== + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +which@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/which/-/which-4.0.0.tgz" + integrity sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg== + dependencies: + isexe "^3.1.1" + +wide-align@^1.1.0: + version "1.1.5" + resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz" + integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== + dependencies: + string-width "^1.0.2 || 2 || 3 || 4" + +winston-transport@^4.7.0: + version "4.7.0" + resolved "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz" + integrity sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg== + dependencies: + logform "^2.3.2" + readable-stream "^3.6.0" + triple-beam "^1.3.0" + +winston@3.12.0: + version "3.12.0" + resolved "https://registry.npmjs.org/winston/-/winston-3.12.0.tgz" + integrity sha512-OwbxKaOlESDi01mC9rkM0dQqQt2I8DAUMRLZ/HpbwvDXm85IryEHgoogy5fziQy38PntgZsLlhAYHz//UPHZ5w== + dependencies: + "@colors/colors" "^1.6.0" + "@dabh/diagnostics" "^2.0.2" + async "^3.2.3" + is-stream "^2.0.0" + logform "^2.4.0" + one-time "^1.0.0" + readable-stream "^3.4.0" + safe-stable-stringify "^2.3.1" + stack-trace "0.0.x" + triple-beam "^1.3.0" + winston-transport "^4.7.0" + +wmf@~1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz" + integrity sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw== + +word-wrap@~1.2.3: + version "1.2.5" + resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +word@~0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/word/-/word-0.3.0.tgz" + integrity sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA== + +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + +xlsx-populate@1.21.0: + version "1.21.0" + resolved "https://registry.npmjs.org/xlsx-populate/-/xlsx-populate-1.21.0.tgz" + integrity sha512-8v2Gm8BehXo6LU7KT802QoXTPkYY1SKk5V8g/UuYZnNB3JzXqud/P99Pxr2yXeKyt+sKlCatmidz6jQNie1hRw== + dependencies: + cfb "^1.1.3" + jszip "^3.2.2" + lodash "^4.17.15" + sax "^1.2.4" + +xlsx@*, xlsx@0.18.5: + version "0.18.5" + resolved "https://registry.npmjs.org/xlsx/-/xlsx-0.18.5.tgz" + integrity sha512-dmg3LCjBPHZnQp5/F/+nnTa+miPJxUXB6vtk42YjBBKayDNagxGEeIdWApkYPOf3Z3pm3k62Knjzp7lMeTEtFQ== + dependencies: + adler-32 "~1.3.0" + cfb "~1.2.1" + codepage "~1.15.0" + crc-32 "~1.2.1" + ssf "~0.11.2" + wmf "~1.0.1" + word "~0.3.0" + +xtend@^4.0.0: + version "4.0.2" + resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.3.1: + version "17.7.2" + resolved "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +yup@1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/yup/-/yup-1.4.0.tgz" + integrity sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg== + dependencies: + property-expr "^2.0.5" + tiny-case "^1.0.3" + toposort "^2.0.2" + type-fest "^2.19.0" diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000000..fb57ccd13af --- /dev/null +++ b/yarn.lock @@ -0,0 +1,4 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + From b98dd54235e9681dc68f914893dcdf671f34901c Mon Sep 17 00:00:00 2001 From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Date: Wed, 29 May 2024 19:02:27 +0530 Subject: [PATCH 252/283] Delete .vscode directory (#754) * Delete .vscode directory * Update .gitignore * Updated the build config * fixed the generate and download issues --- .gitignore | 3 +- .vscode/launch.json | 17 ------- .vscode/settings.json | 3 -- build/build-config.yml | 41 +++------------- .../src/components/UploadData.js | 49 +++++++++++++++++-- .../src/pages/employee/SetupCampaign.js | 9 ---- .../src/server/utils/request.ts | 9 +++- 7 files changed, 58 insertions(+), 73 deletions(-) delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/settings.json diff --git a/.gitignore b/.gitignore index 010719f49a9..58c10f6dafe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ .DS_Store -accelerators/frontend/micro-ui-internals/node_modules/* .idea index.lock /health-services/stock/stock.iml @@ -86,4 +85,4 @@ Thumbs.db Thumbs.db utilities/project-factory/node_modules/* -frontend/*/node_modules/* \ No newline at end of file +frontend/micro-ui/web/micro-ui-internals/node_modules/* \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 65322fe9f51..00000000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "node", - "request": "attach", - "name": "Attach to Remote", - "address": "localhost", - "port": 9229, - "localRoot": "${workspaceFolder}", - "remoteRoot": "/app" - } - ] -} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 14f60307eb1..00000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "editor.inlineSuggest.showToolbar": "onHover" -} \ No newline at end of file diff --git a/build/build-config.yml b/build/build-config.yml index 2e09926ab6a..5d67d344db4 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -242,45 +242,16 @@ config: image-name: "auth-proxy" # frontend - - name: builds/Digit-Frontend/workbench-ui + - name: builds/health-campaign-services/frontend/workbench-ui build: - - work-dir: micro-ui/ - dockerfile: micro-ui/web/workbench/Dockerfile + - work-dir: frontend/micro-ui/ + dockerfile: frontend/micro-ui/web/workbench/Dockerfile image-name: workbench-ui - - name: builds/Digit-Frontend/microplan-ui - build: - - work-dir: micro-ui/ - dockerfile: micro-ui/web/microplan/Dockerfile - image-name: microplan-ui - - - name: builds/Digit-Frontend/storybook-svg - build: - - work-dir: micro-ui/web/micro-ui-internals/packages/svg-components/ - dockerfile: micro-ui/web/micro-ui-internals/packages/svg-components/docker/Dockerfile - image-name: storybook-svg - - - name: builds/Digit-Frontend/storybook - build: - - work-dir: micro-ui/web/micro-ui-internals/packages/components-core/ - dockerfile: micro-ui/web/micro-ui-internals/packages/components-core/docker/Dockerfile - image-name: storybook - - - name: builds/Digit-Frontend/digit-ui - build: - - work-dir: micro-ui/ - dockerfile: micro-ui/web/docker/Dockerfile - image-name: digit-ui - - - name: builds/Digit-Frontend/core-ui - build: - - work-dir: micro-ui/ - dockerfile: micro-ui/web/core/Dockerfile - image-name: core-ui #Utilities - - name: "builds/Digit-Frontend/utilities/project-factory" + - name: "builds/health-campaign-services/health-services/project-factory" build: - - work-dir: "utilities/project-factory" + - work-dir: "health-services/project-factory" image-name: "project-factory" - - work-dir: "utilities/project-factory/migration" + - work-dir: "health-services/project-factory/migration" image-name: "project-factory-db" diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js index 57a66d1fa16..5f51c71886e 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js @@ -49,6 +49,7 @@ const UploadData = ({ formData, onSelect, ...props }) => { const [sheetHeaders, setSheetHeaders] = useState({}); const [translatedSchema, setTranslatedSchema] = useState({}); const [readMeInfo, setReadMeInfo] = useState({}); + const [enabled, setEnabled] = useState(false); useEffect(() => { if (type === "facilityWithBoundary") { @@ -437,7 +438,7 @@ const UploadData = ({ formData, onSelect, ...props }) => { return; } } - if (type === "boundary" && workbook?.SheetNames?.length > 3) { + if (type === "boundary" && workbook?.SheetNames?.length >= 3) { if (!validateMultipleTargets(workbook)) { return; } @@ -616,13 +617,13 @@ const UploadData = ({ formData, onSelect, ...props }) => { } } else { setIsValidation(false); - setShowToast({ key: "error", label: t("HCM_VALIDATION_FAILED") }); + setShowToast({ key: "error", label: t("HCM_VALIDATION_FAILED"), transitionTime: 5000000 }); const processedFileStore = temp?.processedFilestoreId; if (!processedFileStore) { - setShowToast({ key: "error", label: t("HCM_VALIDATION_FAILED") }); + setShowToast({ key: "error", label: t("HCM_VALIDATION_FAILED"), transitionTime: 5000000 }); return; } else { - setShowToast({ key: "warning", label: t("HCM_CHECK_FILE_AGAIN") }); + setShowToast({ key: "warning", label: t("HCM_CHECK_FILE_AGAIN"), transitionTime: 5000000 }); setIsError(true); const { data: { fileStoreIds: fileUrl } = {} } = await Digit.UploadServices.Filefetch([processedFileStore], tenantId); const fileData = fileUrl @@ -658,6 +659,42 @@ const UploadData = ({ formData, onSelect, ...props }) => { fetchData(); }, [errorsType]); + const { data: facilityId, isLoading: isFacilityLoading, refetch: refetchFacility } = Digit.Hooks.campaign.useGenerateIdCampaign({ + type: "facilityWithBoundary", + hierarchyType: params?.hierarchyType, + campaignId: id, + // config: { + // enabled: setTimeout(fetchUpload || (fetchBoundary && currentKey > 6)), + // }, + config: { + enabled: enabled, + }, + }); + + const { data: boundaryId, isLoading: isBoundaryLoading, refetch: refetchBoundary } = Digit.Hooks.campaign.useGenerateIdCampaign({ + type: "boundary", + hierarchyType: params?.hierarchyType, + campaignId: id, + // config: { + // enabled: fetchUpload || (fetchBoundary && currentKey > 6), + // }, + config: { + enabled: enabled, + }, + }); + + const { data: userId, isLoading: isUserLoading, refetch: refetchUser } = Digit.Hooks.campaign.useGenerateIdCampaign({ + type: "userWithBoundary", + hierarchyType: params?.hierarchyType, + campaignId: id, + // config: { + // enabled: fetchUpload || (fetchBoundary && currentKey > 6), + // }, + config: { + enabled: enabled, + }, + }); + const Template = { url: "/project-factory/v1/data/_download", params: { @@ -686,6 +723,8 @@ const UploadData = ({ formData, onSelect, ...props }) => { return; } if (!params?.boundaryId || !params?.facilityId || !params?.userId) { + setEnabled(true); + setDownloadError(true); setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_TRY_IN_SOME_TIME") }); return; @@ -751,7 +790,7 @@ const UploadData = ({ formData, onSelect, ...props }) => { }; useEffect(() => { if (showToast) { - const t = setTimeout(closeToast, 5000); + const t = setTimeout(closeToast, 50000); return () => clearTimeout(t); } }, [showToast]); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js index 1b19ef6537e..708318d9e6b 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js @@ -386,8 +386,6 @@ const SetupCampaign = ({ hierarchyType }) => { setTimeout(() => { setEnabled(fetchUpload || (fetchBoundary && currentKey > 6)); }, 3000); - - // return () => clearTimeout(timeoutId); }, [fetchUpload, fetchBoundary, currentKey]); const { data: facilityId, isLoading: isFacilityLoading, refetch: refetchFacility } = Digit.Hooks.campaign.useGenerateIdCampaign({ @@ -402,16 +400,9 @@ const SetupCampaign = ({ hierarchyType }) => { }, }); - // useEffect(() => { - // if (filteredBoundaryData) { - // refetchBoundary(); - // } - // }, [filteredBoundaryData]); - const { data: boundaryId, isLoading: isBoundaryLoading, refetch: refetchBoundary } = Digit.Hooks.campaign.useGenerateIdCampaign({ type: "boundary", hierarchyType: hierarchyType, - // filters: filteredBoundaryData, campaignId: id, // config: { // enabled: fetchUpload || (fetchBoundary && currentKey > 6), diff --git a/health-services/project-factory/src/server/utils/request.ts b/health-services/project-factory/src/server/utils/request.ts index 3a41cef1e08..ae5ba11dd49 100644 --- a/health-services/project-factory/src/server/utils/request.ts +++ b/health-services/project-factory/src/server/utils/request.ts @@ -4,9 +4,14 @@ import { cacheResponse, getCachedResponse, throwErrorViaRequest } from "./generi var Axios = require("axios").default; // Importing axios library var get = require("lodash/get"); // Importing get function from lodash library +const axiosInstance = Axios.create({ + timeout: 10000, + maxContentLength: Infinity, + maxBodyLength: Infinity, +}); // Axios interceptor to handle response errors -Axios.interceptors.response.use( +axiosInstance.interceptors.response.use( (res: Response) => { return res; }, @@ -143,4 +148,4 @@ const httpRequest = async ( } }; -export { httpRequest }; // Exporting the httpRequest function for use in other modules \ No newline at end of file +export { httpRequest }; // Exporting the httpRequest function for use in other modules From 41a7328cd13d9a0d3f58e709065901d34f8ab525 Mon Sep 17 00:00:00 2001 From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Date: Thu, 30 May 2024 11:54:53 +0530 Subject: [PATCH 253/283] Delete edcr/service/egov/egov-edcr-extract/src/test/resources directory (#755) --- .../src/test/resources/Parking-test.dxf~ | 113500 --------------- 1 file changed, 113500 deletions(-) delete mode 100644 edcr/service/egov/egov-edcr-extract/src/test/resources/Parking-test.dxf~ diff --git a/edcr/service/egov/egov-edcr-extract/src/test/resources/Parking-test.dxf~ b/edcr/service/egov/egov-edcr-extract/src/test/resources/Parking-test.dxf~ deleted file mode 100644 index 0075c9c2aeb..00000000000 --- a/edcr/service/egov/egov-edcr-extract/src/test/resources/Parking-test.dxf~ +++ /dev/null @@ -1,113500 +0,0 @@ -999 -dxfrw 0.6.3 - 0 -SECTION - 2 -HEADER - 9 -$ACADVER - 1 -AC1021 - 9 -$DWGCODEPAGE - 3 -ANSI_1252 - 9 -$INSBASE - 10 -0 - 20 -0 - 30 -0 - 9 -$EXTMIN - 10 -10000000000 - 20 -10000000000 - 30 -0 - 9 -$EXTMAX - 10 --10000000000 - 20 --10000000000 - 30 -0 - 9 -$LIMMIN - 10 -0 - 20 -0 - 9 -$LIMMAX - 10 -12 - 20 -9 - 9 -$ORTHOMODE - 70 - 0 - 9 -$REGENMODE - 70 - 1 - 9 -$FILLMODE - 70 - 1 - 9 -$QTEXTMODE - 70 - 0 - 9 -$MIRRTEXT - 70 - 0 - 9 -$LTSCALE - 40 -1 - 9 -$ATTMODE - 70 - 1 - 9 -$TEXTSIZE - 40 -0.2 - 9 -$TRACEWID - 40 -0.05 - 9 -$TEXTSTYLE - 7 -Standard - 9 -$CLAYER - 8 -BLK_1_FLR_0_COVERED_PARKING - 9 -$CELTYPE - 6 -ByLayer - 9 -$CECOLOR - 62 - 1 - 9 -$CELTSCALE - 40 -1 - 9 -$DISPSILH - 70 - 0 - 9 -$DIMSCALE - 40 -1 - 9 -$DIMASZ - 40 -0.18 - 9 -$DIMEXO - 40 -0.0625 - 9 -$DIMDLI - 40 -0.38 - 9 -$DIMRND - 40 -0 - 9 -$DIMDLE - 40 -0 - 9 -$DIMEXE - 40 -0.18 - 9 -$DIMTP - 40 -0 - 9 -$DIMTM - 40 -0 - 9 -$DIMTXT - 40 -0.18 - 9 -$DIMCEN - 40 -0.09 - 9 -$DIMTSZ - 40 -0 - 9 -$DIMTOL - 70 - 0 - 9 -$DIMLIM - 70 - 0 - 9 -$DIMTIH - 70 - 1 - 9 -$DIMTOH - 70 - 1 - 9 -$DIMSE1 - 70 - 0 - 9 -$DIMSE2 - 70 - 0 - 9 -$DIMTAD - 70 - 0 - 9 -$DIMZIN - 70 - 0 - 9 -$DIMBLK - 1 - - 9 -$DIMASO - 70 - 1 - 9 -$DIMSHO - 70 - 1 - 9 -$DIMPOST - 1 - - 9 -$DIMAPOST - 1 - - 9 -$DIMALT - 70 - 0 - 9 -$DIMALTD - 70 - 2 - 9 -$DIMALTF - 40 -25.4 - 9 -$DIMLFAC - 40 -1 - 9 -$DIMTOFL - 70 - 0 - 9 -$DIMTVP - 40 -0 - 9 -$DIMTIX - 70 - 0 - 9 -$DIMSOXD - 70 - 0 - 9 -$DIMSAH - 70 - 0 - 9 -$DIMBLK1 - 1 - - 9 -$DIMBLK2 - 1 - - 9 -$DIMSTYLE - 2 -Standard - 9 -$DIMCLRD - 70 - 0 - 9 -$DIMCLRE - 70 - 0 - 9 -$DIMCLRT - 70 - 0 - 9 -$DIMTFAC - 40 -1 - 9 -$DIMGAP - 40 -0.09 - 9 -$DIMJUST - 70 - 0 - 9 -$DIMSD1 - 70 - 0 - 9 -$DIMSD2 - 70 - 0 - 9 -$DIMTOLJ - 70 - 1 - 9 -$DIMTZIN - 70 - 0 - 9 -$DIMALTZ - 70 - 0 - 9 -$DIMALTTZ - 70 - 0 - 9 -$DIMUPT - 70 - 0 - 9 -$DIMDEC - 70 - 4 - 9 -$DIMTDEC - 70 - 4 - 9 -$DIMALTU - 70 - 2 - 9 -$DIMALTTD - 70 - 2 - 9 -$DIMTXSTY - 7 -Standard - 9 -$DIMAUNIT - 70 - 0 - 9 -$DIMADEC - 70 - 0 - 9 -$DIMALTRND - 40 -0 - 9 -$DIMAZIN - 70 - 0 - 9 -$DIMDSEP - 70 - 46 - 9 -$DIMATFIT - 70 - 3 - 9 -$DIMFRAC - 70 - 0 - 9 -$DIMLDRBLK - 1 - - 9 -$DIMLUNIT - 70 - 2 - 9 -$DIMLWD - 70 - -2 - 9 -$DIMLWE - 70 - -2 - 9 -$DIMTMOVE - 70 - 0 - 9 -$DIMFXL - 40 -40 - 9 -$DIMFXLON - 70 - 1 - 9 -$DIMJOGANG - 40 -0.7853981633974483 - 9 -$DIMTFILL - 70 - 1 - 9 -$DIMTFILLCLR - 70 - 0 - 9 -$DIMARCSYM - 70 - 1 - 9 -$DIMLTYPE - 6 -Continuous - 9 -$DIMLTEX1 - 6 -ByLayer - 9 -$DIMLTEX2 - 6 -ByLayer - 9 -$LUNITS - 70 - 2 - 9 -$LUPREC - 70 - 4 - 9 -$SKETCHINC - 40 -0.1 - 9 -$FILLETRAD - 40 -0 - 9 -$AUNITS - 70 - 0 - 9 -$AUPREC - 70 - 0 - 9 -$MENU - 1 -. - 9 -$ELEVATION - 40 -0 - 9 -$PELEVATION - 40 -0 - 9 -$THICKNESS - 40 -0 - 9 -$LIMCHECK - 70 - 0 - 9 -$CHAMFERA - 40 -0 - 9 -$CHAMFERB - 40 -0 - 9 -$CHAMFERC - 40 -0 - 9 -$CHAMFERD - 40 -0 - 9 -$SKPOLY - 70 - 0 - 9 -$USRTIMER - 70 - 1 - 9 -$ANGBASE - 50 -0 - 9 -$ANGDIR - 70 - 0 - 9 -$PDMODE - 70 - 0 - 9 -$PDSIZE - 40 -0 - 9 -$PLINEWID - 40 -0 - 9 -$SPLFRAME - 70 - 0 - 9 -$SPLINETYPE - 70 - 6 - 9 -$SPLINESEGS - 70 - 8 - 9 -$HANDSEED - 5 -20000 - 9 -$SURFTAB1 - 70 - 6 - 9 -$SURFTAB2 - 70 - 6 - 9 -$SURFTYPE - 70 - 6 - 9 -$SURFU - 70 - 6 - 9 -$SURFV - 70 - 6 - 9 -$UCSBASE - 2 - - 9 -$UCSNAME - 2 - - 9 -$UCSORG - 10 -0 - 20 -0 - 30 -0 - 9 -$UCSXDIR - 10 -1 - 20 -0 - 30 -0 - 9 -$UCSYDIR - 10 -0 - 20 -1 - 30 -0 - 9 -$UCSORTHOREF - 2 - - 9 -$UCSORTHOVIEW - 70 - 0 - 9 -$UCSORGTOP - 10 -0 - 20 -0 - 30 -0 - 9 -$UCSORGBOTTOM - 10 -0 - 20 -0 - 30 -0 - 9 -$UCSORGLEFT - 10 -0 - 20 -0 - 30 -0 - 9 -$UCSORGRIGHT - 10 -0 - 20 -0 - 30 -0 - 9 -$UCSORGFRONT - 10 -0 - 20 -0 - 30 -0 - 9 -$UCSORGBACK - 10 -0 - 20 -0 - 30 -0 - 9 -$PUCSBASE - 2 - - 9 -$PUCSNAME - 2 - - 9 -$PUCSORG - 10 -0 - 20 -0 - 30 -0 - 9 -$PUCSXDIR - 10 -1 - 20 -0 - 30 -0 - 9 -$PUCSYDIR - 10 -0 - 20 -1 - 30 -0 - 9 -$PUCSORTHOREF - 2 - - 9 -$PUCSORTHOVIEW - 70 - 0 - 9 -$PUCSORGTOP - 10 -0 - 20 -0 - 30 -0 - 9 -$PUCSORGBOTTOM - 10 -0 - 20 -0 - 30 -0 - 9 -$PUCSORGLEFT - 10 -0 - 20 -0 - 30 -0 - 9 -$PUCSORGRIGHT - 10 -0 - 20 -0 - 30 -0 - 9 -$PUCSORGFRONT - 10 -0 - 20 -0 - 30 -0 - 9 -$PUCSORGBACK - 10 -0 - 20 -0 - 30 -0 - 9 -$USERI1 - 70 - 0 - 9 -$USERI2 - 70 - 0 - 9 -$USERI3 - 70 - 0 - 9 -$USERI4 - 70 - 0 - 9 -$USERI5 - 70 - 0 - 9 -$USERR1 - 40 -0 - 9 -$USERR2 - 40 -0 - 9 -$USERR3 - 40 -0 - 9 -$USERR4 - 40 -0 - 9 -$USERR5 - 40 -0 - 9 -$WORLDVIEW - 70 - 1 - 9 -$SHADEDGE - 70 - 3 - 9 -$SHADEDIF - 70 - 70 - 9 -$TILEMODE - 70 - 1 - 9 -$MAXACTVP - 70 - 64 - 9 -$PINSBASE - 10 -0 - 20 -0 - 30 -0 - 9 -$PLIMCHECK - 70 - 0 - 9 -$PEXTMIN - 10 -0 - 20 -0 - 30 -0 - 9 -$PEXTMAX - 10 -0 - 20 -0 - 30 -0 - 9 -$GRIDMODE - 70 - 0 - 9 -$SNAPSTYLE - 70 - 0 - 9 -$PLIMMIN - 10 -0 - 20 -0 - 9 -$PLIMMAX - 10 -12 - 20 -9 - 9 -$UNITMODE - 70 - 0 - 9 -$VISRETAIN - 70 - 1 - 9 -$PLINEGEN - 70 - 0 - 9 -$PSLTSCALE - 70 - 1 - 9 -$TREEDEPTH - 70 - 3020 - 9 -$CMLSTYLE - 2 -Standard - 9 -$CMLJUST - 70 - 0 - 9 -$CMLSCALE - 40 -1 - 9 -$PROXYGRAPHICS - 70 - 1 - 9 -$MEASUREMENT - 70 - 0 - 9 -$CELWEIGHT -370 - -1 - 9 -$ENDCAPS -280 - 0 - 9 -$JOINSTYLE -280 - 0 - 9 -$LWDISPLAY -290 - 0 - 9 -$INSUNITS - 70 - 6 - 9 -$HYPERLINKBASE - 1 - - 9 -$STYLESHEET - 1 - - 9 -$XEDIT -290 - 1 - 9 -$CEPSNTYPE -380 - 0 - 9 -$PSTYLEMODE -290 - 1 - 9 -$EXTNAMES -290 - 1 - 9 -$PSVPSCALE - 40 -0 - 9 -$OLESTARTUP -290 - 0 - 9 -$SORTENTS -280 - 127 - 9 -$INDEXCTL -280 - 0 - 9 -$HIDETEXT -280 - 1 - 9 -$XCLIPFRAME -290 - 0 - 9 -$HALOGAP -280 - 0 - 9 -$OBSCOLOR - 70 - 257 - 9 -$OBSLTYPE -280 - 0 - 9 -$INTERSECTIONDISPLAY -280 - 0 - 9 -$INTERSECTIONCOLOR - 70 - 257 - 9 -$DIMASSOC -280 - 2 - 9 -$PROJECTNAME - 1 - - 9 -$CAMERADISPLAY -290 - 0 - 9 -$LENSLENGTH - 40 -50 - 9 -$CAMERAHEIGHT - 40 -0 - 9 -$STEPSPERSEC - 40 -2 - 9 -$STEPSIZE - 40 -6 - 9 -$3DDWFPREC - 40 -2 - 9 -$PSOLWIDTH - 40 -0.25 - 9 -$PSOLHEIGHT - 40 -4 - 9 -$LOFTANG1 - 40 -1.570795999999999 - 9 -$LOFTANG2 - 40 -1.570795999999999 - 9 -$LOFTMAG1 - 40 -0 - 9 -$LOFTMAG2 - 40 -0 - 9 -$LOFTPARAM - 70 - 7 - 9 -$LOFTNORMALS -280 - 1 - 9 -$LATITUDE - 40 -37.795 - 9 -$LONGITUDE - 40 --122.394 - 9 -$NORTHDIRECTION - 40 -0 - 9 -$TIMEZONE - 70 --8000 - 9 -$LIGHTGLYPHDISPLAY -280 - 1 - 9 -$TILEMODELIGHTSYNCH -280 - 1 - 9 -$SOLIDHIST -280 - 0 - 9 -$SHOWHIST -280 - 1 - 9 -$DWFFRAME -280 - 2 - 9 -$DGNFRAME -280 - 0 - 9 -$REALWORLDSCALE -290 - 1 - 9 -$INTERFERECOLOR - 62 - 1 - 9 -$CSHADOW -280 - 0 - 9 -$SHADOWPLANELOCATION - 40 -0 - 0 -ENDSEC - 0 -SECTION - 2 -CLASSES - 0 -ENDSEC - 0 -SECTION - 2 -TABLES - 0 -TABLE - 2 -VPORT - 5 -8 -330 -0 -100 -AcDbSymbolTable - 70 - 1 - 0 -VPORT - 5 -31 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbViewportTableRecord - 2 -*ACTIVE - 70 - 0 - 10 -0 - 20 -0 - 11 -1 - 21 -1 - 12 -1890.972724807764 - 22 -580.6761978901518 - 13 -0 - 23 -0 - 14 -10 - 24 -10 - 15 -10 - 25 -10 - 16 -0 - 26 -0 - 36 -1 - 17 -0 - 27 -0 - 37 -0 - 40 -129.2679479148683 - 41 -1.31858407079646 - 42 -50 - 43 -0 - 44 -0 - 50 -0 - 51 -0 - 71 - 0 - 72 - 100 - 73 - 1 - 74 - 3 - 75 - 0 - 76 - 0 - 77 - 0 - 78 - 0 -281 - 0 - 65 - 1 -110 -0 -120 -0 -130 -0 -111 -1 -121 -0 -131 -0 -112 -0 -122 -1 -132 -0 - 79 - 0 -146 -0 -348 -10020 - 60 - 7 - 61 - 5 -292 -1 -282 - 1 -141 -0 -142 -0 - 63 - 250 -421 -3358443 - 0 -ENDTAB - 0 -TABLE - 2 -LTYPE - 5 -5 -330 -0 -100 -AcDbSymbolTable - 70 - 4 - 0 -LTYPE - 5 -14 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -ByBlock - 70 - 0 - 3 - - 72 - 65 - 73 - 0 - 40 -0 - 0 -LTYPE - 5 -15 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -ByLayer - 70 - 0 - 3 - - 72 - 65 - 73 - 0 - 40 -0 - 0 -LTYPE - 5 -16 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -Continuous - 70 - 0 - 3 -Solid line - 72 - 65 - 73 - 0 - 40 -0 - 0 -LTYPE - 5 -32 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DOT - 70 - 0 - 3 -Dot . . . . . . . . . . . . . . . . . . . . . . - 72 - 65 - 73 - 2 - 40 -6.35 - 49 -0 - 74 - 0 - 49 --6.35 - 74 - 0 - 0 -LTYPE - 5 -33 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DOTTINY - 70 - 0 - 3 -Dot (.15x) ..................................... - 72 - 65 - 73 - 2 - 40 -0.9525 - 49 -0 - 74 - 0 - 49 --0.9525 - 74 - 0 - 0 -LTYPE - 5 -34 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DOT2 - 70 - 0 - 3 -Dot (.5x) ..................................... - 72 - 65 - 73 - 2 - 40 -3.175 - 49 -0 - 74 - 0 - 49 --3.175 - 74 - 0 - 0 -LTYPE - 5 -35 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DOTX2 - 70 - 0 - 3 -Dot (2x) . . . . . . . . . . . . . - 72 - 65 - 73 - 2 - 40 -12.7 - 49 -0 - 74 - 0 - 49 --12.7 - 74 - 0 - 0 -LTYPE - 5 -36 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DASHED - 70 - 0 - 3 -Dashed _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - 72 - 65 - 73 - 2 - 40 -19.05 - 49 -12.7 - 74 - 0 - 49 --6.35 - 74 - 0 - 0 -LTYPE - 5 -37 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DASHEDTINY - 70 - 0 - 3 -Dashed (.15x) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - 72 - 65 - 73 - 2 - 40 -2.8575 - 49 -1.905 - 74 - 0 - 49 --0.9525 - 74 - 0 - 0 -LTYPE - 5 -38 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DASHED2 - 70 - 0 - 3 -Dashed (.5x) _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ - 72 - 65 - 73 - 2 - 40 -9.524999999999999 - 49 -6.35 - 74 - 0 - 49 --3.175 - 74 - 0 - 0 -LTYPE - 5 -39 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DASHEDX2 - 70 - 0 - 3 -Dashed (2x) ____ ____ ____ ____ ____ ___ - 72 - 65 - 73 - 2 - 40 -38.09999999999999 - 49 -25.4 - 74 - 0 - 49 --12.7 - 74 - 0 - 0 -LTYPE - 5 -3A -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DASHDOT - 70 - 0 - 3 -Dash dot __ . __ . __ . __ . __ . __ . __ . __ - 72 - 65 - 73 - 4 - 40 -25.4 - 49 -12.7 - 74 - 0 - 49 --6.35 - 74 - 0 - 49 -0 - 74 - 0 - 49 --6.35 - 74 - 0 - 0 -LTYPE - 5 -3B -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DASHDOTTINY - 70 - 0 - 3 -Dash dot (.15x) _._._._._._._._._._._._._._._. - 72 - 65 - 73 - 4 - 40 -3.81 - 49 -1.905 - 74 - 0 - 49 --0.9525 - 74 - 0 - 49 -0 - 74 - 0 - 49 --0.9525 - 74 - 0 - 0 -LTYPE - 5 -3C -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DASHDOT2 - 70 - 0 - 3 -Dash dot (.5x) _._._._._._._._._._._._._._._. - 72 - 65 - 73 - 4 - 40 -12.7 - 49 -6.35 - 74 - 0 - 49 --3.175 - 74 - 0 - 49 -0 - 74 - 0 - 49 --3.175 - 74 - 0 - 0 -LTYPE - 5 -3D -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DASHDOTX2 - 70 - 0 - 3 -Dash dot (2x) ____ . ____ . ____ . ___ - 72 - 65 - 73 - 4 - 40 -50.8 - 49 -25.4 - 74 - 0 - 49 --12.7 - 74 - 0 - 49 -0 - 74 - 0 - 49 --12.7 - 74 - 0 - 0 -LTYPE - 5 -3E -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DIVIDE - 70 - 0 - 3 -Divide ____ . . ____ . . ____ . . ____ . . ____ - 72 - 65 - 73 - 6 - 40 -31.75 - 49 -12.7 - 74 - 0 - 49 --6.35 - 74 - 0 - 49 -0 - 74 - 0 - 49 --6.35 - 74 - 0 - 49 -0 - 74 - 0 - 49 --6.35 - 74 - 0 - 0 -LTYPE - 5 -3F -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DIVIDETINY - 70 - 0 - 3 -Divide (.15x) __..__..__..__..__..__..__..__.._ - 72 - 65 - 73 - 6 - 40 -4.7625 - 49 -1.905 - 74 - 0 - 49 --0.9525 - 74 - 0 - 49 -0 - 74 - 0 - 49 --0.9525 - 74 - 0 - 49 -0 - 74 - 0 - 49 --0.9525 - 74 - 0 - 0 -LTYPE - 5 -40 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DIVIDE2 - 70 - 0 - 3 -Divide (.5x) __..__..__..__..__..__..__..__.._ - 72 - 65 - 73 - 6 - 40 -15.875 - 49 -6.35 - 74 - 0 - 49 --3.175 - 74 - 0 - 49 -0 - 74 - 0 - 49 --3.175 - 74 - 0 - 49 -0 - 74 - 0 - 49 --3.175 - 74 - 0 - 0 -LTYPE - 5 -41 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -DIVIDEX2 - 70 - 0 - 3 -Divide (2x) ________ . . ________ . . _ - 72 - 65 - 73 - 6 - 40 -63.5 - 49 -25.4 - 74 - 0 - 49 --12.7 - 74 - 0 - 49 -0 - 74 - 0 - 49 --12.7 - 74 - 0 - 49 -0 - 74 - 0 - 49 --12.7 - 74 - 0 - 0 -LTYPE - 5 -42 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -BORDER - 70 - 0 - 3 -Border __ __ . __ __ . __ __ . __ __ . __ __ . - 72 - 65 - 73 - 6 - 40 -44.45 - 49 -12.7 - 74 - 0 - 49 --6.35 - 74 - 0 - 49 -12.7 - 74 - 0 - 49 --6.35 - 74 - 0 - 49 -0 - 74 - 0 - 49 --6.35 - 74 - 0 - 0 -LTYPE - 5 -43 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -BORDERTINY - 70 - 0 - 3 -Border (.15x) __.__.__.__.__.__.__.__.__.__.__. - 72 - 65 - 73 - 6 - 40 -6.6675 - 49 -1.905 - 74 - 0 - 49 --0.9525 - 74 - 0 - 49 -1.905 - 74 - 0 - 49 --0.9525 - 74 - 0 - 49 -0 - 74 - 0 - 49 --0.9525 - 74 - 0 - 0 -LTYPE - 5 -44 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -BORDER2 - 70 - 0 - 3 -Border (.5x) __.__.__.__.__.__.__.__.__.__.__. - 72 - 65 - 73 - 6 - 40 -22.225 - 49 -6.35 - 74 - 0 - 49 --3.175 - 74 - 0 - 49 -6.35 - 74 - 0 - 49 --3.175 - 74 - 0 - 49 -0 - 74 - 0 - 49 --3.175 - 74 - 0 - 0 -LTYPE - 5 -45 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -BORDERX2 - 70 - 0 - 3 -Border (2x) ____ ____ . ____ ____ . ___ - 72 - 65 - 73 - 6 - 40 -88.89999999999999 - 49 -25.4 - 74 - 0 - 49 --12.7 - 74 - 0 - 49 -25.4 - 74 - 0 - 49 --12.7 - 74 - 0 - 49 -0 - 74 - 0 - 49 --12.7 - 74 - 0 - 0 -LTYPE - 5 -46 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -CENTER - 70 - 0 - 3 -Center ____ _ ____ _ ____ _ ____ _ ____ _ ____ - 72 - 65 - 73 - 4 - 40 -50.8 - 49 -31.75 - 74 - 0 - 49 --6.35 - 74 - 0 - 49 -6.35 - 74 - 0 - 49 --6.35 - 74 - 0 - 0 -LTYPE - 5 -47 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -CENTERTINY - 70 - 0 - 3 -Center (.15x) ___ _ ___ _ ___ _ ___ _ ___ _ ___ - 72 - 65 - 73 - 4 - 40 -7.619999999999999 - 49 -4.7625 - 74 - 0 - 49 --0.9525 - 74 - 0 - 49 -0.9525 - 74 - 0 - 49 --0.9525 - 74 - 0 - 0 -LTYPE - 5 -48 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -CENTER2 - 70 - 0 - 3 -Center (.5x) ___ _ ___ _ ___ _ ___ _ ___ _ ___ - 72 - 65 - 73 - 4 - 40 -28.575 - 49 -19.05 - 74 - 0 - 49 --3.175 - 74 - 0 - 49 -3.175 - 74 - 0 - 49 --3.175 - 74 - 0 - 0 -LTYPE - 5 -49 -330 -5 -100 -AcDbSymbolTableRecord -100 -AcDbLinetypeTableRecord - 2 -CENTERX2 - 70 - 0 - 3 -Center (2x) ________ __ ________ __ _____ - 72 - 65 - 73 - 4 - 40 -101.6 - 49 -63.5 - 74 - 0 - 49 --12.7 - 74 - 0 - 49 -12.7 - 74 - 0 - 49 --12.7 - 74 - 0 - 0 -ENDTAB - 0 -TABLE - 2 -LAYER - 5 -2 -330 -0 -100 -AcDbSymbolTable - 70 - 1 - 0 -LAYER - 5 -10 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -0 - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -370 - -3 -390 -F - 0 -LAYER - 5 -4A -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_BSMNT_FOOT_PRINT - 70 - 0 - 62 - 6 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -4B -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_BSMNT_FRONT_YARD - 70 - 0 - 62 - 2 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -4C -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_BSMNT_REAR_YARD - 70 - 0 - 62 - 11 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -4D -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_BSMNT_SIDE_YARD_1 - 70 - 0 - 62 - 171 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -4E -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_BSMNT_SIDE_YARD_2 - 70 - 0 - 62 - 102 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -4F -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_COVERED_AREA - 70 - 0 - 62 - 140 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -50 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_DA_RAMP_1 - 70 - 0 - 62 - 241 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -51 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_-1_BLT_UP_AREA - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -52 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_-1_BLT_UP_AREA_DEDUCT - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -53 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_-1_EXIT_WIDTH_STAIR - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -54 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_-1_HT_ROOM - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -55 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_-1_LIFT_1 - 70 - 0 - 62 - 30 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -56 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_-1_STAIR_1 - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -57 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -58 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_BLT_UP_AREA - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -59 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_BLT_UP_AREA_DEDUCT - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -5A -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_EXIT_WIDTH_DOOR - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -5B -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -5C -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_FIRESTAIR_1 - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -5D -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -5E -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_HT_ROOM - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -5F -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_SP_WC - 70 - 0 - 62 - 6 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -60 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_STAIR_1 - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -61 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_STAIR_1_FLIGHT - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -62 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_WASH - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -63 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_WATER_CLOSET - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -64 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_BLT_UP_AREA - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -65 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_BLT_UP_AREA_DEDUCT - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -66 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -67 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_FIRESTAIR_1 - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -68 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -69 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_HT_ROOM - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -6A -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_STAIR_1 - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -6B -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_STAIR_1_FLIGHT - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -6C -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_URINAL - 70 - 0 - 62 - 60 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -6D -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_WASH - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -6E -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_1_WATER_CLOSET - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -6F -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_2_BLT_UP_AREA - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -70 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -71 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_2_FIRESTAIR_1 - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -72 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -73 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_2_HT_ROOM - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -74 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_2_STAIR_1 - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -75 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_2_STAIR_1_FLIGHT - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -76 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_3_BLT_UP_AREA - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -77 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_3_EXIT_WIDTH_DOOR - 70 - 0 - 62 - 3 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -78 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_3_FIRESTAIR_1 - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -79 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_HT_OF_BLDG - 70 - 0 - 62 - 5 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -7A -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_LVL_0_BLDG_FOOT_PRINT - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -7B -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_LVL_0_FRONT_YARD - 70 - 0 - 62 - 2 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -7C -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_LVL_0_REAR_YARD - 70 - 0 - 62 - 11 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -7D -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_LVL_0_SIDE_YARD1 - 70 - 0 - 62 - 171 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -7E -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_LVL_0_SIDE_YARD2 - 70 - 0 - 62 - 102 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -7F -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_LVL_1_BLDG_FOOT_PRINT - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -80 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_LVL_1_FRONT_YARD - 70 - 0 - 62 - 2 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -81 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_LVL_1_REAR_YARD - 70 - 0 - 62 - 11 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -82 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_LVL_1_SIDE_YARD1 - 70 - 0 - 62 - 171 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -83 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_LVL_1_SIDE_YARD2 - 70 - 0 - 62 - 102 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -84 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_MAX_HEIGHT_CAL - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -85 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_SHADE_OVERHANG - 70 - 0 - 62 - 6 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -86 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -DA_PARKING - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -87 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -DIST_CL_ROAD - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -88 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -DIST_EXIT - 70 - 0 - 62 - 5 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -89 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -Defpoints - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -8A -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -FURNITURE - 70 - 0 - 62 - 13 - 6 -CONTINUOUS -370 - 13 -390 -F - 0 -LAYER - 5 -8B -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -NOTIFIED_ROAD - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -8C -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -BLK_1_FLR_0_COVERED_PARKING - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -370 - 0 -390 -F - 0 -LAYER - 5 -8D -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -PARKING_SLOT - 70 - 0 - 62 - 30 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -8E -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -PLAN_INFO - 70 - 0 - 62 - 1 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -8F -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -PLOT_BOUNDARY - 70 - 0 - 62 - 70 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -90 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -RWH - 70 - 0 - 62 - 4 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -91 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -SHORTEST_DIST_TO_ROAD - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -92 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -Symbols - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -370 - -3 -390 -F - 0 -LAYER - 5 -93 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -TWO_WHEELER_PARKING - 70 - 0 - 62 - 2 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -94 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -WASTE_DISPOSAL - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -290 -0 -370 - -3 -390 -F - 0 -LAYER - 5 -95 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbLayerTableRecord - 2 -coloumn - 70 - 0 - 62 - 7 - 6 -CONTINUOUS -370 - -3 -390 -F - 0 -ENDTAB - 0 -TABLE - 2 -STYLE - 5 -3 -330 -0 -100 -AcDbSymbolTable - 70 - 3 - 0 -STYLE - 5 -96 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbTextStyleTableRecord - 2 -standard - 70 - 0 - 40 -0 - 41 -1 - 50 -0 - 71 - 0 - 42 -1 - 3 -standard - 4 - - 0 -STYLE - 5 -97 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbTextStyleTableRecord - 2 -title1 - 70 - 0 - 40 -0 - 41 -1 - 50 -0 - 71 - 0 - 42 -1 - 3 -title1 - 4 - - 0 -STYLE - 5 -98 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbTextStyleTableRecord - 2 -arial - 70 - 0 - 40 -0 - 41 -1 - 50 -0 - 71 - 0 - 42 -1 - 3 -arial - 4 - - 0 -STYLE - 5 -99 -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbTextStyleTableRecord - 2 -sree - 70 - 0 - 40 -0 - 41 -1 - 50 -0 - 71 - 0 - 42 -1 - 3 -sree - 4 - - 0 -STYLE - 5 -9A -330 -2 -100 -AcDbSymbolTableRecord -100 -AcDbTextStyleTableRecord - 2 -arial smal - 70 - 0 - 40 -0 - 41 -1 - 50 -0 - 71 - 0 - 42 -1 - 3 -arial smal - 4 - - 0 -ENDTAB - 0 -TABLE - 2 -VIEW - 5 -6 -330 -0 -100 -AcDbSymbolTable - 70 - 0 - 0 -ENDTAB - 0 -TABLE - 2 -UCS - 5 -7 -330 -0 -100 -AcDbSymbolTable - 70 - 0 - 0 -ENDTAB - 0 -TABLE - 2 -APPID - 5 -9 -330 -0 -100 -AcDbSymbolTable - 70 - 1 - 0 -APPID - 5 -12 -330 -9 -100 -AcDbSymbolTableRecord -100 -AcDbRegAppTableRecord - 2 -ACAD - 70 - 0 - 0 -APPID - 5 -9B -330 -9 -100 -AcDbSymbolTableRecord -100 -AcDbRegAppTableRecord - 2 -LibreCad - 70 - 0 - 0 -ENDTAB - 0 -TABLE - 2 -DIMSTYLE - 5 -A -330 -0 -100 -AcDbSymbolTable - 70 - 1 -100 -AcDbDimStyleTable - 71 - 1 - 0 -DIMSTYLE -105 -9C -330 -A -100 -AcDbSymbolTableRecord -100 -AcDbDimStyleTableRecord - 2 -Standard - 70 - 0 - 40 -1 - 41 -0.18 - 42 -0.0625 - 43 -0.38 - 44 -0.18 - 45 -0 - 46 -0 - 47 -0 - 48 -0 - 49 -40 -140 -0.18 -141 -0.09 -142 -0 -143 -25.4 -144 -1 -145 -0 -146 -1 -147 -0.09 -148 -0 - 71 - 0 - 72 - 0 - 73 - 1 - 74 - 1 - 75 - 0 - 76 - 0 - 77 - 0 - 78 - 0 - 79 - 0 -170 - 0 -171 - 2 -172 - 0 -173 - 0 -174 - 0 -175 - 0 -176 - 0 -177 - 0 -178 - 0 -179 - 0 -271 - 4 -272 - 4 -273 - 2 -274 - 2 -275 - 0 -276 - 0 -277 - 2 -278 - 46 -279 - 0 -280 - 0 -281 - 0 -282 - 0 -283 - 1 -284 - 0 -285 - 0 -286 - 0 -288 - 0 -289 - 3 -290 - 1 -340 -Standard -341 - -371 - -2 -372 - -2 - 0 -ENDTAB - 0 -TABLE - 2 -BLOCK_RECORD - 5 -1 -330 -0 -100 -AcDbSymbolTable - 70 - 2 - 0 -BLOCK_RECORD - 5 -1F -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*Model_Space - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -1E -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*Paper_Space - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -9D -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D46 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -A0 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D79 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -A3 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D53 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -A6 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D83 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -A9 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D67 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -AC -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D69 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -AF -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D72 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -B2 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D24 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -B5 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D10 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -B8 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D75 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -BB -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D34 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -BE -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D28 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -C1 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D23 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -C4 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D31 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -C7 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D43 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -CA -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D82 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -CD -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D66 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -D0 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D44 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -D3 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D54 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -D6 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D64 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -D9 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D59 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -DC -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D70 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -DF -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D1 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -E2 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D35 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -E5 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D86 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -E8 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D88 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -EB -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D61 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -EE -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D19 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -F1 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D65 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -F4 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D89 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -F7 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D12 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -FA -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D63 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -FD -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D50 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -100 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D39 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -103 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D71 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -106 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D80 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -109 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D48 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -10C -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D4 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -10F -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D84 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -112 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D74 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -115 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D13 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -118 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D30 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -11B -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D26 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -11E -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D90 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -121 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D47 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -124 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D8 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -127 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D55 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -12A -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D73 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -12D -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D57 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -130 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D5 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -133 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D52 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -136 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D16 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -139 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D2 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -13C -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D6 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -13F -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D38 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -142 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D87 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -145 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D36 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -148 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D27 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -14B -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D3 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -14E -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D20 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -151 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D7 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -154 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D58 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -157 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D81 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -15A -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D11 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -15D -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D62 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -160 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D42 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -163 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D77 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -166 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D17 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -169 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D18 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -16C -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D56 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -16F -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D22 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -172 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D49 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -175 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D60 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -178 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D33 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -17B -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D29 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -17E -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D21 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -181 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D37 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -184 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D32 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -187 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D78 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -18A -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D25 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -18D -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D14 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -190 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D85 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -193 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D76 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -196 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D15 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -199 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D9 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -19C -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D51 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -19F -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D41 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -1A2 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D68 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -1A5 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D45 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -1A8 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*D40 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -1AB -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -_ArchTick - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -1AE -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -15 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -1B1 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -tre - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -1B4 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -*U4 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -1B7 -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -WELL10 - 70 - 0 -280 - 1 -281 - 0 - 0 -BLOCK_RECORD - 5 -1BA -330 -1 -100 -AcDbSymbolTableRecord -100 -AcDbBlockTableRecord - 2 -Basin 22 - 70 - 0 -280 - 1 -281 - 0 - 0 -ENDTAB - 0 -ENDSEC - 0 -SECTION - 2 -BLOCKS - 0 -BLOCK - 5 -20 -330 -1F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*Model_Space - 70 - 0 - 10 -0 - 20 -0 - 30 -0 - 3 -*Model_Space - 1 - - 0 -ENDBLK - 5 -21 -330 -1F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1C -330 -1B -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*Paper_Space - 70 - 0 - 10 -0 - 20 -0 - 30 -0 - 3 -*Paper_Space - 1 - - 0 -ENDBLK - 5 -1D -330 -1F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -9E -330 -9D -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D46 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D46 - 1 - - 0 -LINE - 5 -1BD -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.738675249547 - 20 -1243.552369962674 - 11 -3353.738675249547 - 21 -1243.132369416201 - 0 -SOLID - 5 -1BE -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3353.738675249547 - 20 -1243.552369962674 - 30 -0 - 11 -3353.768647744907 - 21 -1243.372369962674 - 31 -0 - 12 -3353.708702754187 - 22 -1243.372369962674 - 32 -0 - 13 -3353.708702754187 - 23 -1243.372369962674 - 33 -0 - 0 -SOLID - 5 -1BF -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3353.738675249547 - 20 -1242.352368869728 - 30 -0 - 11 -3353.708702754187 - 21 -1242.532368869728 - 31 -0 - 12 -3353.768647744907 - 22 -1242.532368869728 - 32 -0 - 13 -3353.768647744907 - 23 -1242.532368869728 - 33 -0 - 0 -LINE - 5 -1C0 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.738675249547 - 20 -1242.772369416201 - 11 -3353.738675249547 - 21 -1242.352368869728 - 0 -MTEXT - 5 -1C1 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3353.738675249547 - 20 -1242.952369416201 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -1C2 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.738675249528 - 20 -1243.552369962674 - 11 -3353.918675249547 - 21 -1243.552369962674 - 0 -LINE - 5 -1C3 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.73794189703 - 20 -1242.352368869728 - 11 -3353.918675249547 - 21 -1242.352368869728 - 0 -ENDBLK - 5 -9F -330 -9D -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -A1 -330 -A0 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D79 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D79 - 1 - - 0 -LINE - 5 -1C4 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369135 - 20 -1256.28662018356 - 11 -3427.522237369135 - 21 -1257.906620183549 - 0 -SOLID - 5 -1C5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3427.522237369135 - 20 -1256.28662018356 - 30 -0 - 11 -3427.492264873775 - 21 -1256.46662018356 - 31 -0 - 12 -3427.552209864495 - 22 -1256.46662018356 - 32 -0 - 13 -3427.552209864495 - 23 -1256.46662018356 - 33 -0 - 0 -SOLID - 5 -1C6 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3427.522237369135 - 20 -1259.886620183537 - 30 -0 - 11 -3427.552209864495 - 21 -1259.706620183537 - 31 -0 - 12 -3427.492264873775 - 22 -1259.706620183537 - 32 -0 - 13 -3427.492264873775 - 23 -1259.706620183537 - 33 -0 - 0 -LINE - 5 -1C7 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369135 - 20 -1258.266620183549 - 11 -3427.522237369135 - 21 -1259.886620183537 - 0 -MTEXT - 5 -1C8 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3427.394713937268 - 20 -1258.086620183549 - 30 -0 - 40 -0.18 - 41 -0.7000000000000224 - 71 - 5 - 72 - 1 - 1 -3.6000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -1C9 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369135 - 20 -1256.28662018356 - 11 -3427.702237369135 - 21 -1256.28662018356 - 0 -LINE - 5 -1CA -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369135 - 20 -1259.886620183537 - 11 -3427.702237369135 - 21 -1259.886620183537 - 0 -ENDBLK - 5 -A2 -330 -A0 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -A4 -330 -A3 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D53 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D53 - 1 - - 0 -LINE - 5 -1CB -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.137986023692 - 20 -1258.300104171694 - 11 -3316.137986023692 - 21 -1257.480104146831 - 0 -SOLID - 5 -1CC -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3316.137986023692 - 20 -1258.300104171694 - 30 -0 - 11 -3316.167958519052 - 21 -1258.120104171694 - 31 -0 - 12 -3316.108013528332 - 22 -1258.120104171694 - 32 -0 - 13 -3316.108013528332 - 23 -1258.120104171694 - 33 -0 - 0 -SOLID - 5 -1CD -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3316.137986023692 - 20 -1256.300104121969 - 30 -0 - 11 -3316.108013528332 - 21 -1256.480104121969 - 31 -0 - 12 -3316.167958519052 - 22 -1256.480104121969 - 32 -0 - 13 -3316.167958519052 - 23 -1256.480104121969 - 33 -0 - 0 -LINE - 5 -1CE -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.137986023692 - 20 -1257.120104146831 - 11 -3316.137986023692 - 21 -1256.300104121969 - 0 -MTEXT - 5 -1CF -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3316.137986023692 - 20 -1257.300104146831 - 30 -0 - 40 -0.18 - 41 -0.7000000000000001 - 71 - 5 - 72 - 1 - 1 -2.0000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -1D0 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.111287422821 - 20 -1258.300104171694 - 11 -3316.317986023692 - 21 -1258.300104171694 - 0 -LINE - 5 -1D1 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.137986023678 - 20 -1256.300104121969 - 11 -3316.317986023692 - 21 -1256.300104121969 - 0 -ENDBLK - 5 -A5 -330 -A3 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -A7 -330 -A6 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D83 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D83 - 1 - - 0 -LINE - 5 -1D2 -100 -AcDbEntity - 8 -BLK_1_FLR_0_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3439.369119896593 - 20 -1252.686620183584 - 11 -3439.369119896593 - 21 -1250.841620183561 - 0 -SOLID - 5 -1D3 -100 -AcDbEntity - 8 -BLK_1_FLR_0_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3439.369119896593 - 20 -1252.686620183584 - 30 -0 - 11 -3439.399092391953 - 21 -1252.506620183584 - 31 -0 - 12 -3439.339147401233 - 22 -1252.506620183584 - 32 -0 - 13 -3439.339147401233 - 23 -1252.506620183584 - 33 -0 - 0 -SOLID - 5 -1D4 -100 -AcDbEntity - 8 -BLK_1_FLR_0_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3439.369119896593 - 20 -1248.636620183537 - 30 -0 - 11 -3439.339147401233 - 21 -1248.816620183537 - 31 -0 - 12 -3439.399092391953 - 22 -1248.816620183537 - 32 -0 - 13 -3439.399092391953 - 23 -1248.816620183537 - 33 -0 - 0 -LINE - 5 -1D5 -100 -AcDbEntity - 8 -BLK_1_FLR_0_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3439.369119896593 - 20 -1250.481620183561 - 11 -3439.369119896593 - 21 -1248.636620183537 - 0 -MTEXT - 5 -1D6 -100 -AcDbEntity - 8 -BLK_1_FLR_0_HT_ROOM - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3439.369119896593 - 20 -1250.661620183561 - 30 -0 - 40 -0.18 - 41 -0.7200000000000111 - 71 - 5 - 72 - 1 - 1 -4.0500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -1D7 -100 -AcDbEntity - 8 -BLK_1_FLR_0_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1252.686620183584 - 11 -3439.549119896593 - 21 -1252.686620183584 - 0 -LINE - 5 -1D8 -100 -AcDbEntity - 8 -BLK_1_FLR_0_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1248.636620183537 - 11 -3439.549119896593 - 21 -1248.636620183537 - 0 -ENDBLK - 5 -A8 -330 -A6 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -AA -330 -A9 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D67 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D67 - 1 - - 0 -LINE - 5 -1D9 -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.727986019337 - 20 -1256.237604148744 - 11 -3316.727986019337 - 21 -1255.983161899994 - 0 -LINE - 5 -1DA -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.477986019337 - 20 -1256.237604148744 - 11 -3317.477986019337 - 21 -1255.983161899994 - 0 -LINE - 5 -1DB -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.727986019337 - 20 -1256.163161899994 - 11 -3317.477986019337 - 21 -1256.163161899994 - 0 -SOLID - 5 -1DC -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3316.727986019337 - 20 -1256.163161899994 - 30 -0 - 11 -3316.907986019337 - 21 -1256.193134395354 - 31 -0 - 12 -3316.907986019337 - 22 -1256.133189404634 - 32 -0 - 13 -3316.907986019337 - 23 -1256.133189404634 - 33 -0 - 0 -SOLID - 5 -1DD -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.477986019337 - 20 -1256.163161899994 - 30 -0 - 11 -3317.297986019337 - 21 -1256.133189404634 - 31 -0 - 12 -3317.297986019337 - 22 -1256.193134395354 - 32 -0 - 13 -3317.297986019337 - 23 -1256.193134395354 - 33 -0 - 0 -MTEXT - 5 -1DE -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3318.121860507742 - 20 -1256.163161899994 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.7500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -AB -330 -A9 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -AD -330 -AC -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D69 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D69 - 1 - - 0 -LINE - 5 -1DF -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1256.237604171695 - 11 -3352.938675249461 - 21 -1255.983161922944 - 0 -LINE - 5 -1E0 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.688675249461 - 20 -1256.237604171695 - 11 -3353.688675249461 - 21 -1255.983161922944 - 0 -LINE - 5 -1E1 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1256.163161922944 - 11 -3353.688675249461 - 21 -1256.163161922944 - 0 -SOLID - 5 -1E2 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3352.938675249461 - 20 -1256.163161922944 - 30 -0 - 11 -3353.118675249461 - 21 -1256.193134418304 - 31 -0 - 12 -3353.118675249461 - 22 -1256.133189427584 - 32 -0 - 13 -3353.118675249461 - 23 -1256.133189427584 - 33 -0 - 0 -SOLID - 5 -1E3 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3353.688675249461 - 20 -1256.163161922944 - 30 -0 - 11 -3353.508675249461 - 21 -1256.133189427584 - 31 -0 - 12 -3353.508675249461 - 22 -1256.193134418304 - 32 -0 - 13 -3353.508675249461 - 23 -1256.193134418304 - 33 -0 - 0 -MTEXT - 5 -1E4 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3354.332549737865 - 20 -1256.163161922944 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.7500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -AE -330 -AC -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -B0 -330 -AF -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D72 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D72 - 1 - - 0 -LINE - 5 -1E5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3441.644366980692 - 20 -1245.868946037968 - 11 -3440.694366980712 - 21 -1245.868946037968 - 0 -SOLID - 5 -1E6 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3441.284366980692 - 20 -1245.868946037968 - 30 -0 - 11 -3441.464366980692 - 21 -1245.898918533328 - 31 -0 - 12 -3441.464366980692 - 22 -1245.838973542608 - 32 -0 - 13 -3441.464366980692 - 23 -1245.838973542608 - 33 -0 - 0 -SOLID - 5 -1E7 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3441.054366980712 - 20 -1245.868946037968 - 30 -0 - 11 -3440.874366980712 - 21 -1245.838973542608 - 31 -0 - 12 -3440.874366980712 - 22 -1245.898918533328 - 32 -0 - 13 -3440.874366980712 - 23 -1245.898918533328 - 33 -0 - 0 -MTEXT - 5 -1E8 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3441.258357607955 - 20 -1245.996469469835 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.2300 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -1E9 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3441.284366980692 - 20 -1246.12440066169 - 11 -3441.284366980692 - 21 -1245.688946037968 - 0 -LINE - 5 -1EA -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3441.054366980712 - 20 -1246.12440066169 - 11 -3441.054366980712 - 21 -1245.688946037968 - 0 -ENDBLK - 5 -B1 -330 -AF -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -B3 -330 -B2 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D24 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D24 - 1 - - 0 -LINE - 5 -1EB -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3284.525130626578 - 20 -1245.052369962679 - 11 -3284.525130626578 - 21 -1244.482369962678 - 0 -SOLID - 5 -1EC -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3284.525130626578 - 20 -1245.052369962679 - 30 -0 - 11 -3284.555103121938 - 21 -1244.872369962679 - 31 -0 - 12 -3284.495158131218 - 22 -1244.872369962679 - 32 -0 - 13 -3284.495158131218 - 23 -1244.872369962679 - 33 -0 - 0 -SOLID - 5 -1ED -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3284.525130626578 - 20 -1243.552369962679 - 30 -0 - 11 -3284.495158131218 - 21 -1243.732369962679 - 31 -0 - 12 -3284.555103121938 - 22 -1243.732369962679 - 32 -0 - 13 -3284.555103121938 - 23 -1243.732369962679 - 33 -0 - 0 -LINE - 5 -1EE -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3284.525130626578 - 20 -1244.122369962678 - 11 -3284.525130626578 - 21 -1243.552369962679 - 0 -MTEXT - 5 -1EF -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3284.525130626578 - 20 -1244.302369962678 - 30 -0 - 40 -0.18 - 41 -0.6600000000000112 - 71 - 5 - 72 - 1 - 1 -1.5000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -1F0 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3284.699090456707 - 20 -1245.052369962679 - 11 -3284.345130626578 - 21 -1245.052369962679 - 0 -LINE - 5 -1F1 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3284.699090456707 - 20 -1243.552369962679 - 11 -3284.345130626578 - 21 -1243.552369962679 - 0 -ENDBLK - 5 -B4 -330 -B2 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -B6 -330 -B5 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D10 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D10 - 1 - - 0 -LINE - 5 -1F2 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3711.213270720591 - 20 -1109.577723062505 - 11 -3713.636973271638 - 21 -1109.602458632589 - 0 -LINE - 5 -1F3 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3710.973449366783 - 20 -1133.076499321015 - 11 -3713.397151917829 - 21 -1133.101234891099 - 0 -LINE - 5 -1F4 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3713.456982644965 - 20 -1109.60062170307 - 11 -3713.338895711574 - 21 -1121.17131122986 - 0 -SOLID - 5 -1F5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3713.456982644965 - 20 -1109.60062170307 - 30 -0 - 11 -3713.425174780876 - 21 -1109.780306455512 - 31 -0 - 12 -3713.485116650017 - 22 -1109.780918203973 - 32 -0 - 13 -3713.485116650017 - 23 -1109.780918203973 - 33 -0 - 0 -SOLID - 5 -1F6 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3713.217161291157 - 20 -1133.099397961581 - 30 -0 - 11 -3713.248969155246 - 21 -1132.919713209139 - 31 -0 - 12 -3713.189027286105 - 22 -1132.919101460678 - 32 -0 - 13 -3713.189027286105 - 23 -1132.919101460678 - 33 -0 - 0 -LINE - 5 -1F7 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3713.335221661214 - 20 -1121.53131122986 - 11 -3713.217161291157 - 21 -1133.099397961581 - 0 -MTEXT - 5 -1F8 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3713.464588759269 - 20 -1121.35131122986 - 30 -0 - 40 -0.18 - 41 -0.8400000000000225 - 71 - 5 - 72 - 1 - 1 -23.5000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -B7 -330 -B5 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -B9 -330 -B8 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D75 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D75 - 1 - - 0 -LINE - 5 -1F9 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3429.485147392643 - 20 -1247.812661133244 - 11 -3429.984339434687 - 21 -1247.812661133244 - 0 -LINE - 5 -1FA -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3429.984339434687 - 20 -1247.812661133244 - 11 -3429.984339434687 - 21 -1249.558370642658 - 0 -SOLID - 5 -1FB -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbTrace - 10 -3429.485147392643 - 20 -1247.812661133244 - 30 -0 - 11 -3429.665147392643 - 21 -1247.842633628604 - 31 -0 - 12 -3429.665147392643 - 22 -1247.782688637884 - 32 -0 - 13 -3429.665147392643 - 23 -1247.782688637884 - 33 -0 - 0 -ENDBLK - 5 -BA -330 -B8 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -BC -330 -BB -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D34 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D34 - 1 - - 0 -LINE - 5 -1FC -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.674476717278 - 20 -1243.552369962674 - 11 -3300.674476717278 - 21 -1243.132369416201 - 0 -SOLID - 5 -1FD -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.674476717278 - 20 -1243.552369962674 - 30 -0 - 11 -3300.704449212638 - 21 -1243.372369962674 - 31 -0 - 12 -3300.644504221918 - 22 -1243.372369962674 - 32 -0 - 13 -3300.644504221918 - 23 -1243.372369962674 - 33 -0 - 0 -SOLID - 5 -1FE -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.674476717278 - 20 -1242.352368869728 - 30 -0 - 11 -3300.644504221918 - 21 -1242.532368869728 - 31 -0 - 12 -3300.704449212638 - 22 -1242.532368869728 - 32 -0 - 13 -3300.704449212638 - 23 -1242.532368869728 - 33 -0 - 0 -LINE - 5 -1FF -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.674476717278 - 20 -1242.772369416201 - 11 -3300.674476717278 - 21 -1242.352368869728 - 0 -MTEXT - 5 -200 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3300.674476717278 - 20 -1242.952369416201 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -201 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.674476717258 - 20 -1243.552369962674 - 11 -3300.854476717278 - 21 -1243.552369962674 - 0 -LINE - 5 -202 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.673743364761 - 20 -1242.352368869728 - 11 -3300.854476717278 - 21 -1242.352368869728 - 0 -ENDBLK - 5 -BD -330 -BB -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -BF -330 -BE -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D28 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D28 - 1 - - 0 -LINE - 5 -203 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3283.253068378211 - 20 -1243.552369962679 - 11 -3283.253068378211 - 21 -1243.132369416206 - 0 -SOLID - 5 -204 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3283.253068378211 - 20 -1243.552369962679 - 30 -0 - 11 -3283.283040873571 - 21 -1243.372369962679 - 31 -0 - 12 -3283.223095882851 - 22 -1243.372369962679 - 32 -0 - 13 -3283.223095882851 - 23 -1243.372369962679 - 33 -0 - 0 -SOLID - 5 -205 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3283.253068378211 - 20 -1242.352368869733 - 30 -0 - 11 -3283.223095882851 - 21 -1242.532368869733 - 31 -0 - 12 -3283.283040873571 - 22 -1242.532368869733 - 32 -0 - 13 -3283.283040873571 - 23 -1242.532368869733 - 33 -0 - 0 -LINE - 5 -206 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3283.253068378211 - 20 -1242.772369416206 - 11 -3283.253068378211 - 21 -1242.352368869733 - 0 -MTEXT - 5 -207 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3283.253068378211 - 20 -1242.952369416206 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -208 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3283.253068378196 - 20 -1243.552369962679 - 11 -3283.433068378211 - 21 -1243.552369962679 - 0 -LINE - 5 -209 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3283.252335025697 - 20 -1242.352368869733 - 11 -3283.433068378211 - 21 -1242.352368869733 - 0 -ENDBLK - 5 -C0 -330 -BE -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -C2 -330 -C1 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D23 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D23 - 1 - - 0 -LINE - 5 -20A -100 -AcDbEntity - 8 -DIST_CL_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3702.902121539239 - 20 -1113.765732253328 - 11 -3703.831981610121 - 21 -1108.205644738318 - 0 -SOLID - 5 -20B -100 -AcDbEntity - 8 -DIST_CL_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3702.902121539239 - 20 -1113.765732253328 - 30 -0 - 11 -3702.961374051272 - 21 -1113.5931417255 - 31 -0 - 12 -3702.902250167273 - 22 -1113.583253942471 - 32 -0 - 13 -3702.902250167273 - 23 -1113.583253942471 - 33 -0 - 0 -SOLID - 5 -20C -100 -AcDbEntity - 8 -DIST_CL_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3704.822047500537 - 20 -1102.28555722331 - 30 -0 - 11 -3704.762794988505 - 21 -1102.458147751137 - 31 -0 - 12 -3704.821918872503 - 22 -1102.468035534166 - 32 -0 - 13 -3704.821918872503 - 23 -1102.468035534166 - 33 -0 - 0 -LINE - 5 -20D -100 -AcDbEntity - 8 -DIST_CL_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3703.892187429655 - 20 -1107.845644738318 - 11 -3704.822047500537 - 21 -1102.28555722331 - 0 -MTEXT - 5 -20E -100 -AcDbEntity - 8 -DIST_CL_ROAD - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3703.862084519889 - 20 -1108.025644738318 - 30 -0 - 40 -0.18 - 41 -0.7600000000000335 - 71 - 5 - 72 - 1 - 1 -11.6396 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -20F -100 -AcDbEntity - 8 -DIST_CL_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3702.961422993541 - 20 -1113.775649732927 - 11 -3702.724587119897 - 21 -1113.736041683294 - 0 -LINE - 5 -210 -100 -AcDbEntity - 8 -DIST_CL_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3704.82204750054 - 20 -1102.28555722331 - 11 -3704.644513081195 - 21 -1102.255866653276 - 0 -ENDBLK - 5 -C3 -330 -C1 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -C5 -330 -C4 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D31 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D31 - 1 - - 0 -LINE - 5 -211 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3301.124476731815 - 20 -1243.079906270047 - 11 -3300.224476731909 - 21 -1243.079906270047 - 0 -SOLID - 5 -212 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3301.124476731815 - 20 -1243.079906270047 - 30 -0 - 11 -3300.944476731815 - 21 -1243.049933774687 - 31 -0 - 12 -3300.944476731815 - 22 -1243.109878765407 - 32 -0 - 13 -3300.944476731815 - 23 -1243.109878765407 - 33 -0 - 0 -SOLID - 5 -213 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.224476731909 - 20 -1243.079906270047 - 30 -0 - 11 -3300.404476731909 - 21 -1243.109878765407 - 31 -0 - 12 -3300.404476731909 - 22 -1243.049933774687 - 32 -0 - 13 -3300.404476731909 - 23 -1243.049933774687 - 33 -0 - 0 -MTEXT - 5 -214 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3299.581154767381 - 20 -1243.079906270047 - 30 -0 - 40 -0.18 - 41 -0.7000000000000001 - 71 - 5 - 72 - 1 - 1 -0.9000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -215 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3301.124476731815 - 20 -1243.157187090806 - 11 -3301.124476731815 - 21 -1242.899906270047 - 0 -LINE - 5 -216 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.224476731909 - 20 -1243.157187090806 - 11 -3300.224476731909 - 21 -1242.899906270047 - 0 -ENDBLK - 5 -C6 -330 -C4 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -C8 -330 -C7 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D43 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D43 - 1 - - 0 -LINE - 5 -217 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3354.188675264084 - 20 -1243.079906270047 - 11 -3353.288675264177 - 21 -1243.079906270047 - 0 -SOLID - 5 -218 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3354.188675264084 - 20 -1243.079906270047 - 30 -0 - 11 -3354.008675264084 - 21 -1243.049933774687 - 31 -0 - 12 -3354.008675264084 - 22 -1243.109878765407 - 32 -0 - 13 -3354.008675264084 - 23 -1243.109878765407 - 33 -0 - 0 -SOLID - 5 -219 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3353.288675264177 - 20 -1243.079906270047 - 30 -0 - 11 -3353.468675264177 - 21 -1243.109878765407 - 31 -0 - 12 -3353.468675264177 - 22 -1243.049933774687 - 32 -0 - 13 -3353.468675264177 - 23 -1243.049933774687 - 33 -0 - 0 -MTEXT - 5 -21A -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3352.645353299648 - 20 -1243.079906270047 - 30 -0 - 40 -0.18 - 41 -0.7000000000000001 - 71 - 5 - 72 - 1 - 1 -0.9000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -21B -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3354.188675264084 - 20 -1243.157187090806 - 11 -3354.188675264084 - 21 -1242.899906270047 - 0 -LINE - 5 -21C -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.288675264177 - 20 -1243.157187090806 - 11 -3353.288675264177 - 21 -1242.899906270047 - 0 -ENDBLK - 5 -C9 -330 -C7 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -CB -330 -CA -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D82 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D82 - 1 - - 0 -LINE - 5 -21D -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3430.011031889974 - 20 -1246.989735042321 - 11 -3430.011031889974 - 21 -1246.49081901033 - 0 -SOLID - 5 -21E -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3430.011031889974 - 20 -1246.989735042321 - 30 -0 - 11 -3430.041004385334 - 21 -1246.809735042321 - 31 -0 - 12 -3429.981059394614 - 22 -1246.809735042321 - 32 -0 - 13 -3429.981059394614 - 23 -1246.809735042321 - 33 -0 - 0 -SOLID - 5 -21F -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3430.011031889974 - 20 -1245.631902978342 - 30 -0 - 11 -3429.981059394614 - 21 -1245.811902978342 - 31 -0 - 12 -3430.041004385334 - 22 -1245.811902978342 - 32 -0 - 13 -3430.041004385334 - 23 -1245.811902978342 - 33 -0 - 0 -LINE - 5 -220 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3430.011031889974 - 20 -1246.13081901033 - 11 -3430.011031889974 - 21 -1245.631902978342 - 0 -MTEXT - 5 -221 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3429.883508458106 - 20 -1246.31081901033 - 30 -0 - 40 -0.18 - 41 -0.6600000000000223 - 71 - 5 - 72 - 1 - 1 -1.3578 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -222 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3429.485147392643 - 20 -1246.989735042321 - 11 -3430.191031889974 - 21 -1246.989735042321 - 0 -LINE - 5 -223 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3429.485147392643 - 20 -1245.631902978342 - 11 -3430.191031889974 - 21 -1245.631902978342 - 0 -ENDBLK - 5 -CC -330 -CA -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -CE -330 -CD -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D66 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D66 - 1 - - 0 -LINE - 5 -224 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1245.414869962667 - 11 -3301.124476717087 - 21 -1246.400390913326 - 0 -LINE - 5 -225 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3302.324476717273 - 20 -1245.414869962667 - 11 -3302.324476717273 - 21 -1246.400390913326 - 0 -LINE - 5 -226 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1246.220390913326 - 11 -3301.30447671718 - 21 -1246.220390913326 - 0 -SOLID - 5 -227 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3301.124476717087 - 20 -1246.220390913326 - 30 -0 - 11 -3301.304476717087 - 21 -1246.250363408686 - 31 -0 - 12 -3301.304476717087 - 22 -1246.190418417966 - 32 -0 - 13 -3301.304476717087 - 23 -1246.190418417966 - 33 -0 - 0 -SOLID - 5 -228 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3302.324476717273 - 20 -1246.220390913326 - 30 -0 - 11 -3302.144476717273 - 21 -1246.190418417966 - 31 -0 - 12 -3302.144476717273 - 22 -1246.250363408686 - 32 -0 - 13 -3302.144476717273 - 23 -1246.250363408686 - 33 -0 - 0 -LINE - 5 -229 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3302.14447671718 - 20 -1246.220390913326 - 11 -3302.324476717273 - 21 -1246.220390913326 - 0 -MTEXT - 5 -22A -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3301.72447671718 - 20 -1246.220390913326 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -CF -330 -CD -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -D1 -330 -D0 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D44 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D44 - 1 - - 0 -LINE - 5 -22B -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.874667968283 - 20 -1243.552369962674 - 11 -3352.874667968284 - 21 -1245.022369962683 - 0 -SOLID - 5 -22C -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3352.874667968283 - 20 -1243.552369962674 - 30 -0 - 11 -3352.844695472923 - 21 -1243.732369962674 - 31 -0 - 12 -3352.904640463643 - 22 -1243.732369962674 - 32 -0 - 13 -3352.904640463643 - 23 -1243.732369962674 - 33 -0 - 0 -SOLID - 5 -22D -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3352.874667968283 - 20 -1246.852369962691 - 30 -0 - 11 -3352.904640463643 - 21 -1246.672369962691 - 31 -0 - 12 -3352.844695472923 - 22 -1246.672369962691 - 32 -0 - 13 -3352.844695472923 - 23 -1246.672369962691 - 33 -0 - 0 -LINE - 5 -22E -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.874667968284 - 20 -1245.382369962683 - 11 -3352.874667968283 - 21 -1246.852369962691 - 0 -MTEXT - 5 -22F -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3352.874667968283 - 20 -1245.202369962683 - 30 -0 - 40 -0.18 - 41 -0.7000000000000224 - 71 - 5 - 72 - 1 - 1 -3.3000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -230 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.874667968265 - 20 -1243.552369962674 - 11 -3352.694667968283 - 21 -1243.552369962674 - 0 -LINE - 5 -231 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.874667968265 - 20 -1246.852369962691 - 11 -3352.694667968283 - 21 -1246.852369962691 - 0 -ENDBLK - 5 -D2 -330 -D0 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -D4 -330 -D3 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D54 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D54 - 1 - - 0 -LINE - 5 -232 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.727986021899 - 20 -1258.430923504448 - 11 -3317.477986023528 - 21 -1258.430923504448 - 0 -SOLID - 5 -233 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3316.727986021899 - 20 -1258.430923504448 - 30 -0 - 11 -3316.907986021899 - 21 -1258.460895999808 - 31 -0 - 12 -3316.907986021899 - 22 -1258.400951009088 - 32 -0 - 13 -3316.907986021899 - 23 -1258.400951009088 - 33 -0 - 0 -SOLID - 5 -234 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.477986023528 - 20 -1258.430923504448 - 30 -0 - 11 -3317.297986023528 - 21 -1258.400951009088 - 31 -0 - 12 -3317.297986023528 - 22 -1258.460895999808 - 32 -0 - 13 -3317.297986023528 - 23 -1258.460895999808 - 33 -0 - 0 -MTEXT - 5 -235 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3318.121307988058 - 20 -1258.430923504448 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.7500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -236 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.727986021899 - 20 -1258.300104171694 - 11 -3316.727986021899 - 21 -1258.610923504448 - 0 -LINE - 5 -237 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.477986023528 - 20 -1258.300104171694 - 11 -3317.477986023528 - 21 -1258.610923504448 - 0 -ENDBLK - 5 -D5 -330 -D3 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -D7 -330 -D6 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D64 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D64 - 1 - - 0 -LINE - 5 -238 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1256.237604148744 - 11 -3299.874476717086 - 21 -1255.983161899994 - 0 -LINE - 5 -239 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.624476717086 - 20 -1256.237604148744 - 11 -3300.624476717086 - 21 -1255.983161899994 - 0 -LINE - 5 -23A -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1256.163161899994 - 11 -3300.624476717086 - 21 -1256.163161899994 - 0 -SOLID - 5 -23B -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3299.874476717086 - 20 -1256.163161899994 - 30 -0 - 11 -3300.054476717086 - 21 -1256.193134395354 - 31 -0 - 12 -3300.054476717086 - 22 -1256.133189404634 - 32 -0 - 13 -3300.054476717086 - 23 -1256.133189404634 - 33 -0 - 0 -SOLID - 5 -23C -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.624476717086 - 20 -1256.163161899994 - 30 -0 - 11 -3300.444476717086 - 21 -1256.133189404634 - 31 -0 - 12 -3300.444476717086 - 22 -1256.193134395354 - 32 -0 - 13 -3300.444476717086 - 23 -1256.193134395354 - 33 -0 - 0 -MTEXT - 5 -23D -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3301.268351205492 - 20 -1256.163161899994 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.7500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -D8 -330 -D6 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -DA -330 -D9 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D59 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D59 - 1 - - 0 -LINE - 5 -23E -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.774476718857 - 20 -1258.458460622718 - 11 -3299.02447671866 - 21 -1258.458460622718 - 0 -SOLID - 5 -23F -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3299.774476718857 - 20 -1258.458460622718 - 30 -0 - 11 -3299.594476718857 - 21 -1258.428488127358 - 31 -0 - 12 -3299.594476718857 - 22 -1258.488433118078 - 32 -0 - 13 -3299.594476718857 - 23 -1258.488433118078 - 33 -0 - 0 -SOLID - 5 -240 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3299.02447671866 - 20 -1258.458460622718 - 30 -0 - 11 -3299.20447671866 - 21 -1258.488433118078 - 31 -0 - 12 -3299.20447671866 - 22 -1258.428488127358 - 32 -0 - 13 -3299.20447671866 - 23 -1258.428488127358 - 33 -0 - 0 -MTEXT - 5 -241 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3298.381154754131 - 20 -1258.458460622718 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.7500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -242 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.774476718857 - 20 -1258.300104121969 - 11 -3299.774476718857 - 21 -1258.638460622718 - 0 -LINE - 5 -243 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.02447671866 - 20 -1258.300104121969 - 11 -3299.02447671866 - 21 -1258.638460622718 - 0 -ENDBLK - 5 -DB -330 -D9 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -DD -330 -DC -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D70 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D70 - 1 - - 0 -LINE - 5 -244 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1245.414869985618 - 11 -3354.188675249461 - 21 -1246.400390936277 - 0 -LINE - 5 -245 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3355.388675249648 - 20 -1245.414869985618 - 11 -3355.388675249648 - 21 -1246.400390936277 - 0 -LINE - 5 -246 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1246.220390936277 - 11 -3354.368675249555 - 21 -1246.220390936277 - 0 -SOLID - 5 -247 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3354.188675249461 - 20 -1246.220390936277 - 30 -0 - 11 -3354.368675249461 - 21 -1246.250363431637 - 31 -0 - 12 -3354.368675249461 - 22 -1246.190418440917 - 32 -0 - 13 -3354.368675249461 - 23 -1246.190418440917 - 33 -0 - 0 -SOLID - 5 -248 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3355.388675249648 - 20 -1246.220390936277 - 30 -0 - 11 -3355.208675249648 - 21 -1246.190418440917 - 31 -0 - 12 -3355.208675249648 - 22 -1246.250363431637 - 32 -0 - 13 -3355.208675249648 - 23 -1246.250363431637 - 33 -0 - 0 -LINE - 5 -249 -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3355.208675249555 - 20 -1246.220390936277 - 11 -3355.388675249648 - 21 -1246.220390936277 - 0 -MTEXT - 5 -24A -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3354.788675249555 - 20 -1246.220390936277 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -DE -330 -DC -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -E0 -330 -DF -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D1 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D1 - 1 - - 0 -LINE - 5 -24B -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3282.57882252615 - 20 -1242.352369962667 - 11 -3282.57882252615 - 21 -1241.332201593672 - 0 -LINE - 5 -24C -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3282.57882252615 - 20 -1241.332201593672 - 11 -3282.957429503091 - 21 -1241.332201593672 - 0 -SOLID - 5 -24D -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbTrace - 10 -3282.57882252615 - 20 -1242.352369962667 - 30 -0 - 11 -3282.60879502151 - 21 -1242.172369962667 - 31 -0 - 12 -3282.54885003079 - 22 -1242.172369962667 - 32 -0 - 13 -3282.54885003079 - 23 -1242.172369962667 - 33 -0 - 0 -ENDBLK - 5 -E1 -330 -DF -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -E3 -330 -E2 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D35 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D35 - 1 - - 0 -LINE - 5 -24E -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.024476717244 - 20 -1243.756682050019 - 11 -3299.204476717274 - 21 -1243.756682050019 - 0 -SOLID - 5 -24F -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3299.024476717244 - 20 -1243.756682050019 - 30 -0 - 11 -3299.204476717244 - 21 -1243.786654545379 - 31 -0 - 12 -3299.204476717244 - 22 -1243.726709554659 - 32 -0 - 13 -3299.204476717244 - 23 -1243.726709554659 - 33 -0 - 0 -SOLID - 5 -250 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.224476717306 - 20 -1243.756682050019 - 30 -0 - 11 -3300.044476717306 - 21 -1243.726709554659 - 31 -0 - 12 -3300.044476717306 - 22 -1243.786654545379 - 32 -0 - 13 -3300.044476717306 - 23 -1243.786654545379 - 33 -0 - 0 -LINE - 5 -251 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.044476717275 - 20 -1243.756682050019 - 11 -3300.224476717306 - 21 -1243.756682050019 - 0 -MTEXT - 5 -252 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3299.624476717275 - 20 -1243.756682050019 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -253 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.024476717244 - 20 -1245.952369962641 - 11 -3299.024476717244 - 21 -1243.576682050019 - 0 -LINE - 5 -254 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.224476717306 - 20 -1243.552370652369 - 11 -3300.224476717306 - 21 -1243.936682050019 - 0 -ENDBLK - 5 -E4 -330 -E2 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -E6 -330 -E5 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D86 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D86 - 1 - - 0 -LINE - 5 -255 -100 -AcDbEntity - 8 -BLK_1_HT_OF_BLDG - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3451.236564734482 - 20 -1259.886620183537 - 11 -3451.236564734482 - 21 -1253.616620184108 - 0 -SOLID - 5 -256 -100 -AcDbEntity - 8 -BLK_1_HT_OF_BLDG - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3451.236564734482 - 20 -1259.886620183537 - 30 -0 - 11 -3451.266537229842 - 21 -1259.706620183537 - 31 -0 - 12 -3451.206592239122 - 22 -1259.706620183537 - 32 -0 - 13 -3451.206592239122 - 23 -1259.706620183537 - 33 -0 - 0 -SOLID - 5 -257 -100 -AcDbEntity - 8 -BLK_1_HT_OF_BLDG - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3451.236564734482 - 20 -1246.986620184678 - 30 -0 - 11 -3451.206592239122 - 21 -1247.166620184678 - 31 -0 - 12 -3451.266537229842 - 22 -1247.166620184678 - 32 -0 - 13 -3451.266537229842 - 23 -1247.166620184678 - 33 -0 - 0 -LINE - 5 -258 -100 -AcDbEntity - 8 -BLK_1_HT_OF_BLDG - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3451.236564734482 - 20 -1253.256620184108 - 11 -3451.236564734482 - 21 -1246.986620184678 - 0 -MTEXT - 5 -259 -100 -AcDbEntity - 8 -BLK_1_HT_OF_BLDG - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3451.236564734482 - 20 -1253.436620184108 - 30 -0 - 40 -0.18 - 41 -0.8 - 71 - 5 - 72 - 1 - 1 -12.9000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -25A -100 -AcDbEntity - 8 -BLK_1_HT_OF_BLDG - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3448.489835352904 - 20 -1259.886620183537 - 11 -3451.416564734482 - 21 -1259.886620183537 - 0 -LINE - 5 -25B -100 -AcDbEntity - 8 -BLK_1_HT_OF_BLDG - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3453.888227601801 - 20 -1246.986620184678 - 11 -3451.056564734482 - 21 -1246.986620184678 - 0 -ENDBLK - 5 -E7 -330 -E5 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -E9 -330 -E8 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D88 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D88 - 1 - - 0 -LINE - 5 -25C -100 -AcDbEntity - 8 -BLK_1_FLR_-1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3439.277894900691 - 20 -1245.78662018356 - 11 -3439.395394900698 - 21 -1245.78662018356 - 0 -LINE - 5 -25D -100 -AcDbEntity - 8 -BLK_1_FLR_-1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3439.277894900691 - 20 -1248.23662018351 - 11 -3439.395394900698 - 21 -1248.23662018351 - 0 -LINE - 5 -25E -100 -AcDbEntity - 8 -BLK_1_FLR_-1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3439.215394900698 - 20 -1245.78662018356 - 11 -3439.215394900698 - 21 -1246.831620183534 - 0 -SOLID - 5 -25F -100 -AcDbEntity - 8 -BLK_1_FLR_-1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3439.215394900698 - 20 -1245.78662018356 - 30 -0 - 11 -3439.185422405338 - 21 -1245.96662018356 - 31 -0 - 12 -3439.245367396058 - 22 -1245.96662018356 - 32 -0 - 13 -3439.245367396058 - 23 -1245.96662018356 - 33 -0 - 0 -SOLID - 5 -260 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3439.215394900698 - 20 -1248.23662018351 - 30 -0 - 11 -3439.245367396058 - 21 -1248.05662018351 - 31 -0 - 12 -3439.185422405338 - 22 -1248.05662018351 - 32 -0 - 13 -3439.185422405338 - 23 -1248.05662018351 - 33 -0 - 0 -LINE - 5 -261 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3439.215394900698 - 20 -1247.191620183534 - 11 -3439.215394900698 - 21 -1248.23662018351 - 0 -MTEXT - 5 -262 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_HT_ROOM - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3439.215394900697 - 20 -1247.011620183534 - 30 -0 - 40 -0.18 - 41 -0.7200000000000111 - 71 - 5 - 72 - 1 - 1 -2.4500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -EA -330 -E8 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -EC -330 -EB -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D61 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D61 - 1 - - 0 -LINE - 5 -263 -100 -AcDbEntity - 8 -DA_PARKING - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3702.98678187502 - 20 -1113.718525507621 - 11 -3703.232053030336 - 21 -1113.166019878484 - 0 -LINE - 5 -264 -100 -AcDbEntity - 8 -DA_PARKING - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3705.84649103904 - 20 -1114.988022384279 - 11 -3706.091762194356 - 21 -1114.435516755143 - 0 -LINE - 5 -265 -100 -AcDbEntity - 8 -DA_PARKING - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3703.159019451676 - 20 -1113.330537647701 - 11 -3704.183400291301 - 21 -1113.78528608603 - 0 -SOLID - 5 -266 -100 -AcDbEntity - 8 -DA_PARKING - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3703.159019451676 - 20 -1113.330537647701 - 30 -0 - 11 -3703.311376117573 - 21 -1113.430965715663 - 31 -0 - 12 -3703.335698324212 - 22 -1113.376176737059 - 32 -0 - 13 -3703.335698324212 - 23 -1113.376176737059 - 33 -0 - 0 -SOLID - 5 -267 -100 -AcDbEntity - 8 -DA_PARKING - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3706.018728615696 - 20 -1114.60003452436 - 30 -0 - 11 -3705.866371949798 - 21 -1114.499606456397 - 31 -0 - 12 -3705.842049743159 - 22 -1114.554395435002 - 32 -0 - 13 -3705.842049743159 - 23 -1114.554395435002 - 33 -0 - 0 -LINE - 5 -268 -100 -AcDbEntity - 8 -DA_PARKING - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3704.99434777607 - 20 -1114.14528608603 - 11 -3706.018728615696 - 21 -1114.60003452436 - 0 -MTEXT - 5 -269 -100 -AcDbEntity - 8 -DA_PARKING - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3704.588874033686 - 20 -1113.96528608603 - 30 -0 - 40 -0.18 - 41 -0.6600000000000112 - 71 - 5 - 72 - 1 - 1 -3.1288 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -ED -330 -EB -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -EF -330 -EE -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D19 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D19 - 1 - - 0 -LINE - 5 -26A -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3724.301952987811 - 20 -1119.259218588684 - 11 -3724.845406284076 - 21 -1116.009645903309 - 0 -SOLID - 5 -26B -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3724.301952987811 - 20 -1119.259218588684 - 30 -0 - 11 -3724.361205499843 - 21 -1119.086628060856 - 31 -0 - 12 -3724.302081615844 - 22 -1119.076740277828 - 32 -0 - 13 -3724.302081615844 - 23 -1119.076740277828 - 33 -0 - 0 -SOLID - 5 -26C -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3725.456101013639 - 20 -1112.358003846994 - 30 -0 - 11 -3725.396848501607 - 21 -1112.530594374822 - 31 -0 - 12 -3725.455972385605 - 22 -1112.54048215785 - 32 -0 - 13 -3725.455972385605 - 23 -1112.54048215785 - 33 -0 - 0 -LINE - 5 -26D -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3724.90561210361 - 20 -1115.649645903309 - 11 -3725.456101013639 - 21 -1112.358003846994 - 0 -MTEXT - 5 -26E -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3725.004803658664 - 20 -1115.829645903309 - 30 -0 - 40 -0.18 - 41 -0.6600000000000112 - 71 - 5 - 72 - 1 - 1 -6.9971 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -26F -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3724.30195298597 - 20 -1119.259218588376 - 11 -3724.124418568469 - 21 -1119.229528018651 - 0 -LINE - 5 -270 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3725.466256737647 - 20 -1112.359702273902 - 11 -3725.278566594297 - 21 -1112.328313276961 - 0 -ENDBLK - 5 -F0 -330 -EE -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -F2 -330 -F1 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D65 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D65 - 1 - - 0 -LINE - 5 -271 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3304.02812267073 - 20 -1243.701237554058 - 11 -3304.02812267073 - 21 -1243.853737554059 - 0 -LINE - 5 -272 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3307.031947087351 - 20 -1243.701237554058 - 11 -3307.031947087351 - 21 -1243.853737554059 - 0 -LINE - 5 -273 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3304.02812267073 - 20 -1243.673737554059 - 11 -3305.090034879041 - 21 -1243.673737554059 - 0 -SOLID - 5 -274 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3304.02812267073 - 20 -1243.673737554059 - 30 -0 - 11 -3304.20812267073 - 21 -1243.703710049419 - 31 -0 - 12 -3304.20812267073 - 22 -1243.643765058699 - 32 -0 - 13 -3304.20812267073 - 23 -1243.643765058699 - 33 -0 - 0 -SOLID - 5 -275 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3307.031947087351 - 20 -1243.673737554059 - 30 -0 - 11 -3306.851947087351 - 21 -1243.643765058699 - 31 -0 - 12 -3306.851947087351 - 22 -1243.703710049419 - 32 -0 - 13 -3306.851947087351 - 23 -1243.703710049419 - 33 -0 - 0 -LINE - 5 -276 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3305.970034879041 - 20 -1243.673737554059 - 11 -3307.031947087351 - 21 -1243.673737554059 - 0 -MTEXT - 5 -277 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_DOOR - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3305.530034879041 - 20 -1243.673737554059 - 30 -0 - 40 -0.18 - 41 -0.7000000000000224 - 71 - 5 - 72 - 1 - 1 -3.0038 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -F3 -330 -F1 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -F5 -330 -F4 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D89 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D89 - 1 - - 0 -LINE - 5 -278 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3663.24658949637 - 20 -1160.007065680477 - 11 -3662.397645356614 - 21 -1160.006700188826 - 0 -LINE - 5 -279 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3663.2576970396 - 20 -1134.207068071412 - 11 -3662.408752899844 - 21 -1134.206702579761 - 0 -LINE - 5 -27A -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3662.577645339932 - 20 -1160.006777683313 - 11 -3662.583121593416 - 21 -1147.286833780797 - 0 -SOLID - 5 -27B -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3662.577645339932 - 20 -1160.006777683313 - 30 -0 - 11 -3662.607695327002 - 21 -1159.826790603901 - 31 -0 - 12 -3662.547750341838 - 22 -1159.826764796088 - 32 -0 - 13 -3662.547750341838 - 23 -1159.826764796088 - 33 -0 - 0 -SOLID - 5 -27C -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3662.588752883162 - 20 -1134.206780074248 - 30 -0 - 11 -3662.558702896093 - 21 -1134.38676715366 - 31 -0 - 12 -3662.618647881256 - 22 -1134.386792961473 - 32 -0 - 13 -3662.618647881256 - 23 -1134.386792961473 - 33 -0 - 0 -LINE - 5 -27D -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3662.583276582406 - 20 -1146.926833780797 - 11 -3662.588752883162 - 21 -1134.206780074248 - 0 -MTEXT - 5 -27E -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3662.710722531596 - 20 -1147.106833780797 - 30 -0 - 40 -0.18 - 41 -0.8400000000000114 - 71 - 5 - 72 - 1 - 1 -25.8000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -F6 -330 -F4 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -F8 -330 -F7 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D12 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D12 - 1 - - 0 -LINE - 5 -27F -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3701.424551457872 - 20 -1133.220728919789 - 11 -3701.542051457873 - 21 -1133.220728919789 - 0 -LINE - 5 -280 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3698.108545772997 - 20 -1107.029812435309 - 11 -3698.226045772998 - 21 -1107.029812435309 - 0 -LINE - 5 -281 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3701.362051457873 - 20 -1133.220728919789 - 11 -3699.728866225455 - 21 -1120.321288420921 - 0 -SOLID - 5 -282 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3701.362051457873 - 20 -1133.220728919789 - 30 -0 - 11 -3701.369177446491 - 21 -1133.03838975569 - 31 -0 - 12 -3701.309707209915 - 22 -1133.045919222736 - 32 -0 - 13 -3701.309707209915 - 23 -1133.045919222736 - 33 -0 - 0 -SOLID - 5 -283 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3698.046045772998 - 20 -1107.029812435309 - 30 -0 - 11 -3698.03891978438 - 21 -1107.212151599408 - 31 -0 - 12 -3698.098390020955 - 22 -1107.204622132362 - 32 -0 - 13 -3698.098390020955 - 23 -1107.204622132362 - 33 -0 - 0 -LINE - 5 -284 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3699.683286986284 - 20 -1119.961288420921 - 11 -3698.046045772998 - 21 -1107.029812435309 - 0 -MTEXT - 5 -285 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3699.577535147486 - 20 -1120.141288420921 - 30 -0 - 40 -0.18 - 41 -0.8600000000000113 - 71 - 5 - 72 - 1 - 1 -26.4000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -F9 -330 -F7 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -FB -330 -FA -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D63 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D63 - 1 - - 0 -LINE - 5 -286 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3283.703350468274 - 20 -1245.114869326077 - 11 -3283.706205478426 - 21 -1245.747420061637 - 0 -LINE - 5 -287 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3284.903326022838 - 20 -1245.109453250817 - 11 -3284.906181032989 - 21 -1245.742003986377 - 0 -LINE - 5 -288 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3283.705393058862 - 20 -1245.567421895051 - 11 -3283.885380836144 - 21 -1245.566609522379 - 0 -SOLID - 5 -289 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3283.705393058862 - 20 -1245.567421895051 - 30 -0 - 11 -3283.885526504568 - 21 -1245.596581665558 - 31 -0 - 12 -3283.885255946328 - 22 -1245.536637285416 - 32 -0 - 13 -3283.885255946328 - 23 -1245.536637285416 - 33 -0 - 0 -SOLID - 5 -28A -100 -AcDbEntity - 8 -BLK_1_FLR_-1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3284.905368613425 - 20 -1245.562005819791 - 30 -0 - 11 -3284.725235167718 - 21 -1245.532846049284 - 31 -0 - 12 -3284.725505725959 - 22 -1245.592790429426 - 32 -0 - 13 -3284.725505725959 - 23 -1245.592790429426 - 33 -0 - 0 -LINE - 5 -28B -100 -AcDbEntity - 8 -BLK_1_FLR_-1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3284.725380836144 - 20 -1245.562818192463 - 11 -3284.905368613425 - 21 -1245.562005819791 - 0 -MTEXT - 5 -28C -100 -AcDbEntity - 8 -BLK_1_FLR_-1_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3284.305380836144 - 20 -1245.564713857421 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -FC -330 -FA -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -FE -330 -FD -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D50 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D50 - 1 - - 0 -LINE - 5 -28D -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1258.430923504448 - 11 -3353.688675251091 - 21 -1258.430923504448 - 0 -SOLID - 5 -28E -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3352.938675249461 - 20 -1258.430923504448 - 30 -0 - 11 -3353.118675249461 - 21 -1258.460895999808 - 31 -0 - 12 -3353.118675249461 - 22 -1258.400951009088 - 32 -0 - 13 -3353.118675249461 - 23 -1258.400951009088 - 33 -0 - 0 -SOLID - 5 -28F -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3353.688675251091 - 20 -1258.430923504448 - 30 -0 - 11 -3353.508675251091 - 21 -1258.400951009088 - 31 -0 - 12 -3353.508675251091 - 22 -1258.460895999808 - 32 -0 - 13 -3353.508675251091 - 23 -1258.460895999808 - 33 -0 - 0 -MTEXT - 5 -290 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3354.33199721562 - 20 -1258.430923504448 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.7500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -291 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1258.300104171694 - 11 -3352.938675249461 - 21 -1258.610923504448 - 0 -LINE - 5 -292 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.688675251091 - 20 -1258.300104171694 - 11 -3353.688675251091 - 21 -1258.610923504448 - 0 -ENDBLK - 5 -FF -330 -FD -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -101 -330 -100 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D39 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D39 - 1 - - 0 -LINE - 5 -293 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.977986022132 - 20 -1245.809053745033 - 11 -3318.157986022108 - 21 -1245.809053745033 - 0 -SOLID - 5 -294 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.977986022132 - 20 -1245.809053745033 - 30 -0 - 11 -3318.157986022132 - 21 -1245.839026240393 - 31 -0 - 12 -3318.157986022132 - 22 -1245.779081249673 - 32 -0 - 13 -3318.157986022132 - 23 -1245.779081249673 - 33 -0 - 0 -SOLID - 5 -295 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3319.177986022085 - 20 -1245.809053745033 - 30 -0 - 11 -3318.997986022085 - 21 -1245.779081249673 - 31 -0 - 12 -3318.997986022085 - 22 -1245.839026240393 - 32 -0 - 13 -3318.997986022085 - 23 -1245.839026240393 - 33 -0 - 0 -LINE - 5 -296 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3318.997986022108 - 20 -1245.809053745033 - 11 -3319.177986022085 - 21 -1245.809053745033 - 0 -MTEXT - 5 -297 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3318.577986022108 - 20 -1245.809053745033 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -298 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.977986022132 - 20 -1245.652369962656 - 11 -3317.977986022132 - 21 -1245.989053745033 - 0 -LINE - 5 -299 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3319.177986022085 - 20 -1245.652369962656 - 11 -3319.177986022085 - 21 -1245.989053745033 - 0 -ENDBLK - 5 -102 -330 -100 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -104 -330 -103 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D71 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D71 - 1 - - 0 -LINE - 5 -29A -100 -AcDbEntity - 8 -BLK_1_FLR_3_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3372.972164166813 - 20 -1255.730104163693 - 11 -3373.152164166811 - 21 -1255.730104163693 - 0 -SOLID - 5 -29B -100 -AcDbEntity - 8 -BLK_1_FLR_3_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3372.972164166813 - 20 -1255.730104163693 - 30 -0 - 11 -3373.152164166813 - 21 -1255.760076659053 - 31 -0 - 12 -3373.152164166813 - 22 -1255.700131668333 - 32 -0 - 13 -3373.152164166813 - 23 -1255.700131668333 - 33 -0 - 0 -SOLID - 5 -29C -100 -AcDbEntity - 8 -BLK_1_FLR_3_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3374.172164166812 - 20 -1255.730104163693 - 30 -0 - 11 -3373.992164166812 - 21 -1255.700131668333 - 31 -0 - 12 -3373.992164166812 - 22 -1255.760076659053 - 32 -0 - 13 -3373.992164166812 - 23 -1255.760076659053 - 33 -0 - 0 -LINE - 5 -29D -100 -AcDbEntity - 8 -BLK_1_FLR_3_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3373.992164166812 - 20 -1255.730104163693 - 11 -3374.172164166812 - 21 -1255.730104163693 - 0 -MTEXT - 5 -29E -100 -AcDbEntity - 8 -BLK_1_FLR_3_EXIT_WIDTH_DOOR - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3373.572164166812 - 20 -1255.730104163693 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -29F -100 -AcDbEntity - 8 -BLK_1_FLR_3_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3372.972164166813 - 20 -1255.550104162563 - 11 -3372.972164166813 - 21 -1255.910104163693 - 0 -LINE - 5 -2A0 -100 -AcDbEntity - 8 -BLK_1_FLR_3_EXIT_WIDTH_DOOR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3374.172164166812 - 20 -1255.730104162563 - 11 -3374.172164166812 - 21 -1255.910104163693 - 0 -ENDBLK - 5 -105 -330 -103 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -107 -330 -106 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D80 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D80 - 1 - - 0 -LINE - 5 -2A1 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369113 - 20 -1246.986620183514 - 11 -3427.522237369113 - 21 -1246.566620183537 - 0 -SOLID - 5 -2A2 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3427.522237369113 - 20 -1246.986620183514 - 30 -0 - 11 -3427.552209864473 - 21 -1246.806620183514 - 31 -0 - 12 -3427.492264873753 - 22 -1246.806620183514 - 32 -0 - 13 -3427.492264873753 - 23 -1246.806620183514 - 33 -0 - 0 -SOLID - 5 -2A3 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3427.522237369113 - 20 -1245.78662018356 - 30 -0 - 11 -3427.492264873753 - 21 -1245.96662018356 - 31 -0 - 12 -3427.552209864473 - 22 -1245.96662018356 - 32 -0 - 13 -3427.552209864473 - 23 -1245.96662018356 - 33 -0 - 0 -LINE - 5 -2A4 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369113 - 20 -1246.206620183537 - 11 -3427.522237369113 - 21 -1245.78662018356 - 0 -MTEXT - 5 -2A5 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3427.394713937245 - 20 -1246.386620183537 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2A6 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.76242944449 - 20 -1246.986620183514 - 11 -3427.342237369113 - 21 -1246.986620183514 - 0 -LINE - 5 -2A7 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.671571185602 - 20 -1245.78662018356 - 11 -3427.342237369113 - 21 -1245.78662018356 - 0 -ENDBLK - 5 -108 -330 -106 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -10A -330 -109 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D48 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D48 - 1 - - 0 -LINE - 5 -2A8 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.434456956947 - 20 -1258.300104171694 - 11 -3353.434456956947 - 21 -1257.480104146831 - 0 -SOLID - 5 -2A9 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3353.434456956947 - 20 -1258.300104171694 - 30 -0 - 11 -3353.464429452307 - 21 -1258.120104171694 - 31 -0 - 12 -3353.404484461587 - 22 -1258.120104171694 - 32 -0 - 13 -3353.404484461587 - 23 -1258.120104171694 - 33 -0 - 0 -SOLID - 5 -2AA -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3353.434456956947 - 20 -1256.300104121969 - 30 -0 - 11 -3353.404484461587 - 21 -1256.480104121969 - 31 -0 - 12 -3353.464429452307 - 22 -1256.480104121969 - 32 -0 - 13 -3353.464429452307 - 23 -1256.480104121969 - 33 -0 - 0 -LINE - 5 -2AB -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.434456956947 - 20 -1257.120104146831 - 11 -3353.434456956947 - 21 -1256.300104121969 - 0 -MTEXT - 5 -2AC -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3353.434456956946 - 20 -1257.300104146831 - 30 -0 - 40 -0.18 - 41 -0.7000000000000001 - 71 - 5 - 72 - 1 - 1 -2.0000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2AD -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.313675250895 - 20 -1258.300104171694 - 11 -3353.614456956947 - 21 -1258.300104171694 - 0 -LINE - 5 -2AE -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.313675250895 - 20 -1256.300104121969 - 11 -3353.614456956947 - 21 -1256.300104121969 - 0 -ENDBLK - 5 -10B -330 -109 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -10D -330 -10C -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D4 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D4 - 1 - - 0 -LINE - 5 -2AF -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3281.373068378307 - 20 -1257.052749413065 - 11 -3286.751803563298 - 21 -1257.052749413065 - 0 -SOLID - 5 -2B0 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3281.373068378307 - 20 -1257.052749413065 - 30 -0 - 11 -3281.553068378307 - 21 -1257.082721908425 - 31 -0 - 12 -3281.553068378307 - 22 -1257.022776917705 - 32 -0 - 13 -3281.553068378307 - 23 -1257.022776917705 - 33 -0 - 0 -SOLID - 5 -2B1 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3293.070538748289 - 20 -1257.052749413065 - 30 -0 - 11 -3292.890538748289 - 21 -1257.022776917705 - 31 -0 - 12 -3292.890538748289 - 22 -1257.082721908425 - 32 -0 - 13 -3292.890538748289 - 23 -1257.082721908425 - 33 -0 - 0 -LINE - 5 -2B2 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3287.691803563298 - 20 -1257.052749413065 - 11 -3293.070538748289 - 21 -1257.052749413065 - 0 -MTEXT - 5 -2B3 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3287.221803563298 - 20 -1257.180272844932 - 30 -0 - 40 -0.18 - 41 -0.7600000000000224 - 71 - 5 - 72 - 1 - 1 -11.6975 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2B4 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3281.373068378307 - 20 -1258.780104148725 - 11 -3281.373068378307 - 21 -1256.872749413065 - 0 -LINE - 5 -2B5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3293.070538748289 - 20 -1259.050104148744 - 11 -3293.070538748289 - 21 -1256.872749413065 - 0 -ENDBLK - 5 -10E -330 -10C -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -110 -330 -10F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D84 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D84 - 1 - - 0 -LINE - 5 -2B6 -100 -AcDbEntity - 8 -BLK_1_FLR_1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3439.379987518114 - 20 -1252.686620183584 - 11 -3439.379987518114 - 21 -1254.306620183572 - 0 -SOLID - 5 -2B7 -100 -AcDbEntity - 8 -BLK_1_FLR_1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3439.379987518114 - 20 -1252.686620183584 - 30 -0 - 11 -3439.350015022754 - 21 -1252.866620183584 - 31 -0 - 12 -3439.409960013474 - 22 -1252.866620183584 - 32 -0 - 13 -3439.409960013474 - 23 -1252.866620183584 - 33 -0 - 0 -SOLID - 5 -2B8 -100 -AcDbEntity - 8 -BLK_1_FLR_1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3439.379987518114 - 20 -1256.28662018356 - 30 -0 - 11 -3439.409960013474 - 21 -1256.10662018356 - 31 -0 - 12 -3439.350015022754 - 22 -1256.10662018356 - 32 -0 - 13 -3439.350015022754 - 23 -1256.10662018356 - 33 -0 - 0 -LINE - 5 -2B9 -100 -AcDbEntity - 8 -BLK_1_FLR_1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3439.379987518114 - 20 -1254.666620183572 - 11 -3439.379987518114 - 21 -1256.28662018356 - 0 -MTEXT - 5 -2BA -100 -AcDbEntity - 8 -BLK_1_FLR_1_HT_ROOM - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3439.379987518114 - 20 -1254.486620183572 - 30 -0 - 40 -0.18 - 41 -0.7000000000000224 - 71 - 5 - 72 - 1 - 1 -3.6000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2BB -100 -AcDbEntity - 8 -BLK_1_FLR_1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3439.078499989153 - 20 -1252.686620183584 - 11 -3439.559987518114 - 21 -1252.686620183584 - 0 -LINE - 5 -2BC -100 -AcDbEntity - 8 -BLK_1_FLR_1_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3440.061276775585 - 20 -1256.28662018356 - 11 -3439.199987518114 - 21 -1256.28662018356 - 0 -ENDBLK - 5 -111 -330 -10F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -113 -330 -112 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D74 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D74 - 1 - - 0 -LINE - 5 -2BD -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3429.255147392662 - 20 -1248.186620183525 - 11 -3429.255147392662 - 21 -1249.055130511409 - 0 -LINE - 5 -2BE -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3429.255147392662 - 20 -1249.055130511409 - 11 -3428.107193445356 - 21 -1249.055130511409 - 0 -SOLID - 5 -2BF -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbTrace - 10 -3429.255147392662 - 20 -1248.186620183525 - 30 -0 - 11 -3429.225174897302 - 21 -1248.366620183525 - 31 -0 - 12 -3429.285119888022 - 22 -1248.366620183525 - 32 -0 - 13 -3429.285119888022 - 23 -1248.366620183525 - 33 -0 - 0 -ENDBLK - 5 -114 -330 -112 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -116 -330 -115 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D13 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D13 - 1 - - 0 -LINE - 5 -2C0 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3698.10208704836 - 20 -1106.992141264977 - 11 -3698.20744350217 - 21 -1106.940119464575 - 0 -LINE - 5 -2C1 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3710.966993896774 - 20 -1133.038190327934 - 11 -3711.072350350584 - 21 -1132.986168527533 - 0 -LINE - 5 -2C2 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3698.046046381887 - 20 -1107.019812435183 - 11 -3704.417486820407 - 21 -1119.919311220429 - 0 -SOLID - 5 -2C3 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3698.046046381887 - 20 -1107.019812435183 - 30 -0 - 11 -3698.098886937757 - 21 -1107.194472751607 - 31 -0 - 12 -3698.15263324307 - 22 -1107.167925876508 - 32 -0 - 13 -3698.15263324307 - 23 -1107.167925876508 - 33 -0 - 0 -SOLID - 5 -2C4 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3710.910953230301 - 20 -1133.06586149814 - 30 -0 - 11 -3710.858112674431 - 21 -1132.891201181716 - 31 -0 - 12 -3710.804366369118 - 22 -1132.917748056815 - 32 -0 - 13 -3710.804366369118 - 23 -1132.917748056815 - 33 -0 - 0 -LINE - 5 -2C5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3704.595301369333 - 20 -1120.279311220429 - 11 -3710.910953230301 - 21 -1133.06586149814 - 0 -MTEXT - 5 -2C6 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3704.36416309136 - 20 -1120.099311220429 - 30 -0 - 40 -0.18 - 41 -0.8400000000000112 - 71 - 5 - 72 - 1 - 1 -29.0500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -117 -330 -115 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -119 -330 -118 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D30 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D30 - 1 - - 0 -LINE - 5 -2C7 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3301.94653896565 - 20 -1245.652369962656 - 11 -3301.94653896565 - 21 -1244.782369962665 - 0 -SOLID - 5 -2C8 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3301.94653896565 - 20 -1245.652369962656 - 30 -0 - 11 -3301.97651146101 - 21 -1245.472369962656 - 31 -0 - 12 -3301.91656647029 - 22 -1245.472369962656 - 32 -0 - 13 -3301.91656647029 - 23 -1245.472369962656 - 33 -0 - 0 -SOLID - 5 -2C9 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3301.94653896565 - 20 -1243.552369962674 - 30 -0 - 11 -3301.91656647029 - 21 -1243.732369962674 - 31 -0 - 12 -3301.97651146101 - 22 -1243.732369962674 - 32 -0 - 13 -3301.97651146101 - 23 -1243.732369962674 - 33 -0 - 0 -LINE - 5 -2CA -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3301.94653896565 - 20 -1244.422369962665 - 11 -3301.94653896565 - 21 -1243.552369962674 - 0 -MTEXT - 5 -2CB -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3301.94653896565 - 20 -1244.602369962665 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -2.1000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2CC -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3302.120498795771 - 20 -1245.652369962656 - 11 -3301.76653896565 - 21 -1245.652369962656 - 0 -LINE - 5 -2CD -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3302.120498795771 - 20 -1243.552369962674 - 11 -3301.76653896565 - 21 -1243.552369962674 - 0 -ENDBLK - 5 -11A -330 -118 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -11C -330 -11B -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D26 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D26 - 1 - - 0 -LINE - 5 -2CE -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3282.378710914939 - 20 -1243.552369962679 - 11 -3282.378710914939 - 21 -1244.572369962662 - 0 -SOLID - 5 -2CF -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3282.378710914939 - 20 -1243.552369962679 - 30 -0 - 11 -3282.348738419579 - 21 -1243.732369962679 - 31 -0 - 12 -3282.408683410299 - 22 -1243.732369962679 - 32 -0 - 13 -3282.408683410299 - 23 -1243.732369962679 - 33 -0 - 0 -SOLID - 5 -2D0 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3282.378710914939 - 20 -1245.952369962645 - 30 -0 - 11 -3282.408683410299 - 21 -1245.772369962645 - 31 -0 - 12 -3282.348738419579 - 22 -1245.772369962645 - 32 -0 - 13 -3282.348738419579 - 23 -1245.772369962645 - 33 -0 - 0 -LINE - 5 -2D1 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3282.378710914939 - 20 -1244.932369962662 - 11 -3282.378710914939 - 21 -1245.952369962645 - 0 -MTEXT - 5 -2D2 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3282.378710914938 - 20 -1244.752369962662 - 30 -0 - 40 -0.18 - 41 -0.72 - 71 - 5 - 72 - 1 - 1 -2.4000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2D3 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3282.378710914928 - 20 -1243.552369962679 - 11 -3282.198710914939 - 21 -1243.552369962679 - 0 -LINE - 5 -2D4 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3282.378710914933 - 20 -1245.952369962645 - 11 -3282.198710914939 - 21 -1245.952369962645 - 0 -ENDBLK - 5 -11D -330 -11B -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -11F -330 -11E -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D90 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D90 - 1 - - 0 -LINE - 5 -2D5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3666.628909456082 - 20 -1160.460084471688 - 11 -3666.532014407246 - 21 -1161.284758896472 - 0 -LINE - 5 -2D6 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3663.301796227977 - 20 -1160.069165596273 - 11 -3663.204901179141 - 21 -1160.893840021057 - 0 -LINE - 5 -2D7 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3666.553019003537 - 20 -1161.105988633468 - 11 -3665.314581399462 - 21 -1160.960478516359 - 0 -SOLID - 5 -2D8 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3666.553019003537 - 20 -1161.105988633468 - 30 -0 - 11 -3666.377746297004 - 21 -1161.055216310075 - 31 -0 - 12 -3666.370751184061 - 22 -1161.114751764279 - 32 -0 - 13 -3666.370751184061 - 23 -1161.114751764279 - 33 -0 - 0 -SOLID - 5 -2D9 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3663.225905775432 - 20 -1160.715069758053 - 30 -0 - 11 -3663.401178481965 - 21 -1160.765842081446 - 31 -0 - 12 -3663.408173594908 - 22 -1160.706306627242 - 32 -0 - 13 -3663.408173594908 - 23 -1160.706306627242 - 33 -0 - 0 -LINE - 5 -2DA -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3664.435418966782 - 20 -1160.857181403839 - 11 -3663.225905775432 - 21 -1160.715069758053 - 0 -MTEXT - 5 -2DB -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3664.874581399463 - 20 -1161.037181403839 - 30 -0 - 40 -0.18 - 41 -0.7000000000000335 - 71 - 5 - 72 - 1 - 1 -3.3500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -120 -330 -11E -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -122 -330 -121 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D47 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D47 - 1 - - 0 -LINE - 5 -2DC -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.088675249515 - 20 -1243.75668465645 - 11 -3352.268675249544 - 21 -1243.75668465645 - 0 -SOLID - 5 -2DD -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3352.088675249515 - 20 -1243.75668465645 - 30 -0 - 11 -3352.268675249515 - 21 -1243.78665715181 - 31 -0 - 12 -3352.268675249515 - 22 -1243.72671216109 - 32 -0 - 13 -3352.268675249515 - 23 -1243.72671216109 - 33 -0 - 0 -SOLID - 5 -2DE -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3353.288675249574 - 20 -1243.75668465645 - 30 -0 - 11 -3353.108675249574 - 21 -1243.72671216109 - 31 -0 - 12 -3353.108675249574 - 22 -1243.78665715181 - 32 -0 - 13 -3353.108675249574 - 23 -1243.78665715181 - 33 -0 - 0 -LINE - 5 -2DF -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.108675249544 - 20 -1243.75668465645 - 11 -3353.288675249574 - 21 -1243.75668465645 - 0 -MTEXT - 5 -2E0 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3352.688675249544 - 20 -1243.75668465645 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2E1 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.088675249515 - 20 -1245.952369962641 - 11 -3352.088675249515 - 21 -1243.57668465645 - 0 -LINE - 5 -2E2 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3353.288675249574 - 20 -1243.552372614588 - 11 -3353.288675249574 - 21 -1243.93668465645 - 0 -ENDBLK - 5 -123 -330 -121 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -125 -330 -124 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D8 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D8 - 1 - - 0 -LINE - 5 -2E3 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1248.124625565833 - 11 -3299.224289594358 - 21 -1248.124625565833 - 0 -SOLID - 5 -2E4 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3299.024476717227 - 20 -1248.124625565833 - 30 -0 - 11 -3299.204476717227 - 21 -1248.154598061193 - 31 -0 - 12 -3299.204476717227 - 22 -1248.094653070473 - 32 -0 - 13 -3299.204476717227 - 23 -1248.094653070473 - 33 -0 - 0 -SOLID - 5 -2E5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.22410247149 - 20 -1248.124625565833 - 30 -0 - 11 -3300.04410247149 - 21 -1248.094653070473 - 31 -0 - 12 -3300.04410247149 - 22 -1248.154598061193 - 32 -0 - 13 -3300.04410247149 - 23 -1248.154598061193 - 33 -0 - 0 -LINE - 5 -2E6 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.024289594358 - 20 -1248.124625565833 - 11 -3300.22410247149 - 21 -1248.124625565833 - 0 -MTEXT - 5 -2E7 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3299.624289594358 - 20 -1248.2521489977 - 30 -0 - 40 -0.18 - 41 -0.6200000000000112 - 71 - 5 - 72 - 1 - 1 -1.1996 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2E8 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1247.752369962632 - 11 -3299.024476717227 - 21 -1248.304625565833 - 0 -LINE - 5 -2E9 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1247.752369962632 - 11 -3300.22410247149 - 21 -1248.304625565833 - 0 -ENDBLK - 5 -126 -330 -124 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -128 -330 -127 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D55 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D55 - 1 - - 0 -LINE - 5 -2EA -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.627986023668 - 20 -1258.458460622718 - 11 -3315.877986023473 - 21 -1258.458460622718 - 0 -SOLID - 5 -2EB -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3316.627986023668 - 20 -1258.458460622718 - 30 -0 - 11 -3316.447986023668 - 21 -1258.428488127358 - 31 -0 - 12 -3316.447986023668 - 22 -1258.488433118078 - 32 -0 - 13 -3316.447986023668 - 23 -1258.488433118078 - 33 -0 - 0 -SOLID - 5 -2EC -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3315.877986023473 - 20 -1258.458460622718 - 30 -0 - 11 -3316.057986023473 - 21 -1258.488433118078 - 31 -0 - 12 -3316.057986023473 - 22 -1258.428488127358 - 32 -0 - 13 -3316.057986023473 - 23 -1258.428488127358 - 33 -0 - 0 -MTEXT - 5 -2ED -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3315.234664058943 - 20 -1258.458460622718 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.7500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2EE -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.627986023668 - 20 -1258.300104121969 - 11 -3316.627986023668 - 21 -1258.638460622718 - 0 -LINE - 5 -2EF -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3315.877986023473 - 20 -1258.300104121969 - 11 -3315.877986023473 - 21 -1258.638460622718 - 0 -ENDBLK - 5 -129 -330 -127 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -12B -330 -12A -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D73 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D73 - 1 - - 0 -LINE - 5 -2F0 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3431.018724545987 - 20 -1247.78662018356 - 11 -3431.018724545987 - 21 -1246.889261580955 - 0 -SOLID - 5 -2F1 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3431.018724545987 - 20 -1247.78662018356 - 30 -0 - 11 -3431.048697041347 - 21 -1247.60662018356 - 31 -0 - 12 -3430.988752050627 - 22 -1247.60662018356 - 32 -0 - 13 -3430.988752050627 - 23 -1247.60662018356 - 33 -0 - 0 -SOLID - 5 -2F2 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3431.018724545987 - 20 -1245.631902978352 - 30 -0 - 11 -3430.988752050627 - 21 -1245.811902978352 - 31 -0 - 12 -3431.048697041347 - 22 -1245.811902978352 - 32 -0 - 13 -3431.048697041347 - 23 -1245.811902978352 - 33 -0 - 0 -LINE - 5 -2F3 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3431.018724545987 - 20 -1246.529261580955 - 11 -3431.018724545987 - 21 -1245.631902978352 - 0 -MTEXT - 5 -2F4 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3430.89120111412 - 20 -1246.709261580955 - 30 -0 - 40 -0.18 - 41 -0.6800000000000113 - 71 - 5 - 72 - 1 - 1 -2.1547 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2F5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3430.764366980675 - 20 -1247.78662018356 - 11 -3431.198724545987 - 21 -1247.78662018356 - 0 -LINE - 5 -2F6 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3430.764366980675 - 20 -1245.631902978352 - 11 -3431.198724545987 - 21 -1245.631902978352 - 0 -ENDBLK - 5 -12C -330 -12A -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -12E -330 -12D -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D57 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D57 - 1 - - 0 -LINE - 5 -2F7 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.28447671888 - 20 -1258.300104171694 - 11 -3299.28447671888 - 21 -1257.480104146831 - 0 -SOLID - 5 -2F8 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3299.28447671888 - 20 -1258.300104171694 - 30 -0 - 11 -3299.31444921424 - 21 -1258.120104171694 - 31 -0 - 12 -3299.25450422352 - 22 -1258.120104171694 - 32 -0 - 13 -3299.25450422352 - 23 -1258.120104171694 - 33 -0 - 0 -SOLID - 5 -2F9 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3299.28447671888 - 20 -1256.300104121969 - 30 -0 - 11 -3299.25450422352 - 21 -1256.480104121969 - 31 -0 - 12 -3299.31444921424 - 22 -1256.480104121969 - 32 -0 - 13 -3299.31444921424 - 23 -1256.480104121969 - 33 -0 - 0 -LINE - 5 -2FA -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.28447671888 - 20 -1257.120104146831 - 11 -3299.28447671888 - 21 -1256.300104121969 - 0 -MTEXT - 5 -2FB -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3299.28447671888 - 20 -1257.300104146831 - 30 -0 - 40 -0.18 - 41 -0.7000000000000001 - 71 - 5 - 72 - 1 - 1 -2.0000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -2FC -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.257778118009 - 20 -1258.300104171694 - 11 -3299.46447671888 - 21 -1258.300104171694 - 0 -LINE - 5 -2FD -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.284476718866 - 20 -1256.300104121969 - 11 -3299.46447671888 - 21 -1256.300104121969 - 0 -ENDBLK - 5 -12F -330 -12D -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -131 -330 -130 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D5 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D5 - 1 - - 0 -LINE - 5 -2FE -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3281.373068378307 - 20 -1261.079065790865 - 11 -3286.751803563298 - 21 -1261.079065790865 - 0 -SOLID - 5 -2FF -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3281.373068378307 - 20 -1261.079065790865 - 30 -0 - 11 -3281.553068378307 - 21 -1261.109038286225 - 31 -0 - 12 -3281.553068378307 - 22 -1261.049093295505 - 32 -0 - 13 -3281.553068378307 - 23 -1261.049093295505 - 33 -0 - 0 -SOLID - 5 -300 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3293.070538748289 - 20 -1261.079065790865 - 30 -0 - 11 -3292.890538748289 - 21 -1261.049093295505 - 31 -0 - 12 -3292.890538748289 - 22 -1261.109038286225 - 32 -0 - 13 -3292.890538748289 - 23 -1261.109038286225 - 33 -0 - 0 -LINE - 5 -301 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3287.691803563298 - 20 -1261.079065790865 - 11 -3293.070538748289 - 21 -1261.079065790865 - 0 -MTEXT - 5 -302 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3287.221803563298 - 20 -1261.206589222733 - 30 -0 - 40 -0.18 - 41 -0.7600000000000224 - 71 - 5 - 72 - 1 - 1 -11.6975 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -303 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3281.373068378307 - 20 -1259.280104148725 - 11 -3281.373068378307 - 21 -1261.259065790865 - 0 -LINE - 5 -304 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3293.070538748289 - 20 -1259.280104148725 - 11 -3293.070538748289 - 21 -1261.259065790865 - 0 -ENDBLK - 5 -132 -330 -130 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -134 -330 -133 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D52 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D52 - 1 - - 0 -LINE - 5 -305 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.223767729391 - 20 -1258.300104171694 - 11 -3317.223767729391 - 21 -1257.480104146831 - 0 -SOLID - 5 -306 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.223767729391 - 20 -1258.300104171694 - 30 -0 - 11 -3317.253740224751 - 21 -1258.120104171694 - 31 -0 - 12 -3317.193795234031 - 22 -1258.120104171694 - 32 -0 - 13 -3317.193795234031 - 23 -1258.120104171694 - 33 -0 - 0 -SOLID - 5 -307 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.223767729391 - 20 -1256.300104121969 - 30 -0 - 11 -3317.193795234031 - 21 -1256.480104121969 - 31 -0 - 12 -3317.253740224751 - 22 -1256.480104121969 - 32 -0 - 13 -3317.253740224751 - 23 -1256.480104121969 - 33 -0 - 0 -LINE - 5 -308 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.223767729391 - 20 -1257.120104146831 - 11 -3317.223767729391 - 21 -1256.300104121969 - 0 -MTEXT - 5 -309 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3317.223767729391 - 20 -1257.300104146831 - 30 -0 - 40 -0.18 - 41 -0.7000000000000001 - 71 - 5 - 72 - 1 - 1 -2.0000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -30A -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.102986023332 - 20 -1258.300104171694 - 11 -3317.403767729391 - 21 -1258.300104171694 - 0 -LINE - 5 -30B -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.102986023332 - 20 -1256.300104121969 - 11 -3317.403767729391 - 21 -1256.300104121969 - 0 -ENDBLK - 5 -135 -330 -133 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -137 -330 -136 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D16 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D16 - 1 - - 0 -LINE - 5 -30C -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3695.052411675178 - 20 -1112.562226008124 - 11 -3695.513967730656 - 21 -1109.802356924703 - 0 -SOLID - 5 -30D -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3695.052411675178 - 20 -1112.562226008124 - 30 -0 - 11 -3695.11166418721 - 21 -1112.389635480296 - 31 -0 - 12 -3695.052540303212 - 22 -1112.379747697268 - 32 -0 - 13 -3695.052540303212 - 23 -1112.379747697268 - 33 -0 - 0 -SOLID - 5 -30E -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3696.042765219429 - 20 -1106.640418470341 - 30 -0 - 11 -3695.983512707397 - 21 -1106.813008998169 - 31 -0 - 12 -3696.042636591395 - 22 -1106.822896781197 - 32 -0 - 13 -3696.042636591395 - 23 -1106.822896781197 - 33 -0 - 0 -LINE - 5 -30F -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3695.574173550189 - 20 -1109.442356924703 - 11 -3696.042765219429 - 21 -1106.640418470341 - 0 -MTEXT - 5 -310 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3695.673365105243 - 20 -1109.622356924703 - 30 -0 - 40 -0.18 - 41 -0.7200000000000111 - 71 - 5 - 72 - 1 - 1 -6.0040 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -311 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3695.126580710478 - 20 -1112.574629917997 - 11 -3694.874877255836 - 21 -1112.532535438091 - 0 -LINE - 5 -312 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3696.042765217587 - 20 -1106.640418470033 - 11 -3695.865230800087 - 21 -1106.610727900308 - 0 -ENDBLK - 5 -138 -330 -136 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -13A -330 -139 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D2 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D2 - 1 - - 0 -LINE - 5 -313 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3287.850942810532 - 20 -1243.423737554054 - 11 -3287.850942810532 - 21 -1241.416164394351 - 0 -LINE - 5 -314 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3287.850942810532 - 20 -1241.416164394351 - 11 -3286.261099679629 - 21 -1241.416164394351 - 0 -SOLID - 5 -315 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - 0 -100 -AcDbTrace - 10 -3287.850942810532 - 20 -1243.423737554054 - 30 -0 - 11 -3287.880915305892 - 21 -1243.243737554054 - 31 -0 - 12 -3287.820970315172 - 22 -1243.243737554054 - 32 -0 - 13 -3287.820970315172 - 23 -1243.243737554054 - 33 -0 - 0 -ENDBLK - 5 -13B -330 -139 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -13D -330 -13C -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D6 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D6 - 1 - - 0 -LINE - 5 -316 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3294.049122274159 - 20 -1259.280104148725 - 11 -3294.049122274159 - 21 -1252.796237055684 - 0 -SOLID - 5 -317 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3294.049122274159 - 20 -1259.280104148725 - 30 -0 - 11 -3294.079094769519 - 21 -1259.100104148725 - 31 -0 - 12 -3294.019149778799 - 22 -1259.100104148725 - 32 -0 - 13 -3294.019149778799 - 23 -1259.100104148725 - 33 -0 - 0 -SOLID - 5 -318 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3294.049122274159 - 20 -1245.952369962644 - 30 -0 - 11 -3294.019149778799 - 21 -1246.132369962644 - 31 -0 - 12 -3294.079094769519 - 22 -1246.132369962644 - 32 -0 - 13 -3294.079094769519 - 23 -1246.132369962644 - 33 -0 - 0 -LINE - 5 -319 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3294.049122274159 - 20 -1252.436237055684 - 11 -3294.049122274159 - 21 -1245.952369962644 - 0 -MTEXT - 5 -31A -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3293.921598842291 - 20 -1252.616237055684 - 30 -0 - 40 -0.18 - 41 -0.8000000000000224 - 71 - 5 - 72 - 1 - 1 -13.3277 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -31B -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3293.070538748289 - 20 -1259.280104148725 - 11 -3294.229122274159 - 21 -1259.280104148725 - 0 -LINE - 5 -31C -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3293.070538748289 - 20 -1245.952369962644 - 11 -3294.229122274159 - 21 -1245.952369962644 - 0 -ENDBLK - 5 -13E -330 -13C -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -140 -330 -13F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D38 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D38 - 1 - - 0 -LINE - 5 -31D -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.663978740904 - 20 -1243.552369960933 - 11 -3316.663978740904 - 21 -1245.0223699618 - 0 -SOLID - 5 -31E -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3316.663978740904 - 20 -1243.552369960933 - 30 -0 - 11 -3316.634006245544 - 21 -1243.732369960933 - 31 -0 - 12 -3316.693951236264 - 22 -1243.732369960933 - 32 -0 - 13 -3316.693951236264 - 23 -1243.732369960933 - 33 -0 - 0 -SOLID - 5 -31F -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3316.663978740904 - 20 -1246.852369962667 - 30 -0 - 11 -3316.693951236264 - 21 -1246.672369962667 - 31 -0 - 12 -3316.634006245544 - 22 -1246.672369962667 - 32 -0 - 13 -3316.634006245544 - 23 -1246.672369962667 - 33 -0 - 0 -LINE - 5 -320 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.663978740904 - 20 -1245.3823699618 - 11 -3316.663978740904 - 21 -1246.852369962667 - 0 -MTEXT - 5 -321 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3316.663978740903 - 20 -1245.2023699618 - 30 -0 - 40 -0.18 - 41 -0.7000000000000224 - 71 - 5 - 72 - 1 - 1 -3.3000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -322 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.663978740885 - 20 -1243.552369960933 - 11 -3316.483978740904 - 21 -1243.552369960933 - 0 -LINE - 5 -323 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.663978740891 - 20 -1246.852369962667 - 11 -3316.483978740904 - 21 -1246.852369962667 - 0 -ENDBLK - 5 -141 -330 -13F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -143 -330 -142 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D87 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D87 - 1 - - 0 -LINE - 5 -324 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.004476717158 - 20 -1259.050104148744 - 11 -3300.004476717158 - 21 -1258.300104148744 - 0 -SOLID - 5 -325 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.004476717158 - 20 -1259.050104148744 - 30 -0 - 11 -3300.034449212518 - 21 -1258.870104148744 - 31 -0 - 12 -3299.974504221798 - 22 -1258.870104148744 - 32 -0 - 13 -3299.974504221798 - 23 -1258.870104148744 - 33 -0 - 0 -SOLID - 5 -326 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.004476717158 - 20 -1258.300104148744 - 30 -0 - 11 -3299.974504221798 - 21 -1258.480104148744 - 31 -0 - 12 -3300.034449212518 - 22 -1258.480104148744 - 32 -0 - 13 -3300.034449212518 - 23 -1258.480104148744 - 33 -0 - 0 -MTEXT - 5 -327 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3299.361154752628 - 20 -1258.120104148744 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.7500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -328 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.824476717156 - 20 -1259.050104148744 - 11 -3300.184476717158 - 21 -1259.050104148744 - 0 -LINE - 5 -329 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.004476717158 - 20 -1258.300104148744 - 11 -3300.184476717158 - 21 -1258.300104148744 - 0 -ENDBLK - 5 -144 -330 -142 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -146 -330 -145 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D36 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D36 - 1 - - 0 -LINE - 5 -32A -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3318.800048270567 - 20 -1245.652369962656 - 11 -3318.800048270567 - 21 -1244.782369961795 - 0 -SOLID - 5 -32B -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3318.800048270567 - 20 -1245.652369962656 - 30 -0 - 11 -3318.830020765927 - 21 -1245.472369962656 - 31 -0 - 12 -3318.770075775207 - 22 -1245.472369962656 - 32 -0 - 13 -3318.770075775207 - 23 -1245.472369962656 - 33 -0 - 0 -SOLID - 5 -32C -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3318.800048270567 - 20 -1243.552369960933 - 30 -0 - 11 -3318.770075775207 - 21 -1243.732369960933 - 31 -0 - 12 -3318.830020765927 - 22 -1243.732369960933 - 32 -0 - 13 -3318.830020765927 - 23 -1243.732369960933 - 33 -0 - 0 -LINE - 5 -32D -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3318.800048270567 - 20 -1244.422369961795 - 11 -3318.800048270567 - 21 -1243.552369960933 - 0 -MTEXT - 5 -32E -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3318.800048270566 - 20 -1244.602369961795 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -2.1000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -32F -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3318.97400810069 - 20 -1245.652369962656 - 11 -3318.620048270567 - 21 -1245.652369962656 - 0 -LINE - 5 -330 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3318.97400810071 - 20 -1243.552369960933 - 11 -3318.620048270567 - 21 -1243.552369960933 - 0 -ENDBLK - 5 -147 -330 -145 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -149 -330 -148 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D27 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D27 - 1 - - 0 -LINE - 5 -331 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3283.703068378148 - 20 -1245.209053745057 - 11 -3283.883068378125 - 21 -1245.209053745057 - 0 -SOLID - 5 -332 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3283.703068378148 - 20 -1245.209053745057 - 30 -0 - 11 -3283.883068378148 - 21 -1245.239026240417 - 31 -0 - 12 -3283.883068378148 - 22 -1245.179081249697 - 32 -0 - 13 -3283.883068378148 - 23 -1245.179081249697 - 33 -0 - 0 -SOLID - 5 -333 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3284.903068378103 - 20 -1245.209053745057 - 30 -0 - 11 -3284.723068378103 - 21 -1245.179081249697 - 31 -0 - 12 -3284.723068378103 - 22 -1245.239026240417 - 32 -0 - 13 -3284.723068378103 - 23 -1245.239026240417 - 33 -0 - 0 -LINE - 5 -334 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3284.723068378125 - 20 -1245.209053745057 - 11 -3284.903068378103 - 21 -1245.209053745057 - 0 -MTEXT - 5 -335 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3284.303068378125 - 20 -1245.209053745057 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -336 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3283.703068378148 - 20 -1245.052369962679 - 11 -3283.703068378148 - 21 -1245.389053745057 - 0 -LINE - 5 -337 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3284.903068378103 - 20 -1245.052369962679 - 11 -3284.903068378103 - 21 -1245.389053745057 - 0 -ENDBLK - 5 -14A -330 -148 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -14C -330 -14B -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D3 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D3 - 1 - - 0 -LINE - 5 -338 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3288.623488413138 - 20 -1243.623737554066 - 11 -3288.623488413138 - 21 -1251.271920851396 - 0 -SOLID - 5 -339 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3288.623488413138 - 20 -1243.623737554066 - 30 -0 - 11 -3288.593515917778 - 21 -1243.803737554066 - 31 -0 - 12 -3288.653460908498 - 22 -1243.803737554066 - 32 -0 - 13 -3288.653460908498 - 23 -1243.803737554066 - 33 -0 - 0 -SOLID - 5 -33A -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3288.623488413138 - 20 -1259.280104148725 - 30 -0 - 11 -3288.653460908498 - 21 -1259.100104148725 - 31 -0 - 12 -3288.593515917778 - 22 -1259.100104148725 - 32 -0 - 13 -3288.593515917778 - 23 -1259.100104148725 - 33 -0 - 0 -LINE - 5 -33B -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3288.623488413138 - 20 -1251.631920851396 - 11 -3288.623488413138 - 21 -1259.280104148725 - 0 -MTEXT - 5 -33C -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3288.495964981269 - 20 -1251.451920851396 - 30 -0 - 40 -0.18 - 41 -0.8200000000000447 - 71 - 5 - 72 - 1 - 1 -15.6564 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -33D -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3287.835900044962 - 20 -1243.623737554066 - 11 -3288.803488413138 - 21 -1243.623737554066 - 0 -LINE - 5 -33E -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3287.835900044962 - 20 -1259.280104148725 - 11 -3288.803488413138 - 21 -1259.280104148725 - 0 -ENDBLK - 5 -14D -330 -14B -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -14F -330 -14E -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D20 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D20 - 1 - - 0 -LINE - 5 -33F -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3690.568945564359 - 20 -1105.614665471137 - 11 -3691.528679997723 - 21 -1099.875944551971 - 0 -SOLID - 5 -340 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3690.568945564359 - 20 -1105.614665471137 - 30 -0 - 11 -3690.628198076392 - 21 -1105.442074943309 - 31 -0 - 12 -3690.569074192393 - 22 -1105.432187160281 - 32 -0 - 13 -3690.569074192393 - 23 -1105.432187160281 - 33 -0 - 0 -SOLID - 5 -341 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3692.548620250619 - 20 -1093.777223632806 - 30 -0 - 11 -3692.489367738587 - 21 -1093.949814160634 - 31 -0 - 12 -3692.548491622586 - 22 -1093.959701943662 - 32 -0 - 13 -3692.548491622586 - 23 -1093.959701943662 - 33 -0 - 0 -LINE - 5 -342 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3691.588885817256 - 20 -1099.515944551971 - 11 -3692.548620250619 - 21 -1093.777223632806 - 0 -MTEXT - 5 -343 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3691.55878290749 - 20 -1099.695944551971 - 30 -0 - 40 -0.18 - 41 -0.76 - 71 - 5 - 72 - 1 - 1 -12.0018 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -344 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3690.101075426844 - 20 -1105.536419623736 - 11 -3690.746479983701 - 21 -1105.64435604117 - 0 -LINE - 5 -345 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3692.167267226776 - 20 -1093.713446767995 - 11 -3692.726154669961 - 21 -1093.806914202839 - 0 -ENDBLK - 5 -150 -330 -14E -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -152 -330 -151 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D7 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D7 - 1 - - 0 -LINE - 5 -346 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3280.402680748146 - 20 -1242.154635776649 - 11 -3280.402680748146 - 21 -1250.537369962687 - 0 -SOLID - 5 -347 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3280.402680748146 - 20 -1242.154635776649 - 30 -0 - 11 -3280.372708252786 - 21 -1242.334635776649 - 31 -0 - 12 -3280.432653243506 - 22 -1242.334635776649 - 32 -0 - 13 -3280.432653243506 - 23 -1242.334635776649 - 33 -0 - 0 -SOLID - 5 -348 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3280.402680748146 - 20 -1259.280104148725 - 30 -0 - 11 -3280.432653243506 - 21 -1259.100104148725 - 31 -0 - 12 -3280.372708252786 - 22 -1259.100104148725 - 32 -0 - 13 -3280.372708252786 - 23 -1259.100104148725 - 33 -0 - 0 -LINE - 5 -349 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3280.402680748146 - 20 -1250.897369962687 - 11 -3280.402680748146 - 21 -1259.280104148725 - 0 -MTEXT - 5 -34A -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3280.275157316278 - 20 -1250.717369962687 - 30 -0 - 40 -0.18 - 41 -0.7600000000000222 - 71 - 5 - 72 - 1 - 1 -17.1255 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -34B -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3281.373068378307 - 20 -1242.154635776649 - 11 -3280.222680748146 - 21 -1242.154635776649 - 0 -LINE - 5 -34C -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3281.373068378307 - 20 -1259.280104148725 - 11 -3280.222680748146 - 21 -1259.280104148725 - 0 -ENDBLK - 5 -153 -330 -151 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -155 -330 -154 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D58 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D58 - 1 - - 0 -LINE - 5 -34D -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1258.430923504448 - 11 -3300.624476718716 - 21 -1258.430923504448 - 0 -SOLID - 5 -34E -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3299.874476717086 - 20 -1258.430923504448 - 30 -0 - 11 -3300.054476717086 - 21 -1258.460895999808 - 31 -0 - 12 -3300.054476717086 - 22 -1258.400951009088 - 32 -0 - 13 -3300.054476717086 - 23 -1258.400951009088 - 33 -0 - 0 -SOLID - 5 -34F -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.624476718716 - 20 -1258.430923504448 - 30 -0 - 11 -3300.444476718716 - 21 -1258.400951009088 - 31 -0 - 12 -3300.444476718716 - 22 -1258.460895999808 - 32 -0 - 13 -3300.444476718716 - 23 -1258.460895999808 - 33 -0 - 0 -MTEXT - 5 -350 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3301.267798683246 - 20 -1258.430923504448 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.7500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -351 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1258.300104171694 - 11 -3299.874476717086 - 21 -1258.610923504448 - 0 -LINE - 5 -352 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.624476718716 - 20 -1258.300104171694 - 11 -3300.624476718716 - 21 -1258.610923504448 - 0 -ENDBLK - 5 -156 -330 -154 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -158 -330 -157 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D81 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D81 - 1 - - 0 -LINE - 5 -353 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3429.547647392643 - 20 -1248.186620183525 - 11 -3430.191031889974 - 21 -1248.186620183525 - 0 -LINE - 5 -354 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3429.547647392643 - 20 -1246.989735042331 - 11 -3430.191031889974 - 21 -1246.989735042331 - 0 -LINE - 5 -355 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3430.011031889974 - 20 -1248.186620183525 - 11 -3430.011031889974 - 21 -1247.768177612927 - 0 -SOLID - 5 -356 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3430.011031889974 - 20 -1248.186620183525 - 30 -0 - 11 -3430.041004385334 - 21 -1248.006620183525 - 31 -0 - 12 -3429.981059394614 - 22 -1248.006620183525 - 32 -0 - 13 -3429.981059394614 - 23 -1248.006620183525 - 33 -0 - 0 -SOLID - 5 -357 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3430.011031889974 - 20 -1246.989735042331 - 30 -0 - 11 -3429.981059394614 - 21 -1247.169735042331 - 31 -0 - 12 -3430.041004385334 - 22 -1247.169735042331 - 32 -0 - 13 -3430.041004385334 - 23 -1247.169735042331 - 33 -0 - 0 -LINE - 5 -358 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3430.011031889974 - 20 -1247.408177612927 - 11 -3430.011031889974 - 21 -1246.989735042331 - 0 -MTEXT - 5 -359 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3429.883508458106 - 20 -1247.588177612927 - 30 -0 - 40 -0.18 - 41 -0.6200000000000112 - 71 - 5 - 72 - 1 - 1 -1.1969 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -159 -330 -157 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -15B -330 -15A -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D11 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D11 - 1 - - 0 -LINE - 5 -35A -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3701.362999543092 - 20 -1133.283221728451 - 11 -3701.375225701095 - 21 -1134.089105985646 - 0 -LINE - 5 -35B -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3710.911900706631 - 20 -1133.138354306928 - 11 -3710.924126864634 - 21 -1133.944238564123 - 0 -LINE - 5 -35C -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3701.372495215663 - 20 -1133.909126696701 - 11 -3705.708880246726 - 21 -1133.84333892621 - 0 -SOLID - 5 -35D -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3701.372495215663 - 20 -1133.909126696701 - 30 -0 - 11 -3701.552929168286 - 21 -1133.936365257951 - 31 -0 - 12 -3701.552019840931 - 22 -1133.876427164587 - 32 -0 - 13 -3701.552019840931 - 23 -1133.876427164587 - 33 -0 - 0 -SOLID - 5 -35E -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3710.921396379202 - 20 -1133.764259275178 - 30 -0 - 11 -3710.740962426579 - 21 -1133.737020713928 - 31 -0 - 12 -3710.741871753934 - 22 -1133.796958807292 - 32 -0 - 13 -3710.741871753934 - 23 -1133.796958807292 - 33 -0 - 0 -LINE - 5 -35F -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3706.588880246726 - 20 -1133.829988350185 - 11 -3710.921396379202 - 21 -1133.764259275178 - 0 -MTEXT - 5 -360 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3706.148880246726 - 20 -1133.964201744781 - 30 -0 - 40 -0.18 - 41 -0.7000000000000337 - 71 - 5 - 72 - 1 - 1 -9.5500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -15C -330 -15A -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -15E -330 -15D -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D62 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D62 - 1 - - 0 -LINE - 5 -361 -100 -AcDbEntity - 8 -DIST_EXIT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.595899450548 - 20 -1256.244520042979 - 11 -3300.234382164151 - 21 -1255.541352531269 - 0 -LINE - 5 -362 -100 -AcDbEntity - 8 -DIST_EXIT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3310.233369820708 - 20 -1251.289637916136 - 11 -3309.871852534311 - 21 -1250.586470404426 - 0 -LINE - 5 -363 -100 -AcDbEntity - 8 -DIST_EXIT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.316684691782 - 20 -1255.701434678761 - 11 -3304.785311716421 - 21 -1253.40399361534 - 0 -SOLID - 5 -364 -100 -AcDbEntity - 8 -DIST_EXIT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.316684691782 - 20 -1255.701434678761 - 30 -0 - 11 -3300.490471351093 - 21 -1255.645788047924 - 31 -0 - 12 -3300.463062327454 - 22 -1255.592476254337 - 32 -0 - 13 -3300.463062327454 - 23 -1255.592476254337 - 33 -0 - 0 -SOLID - 5 -365 -100 -AcDbEntity - 8 -DIST_EXIT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3309.954155061942 - 20 -1250.746552551918 - 30 -0 - 11 -3309.780368402631 - 21 -1250.802199182755 - 31 -0 - 12 -3309.80777742627 - 22 -1250.855510976343 - 32 -0 - 13 -3309.80777742627 - 23 -1250.855510976343 - 33 -0 - 0 -LINE - 5 -366 -100 -AcDbEntity - 8 -DIST_EXIT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3305.485528037302 - 20 -1253.04399361534 - 11 -3309.954155061942 - 21 -1250.746552551918 - 0 -MTEXT - 5 -367 -100 -AcDbEntity - 8 -DIST_EXIT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3305.135419876862 - 20 -1253.22399361534 - 30 -0 - 40 -0.18 - 41 -0.8000000000000336 - 71 - 5 - 72 - 1 - 1 -10.8366 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -15F -330 -15D -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -161 -330 -160 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D42 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D42 - 1 - - 0 -LINE - 5 -368 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3355.010737497922 - 20 -1245.652369962656 - 11 -3355.010737497922 - 21 -1244.782369962665 - 0 -SOLID - 5 -369 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3355.010737497922 - 20 -1245.652369962656 - 30 -0 - 11 -3355.040709993282 - 21 -1245.472369962656 - 31 -0 - 12 -3354.980765002562 - 22 -1245.472369962656 - 32 -0 - 13 -3354.980765002562 - 23 -1245.472369962656 - 33 -0 - 0 -SOLID - 5 -36A -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3355.010737497922 - 20 -1243.552369962674 - 30 -0 - 11 -3354.980765002562 - 21 -1243.732369962674 - 31 -0 - 12 -3355.040709993282 - 22 -1243.732369962674 - 32 -0 - 13 -3355.040709993282 - 23 -1243.732369962674 - 33 -0 - 0 -LINE - 5 -36B -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3355.010737497922 - 20 -1244.422369962665 - 11 -3355.010737497922 - 21 -1243.552369962674 - 0 -MTEXT - 5 -36C -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3355.010737497922 - 20 -1244.602369962665 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -2.1000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -36D -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3355.18469732804 - 20 -1245.652369962656 - 11 -3354.830737497922 - 21 -1245.652369962656 - 0 -LINE - 5 -36E -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3355.18469732804 - 20 -1243.552369962674 - 11 -3354.830737497922 - 21 -1243.552369962674 - 0 -ENDBLK - 5 -162 -330 -160 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -164 -330 -163 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D77 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D77 - 1 - - 0 -LINE - 5 -36F -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.52223736918 - 20 -1248.636620183537 - 11 -3427.52223736918 - 21 -1250.481622577436 - 0 -SOLID - 5 -370 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3427.52223736918 - 20 -1248.636620183537 - 30 -0 - 11 -3427.49226487382 - 21 -1248.816620183537 - 31 -0 - 12 -3427.55220986454 - 22 -1248.816620183537 - 32 -0 - 13 -3427.55220986454 - 23 -1248.816620183537 - 33 -0 - 0 -SOLID - 5 -371 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3427.52223736918 - 20 -1252.686624971338 - 30 -0 - 11 -3427.55220986454 - 21 -1252.506624971338 - 31 -0 - 12 -3427.49226487382 - 22 -1252.506624971338 - 32 -0 - 13 -3427.49226487382 - 23 -1252.506624971338 - 33 -0 - 0 -LINE - 5 -372 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.52223736918 - 20 -1250.841622577436 - 11 -3427.52223736918 - 21 -1252.686624971338 - 0 -MTEXT - 5 -373 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3427.394713937312 - 20 -1250.661622577436 - 30 -0 - 40 -0.18 - 41 -0.7200000000000111 - 71 - 5 - 72 - 1 - 1 -4.0500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -374 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.762429444553 - 20 -1248.636620183537 - 11 -3427.34223736918 - 21 -1248.636620183537 - 0 -LINE - 5 -375 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.994593221313 - 20 -1252.686624971338 - 11 -3427.34223736918 - 21 -1252.686624971338 - 0 -ENDBLK - 5 -165 -330 -163 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -167 -330 -166 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D17 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D17 - 1 - - 0 -LINE - 5 -376 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3682.788987350215 - 20 -1110.511310697658 - 11 -3683.277497859675 - 21 -1107.5902677691 - 0 -SOLID - 5 -377 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3682.788987350215 - 20 -1110.511310697658 - 30 -0 - 11 -3682.848239862247 - 21 -1110.33872016983 - 31 -0 - 12 -3682.789115978248 - 22 -1110.328832386802 - 32 -0 - 13 -3682.789115978248 - 23 -1110.328832386802 - 33 -0 - 0 -SOLID - 5 -378 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3683.833249802431 - 20 -1104.267155469601 - 30 -0 - 11 -3683.773997290399 - 21 -1104.439745997429 - 31 -0 - 12 -3683.833121174398 - 22 -1104.449633780457 - 32 -0 - 13 -3683.833121174398 - 23 -1104.449633780457 - 33 -0 - 0 -LINE - 5 -379 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3683.337703679209 - 20 -1107.2302677691 - 11 -3683.833249802431 - 21 -1104.267155469601 - 0 -MTEXT - 5 -37A -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3683.436895234262 - 20 -1107.4102677691 - 30 -0 - 40 -0.18 - 41 -0.7000000000000335 - 71 - 5 - 72 - 1 - 1 -6.3309 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -37B -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3682.788987348374 - 20 -1110.51131069735 - 11 -3682.611452930873 - 21 -1110.481620127625 - 0 -LINE - 5 -37C -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3683.833249800589 - 20 -1104.267155469293 - 11 -3683.655715383089 - 21 -1104.237464899568 - 0 -ENDBLK - 5 -168 -330 -166 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -16A -330 -169 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D18 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D18 - 1 - - 0 -LINE - 5 -37D -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3715.716213430494 - 20 -1117.590407744046 - 11 -3716.260409676698 - 21 -1114.336392598132 - 0 -SOLID - 5 -37E -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3715.716213430494 - 20 -1117.590407744046 - 30 -0 - 11 -3715.775465942526 - 21 -1117.417817216219 - 31 -0 - 12 -3715.716342058527 - 22 -1117.40792943319 - 32 -0 - 13 -3715.716342058527 - 23 -1117.40792943319 - 33 -0 - 0 -SOLID - 5 -37F -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3716.871847356197 - 20 -1110.680308081277 - 30 -0 - 11 -3716.812594844165 - 21 -1110.852898609105 - 31 -0 - 12 -3716.871718728164 - 22 -1110.862786392134 - 32 -0 - 13 -3716.871718728164 - 23 -1110.862786392134 - 33 -0 - 0 -LINE - 5 -380 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3716.320615496231 - 20 -1113.976392598132 - 11 -3716.871847356197 - 21 -1110.680308081277 - 0 -MTEXT - 5 -381 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3716.419807051285 - 20 -1114.156392598132 - 30 -0 - 40 -0.18 - 41 -0.6600000000000112 - 71 - 5 - 72 - 1 - 1 -7.0061 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -382 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3715.527812990941 - 20 -1117.558899958314 - 11 -3715.893747849836 - 21 -1117.620098314079 - 0 -LINE - 5 -383 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3716.546538312589 - 20 -1110.625903921355 - 11 -3717.049381775539 - 21 -1110.70999865131 - 0 -ENDBLK - 5 -16B -330 -169 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -16D -330 -16C -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D56 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D56 - 1 - - 0 -LINE - 5 -384 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.370258424579 - 20 -1258.300104171694 - 11 -3300.370258424579 - 21 -1257.480104146831 - 0 -SOLID - 5 -385 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.370258424579 - 20 -1258.300104171694 - 30 -0 - 11 -3300.400230919939 - 21 -1258.120104171694 - 31 -0 - 12 -3300.340285929219 - 22 -1258.120104171694 - 32 -0 - 13 -3300.340285929219 - 23 -1258.120104171694 - 33 -0 - 0 -SOLID - 5 -386 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3300.370258424579 - 20 -1256.300104121969 - 30 -0 - 11 -3300.340285929219 - 21 -1256.480104121969 - 31 -0 - 12 -3300.400230919939 - 22 -1256.480104121969 - 32 -0 - 13 -3300.400230919939 - 23 -1256.480104121969 - 33 -0 - 0 -LINE - 5 -387 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.370258424579 - 20 -1257.120104146831 - 11 -3300.370258424579 - 21 -1256.300104121969 - 0 -MTEXT - 5 -388 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3300.370258424579 - 20 -1257.300104146831 - 30 -0 - 40 -0.18 - 41 -0.7000000000000001 - 71 - 5 - 72 - 1 - 1 -2.0000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -389 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.24947671852 - 20 -1258.300104171694 - 11 -3300.550258424579 - 21 -1258.300104171694 - 0 -LINE - 5 -38A -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3300.24947671852 - 20 -1256.300104121969 - 11 -3300.550258424579 - 21 -1256.300104121969 - 0 -ENDBLK - 5 -16E -330 -16C -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -170 -330 -16F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D22 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D22 - 1 - - 0 -LINE - 5 -38B -100 -AcDbEntity - 8 -SHORTEST_DIST_TO_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3703.119425063774 - 20 -1113.911337638816 - 11 -3703.563136378727 - 21 -1111.258170974501 - 0 -SOLID - 5 -38C -100 -AcDbEntity - 8 -SHORTEST_DIST_TO_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3703.119425063774 - 20 -1113.911337638816 - 30 -0 - 11 -3703.178677575806 - 21 -1113.738747110988 - 31 -0 - 12 -3703.119553691807 - 22 -1113.72885932796 - 32 -0 - 13 -3703.119553691807 - 23 -1113.72885932796 - 33 -0 - 0 -SOLID - 5 -38D -100 -AcDbEntity - 8 -SHORTEST_DIST_TO_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3704.067053513214 - 20 -1108.245004310186 - 30 -0 - 11 -3704.007801001182 - 21 -1108.417594838014 - 31 -0 - 12 -3704.06692488518 - 22 -1108.427482621042 - 32 -0 - 13 -3704.06692488518 - 23 -1108.427482621042 - 33 -0 - 0 -LINE - 5 -38E -100 -AcDbEntity - 8 -SHORTEST_DIST_TO_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3703.62334219826 - 20 -1110.898170974501 - 11 -3704.067053513214 - 21 -1108.245004310186 - 0 -MTEXT - 5 -38F -100 -AcDbEntity - 8 -SHORTEST_DIST_TO_ROAD - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3703.593239288494 - 20 -1111.078170974501 - 30 -0 - 40 -0.18 - 41 -0.7200000000000224 - 71 - 5 - 72 - 1 - 1 -5.7450 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -390 -100 -AcDbEntity - 8 -SHORTEST_DIST_TO_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3702.893813337845 - 20 -1113.87360669755 - 11 -3703.296959483116 - 21 -1113.941028208849 - 0 -LINE - 5 -391 -100 -AcDbEntity - 8 -SHORTEST_DIST_TO_ROAD - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3703.84242825261 - 20 -1108.20743834379 - 11 -3704.244587932556 - 21 -1108.274694880219 - 0 -ENDBLK - 5 -171 -330 -16F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -173 -330 -172 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D49 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D49 - 1 - - 0 -LINE - 5 -392 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.348675251248 - 20 -1258.300104171694 - 11 -3352.348675251248 - 21 -1257.480104146832 - 0 -SOLID - 5 -393 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3352.348675251248 - 20 -1258.300104171694 - 30 -0 - 11 -3352.378647746608 - 21 -1258.120104171694 - 31 -0 - 12 -3352.318702755888 - 22 -1258.120104171694 - 32 -0 - 13 -3352.318702755888 - 23 -1258.120104171694 - 33 -0 - 0 -SOLID - 5 -394 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3352.348675251248 - 20 -1256.300104121969 - 30 -0 - 11 -3352.318702755888 - 21 -1256.480104121969 - 31 -0 - 12 -3352.378647746608 - 22 -1256.480104121969 - 32 -0 - 13 -3352.378647746608 - 23 -1256.480104121969 - 33 -0 - 0 -LINE - 5 -395 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.348675251248 - 20 -1257.120104146832 - 11 -3352.348675251248 - 21 -1256.300104121969 - 0 -MTEXT - 5 -396 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3352.348675251248 - 20 -1257.300104146832 - 30 -0 - 40 -0.18 - 41 -0.7000000000000001 - 71 - 5 - 72 - 1 - 1 -2.0000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -397 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.321976650384 - 20 -1258.300104171694 - 11 -3352.528675251248 - 21 -1258.300104171694 - 0 -LINE - 5 -398 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.348675251239 - 20 -1256.300104121969 - 11 -3352.528675251248 - 21 -1256.300104121969 - 0 -ENDBLK - 5 -174 -330 -172 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -176 -330 -175 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D60 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D60 - 1 - - 0 -LINE - 5 -399 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3319.629717898161 - 20 -1257.851297607682 - 11 -3319.741621811485 - 21 -1257.851297607682 - 0 -SOLID - 5 -39A -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3319.629717898161 - 20 -1257.851297607682 - 30 -0 - 11 -3319.809717898161 - 21 -1257.881270103042 - 31 -0 - 12 -3319.809717898161 - 22 -1257.821325112322 - 32 -0 - 13 -3319.809717898161 - 23 -1257.821325112322 - 33 -0 - 0 -SOLID - 5 -39B -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3320.693525724812 - 20 -1257.851297607682 - 30 -0 - 11 -3320.513525724812 - 21 -1257.821325112322 - 31 -0 - 12 -3320.513525724812 - 22 -1257.881270103042 - 32 -0 - 13 -3320.513525724812 - 23 -1257.881270103042 - 33 -0 - 0 -LINE - 5 -39C -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3320.581621811486 - 20 -1257.851297607682 - 11 -3320.693525724812 - 21 -1257.851297607682 - 0 -MTEXT - 5 -39D -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3320.161621811486 - 20 -1257.851297607682 - 30 -0 - 40 -0.18 - 41 -0.6600000000000223 - 71 - 5 - 72 - 1 - 1 -1.0638 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -39E -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3319.629717898161 - 20 -1257.867062992372 - 11 -3319.629717898161 - 21 -1257.671297607682 - 0 -LINE - 5 -39F -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3320.693525724812 - 20 -1257.867062992372 - 11 -3320.693525724812 - 21 -1257.671297607682 - 0 -ENDBLK - 5 -177 -330 -175 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -179 -330 -178 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D33 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D33 - 1 - - 0 -LINE - 5 -3A0 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3301.124476717212 - 20 -1245.809053745033 - 11 -3301.304476717189 - 21 -1245.809053745033 - 0 -SOLID - 5 -3A1 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3301.124476717212 - 20 -1245.809053745033 - 30 -0 - 11 -3301.304476717212 - 21 -1245.839026240393 - 31 -0 - 12 -3301.304476717212 - 22 -1245.779081249673 - 32 -0 - 13 -3301.304476717212 - 23 -1245.779081249673 - 33 -0 - 0 -SOLID - 5 -3A2 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3302.324476717166 - 20 -1245.809053745033 - 30 -0 - 11 -3302.144476717166 - 21 -1245.779081249673 - 31 -0 - 12 -3302.144476717166 - 22 -1245.839026240393 - 32 -0 - 13 -3302.144476717166 - 23 -1245.839026240393 - 33 -0 - 0 -LINE - 5 -3A3 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3302.144476717189 - 20 -1245.809053745033 - 11 -3302.324476717166 - 21 -1245.809053745033 - 0 -MTEXT - 5 -3A4 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3301.724476717189 - 20 -1245.809053745033 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3A5 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3301.124476717212 - 20 -1245.652369962656 - 11 -3301.124476717212 - 21 -1245.989053745033 - 0 -LINE - 5 -3A6 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3302.324476717166 - 20 -1245.652369962656 - 11 -3302.324476717166 - 21 -1245.989053745033 - 0 -ENDBLK - 5 -17A -330 -178 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -17C -330 -17B -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D29 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D29 - 1 - - 0 -LINE - 5 -3A7 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3281.603068378181 - 20 -1243.756682050024 - 11 -3281.783068378211 - 21 -1243.756682050024 - 0 -SOLID - 5 -3A8 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3281.603068378181 - 20 -1243.756682050024 - 30 -0 - 11 -3281.783068378181 - 21 -1243.786654545384 - 31 -0 - 12 -3281.783068378181 - 22 -1243.726709554664 - 32 -0 - 13 -3281.783068378181 - 23 -1243.726709554664 - 33 -0 - 0 -SOLID - 5 -3A9 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3282.803068378242 - 20 -1243.756682050024 - 30 -0 - 11 -3282.623068378242 - 21 -1243.726709554664 - 31 -0 - 12 -3282.623068378242 - 22 -1243.786654545384 - 32 -0 - 13 -3282.623068378242 - 23 -1243.786654545384 - 33 -0 - 0 -LINE - 5 -3AA -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3282.623068378212 - 20 -1243.756682050024 - 11 -3282.803068378242 - 21 -1243.756682050024 - 0 -MTEXT - 5 -3AB -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3282.203068378212 - 20 -1243.756682050024 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3AC -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3281.603068378181 - 20 -1245.952369962646 - 11 -3281.603068378181 - 21 -1243.576682050024 - 0 -LINE - 5 -3AD -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3282.803068378242 - 20 -1243.552370008162 - 11 -3282.803068378242 - 21 -1243.936682050024 - 0 -ENDBLK - 5 -17D -330 -17B -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -17F -330 -17E -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D21 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D21 - 1 - - 0 -LINE - 5 -3AE -100 -AcDbEntity - 8 -BLK_1_MAX_HEIGHT_CAL - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3701.825734416305 - 20 -1113.585719006579 - 11 -3703.251184360891 - 21 -1105.062257586579 - 0 -SOLID - 5 -3AF -100 -AcDbEntity - 8 -BLK_1_MAX_HEIGHT_CAL - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3701.825734416305 - 20 -1113.585719006579 - 30 -0 - 11 -3701.884986928338 - 21 -1113.413128478751 - 31 -0 - 12 -3701.825863044339 - 22 -1113.403240695723 - 32 -0 - 13 -3701.825863044339 - 23 -1113.403240695723 - 33 -0 - 0 -SOLID - 5 -3B0 -100 -AcDbEntity - 8 -BLK_1_MAX_HEIGHT_CAL - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3704.73684012501 - 20 -1096.178796166579 - 30 -0 - 11 -3704.677587612978 - 21 -1096.351386694407 - 31 -0 - 12 -3704.736711496977 - 22 -1096.361274477435 - 32 -0 - 13 -3704.736711496977 - 23 -1096.361274477435 - 33 -0 - 0 -LINE - 5 -3B1 -100 -AcDbEntity - 8 -BLK_1_MAX_HEIGHT_CAL - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3703.311390180424 - 20 -1104.702257586579 - 11 -3704.73684012501 - 21 -1096.178796166579 - 0 -MTEXT - 5 -3B2 -100 -AcDbEntity - 8 -BLK_1_MAX_HEIGHT_CAL - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3703.281287270659 - 20 -1104.882257586579 - 30 -0 - 40 -0.18 - 41 -0.8200000000000112 - 71 - 5 - 72 - 1 - 1 -17.6487 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3B3 -100 -AcDbEntity - 8 -BLK_1_MAX_HEIGHT_CAL - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3702.961422993541 - 20 -1113.775649733043 - 11 -3701.648199996963 - 21 -1113.556028436546 - 0 -LINE - 5 -3B4 -100 -AcDbEntity - 8 -BLK_1_MAX_HEIGHT_CAL - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3705.551110057835 - 20 -1096.31497335721 - 11 -3704.559305705668 - 21 -1096.149105596546 - 0 -ENDBLK - 5 -180 -330 -17E -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -182 -330 -181 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D37 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D37 - 1 - - 0 -LINE - 5 -3B5 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.977986036755 - 20 -1243.079906268309 - 11 -3317.077986036848 - 21 -1243.079906268309 - 0 -SOLID - 5 -3B6 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.977986036755 - 20 -1243.079906268309 - 30 -0 - 11 -3317.797986036755 - 21 -1243.049933772949 - 31 -0 - 12 -3317.797986036755 - 22 -1243.109878763669 - 32 -0 - 13 -3317.797986036755 - 23 -1243.109878763669 - 33 -0 - 0 -SOLID - 5 -3B7 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.077986036848 - 20 -1243.079906268309 - 30 -0 - 11 -3317.257986036848 - 21 -1243.109878763669 - 31 -0 - 12 -3317.257986036848 - 22 -1243.049933772949 - 32 -0 - 13 -3317.257986036848 - 23 -1243.049933772949 - 33 -0 - 0 -MTEXT - 5 -3B8 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3316.43466407232 - 20 -1243.079906268309 - 30 -0 - 40 -0.18 - 41 -0.7000000000000001 - 71 - 5 - 72 - 1 - 1 -0.9000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3B9 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.977986036755 - 20 -1243.157187089064 - 11 -3317.977986036755 - 21 -1242.899906268309 - 0 -LINE - 5 -3BA -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.077986036848 - 20 -1243.157187089064 - 11 -3317.077986036848 - 21 -1242.899906268309 - 0 -ENDBLK - 5 -183 -330 -181 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -185 -330 -184 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D32 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D32 - 1 - - 0 -LINE - 5 -3BB -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.810469436013 - 20 -1243.552369962674 - 11 -3299.810469436013 - 21 -1245.472369962653 - 0 -SOLID - 5 -3BC -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3299.810469436013 - 20 -1243.552369962674 - 30 -0 - 11 -3299.780496940653 - 21 -1243.732369962674 - 31 -0 - 12 -3299.840441931373 - 22 -1243.732369962674 - 32 -0 - 13 -3299.840441931373 - 23 -1243.732369962674 - 33 -0 - 0 -SOLID - 5 -3BD -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3299.810469436013 - 20 -1247.752369962632 - 30 -0 - 11 -3299.840441931373 - 21 -1247.572369962632 - 31 -0 - 12 -3299.780496940653 - 22 -1247.572369962632 - 32 -0 - 13 -3299.780496940653 - 23 -1247.572369962632 - 33 -0 - 0 -LINE - 5 -3BE -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.810469436013 - 20 -1245.832369962653 - 11 -3299.810469436013 - 21 -1247.752369962632 - 0 -MTEXT - 5 -3BF -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3299.810469436013 - 20 -1245.652369962653 - 30 -0 - 40 -0.18 - 41 -0.72 - 71 - 5 - 72 - 1 - 1 -4.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3C0 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.81046943599 - 20 -1243.552369962674 - 11 -3299.630469436013 - 21 -1243.552369962674 - 0 -LINE - 5 -3C1 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3299.810469435998 - 20 -1247.752369962632 - 11 -3299.630469436013 - 21 -1247.752369962632 - 0 -ENDBLK - 5 -186 -330 -184 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -188 -330 -187 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D78 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D78 - 1 - - 0 -LINE - 5 -3C2 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369127 - 20 -1252.686624971338 - 11 -3427.522237369128 - 21 -1254.306622577448 - 0 -SOLID - 5 -3C3 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3427.522237369127 - 20 -1252.686624971338 - 30 -0 - 11 -3427.492264873767 - 21 -1252.866624971338 - 31 -0 - 12 -3427.552209864487 - 22 -1252.866624971338 - 32 -0 - 13 -3427.552209864487 - 23 -1252.866624971338 - 33 -0 - 0 -SOLID - 5 -3C4 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3427.522237369127 - 20 -1256.28662018356 - 30 -0 - 11 -3427.552209864487 - 21 -1256.10662018356 - 31 -0 - 12 -3427.492264873767 - 22 -1256.10662018356 - 32 -0 - 13 -3427.492264873767 - 23 -1256.10662018356 - 33 -0 - 0 -LINE - 5 -3C5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369128 - 20 -1254.666622577448 - 11 -3427.522237369127 - 21 -1256.28662018356 - 0 -MTEXT - 5 -3C6 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3427.394713937259 - 20 -1254.486622577448 - 30 -0 - 40 -0.18 - 41 -0.7000000000000224 - 71 - 5 - 72 - 1 - 1 -3.6000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3C7 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.994593221261 - 20 -1252.686624971338 - 11 -3427.342237369127 - 21 -1252.686624971338 - 0 -LINE - 5 -3C8 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369125 - 20 -1256.28662018356 - 11 -3427.342237369127 - 21 -1256.28662018356 - 0 -ENDBLK - 5 -189 -330 -187 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -18B -330 -18A -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D25 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D25 - 1 - - 0 -LINE - 5 -3C9 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3283.703068392752 - 20 -1243.079906270055 - 11 -3282.803068392845 - 21 -1243.079906270055 - 0 -SOLID - 5 -3CA -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3283.703068392752 - 20 -1243.079906270055 - 30 -0 - 11 -3283.523068392752 - 21 -1243.049933774695 - 31 -0 - 12 -3283.523068392752 - 22 -1243.109878765415 - 32 -0 - 13 -3283.523068392752 - 23 -1243.109878765415 - 33 -0 - 0 -SOLID - 5 -3CB -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3282.803068392845 - 20 -1243.079906270055 - 30 -0 - 11 -3282.983068392845 - 21 -1243.109878765415 - 31 -0 - 12 -3282.983068392845 - 22 -1243.049933774695 - 32 -0 - 13 -3282.983068392845 - 23 -1243.049933774695 - 33 -0 - 0 -MTEXT - 5 -3CC -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3282.159746428316 - 20 -1243.079906270055 - 30 -0 - 40 -0.18 - 41 -0.7000000000000001 - 71 - 5 - 72 - 1 - 1 -0.9000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3CD -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3283.703068392752 - 20 -1243.15718709081 - 11 -3283.703068392752 - 21 -1242.899906270055 - 0 -LINE - 5 -3CE -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3282.803068392845 - 20 -1243.15718709081 - 11 -3282.803068392845 - 21 -1242.899906270055 - 0 -ENDBLK - 5 -18C -330 -18A -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -18E -330 -18D -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D14 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D14 - 1 - - 0 -LINE - 5 -3CF -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3707.563574271881 - 20 -1108.933105405074 - 11 -3707.633024817817 - 21 -1108.517826670716 - 0 -SOLID - 5 -3D0 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3707.563574271881 - 20 -1108.933105405074 - 30 -0 - 11 -3707.622826783913 - 21 -1108.760514877246 - 31 -0 - 12 -3707.563702899914 - 22 -1108.750627094218 - 32 -0 - 13 -3707.563702899914 - 23 -1108.750627094218 - 33 -0 - 0 -SOLID - 5 -3D1 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3707.769716797048 - 20 -1107.700478565417 - 30 -0 - 11 -3707.710464285016 - 21 -1107.873069093245 - 31 -0 - 12 -3707.769588169015 - 22 -1107.882956876274 - 32 -0 - 13 -3707.769588169015 - 23 -1107.882956876274 - 33 -0 - 0 -LINE - 5 -3D2 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3707.693230637351 - 20 -1108.157826670716 - 11 -3707.769716797048 - 21 -1107.700478565417 - 0 -MTEXT - 5 -3D3 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3707.792422192403 - 20 -1108.337826670716 - 30 -0 - 40 -0.18 - 41 -0.68 - 71 - 5 - 72 - 1 - 1 -1.2497 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3D4 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3707.650442678567 - 20 -1108.947633137341 - 11 -3707.386039852539 - 21 -1108.903414835042 - 0 -LINE - 5 -3D5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3707.882337505863 - 20 -1107.719313071169 - 11 -3707.592182377706 - 21 -1107.670787995385 - 0 -ENDBLK - 5 -18F -330 -18D -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -191 -330 -190 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D85 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D85 - 1 - - 0 -LINE - 5 -3D6 -100 -AcDbEntity - 8 -BLK_1_FLR_2_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3440.165820340022 - 20 -1259.886620183188 - 11 -3440.165820340022 - 21 -1258.266620183374 - 0 -SOLID - 5 -3D7 -100 -AcDbEntity - 8 -BLK_1_FLR_2_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3440.165820340022 - 20 -1259.886620183188 - 30 -0 - 11 -3440.195792835382 - 21 -1259.706620183188 - 31 -0 - 12 -3440.135847844662 - 22 -1259.706620183188 - 32 -0 - 13 -3440.135847844662 - 23 -1259.706620183188 - 33 -0 - 0 -SOLID - 5 -3D8 -100 -AcDbEntity - 8 -BLK_1_FLR_2_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3440.165820340022 - 20 -1256.28662018356 - 30 -0 - 11 -3440.135847844662 - 21 -1256.46662018356 - 31 -0 - 12 -3440.195792835382 - 22 -1256.46662018356 - 32 -0 - 13 -3440.195792835382 - 23 -1256.46662018356 - 33 -0 - 0 -LINE - 5 -3D9 -100 -AcDbEntity - 8 -BLK_1_FLR_2_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3440.165820340022 - 20 -1257.906620183374 - 11 -3440.165820340022 - 21 -1256.28662018356 - 0 -MTEXT - 5 -3DA -100 -AcDbEntity - 8 -BLK_1_FLR_2_HT_ROOM - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3440.165820340022 - 20 -1258.086620183374 - 30 -0 - 40 -0.18 - 41 -0.7000000000000224 - 71 - 5 - 72 - 1 - 1 -3.6000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3DB -100 -AcDbEntity - 8 -BLK_1_FLR_2_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3440.149415793408 - 20 -1259.886620183188 - 11 -3440.345820340022 - 21 -1259.886620183188 - 0 -LINE - 5 -3DC -100 -AcDbEntity - 8 -BLK_1_FLR_2_HT_ROOM - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3440.149415793408 - 20 -1256.28662018356 - 11 -3440.345820340022 - 21 -1256.28662018356 - 0 -ENDBLK - 5 -192 -330 -190 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -194 -330 -193 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D76 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D76 - 1 - - 0 -LINE - 5 -3DD -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.69992944449 - 20 -1246.986620183514 - 11 -3427.342237369113 - 21 -1246.986620183514 - 0 -LINE - 5 -3DE -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.69992944449 - 20 -1248.636620183537 - 11 -3427.342237369113 - 21 -1248.636620183537 - 0 -LINE - 5 -3DF -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369113 - 20 -1246.986620183514 - 11 -3427.522237369113 - 21 -1247.631620183526 - 0 -SOLID - 5 -3E0 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3427.522237369113 - 20 -1246.986620183514 - 30 -0 - 11 -3427.492264873753 - 21 -1247.166620183514 - 31 -0 - 12 -3427.552209864473 - 22 -1247.166620183514 - 32 -0 - 13 -3427.552209864473 - 23 -1247.166620183514 - 33 -0 - 0 -SOLID - 5 -3E1 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3427.522237369113 - 20 -1248.636620183537 - 30 -0 - 11 -3427.552209864473 - 21 -1248.456620183537 - 31 -0 - 12 -3427.492264873753 - 22 -1248.456620183537 - 32 -0 - 13 -3427.492264873753 - 23 -1248.456620183537 - 33 -0 - 0 -LINE - 5 -3E2 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3427.522237369113 - 20 -1247.991620183526 - 11 -3427.522237369113 - 21 -1248.636620183537 - 0 -MTEXT - 5 -3E3 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3427.394713937245 - 20 -1247.811620183526 - 30 -0 - 40 -0.18 - 41 -0.6600000000000223 - 71 - 5 - 72 - 1 - 1 -1.6500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -195 -330 -193 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -197 -330 -196 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D15 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D15 - 1 - - 0 -LINE - 5 -3E4 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3707.685515145951 - 20 -1107.686396817056 - 11 -3707.751080364225 - 21 -1107.294350354412 - 0 -SOLID - 5 -3E5 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3707.685515145951 - 20 -1107.686396817056 - 30 -0 - 11 -3707.744767657984 - 21 -1107.513806289228 - 31 -0 - 12 -3707.685643773985 - 22 -1107.5039185062 - 32 -0 - 13 -3707.685643773985 - 23 -1107.5039185062 - 33 -0 - 0 -SOLID - 5 -3E6 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3707.883887015795 - 20 -1106.500234520827 - 30 -0 - 11 -3707.824634503763 - 21 -1106.672825048655 - 31 -0 - 12 -3707.883758387762 - 22 -1106.682712831683 - 32 -0 - 13 -3707.883758387762 - 23 -1106.682712831683 - 33 -0 - 0 -LINE - 5 -3E7 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3707.811286183759 - 20 -1106.934350354412 - 11 -3707.883887015795 - 21 -1106.500234520827 - 0 -MTEXT - 5 -3E8 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3707.910477738811 - 20 -1107.114350354412 - 30 -0 - 40 -0.18 - 41 -0.6600000000000112 - 71 - 5 - 72 - 1 - 1 -1.2026 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3E9 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3707.764369543838 - 20 -1107.699584299413 - 11 -3707.507980726609 - 21 -1107.656706247023 - 0 -LINE - 5 -3EA -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3707.997366203883 - 20 -1106.519212597268 - 11 -3707.706352596453 - 21 -1106.470543950794 - 0 -ENDBLK - 5 -198 -330 -196 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -19A -330 -199 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D9 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D9 - 1 - - 0 -LINE - 5 -3EB -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3698.04843085989 - 20 -1107.017542090556 - 11 -3698.150796985409 - 21 -1106.490908174588 - 0 -LINE - 5 -3EC -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3711.16218060348 - 20 -1109.566568485509 - 11 -3711.264546728999 - 21 -1109.039934569541 - 0 -LINE - 5 -3ED -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3698.116451734113 - 20 -1106.667601139115 - 11 -3704.391301684291 - 21 -1107.887294854499 - 0 -SOLID - 5 -3EE -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3698.116451734113 - 20 -1106.667601139115 - 30 -0 - 11 -3698.287425738167 - 21 -1106.731368218519 - 31 -0 - 12 -3698.298863659113 - 22 -1106.672524562304 - 32 -0 - 13 -3698.298863659113 - 23 -1106.672524562304 - 33 -0 - 0 -SOLID - 5 -3EF -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3711.230201477702 - 20 -1109.216627534068 - 30 -0 - 11 -3711.059227473648 - 21 -1109.152860454664 - 31 -0 - 12 -3711.047789552702 - 22 -1109.211704110879 - 32 -0 - 13 -3711.047789552702 - 23 -1109.211704110879 - 33 -0 - 0 -LINE - 5 -3F0 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3705.138994248611 - 20 -1108.032629950793 - 11 -3711.230201477702 - 21 -1109.216627534068 - 0 -MTEXT - 5 -3F1 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3704.648994248611 - 20 -1108.067294854499 - 30 -0 - 40 -0.18 - 41 -0.8000000000000336 - 71 - 5 - 72 - 1 - 1 -13.3592 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -19B -330 -199 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -19D -330 -19C -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D51 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D51 - 1 - - 0 -LINE - 5 -3F2 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.838675251231 - 20 -1258.458460622718 - 11 -3352.088675251034 - 21 -1258.458460622718 - 0 -SOLID - 5 -3F3 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3352.838675251231 - 20 -1258.458460622718 - 30 -0 - 11 -3352.658675251231 - 21 -1258.428488127358 - 31 -0 - 12 -3352.658675251231 - 22 -1258.488433118078 - 32 -0 - 13 -3352.658675251231 - 23 -1258.488433118078 - 33 -0 - 0 -SOLID - 5 -3F4 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3352.088675251034 - 20 -1258.458460622718 - 30 -0 - 11 -3352.268675251034 - 21 -1258.488433118078 - 31 -0 - 12 -3352.268675251034 - 22 -1258.428488127358 - 32 -0 - 13 -3352.268675251034 - 23 -1258.428488127358 - 33 -0 - 0 -MTEXT - 5 -3F5 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3351.445353286505 - 20 -1258.458460622718 - 30 -0 - 40 -0.18 - 41 -0.7000000000000112 - 71 - 5 - 72 - 1 - 1 -0.7500 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3F6 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.838675251231 - 20 -1258.300104121969 - 11 -3352.838675251231 - 21 -1258.638460622718 - 0 -LINE - 5 -3F7 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3352.088675251034 - 20 -1258.300104121969 - 11 -3352.088675251034 - 21 -1258.638460622718 - 0 -ENDBLK - 5 -19E -330 -19C -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1A0 -330 -19F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D41 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D41 - 1 - - 0 -LINE - 5 -3F8 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3315.877986022184 - 20 -1243.756683315703 - 11 -3316.057986022213 - 21 -1243.756683315703 - 0 -SOLID - 5 -3F9 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3315.877986022184 - 20 -1243.756683315703 - 30 -0 - 11 -3316.057986022184 - 21 -1243.786655811063 - 31 -0 - 12 -3316.057986022184 - 22 -1243.726710820343 - 32 -0 - 13 -3316.057986022184 - 23 -1243.726710820343 - 33 -0 - 0 -SOLID - 5 -3FA -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.077986022245 - 20 -1243.756683315703 - 30 -0 - 11 -3316.897986022245 - 21 -1243.726710820343 - 31 -0 - 12 -3316.897986022245 - 22 -1243.786655811063 - 32 -0 - 13 -3316.897986022245 - 23 -1243.786655811063 - 33 -0 - 0 -LINE - 5 -3FB -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3316.897986022214 - 20 -1243.756683315703 - 11 -3317.077986022245 - 21 -1243.756683315703 - 0 -MTEXT - 5 -3FC -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3316.477986022214 - 20 -1243.756683315703 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -3FD -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3315.877986022184 - 20 -1245.9523699609 - 11 -3315.877986022184 - 21 -1243.576683315703 - 0 -LINE - 5 -3FE -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.077986022245 - 20 -1243.552371273841 - 11 -3317.077986022245 - 21 -1243.936683315703 - 0 -ENDBLK - 5 -1A1 -330 -19F -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1A3 -330 -1A2 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D68 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D68 - 1 - - 0 -LINE - 5 -3FF -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.977986019338 - 20 -1245.414869962667 - 11 -3317.977986019338 - 21 -1246.400390913326 - 0 -LINE - 5 -400 -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3319.177986019524 - 20 -1245.414869962667 - 11 -3319.177986019524 - 21 -1246.400390913326 - 0 -LINE - 5 -401 -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.977986019338 - 20 -1246.220390913326 - 11 -3318.157986019431 - 21 -1246.220390913326 - 0 -SOLID - 5 -402 -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.977986019338 - 20 -1246.220390913326 - 30 -0 - 11 -3318.157986019338 - 21 -1246.250363408686 - 31 -0 - 12 -3318.157986019338 - 22 -1246.190418417966 - 32 -0 - 13 -3318.157986019338 - 23 -1246.190418417966 - 33 -0 - 0 -SOLID - 5 -403 -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3319.177986019524 - 20 -1246.220390913326 - 30 -0 - 11 -3318.997986019524 - 21 -1246.190418417966 - 31 -0 - 12 -3318.997986019524 - 22 -1246.250363408686 - 32 -0 - 13 -3318.997986019524 - 23 -1246.250363408686 - 33 -0 - 0 -LINE - 5 -404 -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3318.997986019431 - 20 -1246.220390913326 - 11 -3319.177986019524 - 21 -1246.220390913326 - 0 -MTEXT - 5 -405 -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3318.577986019431 - 20 -1246.220390913326 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -ENDBLK - 5 -1A4 -330 -1A2 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1A6 -330 -1A5 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D45 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D45 - 1 - - 0 -LINE - 5 -406 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3354.188675249481 - 20 -1245.809053745032 - 11 -3354.368675249458 - 21 -1245.809053745032 - 0 -SOLID - 5 -407 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3354.188675249481 - 20 -1245.809053745032 - 30 -0 - 11 -3354.368675249481 - 21 -1245.839026240392 - 31 -0 - 12 -3354.368675249481 - 22 -1245.779081249672 - 32 -0 - 13 -3354.368675249481 - 23 -1245.779081249672 - 33 -0 - 0 -SOLID - 5 -408 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3355.388675249435 - 20 -1245.809053745032 - 30 -0 - 11 -3355.208675249435 - 21 -1245.779081249672 - 31 -0 - 12 -3355.208675249435 - 22 -1245.839026240392 - 32 -0 - 13 -3355.208675249435 - 23 -1245.839026240392 - 33 -0 - 0 -LINE - 5 -409 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3355.208675249458 - 20 -1245.809053745032 - 11 -3355.388675249435 - 21 -1245.809053745032 - 0 -MTEXT - 5 -40A -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3354.788675249458 - 20 -1245.809053745032 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -40B -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3354.188675249481 - 20 -1245.652369962656 - 11 -3354.188675249481 - 21 -1245.989053745032 - 0 -LINE - 5 -40C -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3355.388675249435 - 20 -1245.652369962656 - 11 -3355.388675249435 - 21 -1245.989053745032 - 0 -ENDBLK - 5 -1A7 -330 -1A5 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1A9 -330 -1A8 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*D40 - 70 - 1 - 10 -0 - 20 -0 - 3 -*D40 - 1 - - 0 -LINE - 5 -40D -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.527986022219 - 20 -1243.552369960933 - 11 -3317.527986022219 - 21 -1243.13236941446 - 0 -SOLID - 5 -40E -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.527986022219 - 20 -1243.552369960933 - 30 -0 - 11 -3317.557958517579 - 21 -1243.372369960933 - 31 -0 - 12 -3317.498013526859 - 22 -1243.372369960933 - 32 -0 - 13 -3317.498013526859 - 23 -1243.372369960933 - 33 -0 - 0 -SOLID - 5 -40F -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbTrace - 10 -3317.527986022219 - 20 -1242.352368867987 - 30 -0 - 11 -3317.498013526859 - 21 -1242.532368867987 - 31 -0 - 12 -3317.557958517579 - 22 -1242.532368867987 - 32 -0 - 13 -3317.557958517579 - 23 -1242.532368867987 - 33 -0 - 0 -LINE - 5 -410 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.527986022219 - 20 -1242.77236941446 - 11 -3317.527986022219 - 21 -1242.352368867987 - 0 -MTEXT - 5 -411 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 0 -370 - -2 -100 -AcDbMText - 10 -3317.527986022219 - 20 -1242.95236941446 - 30 -0 - 40 -0.18 - 41 -0.66 - 71 - 5 - 72 - 1 - 1 -1.2000 - 7 -Standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 2 - 44 -1 - 0 -LINE - 5 -412 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.527986022199 - 20 -1243.552369960933 - 11 -3317.707986022219 - 21 -1243.552369960933 - 0 -LINE - 5 -413 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -ByBlock - 62 - 0 -370 - -2 -100 -AcDbLine - 10 -3317.5272526697 - 20 -1242.352368867987 - 11 -3317.707986022219 - 21 -1242.352368867987 - 0 -ENDBLK - 5 -1AA -330 -1A8 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1AC -330 -1AB -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -_ArchTick - 70 - 0 - 10 -0 - 20 -0 - 3 -_ArchTick - 1 - - 0 -LWPOLYLINE - 5 -414 -100 -AcDbEntity - 8 -0 - 6 -ByBlock - 62 - 0 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 --0.5 - 20 --0.5 - 10 -0.5 - 20 -0.5 - 0 -ENDBLK - 5 -1AD -330 -1AB -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1AF -330 -1AE -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -15 - 70 - 0 - 10 -0 - 20 -0 - 3 -15 - 1 - - 0 -ARC - 5 -415 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --734091.4099779375 - 20 -80100.94134111518 - 40 -70.32638888976521 -100 -AcDbArc - 50 -91.56964921010622 - 51 -180 - 0 -ARC - 5 -416 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --734165.2626789922 - 20 -80096.93645957157 - 40 -5.257852012237923 -100 -AcDbArc - 50 -2.233197218398334 - 51 -71.98227889500916 - 0 -LINE - 5 -417 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734163.6363668273 - 20 -80102.84134111532 - 11 --734163.6363668273 - 21 -80097.14134111512 - 0 -ARC - 5 -418 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --734167.1882080254 - 20 -80096.54173647799 - 40 -5.257852012237923 -100 -AcDbArc - 50 -6.548247974590567 - 51 -47.50461327031654 - 0 -LWPOLYLINE - 5 -419 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbPolyline - 90 - 31 - 70 - 0 - 43 -0 - 10 --734163.6363668273 - 20 -80097.14134111512 - 10 --734163.6363668273 - 20 -80097.14134111512 - 10 --734163.1723273654 - 20 -80097.44901241222 - 10 --734162.7565162109 - 20 -80097.71946787395 - 10 --734162.3857100526 - 20 -80097.95577616198 - 10 --734162.056685581 - 20 -80098.16100593797 - 10 --734161.7662194849 - 20 -80098.33822586434 - 10 --734161.5110884544 - 20 -80098.4905046036 - 10 --734161.2880691785 - 20 -80098.62091081683 - 10 --734161.0939383473 - 20 -80098.73251316648 - 10 --734160.9255309461 - 20 -80098.82822946853 - 10 --734160.7799151447 - 20 -80098.91037415131 - 10 --734160.6542174083 - 20 -80098.98111079843 - 10 --734160.5455642029 - 20 -80099.04260299215 - 10 --734160.4510819934 - 20 -80099.09701431516 - 10 --734160.3678972463 - 20 -80099.14650835002 - 10 --734160.2931364268 - 20 -80099.19324867986 - 10 --734160.2239260002 - 20 -80099.23939888713 - 10 --734160.1580001159 - 20 -80099.28655706812 - 10 --734160.0955236605 - 20 -80099.33405937278 - 10 --734160.0372692031 - 20 -80099.38067646488 - 10 --734159.9840093135 - 20 -80099.42517900723 - 10 --734159.9365165612 - 20 -80099.46633766427 - 10 --734159.8955635166 - 20 -80099.50292309909 - 10 --734159.8619227484 - 20 -80099.5337059747 - 10 --734159.8363668271 - 20 -80099.55745695531 - 10 --734162.3317586886 - 20 -80098.01414672192 - 10 --734160.8201769179 - 20 -80098.90035531577 - 10 --734160.1953728407 - 20 -80099.22261531162 - 10 --734159.8930494264 - 20 -80099.5045896107 - 10 --734159.8363668271 - 20 -80099.55745695531 - 0 -LWPOLYLINE - 5 -41A -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbPolyline - 90 - 31 - 70 - 0 - 43 -0 - 10 --734163.6015240891 - 20 -80097.1883538838 - 10 --734163.6015240891 - 20 -80097.1883538838 - 10 --734163.3875578792 - 20 -80097.60942625767 - 10 --734163.2105751225 - 20 -80097.97194359101 - 10 --734163.0650450413 - 20 -80098.28438336543 - 10 --734162.9454368583 - 20 -80098.5552230624 - 10 --734162.8462197967 - 20 -80098.79294016329 - 10 --734162.7618630792 - 20 -80099.00601214916 - 10 --734162.6868359284 - 20 -80099.20291650177 - 10 --734162.6156075672 - 20 -80099.39213070294 - 10 --734162.5437002353 - 20 -80099.58080452634 - 10 --734162.4708482389 - 20 -80099.77077691932 - 10 --734162.397838902 - 20 -80099.96255912072 - 10 --734162.3254595482 - 20 -80100.15666237148 - 10 --734162.2544975006 - 20 -80100.35359790991 - 10 --734162.1857400835 - 20 -80100.55387697672 - 10 --734162.1199746196 - 20 -80100.75801081119 - 10 --734162.0579884327 - 20 -80100.9665106528 - 10 --734162.0004589543 - 20 -80101.17905548959 - 10 --734161.9476240454 - 20 -80101.39199530031 - 10 --734161.8996116756 - 20 -80101.60084781237 - 10 --734161.8565498136 - 20 -80101.80113075326 - 10 --734161.8185664287 - 20 -80101.98836184946 - 10 --734161.78578949 - 20 -80102.15805882867 - 10 --734161.7583469664 - 20 -80102.3057394179 - 10 --734161.7363668274 - 20 -80102.4269213439 - 10 --734162.9767200124 - 20 -80098.39682247373 - 10 --734162.6340821024 - 20 -80099.38373252051 - 10 --734162.0092780259 - 20 -80100.91448668436 - 10 --734161.7875836025 - 20 -80102.14308533377 - 10 --734161.7363668274 - 20 -80102.4269213439 - 0 -LINE - 5 -41B -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734159.8363668271 - 20 -80097.14134111512 - 11 --734159.8363668271 - 21 -80100.94134111518 - 0 -LINE - 5 -41C -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734163.6363668273 - 20 -80097.14134111512 - 11 --734159.8363668271 - 21 -80097.14134111512 - 0 -LINE - 5 -41D -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734161.7363668274 - 20 -80102.84134111532 - 11 --734163.6363668273 - 21 -80102.84134111532 - 0 -LINE - 5 -41E -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734161.7363668274 - 20 -80100.94134111518 - 11 --734161.7363668274 - 21 -80102.84134111532 - 0 -LINE - 5 -41F -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734159.8363668271 - 20 -80100.94134111518 - 11 --734161.7363668274 - 21 -80100.94134111518 - 0 -LINE - 5 -420 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734091.4363668264 - 20 -80102.84134111532 - 11 --734091.4363668264 - 21 -80171.24134111615 - 0 -LINE - 5 -421 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734089.5363668264 - 20 -80100.94134111518 - 11 --734089.5363668264 - 21 -80171.24134111615 - 0 -LINE - 5 -422 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734087.6363668264 - 20 -80102.84134111532 - 11 --734087.6363668264 - 21 -80097.14134111512 - 0 -ARC - 5 -423 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --734084.084525628 - 20 -80096.54173647799 - 40 -5.257852012237923 -100 -AcDbArc - 50 -132.4953867296834 - 51 -173.4517520254094 - 0 -ARC - 5 -424 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --734086.0100546615 - 20 -80096.93645957157 - 40 -5.257852012237923 -100 -AcDbArc - 50 -108.0177211049908 - 51 -177.7668027816016 - 0 -LWPOLYLINE - 5 -425 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbPolyline - 90 - 31 - 70 - 0 - 43 -0 - 10 --734087.6363668264 - 20 -80097.14134111512 - 10 --734087.6363668264 - 20 -80097.14134111512 - 10 --734088.1004062882 - 20 -80097.44901241222 - 10 --734088.5162174429 - 20 -80097.71946787395 - 10 --734088.887023601 - 20 -80097.95577616198 - 10 --734089.2160480727 - 20 -80098.16100593797 - 10 --734089.506514169 - 20 -80098.33822586459 - 10 --734089.7616451994 - 20 -80098.4905046036 - 10 --734089.9846644752 - 20 -80098.62091081683 - 10 --734090.1787953064 - 20 -80098.73251316648 - 10 --734090.3472027074 - 20 -80098.82822946853 - 10 --734090.4928185089 - 20 -80098.91037415131 - 10 --734090.6185162457 - 20 -80098.98111079843 - 10 --734090.727169451 - 20 -80099.04260299215 - 10 --734090.8216516601 - 20 -80099.09701431516 - 10 --734090.9048364074 - 20 -80099.14650835002 - 10 --734090.9795972272 - 20 -80099.19324867986 - 10 --734091.0488076537 - 20 -80099.23939888713 - 10 --734091.1147335377 - 20 -80099.28655706812 - 10 --734091.1772099932 - 20 -80099.33405937278 - 10 --734091.2354644507 - 20 -80099.38067646488 - 10 --734091.2887243401 - 20 -80099.42517900723 - 10 --734091.3362170924 - 20 -80099.46633766427 - 10 --734091.3771701372 - 20 -80099.50292309909 - 10 --734091.4108109052 - 20 -80099.5337059747 - 10 --734091.4363668264 - 20 -80099.55745695531 - 10 --734088.9409749656 - 20 -80098.01414672192 - 10 --734090.4525567363 - 20 -80098.90035531577 - 10 --734091.0773608128 - 20 -80099.22261531182 - 10 --734091.3796842272 - 20 -80099.5045896107 - 10 --734091.4363668264 - 20 -80099.55745695531 - 0 -LWPOLYLINE - 5 -426 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbPolyline - 90 - 31 - 70 - 0 - 43 -0 - 10 --734087.6712095645 - 20 -80097.1883538838 - 10 --734087.6712095645 - 20 -80097.1883538838 - 10 --734087.8851757747 - 20 -80097.60942625767 - 10 --734088.0621585316 - 20 -80097.97194359101 - 10 --734088.2076886126 - 20 -80098.28438336543 - 10 --734088.3272967953 - 20 -80098.5552230624 - 10 --734088.4265138567 - 20 -80098.79294016329 - 10 --734088.5108705745 - 20 -80099.00601214916 - 10 --734088.5858977252 - 20 -80099.20291650177 - 10 --734088.6571260863 - 20 -80099.39213070294 - 10 --734088.7290334183 - 20 -80099.58080452634 - 10 --734088.8018854148 - 20 -80099.77077691932 - 10 --734088.8748947517 - 20 -80099.9625591212 - 10 --734088.9472741057 - 20 -80100.15666237148 - 10 --734089.0182361529 - 20 -80100.35359790991 - 10 --734089.0869935704 - 20 -80100.55387697672 - 10 --734089.1527590343 - 20 -80100.75801081119 - 10 --734089.214745221 - 20 -80100.9665106528 - 10 --734089.2722746994 - 20 -80101.17905548959 - 10 --734089.3251096081 - 20 -80101.39199530031 - 10 --734089.3731219782 - 20 -80101.60084781237 - 10 --734089.4161838399 - 20 -80101.80113075326 - 10 --734089.454167225 - 20 -80101.98836184946 - 10 --734089.4869441638 - 20 -80102.15805882867 - 10 --734089.5143866872 - 20 -80102.3057394179 - 10 --734089.5363668264 - 20 -80102.42692134411 - 10 --734088.2960136411 - 20 -80098.39682247373 - 10 --734088.6386515513 - 20 -80099.38373252051 - 10 --734089.263455628 - 20 -80100.91448668436 - 10 --734089.4851500515 - 20 -80102.14308533377 - 10 --734089.5363668264 - 20 -80102.42692134411 - 0 -LINE - 5 -427 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734091.4363668264 - 20 -80097.14134111512 - 11 --734091.4363668264 - 21 -80100.94134111518 - 0 -LINE - 5 -428 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734087.6363668264 - 20 -80097.14134111512 - 11 --734091.4363668264 - 21 -80097.14134111512 - 0 -LINE - 5 -429 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734091.4363668264 - 20 -80100.94134111518 - 11 --734089.5363668264 - 21 -80100.94134111518 - 0 -LINE - 5 -42A -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734087.6363668264 - 20 -80102.84134111532 - 11 --734091.4363668264 - 21 -80102.84134111532 - 0 -LINE - 5 -42B -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --734091.4363668264 - 20 -80171.24134111615 - 11 --734089.5363668264 - 21 -80171.24134111615 - 0 -ENDBLK - 5 -1B0 -330 -1AE -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1B2 -330 -1B1 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -tre - 70 - 0 - 10 -0 - 20 -0 - 3 -tre - 1 - - 0 -LINE - 5 -42C -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255972.014028702 - 20 -16948.64158117022 - 11 -255971.1466769398 - 21 -16948.22025093948 - 0 -LINE - 5 -42D -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255900.8811767594 - 20 -16960.08043886342 - 11 -255900.8811767594 - 21 -16962.34541863444 - 0 -LINE - 5 -42E -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255900.8811767594 - 20 -16962.34541863444 - 11 -255901.0339511941 - 21 -16965.096771303 - 0 -LINE - 5 -42F -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255901.0339511941 - 20 -16965.096771303 - 11 -255901.7214405925 - 21 -16968.76524965129 - 0 -LINE - 5 -430 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255901.7214405925 - 20 -16968.76524965129 - 11 -255903.4019727012 - 21 -16971.44018178025 - 0 -LINE - 5 -431 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.4019727012 - 20 -16971.44018178025 - 11 -255905.464445339 - 21 -16974.49724707053 - 0 -LINE - 5 -432 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255905.464445339 - 20 -16974.49724707053 - 11 -255908.2907945926 - 21 -16976.25505961241 - 0 -LINE - 5 -433 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255908.2907945926 - 20 -16976.25505961241 - 11 -255912.3393482084 - 21 -16977.24859973907 - 0 -LINE - 5 -434 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255912.3393482084 - 20 -16977.24859973907 - 11 -255913.6379442306 - 21 -16977.55430626807 - 0 -LINE - 5 -435 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255913.6379442306 - 20 -16977.55430626807 - 11 -255914.4782080637 - 21 -16977.47787963581 - 0 -LINE - 5 -436 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255914.4782080637 - 20 -16977.47787963581 - 11 -255916.1587401722 - 21 -16976.17863298017 - 0 -LINE - 5 -437 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255916.1587401722 - 20 -16976.17863298017 - 11 -255917.3045573172 - 21 -16974.95580686404 - 0 -LINE - 5 -438 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255917.3045573172 - 20 -16974.95580686404 - 11 -255918.4503744621 - 21 -16972.35730136735 - 0 -LINE - 5 -439 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255918.4503744621 - 20 -16972.35730136735 - 11 -255919.2906427375 - 21 -16968.00098332872 - 0 -LINE - 5 -43A -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255919.2906427375 - 20 -16968.00098332872 - 11 -255919.6725832669 - 21 -16962.19256536994 - 0 -LINE - 5 -43B -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255919.6725832669 - 20 -16962.19256536994 - 11 -255919.8253577014 - 21 -16960.08043886342 - 0 -LINE - 5 -43C -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255919.8253577014 - 20 -16960.08043886342 - 11 -255919.6725832669 - 21 -16957.9683123569 - 0 -LINE - 5 -43D -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255919.6725832669 - 20 -16957.9683123569 - 11 -255919.2906427375 - 21 -16952.15989439811 - 0 -LINE - 5 -43E -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255919.2906427375 - 20 -16952.15989439811 - 11 -255918.4503744621 - 21 -16947.80357635949 - 0 -LINE - 5 -43F -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255918.4503744621 - 20 -16947.80357635949 - 11 -255917.3045573172 - 21 -16945.20507086277 - 0 -LINE - 5 -440 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255917.3045573172 - 20 -16945.20507086277 - 11 -255916.1587401722 - 21 -16943.98224474666 - 0 -LINE - 5 -441 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255916.1587401722 - 20 -16943.98224474666 - 11 -255914.4782080637 - 21 -16942.682998091 - 0 -LINE - 5 -442 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255914.4782080637 - 20 -16942.682998091 - 11 -255913.6379442306 - 21 -16942.60657145877 - 0 -LINE - 5 -443 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255913.6379442306 - 20 -16942.60657145877 - 11 -255912.3393482084 - 21 -16942.91227798777 - 0 -LINE - 5 -444 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255912.3393482084 - 20 -16942.91227798777 - 11 -255908.2907945926 - 21 -16943.9058181144 - 0 -LINE - 5 -445 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255908.2907945926 - 20 -16943.9058181144 - 11 -255905.464445339 - 21 -16945.66363065631 - 0 -LINE - 5 -446 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255905.464445339 - 20 -16945.66363065631 - 11 -255903.4019727012 - 21 -16948.72069594659 - 0 -LINE - 5 -447 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.4019727012 - 20 -16948.72069594659 - 11 -255901.7214405925 - 21 -16951.39562807554 - 0 -LINE - 5 -448 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255901.7214405925 - 20 -16951.39562807554 - 11 -255901.0339511941 - 21 -16955.06410642384 - 0 -LINE - 5 -449 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255901.0339511941 - 20 -16955.06410642384 - 11 -255900.8811767594 - 21 -16957.8154590924 - 0 -LINE - 5 -44A -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255900.8811767594 - 20 -16957.8154590924 - 11 -255900.8811767594 - 21 -16960.08043886342 - 0 -ARC - 5 -44B -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255916.3988343029 - 20 -16955.10161375379 - 40 -16.63276459285422 -100 -AcDbArc - 50 -212.9825838813756 - 51 -267.8609705026604 - 0 -LINE - 5 -44C -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255915.778025748 - 20 -16938.4804388634 - 11 -255916.316015082 - 21 -16938.75521048949 - 0 -ARC - 5 -44D -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255910.8578436243 - 20 -16949.44204184124 - 40 -12.00000000014797 -100 -AcDbArc - 50 -297.0551303575777 - 51 -313.545700673336 - 0 -LINE - 5 -44E -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255919.1250388443 - 20 -16940.74414076125 - 11 -255919.2579466097 - 21 -16940.87046715113 - 0 -LINE - 5 -44F -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255919.2579466097 - 20 -16940.87046715113 - 11 -255919.4799538744 - 21 -16941.14547200695 - 0 -ARC - 5 -450 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255910.1428005038 - 20 -16948.68321483453 - 40 -12.00000000002144 -100 -AcDbArc - 50 -321.0865864327741 - 51 -339.784627350406 - 0 -LINE - 5 -451 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255921.4036046356 - 20 -16944.53661498584 - 11 -255921.4174608355 - 21 -16944.57424387672 - 0 -ARC - 5 -452 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255910.1566567036 - 20 -16948.72084372542 - 40 -12.00000000001947 -100 -AcDbArc - 50 -339.784627350406 - 51 -347.4773250022013 - 0 -LINE - 5 -453 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255921.8711799912 - 20 -16946.11893209258 - 11 -255922.5595169441 - 21 -16949.21801476864 - 0 -ARC - 5 -454 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255910.8449936568 - 20 -16951.81992640147 - 40 -11.9999999998828 -100 -AcDbArc - 50 -347.4773250022013 - 51 -352.4091937246277 - 0 -LINE - 5 -455 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255922.7398346501 - 20 -16950.23475835329 - 11 -255923.2842283672 - 21 -16954.31979950199 - 0 -ARC - 5 -456 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255911.3893873738 - 20 -16955.90496754954 - 40 -11.99999999979925 -100 -AcDbArc - 50 -352.4091937279335 - 51 -358.4754835808301 - 0 -LINE - 5 -457 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255923.3851397643 - 20 -16955.58571125153 - 11 -255923.5047629486 - 21 -16960.08043886342 - 0 -LINE - 5 -458 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255914.4782080637 - 20 -16942.1480116652 - 11 -255915.547637991 - 21 -16939.16737300721 - 0 -ARC - 5 -459 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255916.3988343029 - 20 -16965.05926397305 - 40 -16.63276459285422 -100 -AcDbArc - 50 -92.13902949733965 - 51 -147.0174161186244 - 0 -LINE - 5 -45A -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255915.778025748 - 20 -16981.68043886342 - 11 -255916.316015082 - 21 -16981.40566723732 - 0 -ARC - 5 -45B -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255910.8578436243 - 20 -16970.7188358856 - 40 -12.00000000008443 -100 -AcDbArc - 50 -46.45429932695114 - 51 -62.94486964251714 - 0 -LINE - 5 -45C -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255919.1250388443 - 20 -16979.41673696558 - 11 -255919.2579466097 - 21 -16979.29041057571 - 0 -LINE - 5 -45D -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255919.2579466097 - 20 -16979.29041057571 - 11 -255919.4799538744 - 21 -16979.01540571989 - 0 -ARC - 5 -45E -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255910.1428005038 - 20 -16971.4776628923 - 40 -12.00000000002144 -100 -AcDbArc - 50 -20.21537264959403 - 51 -38.9134135672259 - 0 -LINE - 5 -45F -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255921.4036046356 - 20 -16975.624262741 - 11 -255921.4174608355 - 21 -16975.58663385011 - 0 -ARC - 5 -460 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255910.1566567036 - 20 -16971.44003400142 - 40 -12.00000000001947 -100 -AcDbArc - 50 -12.52267499779867 - 51 -20.21537264959403 - 0 -LINE - 5 -461 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255921.8711799912 - 20 -16974.04194563425 - 11 -255922.5595169441 - 21 -16970.9428629582 - 0 -ARC - 5 -462 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255910.8449936568 - 20 -16968.34095132536 - 40 -11.9999999998828 -100 -AcDbArc - 50 -7.590806275372302 - 51 -12.52267499779867 - 0 -LINE - 5 -463 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255922.7398346501 - 20 -16969.92611937355 - 11 -255923.2842283672 - 21 -16965.84107822484 - 0 -ARC - 5 -464 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255911.3893873738 - 20 -16964.2559101773 - 40 -11.99999999993772 -100 -AcDbArc - 50 -1.524516419169975 - 51 -7.590806272066473 - 0 -LINE - 5 -465 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255923.3851397643 - 20 -16964.57516647528 - 11 -255923.5047629486 - 21 -16960.08043886342 - 0 -ELLIPSE - 5 -466 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -255909.3455914413 - 20 -16960.08043886342 - 30 -0 - 11 --4.375286e-10 - 21 -21.60000000086583 - 31 -0 - 40 -0.4201486266968101 - 41 -1.570796326786386 - 42 -2.277981026602279 - 0 -ELLIPSE - 5 -467 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -255909.3455914413 - 20 -16960.08043886342 - 30 -0 - 11 --4.375286e-10 - 21 -21.60000000086583 - 31 -0 - 40 -0.4201486266968101 - 41 -0.863611626987514 - 42 -1.570796326803408 - 0 -LINE - 5 -468 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255931.3586763357 - 20 -16980.14649989848 - 11 -255920.5866514946 - 21 -16977.38748323465 - 0 -LINE - 5 -469 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255914.4782080637 - 20 -16978.01286606161 - 11 -255915.547637991 - 21 -16980.99350471963 - 0 -LINE - 5 -46A -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255931.3586763357 - 20 -16980.14651208388 - 11 -255936.2802127248 - 21 -16981.78682096109 - 0 -LINE - 5 -46B -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255936.2802127248 - 20 -16981.78682096109 - 11 -255945.8977432138 - 21 -16982.45815556952 - 0 -LINE - 5 -46C -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255945.8977432138 - 20 -16982.45815556952 - 11 -255952.8455914413 - 21 -16981.68045104879 - 0 -ARC - 5 -46D -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255945.8877535334 - 20 -16915.43556604394 - 40 -66.60928086729827 -100 -AcDbArc - 50 -74.65481712156559 - 51 -84.00408918623717 - 0 -ARC - 5 -46E -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255958.8427038578 - 20 -16956.39018656438 - 40 -23.74417378609639 -100 -AcDbArc - 50 -55.6600115736736 - 51 -78.65195057146462 - 0 -ARC - 5 -46F -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255952.6599209097 - 20 -16946.09056392946 - 40 -35.74329587309428 -100 -AcDbArc - 50 -37.95284360978441 - 51 -56.79000771970439 - 0 -ARC - 5 -470 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255964.5177862331 - 20 -16960.42018098404 - 40 -18.0310059913069 -100 -AcDbArc - 50 -358.9204017046412 - 51 -25.11481499733817 - 0 -LINE - 5 -471 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255931.3586763357 - 20 -16980.14649989848 - 11 -255925.9916875007 - 21 -16971.26928807745 - 0 -LINE - 5 -472 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255925.9916875007 - 20 -16971.26928807745 - 11 -255925.9916875007 - 21 -16960.08043886342 - 0 -LINE - 5 -473 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255925.9916875007 - 20 -16960.08043886342 - 11 -255925.9916875007 - 21 -16948.89158964939 - 0 -LINE - 5 -474 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255925.9916875007 - 20 -16948.89158964939 - 11 -255931.3586763357 - 21 -16940.01437782833 - 0 -LINE - 5 -475 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255931.3586763357 - 20 -16940.01436564296 - 11 -255936.2802127248 - 21 -16938.37405676574 - 0 -LINE - 5 -476 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255936.2802127248 - 20 -16938.37405676574 - 11 -255945.8977432138 - 21 -16937.70272215731 - 0 -LINE - 5 -477 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255945.8977432138 - 20 -16937.70272215731 - 11 -255952.8455914413 - 21 -16938.48042667805 - 0 -ARC - 5 -478 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255945.8877535334 - 20 -17004.7253116829 - 40 -66.60928086729827 -100 -AcDbArc - 50 -275.9959108137628 - 51 -285.3451828784344 - 0 -ARC - 5 -479 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255958.8427038578 - 20 -16963.77069116246 - 40 -23.74417378609639 -100 -AcDbArc - 50 -281.3480494285354 - 51 -304.3399884263264 - 0 -ARC - 5 -47A -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255952.6599209097 - 20 -16974.07031379738 - 40 -35.74329587309428 -100 -AcDbArc - 50 -303.2099922802956 - 51 -322.0471563902156 - 0 -ARC - 5 -47B -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -255964.5177862331 - 20 -16959.7406967428 - 40 -18.0310059913069 -100 -AcDbArc - 50 -334.8851850026619 - 51 -1.079598295358819 - 0 -LINE - 5 -47C -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255931.3586763357 - 20 -16940.01437782833 - 11 -255920.5866514946 - 21 -16942.77339449215 - 0 -LINE - 5 -47D -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255980.7892561989 - 20 -16965.45109136029 - 11 -255980.7892561989 - 21 -16954.70978636655 - 0 -LINE - 5 -47E -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255980.7892561989 - 20 -16954.70978636655 - 11 -255979.9115668564 - 21 -16953.88198627053 - 0 -LINE - 5 -47F -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255979.9115668564 - 20 -16953.88198627053 - 11 -255978.9679138663 - 21 -16953.08040990304 - 0 -LINE - 5 -480 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255978.9679138663 - 20 -16953.08040990304 - 11 -255977.9762078532 - 21 -16952.31030207161 - 0 -LINE - 5 -481 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255977.9762078532 - 20 -16952.31030207161 - 11 -255976.9543594422 - 21 -16951.57690758385 - 0 -LINE - 5 -482 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255976.9543594422 - 20 -16951.57690758385 - 11 -255975.9202792581 - 21 -16950.8854712473 - 0 -LINE - 5 -483 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255975.9202792581 - 20 -16950.8854712473 - 11 -255974.8918779253 - 21 -16950.24123786959 - 0 -LINE - 5 -484 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255974.8918779253 - 20 -16950.24123786959 - 11 -255973.8870660691 - 21 -16949.64945225824 - 0 -LINE - 5 -485 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255973.8870660691 - 20 -16949.64945225824 - 11 -255972.9237543143 - 21 -16949.11535922091 - 0 -LINE - 5 -486 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255972.9237543143 - 20 -16949.11535922091 - 11 -255972.014028702 - 21 -16948.64158117022 - 0 -LINE - 5 -487 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255971.1466769398 - 20 -16948.22025093948 - 11 -255970.3046621522 - 21 -16947.84087896707 - 0 -LINE - 5 -488 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255970.3046621522 - 20 -16947.84087896707 - 11 -255969.4709474626 - 21 -16947.49297569138 - 0 -LINE - 5 -489 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255969.4709474626 - 20 -16947.49297569138 - 11 -255968.6284959954 - 21 -16947.16605155082 - 0 -LINE - 5 -48A -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255968.6284959954 - 20 -16947.16605155082 - 11 -255967.760270875 - 21 -16946.84961698372 - 0 -LINE - 5 -48B -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255967.760270875 - 20 -16946.84961698372 - 11 -255966.849235225 - 21 -16946.53318242856 - 0 -LINE - 5 -48C -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255966.849235225 - 20 -16946.53318242856 - 11 -255965.8783521697 - 21 -16946.2062583237 - 0 -LINE - 5 -48D -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255965.8783521697 - 20 -16946.2062583237 - 11 -255964.8358997522 - 21 -16945.86141456024 - 0 -LINE - 5 -48E -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255964.8358997522 - 20 -16945.86141456024 - 11 -255963.7314156918 - 21 -16945.50345884033 - 0 -LINE - 5 -48F -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255963.7314156918 - 20 -16945.50345884033 - 11 -255962.5797526261 - 21 -16945.14025831879 - 0 -LINE - 5 -490 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255962.5797526261 - 20 -16945.14025831879 - 11 -255961.3957631937 - 21 -16944.77968015046 - 0 -LINE - 5 -491 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255961.3957631937 - 20 -16944.77968015046 - 11 -255960.1943000327 - 21 -16944.42959149018 - 0 -LINE - 5 -492 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255960.1943000327 - 20 -16944.42959149018 - 11 -255958.9902157812 - 21 -16944.09785949284 - 0 -LINE - 5 -493 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255958.9902157812 - 20 -16944.09785949284 - 11 -255957.7983630772 - 21 -16943.79235131319 - 0 -LINE - 5 -494 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255957.7983630772 - 20 -16943.79235131319 - 11 -255956.6335945592 - 21 -16943.52093410616 - 0 -LINE - 5 -495 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255956.6335945592 - 20 -16943.52093410616 - 11 -255955.504829088 - 21 -16943.28972677324 - 0 -LINE - 5 -496 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255955.504829088 - 20 -16943.28972677324 - 11 -255954.3972504183 - 21 -16943.09785520264 - 0 -LINE - 5 -497 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255954.3972504183 - 20 -16943.09785520264 - 11 -255953.2901085278 - 21 -16942.94269702923 - 0 -LINE - 5 -498 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255953.2901085278 - 20 -16942.94269702923 - 11 -255952.1626533936 - 21 -16942.8216298879 - 0 -LINE - 5 -499 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255952.1626533936 - 20 -16942.8216298879 - 11 -255950.9941349938 - 21 -16942.73203141355 - 0 -LINE - 5 -49A -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255950.9941349938 - 20 -16942.73203141355 - 11 -255949.7638033056 - 21 -16942.67127924109 - 0 -LINE - 5 -49B -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255949.7638033056 - 20 -16942.67127924109 - 11 -255948.4509083068 - 21 -16942.63675100533 - 0 -LINE - 5 -49C -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255948.4509083068 - 20 -16942.63675100533 - 11 -255947.0346999745 - 21 -16942.62582434125 - 0 -LINE - 5 -49D -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255947.0346999745 - 20 -16942.62582434125 - 11 -255945.4935956204 - 21 -16942.63729779328 - 0 -LINE - 5 -49E -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255945.4935956204 - 20 -16942.63729779328 - 11 -255943.8026818886 - 21 -16942.67565354451 - 0 -LINE - 5 -49F -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255943.8026818886 - 20 -16942.67565354451 - 11 -255941.9362127572 - 21 -16942.74679468757 - 0 -LINE - 5 -4A0 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255941.9362127572 - 20 -16942.74679468757 - 11 -255939.8684422046 - 21 -16942.85662431522 - 0 -LINE - 5 -4A1 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255939.8684422046 - 20 -16942.85662431522 - 11 -255937.5736242083 - 21 -16943.01104552004 - 0 -LINE - 5 -4A2 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255937.5736242083 - 20 -16943.01104552004 - 11 -255935.0260127471 - 21 -16943.21596139479 - 0 -LINE - 5 -4A3 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255935.0260127471 - 20 -16943.21596139479 - 11 -255932.1998617982 - 21 -16943.47727503206 - 0 -LINE - 5 -4A4 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255932.1998617982 - 20 -16943.47727503206 - 11 -255929.0694253403 - 21 -16943.80088952459 - 0 -LINE - 5 -4A5 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255980.7892561989 - 20 -16965.45109136029 - 11 -255979.9115668564 - 21 -16966.27889145631 - 0 -LINE - 5 -4A6 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255979.9115668564 - 20 -16966.27889145631 - 11 -255978.9679138663 - 21 -16967.0804678238 - 0 -LINE - 5 -4A7 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255978.9679138663 - 20 -16967.0804678238 - 11 -255977.9762078532 - 21 -16967.85057565522 - 0 -LINE - 5 -4A8 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255977.9762078532 - 20 -16967.85057565522 - 11 -255976.9543594422 - 21 -16968.58397014298 - 0 -LINE - 5 -4A9 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255976.9543594422 - 20 -16968.58397014298 - 11 -255975.9202792581 - 21 -16969.27540647954 - 0 -LINE - 5 -4AA -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255975.9202792581 - 20 -16969.27540647954 - 11 -255974.8918779253 - 21 -16969.91963985724 - 0 -LINE - 5 -4AB -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255974.8918779253 - 20 -16969.91963985724 - 11 -255973.8870660691 - 21 -16970.51142546857 - 0 -LINE - 5 -4AC -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255973.8870660691 - 20 -16970.51142546857 - 11 -255972.9237543143 - 21 -16971.04551850593 - 0 -LINE - 5 -4AD -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255972.9237543143 - 20 -16971.04551850593 - 11 -255972.014028702 - 21 -16971.51929655661 - 0 -LINE - 5 -4AE -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255972.014028702 - 20 -16971.51929655661 - 11 -255971.1466769398 - 21 -16971.94062678736 - 0 -LINE - 5 -4AF -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255971.1466769398 - 20 -16971.94062678736 - 11 -255970.3046621522 - 21 -16972.31999875977 - 0 -LINE - 5 -4B0 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255970.3046621522 - 20 -16972.31999875977 - 11 -255969.4709474626 - 21 -16972.66790203545 - 0 -LINE - 5 -4B1 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255969.4709474626 - 20 -16972.66790203545 - 11 -255968.6284959954 - 21 -16972.99482617602 - 0 -LINE - 5 -4B2 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255968.6284959954 - 20 -16972.99482617602 - 11 -255967.760270875 - 21 -16973.31126074309 - 0 -LINE - 5 -4B3 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255967.760270875 - 20 -16973.31126074309 - 11 -255966.849235225 - 21 -16973.62769529824 - 0 -LINE - 5 -4B4 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255966.849235225 - 20 -16973.62769529824 - 11 -255965.8783521697 - 21 -16973.95461940313 - 0 -LINE - 5 -4B5 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255965.8783521697 - 20 -16973.95461940313 - 11 -255964.8358997522 - 21 -16974.29946316658 - 0 -LINE - 5 -4B6 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255964.8358997522 - 20 -16974.29946316658 - 11 -255963.7314156918 - 21 -16974.65741888648 - 0 -LINE - 5 -4B7 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255963.7314156918 - 20 -16974.65741888648 - 11 -255962.5797526261 - 21 -16975.02061940804 - 0 -LINE - 5 -4B8 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255962.5797526261 - 20 -16975.02061940804 - 11 -255961.3957631937 - 21 -16975.38119757637 - 0 -LINE - 5 -4B9 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255961.3957631937 - 20 -16975.38119757637 - 11 -255960.1943000327 - 21 -16975.73128623663 - 0 -LINE - 5 -4BA -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255960.1943000327 - 20 -16975.73128623663 - 11 -255958.9902157812 - 21 -16976.063018234 - 0 -LINE - 5 -4BB -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255958.9902157812 - 20 -16976.063018234 - 11 -255957.7983630772 - 21 -16976.36852641365 - 0 -LINE - 5 -4BC -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255957.7983630772 - 20 -16976.36852641365 - 11 -255956.6335945592 - 21 -16976.63994362068 - 0 -LINE - 5 -4BD -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255956.6335945592 - 20 -16976.63994362068 - 11 -255955.504829088 - 21 -16976.8711509536 - 0 -LINE - 5 -4BE -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255955.504829088 - 20 -16976.8711509536 - 11 -255954.3972504183 - 21 -16977.0630225242 - 0 -LINE - 5 -4BF -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255954.3972504183 - 20 -16977.0630225242 - 11 -255953.2901085278 - 21 -16977.21818069761 - 0 -LINE - 5 -4C0 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255953.2901085278 - 20 -16977.21818069761 - 11 -255952.1626533936 - 21 -16977.33924783893 - 0 -LINE - 5 -4C1 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255952.1626533936 - 20 -16977.33924783893 - 11 -255950.9941349938 - 21 -16977.42884631326 - 0 -LINE - 5 -4C2 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255950.9941349938 - 20 -16977.42884631326 - 11 -255949.7638033056 - 21 -16977.48959848575 - 0 -LINE - 5 -4C3 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255949.7638033056 - 20 -16977.48959848575 - 11 -255948.4509083068 - 21 -16977.52412672151 - 0 -LINE - 5 -4C4 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255948.4509083068 - 20 -16977.52412672151 - 11 -255947.0346999745 - 21 -16977.53505338559 - 0 -LINE - 5 -4C5 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255947.0346999745 - 20 -16977.53505338559 - 11 -255945.4935956204 - 21 -16977.52357993356 - 0 -LINE - 5 -4C6 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255945.4935956204 - 20 -16977.52357993356 - 11 -255943.8026818886 - 21 -16977.48522418233 - 0 -LINE - 5 -4C7 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255943.8026818886 - 20 -16977.48522418233 - 11 -255941.9362127572 - 21 -16977.41408303923 - 0 -LINE - 5 -4C8 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255941.9362127572 - 20 -16977.41408303923 - 11 -255939.8684422046 - 21 -16977.30425341162 - 0 -LINE - 5 -4C9 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255939.8684422046 - 20 -16977.30425341162 - 11 -255937.5736242083 - 21 -16977.14983220676 - 0 -LINE - 5 -4CA -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255937.5736242083 - 20 -16977.14983220676 - 11 -255935.0260127471 - 21 -16976.94491633204 - 0 -LINE - 5 -4CB -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255935.0260127471 - 20 -16976.94491633204 - 11 -255932.1998617982 - 21 -16976.68360269475 - 0 -LINE - 5 -4CC -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255932.1998617982 - 20 -16976.68360269475 - 11 -255929.0694253403 - 21 -16976.35998820224 - 0 -LINE - 5 -4CD -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255902.9436449546 - 20 -16948.18570952079 - 11 -255902.9945215014 - 21 -16947.50279576575 - 0 -LINE - 5 -4CE -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255902.9945215014 - 20 -16947.50279576575 - 11 -255903.0355508938 - 21 -16946.97840756433 - 0 -LINE - 5 -4CF -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.0355508938 - 20 -16946.97840756433 - 11 -255903.0712089978 - 21 -16946.57761555732 - 0 -LINE - 5 -4D0 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.0712089978 - 20 -16946.57761555732 - 11 -255903.1059716787 - 21 -16946.26549038535 - 0 -LINE - 5 -4D1 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.1059716787 - 20 -16946.26549038535 - 11 -255903.1443148021 - 21 -16946.00710268917 - 0 -LINE - 5 -4D2 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.1443148021 - 20 -16946.00710268917 - 11 -255903.1907142337 - 21 -16945.76752310955 - 0 -LINE - 5 -4D3 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.1907142337 - 20 -16945.76752310955 - 11 -255903.2496458391 - 21 -16945.51182228719 - 0 -LINE - 5 -4D4 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.2496458391 - 20 -16945.51182228719 - 11 -255903.3255854838 - 21 -16945.2050708628 - 0 -LINE - 5 -4D5 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255902.9436449546 - 20 -16971.97516820605 - 11 -255902.9945215014 - 21 -16972.65808196109 - 0 -LINE - 5 -4D6 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255902.9945215014 - 20 -16972.65808196109 - 11 -255903.0355508938 - 21 -16973.18247016251 - 0 -LINE - 5 -4D7 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.1907142337 - 20 -16974.39335461728 - 11 -255903.2496458391 - 21 -16974.64905543965 - 0 -LINE - 5 -4D8 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.0355508938 - 20 -16973.18247016251 - 11 -255903.0712089978 - 21 -16973.58326216952 - 0 -LINE - 5 -4D9 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.0712089978 - 20 -16973.58326216952 - 11 -255903.1059716787 - 21 -16973.89538734149 - 0 -LINE - 5 -4DA -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.1059716787 - 20 -16973.89538734149 - 11 -255903.1443148021 - 21 -16974.15377503767 - 0 -LINE - 5 -4DB -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.1443148021 - 20 -16974.15377503767 - 11 -255903.1907142337 - 21 -16974.39335461728 - 0 -LINE - 5 -4DC -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -255903.2496458391 - 20 -16974.64905543965 - 11 -255903.3255854838 - 21 -16974.95580686404 - 0 -ENDBLK - 5 -1B3 -330 -1B1 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1B5 -330 -1B4 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -*U4 - 70 - 0 - 10 -0 - 20 -0 - 3 -*U4 - 1 - - 0 -LWPOLYLINE - 5 -4DD -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -880000.2756987195 - 20 -290303.5326859512 - 10 -880023.2756987197 - 20 -290303.5326859512 - 10 -880023.2756987197 - 20 -290253.5326859512 - 10 -880000.2756987195 - 20 -290253.5326859512 - 10 -880000.2756987195 - 20 -290303.5326859512 - 0 -HATCH - 5 -4DE -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -880023.2756987197 - 20 -290253.5326859512 - 11 -880023.2756987197 - 21 -290303.5326859512 - 72 - 1 - 10 -880023.2756987197 - 20 -290303.5326859512 - 11 -880000.2756987195 - 21 -290303.5326859512 - 72 - 1 - 10 -880000.2756987195 - 20 -290303.5326859512 - 11 -880000.2756987195 - 21 -290253.5326859512 - 72 - 1 - 10 -880000.2756987195 - 20 -290253.5326859512 - 11 -880023.2756987197 - 21 -290253.5326859512 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -4DF -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879552.3932570594 - 20 -290336.3959268102 - 11 -879552.3932570594 - 21 -290386.3959268102 - 72 - 1 - 10 -879552.3932570594 - 20 -290386.3959268102 - 11 -879529.3932570594 - 21 -290386.3959268102 - 72 - 1 - 10 -879529.3932570594 - 20 -290386.3959268102 - 11 -879529.3932570594 - 21 -290336.3959268102 - 72 - 1 - 10 -879529.3932570594 - 20 -290336.3959268102 - 11 -879552.3932570594 - 21 -290336.3959268102 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4E0 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -879529.3932570594 - 20 -290386.3959268102 - 10 -879552.3932570594 - 20 -290386.3959268102 - 10 -879552.3932570594 - 20 -290336.3959268102 - 10 -879529.3932570594 - 20 -290336.3959268102 - 10 -879529.3932570594 - 20 -290386.3959268102 - 0 -HATCH - 5 -4E1 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879199.5286617092 - 20 -291789.1693454167 - 11 -879199.5286617092 - 21 -291839.1693454168 - 72 - 1 - 10 -879199.5286617092 - 20 -291839.1693454168 - 11 -879176.528661709 - 21 -291839.1693454168 - 72 - 1 - 10 -879176.528661709 - 20 -291839.1693454168 - 11 -879176.528661709 - 21 -291789.1693454167 - 72 - 1 - 10 -879176.528661709 - 20 -291789.1693454167 - 11 -879199.5286617092 - 21 -291789.1693454167 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4E2 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -879176.528661709 - 20 -291839.1693454168 - 10 -879199.5286617092 - 20 -291839.1693454168 - 10 -879199.5286617092 - 20 -291789.1693454167 - 10 -879176.528661709 - 20 -291789.1693454167 - 10 -879176.528661709 - 20 -291839.1693454168 - 0 -HATCH - 5 -4E3 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 5 - 72 - 1 - 10 -879549.3932570581 - 20 -290273.5326859524 - 11 -879549.3932570581 - 21 -290276.5326859521 - 72 - 1 - 10 -879549.3932570581 - 20 -290276.5326859521 - 11 -879529.3932570578 - 21 -290276.5326859523 - 72 - 1 - 10 -879529.3932570578 - 20 -290276.5326859523 - 11 -879529.3932570578 - 21 -290253.5326859523 - 72 - 1 - 10 -879529.3932570578 - 20 -290253.5326859523 - 11 -879549.3932570581 - 21 -290253.5326859523 - 72 - 1 - 10 -879549.3932570581 - 20 -290253.5326859523 - 11 -879549.3932570581 - 21 -290273.5326859524 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4E4 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -879549.3932570581 - 20 -290273.5326859524 - 10 -879549.3932570581 - 20 -290253.5326859523 - 10 -879529.3932570578 - 20 -290253.5326859523 - 10 -879529.3932570578 - 20 -290276.5326859523 - 10 -879549.3932570581 - 20 -290276.5326859521 - 10 -879549.3932570581 - 20 -290273.5326859524 - 0 -HATCH - 5 -4E5 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 5 - 72 - 1 - 10 -879699.8932570573 - 20 -290273.5326859512 - 11 -879699.8932570573 - 21 -290276.5326859509 - 72 - 1 - 10 -879699.8932570573 - 20 -290276.5326859509 - 11 -879679.8932570572 - 21 -290276.5326859512 - 72 - 1 - 10 -879679.8932570572 - 20 -290276.5326859512 - 11 -879679.8932570572 - 21 -290253.5326859512 - 72 - 1 - 10 -879679.8932570572 - 20 -290253.5326859512 - 11 -879699.8932570573 - 21 -290253.5326859512 - 72 - 1 - 10 -879699.8932570573 - 20 -290253.5326859512 - 11 -879699.8932570573 - 21 -290273.5326859512 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4E6 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -879699.8932570573 - 20 -290273.5326859512 - 10 -879699.8932570573 - 20 -290253.5326859512 - 10 -879679.8932570572 - 20 -290253.5326859512 - 10 -879679.8932570572 - 20 -290276.5326859512 - 10 -879699.8932570573 - 20 -290276.5326859509 - 10 -879699.8932570573 - 20 -290273.5326859512 - 0 -HATCH - 5 -4E7 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -880346.2756987192 - 20 -291839.1693454168 - 11 -880296.2756987197 - 21 -291839.1693454168 - 72 - 1 - 10 -880296.2756987197 - 20 -291839.1693454168 - 11 -880296.2756987197 - 21 -291816.1693454167 - 72 - 1 - 10 -880296.2756987197 - 20 -291816.1693454167 - 11 -880346.2756987192 - 21 -291816.1693454167 - 72 - 1 - 10 -880346.2756987192 - 20 -291816.1693454167 - 11 -880346.2756987192 - 21 -291839.1693454168 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4E8 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -880296.2756987197 - 20 -291816.1693454167 - 10 -880296.2756987197 - 20 -291839.1693454168 - 10 -880346.2756987192 - 20 -291839.1693454168 - 10 -880346.2756987192 - 20 -291816.1693454167 - 10 -880296.2756987197 - 20 -291816.1693454167 - 0 -LINE - 5 -4E9 -100 -AcDbEntity - 8 -coloumn - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -880346.2756987192 - 20 -291816.1693454167 - 11 -880346.2756987192 - 21 -291816.1693454167 - 0 -HATCH - 5 -4EA -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879226.528661709 - 20 -291193.1693454167 - 11 -879176.528661709 - 21 -291193.1693454167 - 72 - 1 - 10 -879176.528661709 - 20 -291193.1693454167 - 11 -879176.528661709 - 21 -291170.1693454168 - 72 - 1 - 10 -879176.528661709 - 20 -291170.1693454168 - 11 -879226.528661709 - 21 -291170.1693454168 - 72 - 1 - 10 -879226.528661709 - 20 -291170.1693454168 - 11 -879226.528661709 - 21 -291193.1693454167 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4EB -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -879176.528661709 - 20 -291170.1693454168 - 10 -879176.528661709 - 20 -291193.1693454167 - 10 -879226.528661709 - 20 -291193.1693454167 - 10 -879226.528661709 - 20 -291170.1693454168 - 10 -879176.528661709 - 20 -291170.1693454168 - 0 -HATCH - 5 -4EC -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -880323.2756987195 - 20 -291193.1693454167 - 11 -880323.2756987195 - 21 -291143.1693454167 - 72 - 1 - 10 -880323.2756987195 - 20 -291143.1693454167 - 11 -880346.2756987192 - 21 -291143.1693454167 - 72 - 1 - 10 -880346.2756987192 - 20 -291143.1693454167 - 11 -880346.2756987192 - 21 -291193.1693454167 - 72 - 1 - 10 -880346.2756987192 - 20 -291193.1693454167 - 11 -880323.2756987195 - 21 -291193.1693454167 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4ED -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -880346.2756987192 - 20 -291143.1693454167 - 10 -880323.2756987195 - 20 -291143.1693454167 - 10 -880323.2756987195 - 20 -291193.1693454167 - 10 -880346.2756987192 - 20 -291193.1693454167 - 10 -880346.2756987192 - 20 -291143.1693454167 - 0 -HATCH - 5 -4EE -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879176.528661709 - 20 -290556.3959268099 - 11 -879176.528661709 - 21 -290506.3959268099 - 72 - 1 - 10 -879176.528661709 - 20 -290506.3959268099 - 11 -879199.5286617092 - 21 -290506.3959268099 - 72 - 1 - 10 -879199.5286617092 - 20 -290506.3959268099 - 11 -879199.5286617092 - 21 -290556.3959268099 - 72 - 1 - 10 -879199.5286617092 - 20 -290556.3959268099 - 11 -879176.528661709 - 21 -290556.3959268099 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4EF -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -879199.5286617092 - 20 -290506.3959268099 - 10 -879176.528661709 - 20 -290506.3959268099 - 10 -879176.528661709 - 20 -290556.3959268099 - 10 -879199.5286617092 - 20 -290556.3959268099 - 10 -879199.5286617092 - 20 -290506.3959268099 - 0 -HATCH - 5 -4F0 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -880323.2756987195 - 20 -290556.3959268099 - 11 -880323.2756987195 - 21 -290506.3959268099 - 72 - 1 - 10 -880323.2756987195 - 20 -290506.3959268099 - 11 -880346.2756987192 - 21 -290506.3959268099 - 72 - 1 - 10 -880346.2756987192 - 20 -290506.3959268099 - 11 -880346.2756987192 - 21 -290556.3959268099 - 72 - 1 - 10 -880346.2756987192 - 20 -290556.3959268099 - 11 -880323.2756987195 - 21 -290556.3959268099 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4F1 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -880346.2756987192 - 20 -290506.3959268099 - 10 -880323.2756987195 - 20 -290506.3959268099 - 10 -880323.2756987195 - 20 -290556.3959268099 - 10 -880346.2756987192 - 20 -290556.3959268099 - 10 -880346.2756987192 - 20 -290506.3959268099 - 0 -HATCH - 5 -4F2 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879717.8932570579 - 20 -291839.1693454168 - 11 -879667.893257058 - 21 -291839.1693454168 - 72 - 1 - 10 -879667.893257058 - 20 -291839.1693454168 - 11 -879667.893257058 - 21 -291816.1693454167 - 72 - 1 - 10 -879667.893257058 - 20 -291816.1693454167 - 11 -879717.8932570579 - 21 -291816.1693454167 - 72 - 1 - 10 -879717.8932570579 - 20 -291816.1693454167 - 11 -879717.8932570579 - 21 -291839.1693454168 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4F3 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -879667.893257058 - 20 -291816.1693454167 - 10 -879667.893257058 - 20 -291839.1693454168 - 10 -879717.8932570579 - 20 -291839.1693454168 - 10 -879717.8932570579 - 20 -291816.1693454167 - 10 -879667.893257058 - 20 -291816.1693454167 - 0 -HATCH - 5 -4F4 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 5 - 72 - 1 - 10 -879699.8932570581 - 20 -290383.3959268093 - 11 -879699.8932570581 - 21 -290386.3959268088 - 72 - 1 - 10 -879699.8932570581 - 20 -290386.3959268088 - 11 -879679.8932570579 - 21 -290386.3959268091 - 72 - 1 - 10 -879679.8932570579 - 20 -290386.3959268091 - 11 -879679.8932570579 - 21 -290363.3959268093 - 72 - 1 - 10 -879679.8932570579 - 20 -290363.3959268093 - 11 -879699.8932570581 - 21 -290363.3959268093 - 72 - 1 - 10 -879699.8932570581 - 20 -290363.3959268093 - 11 -879699.8932570581 - 21 -290383.3959268093 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4F5 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -879699.8932570581 - 20 -290383.3959268093 - 10 -879699.8932570581 - 20 -290363.3959268093 - 10 -879679.8932570579 - 20 -290363.3959268093 - 10 -879679.8932570579 - 20 -290386.3959268091 - 10 -879699.8932570581 - 20 -290386.3959268088 - 10 -879699.8932570581 - 20 -290383.3959268093 - 0 -HATCH - 5 -4F6 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879226.528661709 - 20 -290870.1693454167 - 11 -879176.528661709 - 21 -290870.1693454167 - 72 - 1 - 10 -879176.528661709 - 20 -290870.1693454167 - 11 -879176.528661709 - 21 -290847.1693454167 - 72 - 1 - 10 -879176.528661709 - 20 -290847.1693454167 - 11 -879226.528661709 - 21 -290847.1693454167 - 72 - 1 - 10 -879226.528661709 - 20 -290847.1693454167 - 11 -879226.528661709 - 21 -290870.1693454167 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4F7 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -879176.528661709 - 20 -290847.1693454167 - 10 -879176.528661709 - 20 -290870.1693454167 - 10 -879226.528661709 - 20 -290870.1693454167 - 10 -879226.528661709 - 20 -290847.1693454167 - 10 -879176.528661709 - 20 -290847.1693454167 - 0 -HATCH - 5 -4F8 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -880346.2756987192 - 20 -290870.1693454167 - 11 -880296.2756987197 - 21 -290870.1693454167 - 72 - 1 - 10 -880296.2756987197 - 20 -290870.1693454167 - 11 -880296.2756987197 - 21 -290847.1693454167 - 72 - 1 - 10 -880296.2756987197 - 20 -290847.1693454167 - 11 -880346.2756987192 - 21 -290847.1693454167 - 72 - 1 - 10 -880346.2756987192 - 20 -290847.1693454167 - 11 -880346.2756987192 - 21 -290870.1693454167 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4F9 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -880296.2756987197 - 20 -290847.1693454167 - 10 -880296.2756987197 - 20 -290870.1693454167 - 10 -880346.2756987192 - 20 -290870.1693454167 - 10 -880346.2756987192 - 20 -290847.1693454167 - 10 -880296.2756987197 - 20 -290847.1693454167 - 0 -HATCH - 5 -4FA -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879199.5286617323 - 20 -290136.395926983 - 11 -879199.5286617323 - 21 -290186.395926983 - 72 - 1 - 10 -879199.5286617323 - 20 -290186.395926983 - 11 -879176.5286617324 - 21 -290186.395926983 - 72 - 1 - 10 -879176.5286617324 - 20 -290186.395926983 - 11 -879176.5286617324 - 21 -290136.395926983 - 72 - 1 - 10 -879176.5286617324 - 20 -290136.395926983 - 11 -879199.5286617323 - 21 -290136.395926983 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4FB -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -879176.5286617324 - 20 -290186.395926983 - 10 -879199.5286617323 - 20 -290186.395926983 - 10 -879199.5286617323 - 20 -290136.395926983 - 10 -879176.5286617324 - 20 -290136.395926983 - 10 -879176.5286617324 - 20 -290186.395926983 - 0 -HATCH - 5 -4FC -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -880323.2756987195 - 20 -291516.1693466697 - 11 -880323.2756987195 - 21 -291466.1693466697 - 72 - 1 - 10 -880323.2756987195 - 20 -291466.1693466697 - 11 -880346.2756987192 - 21 -291466.1693466697 - 72 - 1 - 10 -880346.2756987192 - 20 -291466.1693466697 - 11 -880346.2756987192 - 21 -291516.1693466697 - 72 - 1 - 10 -880346.2756987192 - 20 -291516.1693466697 - 11 -880323.2756987195 - 21 -291516.1693466697 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4FD -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -880346.2756987192 - 20 -291466.1693466697 - 10 -880323.2756987195 - 20 -291466.1693466697 - 10 -880323.2756987195 - 20 -291516.1693466697 - 10 -880346.2756987192 - 20 -291516.1693466697 - 10 -880346.2756987192 - 20 -291466.1693466697 - 0 -HATCH - 5 -4FE -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879176.528661709 - 20 -291516.1693466697 - 11 -879176.528661709 - 21 -291466.1693466697 - 72 - 1 - 10 -879176.528661709 - 20 -291466.1693466697 - 11 -879199.5286617092 - 21 -291466.1693466697 - 72 - 1 - 10 -879199.5286617092 - 20 -291466.1693466697 - 11 -879199.5286617092 - 21 -291516.1693466697 - 72 - 1 - 10 -879199.5286617092 - 20 -291516.1693466697 - 11 -879176.528661709 - 21 -291516.1693466697 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -4FF -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -879199.5286617092 - 20 -291466.1693466697 - 10 -879176.528661709 - 20 -291466.1693466697 - 10 -879176.528661709 - 20 -291516.1693466697 - 10 -879199.5286617092 - 20 -291516.1693466697 - 10 -879199.5286617092 - 20 -291466.1693466697 - 0 -HATCH - 5 -500 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879667.893257058 - 20 -291516.1693466697 - 11 -879667.893257058 - 21 -291466.1693466697 - 72 - 1 - 10 -879667.893257058 - 20 -291466.1693466697 - 11 -879690.893257058 - 21 -291466.1693466697 - 72 - 1 - 10 -879690.893257058 - 20 -291466.1693466697 - 11 -879690.893257058 - 21 -291516.1693466697 - 72 - 1 - 10 -879690.893257058 - 20 -291516.1693466697 - 11 -879667.893257058 - 21 -291516.1693466697 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -501 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -879690.893257058 - 20 -291466.1693466697 - 10 -879667.893257058 - 20 -291466.1693466697 - 10 -879667.893257058 - 20 -291516.1693466697 - 10 -879690.893257058 - 20 -291516.1693466697 - 10 -879690.893257058 - 20 -291466.1693466697 - 0 -HATCH - 5 -502 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879359.528661709 - 20 -291516.1693466697 - 11 -879359.528661709 - 21 -291466.1693466697 - 72 - 1 - 10 -879359.528661709 - 20 -291466.1693466697 - 11 -879382.528661709 - 21 -291466.1693466697 - 72 - 1 - 10 -879382.528661709 - 20 -291466.1693466697 - 11 -879382.528661709 - 21 -291516.1693466697 - 72 - 1 - 10 -879382.528661709 - 20 -291516.1693466697 - 11 -879359.528661709 - 21 -291516.1693466697 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -503 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -879382.528661709 - 20 -291466.1693466697 - 10 -879359.528661709 - 20 -291466.1693466697 - 10 -879359.528661709 - 20 -291516.1693466697 - 10 -879382.528661709 - 20 -291516.1693466697 - 10 -879382.528661709 - 20 -291466.1693466697 - 0 -HATCH - 5 -504 -100 -AcDbEntity - 8 -coloumn - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -879409.528661709 - 20 -291839.1693454168 - 11 -879359.528661709 - 21 -291839.1693454168 - 72 - 1 - 10 -879359.528661709 - 20 -291839.1693454168 - 11 -879359.528661709 - 21 -291816.1693454167 - 72 - 1 - 10 -879359.528661709 - 20 -291816.1693454167 - 11 -879409.528661709 - 21 -291816.1693454167 - 72 - 1 - 10 -879409.528661709 - 20 -291816.1693454167 - 11 -879409.528661709 - 21 -291839.1693454168 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -ENDBLK - 5 -1B6 -330 -1B4 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1B8 -330 -1B7 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -WELL10 - 70 - 0 - 10 -0 - 20 -0 - 3 -WELL10 - 1 - - 0 -LINE - 5 -505 -100 -AcDbEntity - 8 -Symbols - 6 -ByLayer - 62 - 5 -370 - -1 -100 -AcDbLine - 10 -0 - 20 -0 - 11 -0 - 21 -2.287486164789693 - 0 -LINE - 5 -506 -100 -AcDbEntity - 8 -Symbols - 6 -ByLayer - 62 - 5 -370 - -1 -100 -AcDbLine - 10 --0.7729281121480654 - 20 -2.287486164789693 - 11 -0 - 21 -2.287486164789693 - 0 -LINE - 5 -507 -100 -AcDbEntity - 8 -Symbols - 6 -ByLayer - 62 - 5 -370 - -1 -100 -AcDbLine - 10 -0.7729281121487475 - 20 -2.287486164789693 - 11 -0 - 21 -2.287486164789693 - 0 -LINE - 5 -508 -100 -AcDbEntity - 8 -Symbols - 6 -ByLayer - 62 - 5 -370 - -1 -100 -AcDbLine - 10 -0 - 20 -2.287486164789693 - 11 -0 - 21 -2.74559999999974 - 0 -LINE - 5 -509 -100 -AcDbEntity - 8 -Symbols - 6 -ByLayer - 62 - 5 -370 - -1 -100 -AcDbLine - 10 --0.7729281121480654 - 20 -2.287486164789693 - 11 --0.7729281121480654 - 21 -2.74559999999974 - 0 -LINE - 5 -50A -100 -AcDbEntity - 8 -Symbols - 6 -ByLayer - 62 - 5 -370 - -1 -100 -AcDbLine - 10 -0.7729281121487475 - 20 -2.287486164789693 - 11 -0.7729281121487475 - 21 -2.74559999999974 - 0 -ENDBLK - 5 -1B9 -330 -1B7 -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -BLOCK - 5 -1BB -330 -1BA -100 -AcDbEntity - 8 -0 -100 -AcDbBlockBegin - 2 -Basin 22 - 70 - 0 - 10 -0 - 20 -0 - 3 -Basin 22 - 1 - - 0 -ARC - 5 -50B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -0.1321794967992105 - 20 --0.325504014951008 - 40 -0.1437500000000217 -100 -AcDbArc - 50 -293.1162141335525 - 51 -40.8351460069247 - 0 -LINE - 5 -50C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -0.2409398981296249 - 20 --0.2315080703446313 - 11 -0.1950320817833813 - 21 --0.1783892623904535 - 0 -ARC - 5 -50D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.0007366406113647 - 20 --0.3475819626819998 - 40 -0.2587500000000005 -100 -AcDbArc - 50 -40.83514600694555 - 51 -88.78463085452169 - 0 -ARC - 5 -50E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.0007366406113647 - 20 --0.3475819626819998 - 40 -0.2587500000000005 -100 -AcDbArc - 50 -92.10640002390524 - 51 -139.0772043571666 - 0 -ARC - 5 -50F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -5.223716119770585 - 20 --4.8767844306374 - 40 -7.173125000041213 -100 -AcDbArc - 50 -139.0772043571666 - 51 -139.6291149363638 - 0 -ARC - 5 -510 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.1317366057217555 - 20 --0.3236273944457366 - 40 -0.1437500000000047 -100 -AcDbArc - 50 -139.6291149363638 - 51 -246.068976754325 - 0 -ARC - 5 -511 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -0.0023769810307499 - 20 --0.0214247530386445 - 40 -0.4743750000000289 -100 -AcDbArc - 50 -246.0689767543184 - 51 -293.1162141335381 - 0 -ARC - 5 -512 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.0031413677898513 - 20 --0.1174269241952572 - 40 -0.0171395037096485 -100 -AcDbArc - 50 -121.873286941506 - 51 -54.44344209893295 - 0 -ARC - 5 -513 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.0031413677898513 - 20 --0.1174269241952572 - 40 -0.0157020037096485 -100 -AcDbArc - 50 -127.4943272133481 - 51 -44.36692534066547 - 0 -ARC - 5 -514 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -0.1321794967992105 - 20 --0.3255040149509796 - 40 -0.1725000000000157 -100 -AcDbArc - 50 -293.1162141335453 - 51 -40.83514600693052 - 0 -LINE - 5 -515 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 -0.2626919783957078 - 20 --0.2127088814233389 - 11 -0.2167841620494642 - 21 --0.1595900734692179 - 0 -ARC - 5 -516 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.0007366406113647 - 20 --0.3475819626820566 - 40 -0.287499999999988 -100 -AcDbArc - 50 -40.83514600695138 - 51 -88.64261667473257 - 0 -ARC - 5 -517 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.0007366406113647 - 20 --0.3475819626820566 - 40 -0.287499999999988 -100 -AcDbArc - 50 -92.15127297321656 - 51 -139.0772043571679 - 0 -ARC - 5 -518 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -5.223716119606535 - 20 --4.876784430512087 - 40 -7.201874999835127 -100 -AcDbArc - 50 -139.0772043570661 - 51 -139.6291149362762 - 0 -ARC - 5 -519 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.1317366057216418 - 20 --0.3236273944457366 - 40 -0.1725000000000949 -100 -AcDbArc - 50 -139.6291149363488 - 51 -246.0689767543001 - 0 -ARC - 5 -51A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -0.0023769810306362 - 20 --0.0214247530384455 - 40 -0.5031250000002138 -100 -AcDbArc - 50 -246.0689767543396 - 51 -293.1162141335489 - 0 -ARC - 5 -51B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.0007366406113647 - 20 --0.3475819626820566 - 40 -0.3162499999999756 -100 -AcDbArc - 50 -107.7441195829452 - 51 -139.077204357162 - 0 -ARC - 5 -51C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -5.223716119607558 - 20 --4.876784430510893 - 40 -7.230624999835111 -100 -AcDbArc - 50 -139.0772043570778 - 51 -139.6291149362888 - 0 -ARC - 5 -51D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.1317366057217555 - 20 --0.3236273944457366 - 40 -0.201250000000043 -100 -AcDbArc - 50 -139.6291149363279 - 51 -148.2007353781487 - 0 -ARC - 5 -51E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.1503825840422337 - 20 --0.2104289250981139 - 40 -0.2111486022219079 -100 -AcDbArc - 50 -94.29349916300878 - 51 -224.6439515676748 - 0 -ARC - 5 -51F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.1663222906667556 - 20 --0.1723728326169294 - 40 -0.14375 -100 -AcDbArc - 50 -61.22222211535271 - 51 -198.3295940544968 - 0 -ARC - 5 -520 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -0.1503905689735916 - 20 --0.2108791257136318 - 40 -0.2113434224539952 -100 -AcDbArc - 50 -315.6271807366346 - 51 -85.71263689210166 - 0 -LINE - 5 -521 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbLine - 10 --0.1661903476086195 - 20 -0.0001271169223003 - 11 -0.1661903476086195 - 21 --0.0001271169223003 - 0 -ARC - 5 -522 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --0.0020133104299589 - 20 --0.3475769123552936 - 40 -0.3162499999999756 -100 -AcDbArc - 50 -40.46948986680843 - 51 -71.80257464102542 - 0 -ARC - 5 -523 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 --5.262135779191737 - 20 --4.835303870623931 - 40 -7.230624999835111 -100 -AcDbArc - 50 -39.91757928768392 - 51 -40.4694898668893 - 0 -ARC - 5 -524 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -0.1291720736139155 - 20 --0.3246595125990836 - 40 -0.201250000000043 -100 -AcDbArc - 50 -31.34595884581941 - 51 -39.91757928764348 - 0 -ARC - 5 -525 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbCircle - 10 -0.1649533410770232 - 20 --0.1736833125678743 - 40 -0.14375 -100 -AcDbArc - 50 -341.2171001694725 - 51 -118.3244721086172 - 0 -ELLIPSE - 5 -526 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0027327899849183 - 20 --0.028747918133206 - 30 -0 - 11 --0.0153089308747744 - 21 --0.0153089308747744 - 31 -0 - 40 -0.9999999999999403 - 41 --0.202915411692806 - 42 -4.914963447533809 - 0 -ELLIPSE - 5 -527 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.04429547158162 - 20 --0.0287838894633978 - 30 -0 - 11 --0.0057408490780428 - 21 --0.0057408490780428 - 31 -0 - 40 -0.9999999999998058 - 41 -5.036668871464866 - 42 -5.958564471470781 - 0 -ELLIPSE - 5 -528 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.04429547158162 - 20 --0.0287838894633978 - 30 -0 - 11 -0.0034445094468257 - 21 --0.0034445094468257 - 31 -0 - 40 -0.9999999999988096 - 41 --0.7853981633980407 - 42 -5.497787143781543 - 0 -ELLIPSE - 5 -529 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.1208297606626161 - 20 --0.07983864518260481 - 30 -0 - 11 -0.08232881912082091 - 21 --0.08232881912082091 - 31 -0 - 40 -0.9999999999999925 - 41 -5.115386456613116 - 42 -5.714220689477993 - 0 -ELLIPSE - 5 -52A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0027469622371541 - 20 --0.1118831317344586 - 30 -0 - 11 -0.008568839601392699 - 21 --0.008568839601392699 - 31 -0 - 40 -0.99999999999972 - 41 --1.405760339110585 - 42 -2.976215721279543 - 0 -ELLIPSE - 5 -52B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.1263127525591585 - 20 --0.0797965142267003 - 30 -0 - 11 -0.0823288191207574 - 21 --0.0823288191207574 - 31 -0 - 40 -0.9999999999999531 - 41 -2.139419999873403 - 42 -2.738254232738236 - 0 -ELLIPSE - 5 -52C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.002732789985032 - 20 --0.0287479181331776 - 30 -0 - 11 --0.0122471446998237 - 21 --0.0122471446998237 - 31 -0 - 40 -0.9999999999995036 - 41 -0.3282574131555149 - 42 -4.383790622607908 - 0 -ELLIPSE - 5 -52D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.06810092985136861 - 20 --0.0263795732227266 - 30 -0 - 11 -0.0123493228681062 - 21 --0.0123493228681062 - 31 -0 - 40 -0.9999999999982275 - 41 -5.900784619497413 - 42 -6.499618852700003 - 0 -ELLIPSE - 5 -52E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0583924701011824 - 20 --0.0428856950881311 - 30 -0 - 11 -0.0012853259402043 - 21 --0.0012853259402043 - 31 -0 - 40 -0.9999999999995312 - 41 --0.6203621761784079 - 42 -3.76161388490069 - 0 -ELLIPSE - 5 -52F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.041883039136053 - 20 --0.0525885265937234 - 30 -0 - 11 --0.0123493228680959 - 21 --0.0123493228680959 - 31 -0 - 40 -0.9999999999992443 - 41 -1.354021835996382 - 42 -1.952856069332864 - 0 -ELLIPSE - 5 -530 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0495761522950602 - 20 --0.0340663708998932 - 30 -0 - 11 -0.001837071704974 - 21 --0.001837071704974 - 31 -0 - 40 -0.9999999999994207 - 41 -2.684451902837356 - 42 -6.739985112866805 - 0 -ELLIPSE - 5 -531 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0466997878237976 - 20 --0.0525893477160366 - 30 -0 - 11 -0.0123493228681223 - 21 --0.0123493228681223 - 31 -0 - 40 -0.9999999999995205 - 41 -4.329988293226125 - 42 -4.928822526562929 - 0 -ELLIPSE - 5 -532 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0301936659464559 - 20 --0.0428808879728138 - 30 -0 - 11 --0.0012853259402012 - 21 --0.0012853259402012 - 31 -0 - 40 -0.9999999999978104 - 41 --3.761954829525154 - 42 -0.6200212315576632 - 0 -ELLIPSE - 5 -533 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0204908344338151 - 20 --0.0263714570196498 - 30 -0 - 11 --0.0123493228681139 - 21 --0.0123493228681139 - 31 -0 - 40 -0.9999999999988762 - 41 --0.2167744901405007 - 42 -0.382059743061979 - 0 -ELLIPSE - 5 -534 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0390129901412024 - 20 --0.0340645701731717 - 30 -0 - 11 -0.001837071704974 - 21 --0.001837071704974 - 31 -0 - 40 -0.9999999999993807 - 41 -1.113655576489847 - 42 -5.169188786518227 - 0 -ELLIPSE - 5 -535 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.04429547158162 - 20 --0.0287838894633978 - 30 -0 - 11 -0.0057408490780452 - 21 --0.0057408490780452 - 31 -0 - 40 -0.9999999999997577 - 41 -1.895076218431659 - 42 -2.816971817239786 - 0 -ELLIPSE - 5 -536 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.04429547158162 - 20 --0.0287838894633978 - 30 -0 - 11 -0.0057408490780365 - 21 --0.0057408490780365 - 31 -0 - 40 -0.999999999999583 - 41 -5.036668872021402 - 42 -5.958564470829807 - 0 -ELLIPSE - 5 -537 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.04429547158162 - 20 --0.0287838894633978 - 30 -0 - 11 -0.0057408490780406 - 21 --0.0057408490780406 - 31 -0 - 40 -0.999999999999841 - 41 -3.465872544669369 - 42 -4.387768144676132 - 0 -ELLIPSE - 5 -538 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0204900133115302 - 20 --0.0311882057040123 - 30 -0 - 11 -0.0123493228681636 - 21 --0.0123493228681636 - 31 -0 - 40 -0.9999999999995047 - 41 -2.759191965902173 - 42 -3.358026199104234 - 0 -ELLIPSE - 5 -539 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0301984730619438 - 20 --0.0146820838385793 - 30 -0 - 11 --0.0012853259401934 - 21 --0.0012853259401934 - 31 -0 - 40 -0.9999999999976362 - 41 -0.9504341506094782 - 42 -5.332410211684042 - 0 -ELLIPSE - 5 -53A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0467079040269596 - 20 --0.0049792523330154 - 30 -0 - 11 -0.0123493228681184 - 21 --0.0123493228681184 - 31 -0 - 40 -0.9999999999983812 - 41 -6.06641081637781 - 42 -6.665245049715536 - 0 -ELLIPSE - 5 -53B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0390147908678387 - 20 --0.0235014080269025 - 30 -0 - 11 --0.0018370717049768 - 21 --0.0018370717049768 - 31 -0 - 40 -0.9999999999997335 - 41 --2.027937077547934 - 42 -2.027596132478682 - 0 -ELLIPSE - 5 -53C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0418911553391013 - 20 --0.0049784312107022 - 30 -0 - 11 --0.0123493228680869 - 21 --0.0123493228680869 - 31 -0 - 40 -0.999999999998668 - 41 --0.3824006871619128 - 42 -0.2164335461759794 - 0 -ELLIPSE - 5 -53D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0583972772165566 - 20 --0.0146868909539819 - 30 -0 - 11 --0.0012853259402012 - 21 --0.0012853259402012 - 31 -0 - 40 -0.9999999999978104 - 41 --0.6203621759353588 - 42 -3.761613885147457 - 0 -ELLIPSE - 5 -53E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0681001087291975 - 20 --0.031196321907089 - 30 -0 - 11 --0.0123493228681196 - 21 --0.0123493228681195 - 31 -0 - 40 -0.9999999999993539 - 41 -2.924818163449156 - 42 -3.523652396651432 - 0 -ELLIPSE - 5 -53F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 -0.0495779530219238 - 20 --0.0235032087535387 - 30 -0 - 11 -0.0018370717049817 - 21 --0.0018370717049817 - 31 -0 - 40 -0.9999999999990304 - 41 --2.02793707710577 - 42 -2.027596132920821 - 0 -ELLIPSE - 5 -540 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0497610515513429 - 20 --0.0287838894633978 - 30 -0 - 11 --0.0057408490780428 - 21 --0.0057408490780428 - 31 -0 - 40 -0.9999999999998058 - 41 -0.3246208357088048 - 42 -1.24651643571472 - 0 -ELLIPSE - 5 -541 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0497610515513429 - 20 --0.0287838894633978 - 30 -0 - 11 -0.0034445094468257 - 21 --0.0034445094468257 - 31 -0 - 40 -0.9999999999988096 - 41 -0.7853981633980434 - 42 -7.068583470577627 - 0 -ELLIPSE - 5 -542 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0735665098212053 - 20 --0.0263795732227266 - 30 -0 - 11 -0.0123493228681062 - 21 --0.0123493228681062 - 31 -0 - 40 -0.9999999999982275 - 41 --0.2164335455204167 - 42 -0.3824006876821728 - 0 -ELLIPSE - 5 -543 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.06385805007101911 - 20 --0.0428856950881311 - 30 -0 - 11 -0.0012853259402043 - 21 --0.0012853259402043 - 31 -0 - 40 -0.9999999999995312 - 41 -2.521571422278896 - 42 -6.903547483357994 - 0 -ELLIPSE - 5 -544 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0473486191058896 - 20 --0.0525885265937234 - 30 -0 - 11 --0.0123493228680959 - 21 --0.0123493228680959 - 31 -0 - 40 -0.999999999999244 - 41 -4.330329237846723 - 42 -4.929163471183204 - 0 -ELLIPSE - 5 -545 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0550417322647832 - 20 --0.0340663708998932 - 30 -0 - 11 -0.001837071704974 - 21 --0.001837071704974 - 31 -0 - 40 -0.9999999999994207 - 41 --0.4567998056872187 - 42 -3.59873340434223 - 0 -ELLIPSE - 5 -546 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0521653677936342 - 20 --0.0525893477160366 - 30 -0 - 11 -0.0123493228681223 - 21 --0.0123493228681223 - 31 -0 - 40 -0.9999999999995205 - 41 -1.354362780616658 - 42 -1.953197013953461 - 0 -ELLIPSE - 5 -547 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0356592459162926 - 20 --0.0428808879728138 - 30 -0 - 11 --0.0012853259402012 - 21 --0.0012853259402012 - 31 -0 - 40 -0.9999999999978104 - 41 -5.663164075621923 - 42 -10.04514013670474 - 0 -ELLIPSE - 5 -548 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0259564144036517 - 20 --0.0263714570196498 - 30 -0 - 11 --0.0123493228681139 - 21 --0.0123493228681139 - 31 -0 - 40 -0.9999999999988762 - 41 -5.901125564117607 - 42 -6.499959797320087 - 0 -ELLIPSE - 5 -549 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0444785701109254 - 20 --0.0340645701731717 - 30 -0 - 11 -0.001837071704974 - 21 --0.001837071704974 - 31 -0 - 40 -0.9999999999993807 - 41 -1.11399652066136 - 42 -5.16952973068974 - 0 -ELLIPSE - 5 -54A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0497610515513429 - 20 --0.0287838894633978 - 30 -0 - 11 -0.0057408490780452 - 21 --0.0057408490780452 - 31 -0 - 40 -0.9999999999997577 - 41 -3.4662134899398 - 42 -4.388109088747927 - 0 -ELLIPSE - 5 -54B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0497610515513429 - 20 --0.0287838894633978 - 30 -0 - 11 -0.0057408490780365 - 21 --0.0057408490780365 - 31 -0 - 40 -0.999999999999583 - 41 -0.3246208363497793 - 42 -1.246516435158184 - 0 -ELLIPSE - 5 -54C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0497610515513429 - 20 --0.0287838894633978 - 30 -0 - 11 -0.0057408490780406 - 21 --0.0057408490780406 - 31 -0 - 40 -0.999999999999841 - 41 -1.895417162503454 - 42 -2.817312762510217 - 0 -ELLIPSE - 5 -54D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0259555932812532 - 20 --0.0311882057040123 - 30 -0 - 11 -0.0123493228681636 - 21 --0.0123493228681636 - 31 -0 - 40 -0.9999999999995047 - 41 -2.925159108075352 - 42 -3.523993341277413 - 0 -ELLIPSE - 5 -54E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0356640530317805 - 20 --0.0146820838385793 - 30 -0 - 11 --0.0012853259401934 - 21 --0.0012853259401934 - 31 -0 - 40 -0.9999999999976362 - 41 -0.9507750954955444 - 42 -5.332751156570108 - 0 -ELLIPSE - 5 -54F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0521734839966825 - 20 --0.0049792523330154 - 30 -0 - 11 -0.0123493228681184 - 21 --0.0123493228681184 - 31 -0 - 40 -0.9999999999983812 - 41 --0.3820597425359502 - 42 -0.2167744908017763 - 0 -ELLIPSE - 5 -550 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0444803708376753 - 20 --0.0235014080269025 - 30 -0 - 11 --0.0018370717049768 - 21 --0.0018370717049768 - 31 -0 - 40 -0.9999999999997335 - 41 -4.255589174700904 - 42 -8.31112238472752 - 0 -ELLIPSE - 5 -551 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0473567353088242 - 20 --0.0049784312107022 - 30 -0 - 11 --0.0123493228680869 - 21 --0.0123493228680869 - 31 -0 - 40 -0.9999999999986684 - 41 -6.066751761003607 - 42 -6.665585994341499 - 0 -ELLIPSE - 5 -552 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0638628571862796 - 20 --0.0146868909539819 - 30 -0 - 11 --0.0012853259402012 - 21 --0.0012853259402012 - 31 -0 - 40 -0.9999999999978104 - 41 -2.521571422032129 - 42 -6.903547483114945 - 0 -ELLIPSE - 5 -553 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0735656886990341 - 20 --0.031196321907089 - 30 -0 - 11 --0.0123493228681196 - 21 --0.0123493228681195 - 31 -0 - 40 -0.9999999999993539 - 41 -2.759532910528154 - 42 -3.35836714373043 - 0 -ELLIPSE - 5 -554 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - 0 -100 -AcDbEllipse - 10 --0.0550435329916468 - 20 --0.0235032087535387 - 30 -0 - 11 -0.0018370717049817 - 21 --0.0018370717049817 - 31 -0 - 40 -0.9999999999990304 - 41 -4.255589174258765 - 42 -8.311122384285357 - 0 -ENDBLK - 5 -1BC -330 -1BA -100 -AcDbEntity - 8 -0 -100 -AcDbBlockEnd - 0 -ENDSEC - 0 -SECTION - 2 -ENTITIES - 0 -MTEXT - 5 -555 -100 -AcDbEntity - 8 -PLAN_INFO - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3274.596016143105 - 20 -1434.320983020817 - 30 -0 - 40 -3.040537499999998 - 41 -162.4998342769979 - 71 - 4 - 72 - 5 - 3 -RS_NO=59/C11 PART,TS NO.7-7-128/2 PART\PREVENUE_WARD=7\PVILLAGE=NAGARAM\PDESAM=NAGARAM\P\PPLOT_AREA_M2=320\PDEPTH_CUTTING_MORE_THAN_1.5_M=NO\PCRZ=NO\PSECURITY_ZONE=NO\PACCESS_WIDTH_M=3.6\P\POPENING_ABOVE_2.1_ON_SIDE_LESS_1M_OR_LESS_EQUALTO_0.6M=NA - 3 - \POPENING_BELOW_2.1_ON_SIDE_LESS_1M_OR_LESS_EQUALTO_0.6M=NA\POPENING_ABOVE_2.1_ON_REAR_LESS_1M=NA\POPENING_BELOW_2.1_ON_REAR_LESS_1M=NA\PNOC_TO_ABUT_SIDE=NO\PNOC_TO_REAR_SIDE=NO\P\PWHETHER_GOVT_OR_AIDED_SCHOOL=NO\PMECHANICAL_PARKING=0\PEXISTING_FLOO - 1 -R_AREA_TO_BE_DEMOLISHED_M2=0\PPLOT_IN_COMMERCIAL_ZONE=YES - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -LINE - 5 -556 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3285.131714331685 - 20 -1244.402369962656 - 11 -3285.131714331685 - 21 -1244.445176272304 - 0 -LINE - 5 -557 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3285.131714331685 - 20 -1244.48176036129 - 11 -3285.131714331685 - 21 -1244.52456667088 - 0 -LINE - 5 -558 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 52 -370 - 0 -100 -AcDbLine - 10 -3286.406714331592 - 20 -1244.402369962656 - 11 -3286.406714331592 - 21 -1243.472369962663 - 0 -LINE - 5 -559 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3286.406714331592 - 20 -1244.552369962621 - 11 -3286.254891354825 - 21 -1244.552369962621 - 0 -LINE - 5 -55A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3285.254891354823 - 20 -1244.552369962679 - 11 -3285.103068378288 - 21 -1244.552369962679 - 0 -LINE - 5 -55B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3286.406714331592 - 20 -1244.752369962633 - 11 -3286.254891354825 - 21 -1244.752369962633 - 0 -LINE - 5 -55C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3285.254891354823 - 20 -1244.752369962633 - 11 -3284.903068378103 - 21 -1244.752369962633 - 0 -LINE - 5 -55D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3285.131714331685 - 20 -1244.402369962656 - 11 -3285.131714331685 - 21 -1244.445176272304 - 0 -LINE - 5 -55E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3285.131714331685 - 20 -1244.48176036129 - 11 -3285.131714331685 - 21 -1244.52456667088 - 0 -LWPOLYLINE - 5 -55F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbPolyline - 90 - 8 - 70 - 0 - 43 -0 - 10 -3286.406714331592 - 20 -1243.472369962663 - 10 -3286.406714331592 - 20 -1244.752369962633 - 10 -3286.606714331778 - 20 -1244.752369962633 - 10 -3286.756714331686 - 20 -1244.752369962633 - 10 -3286.756714331686 - 20 -1244.522369962651 - 10 -3286.606714331778 - 20 -1244.522369962651 - 10 -3286.606714331778 - 20 -1243.472369962663 - 10 -3286.406714331592 - 20 -1243.472369962663 - 0 -LINE - 5 -560 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3289.840538748308 - 20 -1243.423737554054 - 11 -3289.840538748308 - 21 -1240.394335589313 - 0 -LINE - 5 -561 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3293.309696737097 - 20 -1241.112806992692 - 11 -3289.840538748308 - 21 -1241.110540415975 - 0 -LINE - 5 -562 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3293.075420911424 - 20 -1242.276362763427 - 11 -3289.840538748308 - 21 -1242.276362763427 - 0 -LINE - 5 -563 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.802694132552 - 20 -1243.852369962668 - 11 -3281.603068378288 - 21 -1243.852369962668 - 0 -LINE - 5 -564 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.802694132552 - 20 -1243.552369962679 - 11 -3281.603068378288 - 21 -1243.552369962679 - 0 -LINE - 5 -565 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.802694132552 - 20 -1244.152369962656 - 11 -3281.603068378288 - 21 -1244.152369962656 - 0 -LINE - 5 -566 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.802694132552 - 20 -1244.452369962644 - 11 -3281.603068378288 - 21 -1244.452369962644 - 0 -LINE - 5 -567 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.802694132552 - 20 -1244.752369962633 - 11 -3281.603068378288 - 21 -1244.752369962633 - 0 -LINE - 5 -568 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.802694132552 - 20 -1245.052369962679 - 11 -3281.603068378288 - 21 -1245.052369962679 - 0 -LINE - 5 -569 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.802694132552 - 20 -1245.352369962667 - 11 -3281.603068378288 - 21 -1245.352369962667 - 0 -LINE - 5 -56A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.802694132552 - 20 -1245.652369962656 - 11 -3281.603068378288 - 21 -1245.652369962656 - 0 -LINE - 5 -56B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.802694132552 - 20 -1245.952369962644 - 11 -3281.603068378288 - 21 -1245.952369962644 - 0 -LINE - 5 -56C -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3283.703068378148 - 20 -1243.602689753345 - 11 -3283.703068378148 - 21 -1242.352369962667 - 0 -LINE - 5 -56D -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3283.403068378103 - 20 -1243.552369962679 - 11 -3283.403068378103 - 21 -1242.352369962667 - 0 -LINE - 5 -56E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3283.103068378288 - 20 -1243.552369962679 - 11 -3283.103068378288 - 21 -1242.352369962667 - 0 -LINE - 5 -56F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.803068378242 - 20 -1243.552369962679 - 11 -3282.803068378242 - 21 -1242.352369962667 - 0 -LINE - 5 -570 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3283.703068378148 - 20 -1243.852369962668 - 11 -3284.903068378103 - 21 -1243.852369962668 - 0 -LINE - 5 -571 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3283.703068378148 - 20 -1244.152369962656 - 11 -3284.903068378103 - 21 -1244.152369962656 - 0 -LINE - 5 -572 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3283.703068378148 - 20 -1244.452369962644 - 11 -3284.903068378103 - 21 -1244.452369962644 - 0 -LINE - 5 -573 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3283.703068378148 - 20 -1244.752369962633 - 11 -3284.903068378103 - 21 -1244.752369962633 - 0 -LINE - 5 -574 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3283.703068378148 - 20 -1245.052369962679 - 11 -3284.903068378103 - 21 -1245.052369962679 - 0 -LINE - 5 -575 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3281.853068378288 - 20 -1243.552369962679 - 11 -3283.103068378288 - 21 -1243.552369962679 - 0 -LINE - 5 -576 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3283.403068378103 - 20 -1243.552369962679 - 11 -3284.903068378103 - 21 -1243.552369962679 - 0 -LWPOLYLINE - 5 -577 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3282.802694132552 - 20 -1245.952369962644 - 10 -3282.802694132552 - 20 -1243.552369962679 - 10 -3283.103068378288 - 20 -1243.552369962679 - 0 -LWPOLYLINE - 5 -578 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3283.403068378103 - 20 -1243.552369962679 - 10 -3283.703068378148 - 20 -1243.552369962679 - 10 -3283.703068378148 - 20 -1245.052369962679 - 0 -LWPOLYLINE - 5 -579 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3282.772694132524 - 20 -1245.952369962644 - 10 -3282.772694132524 - 20 -1243.522369962651 - 10 -3283.103068378288 - 20 -1243.522369962651 - 0 -LWPOLYLINE - 5 -57A -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3283.403068378103 - 20 -1243.522369962651 - 10 -3283.733068378178 - 20 -1243.522369962651 - 10 -3283.733068378178 - 20 -1245.052369962679 - 0 -LWPOLYLINE - 5 -57B -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3282.742694132496 - 20 -1245.952369962644 - 10 -3282.742694132496 - 20 -1243.492369962681 - 10 -3283.103068378288 - 20 -1243.492369962681 - 0 -LWPOLYLINE - 5 -57C -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3283.403068378103 - 20 -1243.492369962681 - 10 -3283.763068378205 - 20 -1243.492369962681 - 10 -3283.763068378205 - 20 -1245.052369962679 - 0 -LINE - 5 -57D -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3282.802694132552 - 20 -1245.952369962644 - 11 -3282.802694132552 - 21 -1244.752369962633 - 0 -LINE - 5 -57E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3284.903068378103 - 20 -1243.472369962663 - 11 -3284.903068378103 - 21 -1244.752369962633 - 0 -LINE - 5 -57F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3285.103068378288 - 20 -1243.672369962675 - 11 -3285.103068378288 - 21 -1244.552369962679 - 0 -HATCH - 5 -580 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3285.101714331658 - 20 -1242.340948482917 - 11 -3284.903068378103 - 21 -1242.300036849163 - 72 - 1 - 10 -3284.903068378103 - 20 -1242.300036849163 - 11 -3284.903068378103 - 21 -1242.154635776649 - 72 - 1 - 10 -3284.903068378103 - 20 -1242.154635776649 - 11 -3285.101714331658 - 21 -1242.154635776649 - 72 - 1 - 10 -3285.101714331658 - 20 -1242.154635776649 - 11 -3285.101714331658 - 21 -1242.340948482917 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -0.01 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -HATCH - 5 -581 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3289.840538748308 - 20 -1243.316921289777 - 11 -3289.640538748354 - 21 -1243.275730786787 - 72 - 1 - 10 -3289.640538748354 - 20 -1243.275730786787 - 11 -3289.640538748354 - 21 -1241.110540415975 - 72 - 1 - 10 -3289.640538748354 - 20 -1241.110540415975 - 11 -3289.840538748308 - 21 -1241.110540415975 - 72 - 1 - 10 -3289.840538748308 - 20 -1241.110540415975 - 11 -3289.840538748308 - 21 -1243.316921289777 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -0.01 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -HATCH - 5 -582 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3289.840538748308 - 20 -1243.423737554054 - 11 -3289.640538748354 - 21 -1243.423737554054 - 72 - 1 - 10 -3289.640538748354 - 20 -1243.423737554054 - 11 -3289.640538748354 - 21 -1243.275730786787 - 72 - 1 - 10 -3289.640538748354 - 20 -1243.275730786787 - 11 -3289.840538748308 - 21 -1243.316921289777 - 72 - 1 - 10 -3289.840538748308 - 20 -1243.316921289777 - 11 -3289.840538748308 - 21 -1243.423737554054 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -0.01 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -HATCH - 5 -583 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 2 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3291.859715389553 - 20 -1242.27636276203 - 11 -3291.859715389553 - 21 -1241.906840563519 - 72 - 1 - 10 -3291.859715389553 - 20 -1241.906840563519 - 11 -3292.459715389414 - 21 -1241.906840563519 - 72 - 1 - 10 -3292.459715389414 - 20 -1241.906840563519 - 11 -3291.859715389553 - 21 -1242.27636276203 - 97 - 0 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3291.859715389553 - 20 -1242.27636276203 - 11 -3291.25971538946 - 21 -1241.906840563519 - 72 - 1 - 10 -3291.25971538946 - 20 -1241.906840563519 - 11 -3291.859715389553 - 21 -1241.906840563519 - 72 - 1 - 10 -3291.859715389553 - 20 -1241.906840563519 - 11 -3291.859715389553 - 21 -1242.27636276203 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LINE - 5 -584 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3291.859715389553 - 20 -1239.157007771602 - 11 -3291.859715389553 - 21 -1243.114510207961 - 0 -LWPOLYLINE - 5 -585 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3292.459715389414 - 20 -1241.906840563519 - 10 -3291.25971538946 - 20 -1241.906840563519 - 10 -3291.859715389553 - 20 -1242.27636276203 - 10 -3292.459715389414 - 20 -1241.906840563519 - 0 -MTEXT - 5 -586 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3291.537871610606 - 20 -1239.259400455456 - 30 -0 - 40 -0.21 - 41 -1.160833333333376 - 71 - 1 - 72 - 5 - 1 -Ramp Dn - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -587 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3283.13231203123 - 20 -1241.401489503914 - 30 -0 - 40 -0.245 - 41 -3.035277777777835 - 71 - 1 - 72 - 5 - 1 -RCC Retaining wall - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -HATCH - 5 -588 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3281.573068378261 - 20 -1245.952369962644 - 11 -3281.373068378307 - 21 -1245.952369962644 - 72 - 1 - 10 -3281.373068378307 - 20 -1245.952369962644 - 11 -3281.373068378307 - 21 -1242.654635776649 - 72 - 1 - 10 -3281.373068378307 - 20 -1242.654635776649 - 11 -3281.573068378261 - 21 -1242.654635776649 - 72 - 1 - 10 -3281.573068378261 - 20 -1242.654635776649 - 11 -3281.573068378261 - 21 -1245.952369962644 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -0.01 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -HATCH - 5 -589 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3289.610538748326 - 20 -1243.623737554066 - 11 -3286.606714331778 - 21 -1243.623737554066 - 72 - 1 - 10 -3286.606714331778 - 20 -1243.623737554066 - 11 -3286.606714331778 - 21 -1243.423737554054 - 72 - 1 - 10 -3286.606714331778 - 20 -1243.423737554054 - 11 -3289.610538748326 - 21 -1243.423737554054 - 72 - 1 - 10 -3289.610538748326 - 20 -1243.423737554054 - 11 -3289.610538748326 - 21 -1243.623737554066 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -0.01 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -INSERT - 5 -58A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -*U4 - 10 --5510.392218238908 - 20 --1659.111589305452 - 30 -0 - 41 -0.01 - 42 -0.01 - 43 -0 - 50 -0 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -LWPOLYLINE - 5 -58B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3284.303068378243 - 20 -1243.852369962668 - 10 -3284.303068378243 - 20 -1242.952369962644 - 10 -3282.20288125542 - 20 -1242.952369962644 - 10 -3282.20288125542 - 20 -1246.164936604793 - 0 -LWPOLYLINE - 5 -58C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3284.603068378288 - 20 -1243.552369962679 - 10 -3284.003068378196 - 20 -1243.552369962679 - 10 -3284.303068378243 - 20 -1243.852369962668 - 10 -3284.603068378288 - 20 -1243.552369962679 - 0 -LEADER - 5 -58D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLeader - 3 -Standard - 71 - 1 - 72 - 0 - 73 - 3 - 74 - 0 - 75 - 0 - 40 -1 - 41 -10 - 76 -3 - 76 -3 - 10 -3282.57882252615 - 20 -1242.352369962667 - 30 -0 - 10 -3282.57882252615 - 20 -1241.332201593672 - 30 -0 - 10 -3282.957429503091 - 20 -1241.332201593672 - 30 -0 - 0 -LEADER - 5 -58E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLeader - 3 -Standard - 71 - 1 - 72 - 0 - 73 - 3 - 74 - 0 - 75 - 0 - 40 -1 - 41 -10 - 76 -3 - 76 -3 - 10 -3287.850942810532 - 20 -1243.423737554054 - 30 -0 - 10 -3287.850942810532 - 20 -1241.416164394351 - 30 -0 - 10 -3286.261099679629 - 20 -1241.416164394351 - 30 -0 - 0 -LWPOLYLINE - 5 -58F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3281.373068378307 - 20 -1245.952369962644 - 10 -3281.373068378307 - 20 -1242.154635776649 - 10 -3285.101714331658 - 20 -1242.154635776649 - 10 -3285.101714331658 - 20 -1243.472369962663 - 0 -LWPOLYLINE - 5 -590 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3281.573068378261 - 20 -1245.952369962644 - 10 -3281.573067692857 - 20 -1242.352978129291 - 10 -3284.903068378103 - 20 -1242.351769962667 - 10 -3284.901714331704 - 20 -1243.472369962663 - 0 -LWPOLYLINE - 5 -591 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3286.406714331592 - 20 -1243.472369962663 - 10 -3286.406714331592 - 20 -1242.922369962616 - 10 -3285.101714331658 - 20 -1242.922369962616 - 0 -LWPOLYLINE - 5 -592 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3286.606714331778 - 20 -1243.472369962663 - 10 -3286.606714331778 - 20 -1242.722369962663 - 10 -3285.101714331658 - 20 -1242.722369962663 - 0 -HATCH - 5 -593 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 6 - 72 - 1 - 10 -3286.606714331778 - 20 -1243.423737554054 - 11 -3286.406714331825 - 21 -1243.423737554054 - 72 - 1 - 10 -3286.406714331592 - 20 -1243.423737554054 - 11 -3286.406714331592 - 21 -1242.922369962616 - 72 - 1 - 10 -3286.406714331592 - 20 -1242.922369962616 - 11 -3285.101714331658 - 21 -1242.922369962616 - 72 - 1 - 10 -3285.101714331658 - 20 -1242.922369962616 - 11 -3285.101714331658 - 21 -1242.722369962605 - 72 - 1 - 10 -3285.101714331658 - 20 -1242.722369962663 - 11 -3286.606714331545 - 21 -1242.722369962663 - 72 - 1 - 10 -3286.606714331778 - 20 -1242.722369962663 - 11 -3286.606714331778 - 21 -1243.423737554112 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -0.01 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -LWPOLYLINE - 5 -594 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3285.101714331658 - 20 -1243.472369962663 - 10 -3284.903068378103 - 20 -1243.472369962663 - 10 -3284.903068378103 - 20 -1242.352369962667 - 10 -3284.903068378103 - 20 -1242.154635776649 - 0 -HATCH - 5 -595 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 5 - 72 - 1 - 10 -3285.101714331658 - 20 -1243.423737554054 - 11 -3284.903068378103 - 21 -1243.423737554054 - 72 - 1 - 10 -3284.903068378103 - 20 -1243.423737554054 - 11 -3284.903068378103 - 21 -1242.352369962609 - 72 - 1 - 10 -3284.903068378103 - 20 -1242.352369962667 - 11 -3284.903068378103 - 21 -1242.300036849221 - 72 - 1 - 10 -3284.903068378103 - 20 -1242.300036849163 - 11 -3285.101714331658 - 21 -1242.340948482859 - 72 - 1 - 10 -3285.101714331658 - 20 -1242.340948482917 - 11 -3285.101714331658 - 21 -1243.423737554054 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -0.01 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -HATCH - 5 -596 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3284.90308648541 - 20 -1242.352438598078 - 11 -3284.197075190956 - 21 -1242.154635776649 - 72 - 1 - 10 -3284.197075190956 - 20 -1242.154635776649 - 11 -3284.903068378103 - 21 -1242.154635776649 - 72 - 1 - 10 -3284.903068378103 - 20 -1242.154635776649 - 11 -3284.90308648541 - 21 -1242.352438598078 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -0.01 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -LINE - 5 -597 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3285.254891354823 - 20 -1244.552369962679 - 11 -3285.254891354823 - 21 -1244.752369962633 - 0 -LINE - 5 -598 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3286.254891354825 - 20 -1244.552369962621 - 11 -3286.254891354825 - 21 -1244.752369962633 - 0 -LWPOLYLINE - 5 -599 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 7 - 70 - 0 - 43 -0 - 10 -3285.131714331685 - 20 -1244.552369962679 - 10 -3286.406714331592 - 20 -1244.552369962679 - 10 -3286.406714331592 - 20 -1242.922369962616 - 10 -3285.101714331658 - 20 -1242.922369962616 - 10 -3285.101714331658 - 20 -1244.252369962632 - 10 -3285.131714331685 - 20 -1244.252369962632 - 10 -3285.131714331685 - 20 -1244.552369962679 - 0 -LWPOLYLINE - 5 -59A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 1 - 43 -0 - 10 -3285.181714331731 - 20 -1244.502369962632 - 10 -3286.356714331778 - 20 -1244.502369962632 - 10 -3286.356714331778 - 20 -1242.972369962663 - 10 -3285.151714331703 - 20 -1242.972369962663 - 10 -3285.151714331703 - 20 -1244.202369962644 - 10 -3285.181714331731 - 20 -1244.202369962644 - 0 -LWPOLYLINE - 5 -59B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 1 - 43 -0 - 10 -3285.231714331778 - 20 -1244.452369962644 - 10 -3286.306714331731 - 20 -1244.452369962644 - 10 -3286.306714331731 - 20 -1243.022369962651 - 10 -3285.20171433175 - 20 -1243.022369962651 - 10 -3285.20171433175 - 20 -1244.152369962656 - 10 -3285.231714331778 - 20 -1244.152369962656 - 0 -LINE - 5 -59C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3285.131714331685 - 20 -1244.552369962679 - 11 -3286.406714331592 - 21 -1242.922369962616 - 0 -LINE - 5 -59D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3286.406714331592 - 20 -1244.552369962679 - 11 -3285.101714331658 - 21 -1242.922369962616 - 0 -LWPOLYLINE - 5 -59E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3289.610538748326 - 20 -1243.423737554054 - 10 -3286.606714331778 - 20 -1243.423737554054 - 0 -LWPOLYLINE - 5 -59F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3289.610538748326 - 20 -1243.623737554066 - 10 -3286.606714331778 - 20 -1243.623737554066 - 0 -MTEXT - 5 -5A0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3285.410073219799 - 20 -1243.275681681291 - 30 -0 - 40 -0.21 - 41 -0.5133333333333333 - 71 - 1 - 72 - 5 - 1 -LIFT - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -5A1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3285.779215662741 - 20 -1243.303355389158 - 30 -0 - 40 -0.21 - 41 -1.026666666666706 - 71 - 1 - 72 - 5 - 1 -163X130 - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -5A2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3283.059859681409 - 20 -1239.929147053685 - 30 -0 - 40 -0.245 - 41 -2.361527777777777 - 71 - 1 - 72 - 5 - 1 -EARTH FILLING - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -5A3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3281.373068378307 - 20 -1246.452369962644 - 10 -3281.373068378307 - 20 -1259.280104148725 - 10 -3293.070538748289 - 20 -1259.280104148725 - 10 -3293.070538748289 - 20 -1245.952369962644 - 0 -LWPOLYLINE - 5 -5A4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3281.373068378307 - 20 -1246.452369962644 - 10 -3281.373068378182 - 20 -1259.280104148725 - 10 -3293.070538748289 - 20 -1259.280104148715 - 10 -3293.070538748289 - 20 -1245.952369963459 - 0 -MTEXT - 5 -5A5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3281.878084598111 - 20 -1246.088766773348 - 30 -0 - 40 -0.21 - 41 -0.3033333333333333 - 71 - 1 - 72 - 5 - 1 -UP - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -LINE - 5 -5A6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3293.37053874368 - 20 -1245.952369963459 - 11 -3293.070538746659 - 21 -1245.952369963459 - 0 -LWPOLYLINE - 5 -5A7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3289.840538748308 - 20 -1243.423737554054 - 10 -3289.840538748308 - 20 -1241.110540415975 - 10 -3289.640538748354 - 20 -1241.110540415975 - 10 -3289.640538748354 - 20 -1243.423737554054 - 0 -MTEXT - 5 -5A8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3285.859977117814 - 20 -1250.68617734451 - 30 -0 - 40 -0.4900000000000003 - 41 -4.831944444444448 - 71 - 1 - 72 - 5 - 1 -PARKING AREA - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883194 - 73 - 1 - 44 -1 - 0 -DIMENSION - 5 -5A9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D3 - 10 -3288.623488413138 - 20 -1259.280104148725 - 30 -0 - 11 -3288.495964981269 - 21 -1251.451920851396 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3287.835900044962 - 23 -1243.623737554066 - 33 -0 - 14 -3287.835900044962 - 24 -1259.280104148725 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -5AA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D4 - 10 -3293.070538748289 - 20 -1257.052749413065 - 30 -0 - 11 -3287.221803563298 - 21 -1257.180272844932 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3281.373068378307 - 23 -1258.780104148725 - 33 -0 - 14 -3293.070538748289 - 24 -1259.050104148744 - 34 -0 -100 -AcDbRotatedDimension - 0 -LINE - 5 -5AB -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3284.901714331704 - 20 -1244.752369962633 - 11 -3284.903068378103 - 21 -1245.052369962679 - 0 -LINE - 5 -5AC -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3282.081203917508 - 20 -1240.067414091609 - 11 -3282.081203917508 - 21 -1260.721494616649 - 0 -CIRCLE - 5 -5AD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbCircle - 10 -3282.081203917508 - 20 -1241.147899744741 - 40 -0.3105759447062155 - 0 -HATCH - 5 -5AE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3282.391779863741 - 20 -1241.147899743053 - 11 -3282.081203918905 - 21 -1241.458475687716 - 72 - 1 - 10 -3282.081203918905 - 20 -1241.458475687716 - 11 -3282.081203918905 - 21 -1240.837323798332 - 72 - 1 - 10 -3282.081203918905 - 20 -1240.837323798332 - 11 -3282.391779863741 - 21 -1241.147899743053 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -5AF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3282.081203917508 - 20 -1240.837323805026 - 10 -3282.391779859085 - 20 -1241.147899746604 - 10 -3282.081203917508 - 20 -1241.458475688181 - 10 -3282.081203917508 - 20 -1240.837323805026 - 0 -MTEXT - 5 -5B0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3282.367171005579 - 20 -1241.193436495552 - 30 -0 - 40 -0.4900000000000003 - 41 -0.3266666666666669 - 71 - 1 - 72 - 5 - 1 -A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -CIRCLE - 5 -5B1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbCircle - 10 -3282.081203917508 - 20 -1260.305064083717 - 40 -0.3105759447062155 - 0 -HATCH - 5 -5B2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3282.391779863741 - 20 -1260.305064084648 - 11 -3282.081203918905 - 21 -1260.615640029369 - 72 - 1 - 10 -3282.081203918905 - 20 -1260.615640029369 - 11 -3282.081203918905 - 21 -1259.994488139928 - 72 - 1 - 10 -3282.081203918905 - 20 -1259.994488139928 - 11 -3282.391779863741 - 21 -1260.305064084648 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -5B3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3282.081203917508 - 20 -1259.994488144002 - 10 -3282.391779859085 - 20 -1260.30506408558 - 10 -3282.081203917508 - 20 -1260.615640027157 - 10 -3282.081203917508 - 20 -1259.994488144002 - 0 -MTEXT - 5 -5B4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3282.367171005579 - 20 -1260.350600837148 - 30 -0 - 40 -0.4900000000000003 - 41 -0.3266666666666669 - 71 - 1 - 72 - 5 - 1 -A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -LINE - 5 -5B5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3293.070538746659 - 20 -1245.952369963459 - 11 -3293.075420911424 - 21 -1242.276362763427 - 0 -LINE - 5 -5B6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3293.075420911424 - 20 -1242.276362763427 - 11 -3293.299102444435 - 21 -1241.110540415975 - 0 -LWPOLYLINE - 5 -5B7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3300.624476717086 - 20 -1259.280104148725 - 10 -3300.774476717226 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -5B8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3301.974476717179 - 20 -1259.280104148725 - 10 -3302.774476717227 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -5B9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3303.708122670651 - 20 -1259.280104148725 - 10 -3310.491947087228 - 20 -1259.280104148725 - 10 -3310.491947087228 - 20 -1245.952385825629 - 0 -LINE - 5 -5BA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3298.794476717245 - 20 -1243.321229862398 - 11 -3298.794476717245 - 21 -1256.050104161259 - 0 -LINE - 5 -5BB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1243.321229862398 - 11 -3299.024476717227 - 21 -1256.050104161259 - 0 -LINE - 5 -5BC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3301.974476717179 - 20 -1259.050104148744 - 11 -3302.774476717227 - 21 -1259.050104148744 - 0 -LINE - 5 -5BD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3303.708122670651 - 20 -1259.050104148744 - 11 -3310.261947087246 - 21 -1259.050104148744 - 0 -LINE - 5 -5BE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3310.261947087246 - 20 -1259.050104148744 - 11 -3310.261947087246 - 21 -1245.952385825629 - 0 -LINE - 5 -5BF -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1242.252369962632 - 11 -3302.304476717254 - 21 -1242.252369962632 - 0 -LINE - 5 -5C0 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3307.0319470861 - 20 -1243.423737553589 - 11 -3304.028122673277 - 21 -1243.423737553589 - 0 -LINE - 5 -5C1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3305.8319470861 - 20 -1243.123737554066 - 11 -3304.028122670717 - 21 -1243.123737554066 - 0 -LINE - 5 -5C2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3305.8319470861 - 20 -1242.823737554077 - 11 -3304.028122670717 - 21 -1242.823737554077 - 0 -LINE - 5 -5C3 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3307.031947087264 - 20 -1243.423737554054 - 11 -3307.031947087264 - 21 -1242.823737554077 - 0 -LWPOLYLINE - 5 -5C4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3298.794476717245 - 20 -1243.321229862398 - 10 -3298.794476717245 - 20 -1241.721707735967 - 10 -3298.794476717245 - 20 -1241.721707735967 - 10 -3299.024476717227 - 20 -1241.721707735967 - 10 -3299.024476717227 - 20 -1243.321229862398 - 0 -LWPOLYLINE - 5 -5C5 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3300.624476717086 - 20 -1259.280104148725 - 10 -3300.774476717226 - 20 -1259.280104148725 - 0 -LINE - 5 -5C6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.224476717179 - 20 -1243.552369962679 - 11 -3300.224476717179 - 21 -1242.352369962667 - 0 -LINE - 5 -5C7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1243.852369962668 - 11 -3302.324476717273 - 21 -1243.852369962668 - 0 -LINE - 5 -5C8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1244.152369962656 - 11 -3302.324476717273 - 21 -1244.152369962656 - 0 -LINE - 5 -5C9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1244.452369962644 - 11 -3302.324476717273 - 21 -1244.452369962644 - 0 -LINE - 5 -5CA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1244.752369962633 - 11 -3302.324476717273 - 21 -1244.752369962633 - 0 -LINE - 5 -5CB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.274476717226 - 20 -1243.552369962679 - 11 -3302.324476717273 - 21 -1243.552369962679 - 0 -LWPOLYLINE - 5 -5CC -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3300.22410247149 - 20 -1247.752369962632 - 10 -3300.22410247149 - 20 -1244.152369962656 - 0 -LWPOLYLINE - 5 -5CD -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3300.22410247149 - 20 -1243.852369962668 - 10 -3300.22410247149 - 20 -1243.552369962679 - 10 -3301.124476717087 - 20 -1243.552369962679 - 10 -3301.124476717087 - 20 -1245.052369962679 - 0 -LWPOLYLINE - 5 -5CE -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3301.124476717087 - 20 -1245.152369962656 - 10 -3301.124476717087 - 20 -1245.652369962656 - 0 -LINE - 5 -5CF -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3300.194102471462 - 20 -1247.752369962632 - 11 -3300.194102471462 - 21 -1244.152369962656 - 0 -LINE - 5 -5D0 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3300.194102471462 - 20 -1243.852369962668 - 11 -3300.194102471462 - 21 -1243.522369962651 - 0 -LINE - 5 -5D1 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3300.194102471462 - 20 -1243.522369962651 - 11 -3301.154476717115 - 21 -1243.522369962651 - 0 -LINE - 5 -5D2 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.154476717115 - 20 -1245.052369962679 - 11 -3301.154476717115 - 21 -1245.652369962656 - 0 -LINE - 5 -5D3 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3300.164102471434 - 20 -1247.752369962632 - 11 -3300.164102471434 - 21 -1244.152369962656 - 0 -LINE - 5 -5D4 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3300.164102471434 - 20 -1243.852369962668 - 11 -3300.164102471434 - 21 -1243.492369962681 - 0 -LINE - 5 -5D5 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3300.164102471434 - 20 -1243.492369962681 - 11 -3301.184476717143 - 21 -1243.492369962681 - 0 -LINE - 5 -5D6 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.184476717143 - 20 -1245.052369962679 - 11 -3301.184476717143 - 21 -1245.652369962656 - 0 -LINE - 5 -5D7 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1247.752369962632 - 11 -3300.22410247149 - 21 -1244.752369962633 - 0 -LINE - 5 -5D8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3302.324476717273 - 20 -1244.752369962633 - 11 -3302.324476717273 - 21 -1245.052369962679 - 0 -LINE - 5 -5D9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1243.852369962668 - 11 -3299.024476717227 - 21 -1243.852369962668 - 0 -LINE - 5 -5DA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1243.552369962679 - 11 -3299.024476717227 - 21 -1243.552369962679 - 0 -LINE - 5 -5DB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1244.152369962656 - 11 -3299.024476717227 - 21 -1244.152369962656 - 0 -LINE - 5 -5DC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1244.452369962644 - 11 -3299.024476717227 - 21 -1244.452369962644 - 0 -LINE - 5 -5DD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1244.752369962633 - 11 -3299.024476717227 - 21 -1244.752369962633 - 0 -LINE - 5 -5DE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1245.052369962679 - 11 -3299.024476717227 - 21 -1245.052369962679 - 0 -LINE - 5 -5DF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1245.352369962667 - 11 -3299.024476717227 - 21 -1245.352369962667 - 0 -LINE - 5 -5E0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1245.652369962656 - 11 -3299.024476717227 - 21 -1245.652369962656 - 0 -LINE - 5 -5E1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1245.952369962644 - 11 -3299.024476717227 - 21 -1245.952369962644 - 0 -LINE - 5 -5E2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1246.252369962633 - 11 -3299.024476717227 - 21 -1246.252369962633 - 0 -LINE - 5 -5E3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1246.552369962679 - 11 -3299.024476717227 - 21 -1246.552369962679 - 0 -LINE - 5 -5E4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1246.852369962667 - 11 -3299.024476717227 - 21 -1246.852369962667 - 0 -LINE - 5 -5E5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1247.152369962656 - 11 -3299.024476717227 - 21 -1247.152369962656 - 0 -LINE - 5 -5E6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1247.452369962644 - 11 -3299.024476717227 - 21 -1247.452369962644 - 0 -LINE - 5 -5E7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.22410247149 - 20 -1247.752369962632 - 11 -3299.024476717227 - 21 -1247.752369962632 - 0 -LINE - 5 -5E8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1243.602689753345 - 11 -3301.124476717087 - 21 -1242.352369962667 - 0 -LINE - 5 -5E9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.824476717273 - 20 -1243.552369962679 - 11 -3300.824476717273 - 21 -1242.352369962667 - 0 -LINE - 5 -5EA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.524476717227 - 20 -1243.552369962679 - 11 -3300.524476717227 - 21 -1242.352369962667 - 0 -LINE - 5 -5EB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3310.261947087246 - 20 -1245.952385825629 - 11 -3310.493458622135 - 21 -1245.952369962644 - 0 -LWPOLYLINE - 5 -5EC -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3299.024476717227 - 20 -1242.352369962726 - 10 -3302.354476717068 - 20 -1242.352369962726 - 10 -3302.354476717068 - 20 -1242.722369962663 - 0 -LWPOLYLINE - 5 -5ED -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3299.024476717227 - 20 -1242.302369962737 - 10 -3302.404476717115 - 20 -1242.302369962737 - 10 -3302.404476717115 - 20 -1242.722369962663 - 0 -LWPOLYLINE - 5 -5EE -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3299.024476717227 - 20 -1242.252369962749 - 10 -3302.454476717161 - 20 -1242.252369962749 - 10 -3302.454476717161 - 20 -1242.722369962663 - 0 -LINE - 5 -5EF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1245.052369962737 - 11 -3302.324476717273 - 21 -1245.052369962679 - 0 -LINE - 5 -5F0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1245.352369962667 - 11 -3302.324476717273 - 21 -1245.352369962667 - 0 -LINE - 5 -5F1 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1245.652369962656 - 11 -3302.324476717273 - 21 -1245.652369962656 - 0 -LWPOLYLINE - 5 -5F2 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3307.031947087264 - 20 -1243.823737554077 - 10 -3310.491947087228 - 20 -1243.823737554077 - 10 -3310.491947087228 - 20 -1245.238323131343 - 0 -LWPOLYLINE - 5 -5F3 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3307.031947087264 - 20 -1243.873737554066 - 10 -3310.441947087181 - 20 -1243.873737554066 - 10 -3310.441947087181 - 20 -1245.238323131343 - 0 -LWPOLYLINE - 5 -5F4 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3307.031947087264 - 20 -1243.923737554054 - 10 -3310.391947087366 - 20 -1243.923737554054 - 10 -3310.391947087366 - 20 -1245.238323131343 - 0 -LWPOLYLINE - 5 -5F5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3310.493458622135 - 20 -1245.952369962644 - 10 -3310.491947087228 - 20 -1245.238323131343 - 10 -3310.261947087246 - 20 -1245.238323131343 - 10 -3310.261947087246 - 20 -1245.952385825629 - 0 -LINE - 5 -5F6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3302.553122670623 - 20 -1244.402369962656 - 11 -3302.553122670623 - 21 -1244.445176272304 - 0 -LINE - 5 -5F7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3302.553122670623 - 20 -1244.48176036129 - 11 -3302.553122670623 - 21 -1244.52456667088 - 0 -LINE - 5 -5F8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 52 -370 - 0 -100 -AcDbLine - 10 -3303.828122670763 - 20 -1244.402369962656 - 11 -3303.828122670763 - 21 -1243.472369962663 - 0 -LINE - 5 -5F9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3303.828122670763 - 20 -1244.552369962621 - 11 -3303.676299693994 - 21 -1244.552369962621 - 0 -LINE - 5 -5FA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3302.676299693994 - 20 -1244.552369962679 - 11 -3302.553122670623 - 21 -1244.552369962679 - 0 -LINE - 5 -5FB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3303.828122670763 - 20 -1244.752369962633 - 11 -3303.676299693994 - 21 -1244.752369962633 - 0 -LINE - 5 -5FC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3302.676299693994 - 20 -1244.752369962633 - 11 -3302.324476717273 - 21 -1244.752369962633 - 0 -LINE - 5 -5FD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3302.553122670623 - 20 -1244.402369962656 - 11 -3302.553122670623 - 21 -1244.445176272304 - 0 -LINE - 5 -5FE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3302.553122670623 - 20 -1244.48176036129 - 11 -3302.553122670623 - 21 -1244.52456667088 - 0 -LWPOLYLINE - 5 -5FF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 0 - 43 -0 - 10 -3303.828122670763 - 20 -1243.472369962663 - 10 -3303.828122670763 - 20 -1244.752369962633 - 10 -3304.028122670717 - 20 -1244.752369962633 - 10 -3304.178122670623 - 20 -1244.752369962633 - 10 -3304.178122670623 - 20 -1244.522369962651 - 10 -3304.028122670717 - 20 -1244.522369962651 - 10 -3304.028122670717 - 20 -1243.472369962663 - 10 -3303.828122670763 - 20 -1243.472369962663 - 0 -LINE - 5 -600 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3302.324476717273 - 20 -1243.472369962663 - 11 -3302.324476717273 - 21 -1244.752369962633 - 0 -LINE - 5 -601 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3302.524476717226 - 20 -1243.672369962675 - 11 -3302.524476717226 - 21 -1244.252369962632 - 0 -LWPOLYLINE - 5 -602 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3303.828122670763 - 20 -1243.472369962663 - 10 -3303.828122670763 - 20 -1242.922369962616 - 10 -3302.523122670595 - 20 -1242.922369962616 - 0 -LWPOLYLINE - 5 -603 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3304.028122670717 - 20 -1243.472369962663 - 10 -3304.028122670717 - 20 -1242.722369962663 - 10 -3302.523122670595 - 20 -1242.722369962663 - 0 -LWPOLYLINE - 5 -604 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3303.978122670669 - 20 -1243.472369962663 - 10 -3303.978122670669 - 20 -1242.772369962651 - 10 -3302.523122670595 - 20 -1242.772369962651 - 0 -LWPOLYLINE - 5 -605 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3303.928122670622 - 20 -1243.472369962663 - 10 -3303.928122670622 - 20 -1242.822369962639 - 10 -3302.523122670595 - 20 -1242.822369962639 - 0 -LWPOLYLINE - 5 -606 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3302.523122670595 - 20 -1243.472369962663 - 10 -3302.324476717273 - 20 -1243.472369962663 - 10 -3302.324476717273 - 20 -1242.722369962663 - 10 -3302.324476717273 - 20 -1242.722369962663 - 0 -LINE - 5 -607 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3302.676299693994 - 20 -1244.552369962679 - 11 -3302.676299693994 - 21 -1244.752369962633 - 0 -LINE - 5 -608 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3303.676299693994 - 20 -1244.552369962621 - 11 -3303.676299693994 - 21 -1244.752369962633 - 0 -LWPOLYLINE - 5 -609 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 7 - 70 - 0 - 43 -0 - 10 -3302.553122670623 - 20 -1244.552369962679 - 10 -3303.828122670763 - 20 -1244.552369962679 - 10 -3303.828122670763 - 20 -1242.922369962616 - 10 -3302.523122670595 - 20 -1242.922369962616 - 10 -3302.523122670595 - 20 -1244.252369962632 - 10 -3302.553122670623 - 20 -1244.252369962632 - 10 -3302.553122670623 - 20 -1244.552369962679 - 0 -LWPOLYLINE - 5 -60A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 1 - 43 -0 - 10 -3302.60312267067 - 20 -1244.502369962632 - 10 -3303.778122670716 - 20 -1244.502369962632 - 10 -3303.778122670716 - 20 -1242.972369962663 - 10 -3302.57312267064 - 20 -1242.972369962663 - 10 -3302.57312267064 - 20 -1244.202369962644 - 10 -3302.60312267067 - 20 -1244.202369962644 - 0 -LWPOLYLINE - 5 -60B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 1 - 43 -0 - 10 -3302.653122670716 - 20 -1244.452369962644 - 10 -3303.728122670669 - 20 -1244.452369962644 - 10 -3303.728122670669 - 20 -1243.022369962651 - 10 -3302.623122670688 - 20 -1243.022369962651 - 10 -3302.623122670688 - 20 -1244.152369962656 - 10 -3302.653122670716 - 20 -1244.152369962656 - 0 -LINE - 5 -60C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3302.553122670623 - 20 -1244.552369962679 - 11 -3303.828122670763 - 21 -1242.922369962616 - 0 -LINE - 5 -60D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3303.828122670763 - 20 -1244.552369962679 - 11 -3302.523122670595 - 21 -1242.922369962616 - 0 -MTEXT - 5 -60E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3302.83148155897 - 20 -1243.275681681291 - 30 -0 - 40 -0.21 - 41 -0.5133333333333333 - 71 - 1 - 72 - 5 - 1 -LIFT - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -60F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3303.200624001679 - 20 -1243.303355389158 - 30 -0 - 40 -0.21 - 41 -1.026666666666706 - 71 - 1 - 72 - 5 - 1 -163X130 - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -LINE - 5 -610 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3302.323122670641 - 20 -1244.752369962633 - 11 -3302.324476717273 - 21 -1245.052369962679 - 0 -LWPOLYLINE - 5 -611 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3302.523122670595 - 20 -1243.423737554054 - 10 -3302.523122670595 - 20 -1242.722369962663 - 10 -3302.324476717273 - 20 -1242.722369962663 - 10 -3302.324476717273 - 20 -1243.423737554054 - 0 -HATCH - 5 -612 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3299.624509939226 - 20 -1243.852369962668 - 11 -3299.624730284093 - 21 -1243.552369962679 - 72 - 1 - 10 -3299.624730284093 - 20 -1243.552369962679 - 11 -3299.928648714209 - 21 -1243.552369962679 - 72 - 1 - 10 -3299.928648714209 - 20 -1243.552369962679 - 11 -3299.624509939226 - 21 -1243.852369962668 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -613 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3299.624509939226 - 20 -1243.852369962668 - 11 -3299.339834515239 - 21 -1243.552369962679 - 72 - 1 - 10 -3299.339834515239 - 20 -1243.552369962679 - 11 -3299.624730284093 - 21 -1243.552369962679 - 72 - 1 - 10 -3299.624730284093 - 20 -1243.552369962679 - 11 -3299.624509939226 - 21 -1243.852369962668 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -614 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3301.738169059623 - 20 -1246.567925359879 - 10 -3301.738169059623 - 20 -1243.552369962679 - 10 -3301.738169059623 - 20 -1242.922737527056 - 10 -3299.625192738371 - 20 -1242.922737527056 - 10 -3299.624289594358 - 20 -1244.152369962656 - 0 -LWPOLYLINE - 5 -615 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3299.928648714209 - 20 -1243.552369962679 - 10 -3299.624509939226 - 20 -1243.852369962668 - 10 -3299.339834515239 - 20 -1243.552369962679 - 10 -3299.928648714209 - 20 -1243.552369962679 - 0 -LWPOLYLINE - 5 -616 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3301.154476717115 - 20 -1243.82236996438 - 10 -3301.154476717115 - 20 -1245.402369964397 - 10 -3300.194102471462 - 20 -1245.402369964397 - 0 -LWPOLYLINE - 5 -617 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3301.184476717143 - 20 -1243.792369964411 - 10 -3301.184476717143 - 20 -1245.452369964385 - 10 -3300.194102471462 - 20 -1245.452369964385 - 0 -LINE - 5 -618 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3302.324476717273 - 20 -1245.052369962679 - 11 -3302.324476717273 - 21 -1245.652369962656 - 0 -LWPOLYLINE - 5 -619 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3302.323122670641 - 20 -1244.752369962633 - 10 -3302.324476717273 - 20 -1245.052369962679 - 0 -LWPOLYLINE - 5 -61A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3302.373122161487 - 20 -1244.752144290542 - 10 -3302.374476207886 - 20 -1245.05214429053 - 0 -LWPOLYLINE - 5 -61B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3302.4231216521 - 20 -1244.751918618393 - 10 -3302.424475698499 - 20 -1245.051918618439 - 0 -LWPOLYLINE - 5 -61C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3302.324476717273 - 20 -1245.052369962679 - 10 -3302.424475698499 - 20 -1245.051918618439 - 0 -LINE - 5 -61D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1256.300104148744 - 11 -3299.774476717227 - 21 -1256.300104148744 - 0 -LINE - 5 -61E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1256.500104148697 - 11 -3299.774476717227 - 21 -1256.500104148697 - 0 -LINE - 5 -61F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1256.700104148709 - 11 -3299.774476717227 - 21 -1256.700104148709 - 0 -LINE - 5 -620 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1256.900104148721 - 11 -3299.774476717227 - 21 -1256.900104148721 - 0 -LINE - 5 -621 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1257.100104148732 - 11 -3299.774476717227 - 21 -1257.100104148732 - 0 -LINE - 5 -622 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1257.300104148744 - 11 -3299.774476717227 - 21 -1257.300104148744 - 0 -LINE - 5 -623 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1257.500104148697 - 11 -3299.774476717227 - 21 -1257.500104148697 - 0 -LINE - 5 -624 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1257.700104148709 - 11 -3299.774476717227 - 21 -1257.700104148709 - 0 -LINE - 5 -625 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1257.900104148721 - 11 -3299.774476717227 - 21 -1257.900104148721 - 0 -LINE - 5 -626 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1258.100104148732 - 11 -3299.774476717227 - 21 -1258.100104148732 - 0 -LINE - 5 -627 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.024476717227 - 20 -1258.300104148744 - 11 -3299.774476717227 - 21 -1258.300104148744 - 0 -LWPOLYLINE - 5 -628 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3299.774476717227 - 20 -1258.300104148744 - 10 -3299.774476717227 - 20 -1258.100104148732 - 0 -LWPOLYLINE - 5 -629 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3299.774476717227 - 20 -1257.900104148721 - 10 -3299.774476717227 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -62A -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3299.874476717086 - 20 -1258.300104148744 - 10 -3299.874476717086 - 20 -1256.300104148744 - 0 -LINE - 5 -62B -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1256.300104148744 - 11 -3300.624476717086 - 21 -1256.300104148744 - 0 -LINE - 5 -62C -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1256.500104148697 - 11 -3300.624476717086 - 21 -1256.500104148697 - 0 -LINE - 5 -62D -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1256.700104148709 - 11 -3300.624476717086 - 21 -1256.700104148709 - 0 -LINE - 5 -62E -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1256.900104148721 - 11 -3300.624476717086 - 21 -1256.900104148721 - 0 -LINE - 5 -62F -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1257.100104148732 - 11 -3300.624476717086 - 21 -1257.100104148732 - 0 -LINE - 5 -630 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1257.300104148744 - 11 -3300.624476717086 - 21 -1257.300104148744 - 0 -LINE - 5 -631 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1257.500104148697 - 11 -3300.624476717086 - 21 -1257.500104148697 - 0 -LINE - 5 -632 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476703351 - 20 -1257.700104148767 - 11 -3300.624476733152 - 21 -1257.700104148767 - 0 -LINE - 5 -633 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1257.900104148721 - 11 -3300.624476717086 - 21 -1257.900104148721 - 0 -LINE - 5 -634 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1258.100104148732 - 11 -3300.624476717086 - 21 -1258.100104148732 - 0 -LINE - 5 -635 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.874476717086 - 20 -1258.300104148744 - 11 -3300.624476717086 - 21 -1258.300104148744 - 0 -LWPOLYLINE - 5 -636 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3300.624476717086 - 20 -1259.050104148744 - 10 -3300.624476717086 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -637 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3299.774476717227 - 20 -1256.300104148744 - 10 -3299.774476717227 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -638 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3299.774476717227 - 20 -1258.100104148732 - 10 -3299.774476717227 - 20 -1258.300104148744 - 10 -3299.874476717086 - 20 -1258.300104148744 - 10 -3299.874476717086 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -639 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3299.744476717199 - 20 -1256.300104148744 - 10 -3299.744476717199 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -63A -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3299.744476717199 - 20 -1258.100104148732 - 10 -3299.744476717199 - 20 -1258.330104148714 - 10 -3299.904476717114 - 20 -1258.330104148714 - 10 -3299.904476717114 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -63B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3299.71447671717 - 20 -1256.300104148744 - 10 -3299.71447671717 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -63C -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3299.71447671717 - 20 -1258.100104148732 - 10 -3299.71447671717 - 20 -1258.360104148741 - 10 -3299.934476717143 - 20 -1258.360104148741 - 10 -3299.934476717143 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -63D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3300.624476717086 - 20 -1255.998735667439 - 10 -3300.624476717086 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -63E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3300.774476717226 - 20 -1256.048921864945 - 10 -3300.774476717226 - 20 -1259.050104148744 - 0 -LWPOLYLINE - 5 -63F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3300.774476717226 - 20 -1257.550104148744 - 10 -3301.074575636537 - 20 -1257.550104148744 - 0 -LWPOLYLINE - 5 -640 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3300.774476717226 - 20 -1257.550104148744 - 10 -3301.824485586723 - 20 -1257.550104148744 - 0 -LWPOLYLINE - 5 -641 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3302.724476717179 - 20 -1257.550104148744 - 10 -3302.724476717179 - 20 -1259.050104148744 - 0 -LWPOLYLINE - 5 -642 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3300.774476716761 - 20 -1257.500104145787 - 10 -3301.824476721231 - 20 -1257.500104145787 - 0 -LWPOLYLINE - 5 -643 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3302.724476717179 - 20 -1257.500104148697 - 10 -3302.774476717227 - 20 -1257.500104148697 - 10 -3302.774476717227 - 20 -1259.050104148744 - 0 -LINE - 5 -644 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3303.94001641986 - 20 -1256.048360379122 - 11 -3303.94001641986 - 21 -1259.050104148744 - 0 -LINE - 5 -645 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3303.840016419767 - 20 -1256.048360379122 - 11 -3303.840016419767 - 21 -1259.050104148744 - 0 -LWPOLYLINE - 5 -646 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3303.574476713782 - 20 -1257.500104145787 - 10 -3303.840016419535 - 20 -1257.500104145787 - 0 -LWPOLYLINE - 5 -647 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3303.574476717273 - 20 -1257.550104148744 - 10 -3303.840016419767 - 20 -1257.550104148744 - 0 -LWPOLYLINE - 5 -648 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3301.774219281506 - 20 -1256.048735667427 - 10 -3300.774476750289 - 20 -1256.048921864945 - 0 -LWPOLYLINE - 5 -649 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3301.774219281506 - 20 -1256.048735667427 - 10 -3301.774219281506 - 20 -1256.048735667427 - 10 -3300.774476717226 - 20 -1256.048735667427 - 0 -LWPOLYLINE - 5 -64A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3301.824485587422 - 20 -1257.550104146532 - 10 -3301.824476721231 - 20 -1257.500104145787 - 0 -LWPOLYLINE - 5 -64B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3301.824334818404 - 20 -1256.700104148709 - 10 -3301.824210413499 - 20 -1255.998735667439 - 10 -3300.774476717226 - 20 -1255.998735667439 - 0 -LWPOLYLINE - 5 -64C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3300.774476717226 - 20 -1259.050104148744 - 10 -3300.774476717226 - 20 -1255.998735667439 - 10 -3300.624476717086 - 20 -1255.998735667439 - 0 -LINE - 5 -64D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3302.724219282391 - 20 -1255.998735667439 - 11 -3303.709826648236 - 21 -1255.998735667439 - 0 -LINE - 5 -64E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3302.724219282391 - 20 -1256.048735667427 - 11 -3303.709826648236 - 21 -1256.048735667427 - 0 -LINE - 5 -64F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3302.724476717179 - 20 -1257.550104148744 - 11 -3302.724476717179 - 21 -1257.500104148697 - 0 -LINE - 5 -650 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3301.824485586723 - 20 -1257.550104148744 - 11 -3302.724476717179 - 21 -1257.550104148744 - 0 -LINE - 5 -651 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3301.824219282251 - 20 -1256.048735667427 - 11 -3301.824219282251 - 21 -1255.998735667439 - 0 -LINE - 5 -652 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3302.724219282391 - 20 -1256.048735667427 - 11 -3302.724219282391 - 21 -1255.998735667439 - 0 -LINE - 5 -653 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3301.774219281506 - 20 -1256.048735667427 - 11 -3301.774196847809 - 21 -1256.048735667427 - 0 -LINE - 5 -654 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3301.774476716762 - 20 -1257.500104145787 - 11 -3301.824476721231 - 21 -1257.500104145787 - 0 -LINE - 5 -655 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3301.774476717226 - 20 -1256.700104148709 - 11 -3301.824476717972 - 21 -1256.700104148709 - 0 -LINE - 5 -656 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3301.774476717226 - 20 -1256.700104148709 - 11 -3301.774179179687 - 21 -1256.048735667427 - 0 -LINE - 5 -657 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3301.774476717226 - 20 -1256.700104148709 - 11 -3301.774476717226 - 21 -1257.500104148697 - 0 -LINE - 5 -658 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3302.774476717227 - 20 -1257.550104148744 - 11 -3302.774476717227 - 21 -1257.500104148697 - 0 -LINE - 5 -659 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3303.574476713782 - 20 -1257.550104146532 - 11 -3303.574476713782 - 21 -1257.500104145787 - 0 -LINE - 5 -65A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3303.574476717273 - 20 -1257.550104148744 - 11 -3302.774476717227 - 21 -1257.550104148744 - 0 -LWPOLYLINE - 5 -65B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3298.794476717245 - 20 -1256.050104161259 - 10 -3298.794476717245 - 20 -1259.280104148725 - 10 -3300.624476717086 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -65C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3298.844476717059 - 20 -1256.050104161259 - 10 -3298.844476717059 - 20 -1259.230104148737 - 10 -3300.624476717086 - 20 -1259.230104148737 - 0 -LWPOLYLINE - 5 -65D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3298.894476717105 - 20 -1256.050104161259 - 10 -3298.894476717105 - 20 -1259.180104148749 - 10 -3300.624476717086 - 20 -1259.180104148749 - 0 -LWPOLYLINE - 5 -65E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3299.024476717227 - 20 -1256.050104161259 - 10 -3299.024476717227 - 20 -1259.050104148744 - 10 -3300.624476717086 - 20 -1259.050104148744 - 0 -LINE - 5 -65F -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3299.502612257843 - 20 -1240.067414091609 - 11 -3299.502612257843 - 21 -1260.721494616649 - 0 -CIRCLE - 5 -660 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbCircle - 10 -3299.502612257843 - 20 -1241.147899744741 - 40 -0.3105759447062155 - 0 -HATCH - 5 -661 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3299.813188202679 - 20 -1241.147899743053 - 11 -3299.502612257843 - 21 -1241.458475687716 - 72 - 1 - 10 -3299.502612257843 - 20 -1241.458475687716 - 11 -3299.502612257843 - 21 -1240.837323798332 - 72 - 1 - 10 -3299.502612257843 - 20 -1240.837323798332 - 11 -3299.813188202679 - 21 -1241.147899743053 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -662 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3299.502612257843 - 20 -1240.837323816202 - 10 -3299.813188193831 - 20 -1241.147899740957 - 10 -3299.502612257843 - 20 -1241.458475688181 - 10 -3299.502612257843 - 20 -1240.837323816202 - 0 -MTEXT - 5 -663 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3299.788579344517 - 20 -1241.193436495552 - 30 -0 - 40 -0.4900000000000003 - 41 -0.3266666666666669 - 71 - 1 - 72 - 5 - 1 -A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -CIRCLE - 5 -664 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbCircle - 10 -3299.502612257843 - 20 -1260.305064083717 - 40 -0.3105759447062155 - 0 -HATCH - 5 -665 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3299.813188202679 - 20 -1260.305064084648 - 11 -3299.502612257843 - 21 -1260.615640029369 - 72 - 1 - 10 -3299.502612257843 - 20 -1260.615640029369 - 11 -3299.502612257843 - 21 -1259.994488139928 - 72 - 1 - 10 -3299.502612257843 - 20 -1259.994488139928 - 11 -3299.813188202679 - 21 -1260.305064084648 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -666 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3299.502612257843 - 20 -1259.994488147728 - 10 -3299.813188197557 - 20 -1260.305064083717 - 10 -3299.502612257843 - 20 -1260.615640027157 - 10 -3299.502612257843 - 20 -1259.994488147728 - 0 -MTEXT - 5 -667 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3299.788579344517 - 20 -1260.350600837148 - 30 -0 - 40 -0.4900000000000003 - 41 -0.3266666666666669 - 71 - 1 - 72 - 5 - 1 -A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -HATCH - 5 -668 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3305.53003487899 - 20 -1243.423737554054 - 11 -3305.53003487899 - 21 -1243.123737554066 - 72 - 1 - 10 -3305.53003487899 - 20 -1243.123737554066 - 11 -3305.830034879036 - 21 -1243.123737554066 - 72 - 1 - 10 -3305.830034879036 - 20 -1243.123737554066 - 11 -3305.53003487899 - 21 -1243.423737554054 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -669 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3305.53003487899 - 20 -1243.423737554054 - 11 -3305.230034878943 - 21 -1243.123737554066 - 72 - 1 - 10 -3305.230034878943 - 20 -1243.123737554066 - 11 -3305.53003487899 - 21 -1243.123737554066 - 72 - 1 - 10 -3305.53003487899 - 20 -1243.123737554066 - 11 -3305.53003487899 - 21 -1243.423737554054 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LINE - 5 -66A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3305.530034879688 - 20 -1243.423737553589 - 11 -3305.530034879688 - 21 -1241.299706538848 - 0 -LWPOLYLINE - 5 -66B -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3289.610538748326 - 20 -1243.823737554077 - 10 -3293.070538748289 - 20 -1243.823737554077 - 10 -3293.070538748289 - 20 -1245.952369962644 - 0 -DIMENSION - 5 -66C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D5 - 10 -3293.070538748289 - 20 -1261.079065790865 - 30 -0 - 11 -3287.221803563298 - 21 -1261.206589222733 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3281.373068378307 - 23 -1259.280104148725 - 33 -0 - 14 -3293.070538748289 - 24 -1259.280104148725 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -66D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D6 - 10 -3294.049122274159 - 20 -1245.952369962645 - 30 -0 - 11 -3293.921598842291 - 21 -1252.616237055684 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3293.070538748289 - 23 -1259.280104148725 - 33 -0 - 14 -3293.070538748289 - 24 -1245.952369962644 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -66E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D7 - 10 -3280.402680748146 - 20 -1259.280104148726 - 30 -0 - 11 -3280.275157316278 - 21 -1250.717369962687 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3281.373068378307 - 23 -1242.154635776649 - 33 -0 - 14 -3281.373068378307 - 24 -1259.280104148725 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -INSERT - 5 -66F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -tre - 10 -1789.751515634358 - 20 -1356.923699999461 - 30 -0 - 41 --0.0059048999998235 - 42 -0.0059048999997322 - 43 -0 - 50 -179.9911266057404 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -670 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -tre - 10 -1789.807194218505 - 20 -1358.730176527402 - 30 -0 - 41 --0.0059048999998235 - 42 -0.0059048999997322 - 43 -0 - 50 -179.9911266057404 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -LINE - 5 -671 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3300.774476717226 - 20 -1258.644932924595 - 11 -3301.208427953534 - 21 -1258.644932924595 - 0 -LINE - 5 -672 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3301.208427953534 - 20 -1258.644932924595 - 11 -3301.208427953534 - 21 -1258.684932924574 - 0 -LINE - 5 -673 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3301.208427953534 - 20 -1258.684932924574 - 11 -3300.774476717226 - 21 -1258.684932924574 - 0 -LINE - 5 -674 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3300.774476716761 - 20 -1258.018103768758 - 11 -3301.208427953068 - 21 -1258.018103768758 - 0 -LINE - 5 -675 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3301.208427953068 - 20 -1258.018103768758 - 11 -3301.208427953068 - 21 -1258.058103767864 - 0 -LINE - 5 -676 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3301.208427953068 - 20 -1258.058103767864 - 11 -3300.774476716761 - 21 -1258.058103767864 - 0 -INSERT - 5 -677 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbBlockReference - 2 -15 - 10 -4062.757693060674 - 20 -8221.425826757622 - 30 -0 - 41 -0.0094866649972689 - 42 -0.0094866649972689 - 43 -0 - 50 -89.99112660048513 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -MTEXT - 5 -678 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3301.78705061134 - 20 -1256.994305585045 - 30 -0 - 40 -0.22 - 41 -1.381111111111138 - 71 - 1 - 72 - 5 - 1 -\pt308;D2 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -89.9911266023461 - 73 - 1 - 44 -1 - 0 -INSERT - 5 -679 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -tre - 10 -3403.676925843814 - 20 -2770.100082705671 - 30 -0 - 41 --0.0059048999998235 - 42 -0.0059048999997322 - 43 -0 - 50 -89.9911266057404 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -67A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbBlockReference - 2 -15 - 10 --4434.939009629188 - 20 -412.0207373641314 - 30 -0 - 41 --0.0105407388858543 - 42 -0.0105407388858543 - 43 -0 - 50 -0.0088733995148438 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -MTEXT - 5 -67B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3303.006558738184 - 20 -1257.331142450508 - 30 -0 - 40 -0.22 - 41 -1.381111111111138 - 71 - 1 - 72 - 5 - 1 -\pt308;D2 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -89.9911266023461 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -67C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3302.180130573921 - 20 -1257.379249563906 - 30 -0 - 40 -0.22 - 41 -1.454444444444486 - 71 - 1 - 72 - 5 - 1 -\pt3.08;D3 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -89.9911266023461 - 73 - 1 - 44 -1 - 0 -INSERT - 5 -67D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbBlockReference - 2 -15 - 10 -11814.16996514331 - 20 -327.4700975784217 - 30 -0 - 41 -0.0115948127744398 - 42 -0.0115948127744398 - 43 -0 - 50 -359.9911266004852 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -LINE - 5 -67E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3302.774476717227 - 20 -1259.050104148744 - 11 -3302.774476717227 - 21 -1259.280104148725 - 0 -LINE - 5 -67F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3300.774476717226 - 20 -1259.050104148744 - 11 -3300.774476717226 - 21 -1259.280104148725 - 0 -LINE - 5 -680 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3301.974476717179 - 20 -1259.050104148744 - 11 -3301.974476717179 - 21 -1259.280104148725 - 0 -LINE - 5 -681 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3302.774476717227 - 20 -1259.280104148725 - 11 -3303.708122670651 - 21 -1259.280104148725 - 0 -LINE - 5 -682 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3302.774476717227 - 20 -1259.230104148737 - 11 -3303.708122670651 - 21 -1259.230104148737 - 0 -LINE - 5 -683 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3302.774476717227 - 20 -1259.180104148749 - 11 -3303.708122670651 - 21 -1259.180104148749 - 0 -LINE - 5 -684 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3302.774476717227 - 20 -1259.050104148744 - 11 -3303.708122670651 - 21 -1259.050104148744 - 0 -LINE - 5 -685 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3300.774476717226 - 20 -1259.280104148725 - 11 -3301.974476717179 - 21 -1259.280104148725 - 0 -LINE - 5 -686 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3300.774476717226 - 20 -1259.230104148737 - 11 -3301.974476717179 - 21 -1259.230104148737 - 0 -LINE - 5 -687 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3300.774476717226 - 20 -1259.180104148749 - 11 -3301.974476717179 - 21 -1259.180104148749 - 0 -LINE - 5 -688 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3300.774476717226 - 20 -1259.050104148744 - 11 -3301.974476717179 - 21 -1259.050104148744 - 0 -INSERT - 5 -689 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbBlockReference - 2 -15 - 10 -11040.33770562871 - 20 -410.5193688828149 - 30 -0 - 41 -0.0105407388858543 - 42 -0.0105407388858543 - 43 -0 - 50 -359.9911266004852 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -MTEXT - 5 -68A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3302.125557532999 - 20 -1256.012902952148 - 30 -0 - 40 -0.22 - 41 -1.33222222222225 - 71 - 1 - 72 - 5 - 1 -\pt308;D1 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -89.9911266023461 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -68B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3289.177517196164 - 20 -1240.247074862826 - 10 -3291.086696353044 - 20 -1240.67111403431 - 10 -3291.166303563863 - 20 -1241.271821681992 - 10 -3292.05901944451 - 20 -1240.043893054477 - 10 -3291.988317709649 - 20 -1240.83010695572 - 10 -3294.631075764543 - 20 -1241.395507029665 - 0 -LWPOLYLINE - 5 -68C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3305.830034879036 - 20 -1243.123737554066 - 10 -3305.230034878943 - 20 -1243.123737554066 - 10 -3305.53003487899 - 20 -1243.423737554054 - 10 -3305.830034879036 - 20 -1243.123737554066 - 0 -DIMENSION - 5 -68D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D8 - 10 -3300.22410247149 - 20 -1248.124625565833 - 30 -0 - 11 -3299.624289594358 - 21 -1248.2521489977 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3299.024476717227 - 23 -1247.752369962632 - 33 -0 - 14 -3300.22410247149 - 24 -1247.752369962632 - 34 -0 -100 -AcDbRotatedDimension - 0 -MTEXT - 5 -68E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3300.46796825272 - 20 -1243.638422377058 - 30 -0 - 40 -0.21 - 41 -1.18416666666668 - 71 - 1 - 72 - 5 - 1 -CUT OUT - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -LINE - 5 -68F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3299.624289596919 - 20 -1245.052369961224 - 11 -3299.624289596919 - 21 -1249.399006945721 - 0 -HATCH - 5 -690 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3299.624509939226 - 20 -1245.052369962679 - 11 -3299.624730284093 - 21 -1245.352369962667 - 72 - 1 - 10 -3299.624730284093 - 20 -1245.352369962667 - 11 -3299.928648714209 - 21 -1245.352369962667 - 72 - 1 - 10 -3299.928648714209 - 20 -1245.352369962667 - 11 -3299.624509939226 - 21 -1245.052369962679 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -691 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3299.624509939226 - 20 -1245.052369962679 - 11 -3299.339834515239 - 21 -1245.352369962667 - 72 - 1 - 10 -3299.339834515239 - 20 -1245.352369962667 - 11 -3299.624730284093 - 21 -1245.352369962667 - 72 - 1 - 10 -3299.624730284093 - 20 -1245.352369962667 - 11 -3299.624509939226 - 21 -1245.052369962679 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -692 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3299.928648714209 - 20 -1245.352369962667 - 10 -3299.624509939226 - 20 -1245.052369962679 - 10 -3299.339834515239 - 20 -1245.352369962667 - 10 -3299.928648714209 - 20 -1245.352369962667 - 0 -MTEXT - 5 -693 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3299.299492937281 - 20 -1249.322837113054 - 30 -0 - 40 -0.21 - 41 -0.3033333333333333 - 71 - 1 - 72 - 5 - 1 -UP - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -694 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3301.413372402545 - 20 -1246.491755528434 - 30 -0 - 40 -0.21 - 41 -0.3033333333333463 - 71 - 1 - 72 - 5 - 1 -DN - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -695 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3327.345456386451 - 20 -1259.280104146979 - 10 -3327.345456386451 - 20 -1259.280104146979 - 10 -3327.345456386451 - 20 -1245.952385825745 - 0 -LINE - 5 -696 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3315.647986019496 - 20 -1243.321229865483 - 11 -3315.647986019496 - 21 -1256.050104161433 - 0 -LINE - 5 -697 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1243.321229862398 - 11 -3315.877986022039 - 21 -1256.050104161259 - 0 -LINE - 5 -698 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3327.11545639229 - 20 -1259.050104148744 - 11 -3327.11545639229 - 21 -1245.952385825629 - 0 -LINE - 5 -699 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1242.252369962632 - 11 -3319.157986022066 - 21 -1242.252369962632 - 0 -LINE - 5 -69A -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3323.885456392076 - 20 -1243.423737554054 - 11 -3323.885456392076 - 21 -1242.823737554077 - 0 -LWPOLYLINE - 5 -69B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3315.647986022057 - 20 -1243.321229862398 - 10 -3315.647986022057 - 20 -1241.721707735967 - 10 -3315.647986022057 - 20 -1241.721707735967 - 10 -3315.877986022039 - 20 -1241.721707735967 - 10 -3315.877986022039 - 20 -1243.321229862398 - 0 -LWPOLYLINE - 5 -69C -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3324.115456392291 - 20 -1243.923737554054 - 10 -3324.115456392291 - 20 -1242.900966822169 - 10 -3321.032986022066 - 20 -1241.721707735967 - 10 -3315.877986022039 - 20 -1241.721707735967 - 0 -LINE - 5 -69D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077986021992 - 20 -1243.552369962679 - 11 -3317.077986021992 - 21 -1242.352369962667 - 0 -LINE - 5 -69E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.977986022132 - 20 -1243.852369962668 - 11 -3319.177986022085 - 21 -1243.852369962668 - 0 -LINE - 5 -69F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.977986022132 - 20 -1244.152369962656 - 11 -3319.177986022085 - 21 -1244.152369962656 - 0 -LINE - 5 -6A0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.977986022132 - 20 -1244.452369962644 - 11 -3319.177986022085 - 21 -1244.452369962644 - 0 -LINE - 5 -6A1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.977986022132 - 20 -1244.752369962633 - 11 -3319.177986022085 - 21 -1244.752369962633 - 0 -LINE - 5 -6A2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.127986022038 - 20 -1243.552369962679 - 11 -3319.177986022085 - 21 -1243.552369962679 - 0 -LWPOLYLINE - 5 -6A3 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3317.077611776302 - 20 -1246.852369962667 - 10 -3317.077611776302 - 20 -1244.152369962656 - 0 -LWPOLYLINE - 5 -6A4 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3317.077611776302 - 20 -1243.852369962668 - 10 -3317.077611776302 - 20 -1243.552369962679 - 10 -3317.977986022132 - 20 -1243.552369962679 - 10 -3317.977986022132 - 20 -1245.052369962679 - 0 -LWPOLYLINE - 5 -6A5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3317.977986022132 - 20 -1245.152369962656 - 10 -3317.977986022132 - 20 -1245.652369962656 - 0 -LINE - 5 -6A6 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3317.047611776274 - 20 -1246.852369962667 - 11 -3317.047611776274 - 21 -1244.152369962656 - 0 -LINE - 5 -6A7 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3317.047611776274 - 20 -1243.852369962668 - 11 -3317.047611776274 - 21 -1243.522369962651 - 0 -LINE - 5 -6A8 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3317.047611776274 - 20 -1243.522369962651 - 11 -3318.00798602216 - 21 -1243.522369962651 - 0 -LINE - 5 -6A9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3318.00798602216 - 20 -1245.052369962679 - 11 -3318.00798602216 - 21 -1245.652369962656 - 0 -LINE - 5 -6AA -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3317.017611776479 - 20 -1246.852369962667 - 11 -3317.017611776479 - 21 -1244.152369962656 - 0 -LINE - 5 -6AB -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3317.017611776479 - 20 -1243.852369962668 - 11 -3317.017611776479 - 21 -1243.492369962681 - 0 -LINE - 5 -6AC -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3317.017611776479 - 20 -1243.492369962681 - 11 -3318.037986022189 - 21 -1243.492369962681 - 0 -LINE - 5 -6AD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3318.037986022189 - 20 -1245.052369962679 - 11 -3318.037986022189 - 21 -1245.652369962656 - 0 -LINE - 5 -6AE -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1246.852369962667 - 11 -3317.077611776302 - 21 -1244.752369962633 - 0 -LINE - 5 -6AF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3319.177986022085 - 20 -1244.752369962633 - 11 -3319.177986022085 - 21 -1245.052369962679 - 0 -LINE - 5 -6B0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1243.852369962668 - 11 -3315.877986022039 - 21 -1243.852369962668 - 0 -LINE - 5 -6B1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1243.552369962679 - 11 -3315.877986022039 - 21 -1243.552369962679 - 0 -LINE - 5 -6B2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1244.152369962656 - 11 -3315.877986022039 - 21 -1244.152369962656 - 0 -LINE - 5 -6B3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1244.452369962644 - 11 -3315.877986022039 - 21 -1244.452369962644 - 0 -LINE - 5 -6B4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1244.752369962633 - 11 -3315.877986022039 - 21 -1244.752369962633 - 0 -LINE - 5 -6B5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1245.052369962679 - 11 -3315.877986022039 - 21 -1245.052369962679 - 0 -LINE - 5 -6B6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1245.352369962667 - 11 -3315.877986022039 - 21 -1245.352369962667 - 0 -LINE - 5 -6B7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1245.652369962656 - 11 -3315.877986022039 - 21 -1245.652369962656 - 0 -LINE - 5 -6B8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1245.952369962644 - 11 -3315.877986022039 - 21 -1245.952369962644 - 0 -LINE - 5 -6B9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1246.252369962633 - 11 -3315.877986022039 - 21 -1246.252369962633 - 0 -LINE - 5 -6BA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1246.552369962679 - 11 -3315.877986022039 - 21 -1246.552369962679 - 0 -LINE - 5 -6BB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611776302 - 20 -1246.852369962667 - 11 -3315.877986022039 - 21 -1246.852369962667 - 0 -LINE - 5 -6BC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.977986022132 - 20 -1243.602689753345 - 11 -3317.977986022132 - 21 -1242.352369962667 - 0 -LINE - 5 -6BD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.677986022085 - 20 -1243.552369962679 - 11 -3317.677986022085 - 21 -1242.352369962667 - 0 -LINE - 5 -6BE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.37798602204 - 20 -1243.552369962679 - 11 -3317.37798602204 - 21 -1242.352369962667 - 0 -LINE - 5 -6BF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3327.11545639229 - 20 -1245.952385825629 - 11 -3327.34696792718 - 21 -1245.952369962644 - 0 -LWPOLYLINE - 5 -6C0 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3315.877986022039 - 20 -1242.352369962726 - 10 -3319.207986022113 - 20 -1242.352369962726 - 10 -3319.207986022113 - 20 -1242.722369962663 - 0 -LWPOLYLINE - 5 -6C1 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3315.877986022039 - 20 -1242.302369962737 - 10 -3319.257986022159 - 20 -1242.302369962737 - 10 -3319.257986022159 - 20 -1242.722369962663 - 0 -LWPOLYLINE - 5 -6C2 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3315.877986022039 - 20 -1242.252369962749 - 10 -3319.307986021974 - 20 -1242.252369962749 - 10 -3319.307986021974 - 20 -1242.722369962663 - 0 -LINE - 5 -6C3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.977986022112 - 20 -1245.652369964402 - 11 -3319.177986022065 - 21 -1245.652369964402 - 0 -LINE - 5 -6C4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.977986022132 - 20 -1245.352369962667 - 11 -3319.177986022085 - 21 -1245.352369962667 - 0 -LINE - 5 -6C5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.977986022132 - 20 -1245.652369962656 - 11 -3319.177986022085 - 21 -1245.652369962656 - 0 -LWPOLYLINE - 5 -6C6 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3323.885456392076 - 20 -1243.823737554077 - 10 -3327.345456392271 - 20 -1243.823737554077 - 10 -3327.345456392271 - 20 -1245.238323131343 - 0 -LWPOLYLINE - 5 -6C7 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3323.885456392076 - 20 -1243.873737554066 - 10 -3327.295456392225 - 20 -1243.873737554066 - 10 -3327.295456392225 - 20 -1245.238323131343 - 0 -LWPOLYLINE - 5 -6C8 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3323.885456392076 - 20 -1243.923737554054 - 10 -3327.245456392179 - 20 -1243.923737554054 - 10 -3327.245456392179 - 20 -1245.238323131343 - 0 -LWPOLYLINE - 5 -6C9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3327.34696792718 - 20 -1245.952369962644 - 10 -3327.345456392271 - 20 -1245.238323131343 - 10 -3327.11545639229 - 20 -1245.238323131343 - 10 -3327.11545639229 - 20 -1245.952385825629 - 0 -LINE - 5 -6CA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3319.406631975668 - 20 -1244.402369962656 - 11 -3319.406631975668 - 21 -1244.445176272304 - 0 -LINE - 5 -6CB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3319.406631975668 - 20 -1244.48176036129 - 11 -3319.406631975668 - 21 -1244.52456667088 - 0 -LINE - 5 -6CC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 52 -370 - 0 -100 -AcDbLine - 10 -3320.681631975574 - 20 -1244.402369962656 - 11 -3320.681631975574 - 21 -1243.472369962663 - 0 -LINE - 5 -6CD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3320.681631975574 - 20 -1244.552369962621 - 11 -3320.529808998806 - 21 -1244.552369962621 - 0 -LINE - 5 -6CE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3319.529808998807 - 20 -1244.552369962679 - 11 -3319.406631975668 - 21 -1244.552369962679 - 0 -LINE - 5 -6CF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3320.681631975574 - 20 -1244.752369962633 - 11 -3320.529808998806 - 21 -1244.752369962633 - 0 -LINE - 5 -6D0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3319.529808998807 - 20 -1244.752369962633 - 11 -3319.177986022085 - 21 -1244.752369962633 - 0 -LINE - 5 -6D1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3319.406631975668 - 20 -1244.402369962656 - 11 -3319.406631975668 - 21 -1244.445176272304 - 0 -LINE - 5 -6D2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3319.406631975668 - 20 -1244.48176036129 - 11 -3319.406631975668 - 21 -1244.52456667088 - 0 -LWPOLYLINE - 5 -6D3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 0 - 43 -0 - 10 -3320.681631975574 - 20 -1243.472369962663 - 10 -3320.681631975574 - 20 -1244.752369962633 - 10 -3320.881631975528 - 20 -1244.752369962633 - 10 -3321.031631975668 - 20 -1244.752369962633 - 10 -3321.031631975668 - 20 -1244.522369962651 - 10 -3320.881631975528 - 20 -1244.522369962651 - 10 -3320.881631975528 - 20 -1243.472369962663 - 10 -3320.681631975574 - 20 -1243.472369962663 - 0 -LINE - 5 -6D4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3319.177986022085 - 20 -1243.472369962663 - 11 -3319.177986022085 - 21 -1244.752369962633 - 0 -LINE - 5 -6D5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3319.377986022038 - 20 -1243.672369962675 - 11 -3319.377986022038 - 21 -1244.252369962632 - 0 -LWPOLYLINE - 5 -6D6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3319.37663197564 - 20 -1243.472369962663 - 10 -3319.177986022085 - 20 -1243.472369962663 - 10 -3319.177986022085 - 20 -1242.722369962663 - 10 -3319.177986022085 - 20 -1242.722369962663 - 0 -LINE - 5 -6D7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3319.529808998807 - 20 -1244.552369962679 - 11 -3319.529808998807 - 21 -1244.752369962633 - 0 -LINE - 5 -6D8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3320.529808998806 - 20 -1244.552369962621 - 11 -3320.529808998806 - 21 -1244.752369962633 - 0 -LWPOLYLINE - 5 -6D9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 1 - 43 -0 - 10 -3319.456631975481 - 20 -1244.502369962632 - 10 -3320.631631975528 - 20 -1244.502369962632 - 10 -3320.631631975528 - 20 -1242.972369962663 - 10 -3319.426631975686 - 20 -1242.972369962663 - 10 -3319.426631975686 - 20 -1244.202369962644 - 10 -3319.456631975481 - 20 -1244.202369962644 - 0 -LWPOLYLINE - 5 -6DA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 1 - 43 -0 - 10 -3319.506631975528 - 20 -1244.452369962644 - 10 -3320.581631975482 - 20 -1244.452369962644 - 10 -3320.581631975482 - 20 -1243.022369962651 - 10 -3319.4766319755 - 20 -1243.022369962651 - 10 -3319.4766319755 - 20 -1244.152369962656 - 10 -3319.506631975528 - 20 -1244.152369962656 - 0 -LINE - 5 -6DB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3319.406631975668 - 20 -1244.552369962679 - 11 -3320.581631975482 - 21 -1243.022369962651 - 0 -LINE - 5 -6DC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3320.681631975574 - 20 -1244.552369962679 - 11 -3319.37663197564 - 21 -1242.922369962616 - 0 -MTEXT - 5 -6DD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3319.684990863782 - 20 -1243.275681681291 - 30 -0 - 40 -0.21 - 41 -0.5133333333333333 - 71 - 1 - 72 - 5 - 1 -LIFT - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -6DE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3320.054133306723 - 20 -1243.303355389158 - 30 -0 - 40 -0.21 - 41 -1.026666666666706 - 71 - 1 - 72 - 5 - 1 -163X130 - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -LINE - 5 -6DF -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3319.176631975687 - 20 -1244.752369962633 - 11 -3319.177986022085 - 21 -1245.052369962679 - 0 -LWPOLYLINE - 5 -6E0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3319.37663197564 - 20 -1243.423737554054 - 10 -3319.37663197564 - 20 -1242.722369962663 - 10 -3319.177986022085 - 20 -1242.722369962663 - 10 -3319.177986022085 - 20 -1243.423737554054 - 0 -HATCH - 5 -6E1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3316.478019244037 - 20 -1243.852369962668 - 11 -3316.478239589138 - 21 -1243.552369962679 - 72 - 1 - 10 -3316.478239589138 - 20 -1243.552369962679 - 11 -3316.782158019022 - 21 -1243.552369962679 - 72 - 1 - 10 -3316.782158019022 - 20 -1243.552369962679 - 11 -3316.478019244037 - 21 -1243.852369962668 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -6E2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3316.478019244037 - 20 -1243.852369962668 - 11 -3316.193343820052 - 21 -1243.552369962679 - 72 - 1 - 10 -3316.193343820052 - 20 -1243.552369962679 - 11 -3316.478239589138 - 21 -1243.552369962679 - 72 - 1 - 10 -3316.478239589138 - 20 -1243.552369962679 - 11 -3316.478019244037 - 21 -1243.852369962668 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -6E3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3318.591678364434 - 20 -1246.567925359879 - 10 -3318.591678364434 - 20 -1243.552369962679 - 10 -3318.591678364434 - 20 -1242.922737527056 - 10 -3316.478702043416 - 20 -1242.922737527056 - 10 -3316.47779889917 - 20 -1244.152369962656 - 0 -LWPOLYLINE - 5 -6E4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3316.782158019022 - 20 -1243.552369962679 - 10 -3316.478019244037 - 20 -1243.852369962668 - 10 -3316.193343820052 - 20 -1243.552369962679 - 10 -3316.782158019022 - 20 -1243.552369962679 - 0 -LWPOLYLINE - 5 -6E5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3318.00798602216 - 20 -1243.522369962651 - 10 -3318.00798602216 - 20 -1245.402369962702 - 10 -3317.047611776274 - 20 -1245.402369962702 - 0 -LWPOLYLINE - 5 -6E6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3318.037986022189 - 20 -1243.492369962681 - 10 -3318.037986022189 - 20 -1245.452369962691 - 10 -3317.047611776274 - 20 -1245.452369962691 - 0 -LINE - 5 -6E7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3319.177986022085 - 20 -1245.052369962679 - 11 -3319.177986022085 - 21 -1245.652369962656 - 0 -LWPOLYLINE - 5 -6E8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3319.176631975687 - 20 -1244.752369962633 - 10 -3319.177986022085 - 20 -1245.052369962679 - 0 -LWPOLYLINE - 5 -6E9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3319.2266314663 - 20 -1244.752144290542 - 10 -3319.227985512699 - 20 -1245.05214429053 - 0 -LWPOLYLINE - 5 -6EA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3319.276630956912 - 20 -1244.751918618393 - 10 -3319.277985003544 - 20 -1245.051918618439 - 0 -LWPOLYLINE - 5 -6EB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3319.177986022085 - 20 -1245.052369962679 - 10 -3319.277985003544 - 20 -1245.051918618439 - 0 -LINE - 5 -6EC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1256.300104148744 - 11 -3316.62798602204 - 21 -1256.300104148744 - 0 -LINE - 5 -6ED -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1256.500104148697 - 11 -3316.62798602204 - 21 -1256.500104148697 - 0 -LINE - 5 -6EE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1256.700104148709 - 11 -3316.62798602204 - 21 -1256.700104148709 - 0 -LINE - 5 -6EF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1256.900104148721 - 11 -3316.62798602204 - 21 -1256.900104148721 - 0 -LINE - 5 -6F0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1257.100104148732 - 11 -3316.62798602204 - 21 -1257.100104148732 - 0 -LINE - 5 -6F1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1257.300104148744 - 11 -3316.62798602204 - 21 -1257.300104148744 - 0 -LINE - 5 -6F2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1257.500104148697 - 11 -3316.62798602204 - 21 -1257.500104148697 - 0 -LINE - 5 -6F3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1257.700104148709 - 11 -3316.62798602204 - 21 -1257.700104148709 - 0 -LINE - 5 -6F4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1257.900104148721 - 11 -3316.62798602204 - 21 -1257.900104148721 - 0 -LINE - 5 -6F5 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1258.100104148732 - 11 -3316.62798602204 - 21 -1258.100104148732 - 0 -LINE - 5 -6F6 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3315.877986022039 - 20 -1258.300104148744 - 11 -3316.62798602204 - 21 -1258.300104148744 - 0 -LWPOLYLINE - 5 -6F7 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3316.62798602204 - 20 -1258.300104148744 - 10 -3316.62798602204 - 20 -1258.100104148732 - 0 -LWPOLYLINE - 5 -6F8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3316.62798602204 - 20 -1257.900104148721 - 10 -3316.62798602204 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -6F9 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3316.727986022132 - 20 -1258.300104148744 - 10 -3316.727986022132 - 20 -1256.300104148744 - 0 -LINE - 5 -6FA -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1256.300104148744 - 11 -3317.477986022132 - 21 -1256.300104148744 - 0 -LINE - 5 -6FB -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1256.500104148697 - 11 -3317.477986022132 - 21 -1256.500104148697 - 0 -LINE - 5 -6FC -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1256.700104148709 - 11 -3317.477986022132 - 21 -1256.700104148709 - 0 -LINE - 5 -6FD -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1256.900104148721 - 11 -3317.477986022132 - 21 -1256.900104148721 - 0 -LINE - 5 -6FE -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1257.100104148732 - 11 -3317.477986022132 - 21 -1257.100104148732 - 0 -LINE - 5 -6FF -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1257.300104148744 - 11 -3317.477986022132 - 21 -1257.300104148744 - 0 -LINE - 5 -700 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1257.500104148697 - 11 -3317.477986022132 - 21 -1257.500104148697 - 0 -LINE - 5 -701 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1257.700104148709 - 11 -3317.477986022132 - 21 -1257.700104148709 - 0 -LINE - 5 -702 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1257.900104148721 - 11 -3317.477986022132 - 21 -1257.900104148721 - 0 -LINE - 5 -703 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1258.100104148732 - 11 -3317.477986022132 - 21 -1258.100104148732 - 0 -LINE - 5 -704 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.727986022132 - 20 -1258.300104148744 - 11 -3317.477986022132 - 21 -1258.300104148744 - 0 -LWPOLYLINE - 5 -705 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3316.62798602204 - 20 -1256.300104148744 - 10 -3316.62798602204 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -706 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3316.62798602204 - 20 -1258.100104148732 - 10 -3316.62798602204 - 20 -1258.300104148744 - 10 -3316.727986022132 - 20 -1258.300104148744 - 10 -3316.727986022132 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -707 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3316.59798602201 - 20 -1256.300104148744 - 10 -3316.59798602201 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -708 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3316.59798602201 - 20 -1258.100104148732 - 10 -3316.59798602201 - 20 -1258.330104148714 - 10 -3316.757986022159 - 20 -1258.330104148714 - 10 -3316.757986022159 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -709 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3316.567986021983 - 20 -1256.300104148744 - 10 -3316.567986021983 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -70A -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3316.567986021983 - 20 -1258.100104148732 - 10 -3316.567986021983 - 20 -1258.360104148741 - 10 -3316.787986022188 - 20 -1258.360104148741 - 10 -3316.787986022188 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -70B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3315.647986022057 - 20 -1256.050104161259 - 10 -3315.647986019496 - 20 -1259.280104146979 - 10 -3317.477986017709 - 20 -1259.280104146979 - 0 -LWPOLYLINE - 5 -70C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3315.697986022104 - 20 -1256.050104161259 - 10 -3315.697986022104 - 20 -1259.230104148737 - 10 -3317.477986022132 - 20 -1259.230104148737 - 0 -LWPOLYLINE - 5 -70D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3315.74798602215 - 20 -1256.050104161259 - 10 -3315.74798602215 - 20 -1259.180104148749 - 10 -3317.477986022132 - 20 -1259.180104148749 - 0 -LWPOLYLINE - 5 -70E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3315.877986022039 - 20 -1256.050104161259 - 10 -3315.877986022039 - 20 -1259.050104148744 - 10 -3317.477986022132 - 20 -1259.050104148744 - 0 -LINE - 5 -70F -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3324.115456392291 - 20 -1243.423737554054 - 11 -3319.37663197564 - 21 -1242.722369962663 - 0 -LINE - 5 -710 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3324.108135909075 - 20 -1243.473198756284 - 11 -3319.369311492425 - 21 -1242.771831164893 - 0 -LINE - 5 -711 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3324.10081542586 - 20 -1243.522659958515 - 11 -3319.36199100921 - 21 -1242.821292367123 - 0 -LINE - 5 -712 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3320.881631975528 - 20 -1243.423737554054 - 11 -3320.881631975528 - 21 -1243.04620614968 - 0 -LINE - 5 -713 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3320.831631975482 - 20 -1243.423737554054 - 11 -3320.831631975482 - 21 -1243.04620614968 - 0 -LINE - 5 -714 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3320.781631975668 - 20 -1243.423737554054 - 11 -3320.781631975668 - 21 -1243.04620614968 - 0 -LINE - 5 -715 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3320.681631975574 - 20 -1243.423737554054 - 11 -3320.681631975574 - 21 -1243.016605238954 - 0 -LINE - 5 -716 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3316.35612156475 - 20 -1240.067414091609 - 11 -3316.35612156475 - 21 -1260.721494616649 - 0 -CIRCLE - 5 -717 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbCircle - 10 -3316.35612156475 - 20 -1241.147899744741 - 40 -0.3105759447062155 - 0 -HATCH - 5 -718 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3316.666697507491 - 20 -1241.147899743053 - 11 -3316.356121562887 - 21 -1241.458475687716 - 72 - 1 - 10 -3316.356121562887 - 20 -1241.458475687716 - 11 -3316.356121562887 - 21 -1240.837323798332 - 72 - 1 - 10 -3316.356121562887 - 20 -1240.837323798332 - 11 -3316.666697507491 - 21 -1241.147899743053 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -719 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3316.35612156475 - 20 -1240.837323808751 - 10 -3316.666697504465 - 20 -1241.147899744741 - 10 -3316.35612156475 - 20 -1241.458475688181 - 10 -3316.35612156475 - 20 -1240.837323808751 - 0 -MTEXT - 5 -71A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3316.642088649562 - 20 -1241.193436495552 - 30 -0 - 40 -0.4900000000000003 - 41 -0.3266666666666669 - 71 - 1 - 72 - 5 - 1 -A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -CIRCLE - 5 -71B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbCircle - 10 -3316.35612156475 - 20 -1260.305064083717 - 40 -0.3105759447062155 - 0 -HATCH - 5 -71C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3316.666697507491 - 20 -1260.305064084648 - 11 -3316.356121562887 - 21 -1260.615640029369 - 72 - 1 - 10 -3316.356121562887 - 20 -1260.615640029369 - 11 -3316.356121562887 - 21 -1259.994488139928 - 72 - 1 - 10 -3316.356121562887 - 20 -1259.994488139928 - 11 -3316.666697507491 - 21 -1260.305064084648 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -71D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3316.35612156475 - 20 -1259.994488155178 - 10 -3316.666697500739 - 20 -1260.305064079934 - 10 -3316.35612156475 - 20 -1260.615640027157 - 10 -3316.35612156475 - 20 -1259.994488155178 - 0 -MTEXT - 5 -71E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3316.642088649562 - 20 -1260.350600837148 - 30 -0 - 40 -0.4900000000000003 - 41 -0.3266666666666669 - 71 - 1 - 72 - 5 - 1 -A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -71F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3317.477986022132 - 20 -1259.280104148725 - 10 -3317.627986022039 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -720 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3318.827986021992 - 20 -1259.280104148725 - 10 -3319.62798602204 - 20 -1259.280104148725 - 0 -LINE - 5 -721 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3318.827986021992 - 20 -1259.050104148744 - 11 -3319.62798602204 - 21 -1259.050104148744 - 0 -LWPOLYLINE - 5 -722 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3317.477986022132 - 20 -1259.280104148725 - 10 -3317.627986022039 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -723 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3317.477986022132 - 20 -1259.050104148744 - 10 -3317.477986022132 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -724 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3317.477986022132 - 20 -1255.998735667439 - 10 -3317.477986022132 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -725 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3317.627986022039 - 20 -1256.048921864945 - 10 -3317.627986022039 - 20 -1259.050104148744 - 0 -LWPOLYLINE - 5 -726 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3317.627986022039 - 20 -1257.550104148744 - 10 -3317.928084941348 - 20 -1257.550104148744 - 0 -LWPOLYLINE - 5 -727 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3317.627986022039 - 20 -1257.550104148744 - 10 -3318.677994891537 - 20 -1257.550104148744 - 0 -LWPOLYLINE - 5 -728 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3319.577986021992 - 20 -1257.550104148744 - 10 -3319.577986021992 - 20 -1259.050104148744 - 0 -LWPOLYLINE - 5 -729 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3317.627986022039 - 20 -1257.500104148697 - 10 -3318.677986022784 - 20 -1257.500104148697 - 0 -LWPOLYLINE - 5 -72A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3319.577986021992 - 20 -1257.500104148697 - 10 -3319.62798602204 - 20 -1257.500104148697 - 10 -3319.62798602204 - 20 -1259.050104148744 - 0 -LINE - 5 -72B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3320.793525724673 - 20 -1256.048360379122 - 11 -3320.793525724673 - 21 -1259.050104148744 - 0 -LINE - 5 -72C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3320.693525724812 - 20 -1256.048360379122 - 11 -3320.693525724812 - 21 -1259.050104148744 - 0 -LWPOLYLINE - 5 -72D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3320.427986020688 - 20 -1257.500104145787 - 10 -3320.693525726441 - 20 -1257.500104145787 - 0 -LWPOLYLINE - 5 -72E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3320.427986022085 - 20 -1257.550104148744 - 10 -3320.693525724812 - 20 -1257.550104148744 - 0 -LWPOLYLINE - 5 -72F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3318.627728586318 - 20 -1256.048735667427 - 10 -3317.627986055101 - 20 -1256.048921864945 - 0 -LWPOLYLINE - 5 -730 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3318.627728586318 - 20 -1256.048735667427 - 10 -3318.627728586318 - 20 -1256.048735667427 - 10 -3317.627986022039 - 20 -1256.048735667427 - 0 -LWPOLYLINE - 5 -731 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3318.677994891537 - 20 -1257.550104148744 - 10 -3318.677986022784 - 20 -1257.500104148697 - 0 -LWPOLYLINE - 5 -732 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3318.677844123217 - 20 -1256.700104148709 - 10 -3318.677719718543 - 20 -1255.998735667439 - 10 -3317.627986022039 - 20 -1255.998735667439 - 0 -LWPOLYLINE - 5 -733 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3317.627986022039 - 20 -1259.050104148744 - 10 -3317.627986022039 - 20 -1255.998735667439 - 10 -3317.477986022132 - 20 -1255.998735667439 - 0 -LINE - 5 -734 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3319.577728587203 - 20 -1255.998735667439 - 11 -3320.563335953281 - 21 -1255.998735667439 - 0 -LINE - 5 -735 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3319.577728587203 - 20 -1256.048735667427 - 11 -3320.563335953281 - 21 -1256.048735667427 - 0 -LINE - 5 -736 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3319.577986021992 - 20 -1257.550104148744 - 11 -3319.577986021992 - 21 -1257.500104148697 - 0 -LINE - 5 -737 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3318.677994891537 - 20 -1257.550104148744 - 11 -3319.577986021992 - 21 -1257.550104148744 - 0 -LINE - 5 -738 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3318.677728587296 - 20 -1256.048735667427 - 11 -3318.677728587296 - 21 -1255.998735667439 - 0 -LINE - 5 -739 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3319.577728587203 - 20 -1256.048735667427 - 11 -3319.577728587203 - 21 -1255.998735667439 - 0 -LINE - 5 -73A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3318.627728586318 - 20 -1256.048735667427 - 11 -3318.62770615262 - 21 -1256.048735667427 - 0 -LINE - 5 -73B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3318.627986022038 - 20 -1257.500104148697 - 11 -3318.677986022784 - 21 -1257.500104148697 - 0 -LINE - 5 -73C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3318.627986022038 - 20 -1256.700104148709 - 11 -3318.677986022784 - 21 -1256.700104148709 - 0 -LINE - 5 -73D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3318.627986022038 - 20 -1256.700104148709 - 11 -3318.627688484499 - 21 -1256.048735667427 - 0 -LINE - 5 -73E -100 -AcDbEntity - 8 -BLK_1_FLR_1_WATER_CLOSET - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbLine - 10 -3318.627986022038 - 20 -1256.700104148709 - 11 -3318.627986022038 - 21 -1257.500104148697 - 0 -LINE - 5 -73F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3319.62798602204 - 20 -1257.550104148744 - 11 -3319.62798602204 - 21 -1257.500104148697 - 0 -LINE - 5 -740 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3320.427986020688 - 20 -1257.550104146532 - 11 -3320.427986020688 - 21 -1257.500104145787 - 0 -LINE - 5 -741 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3320.427986022085 - 20 -1257.550104148744 - 11 -3319.62798602204 - 21 -1257.550104148744 - 0 -INSERT - 5 -742 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -tre - 10 -1806.60502493917 - 20 -1356.923699999461 - 30 -0 - 41 --0.0059048999998235 - 42 -0.0059048999997322 - 43 -0 - 50 -179.9911266057404 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -743 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbBlockReference - 2 -15 - 10 -4079.611202365717 - 20 -8221.425826757622 - 30 -0 - 41 -0.0094866649972689 - 42 -0.0094866649972689 - 43 -0 - 50 -89.99112660048513 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -MTEXT - 5 -744 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3318.640559916152 - 20 -1256.994305585045 - 30 -0 - 40 -0.22 - 41 -1.381111111111138 - 71 - 1 - 72 - 5 - 1 -\pt308;D2 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -89.9911266023461 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -745 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3317.903847595444 - 20 -1256.633173740993 - 30 -0 - 40 -0.18 - 41 -1.250000000000011 - 71 - 1 - 72 - 5 - 1 -\pt2.52;WC\P1.45X1.00 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -89.9911266023461 - 73 - 1 - 44 -1 - 0 -INSERT - 5 -746 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -tre - 10 -3420.530435148859 - 20 -2770.100082705671 - 30 -0 - 41 --0.0059048999998235 - 42 -0.0059048999997322 - 43 -0 - 50 -89.9911266057404 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -747 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbBlockReference - 2 -15 - 10 --4418.085500324377 - 20 -412.0207373641314 - 30 -0 - 41 --0.0105407388858543 - 42 -0.0105407388858543 - 43 -0 - 50 -0.0088733995148438 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -MTEXT - 5 -748 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3319.860068043229 - 20 -1257.331142450508 - 30 -0 - 40 -0.22 - 41 -1.381111111111138 - 71 - 1 - 72 - 5 - 1 -\pt308;D2 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -89.9911266023461 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -749 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3319.033639878966 - 20 -1257.379249563906 - 30 -0 - 40 -0.22 - 41 -1.454444444444486 - 71 - 1 - 72 - 5 - 1 -\pt3.08;D3 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -89.9911266023461 - 73 - 1 - 44 -1 - 0 -LINE - 5 -74A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3319.62798602204 - 20 -1259.050104148744 - 11 -3319.62798602204 - 21 -1259.280104148725 - 0 -LINE - 5 -74B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3317.627986022039 - 20 -1259.050104148744 - 11 -3317.627986022039 - 21 -1259.280104148725 - 0 -LINE - 5 -74C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3318.827986021992 - 20 -1259.050104148744 - 11 -3318.827986021992 - 21 -1259.280104148725 - 0 -LINE - 5 -74D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3319.62798602204 - 20 -1259.280104148725 - 11 -3320.561631975464 - 21 -1259.280104148725 - 0 -LINE - 5 -74E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3319.62798602204 - 20 -1259.230104148737 - 11 -3320.561631975464 - 21 -1259.230104148737 - 0 -LINE - 5 -74F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3319.62798602204 - 20 -1259.180104148749 - 11 -3320.561631975464 - 21 -1259.180104148749 - 0 -LINE - 5 -750 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3319.62798602204 - 20 -1259.050104148744 - 11 -3320.561631975464 - 21 -1259.050104148744 - 0 -LINE - 5 -751 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3317.627986022039 - 20 -1259.280104148725 - 11 -3318.827986021992 - 21 -1259.280104148725 - 0 -LINE - 5 -752 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3317.627986022039 - 20 -1259.230104148737 - 11 -3318.827986021992 - 21 -1259.230104148737 - 0 -LINE - 5 -753 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3317.627986022039 - 20 -1259.180104148749 - 11 -3318.827986021992 - 21 -1259.180104148749 - 0 -LINE - 5 -754 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3317.627986022039 - 20 -1259.050104148744 - 11 -3318.827986021992 - 21 -1259.050104148744 - 0 -MTEXT - 5 -755 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3319.722613572841 - 20 -1258.560485614987 - 30 -0 - 40 -0.18 - 41 -1.190000000000011 - 71 - 1 - 72 - 5 - 1 -\pt252;WC\P1.06X1.50 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 --0.008873397653922366 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -756 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3318.979066837812 - 20 -1256.012902952148 - 30 -0 - 40 -0.22 - 41 -1.33222222222225 - 71 - 1 - 72 - 5 - 1 -\pt308;D1 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -89.9911266023461 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -757 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3321.061631975464 - 20 -1259.280104148725 - 10 -3327.345456392271 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -758 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3321.061631975464 - 20 -1259.050104148744 - 10 -3327.345456392271 - 20 -1259.050104148744 - 0 -LWPOLYLINE - 5 -759 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3300.249476718251 - 20 -1257.700104148767 - 10 -3300.249476718251 - 20 -1258.743019191257 - 10 -3299.417575473432 - 20 -1258.743019191257 - 10 -3299.417575473432 - 20 -1255.706959677569 - 0 -MTEXT - 5 -75A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3299.317210980691 - 20 -1255.661184545897 - 30 -0 - 40 -0.21 - 41 -0.3033333333333333 - 71 - 1 - 72 - 5 - 1 -UP - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.448289551288331 - 73 - 1 - 44 -1 - 0 -HATCH - 5 -75B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3300.249697062187 - 20 -1257.400104148721 - 11 -3300.249917407054 - 21 -1257.700104148709 - 72 - 1 - 10 -3300.249917407054 - 20 -1257.700104148709 - 11 -3300.553835836938 - 21 -1257.700104148709 - 72 - 1 - 10 -3300.553835836938 - 20 -1257.700104148709 - 11 -3300.249697062187 - 21 -1257.400104148721 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -75C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3300.249697062187 - 20 -1257.400104148721 - 11 -3299.965021637967 - 21 -1257.700104148709 - 72 - 1 - 10 -3299.965021637967 - 20 -1257.700104148709 - 11 -3300.249917407054 - 21 -1257.700104148709 - 72 - 1 - 10 -3300.249917407054 - 20 -1257.700104148709 - 11 -3300.249697062187 - 21 -1257.400104148721 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -75D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3300.553835836938 - 20 -1257.700104148709 - 10 -3300.249697062187 - 20 -1257.400104148721 - 10 -3299.965021634939 - 20 -1257.700104148767 - 10 -3300.553835841363 - 20 -1257.700104148767 - 0 -LWPOLYLINE - 5 -75E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3317.106018910652 - 20 -1255.499554888986 - 10 -3317.106018910652 - 20 -1258.78581493505 - 10 -3316.287334638182 - 20 -1258.78581493505 - 10 -3316.287334638182 - 20 -1257.815531460277 - 0 -LWPOLYLINE - 5 -75F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3316.252986023668 - 20 -1257.300104146532 - 10 -3316.252986023668 - 20 -1255.703955704055 - 0 -MTEXT - 5 -760 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3305.629815684167 - 20 -1241.424159487244 - 30 -0 - 40 -0.21 - 41 -0.3033333333333333 - 71 - 1 - 72 - 5 - 1 -UP - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.448289551288331 - 73 - 1 - 44 -1 - 0 -LINE - 5 -761 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3353.688675249461 - 20 -1259.280104150704 - 11 -3353.918675253634 - 21 -1259.280104150704 - 0 -LINE - 5 -762 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3363.556145619601 - 20 -1249.360104148742 - 11 -3363.556145619601 - 21 -1245.952385825629 - 0 -LINE - 5 -763 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3351.85867524962 - 20 -1243.321229862398 - 11 -3351.85867524962 - 21 -1256.050104161259 - 0 -LINE - 5 -764 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1243.321229862398 - 11 -3352.088675249601 - 21 -1256.050104161259 - 0 -LINE - 5 -765 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3363.32614561962 - 20 -1249.590104148723 - 11 -3363.32614561962 - 21 -1245.952385825629 - 0 -LINE - 5 -766 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1242.252369962691 - 11 -3355.368675249629 - 21 -1242.252369962691 - 0 -LWPOLYLINE - 5 -767 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3351.85867524962 - 20 -1243.321229862398 - 10 -3351.85867524962 - 20 -1241.721707735967 - 10 -3351.85867524962 - 20 -1241.721707735967 - 10 -3352.088675249601 - 20 -1241.721707735967 - 10 -3352.088675249601 - 20 -1243.321229862398 - 0 -LWPOLYLINE - 5 -768 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3360.32614561962 - 20 -1243.923737554054 - 10 -3360.32614561962 - 20 -1242.900966822169 - 10 -3360.32614561962 - 20 -1241.721707735967 - 10 -3352.088675249601 - 20 -1241.721707735967 - 0 -LWPOLYLINE - 5 -769 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3353.688675249461 - 20 -1259.280104150704 - 10 -3353.918675253634 - 20 -1259.280104150704 - 0 -LINE - 5 -76A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288675249554 - 20 -1243.552369962679 - 11 -3353.288675249554 - 21 -1242.352369962667 - 0 -LINE - 5 -76B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1243.852369962668 - 11 -3355.388675249648 - 21 -1243.852369962668 - 0 -LINE - 5 -76C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1244.152369962656 - 11 -3355.388675249648 - 21 -1244.152369962656 - 0 -LINE - 5 -76D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1244.452369962644 - 11 -3355.388675249648 - 21 -1244.452369962644 - 0 -LINE - 5 -76E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1244.752369962691 - 11 -3355.388675249648 - 21 -1244.752369962691 - 0 -LINE - 5 -76F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.338675249601 - 20 -1243.552369962679 - 11 -3355.388675249648 - 21 -1243.552369962679 - 0 -LWPOLYLINE - 5 -770 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3353.288301003864 - 20 -1246.252369962691 - 10 -3353.288301003864 - 20 -1244.152369962656 - 0 -LWPOLYLINE - 5 -771 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3353.288301003864 - 20 -1243.852369962668 - 10 -3353.288301003864 - 20 -1243.552369962679 - 10 -3354.188675249461 - 20 -1243.552369962679 - 10 -3354.188675249461 - 20 -1245.052369962679 - 0 -LWPOLYLINE - 5 -772 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3354.188675249461 - 20 -1245.152369962656 - 10 -3354.188675249461 - 20 -1245.652369962656 - 0 -LINE - 5 -773 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3353.258301003836 - 20 -1246.252369962691 - 11 -3353.258301003836 - 21 -1244.152369962656 - 0 -LINE - 5 -774 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3353.258301003836 - 20 -1243.852369962668 - 11 -3353.258301003836 - 21 -1243.522369962651 - 0 -LINE - 5 -775 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3353.258301003836 - 20 -1243.522369962651 - 11 -3354.21867524949 - 21 -1243.522369962651 - 0 -LINE - 5 -776 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.21867524949 - 20 -1245.052369962679 - 11 -3354.21867524949 - 21 -1245.652369962656 - 0 -LINE - 5 -777 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3353.228301003809 - 20 -1246.252369962691 - 11 -3353.228301003809 - 21 -1244.152369962656 - 0 -LINE - 5 -778 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3353.228301003809 - 20 -1243.852369962668 - 11 -3353.228301003809 - 21 -1243.492369962681 - 0 -LINE - 5 -779 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3353.228301003809 - 20 -1243.492369962681 - 11 -3354.248675249517 - 21 -1243.492369962681 - 0 -LINE - 5 -77A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.248675249517 - 20 -1245.052369962679 - 11 -3354.248675249517 - 21 -1245.652369962656 - 0 -LINE - 5 -77B -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1246.252369962691 - 11 -3353.288301003864 - 21 -1244.752369962691 - 0 -LINE - 5 -77C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3355.388675249648 - 20 -1244.752369962691 - 11 -3355.388675249648 - 21 -1245.052369962679 - 0 -LINE - 5 -77D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1243.852369962668 - 11 -3352.088675249601 - 21 -1243.852369962668 - 0 -LINE - 5 -77E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1243.552369962679 - 11 -3352.088675249601 - 21 -1243.552369962679 - 0 -LINE - 5 -77F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1244.152369962656 - 11 -3352.088675249601 - 21 -1244.152369962656 - 0 -LINE - 5 -780 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1244.452369962644 - 11 -3352.088675249601 - 21 -1244.452369962644 - 0 -LINE - 5 -781 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1244.752369962691 - 11 -3352.088675249601 - 21 -1244.752369962691 - 0 -LINE - 5 -782 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1245.052369962679 - 11 -3352.088675249601 - 21 -1245.052369962679 - 0 -LINE - 5 -783 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1245.352369962667 - 11 -3352.088675249601 - 21 -1245.352369962667 - 0 -LINE - 5 -784 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1245.652369962656 - 11 -3352.088675249601 - 21 -1245.652369962656 - 0 -LINE - 5 -785 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1245.952369962644 - 11 -3352.088675249601 - 21 -1245.952369962644 - 0 -LINE - 5 -786 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1246.252369962691 - 11 -3352.088675249601 - 21 -1246.252369962691 - 0 -LINE - 5 -787 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1243.602689753345 - 11 -3354.188675249461 - 21 -1242.352369962667 - 0 -LINE - 5 -788 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.888675249648 - 20 -1243.552369962679 - 11 -3353.888675249648 - 21 -1242.352369962667 - 0 -LINE - 5 -789 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.588675249601 - 20 -1243.552369962679 - 11 -3353.588675249601 - 21 -1242.352369962667 - 0 -LINE - 5 -78A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3363.32614561962 - 20 -1245.952385825629 - 11 -3363.55765715451 - 21 -1245.952369962644 - 0 -LWPOLYLINE - 5 -78B -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3352.088675249601 - 20 -1242.352369962726 - 10 -3355.418675249442 - 20 -1242.352369962726 - 10 -3355.418675249442 - 20 -1242.722369962663 - 0 -LWPOLYLINE - 5 -78C -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3352.088675249601 - 20 -1242.302369962737 - 10 -3355.468675249489 - 20 -1242.302369962737 - 10 -3355.468675249489 - 20 -1242.722369962663 - 0 -LWPOLYLINE - 5 -78D -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3352.088675249601 - 20 -1242.252369962749 - 10 -3355.518675249536 - 20 -1242.252369962749 - 10 -3355.518675249536 - 20 -1242.722369962663 - 0 -LINE - 5 -78E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1245.052369962679 - 11 -3355.388675249648 - 21 -1245.052369962679 - 0 -LINE - 5 -78F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1245.352369962667 - 11 -3355.388675249648 - 21 -1245.352369962667 - 0 -LINE - 5 -790 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1245.652369962656 - 11 -3355.388675249648 - 21 -1245.652369962656 - 0 -HATCH - 5 -791 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANGLE - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 13 - 72 - 1 - 10 -3363.456145619741 - 20 -1245.238323131401 - 11 -3363.32614561962 - 21 -1245.238323131401 - 72 - 1 - 10 -3363.32614561962 - 20 -1245.238323131401 - 11 -3363.32614561962 - 21 -1245.952802684624 - 72 - 1 - 10 -3363.32614561962 - 20 -1245.952802684624 - 11 -3362.667689515511 - 21 -1245.952802684624 - 72 - 1 - 10 -3362.667689515511 - 20 -1245.952802684624 - 11 -3357.09232120309 - 21 -1245.952802684624 - 72 - 1 - 10 -3357.09232120309 - 20 -1245.952802684624 - 11 -3357.09232120309 - 21 -1245.052802684659 - 72 - 1 - 10 -3357.09232120309 - 20 -1245.052802684659 - 11 -3357.09232120309 - 21 -1244.522369962651 - 72 - 1 - 10 -3357.09232120309 - 20 -1244.522369962651 - 11 -3357.09232120309 - 21 -1243.472369962663 - 72 - 1 - 10 -3357.09232120309 - 20 -1243.472369962663 - 11 -3357.09232120309 - 21 -1243.04620614968 - 72 - 1 - 10 -3357.09232120309 - 20 -1243.04620614968 - 11 -3360.096145619638 - 21 -1243.490785840957 - 72 - 1 - 10 -3360.096145619638 - 20 -1243.490785840957 - 11 -3360.096145619638 - 21 -1243.923737554054 - 72 - 1 - 10 -3360.096145619638 - 20 -1243.923737554054 - 11 -3360.32614561962 - 21 -1243.923737554054 - 72 - 1 - 10 -3360.32614561962 - 20 -1243.923737554054 - 11 -3363.456145619741 - 21 -1243.923737554054 - 72 - 1 - 10 -3363.456145619741 - 20 -1243.923737554054 - 11 -3363.456145619741 - 21 -1245.238323131401 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -1.5 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -HATCH - 5 -792 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3355.617321202998 - 20 -1244.252369962691 - 11 -3355.617321202998 - 21 -1244.752369962691 - 72 - 1 - 10 -3355.617321202998 - 20 -1244.752369962691 - 11 -3355.387321203016 - 21 -1244.752369962691 - 72 - 1 - 10 -3355.387321203016 - 20 -1244.752369962691 - 11 -3355.387321203016 - 21 -1244.252369962691 - 72 - 1 - 10 -3355.387321203016 - 20 -1244.252369962691 - 11 -3355.617321202998 - 21 -1244.252369962691 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -793 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3355.387321203016 - 20 -1244.752369962691 - 10 -3355.617321202998 - 20 -1244.752369962691 - 10 -3355.617321202998 - 20 -1244.252369962691 - 10 -3355.387321203016 - 20 -1244.252369962691 - 10 -3355.387321203016 - 20 -1244.752369962691 - 0 -HATCH - 5 -794 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3352.088675249601 - 20 -1258.780104148725 - 11 -3352.088675249601 - 21 -1259.280104148725 - 72 - 1 - 10 -3352.088675249601 - 20 -1259.280104148725 - 11 -3351.85867524962 - 21 -1259.280104148725 - 72 - 1 - 10 -3351.85867524962 - 20 -1259.280104148725 - 11 -3351.85867524962 - 21 -1258.780104148725 - 72 - 1 - 10 -3351.85867524962 - 20 -1258.780104148725 - 11 -3352.088675249601 - 21 -1258.780104148725 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -795 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3351.85867524962 - 20 -1259.280104148725 - 10 -3352.088675249601 - 20 -1259.280104148725 - 10 -3352.088675249601 - 20 -1258.780104148725 - 10 -3351.85867524962 - 20 -1258.780104148725 - 10 -3351.85867524962 - 20 -1259.280104148725 - 0 -HATCH - 5 -796 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 5 - 72 - 1 - 10 -3355.58732120297 - 20 -1243.623737554066 - 11 -3355.58732120297 - 21 -1243.653737554094 - 72 - 1 - 10 -3355.58732120297 - 20 -1243.653737554094 - 11 -3355.387321203016 - 21 -1243.653737554094 - 72 - 1 - 10 -3355.387321203016 - 20 -1243.653737554094 - 11 -3355.387321203016 - 21 -1243.423737554112 - 72 - 1 - 10 -3355.387321203016 - 20 -1243.423737554112 - 11 -3355.58732120297 - 21 -1243.423737554112 - 72 - 1 - 10 -3355.58732120297 - 20 -1243.423737554112 - 11 -3355.58732120297 - 21 -1243.623737554066 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -797 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3355.58732120297 - 20 -1243.623737554066 - 10 -3355.58732120297 - 20 -1243.423737554112 - 10 -3355.387321203016 - 20 -1243.423737554112 - 10 -3355.387321203016 - 20 -1243.653737554094 - 10 -3355.58732120297 - 20 -1243.653737554094 - 10 -3355.58732120297 - 20 -1243.623737554066 - 0 -HATCH - 5 -798 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 5 - 72 - 1 - 10 -3357.09232120309 - 20 -1243.623737554066 - 11 -3357.09232120309 - 21 -1243.653737554094 - 72 - 1 - 10 -3357.09232120309 - 20 -1243.653737554094 - 11 -3356.892321203137 - 21 -1243.653737554094 - 72 - 1 - 10 -3356.892321203137 - 20 -1243.653737554094 - 11 -3356.892321203137 - 21 -1243.423737554054 - 72 - 1 - 10 -3356.892321203137 - 20 -1243.423737554054 - 11 -3357.09232120309 - 21 -1243.423737554054 - 72 - 1 - 10 -3357.09232120309 - 20 -1243.423737554054 - 11 -3357.09232120309 - 21 -1243.623737554066 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -799 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3357.09232120309 - 20 -1243.623737554066 - 10 -3357.09232120309 - 20 -1243.423737554054 - 10 -3356.892321203137 - 20 -1243.423737554054 - 10 -3356.892321203137 - 20 -1243.653737554094 - 10 -3357.09232120309 - 20 -1243.653737554094 - 10 -3357.09232120309 - 20 -1243.623737554066 - 0 -HATCH - 5 -79A -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3352.358675249619 - 20 -1252.820104148704 - 11 -3351.85867524962 - 21 -1252.820104148704 - 72 - 1 - 10 -3351.85867524962 - 20 -1252.820104148704 - 11 -3351.85867524962 - 21 -1252.590104148723 - 72 - 1 - 10 -3351.85867524962 - 20 -1252.590104148723 - 11 -3352.358675249619 - 21 -1252.590104148723 - 72 - 1 - 10 -3352.358675249619 - 20 -1252.590104148723 - 11 -3352.358675249619 - 21 -1252.820104148704 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -79B -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3351.85867524962 - 20 -1252.590104148723 - 10 -3351.85867524962 - 20 -1252.820104148704 - 10 -3352.358675249619 - 20 -1252.820104148704 - 10 -3352.358675249619 - 20 -1252.590104148723 - 10 -3351.85867524962 - 20 -1252.590104148723 - 0 -HATCH - 5 -79C -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3351.85867524962 - 20 -1246.452369962644 - 11 -3351.85867524962 - 21 -1245.952369962644 - 72 - 1 - 10 -3351.85867524962 - 20 -1245.952369962644 - 11 -3352.088675249601 - 21 -1245.952369962644 - 72 - 1 - 10 -3352.088675249601 - 20 -1245.952369962644 - 11 -3352.088675249601 - 21 -1246.452369962644 - 72 - 1 - 10 -3352.088675249601 - 20 -1246.452369962644 - 11 -3351.85867524962 - 21 -1246.452369962644 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -79D -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3352.088675249601 - 20 -1245.952369962644 - 10 -3351.85867524962 - 20 -1245.952369962644 - 10 -3351.85867524962 - 20 -1246.452369962644 - 10 -3352.088675249601 - 20 -1246.452369962644 - 10 -3352.088675249601 - 20 -1245.952369962644 - 0 -HATCH - 5 -79E -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3363.32614561962 - 20 -1246.452369962644 - 11 -3363.32614561962 - 21 -1245.952369962644 - 72 - 1 - 10 -3363.32614561962 - 20 -1245.952369962644 - 11 -3363.556145619601 - 21 -1245.952369962644 - 72 - 1 - 10 -3363.556145619601 - 20 -1245.952369962644 - 11 -3363.556145619601 - 21 -1246.452369962644 - 72 - 1 - 10 -3363.556145619601 - 20 -1246.452369962644 - 11 -3363.32614561962 - 21 -1246.452369962644 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -79F -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3363.556145619601 - 20 -1245.952369962644 - 10 -3363.32614561962 - 20 -1245.952369962644 - 10 -3363.32614561962 - 20 -1246.452369962644 - 10 -3363.556145619601 - 20 -1246.452369962644 - 10 -3363.556145619601 - 20 -1245.952369962644 - 0 -HATCH - 5 -7A0 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 5 - 72 - 1 - 10 -3357.09232120309 - 20 -1244.722369962663 - 11 -3357.09232120309 - 21 -1244.752369962633 - 72 - 1 - 10 -3357.09232120309 - 20 -1244.752369962633 - 11 -3356.892321203137 - 21 -1244.752369962633 - 72 - 1 - 10 -3356.892321203137 - 20 -1244.752369962633 - 11 -3356.892321203137 - 21 -1244.522369962651 - 72 - 1 - 10 -3356.892321203137 - 20 -1244.522369962651 - 11 -3357.09232120309 - 21 -1244.522369962651 - 72 - 1 - 10 -3357.09232120309 - 20 -1244.522369962651 - 11 -3357.09232120309 - 21 -1244.722369962663 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -7A1 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3357.09232120309 - 20 -1244.722369962663 - 10 -3357.09232120309 - 20 -1244.522369962651 - 10 -3356.892321203137 - 20 -1244.522369962651 - 10 -3356.892321203137 - 20 -1244.752369962633 - 10 -3357.09232120309 - 20 -1244.752369962633 - 10 -3357.09232120309 - 20 -1244.722369962663 - 0 -HATCH - 5 -7A2 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3352.358675249619 - 20 -1249.590104148723 - 11 -3351.85867524962 - 21 -1249.590104148723 - 72 - 1 - 10 -3351.85867524962 - 20 -1249.590104148723 - 11 -3351.85867524962 - 21 -1249.360104148742 - 72 - 1 - 10 -3351.85867524962 - 20 -1249.360104148742 - 11 -3352.358675249619 - 21 -1249.360104148742 - 72 - 1 - 10 -3352.358675249619 - 20 -1249.360104148742 - 11 -3352.358675249619 - 21 -1249.590104148723 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -7A3 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3351.85867524962 - 20 -1249.360104148742 - 10 -3351.85867524962 - 20 -1249.590104148723 - 10 -3352.358675249619 - 20 -1249.590104148723 - 10 -3352.358675249619 - 20 -1249.360104148742 - 10 -3351.85867524962 - 20 -1249.360104148742 - 0 -HATCH - 5 -7A4 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3363.556145619601 - 20 -1249.590104148723 - 11 -3363.056145619601 - 21 -1249.590104148723 - 72 - 1 - 10 -3363.056145619601 - 20 -1249.590104148723 - 11 -3363.056145619601 - 21 -1249.360104148742 - 72 - 1 - 10 -3363.056145619601 - 20 -1249.360104148742 - 11 -3363.556145619601 - 21 -1249.360104148742 - 72 - 1 - 10 -3363.556145619601 - 20 -1249.360104148742 - 11 -3363.556145619601 - 21 -1249.590104148723 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -7A5 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3363.056145619601 - 20 -1249.360104148742 - 10 -3363.056145619601 - 20 -1249.590104148723 - 10 -3363.556145619601 - 20 -1249.590104148723 - 10 -3363.556145619601 - 20 -1249.360104148742 - 10 -3363.056145619601 - 20 -1249.360104148742 - 0 -HATCH - 5 -7A6 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3352.088675249601 - 20 -1242.154635776649 - 11 -3352.088675249601 - 21 -1242.654635776649 - 72 - 1 - 10 -3352.088675249601 - 20 -1242.654635776649 - 11 -3351.85867524962 - 21 -1242.654635776649 - 72 - 1 - 10 -3351.85867524962 - 20 -1242.654635776649 - 11 -3351.85867524962 - 21 -1242.154635776649 - 72 - 1 - 10 -3351.85867524962 - 20 -1242.154635776649 - 11 -3352.088675249601 - 21 -1242.154635776649 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -7A7 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3351.85867524962 - 20 -1242.654635776649 - 10 -3352.088675249601 - 20 -1242.654635776649 - 10 -3352.088675249601 - 20 -1242.154635776649 - 10 -3351.85867524962 - 20 -1242.154635776649 - 10 -3351.85867524962 - 20 -1242.654635776649 - 0 -HATCH - 5 -7A8 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3351.85867524962 - 20 -1256.050104161259 - 11 -3351.85867524962 - 21 -1255.550104161259 - 72 - 1 - 10 -3351.85867524962 - 20 -1255.550104161259 - 11 -3352.088675249601 - 21 -1255.550104161259 - 72 - 1 - 10 -3352.088675249601 - 20 -1255.550104161259 - 11 -3352.088675249601 - 21 -1256.050104161259 - 72 - 1 - 10 -3352.088675249601 - 20 -1256.050104161259 - 11 -3351.85867524962 - 21 -1256.050104161259 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -7A9 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3352.088675249601 - 20 -1255.550104161259 - 10 -3351.85867524962 - 20 -1255.550104161259 - 10 -3351.85867524962 - 20 -1256.050104161259 - 10 -3352.088675249601 - 20 -1256.050104161259 - 10 -3352.088675249601 - 20 -1255.550104161259 - 0 -LWPOLYLINE - 5 -7AA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3360.096145619638 - 20 -1243.823737554077 - 10 -3363.556145619601 - 20 -1243.823737554077 - 10 -3363.556145619601 - 20 -1245.238323131401 - 0 -LWPOLYLINE - 5 -7AB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3363.55765715451 - 20 -1245.952369962644 - 10 -3363.556145619601 - 20 -1245.238323131401 - 10 -3363.32614561962 - 20 -1245.238323131401 - 10 -3363.32614561962 - 20 -1245.952385825629 - 0 -LINE - 5 -7AC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3355.617321202998 - 20 -1244.402369962656 - 11 -3355.617321202998 - 21 -1244.445176272304 - 0 -LINE - 5 -7AD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3355.617321202998 - 20 -1244.48176036129 - 11 -3355.617321202998 - 21 -1244.52456667088 - 0 -LINE - 5 -7AE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 52 -370 - 0 -100 -AcDbLine - 10 -3356.892321203137 - 20 -1244.402369962656 - 11 -3356.892321203137 - 21 -1243.472369962663 - 0 -LINE - 5 -7AF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3356.892321203137 - 20 -1244.552369962679 - 11 -3356.740498226369 - 21 -1244.552369962679 - 0 -LINE - 5 -7B0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3355.740498226369 - 20 -1244.552369962679 - 11 -3355.617321202998 - 21 -1244.552369962679 - 0 -LINE - 5 -7B1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3356.892321203137 - 20 -1244.752369962633 - 11 -3356.740498226369 - 21 -1244.752369962633 - 0 -LINE - 5 -7B2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3355.740498226369 - 20 -1244.752369962691 - 11 -3355.388675249648 - 21 -1244.752369962691 - 0 -LINE - 5 -7B3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3355.617321202998 - 20 -1244.402369962656 - 11 -3355.617321202998 - 21 -1244.445176272304 - 0 -LINE - 5 -7B4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3355.617321202998 - 20 -1244.48176036129 - 11 -3355.617321202998 - 21 -1244.52456667088 - 0 -LWPOLYLINE - 5 -7B5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbPolyline - 90 - 8 - 70 - 0 - 43 -0 - 10 -3356.892321203137 - 20 -1243.472369962663 - 10 -3356.892321203137 - 20 -1244.752369962633 - 10 -3357.09232120309 - 20 -1244.752369962633 - 10 -3357.092321204488 - 20 -1244.752369964204 - 10 -3357.092321204488 - 20 -1244.522369963757 - 10 -3357.092321204488 - 20 -1244.522369963757 - 10 -3357.09232120309 - 20 -1243.472369962663 - 10 -3356.892321203137 - 20 -1243.472369962663 - 0 -LINE - 5 -7B6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3355.388675249648 - 20 -1243.472369962663 - 11 -3355.388675249648 - 21 -1244.752369962691 - 0 -LINE - 5 -7B7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbLine - 10 -3355.588675249601 - 20 -1243.672369962675 - 11 -3355.588675249601 - 21 -1244.252369962691 - 0 -LWPOLYLINE - 5 -7B8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 30 -370 - 35 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3355.58732120297 - 20 -1243.472369962663 - 10 -3355.388675249648 - 20 -1243.472369962663 - 10 -3355.388675249648 - 20 -1242.722369962663 - 10 -3355.388675249648 - 20 -1242.722369962663 - 0 -LINE - 5 -7B9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3355.740498226369 - 20 -1244.552369962679 - 11 -3355.740498226369 - 21 -1244.752369962691 - 0 -LINE - 5 -7BA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3356.740498226369 - 20 -1244.552369962679 - 11 -3356.740498226369 - 21 -1244.752369962633 - 0 -LWPOLYLINE - 5 -7BB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 1 - 43 -0 - 10 -3355.667321203044 - 20 -1244.502369962691 - 10 -3356.84232120309 - 20 -1244.502369962691 - 10 -3356.84232120309 - 20 -1242.972369962663 - 10 -3355.637321203016 - 20 -1242.972369962663 - 10 -3355.637321203016 - 20 -1244.202369962644 - 10 -3355.667321203044 - 20 -1244.202369962644 - 0 -LWPOLYLINE - 5 -7BC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 6 - 70 - 1 - 43 -0 - 10 -3355.717321203091 - 20 -1244.452369962644 - 10 -3356.792321203044 - 20 -1244.452369962644 - 10 -3356.792321203044 - 20 -1243.022369962651 - 10 -3355.687321203062 - 20 -1243.022369962651 - 10 -3355.687321203062 - 20 -1244.152369962656 - 10 -3355.717321203091 - 20 -1244.152369962656 - 0 -LINE - 5 -7BD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3355.617321202998 - 20 -1244.552369962679 - 11 -3356.892321203137 - 21 -1242.922369962675 - 0 -LINE - 5 -7BE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3356.892321203137 - 20 -1244.552369962679 - 11 -3355.58732120297 - 21 -1242.922369962675 - 0 -MTEXT - 5 -7BF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3355.895680091343 - 20 -1243.275681681291 - 30 -0 - 40 -0.21 - 41 -0.5133333333333333 - 71 - 1 - 72 - 5 - 1 -LIFT - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -7C0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3356.264822534053 - 20 -1243.303355389158 - 30 -0 - 40 -0.21 - 41 -1.026666666666706 - 71 - 1 - 72 - 5 - 1 -163X130 - 7 -arial -210 -0 -220 -0 -230 -1 - 50 -89.55171044871167 - 73 - 1 - 44 -1 - 0 -LINE - 5 -7C1 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3355.387321203016 - 20 -1244.752369962691 - 11 -3355.388675249648 - 21 -1245.052369962679 - 0 -LWPOLYLINE - 5 -7C2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3355.58732120297 - 20 -1243.423737554112 - 10 -3355.58732120297 - 20 -1242.722369962663 - 10 -3355.388675249648 - 20 -1242.722369962663 - 10 -3355.388675249648 - 20 -1243.423737554112 - 0 -HATCH - 5 -7C3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3352.6887084716 - 20 -1243.852369962668 - 11 -3352.688928816468 - 21 -1243.552369962679 - 72 - 1 - 10 -3352.688928816468 - 20 -1243.552369962679 - 11 -3352.992847246583 - 21 -1243.552369962679 - 72 - 1 - 10 -3352.992847246583 - 20 -1243.552369962679 - 11 -3352.6887084716 - 21 -1243.852369962668 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -7C4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3352.6887084716 - 20 -1243.852369962668 - 11 -3352.404033047613 - 21 -1243.552369962679 - 72 - 1 - 10 -3352.404033047613 - 20 -1243.552369962679 - 11 -3352.688928816468 - 21 -1243.552369962679 - 72 - 1 - 10 -3352.688928816468 - 20 -1243.552369962679 - 11 -3352.6887084716 - 21 -1243.852369962668 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -7C5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3354.802367591999 - 20 -1246.567925359879 - 10 -3354.802367591999 - 20 -1243.552369962679 - 10 -3354.802367591999 - 20 -1242.922737527056 - 10 -3352.689391270746 - 20 -1242.922737527056 - 10 -3352.688488126732 - 20 -1244.152369962656 - 0 -LWPOLYLINE - 5 -7C6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3352.992847246583 - 20 -1243.552369962679 - 10 -3352.6887084716 - 20 -1243.852369962668 - 10 -3352.404033047613 - 20 -1243.552369962679 - 10 -3352.992847246583 - 20 -1243.552369962679 - 0 -LWPOLYLINE - 5 -7C7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3354.21867524949 - 20 -1243.492369962681 - 10 -3354.21867524949 - 20 -1245.402369962656 - 10 -3353.258301003836 - 20 -1245.402369962656 - 0 -LWPOLYLINE - 5 -7C8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3354.248675249517 - 20 -1243.492369962681 - 10 -3354.248675249517 - 20 -1245.452369962644 - 10 -3353.258301003836 - 20 -1245.452369962644 - 0 -LINE - 5 -7C9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3355.388675249648 - 20 -1245.052369962679 - 11 -3355.388675249648 - 21 -1245.652369962656 - 0 -LWPOLYLINE - 5 -7CA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3355.387321203016 - 20 -1244.752369962691 - 10 -3355.388675249648 - 20 -1245.052369962679 - 0 -LWPOLYLINE - 5 -7CB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3355.437320693862 - 20 -1244.752144290542 - 10 -3355.43867474026 - 20 -1245.05214429053 - 0 -LWPOLYLINE - 5 -7CC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3355.487320184476 - 20 -1244.751918618451 - 10 -3355.488674230874 - 20 -1245.051918618439 - 0 -LWPOLYLINE - 5 -7CD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3355.388675249648 - 20 -1245.052369962679 - 10 -3355.488674230874 - 20 -1245.051918618439 - 0 -LINE - 5 -7CE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1256.300104148744 - 11 -3352.838675249601 - 21 -1256.300104148744 - 0 -LINE - 5 -7CF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1256.500104148756 - 11 -3352.838675249601 - 21 -1256.500104148756 - 0 -LINE - 5 -7D0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1256.700104148709 - 11 -3352.838675249601 - 21 -1256.700104148709 - 0 -LINE - 5 -7D1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1256.900104148721 - 11 -3352.838675249601 - 21 -1256.900104148721 - 0 -LINE - 5 -7D2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1257.100104148732 - 11 -3352.838675249601 - 21 -1257.100104148732 - 0 -LINE - 5 -7D3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1257.300104148744 - 11 -3352.838675249601 - 21 -1257.300104148744 - 0 -LINE - 5 -7D4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1257.500104148756 - 11 -3352.838675249601 - 21 -1257.500104148756 - 0 -LINE - 5 -7D5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1257.700104148709 - 11 -3352.838675249601 - 21 -1257.700104148709 - 0 -LINE - 5 -7D6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1257.900104148721 - 11 -3352.838675249601 - 21 -1257.900104148721 - 0 -LINE - 5 -7D7 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1258.100104148732 - 11 -3352.838675249601 - 21 -1258.100104148732 - 0 -LINE - 5 -7D8 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.088675249601 - 20 -1258.300104148744 - 11 -3352.838675249601 - 21 -1258.300104148744 - 0 -LWPOLYLINE - 5 -7D9 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3352.838675249601 - 20 -1258.300104148744 - 10 -3352.838675249601 - 20 -1258.100104148732 - 0 -LWPOLYLINE - 5 -7DA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3352.838675249601 - 20 -1257.900104148721 - 10 -3352.838675249601 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -7DB -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3352.938675249461 - 20 -1258.300104148744 - 10 -3352.938675249461 - 20 -1256.300104148744 - 0 -LINE - 5 -7DC -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1256.300104148744 - 11 -3353.688675249461 - 21 -1256.300104148744 - 0 -LINE - 5 -7DD -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1256.500104148756 - 11 -3353.688675249461 - 21 -1256.500104148756 - 0 -LINE - 5 -7DE -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1256.700104148709 - 11 -3353.688675249461 - 21 -1256.700104148709 - 0 -LINE - 5 -7DF -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1256.900104148721 - 11 -3353.688675249461 - 21 -1256.900104148721 - 0 -LINE - 5 -7E0 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1257.100104148732 - 11 -3353.688675249461 - 21 -1257.100104148732 - 0 -LINE - 5 -7E1 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1257.300104148744 - 11 -3353.688675249461 - 21 -1257.300104148744 - 0 -LINE - 5 -7E2 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1257.500104148756 - 11 -3353.688675249461 - 21 -1257.500104148756 - 0 -LINE - 5 -7E3 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1257.700104148709 - 11 -3353.688675249461 - 21 -1257.700104148709 - 0 -LINE - 5 -7E4 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1257.900104148721 - 11 -3353.688675249461 - 21 -1257.900104148721 - 0 -LINE - 5 -7E5 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1258.100104148732 - 11 -3353.688675249461 - 21 -1258.100104148732 - 0 -LINE - 5 -7E6 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.938675249461 - 20 -1258.300104148744 - 11 -3353.688675249461 - 21 -1258.300104148744 - 0 -LWPOLYLINE - 5 -7E7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3353.688675249461 - 20 -1259.050104148744 - 10 -3353.688675249461 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -7E8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3352.838675249601 - 20 -1256.300104148744 - 10 -3352.838675249601 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -7E9 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3352.838675249601 - 20 -1258.100104148732 - 10 -3352.838675249601 - 20 -1258.300104148744 - 10 -3352.938675249461 - 20 -1258.300104148744 - 10 -3352.938675249461 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -7EA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3352.808675249573 - 20 -1256.300104148744 - 10 -3352.808675249573 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -7EB -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3352.808675249573 - 20 -1258.100104148732 - 10 -3352.808675249573 - 20 -1258.330104148714 - 10 -3352.968675249489 - 20 -1258.330104148714 - 10 -3352.968675249489 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -7EC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3352.778675249545 - 20 -1256.300104148744 - 10 -3352.778675249545 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -7ED -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3352.778675249545 - 20 -1258.100104148732 - 10 -3352.778675249545 - 20 -1258.360104148741 - 10 -3352.998675249518 - 20 -1258.360104148741 - 10 -3352.998675249518 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -7EE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3353.688675249461 - 20 -1255.998735667846 - 10 -3353.688675249461 - 20 -1259.280104150704 - 0 -LWPOLYLINE - 5 -7EF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3351.85867524962 - 20 -1256.050104161259 - 10 -3351.858675251249 - 20 -1259.280104150704 - 10 -3353.688675249461 - 20 -1259.280104150704 - 0 -LWPOLYLINE - 5 -7F0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3351.908675249666 - 20 -1256.050104161259 - 10 -3351.908675249666 - 20 -1259.230104148737 - 10 -3353.688675249461 - 20 -1259.230104148737 - 0 -LWPOLYLINE - 5 -7F1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3351.95867524948 - 20 -1256.050104161259 - 10 -3351.95867524948 - 20 -1259.180104148749 - 10 -3353.688675249461 - 20 -1259.180104148749 - 0 -LWPOLYLINE - 5 -7F2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3352.088675249601 - 20 -1256.050104161259 - 10 -3352.088675249601 - 20 -1259.050104148744 - 10 -3353.688675249461 - 20 -1259.050104148744 - 0 -LINE - 5 -7F3 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3357.09232120309 - 20 -1243.423737554054 - 11 -3357.09232120309 - 21 -1243.04620614968 - 0 -LINE - 5 -7F4 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3357.042321203044 - 20 -1243.423737554054 - 11 -3357.042321203044 - 21 -1243.04620614968 - 0 -LINE - 5 -7F5 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3356.992321202997 - 20 -1243.423737554054 - 11 -3356.992321202997 - 21 -1243.04620614968 - 0 -LINE - 5 -7F6 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 2 -370 - 0 -100 -AcDbLine - 10 -3356.892321203137 - 20 -1243.423737554054 - 11 -3356.892321203137 - 21 -1243.016605238954 - 0 -LWPOLYLINE - 5 -7F7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3353.918675249442 - 20 -1259.280104148725 - 10 -3353.918675253634 - 20 -1249.590104149363 - 10 -3354.905542837922 - 20 -1249.590104149363 - 0 -LWPOLYLINE - 5 -7F8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3356.105542842066 - 20 -1249.590104148723 - 10 -3357.322410434719 - 20 -1249.590104148723 - 0 -LWPOLYLINE - 5 -7F9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3358.522410434672 - 20 -1249.590104148723 - 10 -3359.73927802709 - 20 -1249.590104148723 - 0 -LWPOLYLINE - 5 -7FA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3360.939278027043 - 20 -1249.590104148723 - 10 -3362.156145619695 - 20 -1249.590104148723 - 0 -LWPOLYLINE - 5 -7FB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3363.056145619601 - 20 -1249.590104148723 - 10 -3363.546145619592 - 20 -1249.590104148723 - 0 -LWPOLYLINE - 5 -7FC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3353.688675249461 - 20 -1255.998735667439 - 10 -3353.688675249461 - 20 -1249.360104148742 - 10 -3354.905542842113 - 20 -1249.360104148742 - 0 -LWPOLYLINE - 5 -7FD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3356.105542842066 - 20 -1249.360104148742 - 10 -3357.322410434719 - 20 -1249.360104148742 - 0 -LWPOLYLINE - 5 -7FE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3358.522410434672 - 20 -1249.360104148742 - 10 -3359.73927802709 - 20 -1249.360104148742 - 0 -LWPOLYLINE - 5 -7FF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3360.939278027043 - 20 -1249.360104148742 - 10 -3362.156145619695 - 20 -1249.360104148742 - 0 -LWPOLYLINE - 5 -800 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3363.056145619601 - 20 -1249.360104148742 - 10 -3363.54677788401 - 20 -1249.360104148742 - 0 -LWPOLYLINE - 5 -801 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3353.918675249442 - 20 -1259.280104148725 - 10 -3363.556145619601 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -802 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3363.556145619601 - 20 -1249.590104148723 - 10 -3363.556145619601 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -803 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3357.092321204488 - 20 -1244.522369963757 - 10 -3357.092321204488 - 20 -1245.052802683494 - 0 -LWPOLYLINE - 5 -804 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3357.092321204488 - 20 -1245.952802682004 - 10 -3357.750777306501 - 20 -1245.952802682004 - 0 -LWPOLYLINE - 5 -805 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3358.950777309481 - 20 -1245.952802682004 - 10 -3359.609233411495 - 20 -1245.952802682004 - 0 -LWPOLYLINE - 5 -806 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3360.809233414475 - 20 -1245.952802682004 - 10 -3361.467689516488 - 20 -1245.952802682004 - 0 -LWPOLYLINE - 5 -807 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3362.667689512019 - 20 -1245.952802682004 - 10 -3363.326145621484 - 20 -1245.952802682004 - 0 -LWPOLYLINE - 5 -808 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3356.862321200315 - 20 -1244.522369963757 - 10 -3356.862321200315 - 20 -1245.052802683494 - 0 -LWPOLYLINE - 5 -809 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3356.862321203109 - 20 -1245.952802684624 - 10 -3356.862321200315 - 20 -1246.182802682451 - 10 -3357.750777306501 - 20 -1246.182802682451 - 0 -LWPOLYLINE - 5 -80A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3358.950777309481 - 20 -1246.182802682451 - 10 -3359.609233411495 - 20 -1246.182802682451 - 0 -LWPOLYLINE - 5 -80B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3360.809233414475 - 20 -1246.182802682451 - 10 -3361.467689516488 - 20 -1246.182802682451 - 0 -LWPOLYLINE - 5 -80C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3362.667689512019 - 20 -1246.182802682451 - 10 -3363.326145621484 - 20 -1246.182802682451 - 0 -LINE - 5 -80D -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3352.566810790218 - 20 -1240.067414091492 - 11 -3352.566810790218 - 21 -1260.721494615893 - 0 -CIRCLE - 5 -80E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbCircle - 10 -3352.566810790218 - 20 -1241.147899743053 - 40 -0.3105759447073808 - 0 -HATCH - 5 -80F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3352.877386735054 - 20 -1241.147899743053 - 11 -3352.566810790218 - 21 -1241.458475687774 - 72 - 1 - 10 -3352.566810790218 - 20 -1241.458475687774 - 11 -3352.566810790218 - 21 -1240.837323798332 - 72 - 1 - 10 -3352.566810790218 - 20 -1240.837323798332 - 11 -3352.877386735054 - 21 -1241.147899743053 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -810 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3352.566810790218 - 20 -1240.837323797925 - 10 -3352.877386735287 - 20 -1241.147899742995 - 10 -3352.566810790218 - 20 -1241.458475687774 - 10 -3352.566810790218 - 20 -1240.837323797925 - 0 -MTEXT - 5 -811 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3352.852777876891 - 20 -1241.193436495552 - 30 -0 - 40 -0.4900000000000003 - 41 -0.3266666666666669 - 71 - 1 - 72 - 5 - 1 -A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -CIRCLE - 5 -812 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbCircle - 10 -3352.566810790218 - 20 -1260.305064084648 - 40 -0.3105759447073808 - 0 -HATCH - 5 -813 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3352.877386735054 - 20 -1260.305064084648 - 11 -3352.566810790218 - 21 -1260.615640029369 - 72 - 1 - 10 -3352.566810790218 - 20 -1260.615640029369 - 11 -3352.566810790218 - 21 -1259.994488139986 - 72 - 1 - 10 -3352.566810790218 - 20 -1259.994488139986 - 11 -3352.877386735054 - 21 -1260.305064084648 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -814 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3352.566810790218 - 20 -1259.994488139753 - 10 -3352.877386735054 - 20 -1260.305064084648 - 10 -3352.566810790218 - 20 -1260.615640029369 - 10 -3352.566810790218 - 20 -1259.994488139753 - 0 -MTEXT - 5 -815 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3352.852777876891 - 20 -1260.350600837148 - 30 -0 - 40 -0.4900000000000003 - 41 -0.3266666666666669 - 71 - 1 - 72 - 5 - 1 -A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -816 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3353.918675253634 - 20 -1259.280104150704 - 10 -3363.556145618204 - 20 -1259.280104150704 - 10 -3363.556145618204 - 20 -1249.590104149363 - 0 -LWPOLYLINE - 5 -817 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3353.918675249442 - 20 -1259.180104148749 - 10 -3363.456145619741 - 20 -1259.180104148749 - 10 -3363.456145619741 - 20 -1249.590104148723 - 0 -LWPOLYLINE - 5 -818 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3357.09232120309 - 20 -1243.472369962663 - 10 -3357.09232120309 - 20 -1242.722369962663 - 10 -3355.58732120297 - 20 -1242.722369962663 - 0 -LWPOLYLINE - 5 -819 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3356.892321203137 - 20 -1243.472369962663 - 10 -3356.892321203137 - 20 -1242.922369962675 - 10 -3355.58732120297 - 20 -1242.922369962675 - 0 -LWPOLYLINE - 5 -81A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3357.042321203044 - 20 -1243.472369962663 - 10 -3357.042321203044 - 20 -1242.772369962651 - 10 -3355.58732120297 - 20 -1242.772369962651 - 0 -LWPOLYLINE - 5 -81B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3356.992321202997 - 20 -1243.472369962663 - 10 -3356.992321202997 - 20 -1242.822369962639 - 10 -3355.58732120297 - 20 -1242.822369962639 - 0 -LINE - 5 -81C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3359.609233411495 - 20 -1245.952802682004 - 11 -3359.609233411495 - 21 -1246.182802682451 - 0 -LINE - 5 -81D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3360.809233414475 - 20 -1245.952802682004 - 11 -3360.809233414475 - 21 -1246.182802682451 - 0 -LINE - 5 -81E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3362.667689512019 - 20 -1245.952802682004 - 11 -3362.667689512019 - 21 -1246.182802682451 - 0 -LINE - 5 -81F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3361.467689516488 - 20 -1245.952802682004 - 11 -3361.467689516488 - 21 -1246.182802682451 - 0 -LINE - 5 -820 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3358.950777309481 - 20 -1245.952802682004 - 11 -3358.950777309481 - 21 -1246.182802682451 - 0 -LINE - 5 -821 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3357.750777306501 - 20 -1245.952802682004 - 11 -3357.750777306501 - 21 -1246.182802682451 - 0 -LINE - 5 -822 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3357.092321204488 - 20 -1245.952802682004 - 11 -3356.862321200315 - 21 -1245.952802682004 - 0 -LINE - 5 -823 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3357.092321204488 - 20 -1245.052802683494 - 11 -3356.862321200315 - 21 -1245.052802683494 - 0 -LINE - 5 -824 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3363.056145618204 - 20 -1249.360104148916 - 11 -3363.056145618204 - 21 -1249.590104149363 - 0 -LINE - 5 -825 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3362.156145619695 - 20 -1249.360104148742 - 11 -3362.156145619695 - 21 -1249.590104148723 - 0 -LWPOLYLINE - 5 -826 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3357.09232120309 - 20 -1245.052802684659 - 10 -3357.092321204488 - 20 -1245.952802682004 - 10 -3362.667689512019 - 20 -1245.952802682004 - 0 -LWPOLYLINE - 5 -827 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3319.37663197564 - 20 -1242.722369962663 - 10 -3324.115456392291 - 20 -1243.423737554054 - 10 -3324.115456392291 - 20 -1243.823737554077 - 10 -3327.345456392271 - 20 -1243.823737554077 - 10 -3327.345456392271 - 20 -1245.238323131343 - 0 -LWPOLYLINE - 5 -828 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3357.09232120309 - 20 -1242.945116815506 - 10 -3360.326145621483 - 20 -1243.423737553589 - 10 -3360.326145621483 - 20 -1243.823737552098 - 10 -3363.556145618204 - 20 -1243.823737552098 - 10 -3363.556145618204 - 20 -1245.238323131285 - 0 -LWPOLYLINE - 5 -829 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3357.09232120309 - 20 -1243.04620614968 - 10 -3360.226145619761 - 20 -1243.510026432865 - 10 -3360.226145619761 - 20 -1243.923737554054 - 10 -3363.456145619741 - 20 -1243.923737554054 - 10 -3363.456145619741 - 20 -1245.238323131343 - 0 -LINE - 5 -82A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3357.750777306501 - 20 -1246.182802682451 - 11 -3358.950777309481 - 21 -1246.182802682451 - 0 -LINE - 5 -82B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3357.750777306501 - 20 -1245.952802682004 - 11 -3358.950777309481 - 21 -1245.952802682004 - 0 -LINE - 5 -82C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3357.750777307199 - 20 -1246.132802684617 - 11 -3358.950777307153 - 21 -1246.132802684617 - 0 -LINE - 5 -82D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3357.750777307199 - 20 -1246.082802684628 - 11 -3358.950777307153 - 21 -1246.082802684628 - 0 -LINE - 5 -82E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3360.809233414475 - 20 -1245.952802682004 - 11 -3360.809233414475 - 21 -1246.182802682451 - 0 -LINE - 5 -82F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3359.609233411495 - 20 -1245.952802682004 - 11 -3359.609233411495 - 21 -1246.182802682451 - 0 -LINE - 5 -830 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3359.609233411495 - 20 -1246.182802682451 - 11 -3360.809233414475 - 21 -1246.182802682451 - 0 -LINE - 5 -831 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3359.609233411495 - 20 -1245.952802682004 - 11 -3360.809233414475 - 21 -1245.952802682004 - 0 -LINE - 5 -832 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3359.609233411263 - 20 -1246.132802684617 - 11 -3360.809233411448 - 21 -1246.132802684617 - 0 -LINE - 5 -833 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3359.609233411263 - 20 -1246.082802684628 - 11 -3360.809233411448 - 21 -1246.082802684628 - 0 -LINE - 5 -834 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3362.667689512019 - 20 -1245.952802682004 - 11 -3362.667689512019 - 21 -1246.182802682451 - 0 -LINE - 5 -835 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3361.467689516488 - 20 -1245.952802682004 - 11 -3361.467689516488 - 21 -1246.182802682451 - 0 -LINE - 5 -836 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3361.467689516488 - 20 -1246.182802682451 - 11 -3362.667689512019 - 21 -1246.182802682451 - 0 -LINE - 5 -837 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3361.467689516488 - 20 -1245.952802682004 - 11 -3362.667689512019 - 21 -1245.952802682004 - 0 -LINE - 5 -838 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3361.467689515557 - 20 -1246.132802684617 - 11 -3362.667689515511 - 21 -1246.132802684617 - 0 -LINE - 5 -839 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3361.467689515557 - 20 -1246.082802684628 - 11 -3362.667689515511 - 21 -1246.082802684628 - 0 -LWPOLYLINE - 5 -83A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3362.667689512019 - 20 -1245.952802682004 - 10 -3362.667689512019 - 20 -1245.352802684239 - 10 -3362.767689513508 - 20 -1245.352802684239 - 10 -3362.767689513508 - 20 -1245.952802682004 - 0 -LWPOLYLINE - 5 -83B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3361.367689514999 - 20 -1245.952802682004 - 10 -3361.367689514999 - 20 -1245.352802684239 - 10 -3361.467689516488 - 20 -1245.352802684239 - 10 -3361.467689516488 - 20 -1245.952802682004 - 0 -LWPOLYLINE - 5 -83C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3360.809233414475 - 20 -1245.952802682004 - 10 -3360.809233414475 - 20 -1245.352802684239 - 10 -3360.909233415965 - 20 -1245.352802684239 - 10 -3360.909233415965 - 20 -1245.952802682004 - 0 -LWPOLYLINE - 5 -83D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3359.509233417455 - 20 -1245.952802682004 - 10 -3359.509233417455 - 20 -1245.352802684239 - 10 -3359.609233411495 - 20 -1245.352802684239 - 10 -3359.609233411495 - 20 -1245.952802682004 - 0 -LWPOLYLINE - 5 -83E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3358.950777309481 - 20 -1245.952802682004 - 10 -3358.950777309481 - 20 -1245.352802684239 - 10 -3359.050777310971 - 20 -1245.352802684239 - 10 -3359.050777310971 - 20 -1245.952802682004 - 0 -LWPOLYLINE - 5 -83F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3357.650777305011 - 20 -1245.952802682004 - 10 -3357.650777305011 - 20 -1245.352802684239 - 10 -3357.750777306501 - 20 -1245.352802684239 - 10 -3357.750777306501 - 20 -1245.952802682004 - 0 -LINE - 5 -840 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3358.522410434672 - 20 -1249.360104148742 - 11 -3358.522410434672 - 21 -1249.590104148723 - 0 -LINE - 5 -841 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3357.322410434719 - 20 -1249.360104148742 - 11 -3357.322410434719 - 21 -1249.590104148723 - 0 -LINE - 5 -842 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3360.939278027043 - 20 -1249.360104148742 - 11 -3360.939278027043 - 21 -1249.590104148723 - 0 -LINE - 5 -843 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3359.73927802709 - 20 -1249.360104148742 - 11 -3359.73927802709 - 21 -1249.590104148723 - 0 -LINE - 5 -844 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3356.105542842066 - 20 -1249.360104148742 - 11 -3356.105542842066 - 21 -1249.590104148723 - 0 -LINE - 5 -845 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3354.905542837922 - 20 -1249.360104148916 - 11 -3354.905542837922 - 21 -1249.590104149363 - 0 -LINE - 5 -846 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3354.905542842113 - 20 -1249.590104148723 - 11 -3363.556145619601 - 21 -1249.590104148723 - 0 -HATCH - 5 -847 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3353.918675249442 - 20 -1258.780104148725 - 11 -3353.918675249442 - 21 -1259.280104148725 - 72 - 1 - 10 -3353.918675249442 - 20 -1259.280104148725 - 11 -3353.688675249461 - 21 -1259.280104148725 - 72 - 1 - 10 -3353.688675249461 - 20 -1259.280104148725 - 11 -3353.688675249461 - 21 -1258.780104148725 - 72 - 1 - 10 -3353.688675249461 - 20 -1258.780104148725 - 11 -3353.918675249442 - 21 -1258.780104148725 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -848 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3353.688675249461 - 20 -1259.280104150704 - 10 -3353.918675253634 - 20 -1259.280104150704 - 10 -3353.918675249442 - 20 -1258.780104148725 - 10 -3353.688675249461 - 20 -1258.780104150704 - 10 -3353.688675249461 - 20 -1259.280104150704 - 0 -HATCH - 5 -849 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3353.688675249461 - 20 -1256.050104161259 - 11 -3353.688675249461 - 21 -1255.550104161259 - 72 - 1 - 10 -3353.688675249461 - 20 -1255.550104161259 - 11 -3353.918675249442 - 21 -1255.550104161259 - 72 - 1 - 10 -3353.918675249442 - 20 -1255.550104161259 - 11 -3353.918675249442 - 21 -1256.050104161259 - 72 - 1 - 10 -3353.918675249442 - 20 -1256.050104161259 - 11 -3353.688675249461 - 21 -1256.050104161259 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -84A -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3353.918675249442 - 20 -1255.550104161259 - 10 -3353.688675249461 - 20 -1255.550104161259 - 10 -3353.688675249461 - 20 -1256.050104161259 - 10 -3353.918675249442 - 20 -1256.050104161259 - 10 -3353.918675249442 - 20 -1255.550104161259 - 0 -HATCH - 5 -84B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANGLE - 70 - 0 - 71 - 0 - 91 - 2 - 92 - 0 - 93 - 6 - 72 - 1 - 10 -3363.456145619741 - 20 -1259.180104148749 - 11 -3353.918675249442 - 21 -1259.180104148749 - 72 - 1 - 10 -3353.918675249442 - 20 -1259.180104148749 - 11 -3353.918675249442 - 21 -1258.780104148725 - 72 - 1 - 10 -3353.918675249442 - 20 -1258.780104148725 - 11 -3353.918675249442 - 21 -1249.590104148723 - 72 - 1 - 10 -3353.918675249442 - 20 -1249.590104148723 - 11 -3354.905542842113 - 21 -1249.590104148723 - 72 - 1 - 10 -3354.905542842113 - 20 -1249.590104148723 - 11 -3363.456145619741 - 21 -1249.590104148723 - 72 - 1 - 10 -3363.456145619741 - 20 -1249.590104148723 - 11 -3363.456145619741 - 21 -1259.180104148749 - 97 - 0 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3355.355586569291 - 20 -1252.165106727509 - 11 -3360.934950756609 - 21 -1252.121452173392 - 72 - 1 - 10 -3360.934950756609 - 20 -1252.121452173392 - 11 -3360.943136016139 - 21 -1253.167586872005 - 72 - 1 - 10 -3360.943136016139 - 20 -1253.167586871947 - 11 -3355.363771828824 - 21 -1253.211241426062 - 72 - 1 - 10 -3355.363771828824 - 20 -1253.211241426062 - 11 -3355.355586569291 - 21 -1252.16510672745 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -1.5 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -MTEXT - 5 -84C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3355.512360998429 - 20 -1252.932892533427 - 30 -0 - 40 -0.4900000000000003 - 41 -4.831944444444448 - 71 - 1 - 72 - 5 - 1 -OPEN TERRACE - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -LINE - 5 -84D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbLine - 10 -3374.172164166812 - 20 -1259.280104150704 - 11 -3374.402164170984 - 21 -1259.280104150704 - 0 -LINE - 5 -84E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3372.342164165108 - 20 -1243.321229862398 - 11 -3372.342164165108 - 21 -1256.050104161259 - 0 -LINE - 5 -84F -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3372.572164165323 - 20 -1242.252369960479 - 11 -3375.852164166514 - 21 -1242.252369960479 - 0 -LWPOLYLINE - 5 -850 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3380.809634535341 - 20 -1243.923737554054 - 10 -3380.809634535341 - 20 -1242.900966822169 - 10 -3380.809634535341 - 20 -1241.721707735967 - 10 -3372.572164165323 - 20 -1241.721707735967 - 0 -LWPOLYLINE - 5 -851 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3374.172164166812 - 20 -1259.280104150704 - 10 -3374.402164170984 - 20 -1259.280104150704 - 0 -HATCH - 5 -852 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANGLE - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 9 - 72 - 1 - 10 -3383.939634535229 - 20 -1245.238323131401 - 11 -3377.575810118579 - 21 -1245.238323131401 - 72 - 1 - 10 -3377.575810118579 - 20 -1245.238323131401 - 11 -3377.575810118579 - 21 -1244.522369962651 - 72 - 1 - 10 -3377.575810118579 - 20 -1244.522369962651 - 11 -3377.575810118579 - 21 -1243.472369962663 - 72 - 1 - 10 -3377.575810118579 - 20 -1243.472369962663 - 11 -3377.575810118579 - 21 -1243.04620614968 - 72 - 1 - 10 -3377.575810118579 - 20 -1243.04620614968 - 11 -3380.579634535126 - 21 -1243.490785840957 - 72 - 1 - 10 -3380.579634535358 - 20 -1243.490785840957 - 11 -3380.579634535358 - 21 -1243.923737554112 - 72 - 1 - 10 -3380.579634535358 - 20 -1243.923737554054 - 11 -3380.809634535341 - 21 -1243.923737554054 - 72 - 1 - 10 -3380.809634535341 - 20 -1243.923737554054 - 11 -3383.939634535229 - 21 -1243.923737554054 - 72 - 1 - 10 -3383.939634535229 - 20 -1243.923737554054 - 11 -3383.939634535229 - 21 -1245.238323131343 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -1.5 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -HATCH - 5 -853 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3372.572164165089 - 20 -1258.780104148725 - 11 -3372.572164165089 - 21 -1259.280104148725 - 72 - 1 - 10 -3372.572164165089 - 20 -1259.280104148725 - 11 -3372.342164165108 - 21 -1259.280104148725 - 72 - 1 - 10 -3372.342164165108 - 20 -1259.280104148725 - 11 -3372.342164165108 - 21 -1258.780104148725 - 72 - 1 - 10 -3372.342164165108 - 20 -1258.780104148725 - 11 -3372.572164165089 - 21 -1258.780104148725 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -854 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3372.3421641686 - 20 -1259.280104150704 - 10 -3372.572164165323 - 20 -1259.280104150704 - 10 -3372.572164165089 - 20 -1258.780104148725 - 10 -3372.342164165108 - 20 -1258.780104148725 - 10 -3372.342164165108 - 20 -1259.280104148725 - 0 -HATCH - 5 -855 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3372.342164165108 - 20 -1256.050104161259 - 11 -3372.342164165108 - 21 -1255.550104161259 - 72 - 1 - 10 -3372.342164165108 - 20 -1255.550104161259 - 11 -3372.572164165089 - 21 -1255.550104161259 - 72 - 1 - 10 -3372.572164165089 - 20 -1255.550104161259 - 11 -3372.572164165089 - 21 -1256.050104161259 - 72 - 1 - 10 -3372.572164165089 - 20 -1256.050104161259 - 11 -3372.342164165108 - 21 -1256.050104161259 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -856 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3372.572164165323 - 20 -1255.550104161433 - 10 -3372.3421641686 - 20 -1255.550104161433 - 10 -3372.3421641686 - 20 -1256.050104161433 - 10 -3372.572164165089 - 20 -1256.050104161259 - 10 -3372.572164165089 - 20 -1255.550104161259 - 0 -LWPOLYLINE - 5 -857 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3380.579634535358 - 20 -1243.823737554077 - 10 -3384.039634535323 - 20 -1243.823737554077 - 10 -3384.039634535323 - 20 -1245.238323131401 - 0 -LINE - 5 -858 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3384.041146070231 - 20 -1245.952369962644 - 11 -3384.039634535323 - 21 -1245.238323131401 - 0 -LINE - 5 -859 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3383.891146406299 - 20 -1245.952687490498 - 11 -3383.88963487139 - 21 -1245.238640659197 - 0 -LINE - 5 -85A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3384.039634535323 - 20 -1245.238323131401 - 11 -3383.809634535341 - 21 -1245.238323131401 - 0 -LINE - 5 -85B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3372.572164165089 - 20 -1257.100104148732 - 11 -3373.322164165089 - 21 -1257.100104148732 - 0 -LINE - 5 -85C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3372.572164165089 - 20 -1257.300104148744 - 11 -3373.322164165089 - 21 -1257.300104148744 - 0 -LINE - 5 -85D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3372.572164165089 - 20 -1257.500104148756 - 11 -3373.322164165089 - 21 -1257.500104148756 - 0 -LINE - 5 -85E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3372.572164165089 - 20 -1257.700104148709 - 11 -3373.322164165089 - 21 -1257.700104148709 - 0 -LINE - 5 -85F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3372.572164165089 - 20 -1257.900104148721 - 11 -3373.322164165089 - 21 -1257.900104148721 - 0 -LINE - 5 -860 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3372.572164165089 - 20 -1258.100104148732 - 11 -3373.322164165089 - 21 -1258.100104148732 - 0 -LINE - 5 -861 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3372.572164165089 - 20 -1258.300104148744 - 11 -3373.322164165089 - 21 -1258.300104148744 - 0 -LWPOLYLINE - 5 -862 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3373.322164165089 - 20 -1258.300104148744 - 10 -3373.322164165089 - 20 -1258.100104148732 - 0 -LWPOLYLINE - 5 -863 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3373.322164165089 - 20 -1257.900104148721 - 10 -3373.322164165089 - 20 -1257.100104148732 - 0 -LWPOLYLINE - 5 -864 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3373.422164165182 - 20 -1258.300104148744 - 10 -3373.422164165182 - 20 -1256.300104148744 - 0 -LINE - 5 -865 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1256.300104148744 - 11 -3374.172164165182 - 21 -1256.300104148744 - 0 -LINE - 5 -866 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1256.500104148756 - 11 -3374.172164165182 - 21 -1256.500104148756 - 0 -LINE - 5 -867 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1256.700104148709 - 11 -3374.172164165182 - 21 -1256.700104148709 - 0 -LINE - 5 -868 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1256.900104148721 - 11 -3374.172164165182 - 21 -1256.900104148721 - 0 -LINE - 5 -869 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1257.100104148732 - 11 -3374.172164165182 - 21 -1257.100104148732 - 0 -LINE - 5 -86A -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1257.300104148744 - 11 -3374.172164165182 - 21 -1257.300104148744 - 0 -LINE - 5 -86B -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1257.500104148756 - 11 -3374.172164165182 - 21 -1257.500104148756 - 0 -LINE - 5 -86C -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1257.700104148709 - 11 -3374.172164165182 - 21 -1257.700104148709 - 0 -LINE - 5 -86D -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1257.900104148721 - 11 -3374.172164165182 - 21 -1257.900104148721 - 0 -LINE - 5 -86E -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1258.100104148732 - 11 -3374.172164165182 - 21 -1258.100104148732 - 0 -LINE - 5 -86F -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3373.422164165182 - 20 -1258.300104148744 - 11 -3374.172164165182 - 21 -1258.300104148744 - 0 -LWPOLYLINE - 5 -870 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3374.172164165182 - 20 -1259.050104148744 - 10 -3374.172164165182 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -871 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3373.322164165089 - 20 -1257.100104148732 - 10 -3373.322164165089 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -872 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3373.322164165089 - 20 -1258.100104148732 - 10 -3373.322164165089 - 20 -1258.300104148744 - 10 -3373.422164165182 - 20 -1258.300104148744 - 10 -3373.422164165182 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -873 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3373.292164165294 - 20 -1257.100104148732 - 10 -3373.292164165294 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -874 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3373.292164165294 - 20 -1258.100104148732 - 10 -3373.292164165294 - 20 -1258.330104148714 - 10 -3373.45216416521 - 20 -1258.330104148714 - 10 -3373.45216416521 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -875 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3373.262164165267 - 20 -1257.100104148732 - 10 -3373.262164165267 - 20 -1257.900104148721 - 0 -LWPOLYLINE - 5 -876 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3373.262164165267 - 20 -1258.100104148732 - 10 -3373.262164165267 - 20 -1258.360104148741 - 10 -3373.482164165238 - 20 -1258.360104148741 - 10 -3373.482164165238 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -877 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3374.172164166812 - 20 -1255.998735667846 - 10 -3374.172164166812 - 20 -1259.280104150704 - 0 -LWPOLYLINE - 5 -878 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3372.342164165108 - 20 -1256.050104161259 - 10 -3372.3421641686 - 20 -1259.280104150704 - 10 -3374.172164166812 - 20 -1259.280104150704 - 0 -LWPOLYLINE - 5 -879 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3372.392164165154 - 20 -1256.050104161259 - 10 -3372.392164165154 - 20 -1259.230104148737 - 10 -3374.172164165182 - 20 -1259.230104148737 - 0 -LWPOLYLINE - 5 -87A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3372.442164165201 - 20 -1256.050104161259 - 10 -3372.442164165201 - 20 -1259.180104148749 - 10 -3374.172164165182 - 20 -1259.180104148749 - 0 -LWPOLYLINE - 5 -87B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3372.572164165089 - 20 -1256.050104161259 - 10 -3372.572164165089 - 20 -1259.050104148744 - 10 -3374.172164165182 - 20 -1259.050104148744 - 0 -LWPOLYLINE - 5 -87C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3374.402164165164 - 20 -1259.280104148725 - 10 -3374.402164165164 - 20 -1255.550104161259 - 0 -LWPOLYLINE - 5 -87D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 30 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3383.539634535555 - 20 -1249.590104149363 - 10 -3384.029634537641 - 20 -1249.590104149363 - 0 -LWPOLYLINE - 5 -87E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3374.402164165164 - 20 -1259.280104148725 - 10 -3384.039634535323 - 20 -1259.280104148725 - 0 -LWPOLYLINE - 5 -87F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3384.039634535555 - 20 -1249.590104149363 - 10 -3384.039634535555 - 20 -1259.280104150704 - 0 -LWPOLYLINE - 5 -880 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3377.575810121838 - 20 -1244.522369963757 - 10 -3377.575810121838 - 20 -1245.052802683494 - 0 -LINE - 5 -881 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3373.050299706403 - 20 -1240.067414091609 - 11 -3373.050299706403 - 21 -1260.721494616649 - 0 -CIRCLE - 5 -882 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbCircle - 10 -3373.050299706403 - 20 -1241.147899744741 - 40 -0.3105759447062155 - 0 -HATCH - 5 -883 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3373.360875650542 - 20 -1241.147899743053 - 11 -3373.050299705937 - 21 -1241.458475687774 - 72 - 1 - 10 -3373.050299705937 - 20 -1241.458475687774 - 11 -3373.050299705937 - 21 -1240.837323798332 - 72 - 1 - 10 -3373.050299705937 - 20 -1240.837323798332 - 11 -3373.360875650542 - 21 -1241.147899743053 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -884 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3373.050299706403 - 20 -1240.837323801301 - 10 -3373.360875649844 - 20 -1241.147899741016 - 10 -3373.050299706403 - 20 -1241.458475688181 - 10 -3373.050299706403 - 20 -1240.837323801301 - 0 -MTEXT - 5 -885 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3373.336266792613 - 20 -1241.193436495552 - 30 -0 - 40 -0.4900000000000003 - 41 -0.3266666666666669 - 71 - 1 - 72 - 5 - 1 -A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -CIRCLE - 5 -886 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbCircle - 10 -3373.050299706403 - 20 -1260.305064083717 - 40 -0.3105759447062155 - 0 -HATCH - 5 -887 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 3 - 72 - 1 - 10 -3373.360875650542 - 20 -1260.305064084648 - 11 -3373.050299705937 - 21 -1260.615640029369 - 72 - 1 - 10 -3373.050299705937 - 20 -1260.615640029369 - 11 -3373.050299705937 - 21 -1259.994488139986 - 72 - 1 - 10 -3373.050299705937 - 20 -1259.994488139986 - 11 -3373.360875650542 - 21 -1260.305064084648 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -888 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3373.050299706403 - 20 -1259.994488125376 - 10 -3373.360875657294 - 20 -1260.305064087442 - 10 -3373.050299706403 - 20 -1260.615640027157 - 10 -3373.050299706403 - 20 -1259.994488125376 - 0 -MTEXT - 5 -889 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3373.336266792613 - 20 -1260.350600837148 - 30 -0 - 40 -0.4900000000000003 - 41 -0.3266666666666669 - 71 - 1 - 72 - 5 - 1 -A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -88A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3374.402164170984 - 20 -1259.280104150704 - 10 -3384.039634535555 - 20 -1259.280104150704 - 10 -3384.039634535555 - 20 -1249.590104149363 - 0 -LWPOLYLINE - 5 -88B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3374.402164165164 - 20 -1259.180104148749 - 10 -3383.939634535229 - 20 -1259.180104148749 - 10 -3383.939634535229 - 20 -1249.590104148723 - 0 -LINE - 5 -88C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3383.539634535555 - 20 -1249.360104148916 - 11 -3383.539634535555 - 21 -1249.590104149363 - 0 -LWPOLYLINE - 5 -88D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3377.575810118579 - 20 -1242.945116815506 - 10 -3380.809634538833 - 20 -1243.423737553589 - 10 -3380.809634538833 - 20 -1243.823737552098 - 10 -3384.039634535555 - 20 -1243.823737552098 - 10 -3384.039634535555 - 20 -1245.238323131285 - 0 -LWPOLYLINE - 5 -88E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3377.575810118579 - 20 -1243.04620614968 - 10 -3380.709634535248 - 20 -1243.510026432865 - 10 -3380.709634535248 - 20 -1243.923737554054 - 10 -3383.939634535229 - 20 -1243.923737554054 - 10 -3383.939634535229 - 20 -1245.238323131343 - 0 -LINE - 5 -88F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3375.389031755272 - 20 -1249.590104149363 - 11 -3384.039634535555 - 21 -1249.590104149363 - 0 -HATCH - 5 -890 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3374.402164165164 - 20 -1258.780104148725 - 11 -3374.402164165164 - 21 -1259.280104148725 - 72 - 1 - 10 -3374.402164165164 - 20 -1259.280104148725 - 11 -3374.172164165182 - 21 -1259.280104148725 - 72 - 1 - 10 -3374.172164165182 - 20 -1259.280104148725 - 11 -3374.172164165182 - 21 -1258.780104148725 - 72 - 1 - 10 -3374.172164165182 - 20 -1258.780104148725 - 11 -3374.402164165164 - 21 -1258.780104148725 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -891 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3374.172164166812 - 20 -1259.280104150704 - 10 -3374.402164170984 - 20 -1259.280104150704 - 10 -3374.402164165164 - 20 -1258.780104148725 - 10 -3374.172164166812 - 20 -1258.780104150704 - 10 -3374.172164166812 - 20 -1259.280104150704 - 0 -HATCH - 5 -892 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3374.172164165182 - 20 -1256.050104161259 - 11 -3374.172164165182 - 21 -1255.550104161259 - 72 - 1 - 10 -3374.172164165182 - 20 -1255.550104161259 - 11 -3374.402164165164 - 21 -1255.550104161259 - 72 - 1 - 10 -3374.402164165164 - 20 -1255.550104161259 - 11 -3374.402164165164 - 21 -1256.050104161259 - 72 - 1 - 10 -3374.402164165164 - 20 -1256.050104161259 - 11 -3374.172164165182 - 21 -1256.050104161259 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -893 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3374.402164170984 - 20 -1255.550104161433 - 10 -3374.172164166812 - 20 -1255.550104161433 - 10 -3374.172164165182 - 20 -1256.050104161259 - 10 -3374.402164165164 - 20 -1256.050104161259 - 10 -3374.402164165164 - 20 -1255.550104161259 - 0 -HATCH - 5 -894 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANGLE - 70 - 0 - 71 - 0 - 91 - 2 - 92 - 0 - 93 - 6 - 72 - 1 - 10 -3383.939634535229 - 20 -1259.180104148749 - 11 -3374.402164165164 - 21 -1259.180104148749 - 72 - 1 - 10 -3374.402164165164 - 20 -1259.180104148749 - 11 -3374.402164165164 - 21 -1258.780104148725 - 72 - 1 - 10 -3374.402164165164 - 20 -1258.780104148725 - 11 -3374.402164165164 - 21 -1249.590104148723 - 72 - 1 - 10 -3374.402164165164 - 20 -1249.590104148723 - 11 -3375.389031757601 - 21 -1249.590104148723 - 72 - 1 - 10 -3375.389031757601 - 20 -1249.590104148723 - 11 -3383.939634535229 - 21 -1249.590104148723 - 72 - 1 - 10 -3383.939634535229 - 20 -1249.590104148723 - 11 -3383.939634535229 - 21 -1259.180104148749 - 97 - 0 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3375.839075485012 - 20 -1252.165106727509 - 11 -3381.418439672329 - 21 -1252.121452173392 - 72 - 1 - 10 -3381.418439672096 - 20 -1252.121452173392 - 11 -3381.426624931628 - 21 -1253.167586872005 - 72 - 1 - 10 -3381.426624931628 - 20 -1253.167586871947 - 11 -3375.847260744311 - 21 -1253.211241426062 - 72 - 1 - 10 -3375.847260744544 - 20 -1253.211241426062 - 11 -3375.839075485012 - 21 -1252.16510672745 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -1.5 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -MTEXT - 5 -895 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3375.995849914151 - 20 -1252.932892533427 - 30 -0 - 40 -0.4900000000000003 - 41 -4.831944444444448 - 71 - 1 - 72 - 5 - 1 -OPEN TERRACE - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -896 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3372.3421641686 - 20 -1255.550104161433 - 10 -3372.572164165323 - 20 -1255.550104161433 - 0 -LWPOLYLINE - 5 -897 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3373.472164171282 - 20 -1255.550104161433 - 10 -3374.402164170984 - 20 -1255.550104161433 - 0 -LWPOLYLINE - 5 -898 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3372.342164165108 - 20 -1255.650104161235 - 10 -3372.572164165089 - 20 -1255.650104161235 - 0 -LWPOLYLINE - 5 -899 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 7 - 70 - 0 - 43 -0 - 10 -3383.889951367848 - 20 -1245.388153112131 - 10 -3377.425810118672 - 20 -1245.388323131366 - 10 -3377.425810118672 - 20 -1242.822369963012 - 10 -3375.912164165173 - 20 -1242.822369963012 - 10 -3375.912164165173 - 20 -1242.402369962656 - 10 -3372.492164165247 - 20 -1242.402369962656 - 10 -3372.492164165247 - 20 -1255.550104161259 - 0 -LWPOLYLINE - 5 -89A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3374.402164170984 - 20 -1255.550104161433 - 10 -3374.402164170984 - 20 -1249.590104149363 - 10 -3384.039634535555 - 20 -1249.590104149363 - 10 -3384.039634535555 - 20 -1245.238323131285 - 0 -LWPOLYLINE - 5 -89B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3374.252164165259 - 20 -1255.550104161259 - 10 -3374.252164165259 - 20 -1249.440104148758 - 10 -3383.8895990575 - 20 -1249.440104148758 - 10 -3383.891145760948 - 20 -1245.95238262658 - 0 -LWPOLYLINE - 5 -89C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3372.3421641686 - 20 -1255.550104161433 - 10 -3372.3421641686 - 20 -1241.721707736782 - 10 -3372.572164165323 - 20 -1241.721707736782 - 10 -3372.572164165323 - 20 -1242.252369960479 - 0 -LWPOLYLINE - 5 -89D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 0 - 43 -0 - 10 -3372.3421641686 - 20 -1255.550104161433 - 10 -3372.3421641686 - 20 -1242.154635777406 - 10 -3372.572164165323 - 20 -1242.154635777406 - 10 -3372.572164165323 - 20 -1242.252369960479 - 10 -3376.002164172474 - 20 -1242.252369960479 - 10 -3376.04216417158 - 20 -1242.252369960479 - 10 -3376.062164167408 - 20 -1242.252369960479 - 10 -3376.062164167408 - 20 -1242.722369963012 - 0 -LINE - 5 -89E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3373.472164171282 - 20 -1255.550104161433 - 11 -3372.572164165323 - 21 -1255.550104161433 - 0 -MTEXT - 5 -89F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3283.061831855216 - 20 -1235.06983288523 - 30 -0 - 40 -0.4900000000000003 - 41 -8.234722118341177 - 71 - 1 - 72 - 5 - 1 -BASEMENT FLOOR PLAN - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8A0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3300.488247429719 - 20 -1235.06983288523 - 30 -0 - 40 -0.4900000000000003 - 41 -7.363611111111177 - 71 - 1 - 72 - 5 - 1 -GROUND FLOOR PLAN - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8A1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3316.827640795847 - 20 -1235.06983288523 - 30 -0 - 40 -0.4900000000000003 - 41 -6.60138878500784 - 71 - 1 - 72 - 5 - 1 -FIRST FLOOR PLAN - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8A2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3352.992303687148 - 20 -1235.06983288523 - 30 -0 - 40 -0.4900000000000003 - 41 -6.887222118341204 - 71 - 1 - 72 - 5 - 1 -SECOND FLOOR PLAN - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8A3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3375.789232264273 - 20 -1235.06983288523 - 30 -0 - 40 -0.4900000000000003 - 41 -7.322777777777783 - 71 - 1 - 72 - 5 - 1 -TERRACE FLOOR PLAN - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -LINE - 5 -8A4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3402.461395606632 - 20 -1238.89051844005 - 11 -3402.461395606632 - 21 -1236.271455681242 - 0 -LINE - 5 -8A5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3392.995761112077 - 20 -1237.146906384849 - 11 -3402.461395606632 - 21 -1237.146906384849 - 0 -LINE - 5 -8A6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3392.995761112077 - 20 -1236.271455681242 - 11 -3402.461395606632 - 21 -1236.271455681242 - 0 -TEXT - 5 -8A7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbText - 10 -3393.180831600912 - 20 -1236.521544189367 - 30 -0 - 40 -0.4857686858836294 - 1 -RS - 50 -0 - 41 -1 - 51 -0 - 7 -sree - 71 - 0 -210 -0 -220 -0 -230 -1 -100 -AcDbText - 0 -MTEXT - 5 -8A8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3395.870399698615 - 20 -1237.882763578906 - 30 -0 - 40 -0.4857686858836294 - 41 -1.997048835998051 - 71 - 1 - 72 - 5 - 1 -GLASS - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -LINE - 5 -8A9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3392.995761112077 - 20 -1238.89051844005 - 11 -3402.461395606632 - 21 -1238.89051844005 - 0 -LINE - 5 -8AA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3392.995761112077 - 20 -1238.89051844005 - 11 -3392.995761112077 - 21 -1236.271455681242 - 0 -MTEXT - 5 -8AB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - -1 -100 -AcDbMText - 10 -3394.543313582195 - 20 -1238.775882851973 - 30 -0 - 40 -0.492075 - 41 -4.538024895679042 - 71 - 1 - 72 - 5 - 1 -SPECIFICATION - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8AC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3393.152249841718 - 20 -1237.882763578906 - 30 -0 - 40 -0.4857686858836294 - 41 -0.269871492157602 - 71 - 1 - 72 - 5 - 1 -G - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -TEXT - 5 -8AD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbText - 10 -3395.910303766374 - 20 -1236.521544189367 - 30 -0 - 40 -0.4857686858836294 - 1 -ROLLING SHUTTER - 50 -0 - 41 -1 - 51 -0 - 7 -sree - 71 - 0 -210 -0 -220 -0 -230 -1 -100 -AcDbText - 0 -LINE - 5 -8AE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3395.251624739031 - 20 -1238.022357088455 - 11 -3395.251624739031 - 21 -1236.271455681242 - 0 -LINE - 5 -8AF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3392.995761112077 - 20 -1238.022357088455 - 11 -3402.461395606632 - 21 -1238.022357088455 - 0 -LINE - 5 -8B0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3403.873485771474 - 20 -1251.320821476576 - 11 -3403.873485771474 - 21 -1240.039741707151 - 0 -LINE - 5 -8B1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1249.920970887702 - 11 -3403.873485771474 - 21 -1249.920970887702 - 0 -LINE - 5 -8B2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1248.509366719052 - 11 -3403.873485771474 - 21 -1248.509366719052 - 0 -LINE - 5 -8B3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1252.720672065392 - 11 -3403.873485771474 - 21 -1252.720672065392 - 0 -LINE - 5 -8B4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1251.320821476576 - 11 -3389.961759146769 - 21 -1240.039741707151 - 0 -MTEXT - 5 -8B5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - -1 -100 -AcDbMText - 10 -3394.439554924146 - 20 -1251.090687079879 - 30 -0 - 40 -0.7934371614720003 - 41 -9.058407425261716 - 71 - 1 - 72 - 5 - 1 -JOINERY DETAILS - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8B6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3390.218430102339 - 20 -1249.772946545738 - 30 -0 - 40 -0.7832686628247535 - 41 -0.4351492571249116 - 71 - 1 - 72 - 5 - 1 -D - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8B7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3392.294592137914 - 20 -1249.623572336684 - 30 -0 - 40 -0.7832686628247535 - 41 -12.05363409024947 - 71 - 1 - 72 - 5 - 1 -SINGLE SHUTTER DOOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -LINE - 5 -8B8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3391.983519680565 - 20 -1249.920970887702 - 11 -3391.983519680565 - 21 -1240.039741707151 - 0 -LINE - 5 -8B9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3400.016167183407 - 20 -1249.920970887702 - 11 -3400.016167183407 - 21 -1240.039741707151 - 0 -LINE - 5 -8BA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1247.097762550402 - 11 -3403.873485771474 - 21 -1247.097762550402 - 0 -LINE - 5 -8BB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1245.686158381752 - 11 -3403.873485771474 - 21 -1245.686158381752 - 0 -LINE - 5 -8BC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1244.274554213101 - 11 -3403.873485771474 - 21 -1244.274554213101 - 0 -LINE - 5 -8BD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1242.862950044451 - 11 -3403.873485771474 - 21 -1242.862950044451 - 0 -MTEXT - 5 -8BE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3390.218430102339 - 20 -1248.361342377087 - 30 -0 - 40 -0.7832686628247535 - 41 -0.8702985142497746 - 71 - 1 - 72 - 5 - 1 -D1 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8BF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3390.218430102339 - 20 -1246.949738208437 - 30 -0 - 40 -0.7832686628247535 - 41 -1.04435821709972 - 71 - 1 - 72 - 5 - 1 -D2 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8C0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3390.218430102339 - 20 -1244.126529871137 - 30 -0 - 40 -0.7832686628247535 - 41 -1.827626879924473 - 71 - 1 - 72 - 5 - 1 -GW1 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8C1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3390.218430102339 - 20 -1242.714925702486 - 30 -0 - 40 -0.7832686628247535 - 41 -0.5221791085498356 - 71 - 1 - 72 - 5 - 1 -V - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8C2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3392.294592137914 - 20 -1248.211968168034 - 30 -0 - 40 -0.7832686628247535 - 41 -12.05363409024947 - 71 - 1 - 72 - 5 - 1 -SINGLE SHUTTER DOOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8C3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3392.294592137914 - 20 -1246.800363999384 - 30 -0 - 40 -0.7832686628247535 - 41 -12.05363409024947 - 71 - 1 - 72 - 5 - 1 -SINGLE SHUTTER DOOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8C4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3392.294592137914 - 20 -1242.565551493433 - 30 -0 - 40 -0.7832686628247535 - 41 -6.266149302598027 - 71 - 1 - 72 - 5 - 1 -VENTILATOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8C5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3392.294592137914 - 20 -1243.977155662083 - 30 -0 - 40 -0.7832686628247535 - 41 -8.072018387557025 - 71 - 1 - 72 - 5 - 1 -GLASS WINDOW - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8C6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3390.218430102339 - 20 -1245.538134039787 - 30 -0 - 40 -0.7832686628247535 - 41 -1.827626879924473 - 71 - 1 - 72 - 5 - 1 -D2A - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8C7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3392.294592137914 - 20 -1245.388759830734 - 30 -0 - 40 -0.7832686628247535 - 41 -12.48878351342902 - 71 - 1 - 72 - 5 - 1 -DOUBLE SHUTTER DOOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -LINE - 5 -8C8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1241.451345875801 - 11 -3403.873485771474 - 21 -1241.451345875801 - 0 -LINE - 5 -8C9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1240.039741707151 - 11 -3403.873485771474 - 21 -1240.039741707151 - 0 -MTEXT - 5 -8CA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3390.218430102339 - 20 -1241.303321533836 - 30 -0 - 40 -0.7832686628247535 - 41 -0.9573283656746986 - 71 - 1 - 72 - 5 - 1 -V1 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8CB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3392.294592137914 - 20 -1241.153947324783 - 30 -0 - 40 -0.7832686628247535 - 41 -6.266149302598027 - 71 - 1 - 72 - 5 - 1 -VENTILATOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8CC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3400.637843515724 - 20 -1246.800363999384 - 30 -0 - 40 -0.7832686628247535 - 41 -3.394164205573932 - 71 - 1 - 72 - 5 - 1 -80X210 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8CD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3400.637843515724 - 20 -1245.388759830734 - 30 -0 - 40 -0.7832686628247535 - 41 -3.829313462698794 - 71 - 1 - 72 - 5 - 1 -120X210 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8CE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3400.637843515724 - 20 -1243.977155662083 - 30 -0 - 40 -0.7832686628247535 - 41 -4.090403016973712 - 71 - 1 - 72 - 5 - 1 -420X120 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8CF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3400.637843515724 - 20 -1242.565551493433 - 30 -0 - 40 -0.7832686628247535 - 41 -3.39416420557398 - 71 - 1 - 72 - 5 - 1 -100X60 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8D0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3400.637843515724 - 20 -1241.153947324783 - 30 -0 - 40 -0.7832686628247535 - 41 -2.959014948449117 - 71 - 1 - 72 - 5 - 1 -80X60 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -LINE - 5 -8D1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3403.873485771474 - 20 -1262.590147666109 - 11 -3403.873485771474 - 21 -1252.720672065392 - 0 -LINE - 5 -8D2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.29848577152 - 20 -1261.190297077293 - 11 -3403.873485771474 - 21 -1261.190297077293 - 0 -LINE - 5 -8D3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbLine - 10 -3389.29848577152 - 20 -1259.778692908643 - 11 -3403.873485771474 - 21 -1259.778692908643 - 0 -LINE - 5 -8D4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.29848577152 - 20 -1262.590147666109 - 11 -3403.873485771474 - 21 -1262.590147666109 - 0 -LINE - 5 -8D5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.29848577152 - 20 -1262.590147666109 - 11 -3389.29848577152 - 21 -1252.720672065392 - 0 -MTEXT - 5 -8D6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - -1 -100 -AcDbMText - 10 -3393.863485771464 - 20 -1262.360013269412 - 30 -0 - 40 -0.7934371614720003 - 41 -7.647852471533669 - 71 - 1 - 72 - 5 - 1 -AREA DETAILS - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8D7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3389.515393301612 - 20 -1261.042272735329 - 30 -0 - 40 -0.7832686628247535 - 41 -3.046044799874041 - 71 - 1 - 72 - 5 - 1 -FLOOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8D8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3396.669611776946 - 20 -1260.892898526275 - 30 -0 - 40 -0.7832686628247535 - 41 -1.653567003014777 - 71 - 1 - 72 - 5 - 1 -(M)² - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8D9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3400.525844009593 - 20 -1260.716449584055 - 30 -0 - 40 -0.6 - 41 -2.783333206132044 - 71 - 1 - 72 - 5 - 1 -SQ .FT. - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -LINE - 5 -8DA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3395.685985771474 - 20 -1261.190297077293 - 11 -3395.685985771474 - 21 -1252.720672065392 - 0 -LINE - 5 -8DB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3399.890535136917 - 20 -1261.190297077293 - 11 -3399.890535136917 - 21 -1252.720672065392 - 0 -LINE - 5 -8DC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.29848577152 - 20 -1258.367088739993 - 11 -3403.873485771474 - 21 -1258.367088739993 - 0 -LINE - 5 -8DD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.29848577152 - 20 -1256.955484571343 - 11 -3403.873485771474 - 21 -1256.955484571343 - 0 -LINE - 5 -8DE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.29848577152 - 20 -1255.543880402692 - 11 -3403.873485771474 - 21 -1255.543880402692 - 0 -LINE - 5 -8DF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.29848577152 - 20 -1254.132276234042 - 11 -3403.873485771474 - 21 -1254.132276234042 - 0 -LINE - 5 -8E0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.29848577152 - 20 -1252.720672065392 - 11 -3403.873485771474 - 21 -1252.720672065392 - 0 -MTEXT - 5 -8E1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3389.484574149598 - 20 -1253.981169540319 - 30 -0 - 40 -0.7832686628247535 - 41 -12.01011949664632 - 71 - 1 - 72 - 5 - 1 -TOTAL AREA \H1.305x; - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8E2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3389.515393301612 - 20 -1259.630668566679 - 30 -0 - 40 -0.7832686628247535 - 41 -9.203406622136212 - 71 - 1 - 72 - 5 - 1 -BASEMENT FLOOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8E3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3389.515393301612 - 20 -1258.219064398028 - 30 -0 - 40 -0.7832686628247535 - 41 -7.810929165391389 - 71 - 1 - 72 - 5 - 1 -GROUND FLOOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8E4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3389.515393301612 - 20 -1256.807460229378 - 30 -0 - 40 -0.7832686628247535 - 41 -6.592511079387035 - 71 - 1 - 72 - 5 - 1 -FIRST FLOOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8E5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3389.515393301612 - 20 -1255.395856060728 - 30 -0 - 40 -0.7832686628247535 - 41 -7.636869296486754 - 71 - 1 - 72 - 5 - 1 -SECOND FLOOR - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8E6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3400.637843515724 - 20 -1249.623572336684 - 30 -0 - 40 -0.7832686628247535 - 41 -3.829313462698794 - 71 - 1 - 72 - 5 - 1 -100X210 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8E7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3400.637843515724 - 20 -1248.211968168034 - 30 -0 - 40 -0.7832686628247535 - 41 -3.39416420557398 - 71 - 1 - 72 - 5 - 1 -90X210 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -LINE - 5 -8E8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3389.961759146769 - 20 -1251.320821476576 - 11 -3403.873485771474 - 21 -1251.320821476576 - 0 -LWPOLYLINE - 5 -8E9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3204.645300902426 - 20 -1297.791080966592 - 10 -3512.634034834802 - 20 -1297.791080966592 - 10 -3512.634034834802 - 20 -1170.354015154764 - 10 -3204.645300902426 - 20 -1170.354015154764 - 0 -LWPOLYLINE - 5 -8EA -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 13 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3672.274958058858 - 20 -1102.020476120804 - 10 -3698.046045772997 - 20 -1107.029812435309 - 10 -3711.150773975219 - 20 -1109.577085239756 - 10 -3734.342027092429 - 20 -1114.084958081897 - 0 -LWPOLYLINE - 5 -8EB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3672.503926400916 - 20 -1100.842523023958 - 10 -3698.275014115051 - 20 -1105.851859338477 - 10 -3711.379742317273 - 20 -1108.399132142923 - 10 -3734.570995434026 - 20 -1112.907004984988 - 0 -LWPOLYLINE - 5 -8EC -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 5 -370 - 30 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3672.732894742511 - 20 -1099.664569927048 - 10 -3698.503982456645 - 20 -1104.673906241568 - 10 -3711.608710659329 - 20 -1107.221179046091 - 10 -3734.79996377608 - 20 -1111.729051888156 - 0 -LWPOLYLINE - 5 -8ED -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3672.732894742511 - 20 -1099.664569927048 - 10 -3698.535822601603 - 20 -1104.680095269986 - 10 -3711.583342462243 - 20 -1107.216248022903 - 10 -3734.79996377608 - 20 -1111.729051888156 - 0 -LWPOLYLINE - 5 -8EE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3674.266571524048 - 20 -1090.284878494705 - 10 -3700.474522549609 - 20 -1095.379131490835 - 10 -3713.295592722377 - 20 -1097.871267372712 - 10 -3736.793186846377 - 20 -1102.438686212563 - 0 -DIMENSION - 5 -8EF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D9 - 10 -3711.230201477702 - 20 -1109.216627534068 - 30 -0 - 11 -3704.648994248611 - 21 -1108.067294854499 - 31 -0 - 70 - 33 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3698.036505425412 - 23 -1107.07889381435 - 33 -0 - 14 -3711.150255169002 - 24 -1109.627920209303 - 34 -0 - 0 -DIMENSION - 5 -8F0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D10 - 10 -3713.217161291157 - 20 -1133.099397961581 - 30 -0 - 11 -3713.464588759269 - 21 -1121.35131122986 - 31 -0 - 70 - 33 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3711.150773975219 - 23 -1109.577085239756 - 33 -0 - 14 -3710.910952621411 - 24 -1133.075861498266 - 34 -0 - 0 -DIMENSION - 5 -8F1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D11 - 10 -3710.921396379202 - 20 -1133.764259275178 - 30 -0 - 11 -3706.148880246726 - 21 -1133.964201744781 - 31 -0 - 70 - 33 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3701.362051457872 - 23 -1133.220728919789 - 33 -0 - 14 -3710.910952621411 - 24 -1133.075861498266 - 34 -0 - 0 -DIMENSION - 5 -8F2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D12 - 10 -3698.046045772998 - 20 -1107.029812435309 - 30 -0 - 11 -3699.577535147486 - 21 -1120.141288420921 - 31 -0 - 70 - 33 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3701.362051457872 - 23 -1133.220728919789 - 33 -0 - 14 -3698.046045772997 - 24 -1107.029812435309 - 34 -0 - 0 -DIMENSION - 5 -8F3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D13 - 10 -3710.910953230301 - 20 -1133.06586149814 - 30 -0 - 11 -3704.36416309136 - 21 -1120.099311220429 - 31 -0 - 70 - 33 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3698.046046381595 - 23 -1107.019812435327 - 33 -0 - 14 -3710.910953230009 - 24 -1133.065861498284 - 34 -0 - 0 -MTEXT - 5 -8F4 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3712.323898692514 - 20 -1133.91149679323 - 30 -0 - 40 -0.68 - 41 -5.213333333333333 - 71 - 5 - 72 - 1 - 1 -\W0.8;\C7;A - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8F5 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3701.773331511015 - 20 -1134.48415198065 - 30 -0 - 40 -0.68 - 41 -5.137777777777778 - 71 - 5 - 72 - 1 - 1 -\W0.8;\C7;B - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -8F6 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3697.726812683696 - 20 -1106.181686485057 - 30 -0 - 40 -0.68 - 41 -5.062222222222222 - 71 - 5 - 72 - 1 - 1 -\W0.8;\C7;C - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -DIMENSION - 5 -8F7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D14 - 10 -3707.769716797048 - 20 -1107.700478565418 - 30 -0 - 11 -3707.792422192403 - 21 -1108.337826670716 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3707.650442678567 - 23 -1108.947633137341 - 33 -0 - 14 -3707.882337505863 - 24 -1107.719313071169 - 34 -0 - 50 -99.49419111659763 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -8F8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D15 - 10 -3707.883887015795 - 20 -1106.500234520827 - 30 -0 - 11 -3707.910477738811 - 21 -1107.114350354412 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3707.764369543838 - 23 -1107.699584299413 - 33 -0 - 14 -3707.997366203883 - 24 -1106.519212597268 - 34 -0 - 50 -99.49419111659763 -100 -AcDbRotatedDimension - 0 -LWPOLYLINE - 5 -8F9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3902.410987750695 - 20 -1301.511978900197 - 10 -3908.645015031192 - 20 -1317.660538005052 - 10 -3919.79417200274 - 20 -1304.419114605728 - 10 -3902.410987750695 - 20 -1301.511978900197 - 0 -LWPOLYLINE - 5 -8FA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3907.964280239541 - 20 -1302.440702581859 - 10 -3913.795947310683 - 20 -1303.415981179812 - 10 -3916.251905305514 - 20 -1288.730608818905 - 10 -3910.420238234371 - 20 -1287.755330220952 - 0 -MTEXT - 5 -8FB -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3915.837736036229 - 20 -1277.818292432038 - 30 -0 - 40 -17 - 41 -128.4444444444445 - 71 - 5 - 72 - 1 - 1 -\W0.8;\C7;N - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LINE - 5 -8FC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3663.245809017876 - 20 -1160.995536376621 - 11 -3672.669210381117 - 21 -1099.652191078797 - 0 -LINE - 5 -8FD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3674.057129834356 - 20 -1091.466627146058 - 11 -3679.859521877605 - 21 -1056.771291184111 - 0 -LINE - 5 -8FE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3650.917277298526 - 20 -1157.080735647538 - 11 -3668.042934631451 - 21 -1054.678066143961 - 0 -LINE - 5 -8FF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3621.930008000513 - 20 -1254.46536760834 - 11 -3663.99190321545 - 21 -1052.405737075454 - 0 -LINE - 5 -900 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3662.37448808464 - 20 -1052.133037315658 - 11 -3619.794049828615 - 21 -1252.689056581804 - 0 -LINE - 5 -901 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3616.773343549434 - 20 -1252.154285308986 - 11 -3658.815639063021 - 21 -1051.533007518213 - 0 -LINE - 5 -902 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3657.136829126123 - 20 -1051.249956458653 - 11 -3614.717015578778 - 21 -1251.400859422596 - 0 -TEXT - 5 -903 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbText - 10 -3650.532340746764 - 20 -1103.953173562304 - 30 -0 - 40 -1.657499999999999 - 1 -RAILWAY TRACK - 50 -102.8084861050996 - 41 -1 - 51 -0 - 7 -title1 - 71 - 0 -210 -0 -220 -0 -230 -1 -100 -AcDbText - 0 -LWPOLYLINE - 5 -904 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3734.045064322938 - 20 -1115.532748664855 - 10 -3735.513223449404 - 20 -1108.374992958203 - 10 -3737.183521288859 - 20 -1108.654330875672 - 10 -3734.523073473556 - 20 -1107.097492335758 - 10 -3735.812381152563 - 20 -1106.916501354847 - 10 -3737.466308103384 - 20 -1099.179022704292 - 0 -LWPOLYLINE - 5 -905 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3734.289965661031 - 20 -1115.582981468166 - 10 -3735.709697833853 - 20 -1108.661322993018 - 10 -3738.48306120235 - 20 -1109.125135810973 - 10 -3735.270236731759 - 20 -1107.245057980108 - 10 -3736.020305085218 - 20 -1107.139764566295 - 10 -3737.710785243486 - 20 -1099.231280984955 - 0 -ARC - 5 -906 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbCircle - 10 -3818.945751805638 - 20 -1144.502502475059 - 40 -168.498605913861 -100 -AcDbArc - 50 -165.8980910274046 - 51 -175.7189518822834 - 0 -LWPOLYLINE - 5 -907 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3715.527812990941 - 20 -1117.558899958314 - 10 -3721.394442062317 - 20 -1118.540025544813 - 10 -3719.024216116146 - 20 -1132.712764114562 - 10 -3713.157587044769 - 20 -1131.731638528063 - 0 -LWPOLYLINE - 5 -908 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3724.30195298597 - 20 -1119.259218588376 - 10 -3730.168582057345 - 20 -1120.240344174874 - 10 -3727.798356111176 - 20 -1134.413082744609 - 10 -3721.9317270398 - 20 -1133.43195715811 - 0 -LWPOLYLINE - 5 -909 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3700.343149125929 - 20 -1092.025307210313 - 10 -3709.849342566172 - 20 -1093.615107673399 - 10 -3710.836675324316 - 20 -1087.711362891115 - 10 -3701.330481884074 - 20 -1086.121562428029 - 0 -LWPOLYLINE - 5 -90A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3687.924933325221 - 20 -1090.476234095497 - 10 -3697.431126765005 - 20 -1092.066034558506 - 10 -3698.418459523152 - 20 -1086.162289776208 - 10 -3688.912266083369 - 20 -1084.572489313198 - 0 -LWPOLYLINE - 5 -90B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3715.520024993609 - 20 -1095.503398078453 - 10 -3725.026218433391 - 20 -1097.093198541463 - 10 -3726.013551191539 - 20 -1091.189453759165 - 10 -3716.507357751758 - 20 -1089.599653296155 - 0 -LWPOLYLINE - 5 -90C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3730.111157028579 - 20 -1097.400565809753 - 10 -3739.617350468821 - 20 -1098.990366272839 - 10 -3740.604683226966 - 20 -1093.086621490555 - 10 -3731.098489786725 - 20 -1091.496821027469 - 0 -MTEXT - 5 -90D -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - -1 -100 -AcDbMText - 10 -3683.251112048439 - 20 -1114.12964576591 - 30 -0 - 40 -0.4875 - 41 -6.093750000000153 - 71 - 7 - 72 - 5 - 1 -\pi3.93533;VENKAY\P\pi3.99469; TOWER - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -90E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3710.831567484591 - 20 -1121.009345265736 - 30 -0 - 40 -0.6375000000000001 - 41 -10.07604166666675 - 71 - 7 - 72 - 5 - 1 -\pi3.91991;EXT BUILDING \P\pi4.81919;LEE FOOT - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -90F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3719.626778997 - 20 -1122.835452260726 - 30 -0 - 40 -0.6375000000000001 - 41 -8.252083333333415 - 71 - 7 - 72 - 5 - 1 -\pi6.1779;EXT \P\pi4.90986;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -910 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3727.780280034512 - 20 -1093.017050375303 - 30 -0 - 40 -0.75 - 41 -13.10416666666667 - 71 - 7 - 72 - 5 - 1 -\pi6.5171;HOTEL \P\pi4.40907;ARYA BHAVAN - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -911 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - -1 -100 -AcDbMText - 10 -3698.069957093073 - 20 -1087.615453141374 - 30 -0 - 40 -0.75 - 41 -7.791666666666852 - 71 - 7 - 72 - 5 - 1 -\pi6.84836;HDFC \P\pi6.7642;BANK - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -912 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3685.768474956669 - 20 -1086.011476629512 - 30 -0 - 40 -0.75 - 41 -10.60416666666676 - 71 - 7 - 72 - 5 - 1 -\pi5.48521;CITY MALL - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -913 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3712.784151652958 - 20 -1091.392069092912 - 30 -0 - 40 -0.75 - 41 -9.791666666666806 - 71 - 7 - 72 - 5 - 1 -\pi5.92186;FATHIMA \P\pi5.67322;COMPLEX - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -914 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3677.098770806683 - 20 -1044.045040395329 - 30 -0 - 40 -2.486249999999999 - 41 -57.94343697290994 - 71 - 7 - 72 - 5 - 1 -\pi13.76172; TO RAILWAY STATION - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -99.98548591323963 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -915 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3666.374137997014 - 20 -1109.409636466498 - 30 -0 - 40 -2.486249999999999 - 41 -48.62000000000014 - 71 - 7 - 72 - 5 - 1 -\pi17.87438; TO MANANCHIRA - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -99.9854859132396 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -916 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3653.116060949333 - 20 -1050.572046072458 - 10 -3667.774039996447 - 20 -1053.043413681799 - 10 -3668.698795209776 - 20 -1058.665144988168 - 10 -3672.173384880478 - 20 -1050.022186411365 - 10 -3673.141891634795 - 20 -1055.150948849436 - 10 -3683.410463330815 - 20 -1057.627804650409 - 0 -LWPOLYLINE - 5 -917 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3612.769074736673 - 20 -1250.687145911562 - 10 -3617.020982355601 - 20 -1252.245018640379 - 10 -3617.670522814061 - 20 -1255.217242955204 - 10 -3619.401430566409 - 20 -1251.721848409485 - 10 -3620.300663649409 - 20 -1253.937087626049 - 10 -3623.7785897269 - 20 -1255.064730610394 - 0 -INSERT - 5 -918 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 5 -370 - -1 -100 -AcDbBlockReference - 2 -WELL10 - 10 -3698.046045772997 - 20 -1107.029812435309 - 30 -0 - 41 -1 - 42 -1 - 43 -0 - 50 -9.494191116597097 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -919 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 5 -370 - -1 -100 -AcDbBlockReference - 2 -WELL10 - 10 -3711.399878877084 - 20 -1109.619960983812 - 30 -0 - 41 -1 - 42 -1 - 43 -0 - 50 -9.494191116597097 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -91A -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 5 -370 - -1 -100 -AcDbBlockReference - 2 -WELL10 - 10 -3686.53303422432 - 20 -1104.467213811765 - 30 -0 - 41 -1 - 42 -1 - 43 -0 - 50 -9.494191116597097 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -91B -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 5 -370 - -1 -100 -AcDbBlockReference - 2 -WELL10 - 10 -3715.05218281703 - 20 -1097.489077892062 - 30 -0 - 41 -1 - 42 -1 - 43 -0 - 50 -9.494191116597097 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -MTEXT - 5 -91C -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - -1 -100 -AcDbMText - 10 -3679.544715149916 - 20 -1103.254248217038 - 30 -0 - 40 -0.4875 - 41 -9.005208333333394 - 71 - 7 - 72 - 5 - 1 -\pi2.64974;PYRA 021025008 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -91D -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - -1 -100 -AcDbMText - 10 -3689.581212828417 - 20 -1105.779364616607 - 30 -0 - 40 -0.4875 - 41 -8.951041666666756 - 71 - 7 - 72 - 5 - 1 -\pi2.64958;PYRA 021025007 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -91E -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - -1 -100 -AcDbMText - 10 -3707.31302465503 - 20 -1108.040408999108 - 30 -0 - 40 -0.4875 - 41 -8.788541666666788 - 71 - 7 - 72 - 5 - 1 -\pi2.65157;PYRA 021025002 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -91F -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - -1 -100 -AcDbMText - 10 -3706.732580925164 - 20 -1095.66068097573 - 30 -0 - 40 -0.4875 - 41 -8.951041666666757 - 71 - 7 - 72 - 5 - 1 -\pi2.64908;PYRA 021025003 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -920 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3711.273699996203 - 20 -1118.425295046578 - 30 -0 - 40 -0.6375000000000001 - 41 -7.897916666666905 - 71 - 7 - 72 - 5 - 1 -\pi5.42756;61/4736 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -921 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3720.192266075204 - 20 -1120.260175708412 - 30 -0 - 40 -0.6375000000000001 - 41 -6.977083333333533 - 71 - 7 - 72 - 5 - 1 -\pi5.67521;7/1166 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -ARC - 5 -922 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbCircle - 10 -3696.917764457168 - 20 -1163.455614783708 - 40 -33.76170269503877 -100 -AcDbArc - 50 -145.9430062472594 - 51 -184.17861443943 - 0 -LWPOLYLINE - 5 -923 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3734.720354382054 - 20 -1114.158496639986 - 10 -3738.686929918392 - 20 -1115.844574412406 - 10 -3747.207562453121 - 20 -1127.42575798961 - 10 -3737.984766603963 - 20 -1184.359010964738 - 10 -3668.946837908695 - 20 -1182.362751978026 - 0 -LWPOLYLINE - 5 -924 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3655.525037135472 - 20 -1185.556737477315 - 10 -3661.933689675147 - 20 -1239.604914529362 - 10 -3658.703168783311 - 20 -1265.862401451442 - 0 -LWPOLYLINE - 5 -925 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 9 - 70 - 0 - 43 -0 - 10 -3742.066222901291 - 20 -1254.329491668528 - 10 -3819.194022095526 - 20 -1161.743556749656 - 10 -3819.194022095526 - 20 -1161.743556749656 - 10 -3776.239488607737 - 20 -1132.452708329507 - 10 -3758.509204227333 - 20 -1131.852486874133 - 10 -3748.595375559345 - 20 -1195.614530581304 - 10 -3673.269371679385 - 20 -1193.436449416088 - 10 -3673.114885321725 - 20 -1244.148526421946 - 10 -3669.288083184822 - 20 -1268.660956136343 - 0 -LWPOLYLINE - 5 -926 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3755.835392925514 - 20 -1264.313243891627 - 10 -3810.771350095322 - 20 -1197.481873112261 - 0 -LWPOLYLINE - 5 -927 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3827.40763642424 - 20 -1177.910735801946 - 10 -3832.929692907018 - 20 -1171.458535321766 - 10 -3894.524955233329 - 20 -1130.214806844929 - 0 -LINE - 5 -928 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3828.253191330998 - 20 -1186.90839669684 - 11 -3864.34204721124 - 21 -1201.334960825953 - 0 -LINE - 5 -929 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3817.569851347105 - 20 -1195.732796192468 - 11 -3857.877077122608 - 21 -1211.845658829175 - 0 -LINE - 5 -92A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3864.34204721124 - 20 -1201.334960825953 - 11 -3933.839036880242 - 21 -1206.669498169772 - 0 -LINE - 5 -92B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3857.877077122608 - 20 -1211.845658829175 - 11 -3929.506972431524 - 21 -1217.343916426788 - 0 -LWPOLYLINE - 5 -92C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3674.038517828119 - 20 -1091.463009378749 - 10 -3736.519598054338 - 20 -1103.607966068941 - 0 -LWPOLYLINE - 5 -92D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3737.002057368151 - 20 -1102.479286077857 - 10 -3737.002057368151 - 20 -1102.479286077857 - 10 -3744.458612101624 - 20 -1106.673476415998 - 10 -3754.921112308807 - 20 -1123.52750767798 - 10 -3775.957144170349 - 20 -1123.614223775269 - 10 -3786.290409368626 - 20 -1089.978103280969 - 0 -LWPOLYLINE - 5 -92E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3886.141628373118 - 20 -1118.068975034996 - 10 -3831.721186576351 - 20 -1154.344822695818 - 10 -3827.417943474372 - 20 -1152.525487771688 - 10 -3784.152615093123 - 20 -1122.975655641954 - 10 -3793.044350720756 - 20 -1091.894007347209 - 0 -LWPOLYLINE - 5 -92F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3674.272604962561 - 20 -1243.869123794117 - 10 -3726.24568563805 - 20 -1244.707679792736 - 10 -3727.000240668569 - 20 -1197.940917009035 - 10 -3675.036768652261 - 20 -1196.506823406191 - 0 -MTEXT - 5 -930 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3756.865414159386 - 20 -1168.433523472095 - 30 -0 - 40 -1.95 - 41 -31.09166666666691 - 71 - 7 - 72 - 5 - 1 -\pi12.13862;MANANCHIRA \P\pi15.70874;SQUARE - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -931 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3776.474118560167 - 20 -1133.461032298888 - 30 -0 - 40 -1.949999999999999 - 41 -30.76666583985863 - 71 - 7 - 72 - 5 - 1 -\pi13.32312;S M STREET - 7 -standard -210 -0 -220 -0 -230 -1 - 50 --74.25125576525804 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -932 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3736.326966023149 - 20 -1104.442964096322 - 30 -0 - 40 -1.325999999999998 - 41 -25.52550000000013 - 71 - 7 - 72 - 5 - 1 -\pi8.1862;VAIKOM MUHAMMED \P\pi10.31088;BASHEER ROAD - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -53.22066029237218 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -933 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3820.722082429027 - 20 -1189.452004851772 - 30 -0 - 40 -1.949999999999999 - 41 -31.03749958659616 - 71 - 7 - 72 - 5 - 1 -\pi13.07039;TO STADIUM - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -21.68440044093668 - 73 - 1 - 44 -1 - 0 -ARC - 5 -934 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbCircle - 10 -3834.105824746369 - 20 -1181.819834705566 - 40 -7.755435580095657 -100 -AcDbArc - 50 -138.9947282420557 - 51 -210.268066171013 - 0 -ARC - 5 -935 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbCircle - 10 -3815.511662832165 - 20 -1201.843414851171 - 40 -6.441553476017277 -100 -AcDbArc - 50 -218.4994950327385 - 51 -293.6827425064117 - 0 -MTEXT - 5 -936 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3842.007876331594 - 20 -1175.051070345304 - 30 -0 - 40 -1.2675 - 41 -29.68062473128743 - 71 - 7 - 72 - 5 - 1 -\pi2.91262;OFFICE OF THE DISTRICT \P\pi7.83001;POLICE CHIEF - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -CIRCLE - 5 -937 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbCircle - 10 -3831.925447103324 - 20 -1141.843907025075 - 40 -9.277483467537976 - 0 -MTEXT - 5 -938 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3826.388260593409 - 20 -1139.603241054131 - 30 -0 - 40 -1.95 - 41 -25.89166666666679 - 71 - 7 - 72 - 5 - 1 -\pi0.48612;PATTALA \P\pi2.99013;PALLI - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -939 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3803.912872544535 - 20 -1126.360022534351 - 30 -0 - 40 -1.949999999999999 - 41 -21.34166666666666 - 71 - 7 - 72 - 5 - 1 -\pi4.71733;LIC \P\pi1.87014;OFFICE - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -34.78643956249795 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -93A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3793.943289383552 - 20 -1127.962435105929 - 10 -3817.668917594136 - 20 -1144.166456730874 - 10 -3824.533853563994 - 20 -1133.668178075407 - 10 -3800.492363226739 - 20 -1117.947192073396 - 0 -MTEXT - 5 -93B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3700.088415629728 - 20 -1159.660879081114 - 30 -0 - 40 -1.95 - 41 -27.84166625326284 - 71 - 7 - 72 - 5 - 1 -\pi13.86915;COMTREST\P\pi15.0184;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -93C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3679.516723670458 - 20 -1212.583629483431 - 30 -0 - 40 -1.95 - 41 -31.09166666666691 - 71 - 7 - 72 - 5 - 1 -\pi12.13862;MANANCHIRA \P\pi17.65076;POND - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -93D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3652.272450410219 - 20 -1264.786938479666 - 10 -3660.97369299198 - 20 -1266.242120259089 - 10 -3661.759734923516 - 20 -1271.020591869534 - 10 -3664.713136143153 - 20 -1263.674077079174 - 10 -3665.536366884463 - 20 -1268.033525151566 - 10 -3672.163893108268 - 20 -1269.141901950961 - 0 -LWPOLYLINE - 5 -93E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3781.614055392398 - 20 -1089.196037382174 - 10 -3788.267946778666 - 20 -1090.308823448827 - 10 -3788.869037667352 - 20 -1093.962948797974 - 10 -3791.12752095285 - 20 -1088.345025722963 - 10 -3791.757050343477 - 20 -1091.678721307767 - 10 -3796.825158631947 - 20 -1092.526303566073 - 0 -LWPOLYLINE - 5 -93F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3884.914400272256 - 20 -1116.482956246178 - 10 -3889.9505181377 - 20 -1124.024111787149 - 10 -3888.159683642405 - 20 -1127.265539579696 - 10 -3893.41192072271 - 20 -1124.252930730671 - 10 -3891.84184139424 - 20 -1127.26036891067 - 10 -3895.296435145634 - 20 -1131.064300997811 - 0 -LWPOLYLINE - 5 -940 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3931.931295981563 - 20 -1216.668312205154 - 10 -3932.638934645709 - 20 -1210.977787222031 - 10 -3935.72075832738 - 20 -1210.336939251194 - 10 -3930.869154464132 - 20 -1208.619355164397 - 10 -3933.67783825718 - 20 -1207.965787985093 - 10 -3934.216829528292 - 20 -1203.631452607232 - 0 -LWPOLYLINE - 5 -941 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3740.087966829236 - 20 -1252.976053281332 - 10 -3747.526265395394 - 20 -1257.719563682483 - 10 -3746.380090707456 - 20 -1262.424660539552 - 10 -3751.972359748435 - 20 -1256.819271587518 - 10 -3751.024350711658 - 20 -1261.153296877611 - 10 -3756.689922995719 - 20 -1264.766314131312 - 0 -LWPOLYLINE - 5 -942 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3774.717837631432 - 20 -1213.704493785373 - 10 -3782.15613619713 - 20 -1218.448004186448 - 10 -3781.009961509651 - 20 -1223.153101043594 - 10 -3786.602230550632 - 20 -1217.547712091545 - 10 -3785.654221513854 - 20 -1221.881737381653 - 10 -3791.319793797454 - 20 -1225.494754635277 - 0 -LWPOLYLINE - 5 -943 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3775.27882247923 - 20 -1212.526682639575 - 10 -3782.777444825555 - 20 -1217.308662386455 - 10 -3781.698986123465 - 20 -1221.735782183009 - 10 -3787.280224343788 - 20 -1216.141449930808 - 10 -3786.274038221407 - 20 -1220.741444162287 - 10 -3791.880778645253 - 20 -1224.316943489479 - 0 -LWPOLYLINE - 5 -944 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3733.704584040967 - 20 -1180.601809104001 - 10 -3706.058145653754 - 20 -1178.541714453807 - 10 -3708.528557137903 - 20 -1145.388830495251 - 10 -3736.174995524656 - 20 -1147.448925145369 - 0 -LWPOLYLINE - 5 -945 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3810.32292119011 - 20 -1237.036034494414 - 10 -3818.976684631721 - 20 -1226.316203024725 - 10 -3809.467087609203 - 20 -1218.639421604025 - 10 -3800.813324167589 - 20 -1229.359253073728 - 0 -LWPOLYLINE - 5 -946 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3822.486698941423 - 20 -1222.093152370142 - 10 -3831.140462383036 - 20 -1211.373320900453 - 10 -3821.630865360518 - 20 -1203.696539479753 - 10 -3812.977101918903 - 20 -1214.416370949456 - 0 -MTEXT - 5 -947 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3788.880713943821 - 20 -1222.566900670318 - 30 -0 - 40 -1.95 - 41 -23.07500000000049 - 71 - 7 - 72 - 5 - 1 -\pi17.87955;DTPC \P\pi16.55206;OFFICE - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -948 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3800.763668755769 - 20 -1207.948432676019 - 30 -0 - 40 -1.95 - 41 -24.32083333333345 - 71 - 7 - 72 - 5 - 1 -\pi19.61805;DD\P\pi16.11444; OFFICE - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -949 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3839.201383212925 - 20 -1179.70943669257 - 10 -3861.520849822987 - 20 -1197.290328442092 - 10 -3875.379086879443 - 20 -1179.696883031727 - 10 -3853.059620269839 - 20 -1162.115991282282 - 0 -MTEXT - 5 -94A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3854.042164330117 - 20 -1147.729192656701 - 30 -0 - 40 -1.949999999999999 - 41 -32.77083333333368 - 71 - 7 - 72 - 5 - 1 -\pi12.54033;TO PALAYAM - 7 -standard -210 -0 -220 -0 -230 -1 - 50 --33.43452738982237 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -94B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3753.7439683156 - 20 -1121.612594720044 - 10 -3760.220504389338 - 20 -1122.695720170199 - 10 -3761.161025697201 - 20 -1117.071883912244 - 10 -3754.684489623463 - 20 -1115.988758462089 - 0 -LWPOLYLINE - 5 -94C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3763.581401153643 - 20 -1121.905275219842 - 10 -3770.057937227381 - 20 -1122.988400669997 - 10 -3770.998458535244 - 20 -1117.364564412042 - 10 -3764.521922461506 - 20 -1116.281438961887 - 0 -MTEXT - 5 -94D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3762.778898677414 - 20 -1118.272107638218 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -94E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3752.728789273267 - 20 -1117.935263517171 - 30 -0 - 40 -0.414375 - 41 -5.58255208333336 - 71 - 7 - 72 - 5 - 1 -\pi3.24384;DISTRICT\P\pi3.18448; LIBRARY - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -94F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3764.306415485752 - 20 -1143.712097525969 - 10 -3775.96418041839 - 20 -1145.661723336233 - 10 -3777.657118772541 - 20 -1135.538818071929 - 10 -3765.999353839904 - 20 -1133.589192261665 - 0 -MTEXT - 5 -950 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3762.723633438748 - 20 -1137.791174678556 - 30 -0 - 40 -0.745875 - 41 -14.10946827561897 - 71 - 7 - 72 - 5 - 1 -\pi3.56669;DISTRICT SPORTS \P\pi3.81523;COUNCIL OFFICE - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -951 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3748.337464807924 - 20 -1112.244153926456 - 10 -3754.814000881662 - 20 -1113.327279376612 - 10 -3755.754522189525 - 20 -1107.703443118657 - 10 -3749.277986115787 - 20 -1106.620317668502 - 0 -MTEXT - 5 -952 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3748.100495253421 - 20 -1108.726756509799 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -953 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3741.845017537538 - 20 -1104.480484601143 - 10 -3748.321553611276 - 20 -1105.563610051298 - 10 -3749.26207491914 - 20 -1099.939773793344 - 10 -3742.785538845402 - 20 -1098.856648343189 - 0 -MTEXT - 5 -954 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3740.732738448468 - 20 -1102.710442323006 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -955 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3731.576376615175 - 20 -1125.983411118625 - 10 -3738.052912688914 - 20 -1127.066536568781 - 10 -3738.993433996775 - 20 -1121.44270031084 - 10 -3732.516897923036 - 20 -1120.359574860685 - 0 -MTEXT - 5 -956 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3731.33940706067 - 20 -1122.466013701968 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -957 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3737.545788317888 - 20 -1132.311689039405 - 10 -3744.022324391627 - 20 -1133.39481448956 - 10 -3744.96284569949 - 20 -1127.770978231606 - 10 -3738.486309625751 - 20 -1126.68785278145 - 0 -MTEXT - 5 -958 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - -1 -100 -AcDbMText - 10 -3737.308818763382 - 20 -1128.794291622748 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -959 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3770.699442659021 - 20 -1114.214100435279 - 10 -3777.175978732759 - 20 -1115.297225885435 - 10 -3778.116500040622 - 20 -1109.67338962748 - 10 -3771.639963966884 - 20 -1108.590264177325 - 0 -MTEXT - 5 -95A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3770.462473104514 - 20 -1110.696703018622 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -95B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3773.259528943675 - 20 -1103.848141244923 - 10 -3779.736065017413 - 20 -1104.931266695079 - 10 -3780.676586325277 - 20 -1099.307430437123 - 10 -3774.200050251539 - 20 -1098.224304986968 - 0 -MTEXT - 5 -95C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3773.022559389171 - 20 -1100.330743828266 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -95D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3775.766091565003 - 20 -1096.827935949267 - 10 -3782.242627638742 - 20 -1097.911061399423 - 10 -3783.183148946603 - 20 -1092.287225141482 - 10 -3776.706612872864 - 20 -1091.204099691327 - 0 -MTEXT - 5 -95E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3775.529122010957 - 20 -1093.310538532687 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -95F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3791.254872115195 - 20 -1106.387796302059 - 10 -3797.731408188933 - 20 -1107.470921752215 - 10 -3798.671929496794 - 20 -1101.847085494274 - 10 -3792.195393423056 - 20 -1100.763960044119 - 0 -MTEXT - 5 -960 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3791.017902561149 - 20 -1102.870398885479 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -961 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3787.955071879999 - 20 -1113.571129457761 - 10 -3794.431607953738 - 20 -1114.654254907916 - 10 -3795.3721292616 - 20 -1109.030418649975 - 10 -3788.895593187862 - 20 -1107.94729319982 - 0 -MTEXT - 5 -962 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3787.718102325494 - 20 -1110.053732041103 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -963 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3793.519755518178 - 20 -1099.875339826408 - 10 -3799.996291591916 - 20 -1100.958465276563 - 10 -3800.93681289978 - 20 -1095.334629018609 - 10 -3794.460276826041 - 20 -1094.251503568453 - 0 -MTEXT - 5 -964 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3793.282785963672 - 20 -1096.357942409751 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -965 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3845.580330387984 - 20 -1144.77593660757 - 10 -3853.926442873503 - 20 -1139.545311696947 - 10 -3849.384481292614 - 20 -1132.298047191109 - 10 -3841.038368807096 - 20 -1137.528672101732 - 0 -MTEXT - 5 -966 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3841.813517766818 - 20 -1141.064513595265 - 30 -0 - 40 -0.6215625000000001 - 41 -7.76953125000004 - 71 - 7 - 72 - 5 - 1 -\pi6.02345;EXT \P\pi4.78711;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 --32.07594501240991 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -967 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3855.873158925529 - 20 -1136.519144882714 - 10 -3864.219271411048 - 20 -1131.288519972091 - 10 -3859.677309830161 - 20 -1124.041255466252 - 10 -3851.331197344642 - 20 -1129.271880376875 - 0 -MTEXT - 5 -968 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3852.106346303904 - 20 -1132.807721870331 - 30 -0 - 40 -0.6215625000000001 - 41 -7.76953125000004 - 71 - 7 - 72 - 5 - 1 -\pi6.02345;EXT \P\pi4.78711;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 --32.07594501240991 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -969 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3866.838061140937 - 20 -1129.756339161086 - 10 -3875.184173625997 - 20 -1124.525714250386 - 10 -3870.64221204511 - 20 -1117.278449744548 - 10 -3862.296099560049 - 20 -1122.509074655247 - 0 -MTEXT - 5 -96A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3863.071248519311 - 20 -1126.044916148703 - 30 -0 - 40 -0.6215625000000001 - 41 -7.76953125000004 - 71 - 7 - 72 - 5 - 1 -\pi6.02345;EXT \P\pi4.78711;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 --32.07594501240991 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -96B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3875.525977642258 - 20 -1155.304222796561 - 10 -3883.872090127777 - 20 -1150.073597885938 - 10 -3879.330128546889 - 20 -1142.8263333801 - 10 -3870.98401606137 - 20 -1148.056958290723 - 0 -MTEXT - 5 -96C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3871.759165021093 - 20 -1151.592799784256 - 30 -0 - 40 -0.6215625000000001 - 41 -7.76953125000004 - 71 - 7 - 72 - 5 - 1 -\pi6.02345;EXT \P\pi4.78711;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 --32.07594501240991 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -96D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3886.246650705176 - 20 -1149.158494117503 - 10 -3894.592763190694 - 20 -1143.92786920688 - 10 -3890.050801609806 - 20 -1136.680604701041 - 10 -3881.704689124286 - 20 -1141.911229611664 - 0 -MTEXT - 5 -96E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3882.479838083551 - 20 -1145.44707110512 - 30 -0 - 40 -0.6215625000000001 - 41 -7.76953125000004 - 71 - 7 - 72 - 5 - 1 -\pi6.02345;EXT \P\pi4.78711;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 --32.07594501240991 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -96F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3862.886892206504 - 20 -1164.730942536645 - 10 -3871.233004692022 - 20 -1159.500317626022 - 10 -3866.691043111135 - 20 -1152.253053120183 - 10 -3858.344930625616 - 20 -1157.483678030806 - 0 -MTEXT - 5 -970 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3859.120079585338 - 20 -1161.019519524339 - 30 -0 - 40 -0.6215625000000001 - 41 -6.388281118227492 - 71 - 7 - 72 - 5 - 1 -\pi5.69041;BSNL - 7 -standard -210 -0 -220 -0 -230 -1 - 50 --32.07594501240991 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -971 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3700.13337714789 - 20 -1140.795822503287 - 10 -3706.609913221628 - 20 -1141.878947953442 - 10 -3707.550434529491 - 20 -1136.255111695487 - 10 -3701.073898455753 - 20 -1135.171986245332 - 0 -MTEXT - 5 -972 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3699.896407593384 - 20 -1137.27842508663 - 30 -0 - 40 -0.414375 - 41 -5.087604166666718 - 71 - 7 - 72 - 5 - 1 -\pi4.01564;EXT \P\pi3.19141;BUILDING - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -973 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3643.462846576567 - 20 -1207.930555156724 - 10 -3653.177650687173 - 20 -1209.555243331957 - 10 -3654.588432648967 - 20 -1201.119488945032 - 10 -3644.87362853836 - 20 -1199.494800769799 - 0 -MTEXT - 5 -974 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 7 -370 - -1 -100 -AcDbMText - 10 -3642.143861537395 - 20 -1202.996452783886 - 30 -0 - 40 -0.6215625000000001 - 41 -9.54789062500004 - 71 - 7 - 72 - 5 - 1 -\pi4.24547;TOWN HALL - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -975 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3640.537600089015 - 20 -1183.410616360269 - 10 -3650.252404199621 - 20 -1185.035304535502 - 10 -3651.663186161414 - 20 -1176.599550148577 - 10 -3641.948382050808 - 20 -1174.974861973343 - 0 -MTEXT - 5 -976 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3637.675691773953 - 20 -1178.825241802199 - 30 -0 - 40 -0.6215625000000001 - 41 -8.045781250000001 - 71 - 7 - 72 - 5 - 1 -\pi5.19456;CROWN \P\pi4.78881;THEATER - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -977 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3601.604909471302 - 20 -1272.231191164763 - 10 -3933.002492243144 - 20 -1327.653588559505 - 10 -3972.194044686567 - 20 -1093.308155027997 - 10 -3640.796461914725 - 20 -1037.885757633255 - 0 -LWPOLYLINE - 5 -978 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3681.434333434648 - 20 -1118.611448071486 - 10 -3693.771926796752 - 20 -1120.674767292133 - 10 -3695.126580710478 - 20 -1112.574629917997 - 10 -3682.788987348374 - 20 -1110.51131069735 - 0 -DIMENSION - 5 -979 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D16 - 10 -3696.042765219429 - 20 -1106.640418470341 - 30 -0 - 11 -3695.673365105243 - 21 -1109.622356924703 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3695.126580710478 - 23 -1112.574629917997 - 33 -0 - 14 -3696.042765217587 - 24 -1106.640418470033 - 34 -0 - 50 -99.49419111659763 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -97A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D17 - 10 -3683.833249802431 - 20 -1104.267155469601 - 30 -0 - 11 -3683.436895234262 - 21 -1107.4102677691 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3682.788987348374 - 23 -1110.51131069735 - 33 -0 - 14 -3683.833249800589 - 24 -1104.267155469293 - 34 -0 - 50 -99.49419111659763 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -97B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D18 - 10 -3716.871847356197 - 20 -1110.680308081277 - 30 -0 - 11 -3716.419807051285 - 21 -1114.156392598132 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3715.527812990941 - 23 -1117.558899958314 - 33 -0 - 14 -3716.546538312589 - 24 -1110.625903921355 - 34 -0 - 50 -99.49419111659763 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -97C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D19 - 10 -3725.456101013639 - 20 -1112.358003846994 - 30 -0 - 11 -3725.004803658664 - 21 -1115.829645903309 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3724.30195298597 - 23 -1119.259218588376 - 33 -0 - 14 -3725.466256737647 - 24 -1112.359702273902 - 34 -0 - 50 -99.49419111659763 -100 -AcDbRotatedDimension - 0 -LINE - 5 -97D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3673.226113949546 - 20 -1096.143998159776 - 11 -3736.982881325131 - 21 -1108.536920556109 - 0 -LINE - 5 -97E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3736.78093467197 - 20 -1102.385368843452 - 11 -3674.250989227 - 21 -1090.230913822521 - 0 -LINE - 5 -97F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3734.331979996244 - 20 -1114.133940960085 - 11 -3672.201238672091 - 21 -1102.057082497029 - 0 -LWPOLYLINE - 5 -980 -100 -AcDbEntity - 8 -BLK_1_FLR_0_BLT_UP_AREA - 6 -CONTINUOUS - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 11 - 70 - 1 - 43 -0 - 10 -3298.794476717245 - 20 -1259.280104148725 - 10 -3310.491947087228 - 20 -1259.280104148725 - 10 -3310.491947087228 - 20 -1243.823737554077 - 10 -3307.261947087351 - 20 -1243.823737554077 - 10 -3307.261947087351 - 20 -1243.423737554054 - 10 -3304.028122670717 - 20 -1243.423737553589 - 10 -3304.028122670717 - 20 -1242.722369962663 - 10 -3302.454476717161 - 20 -1242.722369962663 - 10 -3302.454476717161 - 20 -1242.252369962749 - 10 -3299.024476717227 - 20 -1242.252369962632 - 10 -3298.794476717245 - 20 -1242.252369962632 - 0 -LWPOLYLINE - 5 -981 -100 -AcDbEntity - 8 -BLK_1_BSMNT_FRONT_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 11 - 70 - 1 - 43 -0 - 10 -3699.232777040069 - 20 -1113.775649733053 - 10 -3702.961422993541 - 20 -1113.775649733043 - 10 -3702.961422993541 - 20 -1114.343383919057 - 10 -3704.46743068438 - 20 -1114.343702468373 - 10 -3704.467387999287 - 20 -1115.045070058 - 10 -3707.700247410171 - 20 -1115.045252870157 - 10 -3707.700247523737 - 20 -1115.444751510496 - 10 -3710.930247410173 - 20 -1115.444751510471 - 10 -3710.931485144911 - 20 -1110.563998297215 - 10 -3710.931545268003 - 20 -1109.58540778369 - 10 -3699.234207207088 - 20 -1107.312053327475 - 0 -LWPOLYLINE - 5 -982 -100 -AcDbEntity - 8 -BLK_1_LVL_0_REAR_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 1 - 43 -0 - 10 -3699.232777040192 - 20 -1130.901118105156 - 10 -3699.221250807438 - 20 -1132.969197142546 - 10 -3701.361437638996 - 20 -1133.220526157112 - 10 -3710.910075275855 - 20 -1133.07507759163 - 10 -3710.930245187186 - 20 -1130.901118105119 - 0 -LWPOLYLINE - 5 -983 -100 -AcDbEntity - 8 -BLK_1_BSMNT_SIDE_YARD_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3699.232777040069 - 20 -1130.901118105119 - 10 -3698.034300625808 - 20 -1130.90104516612 - 10 -3698.034300625808 - 20 -1113.775636794068 - 10 -3699.232777040069 - 20 -1113.775649733053 - 0 -MTEXT - 5 -984 -100 -AcDbEntity - 8 -BLK_1_LVL_0_FRONT_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3888.995942445637 - 20 -1107.198799397313 - 30 -0 - 40 -2.221171874999997 - 41 -23.93929687499997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=10.00 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -985 -100 -AcDbEntity - 8 -BLK_1_LVL_0_SIDE_YARD1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3889.412447205002 - 20 -1101.628360942278 - 30 -0 - 40 -2.221171874999997 - 41 -22.21171874999997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=10.0 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -986 -100 -AcDbEntity - 8 -BLK_1_LVL_0_SIDE_YARD2 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3889.558151292881 - 20 -1095.242230762686 - 30 -0 - 40 -2.221171874999997 - 41 -22.21171874999997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=10.0 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -987 -100 -AcDbEntity - 8 -BLK_1_LVL_0_REAR_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3889.025549273135 - 20 -1087.676971439328 - 30 -0 - 40 -2.221171874999997 - 41 -22.21171874999997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=10.0 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -988 -100 -AcDbEntity - 8 -BLK_1_DA_RAMP_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3823.217341994691 - 20 -1103.369298739781 - 30 -0 - 40 -2.221171874999997 - 41 -17.27578077910676 - 71 - 1 - 72 - 5 - 1 -SLOPE=1IN12 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -989 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -2951.195419034542 - 20 -1748.019487073325 - 10 -4256.185188137926 - 20 -1748.019487073325 - 10 -4256.185188137926 - 20 -754.7699488946961 - 10 -2951.195419034542 - 20 -754.7699488946961 - 0 -LWPOLYLINE - 5 -98A -100 -AcDbEntity - 8 -NOTIFIED_ROAD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3674.250989227 - 20 -1090.230913822521 - 10 -3672.296920324905 - 20 -1102.075680919548 - 10 -3734.331979996244 - 20 -1114.133940960085 - 10 -3736.78093467197 - 20 -1102.385368843452 - 0 -DIMENSION - 5 -98B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D20 - 10 -3692.548620250619 - 20 -1093.777223632806 - 30 -0 - 11 -3691.55878290749 - 21 -1099.695944551971 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3690.101075426844 - 23 -1105.536419623736 - 33 -0 - 14 -3692.167267226776 - 24 -1093.713446767995 - 34 -0 - 50 -99.49419111659763 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -98C -100 -AcDbEntity - 8 -BLK_1_MAX_HEIGHT_CAL - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D21 - 10 -3704.73684012501 - 20 -1096.17879616658 - 30 -0 - 11 -3703.281287270659 - 21 -1104.882257586579 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3702.961422993541 - 23 -1113.775649733043 - 33 -0 - 14 -3705.551110057835 - 24 -1096.31497335721 - 34 -0 - 50 -99.49419111659759 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -98D -100 -AcDbEntity - 8 -SHORTEST_DIST_TO_ROAD - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D22 - 10 -3704.067053513214 - 20 -1108.245004310187 - 30 -0 - 11 -3703.593239288494 - 21 -1111.078170974501 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3702.893813337845 - 23 -1113.87360669755 - 33 -0 - 14 -3703.84242825261 - 24 -1108.20743834379 - 34 -0 - 50 -99.49419111659759 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -98E -100 -AcDbEntity - 8 -DIST_CL_ROAD - 6 -ByLayer - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D23 - 10 -3704.822047500537 - 20 -1102.285557223309 - 30 -0 - 11 -3703.862084519889 - 21 -1108.025644738318 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3702.961422993541 - 23 -1113.775649732927 - 33 -0 - 14 -3704.82204750054 - 24 -1102.28555722331 - 34 -0 - 50 -99.49419111659759 -100 -AcDbRotatedDimension - 0 -LWPOLYLINE - 5 -98F -100 -AcDbEntity - 8 -BLK_1_FLR_1_BLT_UP_AREA - 6 -ByLayer - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 11 - 70 - 1 - 43 -0 - 10 -3315.64798602229 - 20 -1259.280104148725 - 10 -3327.345456392271 - 20 -1259.280104148725 - 10 -3327.345456392271 - 20 -1243.823737554077 - 10 -3324.115456392291 - 20 -1243.823737554077 - 10 -3324.115456392291 - 20 -1243.423737552314 - 10 -3321.200256110796 - 20 -1242.992274638342 - 10 -3320.811973281315 - 20 -1242.934807011575 - 10 -3319.307986022206 - 20 -1242.722369962663 - 10 -3319.307986022206 - 20 -1242.252369962749 - 10 -3315.877986022272 - 20 -1242.252369962632 - 10 -3315.64798602229 - 20 -1242.252369962632 - 0 -LWPOLYLINE - 5 -990 -100 -AcDbEntity - 8 -BLK_1_FLR_2_BLT_UP_AREA - 6 -CONTINUOUS - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 13 - 70 - 1 - 43 -0 - 10 -3351.858675254043 - 20 -1259.280104130454 - 10 -3353.918675253634 - 20 -1259.280104148725 - 10 -3353.918675253634 - 20 -1249.590104149363 - 10 -3363.546145619592 - 20 -1249.590104148723 - 10 -3363.55765715451 - 20 -1245.952369962644 - 10 -3357.092321204488 - 20 -1245.95236997268 - 10 -3357.09232120309 - 20 -1244.522369962651 - 10 -3357.09232120309 - 20 -1243.423737554054 - 10 -3357.09232120309 - 20 -1242.722369944391 - 10 -3355.51867525396 - 20 -1242.722369944391 - 10 -3355.51867525396 - 20 -1242.252369944477 - 10 -3352.088675254026 - 20 -1242.252369944361 - 10 -3351.858675254043 - 20 -1242.252369944361 - 0 -LWPOLYLINE - 5 -991 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_BLT_UP_AREA - 6 -CONTINUOUS - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 11 - 70 - 1 - 43 -0 - 10 -3281.373068378307 - 20 -1259.280104148725 - 10 -3293.070538748289 - 20 -1259.280104148725 - 10 -3293.070538748289 - 20 -1243.823737554077 - 10 -3289.840538748288 - 20 -1243.823737554077 - 10 -3289.840538748288 - 20 -1243.423737554054 - 10 -3286.606714331778 - 20 -1243.423737553589 - 10 -3286.606714331778 - 20 -1242.722369962663 - 10 -3285.101714331658 - 20 -1242.722369962663 - 10 -3285.101714331658 - 20 -1242.154635776649 - 10 -3281.605333485642 - 20 -1242.154635776649 - 10 -3281.373068378185 - 20 -1242.154635776659 - 0 -INSERT - 5 -992 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -*U4 - 10 --5492.970809899844 - 20 --1659.111589305452 - 30 -0 - 41 -0.01 - 42 -0.01 - 43 -0 - 50 -0 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -993 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -*U4 - 10 --5476.117300597593 - 20 --1659.111589307198 - 30 -0 - 41 -0.01 - 42 -0.01 - 43 -0 - 50 -0 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -LWPOLYLINE - 5 -994 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3545.073278998258 - 20 -1389.713192906725 - 10 -3989.255620379117 - 20 -1389.713192906725 - 10 -3989.255620379117 - 20 -1027.859286806066 - 10 -3545.073278998258 - 20 -1027.859286806066 - 0 -LWPOLYLINE - 5 -995 -100 -AcDbEntity - 8 -BLK_1_FLR_3_BLT_UP_AREA - 6 -ByLayer - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3372.342164165108 - 20 -1259.280104148725 - 10 -3374.402164170984 - 20 -1259.280104148725 - 10 -3374.402164170984 - 20 -1255.550104161433 - 10 -3372.342164165108 - 20 -1255.550104161433 - 0 -LWPOLYLINE - 5 -996 -100 -AcDbEntity - 8 -BLK_1_FLR_0_BLT_UP_AREA_DEDUCT - 6 -ByLayer - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3300.224476717307 - 20 -1245.352369962667 - 10 -3301.124476717212 - 20 -1245.352369962667 - 10 -3301.124476717087 - 20 -1243.552369962679 - 10 -3300.22410247149 - 20 -1243.552369962679 - 0 -LWPOLYLINE - 5 -997 -100 -AcDbEntity - 8 -BLK_1_FLR_0_BLT_UP_AREA_DEDUCT - 6 -ByLayer - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 1 - 43 -0 - 10 -3302.553122670751 - 20 -1244.552369962679 - 10 -3303.828122670763 - 20 -1244.552369962679 - 10 -3303.828122670763 - 20 -1243.423737554059 - 10 -3303.928122670622 - 20 -1243.423737554059 - 10 -3303.928122670622 - 20 -1242.822369962639 - 10 -3302.523122670595 - 20 -1242.822369962639 - 10 -3302.524476717226 - 20 -1244.252369962649 - 10 -3302.525355745574 - 20 -1244.552369962679 - 0 -LWPOLYLINE - 5 -998 -100 -AcDbEntity - 8 -BLK_1_FLR_1_BLT_UP_AREA_DEDUCT - 6 -ByLayer - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3317.077611773763 - 20 -1245.352369962667 - 10 -3317.977986019338 - 20 -1245.352369962667 - 10 -3317.977986019359 - 20 -1243.552369960936 - 10 -3317.077611773763 - 20 -1243.552369960936 - 0 -LWPOLYLINE - 5 -999 -100 -AcDbEntity - 8 -BLK_1_FLR_1_BLT_UP_AREA_DEDUCT - 6 -ByLayer - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 1 - 43 -0 - 10 -3319.406631973023 - 20 -1244.552369960937 - 10 -3320.681631973035 - 20 -1244.552369960937 - 10 -3320.681631973035 - 20 -1243.423737552317 - 10 -3320.781631972895 - 20 -1243.423737552317 - 10 -3320.781631972895 - 20 -1243.031405693931 - 10 -3319.376631972867 - 20 -1242.822369960897 - 10 -3319.3779860195 - 20 -1244.252369960907 - 10 -3319.378865047845 - 20 -1244.552369960937 - 0 -LWPOLYLINE - 5 -99A -100 -AcDbEntity - 8 -BLK_1_FLR_1_BLT_UP_AREA_DEDUCT - 6 -CONTINUOUS - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3353.288675249576 - 20 -1245.352369962667 - 10 -3354.188675249461 - 20 -1245.352369985618 - 10 -3354.188675250858 - 20 -1243.552369964251 - 10 -3353.288301005261 - 20 -1243.552369964251 - 0 -LWPOLYLINE - 5 -99B -100 -AcDbEntity - 8 -BLK_1_FLR_1_BLT_UP_AREA_DEDUCT - 6 -CONTINUOUS - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 1 - 43 -0 - 10 -3355.617321204522 - 20 -1244.552369964251 - 10 -3356.892321204534 - 20 -1244.552369964251 - 10 -3356.892321204534 - 20 -1243.423737555631 - 10 -3356.992321204394 - 20 -1243.423737555631 - 10 -3356.992321204394 - 20 -1242.822369964211 - 10 -3355.587321204366 - 20 -1242.822369964211 - 10 -3355.588675250998 - 20 -1244.252369964221 - 10 -3355.589554279344 - 20 -1244.552369964251 - 0 -LWPOLYLINE - 5 -99C -100 -AcDbEntity - 8 -BLK_1_FLR_-1_BLT_UP_AREA_DEDUCT - 6 -CONTINUOUS - 62 - 8 -370 - -1 -100 -AcDbPolyline - 90 - 16 - 70 - 1 - 43 -0 - 10 -3281.603068378307 - 20 -1259.050104148725 - 10 -3292.840538748289 - 20 -1259.050104148725 - 10 -3292.840538748287 - 20 -1245.952369962646 - 10 -3293.070538748289 - 20 -1245.952369962644 - 10 -3293.070538748289 - 20 -1243.823737554077 - 10 -3289.610538748287 - 20 -1243.823737554077 - 10 -3289.610538748306 - 20 -1243.623737554299 - 10 -3286.606714331798 - 20 -1243.623737553833 - 10 -3286.606714331777 - 20 -1244.752369962632 - 10 -3284.903068378103 - 20 -1244.752369962632 - 10 -3284.903068378103 - 20 -1245.052369962679 - 10 -3283.703068378148 - 20 -1245.052369962679 - 10 -3283.703068378148 - 20 -1243.552369962679 - 10 -3282.802694132552 - 20 -1243.552369962679 - 10 -3282.802694132552 - 20 -1245.952369962644 - 10 -3281.603068378181 - 20 -1245.952369962646 - 0 -LWPOLYLINE - 5 -99D -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 9 - 70 - 1 - 43 -0 - 10 -3284.903068378103 - 20 -1245.052369962679 - 10 -3283.703068378148 - 20 -1245.052369962679 - 10 -3283.703068378148 - 20 -1243.552369962679 - 10 -3282.803068378242 - 20 -1243.552369962679 - 10 -3282.803068378246 - 20 -1245.952369962644 - 10 -3281.573068378261 - 20 -1245.952369962646 - 10 -3281.573068378261 - 20 -1242.654635776659 - 10 -3281.573067692857 - 20 -1242.352943808457 - 10 -3284.903068378103 - 20 -1242.351804283501 - 0 -LWPOLYLINE - 5 -99E -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3284.903068378103 - 20 -1245.052369962679 - 10 -3283.703068378148 - 20 -1245.052369962679 - 10 -3283.703068378148 - 20 -1243.552369962679 - 10 -3284.903068378103 - 20 -1243.552369962679 - 0 -LWPOLYLINE - 5 -99F -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3283.703068378148 - 20 -1243.552369962679 - 10 -3282.803068378242 - 20 -1243.552369962679 - 10 -3282.803068422602 - 20 -1242.352728218148 - 10 -3283.703068422506 - 20 -1242.352008989147 - 0 -LWPOLYLINE - 5 -9A0 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3282.803068378242 - 20 -1243.552369962679 - 10 -3281.573068378261 - 20 -1243.552369962679 - 10 -3281.573068378261 - 20 -1245.952369962644 - 10 -3282.803068378242 - 20 -1245.952369962644 - 0 -DIMENSION - 5 -9A1 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D24 - 10 -3284.525130626578 - 20 -1243.55236996268 - 30 -0 - 11 -3284.525130626578 - 21 -1244.302369962678 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3284.699090456707 - 23 -1245.052369962679 - 33 -0 - 14 -3284.699090456707 - 24 -1243.552369962679 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9A2 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D25 - 10 -3282.803068392845 - 20 -1243.079906270055 - 30 -0 - 11 -3282.159746428316 - 21 -1243.079906270055 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3283.703068392752 - 23 -1243.15718709081 - 33 -0 - 14 -3282.803068392845 - 24 -1243.15718709081 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9A3 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D26 - 10 -3282.378710914939 - 20 -1245.952369962645 - 30 -0 - 11 -3282.378710914938 - 21 -1244.752369962662 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3282.378710914928 - 23 -1243.552369962679 - 33 -0 - 14 -3282.378710914933 - 24 -1245.952369962645 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9A4 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D27 - 10 -3284.903068378103 - 20 -1245.209053745057 - 30 -0 - 11 -3284.303068378125 - 21 -1245.209053745057 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3283.703068378148 - 23 -1245.052369962679 - 33 -0 - 14 -3284.903068378103 - 24 -1245.052369962679 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9A5 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D28 - 10 -3283.253068378211 - 20 -1242.352368869733 - 30 -0 - 11 -3283.253068378211 - 21 -1242.952369416206 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3283.253068378196 - 23 -1243.552369962679 - 33 -0 - 14 -3283.252335025697 - 24 -1242.352368869733 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9A6 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D29 - 10 -3282.803068378242 - 20 -1243.756682050024 - 30 -0 - 11 -3282.203068378212 - 21 -1243.756682050024 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3281.603068378181 - 23 -1245.952369962646 - 33 -0 - 14 -3282.803068378242 - 24 -1243.552370008162 - 34 -0 -100 -AcDbRotatedDimension - 0 -LWPOLYLINE - 5 -9A7 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 9 - 70 - 1 - 43 -0 - 10 -3302.324476717156 - 20 -1245.652369962656 - 10 -3301.124476717203 - 20 -1245.652369962656 - 10 -3301.124476717212 - 20 -1243.552369962674 - 10 -3300.224476717306 - 20 -1243.552369962674 - 10 -3300.224476717311 - 20 -1247.752369962631 - 10 -3299.024476717244 - 20 -1247.752369962634 - 10 -3299.024476717244 - 20 -1242.654635776654 - 10 -3299.024476717227 - 20 -1242.352369962726 - 10 -3302.324476717166 - 20 -1242.351804283496 - 0 -LWPOLYLINE - 5 -9A8 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3302.324476717166 - 20 -1245.652369962656 - 10 -3301.124476717212 - 20 -1245.652369962656 - 10 -3301.124476717212 - 20 -1243.552369962674 - 10 -3302.324476717166 - 20 -1243.552369962674 - 0 -LWPOLYLINE - 5 -9A9 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3301.124476717212 - 20 -1243.552369962674 - 10 -3300.224476717306 - 20 -1243.552369962674 - 10 -3300.224476761666 - 20 -1242.352728218143 - 10 -3301.124476761569 - 20 -1242.352008989142 - 0 -LWPOLYLINE - 5 -9AA -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3300.224476717306 - 20 -1243.552369962674 - 10 -3299.024476717227 - 20 -1243.552369962674 - 10 -3299.024476717244 - 20 -1247.752369962634 - 10 -3300.224476717306 - 20 -1247.752369962632 - 0 -DIMENSION - 5 -9AB -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D30 - 10 -3301.94653896565 - 20 -1243.552369962674 - 30 -0 - 11 -3301.94653896565 - 21 -1244.602369962665 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3302.120498795771 - 23 -1245.652369962656 - 33 -0 - 14 -3302.120498795771 - 24 -1243.552369962674 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9AC -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D31 - 10 -3300.224476731909 - 20 -1243.079906270047 - 30 -0 - 11 -3299.581154767381 - 21 -1243.079906270047 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3301.124476731815 - 23 -1243.157187090806 - 33 -0 - 14 -3300.224476731909 - 24 -1243.157187090806 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9AD -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D32 - 10 -3299.810469436013 - 20 -1247.752369962632 - 30 -0 - 11 -3299.810469436013 - 21 -1245.652369962653 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3299.81046943599 - 23 -1243.552369962674 - 33 -0 - 14 -3299.810469435998 - 24 -1247.752369962632 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9AE -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D33 - 10 -3302.324476717166 - 20 -1245.809053745033 - 30 -0 - 11 -3301.724476717189 - 21 -1245.809053745033 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3301.124476717212 - 23 -1245.652369962656 - 33 -0 - 14 -3302.324476717166 - 24 -1245.652369962656 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9AF -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D34 - 10 -3300.674476717278 - 20 -1242.352368869728 - 30 -0 - 11 -3300.674476717278 - 21 -1242.952369416201 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3300.674476717258 - 23 -1243.552369962674 - 33 -0 - 14 -3300.673743364761 - 24 -1242.352368869728 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9B0 -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D35 - 10 -3300.224476717306 - 20 -1243.756682050019 - 30 -0 - 11 -3299.624476717275 - 21 -1243.756682050019 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3299.024476717244 - 23 -1245.952369962641 - 33 -0 - 14 -3300.224476717306 - 24 -1243.552370652369 - 34 -0 -100 -AcDbRotatedDimension - 0 -LWPOLYLINE - 5 -9B1 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 9 - 70 - 1 - 43 -0 - 10 -3319.177986022085 - 20 -1245.652369962656 - 10 -3317.977986022132 - 20 -1245.652369962656 - 10 -3317.977986022152 - 20 -1243.552369960933 - 10 -3317.077986022245 - 20 -1243.552369960933 - 10 -3317.077611776302 - 20 -1246.852369962666 - 10 -3315.877986022039 - 20 -1246.852369962667 - 10 -3315.877986022039 - 20 -1242.654635774913 - 10 -3315.877986019499 - 20 -1242.352369962726 - 10 -3319.177986022105 - 20 -1242.351804281755 - 0 -LWPOLYLINE - 5 -9B2 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3319.177986022085 - 20 -1245.652369962656 - 10 -3317.977986022132 - 20 -1245.652369962656 - 10 -3317.977986022152 - 20 -1243.552369960933 - 10 -3319.177986022105 - 20 -1243.552369960933 - 0 -LWPOLYLINE - 5 -9B3 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3317.977986022152 - 20 -1243.552369960933 - 10 -3317.077986022245 - 20 -1243.552369960933 - 10 -3317.077986066605 - 20 -1242.352728216402 - 10 -3317.977986066509 - 20 -1242.352008987401 - 0 -LWPOLYLINE - 5 -9B4 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3317.077986022245 - 20 -1243.552369960933 - 10 -3315.877986022039 - 20 -1243.552369960933 - 10 -3315.877986022039 - 20 -1246.852369962667 - 10 -3317.077611760689 - 20 -1246.852507637009 - 0 -DIMENSION - 5 -9B5 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D36 - 10 -3318.800048270567 - 20 -1243.552369960933 - 30 -0 - 11 -3318.800048270566 - 21 -1244.602369961795 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3318.97400810069 - 23 -1245.652369962656 - 33 -0 - 14 -3318.97400810071 - 24 -1243.552369960933 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9B6 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D37 - 10 -3317.077986036848 - 20 -1243.079906268309 - 30 -0 - 11 -3316.43466407232 - 21 -1243.079906268309 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3317.977986036755 - 23 -1243.157187089064 - 33 -0 - 14 -3317.077986036848 - 24 -1243.157187089064 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9B7 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D38 - 10 -3316.663978740904 - 20 -1246.852369962667 - 30 -0 - 11 -3316.663978740903 - 21 -1245.2023699618 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3316.663978740885 - 23 -1243.552369960933 - 33 -0 - 14 -3316.663978740891 - 24 -1246.852369962667 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9B8 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D39 - 10 -3319.177986022085 - 20 -1245.809053745033 - 30 -0 - 11 -3318.577986022108 - 21 -1245.809053745033 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3317.977986022132 - 23 -1245.652369962656 - 33 -0 - 14 -3319.177986022085 - 24 -1245.652369962656 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9B9 -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D40 - 10 -3317.527986022219 - 20 -1242.352368867987 - 30 -0 - 11 -3317.527986022219 - 21 -1242.95236941446 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3317.527986022199 - 23 -1243.552369960933 - 33 -0 - 14 -3317.5272526697 - 24 -1242.352368867987 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9BA -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D41 - 10 -3317.077986022245 - 20 -1243.756683315703 - 30 -0 - 11 -3316.477986022214 - 21 -1243.756683315703 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3315.877986022184 - 23 -1245.9523699609 - 33 -0 - 14 -3317.077986022245 - 24 -1243.552371273841 - 34 -0 -100 -AcDbRotatedDimension - 0 -LWPOLYLINE - 5 -9BB -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 9 - 70 - 1 - 43 -0 - 10 -3355.388675249435 - 20 -1245.652369962656 - 10 -3354.188675249481 - 20 -1245.652369962656 - 10 -3354.188675249481 - 20 -1243.552369962674 - 10 -3353.288675249574 - 20 -1243.552369962674 - 10 -3353.288675249579 - 20 -1246.852369962691 - 10 -3352.088675592304 - 20 -1246.852369962691 - 10 -3352.088675592303 - 20 -1242.654635776654 - 10 -3352.088674906898 - 20 -1242.352943808452 - 10 -3355.388675249435 - 20 -1242.351804283496 - 0 -LWPOLYLINE - 5 -9BC -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3355.388675249435 - 20 -1245.652369962656 - 10 -3354.188675249481 - 20 -1245.652369962656 - 10 -3354.188675249481 - 20 -1243.552369962674 - 10 -3355.388675249435 - 20 -1243.552369962674 - 0 -LWPOLYLINE - 5 -9BD -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3354.188675249481 - 20 -1243.552369962674 - 10 -3353.288675249574 - 20 -1243.552369962674 - 10 -3353.288675293935 - 20 -1242.352728218143 - 10 -3354.188675293838 - 20 -1242.352008989142 - 0 -LWPOLYLINE - 5 -9BE -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3353.288675249574 - 20 -1243.552369962674 - 10 -3352.088675249515 - 20 -1243.552369962674 - 10 -3352.088675249515 - 20 -1246.852369962691 - 10 -3353.288675249575 - 20 -1246.852369962691 - 0 -DIMENSION - 5 -9BF -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D42 - 10 -3355.010737497922 - 20 -1243.552369962674 - 30 -0 - 11 -3355.010737497922 - 21 -1244.602369962665 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3355.18469732804 - 23 -1245.652369962656 - 33 -0 - 14 -3355.18469732804 - 24 -1243.552369962674 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9C0 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D43 - 10 -3353.288675264177 - 20 -1243.079906270047 - 30 -0 - 11 -3352.645353299648 - 21 -1243.079906270047 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3354.188675264084 - 23 -1243.157187090806 - 33 -0 - 14 -3353.288675264177 - 24 -1243.157187090806 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9C1 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D44 - 10 -3352.874667968283 - 20 -1246.852369962691 - 30 -0 - 11 -3352.874667968283 - 21 -1245.202369962683 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3352.874667968265 - 23 -1243.552369962674 - 33 -0 - 14 -3352.874667968265 - 24 -1246.852369962691 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9C2 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D45 - 10 -3355.388675249435 - 20 -1245.809053745032 - 30 -0 - 11 -3354.788675249458 - 21 -1245.809053745032 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3354.188675249481 - 23 -1245.652369962656 - 33 -0 - 14 -3355.388675249435 - 24 -1245.652369962656 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9C3 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D46 - 10 -3353.738675249547 - 20 -1242.352368869728 - 30 -0 - 11 -3353.738675249547 - 21 -1242.952369416201 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3353.738675249528 - 23 -1243.552369962674 - 33 -0 - 14 -3353.73794189703 - 24 -1242.352368869728 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9C4 -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D47 - 10 -3353.288675249574 - 20 -1243.75668465645 - 30 -0 - 11 -3352.688675249544 - 21 -1243.75668465645 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3352.088675249515 - 23 -1245.952369962641 - 33 -0 - 14 -3353.288675249574 - 24 -1243.552372614588 - 34 -0 -100 -AcDbRotatedDimension - 0 -LINE - 5 -9C5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.977986022132 - 20 -1245.052369962633 - 11 -3319.177986022085 - 21 -1245.052369962633 - 0 -LINE - 5 -9C6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1246.552369962691 - 11 -3352.088675249601 - 21 -1246.552369962691 - 0 -LINE - 5 -9C7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288301003864 - 20 -1246.852369962691 - 11 -3352.088675249601 - 21 -1246.852369962691 - 0 -LWPOLYLINE - 5 -9C8 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_LIFT_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3285.131714331685 - 20 -1244.552369962679 - 10 -3286.406714331592 - 20 -1244.552369962679 - 10 -3286.406714331592 - 20 -1242.922369962616 - 10 -3285.131714331685 - 20 -1242.922369962616 - 0 -LWPOLYLINE - 5 -9C9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3302.553122670751 - 20 -1244.552369962679 - 10 -3303.828122670763 - 20 -1244.552369962679 - 10 -3303.828122670763 - 20 -1242.922369962616 - 10 -3302.553122670751 - 20 -1242.922369962616 - 0 -LWPOLYLINE - 5 -9CA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3319.406631977007 - 20 -1244.552369960937 - 10 -3320.631631975528 - 20 -1244.552369960937 - 10 -3320.631631975528 - 20 -1242.972369962663 - 10 -3319.406631977007 - 20 -1242.972369962663 - 0 -LWPOLYLINE - 5 -9CB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3355.617321202998 - 20 -1244.552369962679 - 10 -3356.892321203137 - 20 -1244.552369962679 - 10 -3356.892321203137 - 20 -1242.922369962675 - 10 -3355.617321202998 - 20 -1242.922369962675 - 0 -MTEXT - 5 -9CC -100 -AcDbEntity - 8 -BLK_1_FLR_-1_STAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3283.268677616787 - 20 -1245.901766790177 - 30 -0 - 40 -0.18509765625 - 41 -2.118339843750011 - 71 - 1 - 72 - 5 - 1 -FLR_HT_M=2.85 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -9CD -100 -AcDbEntity - 8 -BLK_1_FLR_0_STAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3300.725937942232 - 20 -1247.318089485752 - 30 -0 - 40 -0.18509765625 - 41 -2.138906250000011 - 71 - 1 - 72 - 5 - 1 -FLR_HT_M=4.05 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -9CE -100 -AcDbEntity - 8 -BLK_1_FLR_1_STAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3317.252281568243 - 20 -1247.005921261956 - 30 -0 - 40 -0.18509765625 - 41 -1.974375000000023 - 71 - 1 - 72 - 5 - 1 -FLR_HT_M=3.6 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -9CF -100 -AcDbEntity - 8 -BLK_1_FLR_2_STAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3353.879127852625 - 20 -1246.95928062544 - 30 -0 - 40 -0.18509765625 - 41 -1.974375000000023 - 71 - 1 - 72 - 5 - 1 -FLR_HT_M=3.6 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -9D0 -100 -AcDbEntity - 8 -RWH - 6 -ByLayer - 62 - 8 -370 - -1 -100 -AcDbMText - 10 -3699.013859384949 - 20 -1111.516430563994 - 30 -0 - 40 -0.35 - 41 -5.98888888888891 - 71 - 1 - 72 - 5 - 1 -RWH_CAPACITY_L=5000 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -9D1 -100 -AcDbEntity - 8 -RWH - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3699.862406253502 - 20 -1113.369687750055 - 10 -3703.861797786857 - 20 -1113.43945423812 - 10 -3703.925296166536 - 20 -1111.910678144355 - 10 -3699.925752516535 - 20 -1111.858353278301 - 0 -LWPOLYLINE - 5 -9D2 -100 -AcDbEntity - 8 -WASTE_DISPOSAL - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3707.312411874112 - 20 -1129.276287099953 - 10 -3709.588790924883 - 20 -1129.274351026701 - 10 -3709.585205604046 - 20 -1127.324354322738 - 10 -3707.310799102231 - 20 -1127.326286769203 - 0 -LWPOLYLINE - 5 -9D3 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 1 - 43 -0 - 10 -3298.794476717245 - 20 -1259.280104148715 - 10 -3300.624476717086 - 20 -1259.280104148715 - 10 -3300.624476717086 - 20 -1256.300104148744 - 10 -3299.874476717086 - 20 -1256.300104148744 - 10 -3299.874476717086 - 20 -1258.300104148744 - 10 -3299.774476717227 - 20 -1258.300104148744 - 10 -3299.774476717227 - 20 -1256.300104148744 - 10 -3298.794476717245 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -9D4 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 1 - 43 -0 - 10 -3315.647986019496 - 20 -1259.280104146958 - 10 -3317.477986019337 - 20 -1259.280104146958 - 10 -3317.477986019337 - 20 -1256.300104146987 - 10 -3316.727986019337 - 20 -1256.300104146987 - 10 -3316.727986019337 - 20 -1258.300104146987 - 10 -3316.627986019477 - 20 -1258.300104146987 - 10 -3316.627986019477 - 20 -1256.300104146987 - 10 -3315.647986019496 - 20 -1256.300104146987 - 0 -LWPOLYLINE - 5 -9D5 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 1 - 43 -0 - 10 -3351.858675251249 - 20 -1259.280104121939 - 10 -3353.688675251091 - 20 -1259.280104121939 - 10 -3353.688675251091 - 20 -1256.300104121969 - 10 -3352.938675251091 - 20 -1256.300104121969 - 10 -3352.938675251091 - 20 -1258.300104121969 - 10 -3352.838675251231 - 20 -1258.300104121969 - 10 -3352.838675251231 - 20 -1256.300104121969 - 10 -3351.858675251249 - 20 -1256.300104121969 - 0 -LWPOLYLINE - 5 -9D6 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3299.024476717227 - 20 -1258.300104148744 - 10 -3299.774476717227 - 20 -1258.300104148744 - 10 -3299.774476717227 - 20 -1256.300104148744 - 10 -3299.024476717227 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -9D7 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3299.874476717086 - 20 -1256.300104148744 - 10 -3300.624476717086 - 20 -1256.300104148744 - 10 -3300.624476717086 - 20 -1258.300104148744 - 10 -3299.874476717086 - 20 -1258.300104148744 - 0 -LWPOLYLINE - 5 -9D8 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3315.877986019477 - 20 -1258.300104148744 - 10 -3316.627986019477 - 20 -1258.300104148744 - 10 -3316.627986019477 - 20 -1256.300104148744 - 10 -3315.877986019477 - 20 -1256.300104148744 - 0 -LWPOLYLINE - 5 -9D9 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3316.727986019337 - 20 -1256.300104148744 - 10 -3317.477986019337 - 20 -1256.300104148744 - 10 -3317.477986019337 - 20 -1258.300104148744 - 10 -3316.727986019337 - 20 -1258.300104148744 - 0 -LWPOLYLINE - 5 -9DA -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3352.088675251034 - 20 -1258.300104171694 - 10 -3352.838675251034 - 20 -1258.300104171694 - 10 -3352.838675251034 - 20 -1256.300104171695 - 10 -3352.088675251034 - 20 -1256.300104171695 - 0 -LWPOLYLINE - 5 -9DB -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3352.938675250895 - 20 -1256.300104171695 - 10 -3353.688675250895 - 20 -1256.300104171695 - 10 -3353.688675250895 - 20 -1258.300104171694 - 10 -3352.938675250895 - 20 -1258.300104171694 - 0 -LWPOLYLINE - 5 -9DC -100 -AcDbEntity - 8 -BLK_1_FLR_3_FIRESTAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3372.3421641686 - 20 -1259.280104148725 - 10 -3374.402164174477 - 20 -1259.280104148725 - 10 -3374.402164174477 - 20 -1255.550104161433 - 10 -3372.3421641686 - 20 -1255.550104161433 - 0 -DIMENSION - 5 -9DD -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D48 - 10 -3353.434456956947 - 20 -1256.300104121969 - 30 -0 - 11 -3353.434456956946 - 21 -1257.300104146831 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3353.313675250895 - 23 -1258.300104171694 - 33 -0 - 14 -3353.313675250895 - 24 -1256.300104121969 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9DE -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D49 - 10 -3352.348675251248 - 20 -1256.300104121969 - 30 -0 - 11 -3352.348675251248 - 21 -1257.300104146832 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3352.321976650384 - 23 -1258.300104171694 - 33 -0 - 14 -3352.348675251239 - 24 -1256.300104121969 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9DF -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D50 - 10 -3353.688675251091 - 20 -1258.430923504448 - 30 -0 - 11 -3354.33199721562 - 21 -1258.430923504448 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3352.938675249461 - 23 -1258.300104171694 - 33 -0 - 14 -3353.688675251091 - 24 -1258.300104171694 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9E0 -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D51 - 10 -3352.088675251034 - 20 -1258.458460622718 - 30 -0 - 11 -3351.445353286505 - 21 -1258.458460622718 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3352.838675251231 - 23 -1258.300104121969 - 33 -0 - 14 -3352.088675251034 - 24 -1258.300104121969 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9E1 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D52 - 10 -3317.223767729391 - 20 -1256.300104121969 - 30 -0 - 11 -3317.223767729391 - 21 -1257.300104146831 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3317.102986023332 - 23 -1258.300104171694 - 33 -0 - 14 -3317.102986023332 - 24 -1256.300104121969 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9E2 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D53 - 10 -3316.137986023692 - 20 -1256.300104121969 - 30 -0 - 11 -3316.137986023692 - 21 -1257.300104146831 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3316.111287422821 - 23 -1258.300104171694 - 33 -0 - 14 -3316.137986023678 - 24 -1256.300104121969 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9E3 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D54 - 10 -3317.477986023528 - 20 -1258.430923504448 - 30 -0 - 11 -3318.121307988058 - 21 -1258.430923504448 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3316.727986021899 - 23 -1258.300104171694 - 33 -0 - 14 -3317.477986023528 - 24 -1258.300104171694 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9E4 -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D55 - 10 -3315.877986023473 - 20 -1258.458460622718 - 30 -0 - 11 -3315.234664058943 - 21 -1258.458460622718 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3316.627986023668 - 23 -1258.300104121969 - 33 -0 - 14 -3315.877986023473 - 24 -1258.300104121969 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9E5 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D56 - 10 -3300.370258424579 - 20 -1256.300104121969 - 30 -0 - 11 -3300.370258424579 - 21 -1257.300104146831 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3300.24947671852 - 23 -1258.300104171694 - 33 -0 - 14 -3300.24947671852 - 24 -1256.300104121969 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9E6 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbDimension - 2 -*D57 - 10 -3299.28447671888 - 20 -1256.300104121969 - 30 -0 - 11 -3299.28447671888 - 21 -1257.300104146831 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3299.257778118009 - 23 -1258.300104171694 - 33 -0 - 14 -3299.284476718866 - 24 -1256.300104121969 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9E7 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D58 - 10 -3300.624476718716 - 20 -1258.430923504448 - 30 -0 - 11 -3301.267798683246 - 21 -1258.430923504448 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3299.874476717086 - 23 -1258.300104171694 - 33 -0 - 14 -3300.624476718716 - 24 -1258.300104171694 - 34 -0 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -9E8 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D59 - 10 -3299.02447671866 - 20 -1258.458460622718 - 30 -0 - 11 -3298.381154754131 - 21 -1258.458460622718 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3299.774476718857 - 23 -1258.300104121969 - 33 -0 - 14 -3299.02447671866 - 24 -1258.300104121969 - 34 -0 -100 -AcDbRotatedDimension - 0 -MTEXT - 5 -9E9 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3299.840522810782 - 20 -1255.255954826638 - 30 -0 - 40 -0.18509765625 - 41 -2.138906250000011 - 71 - 1 - 72 - 5 - 1 -FLR_HT_M=4.05 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -9EA -100 -AcDbEntity - 8 -BLK_1_FLR_1_FIRESTAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3316.430967205997 - 20 -1255.075127179796 - 30 -0 - 40 -0.18509765625 - 41 -1.974375000000023 - 71 - 1 - 72 - 5 - 1 -FLR_HT_M=3.6 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -9EB -100 -AcDbEntity - 8 -BLK_1_FLR_2_FIRESTAIR_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3352.076468809833 - 20 -1255.935428104983 - 30 -0 - 40 -0.18509765625 - 41 -1.974375000000023 - 71 - 1 - 72 - 5 - 1 -FLR_HT_M=3.6 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -9EC -100 -AcDbEntity - 8 -BLK_1_FLR_0_SP_WC - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3300.774476717226 - 20 -1259.050104148744 - 10 -3302.724476717179 - 20 -1259.050104148744 - 10 -3302.724476717179 - 20 -1257.550104148744 - 10 -3300.774476717226 - 20 -1257.550104148744 - 0 -LWPOLYLINE - 5 -9ED -100 -AcDbEntity - 8 -BLK_1_FLR_0_WATER_CLOSET - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3302.774476717227 - 20 -1259.050104148744 - 10 -3303.840016419767 - 20 -1259.050104148744 - 10 -3303.840016419767 - 20 -1257.550104148744 - 10 -3302.774476717227 - 20 -1257.550104148744 - 0 -LWPOLYLINE - 5 -9EE -100 -AcDbEntity - 8 -BLK_1_FLR_0_WATER_CLOSET - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3301.774179179687 - 20 -1256.048735667427 - 10 -3300.774476717226 - 20 -1256.048735667427 - 10 -3300.774476717226 - 20 -1257.500104145787 - 10 -3301.774179179687 - 20 -1257.500104145787 - 0 -LWPOLYLINE - 5 -9EF -100 -AcDbEntity - 8 -BLK_1_FLR_1_WATER_CLOSET - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3319.627986019477 - 20 -1259.050104146998 - 10 -3320.693525722017 - 20 -1259.050104146998 - 10 -3320.693525722017 - 20 -1257.550104146998 - 10 -3319.627986019477 - 20 -1257.550104146998 - 0 -LWPOLYLINE - 5 -9F0 -100 -AcDbEntity - 8 -BLK_1_FLR_1_WATER_CLOSET - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3318.62798602204 - 20 -1256.048735665681 - 10 -3317.627986019477 - 20 -1256.048735665681 - 10 -3317.627986019477 - 20 -1257.500104144041 - 10 -3318.62798602204 - 20 -1257.500104144041 - 0 -DIMENSION - 5 -9F1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D60 - 10 -3320.693525724812 - 20 -1257.851297607682 - 30 -0 - 11 -3320.161621811486 - 21 -1257.851297607682 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3319.629717898161 - 23 -1257.867062992372 - 33 -0 - 14 -3320.693525724812 - 24 -1257.867062992372 - 34 -0 -100 -AcDbRotatedDimension - 0 -MTEXT - 5 -9F2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3301.203108666742 - 20 -1258.814638991693 - 30 -0 - 40 -0.18 - 41 -2.844999961839636 - 71 - 1 - 72 - 5 - 1 -\pt2.52;DISABLE TOILET\P1.95X1.50 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 --0.008873397653922362 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -9F3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3301.054003263868 - 20 -1256.496157512387 - 30 -0 - 40 -0.18 - 41 -1.250000000000011 - 71 - 1 - 72 - 5 - 1 -\pt2.52;WC\P1.45X1.00 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -89.9911266023461 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -9F4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3302.872769241266 - 20 -1258.423469386382 - 30 -0 - 40 -0.18 - 41 -1.190000000000011 - 71 - 1 - 72 - 5 - 1 -\pt252;WC\P1.06X1.50 - 7 -sree -210 -0 -220 -0 -230 -1 - 50 --0.008873397653922366 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -9F5 -100 -AcDbEntity - 8 -BLK_1_FLR_0_WASH - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3303.840016419767 - 20 -1257.416490417573 - 10 -3303.501700788219 - 20 -1257.416490417573 - 10 -3303.501700788219 - 20 -1257.012183984098 - 10 -3303.840016419767 - 20 -1257.012183984098 - 0 -LWPOLYLINE - 5 -9F6 -100 -AcDbEntity - 8 -BLK_1_FLR_0_WASH - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3303.840016419767 - 20 -1257.012183984098 - 10 -3303.501700788219 - 20 -1257.012183984098 - 10 -3303.501700788219 - 20 -1256.607877550622 - 10 -3303.840016419767 - 20 -1256.607877550622 - 0 -LWPOLYLINE - 5 -9F7 -100 -AcDbEntity - 8 -BLK_1_FLR_0_WASH - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3303.840016419767 - 20 -1258.16588586402 - 10 -3303.527572195436 - 20 -1258.16588586402 - 10 -3303.527572195436 - 20 -1257.761579430545 - 10 -3303.840016419767 - 20 -1257.761579430545 - 0 -LWPOLYLINE - 5 -9F8 -100 -AcDbEntity - 8 -BLK_1_FLR_0_WASH - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3302.219690062577 - 20 -1258.715224104448 - 10 -3302.666040622906 - 20 -1258.715224104448 - 10 -3302.666040622906 - 20 -1259.050104148744 - 10 -3302.219690062577 - 20 -1259.050104148744 - 0 -LWPOLYLINE - 5 -9F9 -100 -AcDbEntity - 8 -BLK_1_FLR_0_WASH - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3301.09647760688 - 20 -1257.499237734466 - 10 -3300.774476717226 - 20 -1257.500104145787 - 10 -3300.774476717226 - 20 -1256.990234874014 - 10 -3301.09647760688 - 20 -1256.989368462692 - 0 -LWPOLYLINE - 5 -9FA -100 -AcDbEntity - 8 -BLK_1_FLR_1_WASH - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3320.693525721927 - 20 -1258.175063545055 - 10 -3320.366959814676 - 20 -1258.175063545055 - 10 -3320.366959814676 - 20 -1257.77075711158 - 10 -3320.693525721927 - 20 -1257.77075711158 - 0 -LWPOLYLINE - 5 -9FB -100 -AcDbEntity - 8 -BLK_1_FLR_1_WASH - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3317.938974262997 - 20 -1257.500104144041 - 10 -3317.627986019477 - 20 -1257.500104144041 - 10 -3317.627986019477 - 20 -1256.995619385907 - 10 -3317.938974262997 - 20 -1256.995619385907 - 0 -LWPOLYLINE - 5 -9FC -100 -AcDbEntity - 8 -BLK_1_FLR_1_WASH - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3320.693525724812 - 20 -1256.056414286734 - 10 -3320.693525724812 - 20 -1256.50374874116 - 10 -3320.379812578121 - 20 -1256.50374874116 - 10 -3320.379812578121 - 20 -1256.056414286734 - 0 -INSERT - 5 -9FD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbBlockReference - 2 -15 - 10 --4419.017518747216 - 20 -410.517336000665 - 30 -0 - 41 --0.0105407388858543 - 42 -0.0105407388858543 - 43 -0 - 50 -0.0088733995148438 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -LWPOLYLINE - 5 -9FE -100 -AcDbEntity - 8 -BLK_1_FLR_1_WATER_CLOSET - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3317.627986019477 - 20 -1259.050104146998 - 10 -3319.577986019432 - 20 -1259.050104146998 - 10 -3319.577986019432 - 20 -1257.550104146998 - 10 -3317.627986019477 - 20 -1257.550104146998 - 0 -LWPOLYLINE - 5 -9FF -100 -AcDbEntity - 8 -BLK_1_FLR_0_WATER_CLOSET - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3300.774476717226 - 20 -1259.050104148744 - 10 -3302.724476717179 - 20 -1259.050104148744 - 10 -3302.724476717179 - 20 -1257.550104148744 - 10 -3300.774476717226 - 20 -1257.550104148744 - 0 -LWPOLYLINE - 5 -A00 -100 -AcDbEntity - 8 -BLK_1_FLR_0_WASH - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3303.840016419767 - 20 -1256.607877550622 - 10 -3303.501700788219 - 20 -1256.607877550622 - 10 -3303.501700788219 - 20 -1256.203571117147 - 10 -3303.840016419767 - 20 -1256.203571117147 - 0 -INSERT - 5 -A01 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3300.764064482679 - 20 -1257.238723462275 - 30 -0 - 41 --0.5904899999997463 - 42 -0.5904900000003975 - 43 -0 - 50 -89.95617518206222 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -A02 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3302.441257043189 - 20 -1259.05429657233 - 30 -0 - 41 --0.5904899999997461 - 42 -0.5904900000003975 - 43 -0 - 50 -359.9561751820622 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -A03 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3303.840016419676 - 20 -1257.96100172704 - 30 -0 - 41 --0.5904899999997453 - 42 -0.5904900000003975 - 43 -0 - 50 -269.9561751820622 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -A04 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3303.857033020101 - 20 -1257.240480225716 - 30 -0 - 41 --0.5904899999997452 - 42 -0.5904900000003975 - 43 -0 - 50 -269.9561751820622 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -A05 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3303.857033020101 - 20 -1256.431867358765 - 30 -0 - 41 --0.5904899999997452 - 42 -0.5904900000003975 - 43 -0 - 50 -269.9561751820622 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -A06 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3303.857033020101 - 20 -1256.836173792241 - 30 -0 - 41 --0.5904899999997452 - 42 -0.5904900000003975 - 43 -0 - 50 -269.9561751820622 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -A07 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3317.61757378493 - 20 -1257.238723460529 - 30 -0 - 41 --0.5904899999997462 - 42 -0.5904900000003975 - 43 -0 - 50 -89.95617518206222 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -A08 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3320.693525721927 - 20 -1257.961001725294 - 30 -0 - 41 --0.5904899999997452 - 42 -0.5904900000003975 - 43 -0 - 50 -269.9561751820622 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -INSERT - 5 -A09 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3320.700460489955 - 20 -1256.257469881089 - 30 -0 - 41 --0.5904899999997451 - 42 -0.5904900000003975 - 43 -0 - 50 -269.9561751820622 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -LWPOLYLINE - 5 -A0A -100 -AcDbEntity - 8 -PARKING_SLOT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3699.480879126581 - 20 -1130.651148569201 - 10 -3705.530442953199 - 20 -1130.661329416645 - 10 -3705.512340866686 - 20 -1127.631876057222 - 10 -3699.462777040068 - 20 -1127.621695209778 - 0 -LWPOLYLINE - 5 -A0B -100 -AcDbEntity - 8 -PARKING_SLOT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3699.480540771053 - 20 -1127.171011960395 - 10 -3705.53010459767 - 20 -1127.181192807839 - 10 -3705.512002511158 - 20 -1124.151739448416 - 10 -3699.46243868454 - 20 -1124.141558600972 - 0 -LWPOLYLINE - 5 -A0C -100 -AcDbEntity - 8 -PARKING_SLOT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3699.462439489231 - 20 -1124.141693268994 - 10 -3705.512003315851 - 20 -1124.151874116438 - 10 -3705.493901229337 - 20 -1121.122420757015 - 10 -3699.444337402718 - 20 -1121.112239909571 - 0 -LWPOLYLINE - 5 -A0D -100 -AcDbEntity - 8 -PARKING_SLOT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3705.89207145331 - 20 -1114.565780762474 - 10 -3706.904327932729 - 20 -1108.682671348149 - 10 -3703.931686830365 - 20 -1108.105042622127 - 10 -3702.902730137132 - 20 -1114.074096068953 - 0 -LWPOLYLINE - 5 -A0E -100 -AcDbEntity - 8 -DA_PARKING - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3698.227108530828 - 20 -1113.767276560903 - 10 -3701.827108530828 - 20 -1113.767276560903 - 10 -3701.827108530828 - 20 -1107.767276560903 - 10 -3698.227108530828 - 20 -1107.767276560903 - 0 -LWPOLYLINE - 5 -A0F -100 -AcDbEntity - 8 -PARKING_SLOT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3699.445660909198 - 20 -1120.800800139392 - 10 -3705.495224735816 - 20 -1120.810980986836 - 10 -3705.477122649303 - 20 -1117.781527627413 - 10 -3699.427558822686 - 20 -1117.771346779969 - 0 -DIMENSION - 5 -A10 -100 -AcDbEntity - 8 -DA_PARKING - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D61 - 10 -3706.018728615696 - 20 -1114.60003452436 - 30 -0 - 11 -3704.588874033686 - 21 -1113.96528608603 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3702.961422993541 - 23 -1113.775649733043 - 33 -0 - 14 -3705.821132157561 - 24 -1115.045146609702 - 34 -0 - 0 -LWPOLYLINE - 5 -A11 -100 -AcDbEntity - 8 -TWO_WHEELER_PARKING - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3710.700245165523 - 20 -1130.671118105119 - 10 -3708.494483323179 - 20 -1130.671118105119 - 10 -3708.494483323179 - 20 -1118.903961396441 - 10 -3710.700247388511 - 20 -1118.903961396441 - 0 -LWPOLYLINE - 5 -A12 -100 -AcDbEntity - 8 -BLK_1_SHADE_OVERHANG - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3699.233813344707 - 20 -1113.873383950561 - 10 -3699.233845640707 - 20 -1113.342721690382 - 10 -3707.700247410191 - 20 -1113.342721690382 - 10 -3707.700247410191 - 20 -1115.445266810411 - 0 -DIMENSION - 5 -A13 -100 -AcDbEntity - 8 -DIST_EXIT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D62 - 10 -3309.954155061942 - 20 -1250.746552551918 - 30 -0 - 11 -3305.135419876862 - 21 -1253.22399361534 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3300.624476717086 - 23 -1256.300104121969 - 33 -0 - 14 -3310.261947087246 - 24 -1251.345221995126 - 34 -0 - 0 -DIMENSION - 5 -A14 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D63 - 10 -3284.905368613425 - 20 -1245.562005819791 - 30 -0 - 11 -3284.305380836144 - 21 -1245.564713857421 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3283.703068378148 - 23 -1245.052369962679 - 33 -0 - 14 -3284.903043932711 - 24 -1245.046953887419 - 34 -0 - 0 -DIMENSION - 5 -A15 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D64 - 10 -3300.624476717086 - 20 -1256.163161899994 - 30 -0 - 11 -3301.268351205492 - 21 -1256.163161899994 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3299.874476717086 - 23 -1256.300104148744 - 33 -0 - 14 -3300.624476717086 - 24 -1256.300104148744 - 34 -0 - 0 -DIMENSION - 5 -A16 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_DOOR - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D65 - 10 -3307.031947087351 - 20 -1243.673737554059 - 30 -0 - 11 -3305.530034879041 - 21 -1243.673737554059 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3304.02812267073 - 23 -1243.638737554058 - 33 -0 - 14 -3307.031947087351 - 24 -1243.638737554058 - 34 -0 - 0 -DIMENSION - 5 -A17 -100 -AcDbEntity - 8 -BLK_1_FLR_0_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D66 - 10 -3302.324476717273 - 20 -1246.220390913326 - 30 -0 - 11 -3301.72447671718 - 21 -1246.220390913326 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3301.124476717087 - 23 -1245.352369962667 - 33 -0 - 14 -3302.324476717273 - 24 -1245.352369962667 - 34 -0 - 0 -DIMENSION - 5 -A18 -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D67 - 10 -3317.477986019337 - 20 -1256.163161899994 - 30 -0 - 11 -3318.121860507742 - 21 -1256.163161899994 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3316.727986019337 - 23 -1256.300104148744 - 33 -0 - 14 -3317.477986019337 - 24 -1256.300104148744 - 34 -0 - 0 -DIMENSION - 5 -A19 -100 -AcDbEntity - 8 -BLK_1_FLR_1_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D68 - 10 -3319.177986019524 - 20 -1246.220390913326 - 30 -0 - 11 -3318.577986019431 - 21 -1246.220390913326 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3317.977986019338 - 23 -1245.352369962667 - 33 -0 - 14 -3319.177986019524 - 24 -1245.352369962667 - 34 -0 - 0 -DIMENSION - 5 -A1A -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D69 - 10 -3353.688675249461 - 20 -1256.163161922944 - 30 -0 - 11 -3354.332549737865 - 21 -1256.163161922944 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3352.938675249461 - 23 -1256.300104171695 - 33 -0 - 14 -3353.688675249461 - 24 -1256.300104171695 - 34 -0 - 0 -DIMENSION - 5 -A1B -100 -AcDbEntity - 8 -BLK_1_FLR_2_EXIT_WIDTH_STAIR - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D70 - 10 -3355.388675249648 - 20 -1246.220390936277 - 30 -0 - 11 -3354.788675249555 - 21 -1246.220390936277 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3354.188675249461 - 23 -1245.352369985618 - 33 -0 - 14 -3355.388675249648 - 24 -1245.352369985618 - 34 -0 - 0 -DIMENSION - 5 -A1C -100 -AcDbEntity - 8 -BLK_1_FLR_3_EXIT_WIDTH_DOOR - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D71 - 10 -3374.172164166812 - 20 -1255.730104163693 - 30 -0 - 11 -3373.572164166812 - 21 -1255.730104163693 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3372.972164166813 - 23 -1255.550104162563 - 33 -0 - 14 -3374.172164166812 - 24 -1255.730104162563 - 34 -0 -100 -AcDbRotatedDimension - 0 -LWPOLYLINE - 5 -A1D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3281.621170464698 - 20 -1259.049291753751 - 10 -3287.621170464697 - 20 -1259.049291753751 - 10 -3287.621170464697 - 20 -1256.049291753751 - 10 -3281.621170464698 - 20 -1256.049291753751 - 0 -LWPOLYLINE - 5 -A1E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3281.627027190037 - 20 -1255.55000842973 - 10 -3287.627027190037 - 20 -1255.55000842973 - 10 -3287.627027190037 - 20 -1252.55000842973 - 10 -3281.627027190037 - 20 -1252.55000842973 - 0 -LWPOLYLINE - 5 -A1F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3281.618487474098 - 20 -1252.520705829546 - 10 -3287.618487474098 - 20 -1252.520705829546 - 10 -3287.618487474098 - 20 -1249.520705829546 - 10 -3281.618487474098 - 20 -1249.520705829546 - 0 -LWPOLYLINE - 5 -A20 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3281.623068378183 - 20 -1249.360104148715 - 10 -3287.623068378183 - 20 -1249.360104148715 - 10 -3287.623068378183 - 20 -1246.360104148715 - 10 -3281.623068378183 - 20 -1246.360104148715 - 0 -LWPOLYLINE - 5 -A21 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3470.160100466838 - 20 -1246.986620183514 - 10 -3475.636187167638 - 20 -1246.986620183514 - 0 -LINE - 5 -A22 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3458.752670446676 - 20 -1248.186620183584 - 11 -3467.820140816769 - 21 -1248.186620183584 - 0 -LINE - 5 -A23 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3470.160100466838 - 20 -1246.986620183514 - 11 -3457.965393430237 - 21 -1246.986620183514 - 0 -LINE - 5 -A24 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3464.586316400124 - 20 -1248.186620183525 - 11 -3467.590140816788 - 21 -1248.186620183525 - 0 -LINE - 5 -A25 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3464.586316400124 - 20 -1248.186620183525 - 11 -3467.590140816788 - 21 -1248.186620183525 - 0 -LINE - 5 -A26 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3464.586316400124 - 20 -1248.336620183549 - 11 -3467.590140816788 - 21 -1248.336620183549 - 0 -LINE - 5 -A27 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3464.586316400124 - 20 -1248.486620183514 - 11 -3467.590140816788 - 21 -1248.486620183514 - 0 -LINE - 5 -A28 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3464.586316400124 - 20 -1248.636620183537 - 11 -3467.590140816788 - 21 -1248.636620183537 - 0 -HATCH - 5 -A29 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3471.050140817417 - 20 -1249.969758161813 - 11 -3471.050140817417 - 21 -1256.28662018356 - 72 - 1 - 10 -3471.050140817417 - 20 -1256.28662018356 - 11 -3467.820140817236 - 21 -1256.28662018356 - 72 - 1 - 10 -3467.820140817236 - 20 -1256.28662018356 - 11 -3467.820140817236 - 21 -1249.969758161813 - 72 - 1 - 10 -3467.820140817236 - 20 -1249.969758161813 - 11 -3471.050140817417 - 21 -1249.969758161813 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -1.199999999999999 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -HATCH - 5 -A2A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3464.586316400011 - 20 -1251.48662018363 - 11 -3463.112670446662 - 21 -1251.48662018363 - 72 - 1 - 10 -3463.112670446662 - 20 -1251.48662018363 - 11 -3463.112670446662 - 21 -1248.186620183584 - 72 - 1 - 10 -3463.112670446662 - 20 -1248.186620183584 - 11 -3464.586316400011 - 21 -1248.186620183584 - 72 - 1 - 10 -3464.586316400011 - 20 -1248.186620183584 - 11 -3464.586316400011 - 21 -1251.48662018363 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -1.199999999999999 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -HATCH - 5 -A2B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3464.586316400124 - 20 -1256.28662018356 - 11 -3463.112670446662 - 21 -1256.28662018356 - 72 - 1 - 10 -3463.112670446662 - 20 -1256.28662018356 - 11 -3463.112670446662 - 21 -1251.636620183595 - 72 - 1 - 10 -3463.112670446662 - 20 -1251.636620183595 - 11 -3464.586316400011 - 21 -1251.636620183595 - 72 - 1 - 10 -3464.586316400011 - 20 -1251.636620183595 - 11 -3464.586316400124 - 21 -1256.28662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -1.199999999999999 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -LINE - 5 -A2C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3456.165727321906 - 20 -1248.186620183584 - 11 -3467.820140816769 - 21 -1248.186620183584 - 0 -LINE - 5 -A2D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3456.230352529125 - 20 -1247.975084647481 - 11 -3467.820140816886 - 21 -1247.975084647481 - 0 -LINE - 5 -A2E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3455.807058111215 - 20 -1247.816432995434 - 11 -3467.820140816886 - 21 -1247.816432995434 - 0 -LINE - 5 -A2F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3456.086294557584 - 20 -1247.569641536746 - 11 -3467.820140816886 - 21 -1247.569641536746 - 0 -LINE - 5 -A30 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3456.124973958275 - 20 -1247.269966194002 - 11 -3467.820140816886 - 21 -1247.269966194002 - 0 -LWPOLYLINE - 5 -A31 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3462.882670446765 - 20 -1260.786620183557 - 10 -3462.882670446765 - 20 -1261.98662018351 - 10 -3464.586316400208 - 20 -1261.98662018351 - 10 -3464.586316400011 - 20 -1256.586620183549 - 0 -LWPOLYLINE - 5 -A32 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3464.586316400124 - 20 -1256.28662018356 - 10 -3464.586316400011 - 20 -1251.636620183595 - 0 -LWPOLYLINE - 5 -A33 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3471.050140817417 - 20 -1256.286620183557 - 10 -3471.050140817417 - 20 -1246.98662018351 - 0 -LWPOLYLINE - 5 -A34 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3459.582670447184 - 20 -1251.486620183626 - 10 -3467.820140817203 - 20 -1251.486620183626 - 10 -3467.820140817203 - 20 -1251.636620183592 - 10 -3459.582670447184 - 20 -1251.636620183592 - 0 -LWPOLYLINE - 5 -A35 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3467.590140816672 - 20 -1248.636620183595 - 10 -3467.590140816672 - 20 -1251.48662018363 - 10 -3467.820140817236 - 20 -1251.48662018363 - 10 -3467.820140817236 - 20 -1246.98662018363 - 0 -LWPOLYLINE - 5 -A36 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3464.586316399835 - 20 -1260.78662018356 - 10 -3470.750140817371 - 20 -1260.786620183557 - 10 -3471.050140817417 - 20 -1260.786620183557 - 10 -3471.050140817417 - 20 -1256.586620183545 - 0 -LINE - 5 -A37 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.820140817236 - 20 -1251.636620183537 - 11 -3467.820140817236 - 21 -1256.28662018356 - 0 -LINE - 5 -A38 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.820140817236 - 20 -1249.969758161813 - 11 -3471.050140817417 - 21 -1249.969758161813 - 0 -LINE - 5 -A39 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3464.586316400124 - 20 -1248.636620183537 - 11 -3464.586316400124 - 21 -1248.186620183525 - 0 -LINE - 5 -A3A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.590140816788 - 20 -1248.636620183537 - 11 -3467.590140816788 - 21 -1248.186620183525 - 0 -LINE - 5 -A3B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.590140817254 - 20 -1251.636620183537 - 11 -3467.590140817254 - 21 -1256.28662018356 - 0 -LINE - 5 -A3C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.45749947269 - 20 -1251.636620183537 - 11 -3467.45749947269 - 21 -1256.28662018356 - 0 -LINE - 5 -A3D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.241986530633 - 20 -1251.636620183537 - 11 -3467.241986530633 - 21 -1256.28662018356 - 0 -LINE - 5 -A3E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3466.910383170505 - 20 -1251.636620183537 - 11 -3466.910383170505 - 21 -1256.28662018356 - 0 -LINE - 5 -A3F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3466.611940146457 - 20 -1251.636620183537 - 11 -3466.611940146457 - 21 -1256.28662018356 - 0 -LINE - 5 -A40 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3466.247176450244 - 20 -1251.636620183537 - 11 -3466.247176450244 - 21 -1256.28662018356 - 0 -LINE - 5 -A41 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3465.817288587485 - 20 -1251.636620183537 - 11 -3465.817288587485 - 21 -1256.28662018356 - 0 -LWPOLYLINE - 5 -A42 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 0 - 43 -0 - 10 -3463.20631640012 - 20 -1256.28662018356 - 10 -3462.882670446765 - 20 -1256.286620183557 - 10 -3462.882670446765 - 20 -1256.286620183557 - 10 -3462.882670446765 - 20 -1256.586620183545 - 10 -3468.190140816849 - 20 -1256.586620183545 - 10 -3468.190140816849 - 20 -1256.586620183545 - 10 -3468.190140816849 - 20 -1256.286620183557 - 10 -3462.882670446765 - 20 -1256.286620183557 - 0 -LINE - 5 -A43 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3464.586316400011 - 20 -1256.586620183607 - 11 -3464.586316400011 - 21 -1260.786620183618 - 0 -LWPOLYLINE - 5 -A44 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3459.582670446752 - 20 -1248.186620183584 - 10 -3459.582670446752 - 20 -1260.786620183618 - 10 -3459.582670446752 - 20 -1261.98662018363 - 10 -3459.35267044677 - 20 -1261.98662018363 - 10 -3459.35267044677 - 20 -1248.186620183584 - 0 -LWPOLYLINE - 5 -A45 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3459.582670446718 - 20 -1260.786620183615 - 10 -3463.112670446513 - 20 -1260.786620183557 - 0 -LWPOLYLINE - 5 -A46 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3463.112670446746 - 20 -1250.43662018358 - 10 -3463.112670446746 - 20 -1256.286620183559 - 0 -LWPOLYLINE - 5 -A47 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3463.112670446662 - 20 -1251.486620183514 - 10 -3463.112670446662 - 20 -1248.186620183525 - 0 -LWPOLYLINE - 5 -A48 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3459.582670447184 - 20 -1251.636620183592 - 10 -3464.737670446746 - 20 -1251.636620183592 - 10 -3464.737670446746 - 20 -1251.486620183626 - 10 -3459.582670447184 - 20 -1251.486620183626 - 0 -LINE - 5 -A49 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.820140817236 - 20 -1251.48662018363 - 11 -3467.820140817236 - 21 -1251.636620183595 - 0 -LINE - 5 -A4A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.756694022715 - 20 -1251.486620183514 - 11 -3467.756694022715 - 21 -1251.636620183537 - 0 -LINE - 5 -A4B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.613932289915 - 20 -1251.486620183514 - 11 -3467.613932289915 - 21 -1251.636620183537 - 0 -LINE - 5 -A4C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.21341312028 - 20 -1251.486620183514 - 11 -3467.21341312028 - 21 -1251.636620183537 - 0 -LINE - 5 -A4D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3466.741519529406 - 20 -1251.486620183514 - 11 -3466.741519529406 - 21 -1251.636620183537 - 0 -LINE - 5 -A4E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3466.187346196767 - 20 -1251.486620183514 - 11 -3466.187346196767 - 21 -1251.636620183537 - 0 -LINE - 5 -A4F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3465.649956229874 - 20 -1251.486620183514 - 11 -3465.649956229874 - 21 -1251.636620183537 - 0 -LINE - 5 -A50 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3459.582670446718 - 20 -1255.284725128789 - 11 -3463.112670446746 - 21 -1260.043325668128 - 0 -LINE - 5 -A51 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3459.582670446752 - 20 -1255.284725128793 - 11 -3459.582670446752 - 21 -1255.13472512877 - 0 -LINE - 5 -A52 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3459.582670447184 - 20 -1255.134725128882 - 11 -3463.112670446746 - 21 -1259.237228920667 - 0 -LWPOLYLINE - 5 -A53 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3465.24477250435 - 20 -1256.586620183549 - 10 -3465.24477250435 - 20 -1258.686620183525 - 10 -3466.444772504303 - 20 -1258.686620183525 - 10 -3466.444772504303 - 20 -1256.586620183549 - 0 -LWPOLYLINE - 5 -A54 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3465.144772504373 - 20 -1256.586620183549 - 10 -3465.144772504373 - 20 -1258.78662018356 - 10 -3466.54477250428 - 20 -1258.78662018356 - 10 -3466.54477250428 - 20 -1256.586620183549 - 0 -LWPOLYLINE - 5 -A55 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3467.103228608529 - 20 -1256.586620183549 - 10 -3467.103228608529 - 20 -1258.686620183525 - 10 -3468.303228608482 - 20 -1258.686620183525 - 10 -3468.303228608482 - 20 -1256.586620183549 - 0 -LWPOLYLINE - 5 -A56 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3467.003228608435 - 20 -1256.586620183549 - 10 -3467.003228608435 - 20 -1258.78662018356 - 10 -3468.403228608459 - 20 -1258.78662018356 - 10 -3468.403228608459 - 20 -1256.586620183549 - 0 -LWPOLYLINE - 5 -A57 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3468.961684712591 - 20 -1256.586620183549 - 10 -3468.961684712591 - 20 -1258.686620183525 - 10 -3470.161684712861 - 20 -1258.686620183522 - 10 -3470.161684712861 - 20 -1256.586620183545 - 0 -LWPOLYLINE - 5 -A58 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3468.861684712614 - 20 -1256.586620183549 - 10 -3468.861684712614 - 20 -1258.78662018356 - 10 -3470.261684712637 - 20 -1258.78662018356 - 10 -3470.261684712637 - 20 -1256.586620183549 - 0 -LINE - 5 -A59 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3468.190140816849 - 20 -1256.286620183557 - 11 -3470.612173036905 - 21 -1256.286620183557 - 0 -LINE - 5 -A5A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3470.612173036905 - 20 -1256.286620183557 - 11 -3471.062173036859 - 21 -1256.286620183557 - 0 -LINE - 5 -A5B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3471.062173036859 - 20 -1256.286620183557 - 11 -3471.062173036859 - 21 -1256.586620183545 - 0 -LWPOLYLINE - 5 -A5C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3468.190140816849 - 20 -1256.586620183545 - 10 -3471.062173036859 - 20 -1256.586620183545 - 0 -LINE - 5 -A5D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3459.582670446752 - 20 -1253.347083962293 - 11 -3463.112670446746 - 21 -1258.105684500897 - 0 -LINE - 5 -A5E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3459.582670446752 - 20 -1253.197083962328 - 11 -3463.112670446746 - 21 -1257.299587754597 - 0 -LINE - 5 -A5F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3459.582670446752 - 20 -1252.000193151998 - 11 -3462.882670446765 - 21 -1256.448743230605 - 0 -LINE - 5 -A60 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3459.582670446752 - 20 -1251.850193151975 - 11 -3463.112670446662 - 21 -1255.952696944241 - 0 -LINE - 5 -A61 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3460.504927551523 - 20 -1251.636620183537 - 11 -3463.112670446662 - 21 -1255.151976202094 - 0 -LINE - 5 -A62 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3460.781487901844 - 20 -1251.636620183537 - 11 -3463.112670446662 - 21 -1254.345879455799 - 0 -LINE - 5 -A63 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3459.582670446752 - 20 -1257.978506749325 - 11 -3461.665770371246 - 21 -1260.78662018356 - 0 -LINE - 5 -A64 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3459.582670446752 - 20 -1257.828506749302 - 11 -3462.127979592453 - 21 -1260.78662018356 - 0 -LWPOLYLINE - 5 -A65 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3464.586316399835 - 20 -1256.586620183622 - 10 -3464.586316399835 - 20 -1261.986620183529 - 10 -3463.112670446746 - 20 -1261.986620183529 - 0 -LWPOLYLINE - 5 -A66 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3456.997920704456 - 20 -1246.025655220324 - 10 -3455.983326281337 - 20 -1247.471872850558 - 10 -3456.29634507679 - 20 -1247.769085132695 - 10 -3455.76420152307 - 20 -1247.800370254674 - 10 -3456.265047064433 - 20 -1247.988088233458 - 10 -3455.795512425979 - 20 -1248.926649139383 - 0 -LINE - 5 -A67 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.520140817389 - 20 -1247.569641536742 - 11 -3471.050140817417 - 21 -1247.569641536742 - 0 -LWPOLYLINE - 5 -A68 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3464.586316400011 - 20 -1251.636620183595 - 10 -3464.586316400011 - 20 -1248.186620183584 - 0 -LWPOLYLINE - 5 -A69 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3464.586316399975 - 20 -1259.886620183533 - 10 -3471.050140817417 - 20 -1259.886620183533 - 10 -3471.050140817417 - 20 -1259.886620183533 - 10 -3471.050140817417 - 20 -1259.786620183557 - 10 -3464.586316399975 - 20 -1259.786620183557 - 0 -LINE - 5 -A6A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3465.24477250435 - 20 -1258.686620183525 - 11 -3466.444772504303 - 21 -1258.686620183525 - 0 -LINE - 5 -A6B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3465.24477250435 - 20 -1257.336620183549 - 11 -3466.444772504303 - 21 -1257.336620183549 - 0 -LWPOLYLINE - 5 -A6C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3466.444772504303 - 20 -1257.336620183549 - 10 -3465.24477250435 - 20 -1257.336620183549 - 10 -3465.24477250435 - 20 -1258.686620183525 - 10 -3466.444772504303 - 20 -1258.686620183525 - 10 -3466.444772504303 - 20 -1257.336620183549 - 0 -LWPOLYLINE - 5 -A6D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3465.884772504363 - 20 -1258.606620183509 - 10 -3466.364772504345 - 20 -1258.606620183509 - 10 -3466.364772504345 - 20 -1257.416620183507 - 10 -3465.884772504363 - 20 -1257.416620183507 - 0 -LWPOLYLINE - 5 -A6E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3465.804772504289 - 20 -1257.416620183507 - 10 -3465.324772504307 - 20 -1257.416620183507 - 10 -3465.324772504307 - 20 -1258.606620183509 - 10 -3465.804772504289 - 20 -1258.606620183509 - 0 -LINE - 5 -A6F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3465.884772504363 - 20 -1257.416620183507 - 11 -3465.884772504363 - 21 -1258.606620183509 - 0 -LINE - 5 -A70 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3465.804772504289 - 20 -1257.416620183507 - 11 -3465.804772504289 - 21 -1258.606620183509 - 0 -LINE - 5 -A71 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.103228608529 - 20 -1258.686620183525 - 11 -3468.303228608482 - 21 -1258.686620183525 - 0 -LINE - 5 -A72 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.103228608529 - 20 -1257.336620183549 - 11 -3468.303228608482 - 21 -1257.336620183549 - 0 -LWPOLYLINE - 5 -A73 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3468.303228608482 - 20 -1257.336620183549 - 10 -3467.103228608529 - 20 -1257.336620183549 - 10 -3467.103228608529 - 20 -1258.686620183525 - 10 -3468.303228608482 - 20 -1258.686620183525 - 10 -3468.303228608482 - 20 -1257.336620183549 - 0 -LWPOLYLINE - 5 -A74 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3467.743228608544 - 20 -1258.606620183509 - 10 -3468.223228608525 - 20 -1258.606620183509 - 10 -3468.223228608525 - 20 -1257.416620183507 - 10 -3467.743228608544 - 20 -1257.416620183507 - 0 -LWPOLYLINE - 5 -A75 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3467.663228608468 - 20 -1257.416620183507 - 10 -3467.183228608487 - 20 -1257.416620183507 - 10 -3467.183228608487 - 20 -1258.606620183509 - 10 -3467.663228608468 - 20 -1258.606620183509 - 0 -LINE - 5 -A76 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.743228608544 - 20 -1257.416620183507 - 11 -3467.743228608544 - 21 -1258.606620183509 - 0 -LINE - 5 -A77 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.663228608468 - 20 -1257.416620183507 - 11 -3467.663228608468 - 21 -1258.606620183509 - 0 -LINE - 5 -A78 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3468.961684712591 - 20 -1258.686620183525 - 11 -3470.161684712661 - 21 -1258.686620183525 - 0 -LINE - 5 -A79 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3468.961684712591 - 20 -1257.336620183549 - 11 -3470.161684712661 - 21 -1257.336620183549 - 0 -LWPOLYLINE - 5 -A7A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3470.161684712661 - 20 -1257.336620183549 - 10 -3468.961684712591 - 20 -1257.336620183549 - 10 -3468.961684712591 - 20 -1258.686620183525 - 10 -3470.161684712661 - 20 -1258.686620183525 - 10 -3470.161684712661 - 20 -1257.336620183549 - 0 -LWPOLYLINE - 5 -A7B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3469.601684712605 - 20 -1258.606620183509 - 10 -3470.081684712588 - 20 -1258.606620183509 - 10 -3470.081684712588 - 20 -1257.416620183507 - 10 -3469.601684712605 - 20 -1257.416620183507 - 0 -LWPOLYLINE - 5 -A7C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3469.521684712648 - 20 -1257.416620183507 - 10 -3469.041684712666 - 20 -1257.416620183507 - 10 -3469.041684712666 - 20 -1258.606620183509 - 10 -3469.521684712648 - 20 -1258.606620183509 - 0 -LINE - 5 -A7D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3469.601684712605 - 20 -1257.416620183507 - 11 -3469.601684712605 - 21 -1258.606620183509 - 0 -LINE - 5 -A7E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3469.521684712648 - 20 -1257.416620183507 - 11 -3469.521684712648 - 21 -1258.606620183509 - 0 -LINE - 5 -A7F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.364366980768 - 20 -1245.78662018356 - 11 -3448.489835352786 - 21 -1245.78662018356 - 0 -HATCH - 5 -A80 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3441.284366980692 - 20 -1248.636620183537 - 11 -3442.961253593941 - 21 -1248.636620183537 - 72 - 1 - 10 -3442.961253593941 - 20 -1248.636620183537 - 11 -3442.961253593941 - 21 -1248.53662018356 - 72 - 1 - 10 -3442.961253593941 - 20 -1248.53662018356 - 11 -3441.284366980692 - 21 -1248.53662018356 - 72 - 1 - 10 -3441.284366980692 - 20 -1248.53662018356 - 11 -3441.284366980692 - 21 -1248.636620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A81 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3441.054366980712 - 20 -1248.636620183537 - 11 -3441.284366980692 - 21 -1248.636620183537 - 72 - 1 - 10 -3441.284366980692 - 20 -1248.636620183537 - 11 -3441.284366980692 - 21 -1248.53662018356 - 72 - 1 - 10 -3441.284366980692 - 20 -1248.53662018356 - 11 -3441.054366980712 - 21 -1248.53662018356 - 72 - 1 - 10 -3441.054366980712 - 20 -1248.53662018356 - 11 -3441.054366980712 - 21 -1248.636620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A82 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3438.054366980713 - 20 -1248.636620183537 - 11 -3441.054366980712 - 21 -1248.636620183537 - 72 - 1 - 10 -3441.054366980712 - 20 -1248.636620183537 - 11 -3441.054366980712 - 21 -1248.53662018356 - 72 - 1 - 10 -3441.054366980712 - 20 -1248.53662018356 - 11 -3438.054366980713 - 21 -1248.53662018356 - 72 - 1 - 10 -3438.054366980713 - 20 -1248.53662018356 - 11 -3438.054366980713 - 21 -1248.636620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A83 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3437.554366980712 - 20 -1248.636620183537 - 11 -3438.054366980713 - 21 -1248.636620183537 - 72 - 1 - 10 -3438.054366980713 - 20 -1248.636620183537 - 11 -3438.054366980713 - 21 -1248.53662018356 - 72 - 1 - 10 -3438.054366980713 - 20 -1248.53662018356 - 11 -3437.554366980712 - 21 -1248.53662018356 - 72 - 1 - 10 -3437.554366980712 - 20 -1248.53662018356 - 11 -3437.554366980712 - 21 -1248.636620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A84 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1248.53662018356 - 11 -3431.59436698075 - 21 -1248.636620183537 - 72 - 1 - 10 -3431.59436698075 - 20 -1248.636620183537 - 11 -3437.554366980829 - 21 -1248.636620183537 - 72 - 1 - 10 -3437.554366980712 - 20 -1248.636620183537 - 11 -3437.554366980712 - 21 -1248.53662018356 - 72 - 1 - 10 -3437.554366980712 - 20 -1248.53662018356 - 11 -3431.594366980635 - 21 -1248.53662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -A85 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.892101166863 - 20 -1248.636620183553 - 10 -3433.744366980717 - 20 -1248.636620183553 - 0 -LWPOLYLINE - 5 -A86 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3444.692101166709 - 20 -1256.286620183557 - 10 -3434.244366980857 - 20 -1256.286620183557 - 0 -HATCH - 5 -A87 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3435.094366968177 - 20 -1259.78662018356 - 11 -3434.864366968195 - 21 -1259.78662018356 - 72 - 1 - 10 -3434.864366968195 - 20 -1259.78662018356 - 11 -3434.864366968195 - 21 -1259.436620183525 - 72 - 1 - 10 -3434.864366968195 - 20 -1259.436620183525 - 11 -3435.094366968177 - 21 -1259.436620183525 - 72 - 1 - 10 -3435.094366968177 - 20 -1259.436620183525 - 11 -3435.094366968177 - 21 -1259.78662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A88 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3434.344366980749 - 20 -1259.886620183537 - 11 -3434.344366980751 - 21 -1259.789325424532 - 72 - 1 - 10 -3434.344366980751 - 20 -1259.789325424532 - 11 -3434.594366968177 - 21 -1259.789325424532 - 72 - 1 - 10 -3434.594366968177 - 20 -1259.789325424532 - 11 -3434.594366968177 - 21 -1259.886620183537 - 72 - 1 - 10 -3434.594366968177 - 20 -1259.886620183537 - 11 -3434.344366980749 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A89 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 2 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3435.094366968177 - 20 -1259.886620183537 - 11 -3434.864366968195 - 21 -1259.886620183537 - 72 - 1 - 10 -3434.864366968195 - 20 -1259.886620183537 - 11 -3434.864366968195 - 21 -1259.789325424532 - 72 - 1 - 10 -3434.864366968195 - 20 -1259.789325424532 - 11 -3435.094366968177 - 21 -1259.789325424532 - 72 - 1 - 10 -3435.094366968177 - 20 -1259.789325424532 - 11 -3435.094366968177 - 21 -1259.886620183537 - 97 - 0 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3437.824366980731 - 20 -1259.886620183537 - 11 -3434.864366968195 - 21 -1259.886620183537 - 72 - 1 - 10 -3434.864366968195 - 20 -1259.886620183537 - 11 -3434.864366968195 - 21 -1259.789325424532 - 72 - 1 - 10 -3434.864366968195 - 20 -1259.789325424532 - 11 -3437.824366980731 - 21 -1259.789325424532 - 72 - 1 - 10 -3437.824366980731 - 20 -1259.789325424532 - 11 -3437.824366980731 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A8A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3438.054366980713 - 20 -1259.886620183537 - 11 -3437.824366980731 - 21 -1259.886620183537 - 72 - 1 - 10 -3437.824366980731 - 20 -1259.886620183537 - 11 -3437.824366980731 - 21 -1259.789325424532 - 72 - 1 - 10 -3437.824366980731 - 20 -1259.789325424532 - 11 -3438.054366980713 - 21 -1259.789325424532 - 72 - 1 - 10 -3438.054366980713 - 20 -1259.789325424532 - 11 -3438.054366980713 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A8B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3441.054366980712 - 20 -1259.886620183537 - 11 -3438.054366980713 - 21 -1259.886620183537 - 72 - 1 - 10 -3438.054366980713 - 20 -1259.886620183537 - 11 -3438.054366980713 - 21 -1259.789325424532 - 72 - 1 - 10 -3438.054366980713 - 20 -1259.789325424532 - 11 -3441.054366980712 - 21 -1259.789325424532 - 72 - 1 - 10 -3441.054366980712 - 20 -1259.789325424532 - 11 -3441.054366980712 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A8C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3441.284366980692 - 20 -1259.886620183537 - 11 -3441.054366980712 - 21 -1259.886620183537 - 72 - 1 - 10 -3441.054366980712 - 20 -1259.886620183537 - 11 -3441.054366980712 - 21 -1259.789325424532 - 72 - 1 - 10 -3441.054366980712 - 20 -1259.789325424532 - 11 -3441.284366980692 - 21 -1259.789325424532 - 72 - 1 - 10 -3441.284366980692 - 20 -1259.789325424532 - 11 -3441.284366980692 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A8D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3444.192101166733 - 20 -1259.886620183537 - 11 -3441.284366980692 - 21 -1259.886620183537 - 72 - 1 - 10 -3441.284366980692 - 20 -1259.886620183537 - 11 -3441.284366980692 - 21 -1259.789325424532 - 72 - 1 - 10 -3441.284366980692 - 20 -1259.789325424532 - 11 -3444.192101166733 - 21 -1259.789325424532 - 72 - 1 - 10 -3444.192101166733 - 20 -1259.789325424532 - 11 -3444.192101166733 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A8E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3444.554366980713 - 20 -1259.886620183537 - 11 -3444.192101166733 - 21 -1259.886620183537 - 72 - 1 - 10 -3444.192101166733 - 20 -1259.886620183537 - 11 -3444.192101166733 - 21 -1259.789325424532 - 72 - 1 - 10 -3444.192101166733 - 20 -1259.789325424532 - 11 -3444.554366980713 - 21 -1259.789325424532 - 72 - 1 - 10 -3444.554366980713 - 20 -1259.789325424532 - 11 -3444.554366980713 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A8F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3444.784366980695 - 20 -1259.886620183537 - 11 -3444.554366980713 - 21 -1259.886620183537 - 72 - 1 - 10 -3444.554366980713 - 20 -1259.886620183537 - 11 -3444.554366980713 - 21 -1259.789325424532 - 72 - 1 - 10 -3444.554366980713 - 20 -1259.789325424532 - 11 -3444.784366980695 - 21 -1259.789325424532 - 72 - 1 - 10 -3444.784366980695 - 20 -1259.789325424532 - 11 -3444.784366980695 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A90 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3445.892101166805 - 20 -1259.886620183537 - 11 -3444.784366980695 - 21 -1259.886620183537 - 72 - 1 - 10 -3444.784366980695 - 20 -1259.886620183537 - 11 -3444.784366980695 - 21 -1259.789325424532 - 72 - 1 - 10 -3444.784366980695 - 20 -1259.789325424532 - 11 -3445.892101166805 - 21 -1259.789325424532 - 72 - 1 - 10 -3445.892101166805 - 20 -1259.789325424532 - 11 -3445.892101166805 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A91 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3447.989835352786 - 20 -1259.886620183537 - 11 -3447.922101166831 - 21 -1259.886620183537 - 72 - 1 - 10 -3447.922101166831 - 20 -1259.886620183537 - 11 -3447.922101166831 - 21 -1259.789325424532 - 72 - 1 - 10 -3447.922101166831 - 20 -1259.789325424532 - 11 -3447.989835352786 - 21 -1259.789325424532 - 72 - 1 - 10 -3447.989835352786 - 20 -1259.789325424532 - 11 -3447.989835352786 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A92 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3447.922101166831 - 20 -1259.886620183537 - 11 -3445.892101166805 - 21 -1259.886620183537 - 72 - 1 - 10 -3445.892101166805 - 20 -1259.886620183537 - 11 -3445.892101166805 - 21 -1259.789325424532 - 72 - 1 - 10 -3445.892101166805 - 20 -1259.789325424532 - 11 -3447.922101166831 - 21 -1259.789325424532 - 72 - 1 - 10 -3447.922101166831 - 20 -1259.789325424532 - 11 -3447.922101166831 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A93 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.162101166705 - 20 -1259.886620183537 - 11 -3447.989835352786 - 21 -1259.886620183537 - 72 - 1 - 10 -3447.989835352786 - 20 -1259.886620183537 - 11 -3447.989835352786 - 21 -1259.789325424532 - 72 - 1 - 10 -3447.989835352786 - 20 -1259.789325424532 - 11 -3448.162101166705 - 21 -1259.789325424532 - 72 - 1 - 10 -3448.162101166705 - 20 -1259.789325424532 - 11 -3448.162101166705 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A94 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.29210116671 - 20 -1259.886620183537 - 11 -3448.162101166705 - 21 -1259.886620183537 - 72 - 1 - 10 -3448.162101166705 - 20 -1259.886620183537 - 11 -3448.162101166705 - 21 -1259.789325424532 - 72 - 1 - 10 -3448.162101166705 - 20 -1259.789325424532 - 11 -3448.29210116671 - 21 -1259.789325424532 - 72 - 1 - 10 -3448.29210116671 - 20 -1259.789325424532 - 11 -3448.29210116671 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A95 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.489835352786 - 20 -1259.886620183537 - 11 -3448.29210116671 - 21 -1259.886620183537 - 72 - 1 - 10 -3448.29210116671 - 20 -1259.886620183537 - 11 -3448.29210116671 - 21 -1259.789325424532 - 72 - 1 - 10 -3448.29210116671 - 20 -1259.789325424532 - 11 -3448.489835352786 - 21 -1259.789325424532 - 72 - 1 - 10 -3448.489835352786 - 20 -1259.789325424532 - 11 -3448.489835352786 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A96 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 5 -370 - 0 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.489835352786 - 20 -1259.78662018356 - 11 -3448.29210116671 - 21 -1259.78662018356 - 72 - 1 - 10 -3448.29210116671 - 20 -1259.78662018356 - 11 -3448.29210116671 - 21 -1259.436620183525 - 72 - 1 - 10 -3448.29210116671 - 20 -1259.436620183525 - 11 -3448.489835352786 - 21 -1259.436620183525 - 72 - 1 - 10 -3448.489835352786 - 20 -1259.436620183525 - 11 -3448.489835352786 - 21 -1259.78662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A97 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 2 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3435.094366968177 - 20 -1259.886620183537 - 11 -3434.864366968195 - 21 -1259.886620183537 - 72 - 1 - 10 -3434.864366968195 - 20 -1259.886620183537 - 11 -3434.864366968195 - 21 -1259.789325424532 - 72 - 1 - 10 -3434.864366968195 - 20 -1259.789325424532 - 11 -3435.094366968177 - 21 -1259.789325424532 - 72 - 1 - 10 -3435.094366968177 - 20 -1259.789325424532 - 11 -3435.094366968177 - 21 -1259.886620183537 - 97 - 0 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3434.864366968195 - 20 -1259.886620183537 - 11 -3434.594366968177 - 21 -1259.886620183537 - 72 - 1 - 10 -3434.594366968177 - 20 -1259.886620183537 - 11 -3434.594366968177 - 21 -1259.789325424532 - 72 - 1 - 10 -3434.594366968177 - 20 -1259.789325424532 - 11 -3434.864366968195 - 21 -1259.789325424532 - 72 - 1 - 10 -3434.864366968195 - 20 -1259.789325424532 - 11 -3434.864366968195 - 21 -1259.886620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -A98 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3448.489835352786 - 20 -1259.789325424532 - 10 -3434.344366980751 - 20 -1259.789325424532 - 0 -LWPOLYLINE - 5 -A99 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3448.489835352637 - 20 -1259.886620183537 - 10 -3434.344366980751 - 20 -1259.884787151034 - 0 -LWPOLYLINE - 5 -A9A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3438.054366980713 - 20 -1259.78662018356 - 10 -3437.554366980712 - 20 -1259.78662018356 - 0 -LWPOLYLINE - 5 -A9B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3444.592101166723 - 20 -1256.186620183522 - 10 -3434.144366980763 - 20 -1256.186620183522 - 0 -HATCH - 5 -A9C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3444.192101166733 - 20 -1248.636620183537 - 11 -3442.961253593941 - 21 -1248.636620183537 - 72 - 1 - 10 -3442.961253593941 - 20 -1248.636620183537 - 11 -3442.961253593941 - 21 -1248.53662018356 - 72 - 1 - 10 -3442.961253593941 - 20 -1248.53662018356 - 11 -3444.192101166733 - 21 -1248.53662018356 - 72 - 1 - 10 -3444.192101166733 - 20 -1248.53662018356 - 11 -3444.192101166733 - 21 -1248.636620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A9D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3445.187635226016 - 20 -1248.636620183537 - 11 -3444.554366980713 - 21 -1248.636620183537 - 72 - 1 - 10 -3444.554366980713 - 20 -1248.636620183537 - 11 -3444.554366980713 - 21 -1248.53662018356 - 72 - 1 - 10 -3444.554366980713 - 20 -1248.53662018356 - 11 -3445.192101166711 - 21 -1248.536620183537 - 72 - 1 - 10 -3445.192101166711 - 20 -1248.536620183537 - 11 -3445.187635226016 - 21 -1248.636620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A9E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3444.554366980713 - 20 -1248.636620183537 - 11 -3444.192101166733 - 21 -1248.636620183537 - 72 - 1 - 10 -3444.192101166733 - 20 -1248.636620183537 - 11 -3444.192101166733 - 21 -1248.53662018356 - 72 - 1 - 10 -3444.192101166733 - 20 -1248.53662018356 - 11 -3444.554366980713 - 21 -1248.53662018356 - 72 - 1 - 10 -3444.554366980713 - 20 -1248.53662018356 - 11 -3444.554366980713 - 21 -1248.636620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -A9F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3438.054366980713 - 20 -1248.53662018356 - 11 -3437.824366980731 - 21 -1248.53662018356 - 72 - 1 - 10 -3437.824366980731 - 20 -1248.53662018356 - 11 -3437.824366980731 - 21 -1248.236620183514 - 72 - 1 - 10 -3437.824366980731 - 20 -1248.236620183514 - 11 -3438.054366980713 - 21 -1248.236620183514 - 72 - 1 - 10 -3438.054366980713 - 20 -1248.236620183514 - 11 -3438.054366980713 - 21 -1248.53662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -AA0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3444.784366980695 - 20 -1248.53662018356 - 11 -3444.554366980713 - 21 -1248.53662018356 - 72 - 1 - 10 -3444.554366980713 - 20 -1248.53662018356 - 11 -3444.554366980713 - 21 -1248.236620183514 - 72 - 1 - 10 -3444.554366980713 - 20 -1248.236620183514 - 11 -3444.784366980695 - 21 -1248.236620183514 - 72 - 1 - 10 -3444.784366980695 - 20 -1248.236620183514 - 11 -3444.784366980695 - 21 -1248.53662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -AA1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.192101166816 - 20 -1248.536620183557 - 10 -3431.294366980903 - 20 -1248.536620183557 - 0 -LINE - 5 -AA2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3442.961253594003 - 20 -1248.636620183553 - 11 -3442.961253594003 - 21 -1245.786620183576 - 0 -LINE - 5 -AA3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3442.961253593941 - 20 -1245.78662018356 - 11 -3440.757226175545 - 21 -1245.78662018356 - 0 -LINE - 5 -AA4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.364366980768 - 20 -1245.631902978352 - 11 -3431.364366980768 - 21 -1262.186620183525 - 0 -LINE - 5 -AA5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3437.824366980731 - 20 -1244.28662018356 - 11 -3437.824366980731 - 21 -1252.586686850121 - 0 -LINE - 5 -AA6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 3 -370 - 0 -100 -AcDbLine - 10 -3437.824366980731 - 20 -1252.686620183525 - 11 -3437.824366980731 - 21 -1256.186620183525 - 0 -LINE - 5 -AA7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3437.824366980731 - 20 -1256.28662018356 - 11 -3437.824366980731 - 21 -1259.886620183537 - 0 -LINE - 5 -AA8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1244.28662018356 - 11 -3438.054366980713 - 21 -1252.586691256267 - 0 -LINE - 5 -AA9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 3 -370 - 0 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1252.686620183525 - 11 -3438.054366980713 - 21 -1256.186620183525 - 0 -LINE - 5 -AAA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1256.28662018356 - 11 -3438.054366980713 - 21 -1259.886620183537 - 0 -LINE - 5 -AAB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 3 -370 - 0 -100 -AcDbLine - 10 -3441.284366980692 - 20 -1252.686620183525 - 11 -3441.284366980692 - 21 -1256.186620183525 - 0 -LINE - 5 -AAC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 3 -370 - 0 -100 -AcDbLine - 10 -3441.284366980692 - 20 -1256.28662018356 - 11 -3441.284366980692 - 21 -1259.886620183537 - 0 -LINE - 5 -AAD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 3 -370 - 0 -100 -AcDbLine - 10 -3441.054366980712 - 20 -1252.686620183525 - 11 -3441.054366980712 - 21 -1256.186620183525 - 0 -LINE - 5 -AAE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 3 -370 - 0 -100 -AcDbLine - 10 -3441.054366980712 - 20 -1256.28662018356 - 11 -3441.054366980712 - 21 -1259.886620183537 - 0 -LINE - 5 -AAF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3444.55436698068 - 20 -1244.286620183557 - 11 -3444.55436698068 - 21 -1248.636620183533 - 0 -LINE - 5 -AB0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3444.784366980695 - 20 -1244.28662018356 - 11 -3444.784366980695 - 21 -1248.636620183553 - 0 -HATCH - 5 -AB1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1247.436620183525 - 11 -3431.364366980768 - 21 -1247.436620183525 - 72 - 1 - 10 -3431.364366980768 - 20 -1247.436620183525 - 11 -3431.364366980768 - 21 -1247.336620183549 - 72 - 1 - 10 -3431.364366980768 - 20 -1247.336620183549 - 11 -3431.59436698075 - 21 -1247.336620183549 - 72 - 1 - 10 -3431.59436698075 - 20 -1247.336620183549 - 11 -3431.59436698075 - 21 -1247.436620183525 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -AB2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1247.78662018356 - 11 -3431.364366980768 - 21 -1247.78662018356 - 72 - 1 - 10 -3431.364366980768 - 20 -1247.78662018356 - 11 -3431.364366980768 - 21 -1247.436620183525 - 72 - 1 - 10 -3431.364366980768 - 20 -1247.436620183525 - 11 -3431.59436698075 - 21 -1247.436620183525 - 72 - 1 - 10 -3431.59436698075 - 20 -1247.436620183525 - 11 -3431.59436698075 - 21 -1247.78662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -AB3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3444.784366980695 - 20 -1245.78662018356 - 10 -3431.364366980768 - 20 -1245.78662018356 - 0 -LINE - 5 -AB4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3453.138227600405 - 20 -1246.986620183514 - 11 -3448.489835352786 - 21 -1248.035623844076 - 0 -LWPOLYLINE - 5 -AB5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3429.255147392662 - 20 -1245.631902978352 - 10 -3429.255147392662 - 20 -1246.386620183537 - 10 -3429.255147392662 - 20 -1246.986620183514 - 10 -3424.159135151804 - 20 -1246.986620183514 - 0 -LWPOLYLINE - 5 -AB6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3429.255147392662 - 20 -1246.986620183514 - 10 -3429.255147392662 - 20 -1248.186620183525 - 10 -3429.485147392643 - 20 -1248.186620183525 - 10 -3429.485147392643 - 20 -1245.486620183514 - 0 -LINE - 5 -AB7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3451.883573844015 - 20 -1247.269758161801 - 11 -3447.092101166756 - 21 -1245.78662018356 - 0 -LINE - 5 -AB8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.59436698075 - 20 -1248.636620183537 - 11 -3431.59436698075 - 21 -1245.78662018356 - 0 -HATCH - 5 -AB9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.364366980768 - 20 -1245.78662018356 - 11 -3431.59436698075 - 21 -1245.78662018356 - 72 - 1 - 10 -3431.59436698075 - 20 -1245.78662018356 - 11 -3431.59436698075 - 21 -1245.686620183525 - 72 - 1 - 10 -3431.59436698075 - 20 -1245.686620183525 - 11 -3431.364366980768 - 21 -1245.686620183525 - 72 - 1 - 10 -3431.364366980768 - 20 -1245.686620183525 - 11 -3431.364366980768 - 21 -1245.78662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -ABA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.364366980768 - 20 -1245.686620183525 - 11 -3431.59436698075 - 21 -1245.686620183525 - 72 - 1 - 10 -3431.59436698075 - 20 -1245.686620183525 - 11 -3431.59436698075 - 21 -1245.186620183525 - 72 - 1 - 10 -3431.59436698075 - 20 -1245.186620183525 - 11 -3431.364366980768 - 21 -1245.186620183525 - 72 - 1 - 10 -3431.364366980768 - 20 -1245.186620183525 - 11 -3431.364366980768 - 21 -1245.686620183525 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -ABB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3431.59436698075 - 20 -1245.78662018356 - 10 -3431.364366980768 - 20 -1245.78662018356 - 10 -3431.364366980768 - 20 -1245.186620183525 - 10 -3431.59436698075 - 20 -1245.186620183525 - 10 -3431.59436698075 - 20 -1245.78662018356 - 0 -HATCH - 5 -ABC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3437.824366980731 - 20 -1245.78662018356 - 11 -3438.054366980713 - 21 -1245.78662018356 - 72 - 1 - 10 -3438.054366980713 - 20 -1245.78662018356 - 11 -3438.054366980713 - 21 -1245.686620183525 - 72 - 1 - 10 -3438.054366980713 - 20 -1245.686620183525 - 11 -3437.824366980731 - 21 -1245.686620183525 - 72 - 1 - 10 -3437.824366980731 - 20 -1245.686620183525 - 11 -3437.824366980731 - 21 -1245.78662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -ABD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3437.824366980731 - 20 -1245.686620183525 - 11 -3438.054366980713 - 21 -1245.686620183525 - 72 - 1 - 10 -3438.054366980713 - 20 -1245.686620183525 - 11 -3438.054366980713 - 21 -1245.186620183525 - 72 - 1 - 10 -3438.054366980713 - 20 -1245.186620183525 - 11 -3437.824366980731 - 21 -1245.186620183525 - 72 - 1 - 10 -3437.824366980731 - 20 -1245.186620183525 - 11 -3437.824366980731 - 21 -1245.686620183525 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -ABE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3438.054366980772 - 20 -1245.786620183576 - 10 -3437.824366980791 - 20 -1245.786620183576 - 10 -3437.824366980731 - 20 -1245.186620183525 - 10 -3438.054366980713 - 20 -1245.186620183525 - 10 -3438.054366980713 - 20 -1245.78662018356 - 0 -HATCH - 5 -ABF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3441.054366980712 - 20 -1245.78662018356 - 11 -3441.284366980692 - 21 -1245.78662018356 - 72 - 1 - 10 -3441.284366980692 - 20 -1245.78662018356 - 11 -3441.284366980692 - 21 -1245.686620183525 - 72 - 1 - 10 -3441.284366980692 - 20 -1245.686620183525 - 11 -3441.054366980712 - 21 -1245.686620183525 - 72 - 1 - 10 -3441.054366980712 - 20 -1245.686620183525 - 11 -3441.054366980712 - 21 -1245.78662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -AC0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3441.054366980712 - 20 -1245.686620183525 - 11 -3441.284366980692 - 21 -1245.686620183525 - 72 - 1 - 10 -3441.284366980692 - 20 -1245.686620183525 - 11 -3441.284366980692 - 21 -1245.186620183525 - 72 - 1 - 10 -3441.284366980692 - 20 -1245.186620183525 - 11 -3441.054366980712 - 21 -1245.186620183525 - 72 - 1 - 10 -3441.054366980712 - 20 -1245.186620183525 - 11 -3441.054366980712 - 21 -1245.686620183525 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -AC1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3441.284366980692 - 20 -1245.78662018356 - 10 -3441.054366980712 - 20 -1245.78662018356 - 10 -3441.054366980712 - 20 -1245.186620183525 - 10 -3441.284366980692 - 20 -1245.186620183525 - 10 -3441.284366980692 - 20 -1245.78662018356 - 0 -HATCH - 5 -AC2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3444.554366980713 - 20 -1245.78662018356 - 11 -3444.784366980695 - 21 -1245.78662018356 - 72 - 1 - 10 -3444.784366980695 - 20 -1245.78662018356 - 11 -3444.784366980695 - 21 -1245.686620183525 - 72 - 1 - 10 -3444.784366980695 - 20 -1245.686620183525 - 11 -3444.554366980713 - 21 -1245.686620183525 - 72 - 1 - 10 -3444.554366980713 - 20 -1245.686620183525 - 11 -3444.554366980713 - 21 -1245.78662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -AC3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3444.554366980713 - 20 -1245.787767908768 - 11 -3444.784366980695 - 21 -1245.787767908768 - 72 - 1 - 10 -3444.784366980695 - 20 -1245.787767908768 - 11 -3444.784366980695 - 21 -1245.287767908768 - 72 - 1 - 10 -3444.784366980695 - 20 -1245.287767908768 - 11 -3444.554366980713 - 21 -1245.287767908768 - 72 - 1 - 10 -3444.554366980713 - 20 -1245.287767908768 - 11 -3444.554366980713 - 21 -1245.787767908768 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -AC4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3444.784366980695 - 20 -1245.78662018356 - 10 -3444.554366980713 - 20 -1245.78662018356 - 10 -3444.554366980713 - 20 -1245.186620183525 - 10 -3444.784366980695 - 20 -1245.186620183525 - 10 -3444.784366980695 - 20 -1245.78662018356 - 0 -DIMENSION - 5 -AC5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D72 - 10 -3441.054366980712 - 20 -1245.868946037968 - 30 -0 - 11 -3440.703357607965 - 21 -1245.996469469835 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3441.284366980692 - 23 -1246.12440066169 - 33 -0 - 14 -3441.054366980712 - 24 -1246.12440066169 - 34 -0 - 50 -180 -100 -AcDbRotatedDimension - 0 -HATCH - 5 -AC6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3441.054366980712 - 20 -1248.53662018356 - 11 -3441.284366980692 - 21 -1248.53662018356 - 72 - 1 - 10 -3441.284366980692 - 20 -1248.53662018356 - 11 -3441.284366980692 - 21 -1248.436620183525 - 72 - 1 - 10 -3441.284366980692 - 20 -1248.436620183525 - 11 -3441.054366980712 - 21 -1248.436620183525 - 72 - 1 - 10 -3441.054366980712 - 20 -1248.436620183525 - 11 -3441.054366980712 - 21 -1248.53662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -AC7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3437.824366980731 - 20 -1248.53662018356 - 11 -3438.054366980713 - 21 -1248.53662018356 - 72 - 1 - 10 -3438.054366980713 - 20 -1248.53662018356 - 11 -3438.054366980713 - 21 -1248.436620183525 - 72 - 1 - 10 -3438.054366980713 - 20 -1248.436620183525 - 11 -3437.824366980731 - 21 -1248.436620183525 - 72 - 1 - 10 -3437.824366980731 - 20 -1248.436620183525 - 11 -3437.824366980731 - 21 -1248.53662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -AC8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3431.364366980768 - 20 -1245.78662018356 - 10 -3431.364366980736 - 20 -1245.786620183557 - 10 -3430.856520395027 - 20 -1245.631902978348 - 0 -LINE - 5 -AC9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.364366980768 - 20 -1245.631902978352 - 11 -3431.364366980768 - 21 -1262.186620183525 - 0 -HATCH - 5 -ACA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 5 - 72 - 1 - 10 -3431.865465748098 - 20 -1250.572620183552 - 11 -3431.595465748081 - 21 -1250.572620183552 - 72 - 1 - 10 -3431.595465748081 - 20 -1250.572620183552 - 11 -3431.595465748081 - 21 -1250.522620183563 - 72 - 1 - 10 -3431.595465748081 - 20 -1250.522620183563 - 11 -3431.595465748081 - 21 -1250.472620183575 - 72 - 1 - 10 -3431.595465748081 - 20 -1250.472620183575 - 11 -3431.865465748098 - 21 -1250.472620183575 - 72 - 1 - 10 -3431.865465748098 - 20 -1250.472620183575 - 11 -3431.865465748098 - 21 -1250.572620183552 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LINE - 5 -ACB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.59436698075 - 20 -1245.631902978352 - 11 -3431.59436698075 - 21 -1262.186620183525 - 0 -LINE - 5 -ACC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1245.534608219346 - 11 -3435.094366968177 - 21 -1252.586634551295 - 0 -LINE - 5 -ACD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1252.686620183525 - 11 -3435.094366968177 - 21 -1256.186620183525 - 0 -LINE - 5 -ACE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1256.28662018356 - 11 -3435.094366968177 - 21 -1259.789325424532 - 0 -LINE - 5 -ACF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1244.28662018356 - 11 -3438.054366980713 - 21 -1252.586691256267 - 0 -LINE - 5 -AD0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1252.686620183525 - 11 -3438.054366980713 - 21 -1256.186620183525 - 0 -LINE - 5 -AD1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1256.28662018356 - 11 -3438.054366980713 - 21 -1259.886620183537 - 0 -LINE - 5 -AD2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3437.824366980731 - 20 -1244.28662018356 - 11 -3437.824366980731 - 21 -1252.586686850121 - 0 -LINE - 5 -AD3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3437.824366980731 - 20 -1252.686620183525 - 11 -3437.824366980731 - 21 -1256.186620183525 - 0 -LINE - 5 -AD4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3437.824366980731 - 20 -1256.28662018356 - 11 -3437.824366980731 - 21 -1259.886620183537 - 0 -LINE - 5 -AD5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3441.054366980712 - 20 -1252.686620183525 - 11 -3441.054366980712 - 21 -1256.186620183525 - 0 -LINE - 5 -AD6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3441.054366980712 - 20 -1256.28662018356 - 11 -3441.054366980712 - 21 -1259.886620183537 - 0 -LINE - 5 -AD7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3441.284366980692 - 20 -1252.686620183525 - 11 -3441.284366980692 - 21 -1256.186620183525 - 0 -LINE - 5 -AD8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - 0 -100 -AcDbLine - 10 -3441.284366980692 - 20 -1256.28662018356 - 11 -3441.284366980692 - 21 -1259.886620183537 - 0 -LINE - 5 -AD9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3448.489835352637 - 20 -1245.631902978348 - 11 -3448.489835352637 - 21 -1261.231902978325 - 0 -LINE - 5 -ADA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3433.744366980717 - 20 -1248.636620183553 - 11 -3438.054366980772 - 21 -1248.636620183553 - 0 -HATCH - 5 -ADB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.392101166688 - 20 -1247.586620183549 - 11 -3448.29210116671 - 21 -1247.586620183549 - 72 - 1 - 10 -3448.29210116671 - 20 -1247.586620183549 - 11 -3448.29210116671 - 21 -1247.28662018356 - 72 - 1 - 10 -3448.29210116671 - 20 -1247.28662018356 - 11 -3448.392101166688 - 21 -1247.28662018356 - 72 - 1 - 10 -3448.392101166688 - 20 -1247.28662018356 - 11 -3448.392101166688 - 21 -1247.586620183549 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -ADC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.489835352786 - 20 -1247.586620183549 - 11 -3448.392101166688 - 21 -1247.586620183549 - 72 - 1 - 10 -3448.392101166688 - 20 -1247.586620183549 - 11 -3448.392101166688 - 21 -1247.28662018356 - 72 - 1 - 10 -3448.392101166688 - 20 -1247.28662018356 - 11 -3448.489835352786 - 21 -1247.28662018356 - 72 - 1 - 10 -3448.489835352786 - 20 -1247.28662018356 - 11 -3448.489835352786 - 21 -1247.586620183549 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -ADD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.489835352786 - 20 -1247.28662018356 - 11 -3448.392101166688 - 21 -1247.28662018356 - 72 - 1 - 10 -3448.392101166688 - 20 -1247.28662018356 - 11 -3448.392101166688 - 21 -1247.186620183525 - 72 - 1 - 10 -3448.392101166688 - 20 -1247.186620183525 - 11 -3448.489835352786 - 21 -1247.186620183525 - 72 - 1 - 10 -3448.489835352786 - 20 -1247.186620183525 - 11 -3448.489835352786 - 21 -1247.28662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -ADE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.392101166688 - 20 -1247.28662018356 - 11 -3448.29210116671 - 21 -1247.28662018356 - 72 - 1 - 10 -3448.29210116671 - 20 -1247.28662018356 - 11 -3448.29210116671 - 21 -1247.186620183525 - 72 - 1 - 10 -3448.29210116671 - 20 -1247.186620183525 - 11 -3448.392101166688 - 21 -1247.186620183525 - 72 - 1 - 10 -3448.392101166688 - 20 -1247.186620183525 - 11 -3448.392101166688 - 21 -1247.28662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -ADF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.29210116671 - 20 -1247.28662018356 - 11 -3448.162101166705 - 21 -1247.28662018356 - 72 - 1 - 10 -3448.162101166705 - 20 -1247.28662018356 - 11 -3448.162101166705 - 21 -1247.186620183525 - 72 - 1 - 10 -3448.162101166705 - 20 -1247.186620183525 - 11 -3448.29210116671 - 21 -1247.186620183525 - 72 - 1 - 10 -3448.29210116671 - 20 -1247.186620183525 - 11 -3448.29210116671 - 21 -1247.28662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -AE0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.162101166705 - 20 -1247.28662018356 - 11 -3447.989835352786 - 21 -1247.28662018356 - 72 - 1 - 10 -3447.989835352786 - 20 -1247.28662018356 - 11 -3447.989835352786 - 21 -1247.186620183525 - 72 - 1 - 10 -3447.989835352786 - 20 -1247.186620183525 - 11 -3448.162101166705 - 21 -1247.186620183525 - 72 - 1 - 10 -3448.162101166705 - 20 -1247.186620183525 - 11 -3448.162101166705 - 21 -1247.28662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LINE - 5 -AE1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1259.789325424532 - 11 -3435.094366968177 - 21 -1256.28662018356 - 0 -LINE - 5 -AE2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1256.186620183525 - 11 -3435.094366968177 - 21 -1252.686620183525 - 0 -LINE - 5 -AE3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1252.586634551295 - 11 -3435.094366968177 - 21 -1245.534608219346 - 0 -LINE - 5 -AE4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3437.824366980731 - 20 -1259.886620183537 - 11 -3437.824366980731 - 21 -1256.28662018356 - 0 -LINE - 5 -AE5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3437.824366980731 - 20 -1256.186620183525 - 11 -3437.824366980731 - 21 -1252.686620183525 - 0 -LINE - 5 -AE6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3437.824366980731 - 20 -1252.586686850121 - 11 -3437.824366980731 - 21 -1244.28662018356 - 0 -LINE - 5 -AE7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1259.886620183537 - 11 -3438.054366980713 - 21 -1256.28662018356 - 0 -LINE - 5 -AE8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1256.186620183525 - 11 -3438.054366980713 - 21 -1252.686620183525 - 0 -LINE - 5 -AE9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3438.054366980713 - 20 -1252.586691256267 - 11 -3438.054366980713 - 21 -1244.28662018356 - 0 -LINE - 5 -AEA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3441.054366980712 - 20 -1259.886620183537 - 11 -3441.054366980712 - 21 -1256.28662018356 - 0 -LINE - 5 -AEB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3441.054366980712 - 20 -1256.186620183525 - 11 -3441.054366980712 - 21 -1252.686620183525 - 0 -LINE - 5 -AEC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3441.284366980692 - 20 -1259.886620183537 - 11 -3441.284366980692 - 21 -1256.28662018356 - 0 -LINE - 5 -AED -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbLine - 10 -3441.284366980692 - 20 -1256.186620183525 - 11 -3441.284366980692 - 21 -1252.686620183525 - 0 -LINE - 5 -AEE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3444.192101166733 - 20 -1249.28662018356 - 11 -3444.192101166733 - 21 -1245.78662018356 - 0 -LINE - 5 -AEF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3448.489835352637 - 20 -1261.231902978325 - 11 -3448.489835352637 - 21 -1245.631902978348 - 0 -LINE - 5 -AF0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3448.29210116671 - 20 -1259.886620183537 - 11 -3448.29210116671 - 21 -1245.78662018356 - 0 -LINE - 5 -AF1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3448.48983535287 - 20 -1261.231902978325 - 11 -3448.48983535287 - 21 -1245.786620183557 - 0 -LWPOLYLINE - 5 -AF2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3447.092101166724 - 20 -1246.961620183545 - 10 -3447.092101166724 - 20 -1247.711620183545 - 0 -LWPOLYLINE - 5 -AF3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 6 - 70 - 0 - 43 -0 - 10 -3457.965393430237 - 20 -1246.986620183514 - 10 -3453.888227600405 - 20 -1246.986620183514 - 10 -3453.888227600405 - 20 -1246.086620183549 - 10 -3453.138227600405 - 20 -1246.086620183549 - 10 -3453.138227600405 - 20 -1246.986620183514 - 10 -3453.138227600405 - 20 -1246.986620183514 - 0 -LINE - 5 -AF4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3429.485147392643 - 20 -1245.631902978352 - 11 -3450.19467215965 - 21 -1245.631902978352 - 0 -HATCH - 5 -AF5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 5 - 72 - 1 - 10 -3429.485147392643 - 20 -1247.186620183525 - 11 -3429.255147392662 - 21 -1247.186620183525 - 72 - 1 - 10 -3429.255147392662 - 20 -1247.186620183525 - 11 -3429.255147392662 - 21 -1246.986620183514 - 72 - 1 - 10 -3429.255147392662 - 20 -1246.986620183514 - 11 -3429.260147392666 - 21 -1245.631902978352 - 72 - 1 - 10 -3429.260147392666 - 20 -1245.631902978352 - 11 -3429.485147392643 - 21 -1245.631902978352 - 72 - 1 - 10 -3429.485147392643 - 20 -1245.631902978352 - 11 -3429.485147392643 - 21 -1247.186620183525 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -AF6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3429.485147392643 - 20 -1245.631902978352 - 11 -3429.03514739269 - 21 -1245.631902978352 - 72 - 1 - 10 -3429.03514739269 - 20 -1245.631902978352 - 11 -3429.03514739269 - 21 -1245.031902978375 - 72 - 1 - 10 -3429.03514739269 - 20 -1245.031902978375 - 11 -3429.485147392643 - 21 -1245.031902978375 - 72 - 1 - 10 -3429.485147392643 - 20 -1245.031902978375 - 11 -3429.485147392643 - 21 -1245.631902978352 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -AF7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3429.485147392643 - 20 -1245.631902978352 - 10 -3429.03514739269 - 20 -1245.631902978352 - 10 -3429.03514739269 - 20 -1245.031902978375 - 10 -3429.485147392643 - 20 -1245.031902978375 - 10 -3429.485147392643 - 20 -1245.631902978352 - 0 -LWPOLYLINE - 5 -AF8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3448.29210116671 - 20 -1247.28662018356 - 10 -3448.489835352786 - 20 -1247.28662018356 - 0 -LWPOLYLINE - 5 -AF9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3445.892101166805 - 20 -1259.789325424532 - 10 -3445.892101166805 - 20 -1263.248947075572 - 10 -3447.922101166831 - 20 -1263.248947075572 - 10 -3447.922101166831 - 20 -1259.789325424532 - 0 -LINE - 5 -AFA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1262.189325424497 - 11 -3435.094366968177 - 21 -1256.28662018356 - 0 -LINE - 5 -AFB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1256.186620183525 - 11 -3435.094366968177 - 21 -1252.686620183525 - 0 -LINE - 5 -AFC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1252.586634551295 - 11 -3435.094366968177 - 21 -1245.534608219346 - 0 -LINE - 5 -AFD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3434.594366968177 - 20 -1262.28662018356 - 11 -3434.594366968177 - 21 -1256.28662018356 - 0 -LINE - 5 -AFE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3434.594366968177 - 20 -1256.186620183525 - 11 -3434.594366968177 - 21 -1252.686620183525 - 0 -LINE - 5 -AFF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3434.594366968177 - 20 -1252.586624972759 - 11 -3434.594366968177 - 21 -1245.631902978352 - 0 -LINE - 5 -B00 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1259.689325424497 - 11 -3435.094366968177 - 21 -1262.189325424497 - 0 -HATCH - 5 -B01 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -ANSI31 - 70 - 0 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3434.864366968195 - 20 -1262.28662018356 - 11 -3431.59436698075 - 21 -1262.28662018356 - 72 - 1 - 10 -3431.59436698075 - 20 -1262.28662018356 - 11 -3431.59436698075 - 21 -1262.189325424497 - 72 - 1 - 10 -3431.59436698075 - 20 -1262.189325424497 - 11 -3434.864366968195 - 21 -1262.189325424497 - 72 - 1 - 10 -3434.864366968195 - 20 -1262.189325424497 - 11 -3434.864366968195 - 21 -1262.28662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 52 -0 - 41 -0.01 - 77 - 0 - 78 - 0 - 98 - 0 - 0 -LINE - 5 -B02 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbLine - 10 -3435.094366968177 - 20 -1262.189325424497 - 11 -3431.364366980768 - 21 -1262.189325424497 - 0 -LINE - 5 -B03 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbLine - 10 -3431.364366980768 - 20 -1262.28662018356 - 11 -3435.094366968177 - 21 -1262.28662018356 - 0 -HATCH - 5 -B04 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3435.094366968177 - 20 -1262.28662018356 - 11 -3434.864366968195 - 21 -1262.28662018356 - 72 - 1 - 10 -3434.864366968195 - 20 -1262.28662018356 - 11 -3434.864366968195 - 21 -1262.186620183525 - 72 - 1 - 10 -3434.864366968195 - 20 -1262.186620183525 - 11 -3435.094366968177 - 21 -1262.186620183525 - 72 - 1 - 10 -3435.094366968177 - 20 -1262.186620183525 - 11 -3435.094366968177 - 21 -1262.28662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B05 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3435.694366968153 - 20 -1262.086620183549 - 11 -3435.094366968177 - 21 -1262.086620183549 - 72 - 1 - 10 -3435.094366968177 - 20 -1262.086620183549 - 11 -3435.094366968177 - 21 -1261.986620183514 - 72 - 1 - 10 -3435.094366968177 - 20 -1261.986620183514 - 11 -3435.694366968153 - 21 -1261.986620183514 - 72 - 1 - 10 -3435.694366968153 - 20 -1261.986620183514 - 11 -3435.694366968153 - 21 -1262.086620183549 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B06 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3435.094366968177 - 20 -1262.186620183525 - 11 -3434.864366968195 - 21 -1262.186620183525 - 72 - 1 - 10 -3434.864366968195 - 20 -1262.186620183525 - 11 -3434.864366968195 - 21 -1261.986620183514 - 72 - 1 - 10 -3434.864366968195 - 20 -1261.986620183514 - 11 -3435.094366968177 - 21 -1261.986620183514 - 72 - 1 - 10 -3435.094366968177 - 20 -1261.986620183514 - 11 -3435.094366968177 - 21 -1262.186620183525 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B07 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3435.094366968177 - 20 -1259.789325424532 - 10 -3435.094366968177 - 20 -1262.189325424497 - 10 -3434.864366968195 - 20 -1262.189325424497 - 10 -3434.864366968195 - 20 -1259.789325424532 - 0 -LWPOLYLINE - 5 -B08 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3434.864366968195 - 20 -1261.986620183514 - 10 -3435.094366968177 - 20 -1261.986620183514 - 10 -3435.694366968153 - 20 -1261.986620183514 - 10 -3435.694366968153 - 20 -1262.086620183549 - 10 -3435.094366968177 - 20 -1262.086620183549 - 0 -HATCH - 5 -B09 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1247.836620183549 - 11 -3431.364366980768 - 21 -1247.836620183549 - 72 - 1 - 10 -3431.364366980768 - 20 -1247.836620183549 - 11 -3431.364366980768 - 21 -1247.78662018356 - 72 - 1 - 10 -3431.364366980768 - 20 -1247.78662018356 - 11 -3431.59436698075 - 21 -1247.78662018356 - 72 - 1 - 10 -3431.59436698075 - 20 -1247.78662018356 - 11 -3431.59436698075 - 21 -1247.836620183549 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B0A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.364366980768 - 20 -1247.78662018356 - 11 -3430.764366980675 - 21 -1247.78662018356 - 72 - 1 - 10 -3430.764366980675 - 20 -1247.78662018356 - 11 -3430.764366980675 - 21 -1247.686620183525 - 72 - 1 - 10 -3430.764366980675 - 20 -1247.686620183525 - 11 -3431.364366980768 - 21 -1247.686620183525 - 72 - 1 - 10 -3431.364366980768 - 20 -1247.686620183525 - 11 -3431.364366980768 - 21 -1247.78662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B0B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3431.364366980768 - 20 -1247.336620183549 - 10 -3431.364366980768 - 20 -1247.78662018356 - 10 -3431.59436698075 - 20 -1247.78662018356 - 10 -3431.59436698075 - 20 -1247.336620183549 - 0 -LWPOLYLINE - 5 -B0C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3431.364366980768 - 20 -1247.78662018356 - 10 -3430.764366980675 - 20 -1247.78662018356 - 10 -3430.764366980675 - 20 -1247.686620183525 - 10 -3431.364366980768 - 20 -1247.686620183525 - 0 -DIMENSION - 5 -B0D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D73 - 10 -3431.018724545987 - 20 -1245.631902978352 - 30 -0 - 11 -3430.89120111412 - 21 -1246.709261580955 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3430.764366980675 - 23 -1247.78662018356 - 33 -0 - 14 -3430.764366980675 - 24 -1245.631902978352 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -LWPOLYLINE - 5 -B0E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3431.364366980768 - 20 -1247.78662018356 - 10 -3431.364366980768 - 20 -1247.836620183549 - 10 -3431.59436698075 - 20 -1247.836620183549 - 10 -3431.59436698075 - 20 -1247.78662018356 - 0 -LINE - 5 -B0F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3434.594366968177 - 20 -1248.636620183537 - 11 -3434.594366968177 - 21 -1248.236620183514 - 0 -LINE - 5 -B10 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.594366980717 - 20 -1248.23662018351 - 11 -3448.48983535287 - 21 -1248.23662018351 - 0 -LWPOLYLINE - 5 -B11 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3444.392101166803 - 20 -1245.78662018356 - 10 -3444.292101166826 - 20 -1245.78662018356 - 10 -3444.292101166826 - 20 -1245.584312605966 - 10 -3444.554366980713 - 20 -1245.584312605966 - 0 -LWPOLYLINE - 5 -B12 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3448.29210116671 - 20 -1247.186620183525 - 10 -3448.29210116671 - 20 -1247.586620183549 - 10 -3448.489835352786 - 20 -1247.586620183549 - 10 -3448.489835352786 - 20 -1247.186620183525 - 0 -LINE - 5 -B13 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3448.29210116671 - 20 -1248.636620183537 - 11 -3431.59436698075 - 21 -1248.636620183537 - 0 -LWPOLYLINE - 5 -B14 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3438.054366980713 - 20 -1248.236620183514 - 10 -3437.824366980731 - 20 -1248.236620183514 - 10 -3437.824366980731 - 20 -1248.636620183537 - 10 -3438.054366980713 - 20 -1248.636620183537 - 10 -3438.054366980713 - 20 -1248.236620183514 - 0 -HATCH - 5 -B15 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3434.594366968177 - 20 -1248.636620183537 - 11 -3435.094366968177 - 21 -1248.636620183537 - 72 - 1 - 10 -3435.094366968177 - 20 -1248.636620183537 - 11 -3435.094366968177 - 21 -1248.53662018356 - 72 - 1 - 10 -3435.094366968177 - 20 -1248.53662018356 - 11 -3434.594366968177 - 21 -1248.53662018356 - 72 - 1 - 10 -3434.594366968177 - 20 -1248.53662018356 - 11 -3434.594366968177 - 21 -1248.636620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B16 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3435.094366968177 - 20 -1248.53662018356 - 11 -3434.864366968195 - 21 -1248.53662018356 - 72 - 1 - 10 -3434.864366968195 - 20 -1248.53662018356 - 11 -3434.864366968195 - 21 -1248.236620183514 - 72 - 1 - 10 -3434.864366968195 - 20 -1248.236620183514 - 11 -3435.094366968177 - 21 -1248.236620183514 - 72 - 1 - 10 -3435.094366968177 - 20 -1248.236620183514 - 11 -3435.094366968177 - 21 -1248.53662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B17 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3434.864366968195 - 20 -1248.53662018356 - 11 -3435.094366968177 - 21 -1248.53662018356 - 72 - 1 - 10 -3435.094366968177 - 20 -1248.53662018356 - 11 -3435.094366968177 - 21 -1248.436620183525 - 72 - 1 - 10 -3435.094366968177 - 20 -1248.436620183525 - 11 -3434.864366968195 - 21 -1248.436620183525 - 72 - 1 - 10 -3434.864366968195 - 20 -1248.436620183525 - 11 -3434.864366968195 - 21 -1248.53662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B18 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3435.094366968177 - 20 -1248.236620183514 - 10 -3434.864366968195 - 20 -1248.236620183514 - 10 -3434.864366968195 - 20 -1248.636620183537 - 10 -3435.094366968177 - 20 -1248.636620183537 - 10 -3435.094366968177 - 20 -1248.236620183514 - 0 -HATCH - 5 -B19 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3435.094366968177 - 20 -1245.686620183525 - 11 -3434.864366968195 - 21 -1245.686620183525 - 72 - 1 - 10 -3434.864366968195 - 20 -1245.686620183525 - 11 -3434.864366968195 - 21 -1245.386620183537 - 72 - 1 - 10 -3434.864366968195 - 20 -1245.386620183537 - 11 -3435.094366968177 - 21 -1245.386620183537 - 72 - 1 - 10 -3435.094366968177 - 20 -1245.386620183537 - 11 -3435.094366968177 - 21 -1245.686620183525 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B1A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3434.864366968195 - 20 -1245.686620183525 - 11 -3435.094366968177 - 21 -1245.686620183525 - 72 - 1 - 10 -3435.094366968177 - 20 -1245.686620183525 - 11 -3435.094366968177 - 21 -1245.586620183549 - 72 - 1 - 10 -3435.094366968177 - 20 -1245.586620183549 - 11 -3434.864366968195 - 21 -1245.586620183549 - 72 - 1 - 10 -3434.864366968195 - 20 -1245.586620183549 - 11 -3434.864366968195 - 21 -1245.686620183525 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B1B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3435.094366968177 - 20 -1245.386620183537 - 10 -3434.864366968195 - 20 -1245.386620183537 - 10 -3434.864366968195 - 20 -1245.78662018356 - 10 -3435.094366968177 - 20 -1245.78662018356 - 10 -3435.094366968177 - 20 -1245.386620183537 - 0 -HATCH - 5 -B1C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1248.636620183537 - 11 -3431.364366980768 - 21 -1248.636620183537 - 72 - 1 - 10 -3431.364366980768 - 20 -1248.636620183537 - 11 -3431.364366980768 - 21 -1248.224683506243 - 72 - 1 - 10 -3431.364366980768 - 20 -1248.224683506243 - 11 -3431.59436698075 - 21 -1248.224683506243 - 72 - 1 - 10 -3431.59436698075 - 20 -1248.224683506243 - 11 -3431.59436698075 - 21 -1248.636620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B1D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3431.59436698075 - 20 -1248.636620183537 - 10 -3431.364366980768 - 20 -1248.636620183537 - 10 -3431.364366980768 - 20 -1248.224683506243 - 10 -3431.59436698075 - 20 -1248.224683506243 - 10 -3431.59436698075 - 20 -1248.636620183537 - 0 -HATCH - 5 -B1E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.489835352786 - 20 -1248.636620183537 - 11 -3448.29210116671 - 21 -1248.636620183537 - 72 - 1 - 10 -3448.29210116671 - 20 -1248.636620183537 - 11 -3448.29210116671 - 21 -1248.236620183514 - 72 - 1 - 10 -3448.29210116671 - 20 -1248.236620183514 - 11 -3448.489835352786 - 21 -1248.236620183514 - 72 - 1 - 10 -3448.489835352786 - 20 -1248.236620183514 - 11 -3448.489835352786 - 21 -1248.636620183537 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B1F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3448.29210116671 - 20 -1248.636620183537 - 10 -3448.489835352786 - 20 -1248.636620183537 - 10 -3448.489835352786 - 20 -1248.236620183514 - 10 -3448.29210116671 - 20 -1248.236620183514 - 10 -3448.29210116671 - 20 -1248.636620183537 - 0 -HATCH - 5 -B20 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.594366980749 - 20 -1250.172620183587 - 11 -3431.364366980766 - 21 -1250.172620183587 - 72 - 1 - 10 -3431.364366980766 - 20 -1250.172620183587 - 11 -3431.364366980766 - 21 -1250.072620183552 - 72 - 1 - 10 -3431.364366980766 - 20 -1250.072620183552 - 11 -3431.594366980749 - 21 -1250.072620183552 - 72 - 1 - 10 -3431.594366980749 - 20 -1250.072620183552 - 11 -3431.594366980749 - 21 -1250.172620183587 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B21 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.594366980749 - 20 -1250.522620183563 - 11 -3431.364366980766 - 21 -1250.522620183563 - 72 - 1 - 10 -3431.364366980766 - 20 -1250.522620183563 - 11 -3431.364366980766 - 21 -1250.172620183587 - 72 - 1 - 10 -3431.364366980766 - 20 -1250.172620183587 - 11 -3431.594366980749 - 21 -1250.172620183587 - 72 - 1 - 10 -3431.594366980749 - 20 -1250.172620183587 - 11 -3431.594366980749 - 21 -1250.522620183563 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B22 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.594366980749 - 20 -1250.572620183552 - 11 -3431.364366980766 - 21 -1250.572620183552 - 72 - 1 - 10 -3431.364366980766 - 20 -1250.572620183552 - 11 -3431.364366980766 - 21 -1250.522620183563 - 72 - 1 - 10 -3431.364366980766 - 20 -1250.522620183563 - 11 -3431.594366980749 - 21 -1250.522620183563 - 72 - 1 - 10 -3431.594366980749 - 20 -1250.522620183563 - 11 -3431.594366980749 - 21 -1250.572620183552 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B23 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.364366980768 - 20 -1250.611720183518 - 11 -3430.764366980675 - 21 -1250.611720183518 - 72 - 1 - 10 -3430.764366980675 - 20 -1250.611720183518 - 11 -3430.764366980675 - 21 -1250.511720183542 - 72 - 1 - 10 -3430.764366980675 - 20 -1250.511720183542 - 11 -3431.364366980768 - 21 -1250.511720183542 - 72 - 1 - 10 -3431.364366980768 - 20 -1250.511720183542 - 11 -3431.364366980768 - 21 -1250.611720183518 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B24 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3431.364366980736 - 20 -1250.614136013726 - 10 -3430.764366980643 - 20 -1250.614136013726 - 10 -3430.764366980643 - 20 -1250.514136013749 - 10 -3431.364366980736 - 20 -1250.514136013749 - 0 -HATCH - 5 -B25 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1254.140620183486 - 11 -3431.364366980768 - 21 -1254.140620183486 - 72 - 1 - 10 -3431.364366980768 - 20 -1254.140620183486 - 11 -3431.364366980768 - 21 -1254.04062018351 - 72 - 1 - 10 -3431.364366980768 - 20 -1254.04062018351 - 11 -3431.59436698075 - 21 -1254.04062018351 - 72 - 1 - 10 -3431.59436698075 - 20 -1254.04062018351 - 11 -3431.59436698075 - 21 -1254.140620183486 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B26 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1254.490620183463 - 11 -3431.364366980768 - 21 -1254.490620183463 - 72 - 1 - 10 -3431.364366980768 - 20 -1254.490620183463 - 11 -3431.364366980768 - 21 -1254.140620183486 - 72 - 1 - 10 -3431.364366980768 - 20 -1254.140620183486 - 11 -3431.59436698075 - 21 -1254.140620183486 - 72 - 1 - 10 -3431.59436698075 - 20 -1254.140620183486 - 11 -3431.59436698075 - 21 -1254.490620183463 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B27 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.364366980768 - 20 -1254.771631514657 - 11 -3430.764366980675 - 21 -1254.771631514657 - 72 - 1 - 10 -3430.764366980675 - 20 -1254.771631514657 - 11 -3430.764366980675 - 21 -1254.67163151468 - 72 - 1 - 10 -3430.764366980675 - 20 -1254.67163151468 - 11 -3431.364366980768 - 21 -1254.67163151468 - 72 - 1 - 10 -3431.364366980768 - 20 -1254.67163151468 - 11 -3431.364366980768 - 21 -1254.771631514657 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B28 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3431.364366980736 - 20 -1254.770708683412 - 10 -3430.764366980643 - 20 -1254.770708683412 - 10 -3430.764366980643 - 20 -1254.670708683494 - 10 -3431.364366980736 - 20 -1254.670708683494 - 0 -HATCH - 5 -B29 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1258.020020183528 - 11 -3431.364366980768 - 21 -1258.020020183528 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.020020183528 - 11 -3431.364366980768 - 21 -1257.920020183552 - 72 - 1 - 10 -3431.364366980768 - 20 -1257.920020183552 - 11 -3431.59436698075 - 21 -1257.920020183552 - 72 - 1 - 10 -3431.59436698075 - 20 -1257.920020183552 - 11 -3431.59436698075 - 21 -1258.020020183528 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B2A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1258.040620183477 - 11 -3431.364366980768 - 21 -1258.040620183477 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.040620183477 - 11 -3431.364366980768 - 21 -1257.6906201835 - 72 - 1 - 10 -3431.364366980768 - 20 -1257.6906201835 - 11 -3431.59436698075 - 21 -1257.6906201835 - 72 - 1 - 10 -3431.59436698075 - 20 -1257.6906201835 - 11 -3431.59436698075 - 21 -1258.040620183477 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B2B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1258.090620183524 - 11 -3431.364366980768 - 21 -1258.090620183524 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.090620183524 - 11 -3431.364366980768 - 21 -1258.040620183477 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.040620183477 - 11 -3431.59436698075 - 21 -1258.040620183477 - 72 - 1 - 10 -3431.59436698075 - 20 -1258.040620183477 - 11 -3431.59436698075 - 21 -1258.090620183524 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B2C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.370020183505 - 11 -3430.764366980675 - 21 -1258.370020183505 - 72 - 1 - 10 -3430.764366980675 - 20 -1258.370020183505 - 11 -3430.764366980675 - 21 -1258.270020183529 - 72 - 1 - 10 -3430.764366980675 - 20 -1258.270020183529 - 11 -3431.364366980768 - 21 -1258.270020183529 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.270020183529 - 11 -3431.364366980768 - 21 -1258.370020183505 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B2D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3431.364366980736 - 20 -1257.590620183502 - 10 -3431.364366980736 - 20 -1258.040620183456 - 10 -3431.594366980717 - 20 -1258.040620183456 - 10 -3431.594366980717 - 20 -1257.590620183502 - 0 -LWPOLYLINE - 5 -B2E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3431.364366980736 - 20 -1258.040620183456 - 10 -3431.364366980736 - 20 -1258.090620183502 - 10 -3431.594366980717 - 20 -1258.090620183502 - 10 -3431.594366980717 - 20 -1258.040620183456 - 0 -LWPOLYLINE - 5 -B2F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3429.260147392666 - 20 -1245.631902978352 - 10 -3429.255147392662 - 20 -1246.986620183514 - 10 -3429.255147392662 - 20 -1247.186620183525 - 10 -3429.485147392643 - 20 -1247.186620183525 - 10 -3429.485147392643 - 20 -1245.631902978352 - 0 -LINE - 5 -B30 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbLine - 10 -3426.51679551465 - 20 -1246.986620183514 - 11 -3426.51679551465 - 21 -1246.726972465814 - 0 -LINE - 5 -B31 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbLine - 10 -3426.610354400156 - 20 -1246.986620183514 - 11 -3426.610354400156 - 21 -1246.726972465814 - 0 -LINE - 5 -B32 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbLine - 10 -3426.719510730157 - 20 -1246.986620183514 - 11 -3426.719510730157 - 21 -1246.726972465814 - 0 -LINE - 5 -B33 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbLine - 10 -3427.358851265428 - 20 -1246.986620183514 - 11 -3427.358851265428 - 21 -1246.726972465814 - 0 -LINE - 5 -B34 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbLine - 10 -3427.452410150934 - 20 -1246.986620183514 - 11 -3427.452410150934 - 21 -1246.726972465814 - 0 -LINE - 5 -B35 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbLine - 10 -3427.561566480934 - 20 -1246.986620183514 - 11 -3427.561566480934 - 21 -1246.726972465814 - 0 -LINE - 5 -B36 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 6 -370 - 0 -100 -AcDbLine - 10 -3427.998204691252 - 20 -1246.986620183514 - 11 -3427.998204691252 - 21 -1246.726972465814 - 0 -LINE - 5 -B37 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3428.091763576759 - 20 -1246.986620183514 - 11 -3428.091763576759 - 21 -1246.726972465814 - 0 -LINE - 5 -B38 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3428.200919906758 - 20 -1246.986620183514 - 11 -3428.200919906758 - 21 -1246.726972465814 - 0 -LINE - 5 -B39 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3428.699922113712 - 20 -1246.986620183514 - 11 -3428.699922113712 - 21 -1246.726972465814 - 0 -LINE - 5 -B3A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3428.793480999335 - 20 -1246.986620183514 - 11 -3428.793480999335 - 21 -1246.726972465814 - 0 -LINE - 5 -B3B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3428.902637329218 - 20 -1246.986620183514 - 11 -3428.902637329218 - 21 -1246.726972465814 - 0 -LEADER - 5 -B3C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLeader - 3 -Standard - 71 - 1 - 72 - 0 - 73 - 3 - 74 - 0 - 75 - 0 - 40 -1 - 41 -10 - 76 -3 - 76 -3 - 10 -3429.255147392662 - 20 -1248.186620183525 - 30 -0 - 10 -3429.255147392662 - 20 -1249.055130511409 - 30 -0 - 10 -3428.107193445356 - 20 -1249.055130511409 - 30 -0 - 0 -LEADER - 5 -B3D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLeader - 3 -Standard - 71 - 1 - 72 - 0 - 73 - 3 - 74 - 0 - 75 - 0 - 40 -1 - 41 -10 - 76 -3 - 76 -3 - 10 -3429.485147392643 - 20 -1247.812661133244 - 30 -0 - 10 -3429.984339434687 - 20 -1247.812661133244 - 30 -0 - 10 -3429.984339434687 - 20 -1249.558370642658 - 30 -0 - 0 -MTEXT - 5 -B3E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3424.709583766791 - 20 -1247.229278560964 - 30 -0 - 40 -0.2 - 41 -1.105555555555556 - 71 - 1 - 72 - 5 - 1 -G Level\P+/-0 Lvl - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -B3F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3428.061230431111 - 20 -1249.304358304656 - 30 -0 - 40 -0.1457306057650888 - 41 -1.339911927667163 - 71 - 1 - 72 - 5 - 1 -Site boundary - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -B40 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3429.291750858221 - 20 -1249.7602796678 - 30 -0 - 40 -0.1457306057650888 - 41 -2.611006761571927 - 71 - 1 - 72 - 5 - 1 -Applicants compound wall - 7 -sree -210 -0 -220 -0 -230 -1 - 50 -0 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -B41 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3430.764366980675 - 20 -1247.78662018356 - 10 -3430.764366980675 - 20 -1247.986620183514 - 10 -3430.864366980768 - 20 -1247.986620183514 - 10 -3430.864366980768 - 20 -1247.78662018356 - 0 -LINE - 5 -B42 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3430.864366980768 - 20 -1247.986620183514 - 11 -3431.364366980768 - 21 -1247.986620183514 - 0 -LWPOLYLINE - 5 -B43 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3430.764366980643 - 20 -1250.614136013726 - 10 -3430.764366980643 - 20 -1250.814136013738 - 10 -3430.864366980735 - 20 -1250.814136013738 - 10 -3430.864366980735 - 20 -1250.614136013726 - 0 -LINE - 5 -B44 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3430.864366980735 - 20 -1250.814136013738 - 11 -3431.364366980736 - 21 -1250.814136013738 - 0 -LWPOLYLINE - 5 -B45 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3430.764366980643 - 20 -1254.771631514653 - 10 -3430.764366980643 - 20 -1254.971631514665 - 10 -3430.864366980735 - 20 -1254.971631514665 - 10 -3430.864366980735 - 20 -1254.771631514653 - 0 -LINE - 5 -B46 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3430.864366980768 - 20 -1254.971631514669 - 11 -3431.364366980768 - 21 -1254.971631514669 - 0 -LWPOLYLINE - 5 -B47 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3430.764366980643 - 20 -1258.370020183502 - 10 -3430.764366980643 - 20 -1258.570020183513 - 10 -3430.864366980735 - 20 -1258.570020183513 - 10 -3430.864366980735 - 20 -1258.370020183502 - 0 -LINE - 5 -B48 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3430.864366980768 - 20 -1258.570020183517 - 11 -3431.364366980768 - 21 -1258.570020183517 - 0 -HATCH - 5 -B49 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.364366980768 - 20 -1261.986620183514 - 11 -3431.59436698075 - 21 -1261.986620183514 - 72 - 1 - 10 -3431.59436698075 - 20 -1261.986620183514 - 11 -3431.59436698075 - 21 -1262.286620183502 - 72 - 1 - 10 -3431.59436698075 - 20 -1262.28662018356 - 11 -3431.364366980768 - 21 -1262.28662018356 - 72 - 1 - 10 -3431.364366980768 - 20 -1262.28662018356 - 11 -3431.364366980768 - 21 -1261.986620183572 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B4A -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.364366980768 - 20 -1262.08932542452 - 11 -3430.764366980675 - 21 -1262.08932542452 - 72 - 1 - 10 -3430.764366980675 - 20 -1262.08932542452 - 11 -3430.764366980675 - 21 -1261.989325424485 - 72 - 1 - 10 -3430.764366980675 - 20 -1261.989325424485 - 11 -3431.364366980768 - 21 -1261.989325424485 - 72 - 1 - 10 -3431.364366980768 - 20 -1261.989325424485 - 11 -3431.364366980768 - 21 -1262.08932542452 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B4B -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3431.364366980768 - 20 -1261.836620183549 - 10 -3431.364366980768 - 20 -1262.189325424497 - 10 -3431.59436698075 - 20 -1262.189325424497 - 10 -3431.59436698075 - 20 -1261.739325424485 - 0 -LWPOLYLINE - 5 -B4C -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3430.764366980876 - 20 -1262.189325424493 - 10 -3430.764366980876 - 20 -1262.089325424516 - 10 -3431.364366980968 - 20 -1262.089325424516 - 0 -LWPOLYLINE - 5 -B4D -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3431.364366980768 - 20 -1262.189325424497 - 10 -3431.364366980768 - 20 -1262.239325424485 - 10 -3431.59436698075 - 20 -1262.239325424485 - 10 -3431.59436698075 - 20 -1262.189325424497 - 0 -LWPOLYLINE - 5 -B4E -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3430.764366980675 - 20 -1262.08932542452 - 10 -3430.764366980675 - 20 -1262.289325424532 - 10 -3430.864366980768 - 20 -1262.289325424532 - 10 -3430.864366980768 - 20 -1262.08932542452 - 0 -LWPOLYLINE - 5 -B4F -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3434.864366968195 - 20 -1262.189325424497 - 10 -3434.864366968195 - 20 -1262.28662018356 - 10 -3431.364366980768 - 20 -1262.28662018356 - 0 -LWPOLYLINE - 5 -B50 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3431.594366980717 - 20 -1262.186620183522 - 10 -3431.594366980717 - 20 -1262.286620183557 - 10 -3434.864366968162 - 20 -1262.286620183557 - 10 -3434.864366968162 - 20 -1262.189325424493 - 10 -3431.594366980717 - 20 -1262.186620183522 - 0 -LINE - 5 -B51 -100 -AcDbEntity - 8 -0 - 6 -DASHED - 62 - 256 -370 - 9 -100 -AcDbLine - 10 -3431.364366980768 - 20 -1262.28662018356 - 11 -3430.864366980768 - 21 -1262.28662018356 - 0 -HATCH - 5 -B52 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3434.344366980633 - 20 -1256.28662018356 - 11 -3434.244366980773 - 21 -1256.28662018356 - 72 - 1 - 10 -3434.244366980773 - 20 -1256.28662018356 - 11 -3434.244366980773 - 21 -1256.186620183525 - 72 - 1 - 10 -3434.244366980773 - 20 -1256.186620183525 - 11 -3434.344366980633 - 21 -1256.186620183525 - 72 - 1 - 10 -3434.344366980633 - 20 -1256.186620183525 - 11 -3434.344366980633 - 21 -1256.28662018356 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B53 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1258.021631514657 - 11 -3431.364366980768 - 21 -1258.021631514657 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.021631514657 - 11 -3431.364366980768 - 21 -1257.92163151468 - 72 - 1 - 10 -3431.364366980768 - 20 -1257.92163151468 - 11 -3431.59436698075 - 21 -1257.92163151468 - 72 - 1 - 10 -3431.59436698075 - 20 -1257.92163151468 - 11 -3431.59436698075 - 21 -1258.021631514657 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B54 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1258.042231514664 - 11 -3431.364366980768 - 21 -1258.042231514664 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.042231514664 - 11 -3431.364366980768 - 21 -1257.692231514629 - 72 - 1 - 10 -3431.364366980768 - 20 -1257.692231514629 - 11 -3431.59436698075 - 21 -1257.692231514629 - 72 - 1 - 10 -3431.59436698075 - 20 -1257.692231514629 - 11 -3431.59436698075 - 21 -1258.042231514664 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B55 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.59436698075 - 20 -1258.092231514652 - 11 -3431.364366980768 - 21 -1258.092231514652 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.092231514652 - 11 -3431.364366980768 - 21 -1258.042231514664 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.042231514664 - 11 -3431.59436698075 - 21 -1258.042231514664 - 72 - 1 - 10 -3431.59436698075 - 20 -1258.042231514664 - 11 -3431.59436698075 - 21 -1258.092231514652 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -B56 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.371631514692 - 11 -3430.764366980675 - 21 -1258.371631514692 - 72 - 1 - 10 -3430.764366980675 - 20 -1258.371631514692 - 11 -3430.764366980675 - 21 -1258.271631514657 - 72 - 1 - 10 -3430.764366980675 - 20 -1258.271631514657 - 11 -3431.364366980768 - 21 -1258.271631514657 - 72 - 1 - 10 -3431.364366980768 - 20 -1258.271631514657 - 11 -3431.364366980768 - 21 -1258.371631514692 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -B57 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3431.364366980736 - 20 -1257.622231514601 - 10 -3431.364366980736 - 20 -1258.092231514631 - 10 -3431.594366980717 - 20 -1258.092231514631 - 10 -3431.594366980717 - 20 -1257.592231514631 - 0 -LWPOLYLINE - 5 -B58 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3430.764366980643 - 20 -1258.371631514688 - 10 -3430.764366980643 - 20 -1258.5716315147 - 10 -3430.864366980735 - 20 -1258.5716315147 - 10 -3430.864366980735 - 20 -1258.371631514688 - 0 -LINE - 5 -B59 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3430.864366980768 - 20 -1258.571631514704 - 11 -3431.364366980768 - 21 -1258.571631514704 - 0 -LINE - 5 -B5A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3434.864366968162 - 20 -1261.231902978325 - 11 -3448.48983535287 - 21 -1261.231902978325 - 0 -LWPOLYLINE - 5 -B5B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3434.864366968162 - 20 -1261.231902978325 - 10 -3434.864366968162 - 20 -1260.781902978313 - 10 -3448.48983535287 - 20 -1260.781902978313 - 0 -LINE - 5 -B5C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.364366980768 - 20 -1248.636620183537 - 11 -3424.624974634298 - 21 -1248.636620183537 - 0 -LINE - 5 -B5D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.364289394499 - 20 -1252.686624971338 - 11 -3424.624897048027 - 21 -1252.686624971338 - 0 -LINE - 5 -B5E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.364366980768 - 20 -1256.28662018356 - 11 -3424.624974634298 - 21 -1256.28662018356 - 0 -LINE - 5 -B5F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.364366980768 - 20 -1259.886620183537 - 11 -3424.624974634298 - 21 -1259.886620183537 - 0 -DIMENSION - 5 -B60 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 5 -100 -AcDbDimension - 2 -*D76 - 10 -3427.522237369113 - 20 -1248.636620183537 - 30 -0 - 11 -3427.394713937245 - 21 -1247.811620183526 - 31 -0 - 70 - 33 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3427.76242944449 - 23 -1246.986620183514 - 33 -0 - 14 -3427.76242944449 - 24 -1248.636620183537 - 34 -0 - 0 -DIMENSION - 5 -B61 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 255 -370 - 5 -100 -AcDbDimension - 2 -*D77 - 10 -3427.52223736918 - 20 -1252.686624971338 - 30 -0 - 11 -3427.394713937312 - 21 -1250.661622577436 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3427.762429444553 - 23 -1248.636620183537 - 33 -0 - 14 -3427.994593221313 - 24 -1252.686624971338 - 34 -0 - 50 -270 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -B62 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D78 - 10 -3427.522237369127 - 20 -1256.28662018356 - 30 -0 - 11 -3427.394713937259 - 21 -1254.486622577448 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3427.994593221261 - 23 -1252.686624971338 - 33 -0 - 14 -3427.522237369125 - 24 -1256.28662018356 - 34 -0 - 50 -270 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -B63 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 5 -100 -AcDbDimension - 2 -*D79 - 10 -3427.522237369135 - 20 -1259.886620183537 - 30 -0 - 11 -3427.394713937268 - 21 -1258.086620183549 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3427.522237369135 - 23 -1256.28662018356 - 33 -0 - 14 -3427.522237369135 - 24 -1259.886620183537 - 34 -0 - 50 -270 -100 -AcDbRotatedDimension - 0 -MTEXT - 5 -B64 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3424.612683876567 - 20 -1249.226913949711 - 30 -0 - 40 -0.2 - 41 -1.661111111111139 - 71 - 1 - 72 - 5 - 1 -ground floor\PFFL\P+1.65 Lvl - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -B65 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3424.612683876567 - 20 -1253.274124337131 - 30 -0 - 40 -0.2 - 41 -1.372222325079662 - 71 - 1 - 72 - 5 - 1 -first floor\PFFL\P+5.70 Lvl - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -B66 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3424.612683876567 - 20 -1256.884222381519 - 30 -0 - 40 -0.2 - 41 -1.661187305516043 - 71 - 1 - 72 - 5 - 1 -second floor\PFFL\P+9.30 Lvl - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -B67 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3424.612683876567 - 20 -1260.470465333437 - 30 -0 - 40 -0.2 - 41 -1.75000000000001 - 71 - 1 - 72 - 5 - 1 -terrace floor\PFFL\P+12.90 Lvl - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -LINE - 5 -B68 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.364366980768 - 20 -1245.78662018356 - 11 -3424.624974634298 - 21 -1245.78662018356 - 0 -MTEXT - 5 -B69 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3424.612683876567 - 20 -1246.385440453483 - 30 -0 - 40 -0.2 - 41 -2.016666769524143 - 71 - 1 - 72 - 5 - 1 -basement floor\PFFL\P-1.20 Lvl - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -B6A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3438.407092350452 - 20 -1260.178373193954 - 30 -0 - 40 -0.2 - 41 -0.9333333333333427 - 71 - 1 - 72 - 5 - 1 -terrace - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -DIMENSION - 5 -B6B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 5 -100 -AcDbDimension - 2 -*D80 - 10 -3427.522237369113 - 20 -1245.78662018356 - 30 -0 - 11 -3427.394713937245 - 21 -1246.386620183537 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3427.76242944449 - 23 -1246.986620183514 - 33 -0 - 14 -3427.671571185602 - 24 -1245.78662018356 - 34 -0 - 50 -270 -100 -AcDbRotatedDimension - 0 -MTEXT - 5 -B6C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3431.682673379422 - 20 -1251.150940983967 - 30 -0 - 40 -0.1 - 41 -0.6777777777777824 - 71 - 1 - 72 - 5 - 1 -rise=.176\Ptread=0.20 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883538 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -B6D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3462.358168989803 - 20 -1245.025794498335 - 30 -0 - 40 -0.4900000000000003 - 41 -5.920833333333337 - 71 - 1 - 72 - 5 - 1 -FRONT ELEVATION - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -B6E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3431.835146950707 - 20 -1243.135056148811 - 30 -0 - 40 -0.4900000000000003 - 41 -4.219444340563395 - 71 - 1 - 72 - 5 - 1 -SECTION A A - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -LINE - 5 -B6F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.820140817352 - 20 -1247.434328626845 - 11 -3471.050140817417 - 21 -1247.434328626845 - 0 -LINE - 5 -B70 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.820140817352 - 20 -1247.244892983875 - 11 -3471.050140817417 - 21 -1247.244892983875 - 0 -LINE - 5 -B71 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3467.820140817352 - 20 -1247.136635363455 - 11 -3471.050140817417 - 21 -1247.136635363455 - 0 -DIMENSION - 5 -B72 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D81 - 10 -3430.011031889974 - 20 -1246.989735042331 - 30 -0 - 11 -3429.883508458106 - 21 -1247.588177612927 - 31 -0 - 70 - 33 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3429.485147392643 - 23 -1248.186620183525 - 33 -0 - 14 -3429.485147392643 - 24 -1246.989735042331 - 34 -0 - 0 -DIMENSION - 5 -B73 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D82 - 10 -3430.011031889974 - 20 -1245.631902978342 - 30 -0 - 11 -3429.883508458106 - 21 -1246.31081901033 - 31 -0 - 70 - 32 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3429.485147392643 - 23 -1246.989735042321 - 33 -0 - 14 -3429.485147392643 - 24 -1245.631902978342 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -B74 -100 -AcDbEntity - 8 -BLK_1_FLR_0_HT_ROOM - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D83 - 10 -3439.369119896593 - 20 -1248.636620183537 - 30 -0 - 11 -3439.369119896593 - 21 -1250.661620183561 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3438.054366980713 - 23 -1252.686620183584 - 33 -0 - 14 -3438.054366980713 - 24 -1248.636620183537 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -B75 -100 -AcDbEntity - 8 -BLK_1_FLR_1_HT_ROOM - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D84 - 10 -3439.379987518114 - 20 -1256.28662018356 - 30 -0 - 11 -3439.379987518114 - 21 -1254.486620183572 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3439.078499989153 - 23 -1252.686620183584 - 33 -0 - 14 -3440.061276775585 - 24 -1256.28662018356 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -B76 -100 -AcDbEntity - 8 -BLK_1_FLR_2_HT_ROOM - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D85 - 10 -3440.165820340022 - 20 -1256.28662018356 - 30 -0 - 11 -3440.165820340022 - 21 -1258.086620183374 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Dimension in meters - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3440.149415793408 - 23 -1259.886620183188 - 33 -0 - 14 -3440.149415793408 - 24 -1256.28662018356 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -DIMENSION - 5 -B77 -100 -AcDbEntity - 8 -BLK_1_HT_OF_BLDG - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbDimension - 2 -*D86 - 10 -3451.236564734482 - 20 -1246.986620184678 - 30 -0 - 11 -3451.236564734482 - 21 -1253.436620184108 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3448.489835352904 - 23 -1259.886620183537 - 33 -0 - 14 -3453.888227601801 - 24 -1246.986620184678 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -LWPOLYLINE - 5 -B78 -100 -AcDbEntity - 8 -BLK_1_BSMNT_FOOT_PRINT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 11 - 70 - 1 - 43 -0 - 10 -3699.232777040192 - 20 -1130.901118105119 - 10 -3710.930247410173 - 20 -1130.901118105119 - 10 -3710.930247410173 - 20 -1115.444751510471 - 10 -3707.700247410171 - 20 -1115.444751510471 - 10 -3707.700247410171 - 20 -1115.044751510448 - 10 -3704.466422993662 - 20 -1115.044751509982 - 10 -3704.466422993662 - 20 -1114.343383919057 - 10 -3702.961422993541 - 20 -1114.343383919057 - 10 -3702.961422993541 - 20 -1113.775649733043 - 10 -3699.465042147525 - 20 -1113.775649733043 - 10 -3699.232777040069 - 20 -1113.775649733053 - 0 -LINE - 5 -B79 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3300.224476717306 - 20 -1245.352369954856 - 11 -3301.124476717212 - 21 -1243.552369962679 - 0 -LINE - 5 -B7A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3301.124476717087 - 20 -1245.352369962667 - 11 -3300.224476717306 - 21 -1243.552390304204 - 0 -LINE - 5 -B7B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077781888094 - 20 -1245.352369962667 - 11 -3317.977986022152 - 21 -1243.552369962679 - 0 -LINE - 5 -B7C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3317.077611773763 - 20 -1243.552369962679 - 11 -3317.977986019338 - 21 -1245.352369962667 - 0 -LINE - 5 -B7D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3354.188675249461 - 20 -1245.352369962667 - 11 -3353.288675249574 - 21 -1243.552384968265 - 0 -LINE - 5 -B7E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3353.288675249575 - 20 -1245.352369952924 - 11 -3354.188675249481 - 21 -1243.552369964251 - 0 -LWPOLYLINE - 5 -B7F -100 -AcDbEntity - 8 -PLOT_BOUNDARY - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 1 - 43 -0 - 10 -3698.034300625808 - 20 -1132.82980976987 - 10 -3701.361437638996 - 20 -1133.220526157112 - 10 -3710.910329968247 - 20 -1133.07507759163 - 10 -3711.148205478351 - 20 -1109.627121782186 - 10 -3698.034300625808 - 20 -1107.078893492156 - 0 -LWPOLYLINE - 5 -B80 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3305.8319470861 - 20 -1243.423737553594 - 10 -3307.0319470861 - 20 -1243.423737553594 - 10 -3307.0319470861 - 20 -1241.218060514017 - 10 -3305.8319470861 - 20 -1241.218060514017 - 0 -LWPOLYLINE - 5 -B81 -100 -AcDbEntity - 8 -BLK_1_FLR_1_URINAL - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3317.682038925002 - 20 -1259.050104148744 - 10 -3318.282038925001 - 20 -1259.050104148744 - 10 -3318.282038925001 - 20 -1258.350104148744 - 10 -3317.682038925002 - 20 -1258.350104148744 - 0 -LWPOLYLINE - 5 -B82 -100 -AcDbEntity - 8 -BLK_1_FLR_1_URINAL - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3318.282038924955 - 20 -1259.050104146998 - 10 -3318.882038924955 - 20 -1259.050104146998 - 10 -3318.882038924955 - 20 -1258.350104146998 - 10 -3318.282038924955 - 20 -1258.350104146998 - 0 -LWPOLYLINE - 5 -B83 -100 -AcDbEntity - 8 -BLK_1_FLR_1_URINAL - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3318.882038924909 - 20 -1259.050104148744 - 10 -3319.482038924909 - 20 -1259.050104148744 - 10 -3319.482038924909 - 20 -1258.350104148744 - 10 -3318.882038924909 - 20 -1258.350104148744 - 0 -LWPOLYLINE - 5 -B84 -100 -AcDbEntity - 8 -BLK_1_FLR_1_WASH - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3320.693525724812 - 20 -1256.50374874116 - 10 -3320.693525724812 - 20 -1256.951083195586 - 10 -3320.379812578121 - 20 -1256.951083195586 - 10 -3320.379812578121 - 20 -1256.50374874116 - 0 -INSERT - 5 -B85 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3320.700460489955 - 20 -1256.704804335515 - 30 -0 - 41 --0.5904899999997447 - 42 -0.5904900000003975 - 43 -0 - 50 -269.9561751820622 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -LWPOLYLINE - 5 -B86 -100 -AcDbEntity - 8 -BLK_1_FLR_1_WASH - 6 -CONTINUOUS - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3320.689148559377 - 20 -1256.951083195586 - 10 -3320.689148559377 - 20 -1257.398417650012 - 10 -3320.375435412687 - 20 -1257.398417650012 - 10 -3320.375435412687 - 20 -1256.951083195586 - 0 -INSERT - 5 -B87 -100 -AcDbEntity - 8 -FURNITURE - 6 -ByLayer - 62 - 7 -370 - 0 -100 -AcDbBlockReference - 2 -Basin 22 - 10 -3320.69608332452 - 20 -1257.152138789941 - 30 -0 - 41 --0.5904899999997446 - 42 -0.5904900000003975 - 43 -0 - 50 -269.9561751820622 - 70 - 1 - 71 - 1 - 44 -0 - 45 -0 - 0 -LINE - 5 -B88 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3444.169366980704 - 20 -1243.831902978422 - 11 -3445.169366980703 - 21 -1243.831902978422 - 0 -LINE - 5 -B89 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3444.169366980704 - 20 -1243.681902978398 - 11 -3445.169366980703 - 21 -1243.681902978398 - 0 -LINE - 5 -B8A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3444.169366980704 - 20 -1243.561902978403 - 11 -3445.169366980703 - 21 -1243.561902978403 - 0 -LINE - 5 -B8B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3444.169366980704 - 20 -1243.561902978403 - 11 -3444.169366980704 - 21 -1243.831902978422 - 0 -LINE - 5 -B8C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3445.169366980703 - 20 -1243.561902978403 - 11 -3445.169366980703 - 21 -1243.831902978422 - 0 -LINE - 5 -B8D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3444.454366980853 - 20 -1244.13190297841 - 11 -3444.169366980704 - 21 -1243.831902978422 - 0 -LINE - 5 -B8E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3444.884366980788 - 20 -1244.13190297841 - 11 -3445.169366980703 - 21 -1243.831902978422 - 0 -LINE - 5 -B8F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3444.454366980853 - 20 -1244.13190297841 - 11 -3444.884366980788 - 21 -1244.13190297841 - 0 -LWPOLYLINE - 5 -B90 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3444.554366980713 - 20 -1245.631902978352 - 10 -3444.554366980713 - 20 -1244.131902978352 - 10 -3444.784366980695 - 20 -1244.131902978352 - 10 -3444.784366980695 - 20 -1245.631902978352 - 10 -3444.554366980713 - 20 -1245.631902978352 - 0 -LINE - 5 -B91 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.874835352739 - 20 -1243.831902978422 - 11 -3448.874835352739 - 21 -1243.831902978422 - 0 -LINE - 5 -B92 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.874835352739 - 20 -1243.681902978398 - 11 -3448.874835352739 - 21 -1243.681902978398 - 0 -LINE - 5 -B93 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.874835352739 - 20 -1243.561902978403 - 11 -3448.874835352739 - 21 -1243.561902978403 - 0 -LINE - 5 -B94 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.874835352739 - 20 -1243.561902978403 - 11 -3447.874835352739 - 21 -1243.831902978422 - 0 -LINE - 5 -B95 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3448.874835352739 - 20 -1243.561902978403 - 11 -3448.874835352739 - 21 -1243.831902978422 - 0 -LINE - 5 -B96 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3448.159835352889 - 20 -1244.13190297841 - 11 -3447.874835352739 - 21 -1243.831902978422 - 0 -LINE - 5 -B97 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3448.589835352823 - 20 -1244.13190297841 - 11 -3448.874835352739 - 21 -1243.831902978422 - 0 -LINE - 5 -B98 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3448.159835352889 - 20 -1244.13190297841 - 11 -3448.589835352823 - 21 -1244.13190297841 - 0 -LWPOLYLINE - 5 -B99 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3448.259835352749 - 20 -1245.631902978352 - 10 -3448.259835352749 - 20 -1244.131902978352 - 10 -3448.48983535273 - 20 -1244.131902978352 - 10 -3448.48983535273 - 20 -1245.631902978352 - 10 -3448.259835352749 - 20 -1245.631902978352 - 0 -LINE - 5 -B9A -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3440.669366980703 - 20 -1243.831902978422 - 11 -3441.669366980703 - 21 -1243.831902978422 - 0 -LINE - 5 -B9B -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3440.669366980703 - 20 -1243.681902978398 - 11 -3441.669366980703 - 21 -1243.681902978398 - 0 -LINE - 5 -B9C -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3440.669366980703 - 20 -1243.561902978403 - 11 -3441.669366980703 - 21 -1243.561902978403 - 0 -LINE - 5 -B9D -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3440.669366980703 - 20 -1243.561902978403 - 11 -3440.669366980703 - 21 -1243.831902978422 - 0 -LINE - 5 -B9E -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3441.669366980703 - 20 -1243.561902978403 - 11 -3441.669366980703 - 21 -1243.831902978422 - 0 -LINE - 5 -B9F -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3440.954366980852 - 20 -1244.13190297841 - 11 -3440.669366980703 - 21 -1243.831902978422 - 0 -LINE - 5 -BA0 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3441.384366980787 - 20 -1244.13190297841 - 11 -3441.669366980703 - 21 -1243.831902978422 - 0 -LINE - 5 -BA1 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3440.954366980852 - 20 -1244.13190297841 - 11 -3441.384366980787 - 21 -1244.13190297841 - 0 -LWPOLYLINE - 5 -BA2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3441.054366980712 - 20 -1245.631902978352 - 10 -3441.054366980712 - 20 -1244.131902978352 - 10 -3441.284366980692 - 20 -1244.131902978352 - 10 -3441.284366980692 - 20 -1245.631902978352 - 10 -3441.054366980712 - 20 -1245.631902978352 - 0 -LINE - 5 -BA3 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3437.439366980767 - 20 -1243.831902978422 - 11 -3438.439366980766 - 21 -1243.831902978422 - 0 -LINE - 5 -BA4 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3437.439366980767 - 20 -1243.681902978398 - 11 -3438.439366980766 - 21 -1243.681902978398 - 0 -LINE - 5 -BA5 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3437.439366980767 - 20 -1243.561902978403 - 11 -3438.439366980766 - 21 -1243.561902978403 - 0 -LINE - 5 -BA6 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3437.439366980767 - 20 -1243.561902978403 - 11 -3437.439366980767 - 21 -1243.831902978422 - 0 -LINE - 5 -BA7 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3438.439366980766 - 20 -1243.561902978403 - 11 -3438.439366980766 - 21 -1243.831902978422 - 0 -LINE - 5 -BA8 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3437.724366980916 - 20 -1244.13190297841 - 11 -3437.439366980767 - 21 -1243.831902978422 - 0 -LINE - 5 -BA9 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3438.15436698085 - 20 -1244.13190297841 - 11 -3438.439366980766 - 21 -1243.831902978422 - 0 -LINE - 5 -BAA -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3437.724366980916 - 20 -1244.13190297841 - 11 -3438.15436698085 - 21 -1244.13190297841 - 0 -LWPOLYLINE - 5 -BAB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3437.824366980776 - 20 -1245.631902978352 - 10 -3437.824366980776 - 20 -1244.131902978352 - 10 -3438.054366980757 - 20 -1244.131902978352 - 10 -3438.054366980757 - 20 -1245.631902978352 - 10 -3437.824366980776 - 20 -1245.631902978352 - 0 -LINE - 5 -BAC -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3434.479366968187 - 20 -1243.831902978422 - 11 -3435.479366968186 - 21 -1243.831902978422 - 0 -LINE - 5 -BAD -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3434.479366968187 - 20 -1243.681902978398 - 11 -3435.479366968186 - 21 -1243.681902978398 - 0 -LINE - 5 -BAE -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3434.479366968187 - 20 -1243.561902978403 - 11 -3435.479366968186 - 21 -1243.561902978403 - 0 -LINE - 5 -BAF -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3434.479366968187 - 20 -1243.561902978403 - 11 -3434.479366968187 - 21 -1243.831902978422 - 0 -LINE - 5 -BB0 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3435.479366968186 - 20 -1243.561902978403 - 11 -3435.479366968186 - 21 -1243.831902978422 - 0 -LINE - 5 -BB1 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3434.764366968335 - 20 -1244.13190297841 - 11 -3434.479366968187 - 21 -1243.831902978422 - 0 -LINE - 5 -BB2 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3435.19436696827 - 20 -1244.13190297841 - 11 -3435.479366968186 - 21 -1243.831902978422 - 0 -LINE - 5 -BB3 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3434.764366968335 - 20 -1244.13190297841 - 11 -3435.19436696827 - 21 -1244.13190297841 - 0 -LWPOLYLINE - 5 -BB4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3434.864366968195 - 20 -1245.631902978352 - 10 -3434.864366968195 - 20 -1244.131902978352 - 10 -3435.094366968177 - 20 -1244.131902978352 - 10 -3435.094366968177 - 20 -1245.631902978352 - 10 -3434.864366968195 - 20 -1245.631902978352 - 0 -LINE - 5 -BB5 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3430.979366980759 - 20 -1243.831902978422 - 11 -3431.979366980761 - 21 -1243.831902978422 - 0 -LINE - 5 -BB6 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3430.979366980759 - 20 -1243.681902978398 - 11 -3431.979366980761 - 21 -1243.681902978398 - 0 -LINE - 5 -BB7 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3430.979366980759 - 20 -1243.561902978403 - 11 -3431.979366980761 - 21 -1243.561902978403 - 0 -LINE - 5 -BB8 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3430.979366980759 - 20 -1243.561902978403 - 11 -3430.979366980759 - 21 -1243.831902978422 - 0 -LINE - 5 -BB9 -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3431.979366980761 - 20 -1243.561902978403 - 11 -3431.979366980761 - 21 -1243.831902978422 - 0 -LINE - 5 -BBA -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3431.264366980908 - 20 -1244.13190297841 - 11 -3430.979366980759 - 21 -1243.831902978422 - 0 -LINE - 5 -BBB -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3431.694366980842 - 20 -1244.13190297841 - 11 -3431.979366980761 - 21 -1243.831902978422 - 0 -LINE - 5 -BBC -100 -AcDbEntity - 8 -0 - 6 -DASHED2 - 62 - 256 -370 - 0 -100 -AcDbLine - 10 -3431.264366980908 - 20 -1244.13190297841 - 11 -3431.694366980842 - 21 -1244.13190297841 - 0 -LWPOLYLINE - 5 -BBD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 0 - 43 -0 - 10 -3431.364366980768 - 20 -1245.631902978352 - 10 -3431.364366980768 - 20 -1244.131902978352 - 10 -3431.59436698075 - 20 -1244.131902978352 - 10 -3431.59436698075 - 20 -1245.631902978352 - 10 -3431.364366980768 - 20 -1245.631902978352 - 0 -MTEXT - 5 -BBE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 45 -370 - -1 -100 -AcDbMText - 10 -3318.107607782454 - 20 -1258.23396419466 - 30 -0 - 40 -0.18 - 41 -1.530000000000028 - 71 - 1 - 72 - 5 - 1 -\pt252;Urinal - 7 -sree -210 -0 -220 -0 -230 -1 - 50 --0.008873397653922362 - 73 - 1 - 44 -1 - 0 -LINE - 5 -BBF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - -1 -100 -AcDbLine - 10 -3372.972164166813 - 20 -1255.550104161433 - 11 -3372.972236733065 - 21 -1255.780104182067 - 0 -LINE - 5 -BC0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - -1 -100 -AcDbLine - 10 -3372.572164165089 - 20 -1255.550104161259 - 11 -3372.972164166813 - 21 -1255.550104162563 - 0 -LINE - 5 -BC1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - -1 -100 -AcDbLine - 10 -3372.972164166813 - 20 -1255.550104162563 - 11 -3372.972164166813 - 21 -1255.780104162563 - 0 -LINE - 5 -BC2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - -1 -100 -AcDbLine - 10 -3372.972164166813 - 20 -1255.780104162563 - 11 -3372.572164165089 - 21 -1255.77999665458 - 0 -LWPOLYLINE - 5 -BC3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3292.840538748289 - 20 -1259.050104171597 - 10 -3290.634776905874 - 20 -1259.050104171597 - 10 -3290.634776905874 - 20 -1247.282947462919 - 10 -3292.840540971275 - 20 -1247.282947462919 - 0 -LINE - 5 -BC4 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3299.824476717156 - 20 -1258.300104148744 - 11 -3299.824476717156 - 21 -1259.050104148744 - 0 -DIMENSION - 5 -BC5 -100 -AcDbEntity - 8 -BLK_1_FLR_0_FIRESTAIR_1_FLIGHT - 6 -CONTINUOUS - 62 - 2 -370 - -1 -100 -AcDbDimension - 2 -*D87 - 10 -3300.004476717158 - 20 -1258.300104148744 - 30 -0 - 11 -3299.361154752628 - 21 -1258.120104148744 - 31 -0 - 70 - 32 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3299.824476717156 - 23 -1259.050104148744 - 33 -0 - 14 -3300.004476717158 - 24 -1258.300104148744 - 34 -0 - 50 -90 -100 -AcDbRotatedDimension - 0 -LWPOLYLINE - 5 -BC6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 21 - 70 - 0 - 43 -0 - 10 -3434.344366980751 - 20 -1248.636620183553 - 10 -3434.344366980751 - 20 -1248.812620183553 - 10 -3434.14436698075 - 20 -1248.812620183553 - 10 -3434.14436698075 - 20 -1248.988620183553 - 10 -3433.944366980751 - 20 -1248.988620183553 - 10 -3433.944366980751 - 20 -1249.164620183553 - 10 -3433.744366980751 - 20 -1249.164620183553 - 10 -3433.744366980751 - 20 -1249.340620183553 - 10 -3433.544366980751 - 20 -1249.340620183553 - 10 -3433.544366980751 - 20 -1249.516620183553 - 10 -3433.344366980751 - 20 -1249.516620183553 - 10 -3433.344366980751 - 20 -1249.692620183552 - 10 -3433.144366980751 - 20 -1249.692620183552 - 10 -3433.144366980751 - 20 -1249.868620183552 - 10 -3432.944366980752 - 20 -1249.868620183552 - 10 -3432.944366980752 - 20 -1250.044620183552 - 10 -3432.744366980752 - 20 -1250.044620183552 - 10 -3432.744366980752 - 20 -1250.220620183552 - 10 -3432.544366980752 - 20 -1250.220620183552 - 10 -3432.544366980752 - 20 -1250.396620183552 - 10 -3432.344366980752 - 20 -1250.396620183552 - 0 -LWPOLYLINE - 5 -BC7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3432.344366980752 - 20 -1250.396620183552 - 10 -3432.344366980752 - 20 -1250.572620183552 - 10 -3431.594366980752 - 20 -1250.572620183552 - 0 -LWPOLYLINE - 5 -BC8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 23 - 70 - 0 - 43 -0 - 10 -3434.24436698075 - 20 -1248.636620183553 - 10 -3434.24436698075 - 20 -1248.712620183553 - 10 -3434.044366980751 - 20 -1248.712620183553 - 10 -3434.044366980751 - 20 -1248.888620183553 - 10 -3433.844366980751 - 20 -1248.888620183553 - 10 -3433.844366980751 - 20 -1249.064620183553 - 10 -3433.644366980751 - 20 -1249.064620183553 - 10 -3433.644366980751 - 20 -1249.240620183553 - 10 -3433.444366980751 - 20 -1249.240620183553 - 10 -3433.444366980751 - 20 -1249.416620183553 - 10 -3433.244366980751 - 20 -1249.416620183553 - 10 -3433.244366980751 - 20 -1249.592620183553 - 10 -3433.044366980752 - 20 -1249.592620183553 - 10 -3433.044366980752 - 20 -1249.768620183553 - 10 -3432.844366980752 - 20 -1249.768620183553 - 10 -3432.844366980752 - 20 -1249.944620183552 - 10 -3432.644366980752 - 20 -1249.944620183552 - 10 -3432.644366980752 - 20 -1250.120620183552 - 10 -3432.444366980752 - 20 -1250.120620183552 - 10 -3432.444366980752 - 20 -1250.296620183552 - 10 -3432.244366980752 - 20 -1250.296620183552 - 10 -3432.244366980752 - 20 -1250.472620183552 - 10 -3431.594366980752 - 20 -1250.472620183552 - 0 -LWPOLYLINE - 5 -BC9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3434.24436698075 - 20 -1248.636620183553 - 10 -3434.344366980751 - 20 -1248.636620183553 - 0 -LINE - 5 -BCA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3432.344366980752 - 20 -1250.572620183552 - 11 -3432.344366980752 - 21 -1250.748620183552 - 0 -LINE - 5 -BCB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3432.344366980752 - 20 -1250.748620183552 - 11 -3431.594366980752 - 21 -1250.748620183552 - 0 -LINE - 5 -BCC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3431.594366980752 - 20 -1250.748620183552 - 11 -3431.594366980752 - 21 -1250.472620183552 - 0 -HATCH - 5 -BCD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 46 - 72 - 1 - 10 -3432.344366980752 - 20 -1250.572620183552 - 11 -3431.594366980752 - 21 -1250.572620183552 - 72 - 1 - 10 -3431.594366980752 - 20 -1250.572620183552 - 11 -3431.594366980752 - 21 -1250.472620183552 - 72 - 1 - 10 -3431.594366980752 - 20 -1250.472620183552 - 11 -3432.244366980752 - 21 -1250.472620183552 - 72 - 1 - 10 -3432.244366980752 - 20 -1250.472620183552 - 11 -3432.244366980752 - 21 -1250.296620183552 - 72 - 1 - 10 -3432.244366980752 - 20 -1250.296620183552 - 11 -3432.444366980752 - 21 -1250.296620183552 - 72 - 1 - 10 -3432.444366980752 - 20 -1250.296620183552 - 11 -3432.444366980752 - 21 -1250.120620183552 - 72 - 1 - 10 -3432.444366980752 - 20 -1250.120620183552 - 11 -3432.644366980752 - 21 -1250.120620183552 - 72 - 1 - 10 -3432.644366980752 - 20 -1250.120620183552 - 11 -3432.644366980752 - 21 -1249.944620183552 - 72 - 1 - 10 -3432.644366980752 - 20 -1249.944620183552 - 11 -3432.844366980752 - 21 -1249.944620183552 - 72 - 1 - 10 -3432.844366980752 - 20 -1249.944620183552 - 11 -3432.844366980752 - 21 -1249.768620183553 - 72 - 1 - 10 -3432.844366980752 - 20 -1249.768620183553 - 11 -3433.044366980752 - 21 -1249.768620183553 - 72 - 1 - 10 -3433.044366980752 - 20 -1249.768620183553 - 11 -3433.044366980752 - 21 -1249.592620183553 - 72 - 1 - 10 -3433.044366980752 - 20 -1249.592620183553 - 11 -3433.244366980751 - 21 -1249.592620183553 - 72 - 1 - 10 -3433.244366980751 - 20 -1249.592620183553 - 11 -3433.244366980751 - 21 -1249.416620183553 - 72 - 1 - 10 -3433.244366980751 - 20 -1249.416620183553 - 11 -3433.444366980751 - 21 -1249.416620183553 - 72 - 1 - 10 -3433.444366980751 - 20 -1249.416620183553 - 11 -3433.444366980751 - 21 -1249.240620183553 - 72 - 1 - 10 -3433.444366980751 - 20 -1249.240620183553 - 11 -3433.644366980751 - 21 -1249.240620183553 - 72 - 1 - 10 -3433.644366980751 - 20 -1249.240620183553 - 11 -3433.644366980751 - 21 -1249.064620183553 - 72 - 1 - 10 -3433.644366980751 - 20 -1249.064620183553 - 11 -3433.844366980751 - 21 -1249.064620183553 - 72 - 1 - 10 -3433.844366980751 - 20 -1249.064620183553 - 11 -3433.844366980751 - 21 -1248.888620183553 - 72 - 1 - 10 -3433.844366980751 - 20 -1248.888620183553 - 11 -3434.044366980751 - 21 -1248.888620183553 - 72 - 1 - 10 -3434.044366980751 - 20 -1248.888620183553 - 11 -3434.044366980751 - 21 -1248.712620183553 - 72 - 1 - 10 -3434.044366980751 - 20 -1248.712620183553 - 11 -3434.24436698075 - 21 -1248.712620183553 - 72 - 1 - 10 -3434.24436698075 - 20 -1248.712620183553 - 11 -3434.24436698075 - 21 -1248.636620183553 - 72 - 1 - 10 -3434.24436698075 - 20 -1248.636620183553 - 11 -3434.344366980751 - 21 -1248.636620183553 - 72 - 1 - 10 -3434.344366980751 - 20 -1248.636620183553 - 11 -3434.344366980751 - 21 -1248.812620183553 - 72 - 1 - 10 -3434.344366980751 - 20 -1248.812620183553 - 11 -3434.14436698075 - 21 -1248.812620183553 - 72 - 1 - 10 -3434.14436698075 - 20 -1248.812620183553 - 11 -3434.14436698075 - 21 -1248.988620183553 - 72 - 1 - 10 -3434.14436698075 - 20 -1248.988620183553 - 11 -3433.944366980751 - 21 -1248.988620183553 - 72 - 1 - 10 -3433.944366980751 - 20 -1248.988620183553 - 11 -3433.944366980751 - 21 -1249.164620183553 - 72 - 1 - 10 -3433.944366980751 - 20 -1249.164620183553 - 11 -3433.744366980751 - 21 -1249.164620183553 - 72 - 1 - 10 -3433.744366980751 - 20 -1249.164620183553 - 11 -3433.744366980751 - 21 -1249.340620183553 - 72 - 1 - 10 -3433.744366980751 - 20 -1249.340620183553 - 11 -3433.544366980751 - 21 -1249.340620183553 - 72 - 1 - 10 -3433.544366980751 - 20 -1249.340620183553 - 11 -3433.544366980751 - 21 -1249.516620183553 - 72 - 1 - 10 -3433.544366980751 - 20 -1249.516620183553 - 11 -3433.344366980751 - 21 -1249.516620183553 - 72 - 1 - 10 -3433.344366980751 - 20 -1249.516620183553 - 11 -3433.344366980751 - 21 -1249.692620183552 - 72 - 1 - 10 -3433.344366980751 - 20 -1249.692620183552 - 11 -3433.144366980751 - 21 -1249.692620183552 - 72 - 1 - 10 -3433.144366980751 - 20 -1249.692620183552 - 11 -3433.144366980751 - 21 -1249.868620183552 - 72 - 1 - 10 -3433.144366980751 - 20 -1249.868620183552 - 11 -3432.944366980752 - 21 -1249.868620183552 - 72 - 1 - 10 -3432.944366980752 - 20 -1249.868620183552 - 11 -3432.944366980752 - 21 -1250.044620183552 - 72 - 1 - 10 -3432.944366980752 - 20 -1250.044620183552 - 11 -3432.744366980752 - 21 -1250.044620183552 - 72 - 1 - 10 -3432.744366980752 - 20 -1250.044620183552 - 11 -3432.744366980752 - 21 -1250.220620183552 - 72 - 1 - 10 -3432.744366980752 - 20 -1250.220620183552 - 11 -3432.544366980752 - 21 -1250.220620183552 - 72 - 1 - 10 -3432.544366980752 - 20 -1250.220620183552 - 11 -3432.544366980752 - 21 -1250.396620183552 - 72 - 1 - 10 -3432.544366980752 - 20 -1250.396620183552 - 11 -3432.344366980752 - 21 -1250.396620183552 - 72 - 1 - 10 -3432.344366980752 - 20 -1250.396620183552 - 11 -3432.344366980752 - 21 -1250.572620183552 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -BCE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 25 - 70 - 0 - 43 -0 - 10 -3432.344366980752 - 20 -1250.748620183552 - 10 -3432.344366980752 - 20 -1250.924620183552 - 10 -3432.544366980752 - 20 -1250.924620183552 - 10 -3432.544366980752 - 20 -1251.100620183552 - 10 -3432.744366980752 - 20 -1251.100620183552 - 10 -3432.744366980752 - 20 -1251.276620183552 - 10 -3432.944366980752 - 20 -1251.276620183552 - 10 -3432.944366980752 - 20 -1251.452620183552 - 10 -3433.144366980751 - 20 -1251.452620183552 - 10 -3433.144366980751 - 20 -1251.628620183552 - 10 -3433.344366980751 - 20 -1251.628620183552 - 10 -3433.344366980751 - 20 -1251.804620183552 - 10 -3433.544366980751 - 20 -1251.804620183552 - 10 -3433.544366980751 - 20 -1251.980620183552 - 10 -3433.744366980751 - 20 -1251.980620183552 - 10 -3433.744366980751 - 20 -1252.156620183552 - 10 -3433.944366980751 - 20 -1252.156620183552 - 10 -3433.944366980751 - 20 -1252.332620183551 - 10 -3434.14436698075 - 20 -1252.332620183551 - 10 -3434.14436698075 - 20 -1252.508620183551 - 10 -3434.344366980751 - 20 -1252.508620183551 - 10 -3434.344366980751 - 20 -1252.684620183551 - 10 -3434.54436698075 - 20 -1252.684620183551 - 10 -3434.54436698075 - 20 -1252.684620183551 - 10 -3434.54436698075 - 20 -1252.684620183551 - 0 -LWPOLYLINE - 5 -BCF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 23 - 70 - 0 - 43 -0 - 10 -3432.444366980752 - 20 -1250.748620183552 - 10 -3432.444366980752 - 20 -1250.824620183552 - 10 -3432.644366980752 - 20 -1250.824620183552 - 10 -3432.644366980752 - 20 -1251.000620183552 - 10 -3432.844366980752 - 20 -1251.000620183552 - 10 -3432.844366980752 - 20 -1251.176620183552 - 10 -3433.044366980752 - 20 -1251.176620183552 - 10 -3433.044366980752 - 20 -1251.352620183552 - 10 -3433.244366980751 - 20 -1251.352620183552 - 10 -3433.244366980751 - 20 -1251.528620183552 - 10 -3433.444366980751 - 20 -1251.528620183552 - 10 -3433.444366980751 - 20 -1251.704620183552 - 10 -3433.644366980751 - 20 -1251.704620183552 - 10 -3433.644366980751 - 20 -1251.880620183552 - 10 -3433.844366980751 - 20 -1251.880620183552 - 10 -3433.844366980751 - 20 -1252.056620183552 - 10 -3434.044366980751 - 20 -1252.056620183552 - 10 -3434.044366980751 - 20 -1252.232620183552 - 10 -3434.24436698075 - 20 -1252.232620183552 - 10 -3434.24436698075 - 20 -1252.408620183551 - 10 -3434.444366980751 - 20 -1252.408620183551 - 10 -3434.444366980751 - 20 -1252.584620183551 - 10 -3434.54436698075 - 20 -1252.584620183551 - 0 -LINE - 5 -BD0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3432.344366980752 - 20 -1250.748620183552 - 11 -3432.344366980752 - 21 -1250.648620183552 - 0 -LINE - 5 -BD1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3432.344366980752 - 20 -1250.648620183552 - 11 -3432.444366980752 - 21 -1250.648620183552 - 0 -LINE - 5 -BD2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3432.444366980752 - 20 -1250.648620183552 - 11 -3432.444366980752 - 21 -1250.748620183552 - 0 -LWPOLYLINE - 5 -BD3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 50 - 70 - 0 - 43 -0 - 10 -3431.918118909449 - 20 -1254.390620183463 - 10 -3432.044366980719 - 20 -1254.390620183463 - 10 -3432.044366980719 - 20 -1254.390620183463 - 10 -3432.244366980718 - 20 -1254.390620183463 - 10 -3432.244366980718 - 20 -1254.226620183463 - 10 -3432.444366980718 - 20 -1254.226620183463 - 10 -3432.444366980718 - 20 -1254.062620183464 - 10 -3432.644366980718 - 20 -1254.062620183464 - 10 -3432.644366980718 - 20 -1253.898620183464 - 10 -3432.844366980718 - 20 -1253.898620183464 - 10 -3432.844366980718 - 20 -1253.734620183464 - 10 -3433.044366980718 - 20 -1253.734620183464 - 10 -3433.044366980718 - 20 -1253.570620183463 - 10 -3433.244366980718 - 20 -1253.570620183463 - 10 -3433.244366980718 - 20 -1253.406620183463 - 10 -3433.444366980717 - 20 -1253.406620183463 - 10 -3433.444366980717 - 20 -1253.242620183464 - 10 -3433.644366980717 - 20 -1253.242620183464 - 10 -3433.644366980717 - 20 -1253.078620183464 - 10 -3433.844366980717 - 20 -1253.078620183464 - 10 -3433.844366980717 - 20 -1252.914620183464 - 10 -3434.044366980717 - 20 -1252.914620183464 - 10 -3434.044366980717 - 20 -1252.750620183464 - 10 -3434.244366980717 - 20 -1252.750620183464 - 10 -3434.244366980717 - 20 -1252.586620183464 - 10 -3434.344366980717 - 20 -1252.586620183464 - 10 -3434.344366980717 - 20 -1252.850620183463 - 10 -3434.144366980717 - 20 -1252.850620183463 - 10 -3434.144366980717 - 20 -1253.014620183463 - 10 -3433.944366980717 - 20 -1253.014620183463 - 10 -3433.944366980717 - 20 -1253.178620183464 - 10 -3433.744366980717 - 20 -1253.178620183464 - 10 -3433.744366980717 - 20 -1253.342620183463 - 10 -3433.544366980718 - 20 -1253.342620183463 - 10 -3433.544366980718 - 20 -1253.506620183463 - 10 -3433.344366980718 - 20 -1253.506620183463 - 10 -3433.344366980718 - 20 -1253.670620183463 - 10 -3433.144366980718 - 20 -1253.670620183463 - 10 -3433.144366980718 - 20 -1253.834620183464 - 10 -3432.944366980718 - 20 -1253.834620183464 - 10 -3432.944366980718 - 20 -1253.998620183464 - 10 -3432.744366980717 - 20 -1253.998620183464 - 10 -3432.744366980717 - 20 -1254.162620183463 - 10 -3432.54436698072 - 20 -1254.162620183463 - 10 -3432.54436698072 - 20 -1254.326620183463 - 10 -3432.344366980718 - 20 -1254.326620183463 - 10 -3432.344366980718 - 20 -1254.490620183463 - 10 -3432.344366980718 - 20 -1254.490620183463 - 10 -3432.344366980718 - 20 -1254.490620183463 - 10 -3431.59436698075 - 20 -1254.490620183463 - 0 -LWPOLYLINE - 5 -BD4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3432.144366980719 - 20 -1254.390620183463 - 10 -3431.59436698075 - 20 -1254.390620183463 - 0 -LWPOLYLINE - 5 -BD5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3432.344366980718 - 20 -1254.654620183463 - 10 -3432.344366980718 - 20 -1254.490620183463 - 0 -LWPOLYLINE - 5 -BD6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 40 - 70 - 0 - 43 -0 - 10 -3434.244366980717 - 20 -1256.022620183525 - 10 -3434.244366980717 - 20 -1255.866620183463 - 10 -3434.044366980717 - 20 -1255.866620183463 - 10 -3434.044366980717 - 20 -1255.702620183463 - 10 -3433.844366980717 - 20 -1255.702620183463 - 10 -3433.844366980717 - 20 -1255.538620183463 - 10 -3433.644366980717 - 20 -1255.538620183463 - 10 -3433.644366980717 - 20 -1255.374620183463 - 10 -3433.444366980717 - 20 -1255.374620183463 - 10 -3433.444366980717 - 20 -1255.210620183463 - 10 -3433.244366980718 - 20 -1255.210620183463 - 10 -3433.244366980718 - 20 -1255.046620183464 - 10 -3433.044366980718 - 20 -1255.046620183464 - 10 -3433.044366980718 - 20 -1254.882620183463 - 10 -3432.844366980718 - 20 -1254.882620183463 - 10 -3432.844366980718 - 20 -1254.718620183463 - 10 -3432.644366980718 - 20 -1254.718620183463 - 10 -3432.644366980718 - 20 -1254.554620183463 - 10 -3432.444366980718 - 20 -1254.554620183463 - 10 -3432.444366980718 - 20 -1254.390620183463 - 10 -3432.344366980718 - 20 -1254.390620183463 - 10 -3432.344366980718 - 20 -1254.654620183463 - 10 -3432.54436698072 - 20 -1254.654620183463 - 10 -3432.54436698072 - 20 -1254.818620183463 - 10 -3432.744366980717 - 20 -1254.818620183463 - 10 -3432.744366980717 - 20 -1254.982620183463 - 10 -3432.944366980718 - 20 -1254.982620183463 - 10 -3432.944366980718 - 20 -1255.146620183463 - 10 -3433.144366980718 - 20 -1255.146620183463 - 10 -3433.144366980718 - 20 -1255.310620183463 - 10 -3433.344366980718 - 20 -1255.310620183463 - 10 -3433.344366980718 - 20 -1255.474620183463 - 10 -3433.544366980718 - 20 -1255.474620183463 - 10 -3433.544366980718 - 20 -1255.638620183463 - 10 -3433.744366980717 - 20 -1255.638620183463 - 10 -3433.744366980717 - 20 -1255.802620183463 - 10 -3433.944366980717 - 20 -1255.802620183463 - 10 -3433.944366980717 - 20 -1255.966620183463 - 10 -3434.144366980717 - 20 -1255.966620183463 - 10 -3434.144366980717 - 20 -1256.12262018356 - 0 -HATCH - 5 -BD7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 47 - 72 - 1 - 10 -3432.54436698072 - 20 -1254.326620183463 - 11 -3432.344366980718 - 21 -1254.326620183463 - 72 - 1 - 10 -3432.344366980718 - 20 -1254.326620183463 - 11 -3432.344366980718 - 21 -1254.490620183463 - 72 - 1 - 10 -3432.344366980718 - 20 -1254.490620183463 - 11 -3431.59436698075 - 21 -1254.490620183463 - 72 - 1 - 10 -3431.59436698075 - 20 -1254.490620183463 - 11 -3431.59436698075 - 21 -1254.390620183463 - 72 - 1 - 10 -3431.59436698075 - 20 -1254.390620183463 - 11 -3432.144366980719 - 21 -1254.390620183463 - 72 - 1 - 10 -3432.144366980719 - 20 -1254.390620183463 - 11 -3432.244366980718 - 21 -1254.390620183463 - 72 - 1 - 10 -3432.244366980718 - 20 -1254.390620183463 - 11 -3432.244366980718 - 21 -1254.226620183463 - 72 - 1 - 10 -3432.244366980718 - 20 -1254.226620183463 - 11 -3432.444366980718 - 21 -1254.226620183463 - 72 - 1 - 10 -3432.444366980718 - 20 -1254.226620183463 - 11 -3432.444366980718 - 21 -1254.062620183464 - 72 - 1 - 10 -3432.444366980718 - 20 -1254.062620183464 - 11 -3432.644366980718 - 21 -1254.062620183464 - 72 - 1 - 10 -3432.644366980718 - 20 -1254.062620183464 - 11 -3432.644366980718 - 21 -1253.898620183464 - 72 - 1 - 10 -3432.644366980718 - 20 -1253.898620183464 - 11 -3432.844366980718 - 21 -1253.898620183464 - 72 - 1 - 10 -3432.844366980718 - 20 -1253.898620183464 - 11 -3432.844366980718 - 21 -1253.734620183464 - 72 - 1 - 10 -3432.844366980718 - 20 -1253.734620183464 - 11 -3433.044366980718 - 21 -1253.734620183464 - 72 - 1 - 10 -3433.044366980718 - 20 -1253.734620183464 - 11 -3433.044366980718 - 21 -1253.570620183463 - 72 - 1 - 10 -3433.044366980718 - 20 -1253.570620183463 - 11 -3433.244366980718 - 21 -1253.570620183463 - 72 - 1 - 10 -3433.244366980718 - 20 -1253.570620183463 - 11 -3433.244366980718 - 21 -1253.406620183463 - 72 - 1 - 10 -3433.244366980718 - 20 -1253.406620183463 - 11 -3433.444366980717 - 21 -1253.406620183463 - 72 - 1 - 10 -3433.444366980717 - 20 -1253.406620183463 - 11 -3433.444366980717 - 21 -1253.242620183464 - 72 - 1 - 10 -3433.444366980717 - 20 -1253.242620183464 - 11 -3433.644366980717 - 21 -1253.242620183464 - 72 - 1 - 10 -3433.644366980717 - 20 -1253.242620183464 - 11 -3433.644366980717 - 21 -1253.078620183464 - 72 - 1 - 10 -3433.644366980717 - 20 -1253.078620183464 - 11 -3433.844366980717 - 21 -1253.078620183464 - 72 - 1 - 10 -3433.844366980717 - 20 -1253.078620183464 - 11 -3433.844366980717 - 21 -1252.914620183464 - 72 - 1 - 10 -3433.844366980717 - 20 -1252.914620183464 - 11 -3434.044366980717 - 21 -1252.914620183464 - 72 - 1 - 10 -3434.044366980717 - 20 -1252.914620183464 - 11 -3434.044366980717 - 21 -1252.750620183464 - 72 - 1 - 10 -3434.044366980717 - 20 -1252.750620183464 - 11 -3434.244366980717 - 21 -1252.750620183464 - 72 - 1 - 10 -3434.244366980717 - 20 -1252.750620183464 - 11 -3434.244366980717 - 21 -1252.586620183464 - 72 - 1 - 10 -3434.244366980717 - 20 -1252.586620183464 - 11 -3434.344366980717 - 21 -1252.586620183464 - 72 - 1 - 10 -3434.344366980717 - 20 -1252.586620183464 - 11 -3434.344366980717 - 21 -1252.850620183463 - 72 - 1 - 10 -3434.344366980717 - 20 -1252.850620183463 - 11 -3434.144366980717 - 21 -1252.850620183463 - 72 - 1 - 10 -3434.144366980717 - 20 -1252.850620183463 - 11 -3434.144366980717 - 21 -1253.014620183463 - 72 - 1 - 10 -3434.144366980717 - 20 -1253.014620183463 - 11 -3433.944366980717 - 21 -1253.014620183463 - 72 - 1 - 10 -3433.944366980717 - 20 -1253.014620183463 - 11 -3433.944366980717 - 21 -1253.178620183464 - 72 - 1 - 10 -3433.944366980717 - 20 -1253.178620183464 - 11 -3433.744366980717 - 21 -1253.178620183464 - 72 - 1 - 10 -3433.744366980717 - 20 -1253.178620183464 - 11 -3433.744366980717 - 21 -1253.342620183463 - 72 - 1 - 10 -3433.744366980717 - 20 -1253.342620183463 - 11 -3433.544366980718 - 21 -1253.342620183463 - 72 - 1 - 10 -3433.544366980718 - 20 -1253.342620183463 - 11 -3433.544366980718 - 21 -1253.506620183463 - 72 - 1 - 10 -3433.544366980718 - 20 -1253.506620183463 - 11 -3433.344366980718 - 21 -1253.506620183463 - 72 - 1 - 10 -3433.344366980718 - 20 -1253.506620183463 - 11 -3433.344366980718 - 21 -1253.670620183463 - 72 - 1 - 10 -3433.344366980718 - 20 -1253.670620183463 - 11 -3433.144366980718 - 21 -1253.670620183463 - 72 - 1 - 10 -3433.144366980718 - 20 -1253.670620183463 - 11 -3433.144366980718 - 21 -1253.834620183464 - 72 - 1 - 10 -3433.144366980718 - 20 -1253.834620183464 - 11 -3432.944366980718 - 21 -1253.834620183464 - 72 - 1 - 10 -3432.944366980718 - 20 -1253.834620183464 - 11 -3432.944366980718 - 21 -1253.998620183464 - 72 - 1 - 10 -3432.944366980718 - 20 -1253.998620183464 - 11 -3432.744366980717 - 21 -1253.998620183464 - 72 - 1 - 10 -3432.744366980717 - 20 -1253.998620183464 - 11 -3432.744366980717 - 21 -1254.162620183463 - 72 - 1 - 10 -3432.744366980717 - 20 -1254.162620183463 - 11 -3432.54436698072 - 21 -1254.162620183463 - 72 - 1 - 10 -3432.54436698072 - 20 -1254.162620183463 - 11 -3432.54436698072 - 21 -1254.326620183463 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -BD8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 50 - 70 - 0 - 43 -0 - 10 -3431.918118909449 - 20 -1257.990620183524 - 10 -3432.044366980719 - 20 -1257.990620183524 - 10 -3432.044366980719 - 20 -1257.990620183524 - 10 -3432.244366980718 - 20 -1257.990620183524 - 10 -3432.244366980718 - 20 -1257.826620183525 - 10 -3432.444366980718 - 20 -1257.826620183525 - 10 -3432.444366980718 - 20 -1257.662620183525 - 10 -3432.644366980718 - 20 -1257.662620183525 - 10 -3432.644366980718 - 20 -1257.498620183525 - 10 -3432.844366980718 - 20 -1257.498620183525 - 10 -3432.844366980718 - 20 -1257.334620183525 - 10 -3433.044366980718 - 20 -1257.334620183525 - 10 -3433.044366980718 - 20 -1257.170620183525 - 10 -3433.244366980718 - 20 -1257.170620183525 - 10 -3433.244366980718 - 20 -1257.006620183525 - 10 -3433.444366980717 - 20 -1257.006620183525 - 10 -3433.444366980717 - 20 -1256.842620183524 - 10 -3433.644366980717 - 20 -1256.842620183524 - 10 -3433.644366980717 - 20 -1256.678620183525 - 10 -3433.844366980717 - 20 -1256.678620183525 - 10 -3433.844366980717 - 20 -1256.514620183525 - 10 -3434.044366980717 - 20 -1256.514620183525 - 10 -3434.044366980717 - 20 -1256.350620183525 - 10 -3434.244366980717 - 20 -1256.350620183525 - 10 -3434.244366980717 - 20 -1256.186620183525 - 10 -3434.344366980717 - 20 -1256.186620183525 - 10 -3434.344366980717 - 20 -1256.450620183525 - 10 -3434.144366980717 - 20 -1256.450620183525 - 10 -3434.144366980717 - 20 -1256.614620183525 - 10 -3433.944366980717 - 20 -1256.614620183525 - 10 -3433.944366980717 - 20 -1256.778620183524 - 10 -3433.744366980717 - 20 -1256.778620183524 - 10 -3433.744366980717 - 20 -1256.942620183524 - 10 -3433.544366980718 - 20 -1256.942620183524 - 10 -3433.544366980718 - 20 -1257.106620183525 - 10 -3433.344366980718 - 20 -1257.106620183525 - 10 -3433.344366980718 - 20 -1257.270620183525 - 10 -3433.144366980718 - 20 -1257.270620183525 - 10 -3433.144366980718 - 20 -1257.434620183525 - 10 -3432.944366980718 - 20 -1257.434620183525 - 10 -3432.944366980718 - 20 -1257.598620183524 - 10 -3432.744366980717 - 20 -1257.598620183524 - 10 -3432.744366980717 - 20 -1257.762620183524 - 10 -3432.54436698072 - 20 -1257.762620183524 - 10 -3432.54436698072 - 20 -1257.926620183524 - 10 -3432.344366980718 - 20 -1257.926620183524 - 10 -3432.344366980718 - 20 -1258.090620183524 - 10 -3432.344366980718 - 20 -1258.090620183524 - 10 -3432.344366980718 - 20 -1258.090620183524 - 10 -3431.59436698075 - 20 -1258.090620183524 - 0 -LWPOLYLINE - 5 -BD9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3432.344366980718 - 20 -1258.254620183524 - 10 -3432.344366980718 - 20 -1258.090620183524 - 0 -LWPOLYLINE - 5 -BDA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 40 - 70 - 0 - 43 -0 - 10 -3434.244366980717 - 20 -1259.622620183586 - 10 -3434.244366980717 - 20 -1259.466620183524 - 10 -3434.044366980717 - 20 -1259.466620183524 - 10 -3434.044366980717 - 20 -1259.302620183524 - 10 -3433.844366980717 - 20 -1259.302620183524 - 10 -3433.844366980717 - 20 -1259.138620183525 - 10 -3433.644366980717 - 20 -1259.138620183525 - 10 -3433.644366980717 - 20 -1258.974620183525 - 10 -3433.444366980717 - 20 -1258.974620183525 - 10 -3433.444366980717 - 20 -1258.810620183524 - 10 -3433.244366980718 - 20 -1258.810620183524 - 10 -3433.244366980718 - 20 -1258.646620183524 - 10 -3433.044366980718 - 20 -1258.646620183524 - 10 -3433.044366980718 - 20 -1258.482620183525 - 10 -3432.844366980718 - 20 -1258.482620183525 - 10 -3432.844366980718 - 20 -1258.318620183525 - 10 -3432.644366980718 - 20 -1258.318620183525 - 10 -3432.644366980718 - 20 -1258.154620183524 - 10 -3432.444366980718 - 20 -1258.154620183524 - 10 -3432.444366980718 - 20 -1257.990620183524 - 10 -3432.344366980718 - 20 -1257.990620183524 - 10 -3432.344366980718 - 20 -1258.254620183524 - 10 -3432.54436698072 - 20 -1258.254620183524 - 10 -3432.54436698072 - 20 -1258.418620183525 - 10 -3432.744366980717 - 20 -1258.418620183525 - 10 -3432.744366980717 - 20 -1258.582620183524 - 10 -3432.944366980718 - 20 -1258.582620183524 - 10 -3432.944366980718 - 20 -1258.746620183524 - 10 -3433.144366980718 - 20 -1258.746620183524 - 10 -3433.144366980718 - 20 -1258.910620183524 - 10 -3433.344366980718 - 20 -1258.910620183524 - 10 -3433.344366980718 - 20 -1259.074620183524 - 10 -3433.544366980718 - 20 -1259.074620183524 - 10 -3433.544366980718 - 20 -1259.238620183524 - 10 -3433.744366980717 - 20 -1259.238620183524 - 10 -3433.744366980717 - 20 -1259.402620183524 - 10 -3433.944366980717 - 20 -1259.402620183524 - 10 -3433.944366980717 - 20 -1259.566620183524 - 10 -3434.144366980717 - 20 -1259.566620183524 - 10 -3434.144366980717 - 20 -1259.722620183621 - 0 -HATCH - 5 -BDB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 47 - 72 - 1 - 10 -3432.54436698072 - 20 -1257.926620183524 - 11 -3432.344366980718 - 21 -1257.926620183524 - 72 - 1 - 10 -3432.344366980718 - 20 -1257.926620183524 - 11 -3432.344366980718 - 21 -1258.090620183524 - 72 - 1 - 10 -3432.344366980718 - 20 -1258.090620183524 - 11 -3431.59436698075 - 21 -1258.090620183524 - 72 - 1 - 10 -3431.59436698075 - 20 -1258.090620183524 - 11 -3431.59436698075 - 21 -1257.990620183524 - 72 - 1 - 10 -3431.59436698075 - 20 -1257.990620183524 - 11 -3432.144366980719 - 21 -1257.990620183524 - 72 - 1 - 10 -3432.144366980719 - 20 -1257.990620183524 - 11 -3432.244366980718 - 21 -1257.990620183524 - 72 - 1 - 10 -3432.244366980718 - 20 -1257.990620183524 - 11 -3432.244366980718 - 21 -1257.826620183525 - 72 - 1 - 10 -3432.244366980718 - 20 -1257.826620183525 - 11 -3432.444366980718 - 21 -1257.826620183525 - 72 - 1 - 10 -3432.444366980718 - 20 -1257.826620183525 - 11 -3432.444366980718 - 21 -1257.662620183525 - 72 - 1 - 10 -3432.444366980718 - 20 -1257.662620183525 - 11 -3432.644366980718 - 21 -1257.662620183525 - 72 - 1 - 10 -3432.644366980718 - 20 -1257.662620183525 - 11 -3432.644366980718 - 21 -1257.498620183525 - 72 - 1 - 10 -3432.644366980718 - 20 -1257.498620183525 - 11 -3432.844366980718 - 21 -1257.498620183525 - 72 - 1 - 10 -3432.844366980718 - 20 -1257.498620183525 - 11 -3432.844366980718 - 21 -1257.334620183525 - 72 - 1 - 10 -3432.844366980718 - 20 -1257.334620183525 - 11 -3433.044366980718 - 21 -1257.334620183525 - 72 - 1 - 10 -3433.044366980718 - 20 -1257.334620183525 - 11 -3433.044366980718 - 21 -1257.170620183525 - 72 - 1 - 10 -3433.044366980718 - 20 -1257.170620183525 - 11 -3433.244366980718 - 21 -1257.170620183525 - 72 - 1 - 10 -3433.244366980718 - 20 -1257.170620183525 - 11 -3433.244366980718 - 21 -1257.006620183525 - 72 - 1 - 10 -3433.244366980718 - 20 -1257.006620183525 - 11 -3433.444366980717 - 21 -1257.006620183525 - 72 - 1 - 10 -3433.444366980717 - 20 -1257.006620183525 - 11 -3433.444366980717 - 21 -1256.842620183524 - 72 - 1 - 10 -3433.444366980717 - 20 -1256.842620183524 - 11 -3433.644366980717 - 21 -1256.842620183524 - 72 - 1 - 10 -3433.644366980717 - 20 -1256.842620183524 - 11 -3433.644366980717 - 21 -1256.678620183525 - 72 - 1 - 10 -3433.644366980717 - 20 -1256.678620183525 - 11 -3433.844366980717 - 21 -1256.678620183525 - 72 - 1 - 10 -3433.844366980717 - 20 -1256.678620183525 - 11 -3433.844366980717 - 21 -1256.514620183525 - 72 - 1 - 10 -3433.844366980717 - 20 -1256.514620183525 - 11 -3434.044366980717 - 21 -1256.514620183525 - 72 - 1 - 10 -3434.044366980717 - 20 -1256.514620183525 - 11 -3434.044366980717 - 21 -1256.350620183525 - 72 - 1 - 10 -3434.044366980717 - 20 -1256.350620183525 - 11 -3434.244366980717 - 21 -1256.350620183525 - 72 - 1 - 10 -3434.244366980717 - 20 -1256.350620183525 - 11 -3434.244366980717 - 21 -1256.186620183525 - 72 - 1 - 10 -3434.244366980717 - 20 -1256.186620183525 - 11 -3434.344366980717 - 21 -1256.186620183525 - 72 - 1 - 10 -3434.344366980717 - 20 -1256.186620183525 - 11 -3434.344366980717 - 21 -1256.450620183525 - 72 - 1 - 10 -3434.344366980717 - 20 -1256.450620183525 - 11 -3434.144366980717 - 21 -1256.450620183525 - 72 - 1 - 10 -3434.144366980717 - 20 -1256.450620183525 - 11 -3434.144366980717 - 21 -1256.614620183525 - 72 - 1 - 10 -3434.144366980717 - 20 -1256.614620183525 - 11 -3433.944366980717 - 21 -1256.614620183525 - 72 - 1 - 10 -3433.944366980717 - 20 -1256.614620183525 - 11 -3433.944366980717 - 21 -1256.778620183524 - 72 - 1 - 10 -3433.944366980717 - 20 -1256.778620183524 - 11 -3433.744366980717 - 21 -1256.778620183524 - 72 - 1 - 10 -3433.744366980717 - 20 -1256.778620183524 - 11 -3433.744366980717 - 21 -1256.942620183524 - 72 - 1 - 10 -3433.744366980717 - 20 -1256.942620183524 - 11 -3433.544366980718 - 21 -1256.942620183524 - 72 - 1 - 10 -3433.544366980718 - 20 -1256.942620183524 - 11 -3433.544366980718 - 21 -1257.106620183525 - 72 - 1 - 10 -3433.544366980718 - 20 -1257.106620183525 - 11 -3433.344366980718 - 21 -1257.106620183525 - 72 - 1 - 10 -3433.344366980718 - 20 -1257.106620183525 - 11 -3433.344366980718 - 21 -1257.270620183525 - 72 - 1 - 10 -3433.344366980718 - 20 -1257.270620183525 - 11 -3433.144366980718 - 21 -1257.270620183525 - 72 - 1 - 10 -3433.144366980718 - 20 -1257.270620183525 - 11 -3433.144366980718 - 21 -1257.434620183525 - 72 - 1 - 10 -3433.144366980718 - 20 -1257.434620183525 - 11 -3432.944366980718 - 21 -1257.434620183525 - 72 - 1 - 10 -3432.944366980718 - 20 -1257.434620183525 - 11 -3432.944366980718 - 21 -1257.598620183524 - 72 - 1 - 10 -3432.944366980718 - 20 -1257.598620183524 - 11 -3432.744366980717 - 21 -1257.598620183524 - 72 - 1 - 10 -3432.744366980717 - 20 -1257.598620183524 - 11 -3432.744366980717 - 21 -1257.762620183524 - 72 - 1 - 10 -3432.744366980717 - 20 -1257.762620183524 - 11 -3432.54436698072 - 21 -1257.762620183524 - 72 - 1 - 10 -3432.54436698072 - 20 -1257.762620183524 - 11 -3432.54436698072 - 21 -1257.926620183524 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -BDC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3430.764366980643 - 20 -1258.371631514688 - 10 -3431.364366980768 - 20 -1258.371631514688 - 10 -3431.364366980768 - 20 -1258.27323848752 - 10 -3430.764366980643 - 20 -1258.27323848752 - 0 -LWPOLYLINE - 5 -BDD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3434.144366980717 - 20 -1255.966620183463 - 10 -3434.144366980717 - 20 -1256.130620183463 - 10 -3434.344366980717 - 20 -1256.130620183463 - 10 -3434.344366980751 - 20 -1256.186620183525 - 0 -LWPOLYLINE - 5 -BDE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3434.244366980717 - 20 -1255.966620183463 - 10 -3434.244366980717 - 20 -1256.030620183463 - 10 -3434.444366980657 - 20 -1256.030620183463 - 10 -3434.444366980751 - 20 -1256.186620183465 - 0 -LWPOLYLINE - 5 -BDF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3434.144366980717 - 20 -1259.566620183524 - 10 -3434.144366980717 - 20 -1259.730620183524 - 10 -3434.344366980717 - 20 -1259.730620183524 - 10 -3434.344366980751 - 20 -1259.884787151034 - 0 -LWPOLYLINE - 5 -BE0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3434.244366980717 - 20 -1259.566620183524 - 10 -3434.244366980717 - 20 -1259.630620183524 - 10 -3434.444366980694 - 20 -1259.630620183524 - 10 -3434.444366980751 - 20 -1259.884787151012 - 0 -MTEXT - 5 -BE1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3431.682673379422 - 20 -1255.238385335864 - 30 -0 - 40 -0.1 - 41 -0.6777777777777824 - 71 - 1 - 72 - 5 - 1 -rise=0.164\Ptread=0.20 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883538 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -BE2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3431.682673379422 - 20 -1258.786671845358 - 30 -0 - 40 -0.1 - 41 -0.6777777777777824 - 71 - 1 - 72 - 5 - 1 -rise=0.164\Ptread=0.20 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883538 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -BE3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3447.212417758449 - 20 -1247.926913006706 - 30 -0 - 40 -0.1 - 41 -0.6000000000000109 - 71 - 1 - 72 - 5 - 1 -rise=0.15\Ptread=0.3 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -BE4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 19 - 70 - 0 - 43 -0 - 10 -3444.692101166711 - 20 -1245.78662018356 - 10 -3444.692101166711 - 20 -1245.93662018356 - 10 -3444.992101166711 - 20 -1245.93662018356 - 10 -3444.992101166711 - 20 -1246.08662018356 - 10 -3445.292101166711 - 20 -1246.08662018356 - 10 -3445.292101166711 - 20 -1246.23662018356 - 10 -3445.592101166711 - 20 -1246.23662018356 - 10 -3445.592101166711 - 20 -1246.38662018356 - 10 -3445.892101166712 - 20 -1246.38662018356 - 10 -3445.892101166712 - 20 -1246.53662018356 - 10 -3446.192101166712 - 20 -1246.53662018356 - 10 -3446.192101166712 - 20 -1246.68662018356 - 10 -3446.492101166712 - 20 -1246.68662018356 - 10 -3446.492101166712 - 20 -1246.836620183561 - 10 -3446.792101166713 - 20 -1246.836620183561 - 10 -3446.792101166713 - 20 -1246.986620183561 - 10 -3447.092101166712 - 20 -1246.986620183561 - 10 -3447.092101166712 - 20 -1247.13662018356 - 10 -3448.29210116671 - 20 -1247.13662018356 - 0 -LWPOLYLINE - 5 -BE5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 19 - 70 - 0 - 43 -0 - 10 -3444.792101166711 - 20 -1245.78662018356 - 10 -3444.792101166711 - 20 -1245.83662018356 - 10 -3445.092101166711 - 20 -1245.83662018356 - 10 -3445.092101166711 - 20 -1245.98662018356 - 10 -3445.392101166711 - 20 -1245.98662018356 - 10 -3445.392101166711 - 20 -1246.13662018356 - 10 -3445.692101166712 - 20 -1246.13662018356 - 10 -3445.692101166712 - 20 -1246.28662018356 - 10 -3445.992101166711 - 20 -1246.28662018356 - 10 -3445.992101166711 - 20 -1246.43662018356 - 10 -3446.292101166712 - 20 -1246.43662018356 - 10 -3446.292101166712 - 20 -1246.58662018356 - 10 -3446.592101166711 - 20 -1246.58662018356 - 10 -3446.592101166711 - 20 -1246.736620183561 - 10 -3446.892101166712 - 20 -1246.736620183561 - 10 -3446.892101166712 - 20 -1246.886620183561 - 10 -3447.192101166712 - 20 -1246.886620183561 - 10 -3447.192101166712 - 20 -1247.036620183561 - 10 -3448.29210116671 - 20 -1247.036620183561 - 0 -LINE - 5 -BE6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166712 - 20 -1247.13662018356 - 11 -3448.29210116671 - 21 -1247.13662018356 - 0 -LINE - 5 -BE7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166712 - 20 -1247.286620183561 - 11 -3448.29210116671 - 21 -1247.286620183561 - 0 -LINE - 5 -BE8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166712 - 20 -1247.436620183561 - 11 -3448.29210116671 - 21 -1247.436620183561 - 0 -LINE - 5 -BE9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166712 - 20 -1247.586620183561 - 11 -3448.29210116671 - 21 -1247.586620183561 - 0 -LWPOLYLINE - 5 -BEA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 15 - 70 - 0 - 43 -0 - 10 -3447.092101166711 - 20 -1247.586620183561 - 10 -3447.092101166711 - 20 -1247.736620183561 - 10 -3446.79210116671 - 20 -1247.736620183561 - 10 -3446.79210116671 - 20 -1247.886620183561 - 10 -3446.49210116671 - 20 -1247.886620183561 - 10 -3446.49210116671 - 20 -1248.036620183561 - 10 -3446.19210116671 - 20 -1248.036620183561 - 10 -3446.19210116671 - 20 -1248.186620183561 - 10 -3445.89210116671 - 20 -1248.186620183561 - 10 -3445.89210116671 - 20 -1248.336620183561 - 10 -3445.59210116671 - 20 -1248.336620183561 - 10 -3445.59210116671 - 20 -1248.486620183562 - 10 -3445.292101166709 - 20 -1248.486620183562 - 10 -3445.292101166709 - 20 -1248.636620183561 - 10 -3444.99210116671 - 20 -1248.636620183561 - 0 -LWPOLYLINE - 5 -BEB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 16 - 70 - 0 - 43 -0 - 10 -3446.99210116671 - 20 -1247.586620183561 - 10 -3446.99210116671 - 20 -1247.636620183561 - 10 -3446.692101166711 - 20 -1247.636620183561 - 10 -3446.692101166711 - 20 -1247.786620183561 - 10 -3446.39210116671 - 20 -1247.786620183561 - 10 -3446.39210116671 - 20 -1247.936620183561 - 10 -3446.092101166711 - 20 -1247.936620183561 - 10 -3446.092101166711 - 20 -1248.086620183561 - 10 -3445.79210116671 - 20 -1248.086620183561 - 10 -3445.79210116671 - 20 -1248.236620183561 - 10 -3445.49210116671 - 20 -1248.236620183561 - 10 -3445.49210116671 - 20 -1248.386620183562 - 10 -3445.192101166711 - 20 -1248.386620183562 - 10 -3445.192101166711 - 20 -1248.536620183562 - 10 -3444.89210116671 - 20 -1248.536620183562 - 10 -3444.89210116671 - 20 -1248.536620183562 - 0 -LWPOLYLINE - 5 -BEC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3447.092101166756 - 20 -1247.586620183561 - 10 -3447.092101166756 - 20 -1247.486620183561 - 10 -3446.99210116671 - 20 -1247.486620183559 - 10 -3446.99210116671 - 20 -1247.586620183561 - 0 -LWPOLYLINE - 5 -BED -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 35 - 70 - 0 - 43 -0 - 10 -3442.892101166711 - 20 -1248.636620183537 - 10 -3442.892101166711 - 20 -1248.786620183537 - 10 -3443.192101166711 - 20 -1248.786620183537 - 10 -3443.192101166711 - 20 -1248.936620183537 - 10 -3443.492101166711 - 20 -1248.936620183537 - 10 -3443.492101166711 - 20 -1249.086620183537 - 10 -3443.792101166711 - 20 -1249.086620183537 - 10 -3443.792101166711 - 20 -1249.236620183537 - 10 -3444.092101166711 - 20 -1249.236620183537 - 10 -3444.092101166711 - 20 -1249.386620183537 - 10 -3444.392101166712 - 20 -1249.386620183537 - 10 -3444.392101166712 - 20 -1249.536620183537 - 10 -3444.692101166712 - 20 -1249.536620183537 - 10 -3444.692101166712 - 20 -1249.686620183537 - 10 -3444.992101166711 - 20 -1249.686620183537 - 10 -3444.992101166711 - 20 -1249.836620183538 - 10 -3445.292101166713 - 20 -1249.836620183538 - 10 -3445.292101166713 - 20 -1249.986620183521 - 10 -3445.592101166712 - 20 -1249.986620183521 - 10 -3445.592101166712 - 20 -1250.136620183522 - 10 -3445.892101166712 - 20 -1250.136620183522 - 10 -3445.892101166712 - 20 -1250.286620183522 - 10 -3446.192101166712 - 20 -1250.286620183522 - 10 -3446.192101166712 - 20 -1250.436620183522 - 10 -3446.492101166712 - 20 -1250.436620183522 - 10 -3446.492101166712 - 20 -1250.586620183522 - 10 -3446.792101166713 - 20 -1250.586620183522 - 10 -3446.792101166713 - 20 -1250.736620183522 - 10 -3447.092101166714 - 20 -1250.736620183522 - 10 -3447.092101166714 - 20 -1250.886620183522 - 10 -3448.29210116671 - 20 -1250.886620183522 - 10 -3448.29210116671 - 20 -1250.886620183522 - 10 -3448.29210116671 - 20 -1250.886620183522 - 10 -3448.29210116671 - 20 -1250.886620183522 - 10 -3448.29210116671 - 20 -1250.886620183522 - 0 -LINE - 5 -BEE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166711 - 20 -1250.886620183522 - 11 -3448.29210116671 - 21 -1250.886620183522 - 0 -LINE - 5 -BEF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166711 - 20 -1251.036620183522 - 11 -3448.29210116671 - 21 -1251.036620183522 - 0 -LINE - 5 -BF0 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166711 - 20 -1251.186620183522 - 11 -3448.29210116671 - 21 -1251.186620183522 - 0 -LINE - 5 -BF1 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166711 - 20 -1251.336620183522 - 11 -3448.29210116671 - 21 -1251.336620183522 - 0 -LWPOLYLINE - 5 -BF2 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 31 - 70 - 0 - 43 -0 - 10 -3442.992101166711 - 20 -1248.636620183537 - 10 -3442.992101166711 - 20 -1248.686620183537 - 10 -3443.292101166711 - 20 -1248.686620183537 - 10 -3443.292101166711 - 20 -1248.836620183537 - 10 -3443.592101166711 - 20 -1248.836620183537 - 10 -3443.592101166711 - 20 -1248.986620183537 - 10 -3443.89210116671 - 20 -1248.986620183537 - 10 -3443.89210116671 - 20 -1249.136620183537 - 10 -3444.192101166712 - 20 -1249.136620183537 - 10 -3444.192101166712 - 20 -1249.286620183537 - 10 -3444.492101166711 - 20 -1249.286620183537 - 10 -3444.492101166711 - 20 -1249.436620183537 - 10 -3444.792101166711 - 20 -1249.436620183537 - 10 -3444.792101166711 - 20 -1249.586620183537 - 10 -3445.092101166711 - 20 -1249.586620183537 - 10 -3445.092101166711 - 20 -1249.736620183538 - 10 -3445.392101166712 - 20 -1249.736620183538 - 10 -3445.392101166712 - 20 -1249.886620183521 - 10 -3445.692101166712 - 20 -1249.886620183521 - 10 -3445.692101166712 - 20 -1250.036620183522 - 10 -3445.992101166712 - 20 -1250.036620183522 - 10 -3445.992101166712 - 20 -1250.186620183522 - 10 -3446.292101166712 - 20 -1250.186620183522 - 10 -3446.292101166712 - 20 -1250.336620183522 - 10 -3446.592101166713 - 20 -1250.336620183522 - 10 -3446.592101166713 - 20 -1250.486620183522 - 10 -3446.892101166714 - 20 -1250.486620183522 - 10 -3446.892101166714 - 20 -1250.636620183522 - 10 -3447.192101166713 - 20 -1250.636620183522 - 10 -3447.192101166713 - 20 -1250.786620183522 - 10 -3448.29210116671 - 20 -1250.786620183522 - 0 -LWPOLYLINE - 5 -BF3 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 19 - 70 - 0 - 43 -0 - 10 -3447.092101166711 - 20 -1251.336620183522 - 10 -3447.092101166711 - 20 -1251.486620183522 - 10 -3446.79210116671 - 20 -1251.486620183522 - 10 -3446.79210116671 - 20 -1251.636620183522 - 10 -3446.49210116671 - 20 -1251.636620183522 - 10 -3446.49210116671 - 20 -1251.786620183523 - 10 -3446.19210116671 - 20 -1251.786620183523 - 10 -3446.19210116671 - 20 -1251.936620183523 - 10 -3445.89210116671 - 20 -1251.936620183523 - 10 -3445.89210116671 - 20 -1252.086620183523 - 10 -3445.59210116671 - 20 -1252.086620183523 - 10 -3445.59210116671 - 20 -1252.236620183523 - 10 -3445.292101166709 - 20 -1252.236620183523 - 10 -3445.292101166709 - 20 -1252.386620183523 - 10 -3444.99210116671 - 20 -1252.386620183523 - 10 -3444.99210116671 - 20 -1252.536620183523 - 10 -3444.692101166709 - 20 -1252.536620183523 - 10 -3444.692101166709 - 20 -1252.686620183507 - 10 -3444.392101166709 - 20 -1252.686620183507 - 0 -LWPOLYLINE - 5 -BF4 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 20 - 70 - 0 - 43 -0 - 10 -3446.99210116671 - 20 -1251.336620183522 - 10 -3446.99210116671 - 20 -1251.386620183522 - 10 -3446.692101166711 - 20 -1251.386620183522 - 10 -3446.692101166711 - 20 -1251.536620183523 - 10 -3446.39210116671 - 20 -1251.536620183523 - 10 -3446.39210116671 - 20 -1251.686620183523 - 10 -3446.092101166711 - 20 -1251.686620183523 - 10 -3446.092101166711 - 20 -1251.836620183523 - 10 -3445.79210116671 - 20 -1251.836620183523 - 10 -3445.79210116671 - 20 -1251.986620183523 - 10 -3445.49210116671 - 20 -1251.986620183523 - 10 -3445.49210116671 - 20 -1252.136620183523 - 10 -3445.192101166711 - 20 -1252.136620183523 - 10 -3445.192101166711 - 20 -1252.286620183523 - 10 -3444.89210116671 - 20 -1252.286620183523 - 10 -3444.89210116671 - 20 -1252.436620183523 - 10 -3444.592101166711 - 20 -1252.436620183523 - 10 -3444.592101166711 - 20 -1252.586620183507 - 10 -3444.292101166709 - 20 -1252.586620183507 - 10 -3444.292101166709 - 20 -1252.586620183549 - 0 -LWPOLYLINE - 5 -BF5 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3447.092101166756 - 20 -1251.336620183522 - 10 -3447.092101166756 - 20 -1251.236620183522 - 10 -3446.99210116671 - 20 -1251.23662018352 - 10 -3446.99210116671 - 20 -1251.336620183522 - 0 -LWPOLYLINE - 5 -BF6 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 30 - 70 - 0 - 43 -0 - 10 -3443.792101166711 - 20 -1252.686620183463 - 10 -3443.792101166711 - 20 -1252.686620183463 - 10 -3443.792101166711 - 20 -1252.836620183464 - 10 -3444.092101166711 - 20 -1252.836620183464 - 10 -3444.092101166711 - 20 -1252.986620183464 - 10 -3444.392101166711 - 20 -1252.986620183464 - 10 -3444.392101166711 - 20 -1253.136620183464 - 10 -3444.692101166711 - 20 -1253.136620183464 - 10 -3444.692101166711 - 20 -1253.286620183464 - 10 -3444.992101166711 - 20 -1253.286620183464 - 10 -3444.992101166711 - 20 -1253.436620183464 - 10 -3445.292101166713 - 20 -1253.436620183464 - 10 -3445.292101166713 - 20 -1253.586620183448 - 10 -3445.592101166712 - 20 -1253.586620183448 - 10 -3445.592101166712 - 20 -1253.736620183448 - 10 -3445.892101166712 - 20 -1253.736620183448 - 10 -3445.892101166712 - 20 -1253.886620183448 - 10 -3446.192101166712 - 20 -1253.886620183448 - 10 -3446.192101166712 - 20 -1254.036620183448 - 10 -3446.492101166712 - 20 -1254.036620183448 - 10 -3446.492101166712 - 20 -1254.186620183448 - 10 -3446.792101166713 - 20 -1254.186620183448 - 10 -3446.792101166713 - 20 -1254.336620183448 - 10 -3447.092101166712 - 20 -1254.336620183448 - 10 -3447.092101166712 - 20 -1254.486620183448 - 10 -3448.29210116671 - 20 -1254.486620183448 - 10 -3448.29210116671 - 20 -1254.486620183448 - 10 -3448.29210116671 - 20 -1254.486620183448 - 10 -3448.29210116671 - 20 -1254.486620183448 - 10 -3448.29210116671 - 20 -1254.486620183448 - 0 -LWPOLYLINE - 5 -BF7 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 25 - 70 - 0 - 43 -0 - 10 -3443.89210116671 - 20 -1252.686620183463 - 10 -3443.89210116671 - 20 -1252.736620183464 - 10 -3444.192101166712 - 20 -1252.736620183464 - 10 -3444.192101166712 - 20 -1252.886620183464 - 10 -3444.492101166711 - 20 -1252.886620183464 - 10 -3444.492101166711 - 20 -1253.036620183464 - 10 -3444.792101166711 - 20 -1253.036620183464 - 10 -3444.792101166711 - 20 -1253.186620183464 - 10 -3445.092101166711 - 20 -1253.186620183464 - 10 -3445.092101166711 - 20 -1253.336620183464 - 10 -3445.392101166711 - 20 -1253.336620183464 - 10 -3445.392101166711 - 20 -1253.486620183448 - 10 -3445.692101166712 - 20 -1253.486620183448 - 10 -3445.692101166712 - 20 -1253.636620183448 - 10 -3445.992101166711 - 20 -1253.636620183448 - 10 -3445.992101166711 - 20 -1253.786620183448 - 10 -3446.292101166712 - 20 -1253.786620183448 - 10 -3446.292101166712 - 20 -1253.936620183448 - 10 -3446.592101166712 - 20 -1253.936620183448 - 10 -3446.592101166712 - 20 -1254.086620183448 - 10 -3446.892101166712 - 20 -1254.086620183448 - 10 -3446.892101166712 - 20 -1254.236620183448 - 10 -3447.192101166712 - 20 -1254.236620183448 - 10 -3447.192101166712 - 20 -1254.386620183449 - 10 -3448.29210116671 - 20 -1254.386620183449 - 0 -LINE - 5 -BF8 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166711 - 20 -1254.486620183448 - 11 -3448.29210116671 - 21 -1254.486620183448 - 0 -LINE - 5 -BF9 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166711 - 20 -1254.636620183449 - 11 -3448.29210116671 - 21 -1254.636620183449 - 0 -LINE - 5 -BFA -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166711 - 20 -1254.786620183448 - 11 -3448.29210116671 - 21 -1254.786620183448 - 0 -LINE - 5 -BFB -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3447.092101166711 - 20 -1254.936620183449 - 11 -3448.29210116671 - 21 -1254.936620183449 - 0 -LWPOLYLINE - 5 -BFC -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 19 - 70 - 0 - 43 -0 - 10 -3447.092101166711 - 20 -1254.936620183449 - 10 -3447.092101166711 - 20 -1255.086620183449 - 10 -3446.79210116671 - 20 -1255.086620183449 - 10 -3446.79210116671 - 20 -1255.236620183449 - 10 -3446.49210116671 - 20 -1255.236620183449 - 10 -3446.49210116671 - 20 -1255.386620183449 - 10 -3446.19210116671 - 20 -1255.386620183449 - 10 -3446.19210116671 - 20 -1255.536620183449 - 10 -3445.89210116671 - 20 -1255.536620183449 - 10 -3445.89210116671 - 20 -1255.686620183449 - 10 -3445.59210116671 - 20 -1255.686620183449 - 10 -3445.59210116671 - 20 -1255.836620183449 - 10 -3445.292101166709 - 20 -1255.836620183449 - 10 -3445.292101166709 - 20 -1255.986620183449 - 10 -3444.99210116671 - 20 -1255.986620183449 - 10 -3444.99210116671 - 20 -1256.13662018345 - 10 -3444.692101166709 - 20 -1256.13662018345 - 10 -3444.692101166709 - 20 -1256.286620183433 - 10 -3444.392101166709 - 20 -1256.286620183433 - 0 -LWPOLYLINE - 5 -BFD -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 20 - 70 - 0 - 43 -0 - 10 -3446.99210116671 - 20 -1254.936620183449 - 10 -3446.99210116671 - 20 -1254.986620183449 - 10 -3446.692101166711 - 20 -1254.986620183449 - 10 -3446.692101166711 - 20 -1255.136620183449 - 10 -3446.39210116671 - 20 -1255.136620183449 - 10 -3446.39210116671 - 20 -1255.286620183449 - 10 -3446.092101166711 - 20 -1255.286620183449 - 10 -3446.092101166711 - 20 -1255.436620183449 - 10 -3445.79210116671 - 20 -1255.436620183449 - 10 -3445.79210116671 - 20 -1255.586620183449 - 10 -3445.49210116671 - 20 -1255.586620183449 - 10 -3445.49210116671 - 20 -1255.736620183449 - 10 -3445.192101166711 - 20 -1255.736620183449 - 10 -3445.192101166711 - 20 -1255.886620183449 - 10 -3444.89210116671 - 20 -1255.886620183449 - 10 -3444.89210116671 - 20 -1256.03662018345 - 10 -3444.592101166711 - 20 -1256.03662018345 - 10 -3444.592101166711 - 20 -1256.186620183522 - 10 -3444.292101166709 - 20 -1256.186620183433 - 10 -3444.292101166709 - 20 -1256.28662018339 - 0 -LWPOLYLINE - 5 -BFE -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3447.092101166756 - 20 -1254.936620183449 - 10 -3447.092101166756 - 20 -1254.836620183449 - 10 -3446.99210116671 - 20 -1254.836620183447 - 10 -3446.99210116671 - 20 -1254.936620183449 - 0 -HATCH - 5 -BFF -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 38 - 72 - 1 - 10 -3446.892101166712 - 20 -1246.886620183561 - 11 -3447.192101166712 - 21 -1246.886620183561 - 72 - 1 - 10 -3447.192101166712 - 20 -1246.886620183561 - 11 -3447.192101166712 - 21 -1247.036620183561 - 72 - 1 - 10 -3447.192101166712 - 20 -1247.036620183561 - 11 -3448.29210116671 - 21 -1247.036620183561 - 72 - 1 - 10 -3448.29210116671 - 20 -1247.036620183561 - 11 -3448.29210116671 - 21 -1247.13662018356 - 72 - 1 - 10 -3448.29210116671 - 20 -1247.13662018356 - 11 -3447.092101166712 - 21 -1247.13662018356 - 72 - 1 - 10 -3447.092101166712 - 20 -1247.13662018356 - 11 -3447.092101166712 - 21 -1246.986620183561 - 72 - 1 - 10 -3447.092101166712 - 20 -1246.986620183561 - 11 -3446.792101166713 - 21 -1246.986620183561 - 72 - 1 - 10 -3446.792101166713 - 20 -1246.986620183561 - 11 -3446.792101166713 - 21 -1246.836620183561 - 72 - 1 - 10 -3446.792101166713 - 20 -1246.836620183561 - 11 -3446.492101166712 - 21 -1246.836620183561 - 72 - 1 - 10 -3446.492101166712 - 20 -1246.836620183561 - 11 -3446.492101166712 - 21 -1246.68662018356 - 72 - 1 - 10 -3446.492101166712 - 20 -1246.68662018356 - 11 -3446.192101166712 - 21 -1246.68662018356 - 72 - 1 - 10 -3446.192101166712 - 20 -1246.68662018356 - 11 -3446.192101166712 - 21 -1246.53662018356 - 72 - 1 - 10 -3446.192101166712 - 20 -1246.53662018356 - 11 -3445.892101166712 - 21 -1246.53662018356 - 72 - 1 - 10 -3445.892101166712 - 20 -1246.53662018356 - 11 -3445.892101166712 - 21 -1246.38662018356 - 72 - 1 - 10 -3445.892101166712 - 20 -1246.38662018356 - 11 -3445.592101166711 - 21 -1246.38662018356 - 72 - 1 - 10 -3445.592101166711 - 20 -1246.38662018356 - 11 -3445.592101166711 - 21 -1246.23662018356 - 72 - 1 - 10 -3445.592101166711 - 20 -1246.23662018356 - 11 -3445.292101166711 - 21 -1246.23662018356 - 72 - 1 - 10 -3445.292101166711 - 20 -1246.23662018356 - 11 -3445.292101166711 - 21 -1246.08662018356 - 72 - 1 - 10 -3445.292101166711 - 20 -1246.08662018356 - 11 -3444.992101166711 - 21 -1246.08662018356 - 72 - 1 - 10 -3444.992101166711 - 20 -1246.08662018356 - 11 -3444.992101166711 - 21 -1245.93662018356 - 72 - 1 - 10 -3444.992101166711 - 20 -1245.93662018356 - 11 -3444.784366980695 - 21 -1245.93662018356 - 72 - 1 - 10 -3444.784366980695 - 20 -1245.93662018356 - 11 -3444.784366980695 - 21 -1245.78662018356 - 72 - 1 - 10 -3444.784366980695 - 20 -1245.78662018356 - 11 -3444.792101166711 - 21 -1245.78662018356 - 72 - 1 - 10 -3444.792101166711 - 20 -1245.78662018356 - 11 -3444.792101166711 - 21 -1245.83662018356 - 72 - 1 - 10 -3444.792101166711 - 20 -1245.83662018356 - 11 -3445.092101166711 - 21 -1245.83662018356 - 72 - 1 - 10 -3445.092101166711 - 20 -1245.83662018356 - 11 -3445.092101166711 - 21 -1245.98662018356 - 72 - 1 - 10 -3445.092101166711 - 20 -1245.98662018356 - 11 -3445.392101166711 - 21 -1245.98662018356 - 72 - 1 - 10 -3445.392101166711 - 20 -1245.98662018356 - 11 -3445.392101166711 - 21 -1246.13662018356 - 72 - 1 - 10 -3445.392101166711 - 20 -1246.13662018356 - 11 -3445.692101166712 - 21 -1246.13662018356 - 72 - 1 - 10 -3445.692101166712 - 20 -1246.13662018356 - 11 -3445.692101166712 - 21 -1246.28662018356 - 72 - 1 - 10 -3445.692101166712 - 20 -1246.28662018356 - 11 -3445.992101166711 - 21 -1246.28662018356 - 72 - 1 - 10 -3445.992101166711 - 20 -1246.28662018356 - 11 -3445.992101166711 - 21 -1246.43662018356 - 72 - 1 - 10 -3445.992101166711 - 20 -1246.43662018356 - 11 -3446.292101166712 - 21 -1246.43662018356 - 72 - 1 - 10 -3446.292101166712 - 20 -1246.43662018356 - 11 -3446.292101166712 - 21 -1246.58662018356 - 72 - 1 - 10 -3446.292101166712 - 20 -1246.58662018356 - 11 -3446.592101166711 - 21 -1246.58662018356 - 72 - 1 - 10 -3446.592101166711 - 20 -1246.58662018356 - 11 -3446.592101166711 - 21 -1246.736620183561 - 72 - 1 - 10 -3446.592101166711 - 20 -1246.736620183561 - 11 -3446.892101166712 - 21 -1246.736620183561 - 72 - 1 - 10 -3446.892101166712 - 20 -1246.736620183561 - 11 -3446.892101166712 - 21 -1246.886620183561 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -C00 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 38 - 72 - 1 - 10 -3448.29210116671 - 20 -1254.486620183448 - 11 -3447.092101166712 - 21 -1254.486620183448 - 72 - 1 - 10 -3447.092101166712 - 20 -1254.486620183448 - 11 -3447.092101166712 - 21 -1254.336620183448 - 72 - 1 - 10 -3447.092101166712 - 20 -1254.336620183448 - 11 -3446.792101166713 - 21 -1254.336620183448 - 72 - 1 - 10 -3446.792101166713 - 20 -1254.336620183448 - 11 -3446.792101166713 - 21 -1254.186620183448 - 72 - 1 - 10 -3446.792101166713 - 20 -1254.186620183448 - 11 -3446.492101166712 - 21 -1254.186620183448 - 72 - 1 - 10 -3446.492101166712 - 20 -1254.186620183448 - 11 -3446.492101166712 - 21 -1254.036620183448 - 72 - 1 - 10 -3446.492101166712 - 20 -1254.036620183448 - 11 -3446.192101166712 - 21 -1254.036620183448 - 72 - 1 - 10 -3446.192101166712 - 20 -1254.036620183448 - 11 -3446.192101166712 - 21 -1253.886620183448 - 72 - 1 - 10 -3446.192101166712 - 20 -1253.886620183448 - 11 -3445.892101166712 - 21 -1253.886620183448 - 72 - 1 - 10 -3445.892101166712 - 20 -1253.886620183448 - 11 -3445.892101166712 - 21 -1253.736620183448 - 72 - 1 - 10 -3445.892101166712 - 20 -1253.736620183448 - 11 -3445.592101166712 - 21 -1253.736620183448 - 72 - 1 - 10 -3445.592101166712 - 20 -1253.736620183448 - 11 -3445.592101166712 - 21 -1253.586620183448 - 72 - 1 - 10 -3445.592101166712 - 20 -1253.586620183448 - 11 -3445.292101166713 - 21 -1253.586620183448 - 72 - 1 - 10 -3445.292101166713 - 20 -1253.586620183448 - 11 -3445.292101166713 - 21 -1253.436620183464 - 72 - 1 - 10 -3445.292101166713 - 20 -1253.436620183464 - 11 -3444.992101166711 - 21 -1253.436620183464 - 72 - 1 - 10 -3444.992101166711 - 20 -1253.436620183464 - 11 -3444.992101166711 - 21 -1253.286620183464 - 72 - 1 - 10 -3444.992101166711 - 20 -1253.286620183464 - 11 -3444.784366980695 - 21 -1253.286620183464 - 72 - 1 - 10 -3444.784366980695 - 20 -1253.286620183464 - 11 -3444.784366980695 - 21 -1253.036620183464 - 72 - 1 - 10 -3444.784366980695 - 20 -1253.036620183464 - 11 -3444.792101166711 - 21 -1253.036620183464 - 72 - 1 - 10 -3444.792101166711 - 20 -1253.036620183464 - 11 -3444.792101166711 - 21 -1253.186620183464 - 72 - 1 - 10 -3444.792101166711 - 20 -1253.186620183464 - 11 -3445.092101166711 - 21 -1253.186620183464 - 72 - 1 - 10 -3445.092101166711 - 20 -1253.186620183464 - 11 -3445.092101166711 - 21 -1253.336620183464 - 72 - 1 - 10 -3445.092101166711 - 20 -1253.336620183464 - 11 -3445.392101166711 - 21 -1253.336620183464 - 72 - 1 - 10 -3445.392101166711 - 20 -1253.336620183464 - 11 -3445.392101166711 - 21 -1253.486620183448 - 72 - 1 - 10 -3445.392101166711 - 20 -1253.486620183448 - 11 -3445.692101166712 - 21 -1253.486620183448 - 72 - 1 - 10 -3445.692101166712 - 20 -1253.486620183448 - 11 -3445.692101166712 - 21 -1253.636620183448 - 72 - 1 - 10 -3445.692101166712 - 20 -1253.636620183448 - 11 -3445.992101166711 - 21 -1253.636620183448 - 72 - 1 - 10 -3445.992101166711 - 20 -1253.636620183448 - 11 -3445.992101166711 - 21 -1253.786620183448 - 72 - 1 - 10 -3445.992101166711 - 20 -1253.786620183448 - 11 -3446.292101166712 - 21 -1253.786620183448 - 72 - 1 - 10 -3446.292101166712 - 20 -1253.786620183448 - 11 -3446.292101166712 - 21 -1253.936620183448 - 72 - 1 - 10 -3446.292101166712 - 20 -1253.936620183448 - 11 -3446.592101166712 - 21 -1253.936620183448 - 72 - 1 - 10 -3446.592101166712 - 20 -1253.936620183448 - 11 -3446.592101166712 - 21 -1254.086620183448 - 72 - 1 - 10 -3446.592101166712 - 20 -1254.086620183448 - 11 -3446.892101166712 - 21 -1254.086620183448 - 72 - 1 - 10 -3446.892101166712 - 20 -1254.086620183448 - 11 -3446.892101166712 - 21 -1254.236620183448 - 72 - 1 - 10 -3446.892101166712 - 20 -1254.236620183448 - 11 -3447.192101166712 - 21 -1254.236620183448 - 72 - 1 - 10 -3447.192101166712 - 20 -1254.236620183448 - 11 -3447.192101166712 - 21 -1254.386620183449 - 72 - 1 - 10 -3447.192101166712 - 20 -1254.386620183449 - 11 -3448.29210116671 - 21 -1254.386620183449 - 72 - 1 - 10 -3448.29210116671 - 20 -1254.386620183449 - 11 -3448.29210116671 - 21 -1254.486620183448 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -C01 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 62 - 72 - 1 - 10 -3448.29210116671 - 20 -1250.886620183522 - 11 -3447.092101166714 - 21 -1250.886620183522 - 72 - 1 - 10 -3447.092101166714 - 20 -1250.886620183522 - 11 -3447.092101166714 - 21 -1250.736620183522 - 72 - 1 - 10 -3447.092101166714 - 20 -1250.736620183522 - 11 -3446.792101166713 - 21 -1250.736620183522 - 72 - 1 - 10 -3446.792101166713 - 20 -1250.736620183522 - 11 -3446.792101166713 - 21 -1250.586620183522 - 72 - 1 - 10 -3446.792101166713 - 20 -1250.586620183522 - 11 -3446.492101166712 - 21 -1250.586620183522 - 72 - 1 - 10 -3446.492101166712 - 20 -1250.586620183522 - 11 -3446.492101166712 - 21 -1250.436620183522 - 72 - 1 - 10 -3446.492101166712 - 20 -1250.436620183522 - 11 -3446.192101166712 - 21 -1250.436620183522 - 72 - 1 - 10 -3446.192101166712 - 20 -1250.436620183522 - 11 -3446.192101166712 - 21 -1250.286620183522 - 72 - 1 - 10 -3446.192101166712 - 20 -1250.286620183522 - 11 -3445.892101166712 - 21 -1250.286620183522 - 72 - 1 - 10 -3445.892101166712 - 20 -1250.286620183522 - 11 -3445.892101166712 - 21 -1250.136620183522 - 72 - 1 - 10 -3445.892101166712 - 20 -1250.136620183522 - 11 -3445.592101166712 - 21 -1250.136620183522 - 72 - 1 - 10 -3445.592101166712 - 20 -1250.136620183522 - 11 -3445.592101166712 - 21 -1249.986620183521 - 72 - 1 - 10 -3445.592101166712 - 20 -1249.986620183521 - 11 -3445.292101166713 - 21 -1249.986620183521 - 72 - 1 - 10 -3445.292101166713 - 20 -1249.986620183521 - 11 -3445.292101166713 - 21 -1249.836620183538 - 72 - 1 - 10 -3445.292101166713 - 20 -1249.836620183538 - 11 -3444.992101166711 - 21 -1249.836620183538 - 72 - 1 - 10 -3444.992101166711 - 20 -1249.836620183538 - 11 -3444.992101166711 - 21 -1249.686620183537 - 72 - 1 - 10 -3444.992101166711 - 20 -1249.686620183537 - 11 -3444.692101166712 - 21 -1249.686620183537 - 72 - 1 - 10 -3444.692101166712 - 20 -1249.686620183537 - 11 -3444.692101166712 - 21 -1249.536620183537 - 72 - 1 - 10 -3444.692101166712 - 20 -1249.536620183537 - 11 -3444.392101166712 - 21 -1249.536620183537 - 72 - 1 - 10 -3444.392101166712 - 20 -1249.536620183537 - 11 -3444.392101166712 - 21 -1249.386620183537 - 72 - 1 - 10 -3444.392101166712 - 20 -1249.386620183537 - 11 -3444.092101166711 - 21 -1249.386620183537 - 72 - 1 - 10 -3444.092101166711 - 20 -1249.386620183537 - 11 -3444.092101166711 - 21 -1249.236620183537 - 72 - 1 - 10 -3444.092101166711 - 20 -1249.236620183537 - 11 -3443.792101166711 - 21 -1249.236620183537 - 72 - 1 - 10 -3443.792101166711 - 20 -1249.236620183537 - 11 -3443.792101166711 - 21 -1249.086620183537 - 72 - 1 - 10 -3443.792101166711 - 20 -1249.086620183537 - 11 -3443.492101166711 - 21 -1249.086620183537 - 72 - 1 - 10 -3443.492101166711 - 20 -1249.086620183537 - 11 -3443.492101166711 - 21 -1248.936620183537 - 72 - 1 - 10 -3443.492101166711 - 20 -1248.936620183537 - 11 -3443.192101166711 - 21 -1248.936620183537 - 72 - 1 - 10 -3443.192101166711 - 20 -1248.936620183537 - 11 -3443.192101166711 - 21 -1248.786620183537 - 72 - 1 - 10 -3443.192101166711 - 20 -1248.786620183537 - 11 -3442.892101166711 - 21 -1248.786620183537 - 72 - 1 - 10 -3442.892101166711 - 20 -1248.786620183537 - 11 -3442.892101166711 - 21 -1248.636620183537 - 72 - 1 - 10 -3442.892101166711 - 20 -1248.636620183537 - 11 -3442.992101166711 - 21 -1248.636620183537 - 72 - 1 - 10 -3442.992101166711 - 20 -1248.636620183537 - 11 -3442.992101166711 - 21 -1248.686620183537 - 72 - 1 - 10 -3442.992101166711 - 20 -1248.686620183537 - 11 -3443.292101166711 - 21 -1248.686620183537 - 72 - 1 - 10 -3443.292101166711 - 20 -1248.686620183537 - 11 -3443.292101166711 - 21 -1248.836620183537 - 72 - 1 - 10 -3443.292101166711 - 20 -1248.836620183537 - 11 -3443.592101166711 - 21 -1248.836620183537 - 72 - 1 - 10 -3443.592101166711 - 20 -1248.836620183537 - 11 -3443.592101166711 - 21 -1248.986620183537 - 72 - 1 - 10 -3443.592101166711 - 20 -1248.986620183537 - 11 -3443.89210116671 - 21 -1248.986620183537 - 72 - 1 - 10 -3443.89210116671 - 20 -1248.986620183537 - 11 -3443.89210116671 - 21 -1249.136620183537 - 72 - 1 - 10 -3443.89210116671 - 20 -1249.136620183537 - 11 -3444.192101166712 - 21 -1249.136620183537 - 72 - 1 - 10 -3444.192101166712 - 20 -1249.136620183537 - 11 -3444.192101166712 - 21 -1249.286620183537 - 72 - 1 - 10 -3444.192101166712 - 20 -1249.286620183537 - 11 -3444.492101166711 - 21 -1249.286620183537 - 72 - 1 - 10 -3444.492101166711 - 20 -1249.286620183537 - 11 -3444.492101166711 - 21 -1249.436620183537 - 72 - 1 - 10 -3444.492101166711 - 20 -1249.436620183537 - 11 -3444.792101166711 - 21 -1249.436620183537 - 72 - 1 - 10 -3444.792101166711 - 20 -1249.436620183537 - 11 -3444.792101166711 - 21 -1249.586620183537 - 72 - 1 - 10 -3444.792101166711 - 20 -1249.586620183537 - 11 -3445.092101166711 - 21 -1249.586620183537 - 72 - 1 - 10 -3445.092101166711 - 20 -1249.586620183537 - 11 -3445.092101166711 - 21 -1249.736620183538 - 72 - 1 - 10 -3445.092101166711 - 20 -1249.736620183538 - 11 -3445.392101166712 - 21 -1249.736620183538 - 72 - 1 - 10 -3445.392101166712 - 20 -1249.736620183538 - 11 -3445.392101166712 - 21 -1249.886620183521 - 72 - 1 - 10 -3445.392101166712 - 20 -1249.886620183521 - 11 -3445.692101166712 - 21 -1249.886620183521 - 72 - 1 - 10 -3445.692101166712 - 20 -1249.886620183521 - 11 -3445.692101166712 - 21 -1250.036620183522 - 72 - 1 - 10 -3445.692101166712 - 20 -1250.036620183522 - 11 -3445.992101166712 - 21 -1250.036620183522 - 72 - 1 - 10 -3445.992101166712 - 20 -1250.036620183522 - 11 -3445.992101166712 - 21 -1250.186620183522 - 72 - 1 - 10 -3445.992101166712 - 20 -1250.186620183522 - 11 -3446.292101166712 - 21 -1250.186620183522 - 72 - 1 - 10 -3446.292101166712 - 20 -1250.186620183522 - 11 -3446.292101166712 - 21 -1250.336620183522 - 72 - 1 - 10 -3446.292101166712 - 20 -1250.336620183522 - 11 -3446.592101166713 - 21 -1250.336620183522 - 72 - 1 - 10 -3446.592101166713 - 20 -1250.336620183522 - 11 -3446.592101166713 - 21 -1250.486620183522 - 72 - 1 - 10 -3446.592101166713 - 20 -1250.486620183522 - 11 -3446.892101166714 - 21 -1250.486620183522 - 72 - 1 - 10 -3446.892101166714 - 20 -1250.486620183522 - 11 -3446.892101166714 - 21 -1250.636620183522 - 72 - 1 - 10 -3446.892101166714 - 20 -1250.636620183522 - 11 -3447.192101166713 - 21 -1250.636620183522 - 72 - 1 - 10 -3447.192101166713 - 20 -1250.636620183522 - 11 -3447.192101166713 - 21 -1250.786620183522 - 72 - 1 - 10 -3447.192101166713 - 20 -1250.786620183522 - 11 -3448.29210116671 - 21 -1250.786620183522 - 72 - 1 - 10 -3448.29210116671 - 20 -1250.786620183522 - 11 -3448.29210116671 - 21 -1250.886620183522 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -C02 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 9 - 72 - 1 - 10 -3444.192101166712 - 20 -1252.886620183464 - 11 -3444.192101166716 - 21 -1252.986620183464 - 72 - 1 - 10 -3444.192101166716 - 20 -1252.986620183464 - 11 -3444.092101166711 - 21 -1252.986620183464 - 72 - 1 - 10 -3444.092101166711 - 20 -1252.986620183464 - 11 -3444.092101166711 - 21 -1252.836620183464 - 72 - 1 - 10 -3444.092101166711 - 20 -1252.836620183464 - 11 -3443.792101166711 - 21 -1252.836620183464 - 72 - 1 - 10 -3443.792101166711 - 20 -1252.836620183464 - 11 -3443.792101166711 - 21 -1252.686620183463 - 72 - 1 - 10 -3443.792101166711 - 20 -1252.686620183463 - 11 -3443.89210116671 - 21 -1252.686620183463 - 72 - 1 - 10 -3443.89210116671 - 20 -1252.686620183463 - 11 -3443.89210116671 - 21 -1252.736620183464 - 72 - 1 - 10 -3443.89210116671 - 20 -1252.736620183464 - 11 -3444.192101166712 - 21 -1252.736620183464 - 72 - 1 - 10 -3444.192101166712 - 20 -1252.736620183464 - 11 -3444.192101166712 - 21 -1252.886620183464 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -C03 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 6 - 72 - 1 - 10 -3444.784366980695 - 20 -1253.286620183464 - 11 -3444.692101166711 - 21 -1253.286620183464 - 72 - 1 - 10 -3444.692101166711 - 20 -1253.286620183464 - 11 -3444.692101166711 - 21 -1253.136620183464 - 72 - 1 - 10 -3444.692101166711 - 20 -1253.136620183464 - 11 -3444.554366980713 - 21 -1253.136620183464 - 72 - 1 - 10 -3444.554366980713 - 20 -1253.136620183464 - 11 -3444.554366980713 - 21 -1253.036620183464 - 72 - 1 - 10 -3444.554366980713 - 20 -1253.036620183464 - 11 -3444.784366980695 - 21 -1253.036620183464 - 72 - 1 - 10 -3444.784366980695 - 20 -1253.036620183464 - 11 -3444.784366980695 - 21 -1253.286620183464 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -C04 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 8 - 72 - 1 - 10 -3444.492101166711 - 20 -1253.036620183464 - 11 -3444.554366980713 - 21 -1253.036620183464 - 72 - 1 - 10 -3444.554366980713 - 20 -1253.036620183464 - 11 -3444.554366980713 - 21 -1253.136620183464 - 72 - 1 - 10 -3444.554366980713 - 20 -1253.136620183464 - 11 -3444.392101166711 - 21 -1253.136620183464 - 72 - 1 - 10 -3444.392101166711 - 20 -1253.136620183464 - 11 -3444.392101166711 - 21 -1252.986620183464 - 72 - 1 - 10 -3444.392101166711 - 20 -1252.986620183464 - 11 -3444.192101166733 - 21 -1252.986620183464 - 72 - 1 - 10 -3444.192101166733 - 20 -1252.986620183464 - 11 -3444.192101166733 - 21 -1252.886620183464 - 72 - 1 - 10 -3444.192101166733 - 20 -1252.886620183464 - 11 -3444.492101166711 - 21 -1252.886620183464 - 72 - 1 - 10 -3444.492101166711 - 20 -1252.886620183464 - 11 -3444.492101166711 - 21 -1253.036620183464 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LINE - 5 -C05 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3448.29210116671 - 20 -1248.536620183537 - 11 -3431.59436698075 - 21 -1248.536620183537 - 0 -LWPOLYLINE - 5 -C06 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3434.344366980717 - 20 -1252.684620183551 - 10 -3444.692101166709 - 20 -1252.684620183551 - 10 -3444.692101166709 - 20 -1252.586798794548 - 10 -3434.344366980717 - 20 -1252.586798794548 - 0 -HATCH - 5 -C07 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3444.692101166709 - 20 -1252.686620183584 - 11 -3434.344366980717 - 21 -1252.686620183584 - 72 - 1 - 10 -3434.344366980717 - 20 -1252.686620183584 - 11 -3434.344366980717 - 21 -1252.586798794548 - 72 - 1 - 10 -3434.344366980717 - 20 -1252.586798794548 - 11 -3444.692101166709 - 21 -1252.586798794548 - 72 - 1 - 10 -3444.692101166709 - 20 -1252.586798794548 - 11 -3444.692101166709 - 21 -1252.686620183584 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -C08 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3444.592101166711 - 20 -1256.286620183557 - 11 -3434.344366980717 - 21 -1256.286620183557 - 72 - 1 - 10 -3434.344366980717 - 20 -1256.286620183557 - 11 -3434.344366980717 - 21 -1256.186620183522 - 72 - 1 - 10 -3434.344366980717 - 20 -1256.186620183522 - 11 -3444.592101166711 - 21 -1256.186620183522 - 72 - 1 - 10 -3444.592101166711 - 20 -1256.186620183522 - 11 -3444.592101166711 - 21 -1256.286620183557 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -C09 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3447.092101166756 - 20 -1251.336620183522 - 10 -3447.092101166756 - 20 -1250.886620183522 - 0 -LWPOLYLINE - 5 -C0A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3447.092101166756 - 20 -1254.936620183449 - 10 -3447.092101166711 - 20 -1254.486620183448 - 0 -LWPOLYLINE - 5 -C0B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.59210116671 - 20 -1259.789325424532 - 10 -3445.59210116671 - 20 -1255.836620183449 - 0 -LWPOLYLINE - 5 -C0C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.59210116671 - 20 -1255.586620183449 - 10 -3445.592101166712 - 20 -1253.586620183448 - 0 -LWPOLYLINE - 5 -C0D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.592101166712 - 20 -1253.486620183448 - 10 -3445.592101166712 - 20 -1252.086620183523 - 0 -LWPOLYLINE - 5 -C0E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.59210116671 - 20 -1251.986620183523 - 10 -3445.59210116671 - 20 -1249.986620183521 - 0 -LWPOLYLINE - 5 -C0F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3445.59210116671 - 20 -1249.886620183521 - 10 -3445.59210116671 - 20 -1248.636620183553 - 10 -3445.59210116671 - 20 -1248.336620183561 - 0 -LWPOLYLINE - 5 -C10 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.59210116671 - 20 -1248.236620183561 - 10 -3445.59210116671 - 20 -1246.23662018356 - 0 -LWPOLYLINE - 5 -C11 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.59210116671 - 20 -1246.13662018356 - 10 -3445.59210116671 - 20 -1245.78662018356 - 0 -LWPOLYLINE - 5 -C12 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.10610116671 - 20 -1259.789325424532 - 10 -3445.10610116671 - 20 -1255.986620183449 - 0 -LWPOLYLINE - 5 -C13 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.10610116671 - 20 -1255.886620183449 - 10 -3445.106101166711 - 20 -1253.436620183464 - 0 -LWPOLYLINE - 5 -C14 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.10610116671 - 20 -1252.286620183523 - 10 -3445.10610116671 - 20 -1249.986620183521 - 0 -LWPOLYLINE - 5 -C15 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.106101166711 - 20 -1253.336620183464 - 10 -3445.106101166711 - 20 -1252.386620183523 - 0 -LWPOLYLINE - 5 -C16 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 3 - 70 - 0 - 43 -0 - 10 -3445.10610116671 - 20 -1249.886620183521 - 10 -3445.10610116671 - 20 -1248.636620183553 - 10 -3445.10610116671 - 20 -1248.336620183561 - 0 -LWPOLYLINE - 5 -C17 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3445.10610116671 - 20 -1248.236620183561 - 10 -3445.10610116671 - 20 -1246.23662018356 - 0 -MTEXT - 5 -C18 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3447.212417758449 - 20 -1252.032848458575 - 30 -0 - 40 -0.1 - 41 -0.6000000000000109 - 71 - 1 - 72 - 5 - 1 -rise=0.15\Ptread=0.3 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C19 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3447.212417758449 - 20 -1255.619126371433 - 30 -0 - 40 -0.1 - 41 -0.6000000000000109 - 71 - 1 - 72 - 5 - 1 -rise=0.15\Ptread=0.3 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C1A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3375.995849914151 - 20 -1247.328727787206 - 30 -0 - 40 -0.4900000000000003 - 41 -4.831944444444448 - 71 - 1 - 72 - 5 - 1 -OPEN TERRACE - 7 -arial -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883195 - 73 - 1 - 44 -1 - 0 -LINE - 5 -C1B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3466.390140816788 - 20 -1248.636620183537 - 11 -3466.390140816788 - 21 -1248.186620183525 - 0 -LINE - 5 -C1C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3466.390140816788 - 20 -1248.569042596211 - 11 -3467.590140816788 - 21 -1248.569042596211 - 0 -LINE - 5 -C1D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3466.390140816788 - 20 -1248.411620183531 - 11 -3467.590140816788 - 21 -1248.411620183531 - 0 -LINE - 5 -C1E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3466.390140816788 - 20 -1248.272427580647 - 11 -3467.590140816788 - 21 -1248.272427580647 - 0 -LWPOLYLINE - 5 -C1F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 0 - 43 -0 - 10 -3376.062164167408 - 20 -1242.722369963012 - 10 -3377.575810118579 - 20 -1242.722369963012 - 10 -3377.575810118579 - 20 -1245.238323131401 - 10 -3383.809634535341 - 20 -1245.238323131401 - 0 -LWPOLYLINE - 5 -C20 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 1 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3372.492164165247 - 20 -1255.550104161259 - 10 -3374.252164165259 - 20 -1255.550104161433 - 0 -MTEXT - 5 -C21 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3354.521414246792 - 20 -1243.408046316952 - 30 -0 - 40 -0.1 - 41 -0.6000000000000109 - 71 - 1 - 72 - 5 - 1 -rise=0.15\Ptread=0.3 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C22 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3318.268788193533 - 20 -1243.415108964659 - 30 -0 - 40 -0.1 - 41 -0.6000000000000109 - 71 - 1 - 72 - 5 - 1 -rise=0.15\Ptread=0.3 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C23 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3301.394087663785 - 20 -1243.407997752577 - 30 -0 - 40 -0.1 - 41 -0.6000000000000109 - 71 - 1 - 72 - 5 - 1 -rise=0.15\Ptread=0.3 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C24 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3283.871208875372 - 20 -1243.293785905065 - 30 -0 - 40 -0.1 - 41 -0.6000000000000109 - 71 - 1 - 72 - 5 - 1 -rise=0.15\Ptread=0.3 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.448289551288354 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C25 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3299.13600457971 - 20 -1258.982525219176 - 30 -0 - 40 -0.1 - 41 -0.6777777777777824 - 71 - 1 - 72 - 5 - 1 -rise=.176\Ptread=0.20 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883538 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C26 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3316.331542286111 - 20 -1258.941173809992 - 30 -0 - 40 -0.1 - 41 -0.6777777777777824 - 71 - 1 - 72 - 5 - 1 -rise=0.164\Ptread=0.20 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883538 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C27 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3352.588222598622 - 20 -1258.954535950939 - 30 -0 - 40 -0.1 - 41 -0.6777777777777824 - 71 - 1 - 72 - 5 - 1 -rise=0.164\Ptread=0.20 - 7 -arial smal -210 -0 -220 -0 -230 -1 - 50 --0.4482895512883538 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C28 -100 -AcDbEntity - 8 -0 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3705.993289694646 - 20 -1109.033869380241 - 30 -0 - 40 -0.34 - 41 -4.004444300282983 - 71 - 5 - 72 - 1 - 1 -\W0.8;\C7;ACCESS - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -9.494191116597102 - 73 - 1 - 44 -1 - 0 -HATCH - 5 -C29 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.48983535287 - 20 -1254.036620183495 - 11 -3448.48983535287 - 21 -1254.136620183471 - 72 - 1 - 10 -3448.48983535287 - 20 -1254.136620183471 - 11 -3448.29210116671 - 21 -1254.136620183471 - 72 - 1 - 10 -3448.29210116671 - 20 -1254.136620183471 - 11 -3448.29210116671 - 21 -1254.036620183495 - 72 - 1 - 10 -3448.29210116671 - 20 -1254.036620183495 - 11 -3448.48983535287 - 21 -1254.036620183495 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -C2A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.48983535287 - 20 -1254.136620183471 - 11 -3448.48983535287 - 21 -1254.486620183448 - 72 - 1 - 10 -3448.48983535287 - 20 -1254.486620183448 - 11 -3448.29210116671 - 21 -1254.486620183448 - 72 - 1 - 10 -3448.29210116671 - 20 -1254.486620183448 - 11 -3448.29210116671 - 21 -1254.136620183471 - 72 - 1 - 10 -3448.29210116671 - 20 -1254.136620183471 - 11 -3448.48983535287 - 21 -1254.136620183471 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -C2B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.48983535287 - 20 -1250.436620183569 - 11 -3448.48983535287 - 21 -1250.536620183545 - 72 - 1 - 10 -3448.48983535287 - 20 -1250.536620183545 - 11 -3448.29210116671 - 21 -1250.536620183545 - 72 - 1 - 10 -3448.29210116671 - 20 -1250.536620183545 - 11 -3448.29210116671 - 21 -1250.436620183569 - 72 - 1 - 10 -3448.29210116671 - 20 -1250.436620183569 - 11 -3448.48983535287 - 21 -1250.436620183569 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -HATCH - 5 -C2C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbHatch - 10 -0 - 20 -0 - 30 -0 -210 -0 -220 -0 -230 -1 - 2 -SOLID - 70 - 1 - 71 - 0 - 91 - 1 - 92 - 0 - 93 - 4 - 72 - 1 - 10 -3448.48983535287 - 20 -1250.536620183545 - 11 -3448.48983535287 - 21 -1250.886620183522 - 72 - 1 - 10 -3448.48983535287 - 20 -1250.886620183522 - 11 -3448.29210116671 - 21 -1250.886620183522 - 72 - 1 - 10 -3448.29210116671 - 20 -1250.886620183522 - 11 -3448.29210116671 - 21 -1250.536620183545 - 72 - 1 - 10 -3448.29210116671 - 20 -1250.536620183545 - 11 -3448.48983535287 - 21 -1250.536620183545 - 97 - 0 - 75 - 0 - 76 - 1 - 98 - 0 - 0 -LWPOLYLINE - 5 -C2D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.8319470861 - 20 -1243.312547942015 - 10 -3307.031947087264 - 20 -1243.312547942015 - 0 -LWPOLYLINE - 5 -C2E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.8319470861 - 20 -1243.20135832997 - 10 -3307.031947087264 - 20 -1243.20135832997 - 0 -LWPOLYLINE - 5 -C2F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084847 - 20 -1243.090168717925 - 10 -3307.031947086011 - 20 -1243.090168717925 - 0 -LWPOLYLINE - 5 -C30 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084757 - 20 -1242.97897910588 - 10 -3307.031947085923 - 20 -1242.97897910588 - 0 -LWPOLYLINE - 5 -C31 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084668 - 20 -1242.867789493836 - 10 -3307.031947085833 - 20 -1242.867789493836 - 0 -LWPOLYLINE - 5 -C32 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084579 - 20 -1242.756599881791 - 10 -3307.031947085743 - 20 -1242.756599881791 - 0 -LWPOLYLINE - 5 -C33 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.83194708449 - 20 -1242.645410269746 - 10 -3307.031947085655 - 20 -1242.645410269746 - 0 -LWPOLYLINE - 5 -C34 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084401 - 20 -1242.534220657701 - 10 -3307.031947085565 - 20 -1242.534220657701 - 0 -LWPOLYLINE - 5 -C35 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084313 - 20 -1242.423031045656 - 10 -3307.031947085476 - 20 -1242.423031045656 - 0 -LWPOLYLINE - 5 -C36 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084223 - 20 -1242.311841433611 - 10 -3307.031947085387 - 20 -1242.311841433611 - 0 -LWPOLYLINE - 5 -C37 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084133 - 20 -1242.200651821566 - 10 -3307.031947085298 - 20 -1242.200651821566 - 0 -LWPOLYLINE - 5 -C38 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084044 - 20 -1242.089462209521 - 10 -3307.031947085209 - 20 -1242.089462209521 - 0 -LWPOLYLINE - 5 -C39 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947083955 - 20 -1241.978272597477 - 10 -3307.03194708512 - 20 -1241.978272597477 - 0 -LWPOLYLINE - 5 -C3A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947083866 - 20 -1241.867082985432 - 10 -3307.031947085032 - 20 -1241.867082985432 - 0 -LWPOLYLINE - 5 -C3B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947083777 - 20 -1241.755893373387 - 10 -3307.031947084941 - 20 -1241.755893373387 - 0 -LWPOLYLINE - 5 -C3C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947083688 - 20 -1241.644703761342 - 10 -3307.0319470861 - 20 -1241.644703761342 - 0 -LWPOLYLINE - 5 -C3D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.8319470861 - 20 -1241.615544322921 - 10 -3307.0319470861 - 20 -1241.615544322921 - 0 -LWPOLYLINE - 5 -C3E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.8319470861 - 20 -1241.573887651951 - 10 -3307.0319470861 - 20 -1241.573887651951 - 0 -LWPOLYLINE - 5 -C3F -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.8319470861 - 20 -1241.546811856485 - 10 -3307.0319470861 - 20 -1241.546811856485 - 0 -LWPOLYLINE - 5 -C40 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.8319470861 - 20 -1241.53223098098 - 10 -3307.0319470861 - 20 -1241.53223098098 - 0 -LWPOLYLINE - 5 -C41 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.8319470861 - 20 -1241.51140380179 - 10 -3307.0319470861 - 20 -1241.51140380179 - 0 -LWPOLYLINE - 5 -C42 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.8319470861 - 20 -1241.47807707746 - 10 -3307.0319470861 - 20 -1241.47807707746 - 0 -LWPOLYLINE - 5 -C43 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.8319470861 - 20 -1241.461414871589 - 10 -3307.0319470861 - 20 -1241.461414871589 - 0 -LWPOLYLINE - 5 -C44 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.821525894156 - 20 -1241.442669022764 - 10 -3307.0319470861 - 20 -1241.442669022764 - 0 -LWPOLYLINE - 5 -C45 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.821525894156 - 20 -1241.403095994748 - 10 -3307.0319470861 - 20 -1241.403095994748 - 0 -LWPOLYLINE - 5 -C46 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.825692467923 - 20 -1241.365606609687 - 10 -3307.0319470861 - 20 -1241.365606609687 - 0 -LWPOLYLINE - 5 -C47 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.825692467923 - 20 -1241.359357993413 - 10 -3307.0319470861 - 20 -1241.359357993413 - 0 -LWPOLYLINE - 5 -C48 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.825692467923 - 20 -1241.334363528312 - 10 -3307.0319470861 - 20 -1241.334363528312 - 0 -LWPOLYLINE - 5 -C49 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.827775754806 - 20 -1241.313534036532 - 10 -3307.0319470861 - 20 -1241.313534036532 - 0 -LWPOLYLINE - 5 -C4A -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.827775754806 - 20 -1241.298955473617 - 10 -3307.0319470861 - 20 -1241.298955473617 - 0 -LWPOLYLINE - 5 -C4B -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084936 - 20 -1241.263547418921 - 10 -3307.0319470861 - 20 -1241.263547418921 - 0 -LWPOLYLINE - 5 -C4C -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.8319470861 - 20 -1241.280209624791 - 10 -3307.0319470861 - 20 -1241.280209624791 - 0 -LWPOLYLINE - 5 -C4D -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.831947084936 - 20 -1241.234387980501 - 10 -3307.0319470861 - 20 -1241.234387980501 - 0 -LWPOLYLINE - 5 -C4E -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3305.82224410493 - 20 -1241.386685861111 - 10 -3307.0319470861 - 20 -1241.386685861111 - 0 -LWPOLYLINE - 5 -C4F -100 -AcDbEntity - 8 -BLK_1_DA_RAMP_1 - 6 -ByLayer - 62 - 256 -370 - 0 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3706.270247408939 - 20 -1115.045252869691 - 10 -3707.47024740894 - 20 -1115.045252869691 - 10 -3707.47024740894 - 20 -1112.839575830113 - 10 -3706.270247408939 - 20 -1112.839575830113 - 0 -LWPOLYLINE - 5 -C50 -100 -AcDbEntity - 8 -BLK_1_LVL_0_SIDE_YARD2 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 9 - 70 - 1 - 43 -0 - 10 -3710.930247410173 - 20 -1115.444751510471 - 10 -3711.089186617583 - 20 -1115.444751510469 - 10 -3711.089094240743 - 20 -1115.453857315655 - 10 -3711.088437912353 - 20 -1115.51855316904 - 10 -3711.085390260873 - 20 -1115.818967437 - 10 -3711.083445397838 - 20 -1116.010677220192 - 10 -3710.968487745084 - 20 -1127.342326958088 - 10 -3710.932387921423 - 20 -1130.90106992539 - 10 -3710.930247410173 - 20 -1130.901118105119 - 0 -LWPOLYLINE - 5 -C51 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 2 - 70 - 0 - 43 -0 - 10 -3463.112670446746 - 20 -1256.586620183545 - 10 -3463.112670446746 - 20 -1260.786620183557 - 0 -LINE - 5 -C52 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbLine - 10 -3462.984949602144 - 20 -1256.586620183545 - 11 -3463.112670446746 - 21 -1256.758793690603 - 0 -LWPOLYLINE - 5 -C53 -100 -AcDbEntity - 8 -BLK_1_COVERED_AREA - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 11 - 70 - 1 - 43 -0 - 10 -3699.232776431592 - 20 -1130.901118105156 - 10 -3710.930246801574 - 20 -1130.901118105156 - 10 -3710.930246801574 - 20 -1115.444751510508 - 10 -3707.700246801593 - 20 -1115.444751510508 - 10 -3707.700246801593 - 20 -1115.044751508745 - 10 -3704.785046520098 - 20 -1114.613288594773 - 10 -3704.396763690617 - 20 -1114.555820968006 - 10 -3702.892776431508 - 20 -1114.343383919094 - 10 -3702.892776431508 - 20 -1113.87338391918 - 10 -3699.462776431575 - 20 -1113.873383919063 - 10 -3699.232776431592 - 20 -1113.873383919063 - 0 -MTEXT - 5 -C54 -100 -AcDbEntity - 8 -BLK_1_BSMNT_FRONT_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3856.260514967662 - 20 -1108.027138911895 - 30 -0 - 40 -2.221171874999997 - 41 -22.21171874999997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=10.0 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C55 -100 -AcDbEntity - 8 -BLK_1_BSMNT_REAR_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3856.677019727028 - 20 -1102.45670045686 - 30 -0 - 40 -2.221171874999997 - 41 -22.21171874999997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=10.0 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C56 -100 -AcDbEntity - 8 -BLK_1_BSMNT_SIDE_YARD_1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3856.822723814906 - 20 -1096.070570277268 - 30 -0 - 40 -2.221171874999997 - 41 -22.21171874999997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=10.0 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C57 -100 -AcDbEntity - 8 -BLK_1_BSMNT_SIDE_YARD_2 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3856.290121795161 - 20 -1088.50531095391 - 30 -0 - 40 -2.221171874999997 - 41 -22.21171874999997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=10.0 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C58 -100 -AcDbEntity - 8 -BLK_1_LVL_1_FRONT_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3925.790283753418 - 20 -1113.160585340491 - 30 -0 - 40 -2.221171874999997 - 41 -23.93929687499997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=12.90 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C59 -100 -AcDbEntity - 8 -BLK_1_LVL_1_REAR_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3926.206788512785 - 20 -1107.590146885456 - 30 -0 - 40 -2.221171874999997 - 41 -23.93929687499997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=12.90 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C5A -100 -AcDbEntity - 8 -BLK_1_LVL_1_SIDE_YARD1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3926.352492600663 - 20 -1101.204016705864 - 30 -0 - 40 -2.221171874999997 - 41 -23.93929687499997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=12.90 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -MTEXT - 5 -C5B -100 -AcDbEntity - 8 -BLK_1_LVL_1_SIDE_YARD2 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbMText - 10 -3925.819890580917 - 20 -1093.638757382506 - 30 -0 - 40 -2.221171874999997 - 41 -23.93929687499997 - 71 - 1 - 72 - 5 - 1 -HEIGHT_N=12.90 - 7 -standard -210 -0 -220 -0 -230 -1 - 50 -0.08689478073013604 - 73 - 1 - 44 -1 - 0 -LWPOLYLINE - 5 -C5C -100 -AcDbEntity - 8 -BLK_1_LVL_0_BLDG_FOOT_PRINT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 11 - 70 - 1 - 43 -0 - 10 -3699.232777044987 - 20 -1130.901118125413 - 10 -3710.93024741497 - 20 -1130.901118125413 - 10 -3710.93024741497 - 20 -1115.444751530765 - 10 -3707.700247415093 - 20 -1115.444751530765 - 10 -3707.700247415093 - 20 -1115.044751530742 - 10 -3704.466422998459 - 20 -1115.044751530277 - 10 -3704.466422998459 - 20 -1114.343383939351 - 10 -3702.892777044905 - 20 -1114.343383939351 - 10 -3702.892777044905 - 20 -1113.873383939437 - 10 -3699.462777044971 - 20 -1113.87338393932 - 10 -3699.232777044987 - 20 -1113.87338393932 - 0 -LWPOLYLINE - 5 -C5D -100 -AcDbEntity - 8 -BLK_1_LVL_0_FRONT_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 11 - 70 - 1 - 43 -0 - 10 -3699.232777040066 - 20 -1113.873383919085 - 10 -3702.892776431506 - 20 -1113.873383919075 - 10 -3702.89277643151 - 20 -1114.343383919057 - 10 -3704.46743068438 - 20 -1114.343702468373 - 10 -3704.467387999287 - 20 -1115.045070058 - 10 -3707.700247410171 - 20 -1115.045252870157 - 10 -3707.700247523737 - 20 -1115.444751510496 - 10 -3710.930248785113 - 20 -1115.444751510469 - 10 -3710.931485144911 - 20 -1110.563998297215 - 10 -3710.931545268003 - 20 -1109.58540778369 - 10 -3699.234207207088 - 20 -1107.312053327475 - 0 -LWPOLYLINE - 5 -C5E -100 -AcDbEntity - 8 -BLK_1_LVL_0_SIDE_YARD1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3699.232777040192 - 20 -1130.901118105119 - 10 -3698.034300625808 - 20 -1130.90104516612 - 10 -3698.034302000869 - 20 -1113.8734017972 - 10 -3699.232778415129 - 20 -1113.873414736185 - 0 -LWPOLYLINE - 5 -C5F -100 -AcDbEntity - 8 -BLK_1_BSMNT_REAR_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 5 - 70 - 1 - 43 -0 - 10 -3699.232777040192 - 20 -1130.901118105156 - 10 -3699.221250807438 - 20 -1132.969197142546 - 10 -3701.361437638996 - 20 -1133.220526157112 - 10 -3710.910075275855 - 20 -1133.07507759163 - 10 -3710.930245187186 - 20 -1130.901118105119 - 0 -LWPOLYLINE - 5 -C60 -100 -AcDbEntity - 8 -BLK_1_LVL_1_REAR_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 8 - 70 - 1 - 43 -0 - 10 -3699.232777040192 - 20 -1130.901118105156 - 10 -3699.221250807438 - 20 -1132.969197142546 - 10 -3701.361437638996 - 20 -1133.220526157112 - 10 -3710.910075275855 - 20 -1133.07507759163 - 10 -3710.930245187186 - 20 -1130.901118105119 - 10 -3710.920247410536 - 20 -1121.211118103174 - 10 -3701.292777044578 - 20 -1121.211118103815 - 10 -3701.292777044578 - 20 -1130.901118103177 - 0 -LWPOLYLINE - 5 -C61 -100 -AcDbEntity - 8 -BLK_1_LVL_1_FRONT_YARD - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 11 - 70 - 1 - 43 -0 - 10 -3699.232777040066 - 20 -1113.873383919085 - 10 -3702.892776431506 - 20 -1113.873383919075 - 10 -3702.89277643151 - 20 -1114.343383919057 - 10 -3704.46743068438 - 20 -1114.343702468373 - 10 -3704.467388003211 - 20 -1117.573292518543 - 10 -3707.700247414094 - 20 -1117.5734753307 - 10 -3707.700247527041 - 20 -1117.573383919618 - 10 -3710.931758942712 - 20 -1117.573384783489 - 10 -3710.931485144911 - 20 -1110.563998297215 - 10 -3710.931545268003 - 20 -1109.58540778369 - 10 -3699.234207207088 - 20 -1107.312053327475 - 0 -LWPOLYLINE - 5 -C62 -100 -AcDbEntity - 8 -BLK_1_LVL_1_SIDE_YARD1 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3699.232777040192 - 20 -1130.901118105119 - 10 -3698.034300625808 - 20 -1130.90104516612 - 10 -3698.034302000869 - 20 -1113.8734017972 - 10 -3699.232778415129 - 20 -1113.873414736185 - 0 -LWPOLYLINE - 5 -C63 -100 -AcDbEntity - 8 -BLK_1_LVL_1_SIDE_YARD2 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 12 - 70 - 1 - 43 -0 - 10 -3710.931758837711 - 20 -1117.573417964718 - 10 -3711.067577681534 - 20 -1117.574795823711 - 10 -3711.067343703188 - 20 -1117.597859627006 - 10 -3711.065630789529 - 20 -1117.766705607395 - 10 -3711.062969402351 - 20 -1118.029044882827 - 10 -3711.057994324521 - 20 -1118.519450158549 - 10 -3710.968487745084 - 20 -1127.342326958088 - 10 -3710.93238490432 - 20 -1130.901069993301 - 10 -3710.930247410173 - 20 -1130.901118105119 - 10 -3701.292777044578 - 20 -1130.901118103177 - 10 -3701.292777044578 - 20 -1121.211118103815 - 10 -3710.920247410536 - 20 -1121.211118103174 - 0 -LWPOLYLINE - 5 -C64 -100 -AcDbEntity - 8 -BLK_1_LVL_1_BLDG_FOOT_PRINT - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 13 - 70 - 1 - 43 -0 - 10 -3699.232777044987 - 20 -1130.901118084906 - 10 -3701.292777044578 - 20 -1130.901118103177 - 10 -3701.292777044578 - 20 -1121.211118103815 - 10 -3710.920247410536 - 20 -1121.211118103174 - 10 -3710.931758945454 - 20 -1117.573383917096 - 10 -3704.466422995432 - 20 -1117.573383927132 - 10 -3704.466422994034 - 20 -1116.143383917103 - 10 -3704.466422994034 - 20 -1115.044751508506 - 10 -3704.466422994034 - 20 -1114.343383898843 - 10 -3702.892777044905 - 20 -1114.343383898843 - 10 -3702.892777044905 - 20 -1113.873383898928 - 10 -3699.462777044971 - 20 -1113.873383898813 - 10 -3699.232777044987 - 20 -1113.873383898813 - 0 -LWPOLYLINE - 5 -C65 -100 -AcDbEntity - 8 -BLK_1_BSMNT_SIDE_YARD_2 - 6 -CONTINUOUS - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 9 - 70 - 1 - 43 -0 - 10 -3710.930248795403 - 20 -1115.444710887573 - 10 -3711.090615002316 - 20 -1115.444751510469 - 10 -3711.090522625478 - 20 -1115.453857315655 - 10 -3711.089866297085 - 20 -1115.51855316904 - 10 -3711.086818645604 - 20 -1115.818967437 - 10 -3711.084873782571 - 20 -1116.010677220192 - 10 -3710.969916129818 - 20 -1127.342326958088 - 10 -3710.932384904318 - 20 -1130.901069993495 - 10 -3710.93024741497 - 20 -1130.901118105011 - 0 -DIMENSION - 5 -C66 -100 -AcDbEntity - 8 -BLK_1_FLR_-1_HT_ROOM - 6 -CONTINUOUS - 62 - 4 -370 - -1 -100 -AcDbDimension - 2 -*D88 - 10 -3439.215394900698 - 20 -1248.23662018351 - 30 -0 - 11 -3439.215394900697 - 21 -1247.011620183534 - 31 -0 - 70 - 33 - 71 - 5 - 3 -Standard - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3439.215394900691 - 23 -1245.78662018356 - 33 -0 - 14 -3439.215394900691 - 24 -1248.23662018351 - 34 -0 - 0 -DIMENSION - 5 -C67 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D89 - 10 -3662.588752883162 - 20 -1134.206780074248 - 30 -0 - 11 -3662.710722531596 - 21 -1147.106833780797 - 31 -0 - 70 - 33 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3663.309089490578 - 23 -1160.007092588285 - 33 -0 - 14 -3663.320197033808 - 24 -1134.20709497922 - 34 -0 - 0 -DIMENSION - 5 -C68 -100 -AcDbEntity - 8 -0 - 6 -ByLayer - 62 - 2 -370 - 0 -100 -AcDbDimension - 2 -*D90 - 10 -3663.225905775432 - 20 -1160.715069758053 - 30 -0 - 11 -3664.874581399463 - 21 -1161.037181403839 - 31 -0 - 70 - 33 - 71 - 5 - 3 -DIM 1in 100 - 53 -0 -210 -0 -220 -0 -230 -1 -100 -AcDbAlignedDimension - 13 -3666.636202718683 - 23 -1160.3980114637 - 33 -0 - 14 -3663.309089490578 - 24 -1160.007092588285 - 34 -0 - 0 -LWPOLYLINE - 5 -C69 -100 -AcDbEntity - 8 -BLK_1_FLR_0_COVERED_PARKING - 6 -ByLayer - 62 - 256 -370 - -1 -100 -AcDbPolyline - 90 - 4 - 70 - 1 - 43 -0 - 10 -3679.952282838893 - 20 -1149.381636383732 - 10 -3663.397645263938 - 20 -1149.381636383732 - 10 -3663.397645263938 - 20 -1160.007130713757 - 10 -3679.952282838893 - 20 -1160.007130713757 - 0 -ENDSEC - 0 -SECTION - 2 -OBJECTS - 0 -DICTIONARY - 5 -C -330 -0 -100 -AcDbDictionary -281 - 1 - 3 -ACAD_GROUP -350 -D - 0 -DICTIONARY - 5 -D -330 -C -100 -AcDbDictionary -281 - 1 - 0 -ENDSEC - 0 -EOF From b7a63ee2df4ab446bb4bc2f65f1ad1e9d64b4605 Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Thu, 30 May 2024 15:04:45 +0530 Subject: [PATCH 254/283] Health Campaign Service - Build Config update for master build using java 17 (#757) --- build/build-config.yml | 21 +++++++++++++++++++ .../egov/common/models/facility/Field.java | 3 --- health-services/product/pom.xml | 4 ++-- 3 files changed, 23 insertions(+), 5 deletions(-) diff --git a/build/build-config.yml b/build/build-config.yml index 5d67d344db4..0c97c19086f 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -71,6 +71,13 @@ config: dockerfile: "build/17/maven/Dockerfile" - work-dir: "health-services/project/src/main/resources/db" image-name: "health-project-db" + - name: "builds/health-campaign-services/health-services/project-java-17" + build: + - work-dir: "health-services/project" + image-name: "project" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "health-services/project/src/main/resources/db" + image-name: "project-db" - name: "builds/health-campaign-services/health-services/referralmanagement-java-17" build: - work-dir: "health-services/referralmanagement" @@ -85,6 +92,13 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "health-services/individual/src/main/resources/db" image-name: "individual-db" + - name: "builds/health-campaign-services/health-services/individual-java-17" + build: + - work-dir: "health-services/individual" + image-name: "individual" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "health-services/individual/src/main/resources/db" + image-name: "individual-db" - name: "builds/health-campaign-services/health-services/health-individual" build: - work-dir: "health-services/individual" @@ -222,6 +236,13 @@ config: dockerfile: "build/maven/Dockerfile" - work-dir: "core-services/egov-hrms/src/main/resources/db" image-name: "egov-hrms-db" + - name: "builds/health-campaign-services/core-services/egov-hrms-java-17" + build: + - work-dir: "core-services/egov-hrms" + image-name: "egov-hrms" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "core-services/egov-hrms/src/main/resources/db" + image-name: "egov-hrms-db" - name: "builds/health-campaign-services/health-services/plan-service" build: - work-dir: "health-services/plan-service" diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Field.java index 5bfc126060e..6fea19acbe4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Field.java @@ -1,8 +1,5 @@ package org.egov.common.models.facility; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; diff --git a/health-services/product/pom.xml b/health-services/product/pom.xml index ceaddfe4f4b..fada716dc88 100644 --- a/health-services/product/pom.xml +++ b/health-services/product/pom.xml @@ -75,12 +75,12 @@ org.egov.common health-services-common - 1.0.16-SNAPSHOT + 1.0.8-SNAPSHOT org.egov.common health-services-models - 1.0.20-SNAPSHOT + 1.0.15-SNAPSHOT compile From e8d6558539117c0278e0d55388d8eab17d1cadc8 Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Thu, 30 May 2024 19:15:13 +0530 Subject: [PATCH 255/283] HLM Individual search failed on userid based search fixed (#758) --- .../egov/individual/repository/IndividualRepository.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index cb9360cad80..3d9b4bb19c8 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -267,13 +267,15 @@ private String getQueryForIndividual(IndividualSearch searchObject, Integer limi } if (searchObject.getUsername() != null) { - query = query + "AND username=:username "; + query = query + "AND username in (:username) "; paramsMap.put("username", searchObject.getUsername()); } if (searchObject.getUserId() != null) { - query = query + "AND userId=:userId "; - paramsMap.put("userId", String.valueOf(searchObject.getUserId())); + query = query + "AND userId in (:userId) "; + paramsMap.put("userId", searchObject.getUserId().stream() + .map(Object::toString) + .collect(Collectors.toList())); } if (searchObject.getUserUuid() != null) { From 3c88770026b1bc74e79be24004da9bfb57abf0b3 Mon Sep 17 00:00:00 2001 From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Date: Thu, 30 May 2024 19:54:47 +0530 Subject: [PATCH 256/283] Fixes of admin console v0.1 (#759) * Merge branch 'campaign' into campaign-merged * Merge branch 'campaign' into campaign-merged --- frontend/micro-ui/web/CHANGELOG.md | 7 ++ .../micro-ui-internals/example/package.json | 4 +- .../example/public/index.html | 6 +- .../web/micro-ui-internals/package.json | 4 +- .../packages/css/package.json | 2 +- .../css/src/pages/employee/campaign.scss | 5 +- .../css/src/pages/employee/campaignCycle.scss | 7 +- .../css/src/pages/employee/index.scss | 64 +++++++++-- .../packages/css/tailwind.config.js | 5 +- .../modules/campaign-manager/package.json | 4 +- .../src/components/CampaignDates.js | 5 +- .../src/components/CampaignType.js | 2 +- .../src/components/SelectingBoundaries.js | 28 +++-- .../src/components/UploadData.js | 6 ++ .../src/hooks/useParallelSearch.js | 20 ++++ .../src/pages/employee/CycleConfiguration.js | 18 ++-- .../src/pages/employee/MyCampaign.js | 38 ++++++- .../src/pages/employee/SetupCampaign.js | 18 ++++ .../deliveryRule/AddDeliverycontext.js | 11 +- .../employee/deliveryRule/MultiTabcontext.js | 4 +- .../src/pages/employee/deliveryRule/index.js | 2 +- frontend/micro-ui/web/package.json | 2 +- frontend/micro-ui/web/public/index.html | 4 +- frontend/micro-ui/web/workbench/package.json | 2 +- .../src/server/api/campaignApis.ts | 77 +++++++++----- .../src/server/api/genericApis.ts | 2 - .../src/server/config/createAndSearch.ts | 2 +- .../src/server/config/index.ts | 3 +- .../server/config/models/campaignDetails.ts | 2 +- .../src/server/kafka/Listener.ts | 1 + .../src/server/utils/campaignUtils.ts | 46 ++++---- .../src/server/utils/genericUtils.ts | 22 +++- .../utils/transforms/projectTypeUtils.ts | 13 ++- .../server/validators/campaignValidators.ts | 100 +++++++++++++----- 34 files changed, 397 insertions(+), 139 deletions(-) create mode 100644 frontend/micro-ui/web/CHANGELOG.md create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useParallelSearch.js diff --git a/frontend/micro-ui/web/CHANGELOG.md b/frontend/micro-ui/web/CHANGELOG.md new file mode 100644 index 00000000000..826105084e8 --- /dev/null +++ b/frontend/micro-ui/web/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog +All notable changes to this module will be documented in this file. + +## 0.1.0 - 2024-05-28 +#### Base Admin console web + 1. Helps in creating the Campaign and configure delivery rules + 2. Create Data: Validates and creates resource details of type facility,user and boundary. diff --git a/frontend/micro-ui/web/micro-ui-internals/example/package.json b/frontend/micro-ui/web/micro-ui-internals/example/package.json index 495c3688d23..ccd8104bdb1 100644 --- a/frontend/micro-ui/web/micro-ui-internals/example/package.json +++ b/frontend/micro-ui/web/micro-ui-internals/example/package.json @@ -12,8 +12,8 @@ "@egovernments/digit-ui-libraries": "1.8.1-beta.4", "@egovernments/digit-ui-module-core": "1.8.1-beta.23", "@egovernments/digit-ui-module-utilities": "1.0.1-beta.2", - "@egovernments/digit-ui-components": "0.0.1-beta.28", - "@egovernments/digit-ui-react-components": "1.8.1-beta.23", + "@egovernments/digit-ui-components": "0.0.1-beta.31", + "@egovernments/digit-ui-react-components": "1.8.1-beta.24", "@egovernments/digit-ui-module-workbench": "1.0.1-beta.16", "@egovernments/digit-ui-module-hcmworkbench":"0.0.38", "@egovernments/digit-ui-module-campaign-manager": "0.0.1", diff --git a/frontend/micro-ui/web/micro-ui-internals/example/public/index.html b/frontend/micro-ui/web/micro-ui-internals/example/public/index.html index 64c6f223cec..63af0a10bac 100644 --- a/frontend/micro-ui/web/micro-ui-internals/example/public/index.html +++ b/frontend/micro-ui/web/micro-ui-internals/example/public/index.html @@ -15,8 +15,8 @@ href="https://unpkg.com/@egovernments/digit-ui-css@1.8.0-alpha.6/dist/index.css" /> --> - - + + @@ -32,4 +32,4 @@
- \ No newline at end of file + diff --git a/frontend/micro-ui/web/micro-ui-internals/package.json b/frontend/micro-ui/web/micro-ui-internals/package.json index 1545335ab30..072483e9f0c 100644 --- a/frontend/micro-ui/web/micro-ui-internals/package.json +++ b/frontend/micro-ui/web/micro-ui-internals/package.json @@ -45,8 +45,8 @@ "ajv": "^8.12.0", "lodash": "4.17.21", "microbundle-crl": "0.13.11", - "@egovernments/digit-ui-react-components": "1.8.1-beta.23", - "@egovernments/digit-ui-components": "0.0.1-beta.28", + "@egovernments/digit-ui-react-components": "1.8.1-beta.24", + "@egovernments/digit-ui-components": "0.0.1-beta.31", "react": "17.0.2", "react-dom": "17.0.2", "react-hook-form": "6.15.8", diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json b/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json index af328f65f0f..e91bf430a29 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json @@ -1,6 +1,6 @@ { "name": "@egovernments/digit-ui-css", - "version": "1.0.47-campaign", + "version": "1.0.49-campaign", "license": "MIT", "main": "dist/index.css", "author": "Jagankumar ", diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss index 3a10013d8ea..ff5cdb24093 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss @@ -1,7 +1,7 @@ @import url("../../index.scss"); @import "../../typography.scss"; -.summary-header{ +.summary-header { @extend .typography.text-heading-l; font-size: 2.25rem; } @@ -58,6 +58,9 @@ } .selecting-boundary-div { padding-top: 0.5rem; + .label-field-pair { + margin-bottom: 1.5rem; + } } .campaign-table { border-collapse: collapse; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss index 69f4b0a9eb7..2506d8ea136 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss @@ -6,7 +6,7 @@ .sub-tab-container { margin-top: 5px; padding: 1.5rem; - .card-text{ + .card-text { margin-bottom: 0; } } @@ -69,6 +69,9 @@ } } } +.selector-button-primary { + background-color: theme(digitv2.lightTheme.primary); +} .campaign-breadcrumb { margin: 0; margin-bottom: 1.5rem; @@ -272,7 +275,7 @@ .options-card { max-height: 10rem !important; } - .card-label{ + .card-label { margin-bottom: 0.5rem; } } diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss index e8f42d00428..fb8aca4ee84 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss @@ -9,6 +9,7 @@ margin-left: 92px; .employee-app-wrapper.digit-home-app-wrapper { margin-left: 0; + margin-right: 2rem; .ground-container.digit-home-ground { padding: 0; .employee-app-container.digit-home-employee-app { @@ -16,8 +17,12 @@ gap: 2.5rem; margin-top: 2rem; padding: 0; + display: grid !important; + grid-template-columns: repeat(auto-fill, minmax(263px, 1fr)); .employeeCard.customEmployeeCard.card-home.home-action-cards { margin: 0 !important; + min-width: 263px !important; + width: auto !important; } } } @@ -107,22 +112,40 @@ } .campaign-attribute-table { margin-bottom: 1rem; + border: 1px solid #d6d5d4; + overflow: hidden; + border-radius: 4px; table { background-color: #fafafa; border: 1px solid #d6d5d4; border-collapse: collapse; border-radius: 1rem; + tbody { + tr:nth-child(odd) { + background-color: white; + } + } th { - border: 1px solid #d6d5d4; + border-right: 1px solid #d6d5d4; + } + th:last-child { + border-right: none; } td { padding: 1rem; - border: 1px solid #d6d5d4; + border-right: 1px solid #d6d5d4; + } + td:last-child { + padding: 1rem; + border-right: none; } } } .campaign-product-table { margin-bottom: 1rem; + border: 1px solid #d6d5d4; + overflow: hidden; + border-radius: 4px; table { background-color: #fafafa; border: 1px solid #d6d5d4; @@ -130,13 +153,22 @@ border-radius: 1rem; tbody { background-color: #fff; + tr:nth-child(odd) { + background-color: white; + } } th { - border: 1px solid #d6d5d4; + border-right: 1px solid #d6d5d4; + } + th:last-child { + border-right: none; } td { padding: 1rem; - border: 1px solid #d6d5d4; + border-right: 1px solid #d6d5d4; + } + td:last-child { + border-right: none; } } } @@ -170,13 +202,20 @@ input[type="date"]::-webkit-calendar-picker-indicator { } } .campaign-attribute-table { + border: 1px solid #d6d5d4; + overflow: hidden; + border-radius: 4px; tbody { tr:nth-child(odd) { background-color: white; } } } - +tbody { + tr:nth-child(odd) { + background-color: white; + } +} .popup-wrap.campaign-data-preview { flex-direction: column; } @@ -212,6 +251,9 @@ input[type="date"]::-webkit-calendar-picker-indicator { .digit-dropdown-options-card { max-height: 10rem !important; } + .digit-field { + margin-bottom: 0 !important; + } } .campaign-summary-container { .setup-campaign-card { @@ -317,9 +359,9 @@ input[type="date"]::-webkit-calendar-picker-indicator { .popup-module-action-bar.campaign-pop-action { .selector-button-border { background-color: #ffffff; - border: 1px solid #f47738; + border: 1px solid #c84c0e; h2 { - color: #f47738 !important; + color: #c84c0e !important; } } } @@ -347,3 +389,11 @@ input[type="date"]::-webkit-calendar-picker-indicator { font-size: 14px; } } +.individualElement { + h2 { + color: theme(digitv2.lightTheme.text-primary); + } +} +.link { + color: #c84c0e !important; +} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js b/frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js index b6a497b173d..e59e972d1ad 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js @@ -114,9 +114,10 @@ module.exports = { "header-sidenav": "#0B4B66", "input-border": "#505A5F", "primary-bg": "#FEEFE7", + "text-primary": "#363636", }, alert: { - error: "#b91900", + error: "#b91900", "error-bg": "#EFC7C1", success: "#00703C", "success-bg": "#BAD6C9", @@ -228,4 +229,4 @@ module.exports = { }, variants: {}, plugins: [], -}; \ No newline at end of file +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json index 470bed80d1a..ba8776efd9b 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json @@ -18,8 +18,8 @@ "react-router-dom": "5.3.0" }, "dependencies": { - "@egovernments/digit-ui-react-components": "1.8.1-beta.23", - "@egovernments/digit-ui-components": "0.0.1-beta.30", + "@egovernments/digit-ui-react-components": "1.8.1-beta.24", + "@egovernments/digit-ui-components": "0.0.1-beta.31", "@rjsf/core": "5.10.0", "@rjsf/utils": "5.10.0", "@rjsf/validator-ajv8": "5.10.0", diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDates.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDates.js index 9a15894f041..71bcfa4e447 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDates.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDates.js @@ -45,6 +45,9 @@ const CampaignDates = ({ onSelect, formData, ...props }) => { } else if (new Date(endDate).getTime() < new Date(startDate).getTime() && startValidation) { setError({ endDate: "CAMPAIGN_END_DATE_BEFORE_ERROR" }); onSelect("campaignDates", { startDate: startDate, endDate: endDate }); + } else if (startValidation && new Date(endDate).getTime() === new Date(startDate).getTime()) { + setError({ endDate: "CAMPAIGN_END_DATE_SAME_ERROR" }); + onSelect("campaignDates", { startDate: startDate, endDate: endDate }); } else if (startDate || endDate) { setError(null); onSelect("campaignDates", { startDate: startDate, endDate: endDate }); @@ -89,7 +92,7 @@ const CampaignDates = ({ onSelect, formData, ...props }) => { }} min={Digit.Utils.date.getDate(Date.now() + ONE_DAY_IN_MS)} onChange={(d) => { - setStartValidation(true); + // setStartValidation(true); setStart(d); }} /> diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignType.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignType.js index a4f247ac64d..22d47594cd7 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignType.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignType.js @@ -58,7 +58,7 @@ const CampaignSelection = ({ onSelect, formData, formState, ...props }) => {
{ + setLoaderEnabled(false); + }, 1000); + // closeToast(); } }; @@ -256,7 +261,9 @@ function SelectingBoundaries({ onSelect, formData, ...props }) { updatedBoundaryData[type] = []; } }); - setSelectedData(updatedSelectedData); + if (!_.isEqual(selectedData, updatedSelectedData)) { + setSelectedData(updatedSelectedData); + } setBoundaryData(updatedBoundaryData); } return; @@ -317,8 +324,9 @@ function SelectingBoundaries({ onSelect, formData, ...props }) { } }) .flat(); - - setSelectedData(updatedSelectedData); + if (!_.isEqual(selectedData, updatedSelectedData)) { + setSelectedData(updatedSelectedData); + } } else { // Update only the data for the new boundaryType const mergedData = [...selectedData?.filter((item) => item?.type !== newBoundaryType), ...transformedRes]; @@ -337,8 +345,9 @@ function SelectingBoundaries({ onSelect, formData, ...props }) { children.forEach((child) => addChildren(child)); }; filteredData.filter((item) => item.isRoot).forEach((rootItem) => addChildren(rootItem)); - - setSelectedData(updatedSelectedData); + if (!_.isEqual(selectedData, updatedSelectedData)) { + setSelectedData(updatedSelectedData); + } } const parentBoundaryEntry = hierarchyTypeDataresult ? hierarchyTypeDataresult?.boundaryHierarchy?.find( @@ -354,6 +363,7 @@ function SelectingBoundaries({ onSelect, formData, ...props }) { return ( <> + {loaderEnabled && }
{t(`CAMPAIGN_SELECT_BOUNDARY`)}
diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js index 5f51c71886e..c78d98166d5 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js @@ -50,6 +50,8 @@ const UploadData = ({ formData, onSelect, ...props }) => { const [translatedSchema, setTranslatedSchema] = useState({}); const [readMeInfo, setReadMeInfo] = useState({}); const [enabled, setEnabled] = useState(false); + const currentKey = searchParams.get("key"); + useEffect(() => { if (type === "facilityWithBoundary") { @@ -795,6 +797,10 @@ const UploadData = ({ formData, onSelect, ...props }) => { } }, [showToast]); + useEffect(() => { + setShowToast(null); + }, [currentKey]); + return ( <> {isValidation && } diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useParallelSearch.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useParallelSearch.js new file mode 100644 index 00000000000..985afd73d95 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useParallelSearch.js @@ -0,0 +1,20 @@ +const useParallelSearch = ({ parentArray, tenantId, boundaryType, hierarchy, parentCode }) => { + for (const parentCode of parentArray) { + const reqCriteriaBoundaryTypeSearch = Digit.CustomService.getResponse({ + url: "/boundary-service/boundary-relationships/_search", + params: { + tenantId: tenantId, + hierarchyType:hierarchy, + boundaryType: boundaryType, + parent: parentCode, + }, + body: {}, + }); + // setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_LOADING_BOUNDARY") }); + setLoaderEnabled(true); + const boundaryTypeData = await reqCriteriaBoundaryTypeSearch; + newData.push({ parentCode, boundaryTypeData }); + } +}; + +export default useParallelSearch; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/CycleConfiguration.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/CycleConfiguration.js index 59882ee75e6..01f7780f03f 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/CycleConfiguration.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/CycleConfiguration.js @@ -2,17 +2,17 @@ import React, { useReducer, Fragment, useEffect, useState } from "react"; import { CardText, LabelFieldPair, Card, CardLabel, CardSubHeader, Paragraph, Header } from "@egovernments/digit-ui-react-components"; import { useTranslation } from "react-i18next"; import { TextInput } from "@egovernments/digit-ui-components"; -import { deliveryConfig } from "../../configs/deliveryConfig"; +// import { deliveryConfig } from "../../configs/deliveryConfig"; -const initialState = (saved, filteredDeliveryConfig) => { +const initialState = (saved, filteredDeliveryConfig, refetch) => { const data = { cycleConfgureDate: { - cycle: saved?.cycleConfgureDate?.cycle + cycle: saved?.cycleConfgureDate?.cycle && !refetch ? saved?.cycleConfgureDate?.cycle : filteredDeliveryConfig?.cycleConfig ? filteredDeliveryConfig?.cycleConfig?.cycle : 1, - deliveries: saved?.cycleConfgureDate?.deliveries + deliveries: saved?.cycleConfgureDate?.deliveries && !refetch ? saved?.cycleConfgureDate?.deliveries : filteredDeliveryConfig?.cycleConfig ? filteredDeliveryConfig?.cycleConfig?.deliveries @@ -27,7 +27,7 @@ const initialState = (saved, filteredDeliveryConfig) => { const reducer = (state, action) => { switch (action.type) { case "RELOAD": - return initialState(action.saved, action.filteredDeliveryConfig); + return initialState(action.saved, action.filteredDeliveryConfig, action.refetch); case "UPDATE_CYCLE": return { ...state, cycleConfgureDate: { ...state.cycleConfgureDate, cycle: action.payload } }; case "UPDATE_DELIVERY": @@ -71,14 +71,15 @@ function CycleConfiguration({ onSelect, formData, control, ...props }) { { select: (data) => { const temp = data?.["HCM-ADMIN-CONSOLE"]?.deliveryConfig; - // return temp?.find((i) => i?.projectType === selectedProjectType); - return deliveryConfig?.find((i) => i?.projectType === selectedProjectType); + return temp?.find((i) => i?.projectType === selectedProjectType); + // return deliveryConfig?.find((i) => i?.projectType === selectedProjectType); }, } ); const saved = Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA")?.HCM_CAMPAIGN_CYCLE_CONFIGURE?.cycleConfigure; + const refetch = Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA")?.HCM_CAMPAIGN_CYCLE_CONFIGURE?.cycleConfigure?.cycleConfgureDate?.refetch; const tempSession = Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA"); - const [state, dispatch] = useReducer(reducer, initialState(saved, filteredDeliveryConfig)); + const [state, dispatch] = useReducer(reducer, initialState(saved, filteredDeliveryConfig, refetch)); const { cycleConfgureDate, cycleData } = state; const { t } = useTranslation(); const [dateRange, setDateRange] = useState({ @@ -93,6 +94,7 @@ function CycleConfiguration({ onSelect, formData, control, ...props }) { type: "RELOAD", saved: saved, filteredDeliveryConfig: filteredDeliveryConfig, + refetch: refetch, }); } }, [filteredDeliveryConfig, deliveryConfigLoading]); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js index 9e906e3ae2d..4e72d9f98e1 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js @@ -1,7 +1,7 @@ import React, { useMemo, useState, useEffect } from "react"; import { useTranslation } from "react-i18next"; import { Button, Header, InboxSearchComposer, Loader } from "@egovernments/digit-ui-react-components"; -import { useLocation } from "react-router-dom"; +import { useHistory, useLocation } from "react-router-dom"; import { myCampaignConfig } from "../../configs/myCampaignConfig"; /** @@ -15,6 +15,7 @@ import { myCampaignConfig } from "../../configs/myCampaignConfig"; const MyCampaign = () => { const { t } = useTranslation(); const location = useLocation(); + const history = useHistory(); const moduleName = Digit?.Utils?.getConfigModuleName() || "commonCampaignUiConfig"; const tenant = Digit.ULBService.getStateId(); const tenantId = Digit.ULBService.getCurrentTenantId(); @@ -33,11 +34,44 @@ const MyCampaign = () => { window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_UPLOAD_ID"); }, []); + const onClickRow = ({ original: row }) => { + const currentTab = tabData?.find((i) => i?.active === true)?.label; + switch (currentTab) { + case "CAMPAIGN_ONGOING": + history.push(`/${window.contextPath}/employee/campaign/setup-campaign?id=${row.id}&preview=${true}&action=${false}`); + break; + case "CAMPAIGN_COMPLETED": + history.push(`/${window.contextPath}/employee/campaign/setup-campaign?id=${row.id}&preview=${true}&action=${false}`); + break; + case "CAMPAIGN_UPCOMING": + history.push(`/${window.contextPath}/employee/campaign/setup-campaign?id=${row.id}&preview=${true}&action=${false}`); + break; + case "CAMPAIGN_DRAFTS": + history.push(`/${window.contextPath}/employee/campaign/setup-campaign?id=${row.id}&draft=${true}&fetchBoundary=${true}`); + break; + case "CAMPAIGN_FAILED": + history.push(`/${window.contextPath}/employee/campaign/setup-campaign?id=${row.id}&preview=${true}&action=${false}`); + break; + default: + break; + } + }; + return (
{t("CAMPAIGN_SEARCH_TITLE")}
- +
); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js index 708318d9e6b..a8475625252 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js @@ -254,6 +254,7 @@ const SetupCampaign = ({ hierarchyType }) => { const [fetchBoundary, setFetchBoundary] = useState(() => Boolean(searchParams.get("fetchBoundary"))); const [fetchUpload, setFetchUpload] = useState(false); const [enabled, setEnabled] = useState(false); + // const [active, setActive] = useState(0); const { data: hierarchyConfig } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "hierarchyConfig" }]); // const hierarchyType = hierarchyConfig?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.hierarchy; @@ -354,6 +355,7 @@ const SetupCampaign = ({ hierarchyType }) => { : { cycle: delivery?.map((obj) => obj?.cycleNumber)?.length > 0 ? Math.max(...delivery?.map((obj) => obj?.cycleNumber)) : 1, deliveries: delivery?.map((obj) => obj?.deliveryNumber)?.length > 0 ? Math.max(...delivery?.map((obj) => obj?.deliveryNumber)) : 1, + refetch: true, }, cycleData: draftData?.additionalDetails?.cycleData?.cycleData ? draftData?.additionalDetails?.cycleData?.cycleData @@ -1134,6 +1136,7 @@ const SetupCampaign = ({ hierarchyType }) => { }; const onStepClick = (step) => { + console.log("step", step); if ((currentKey === 4 || currentKey === 5) && step > 1) { return; } @@ -1157,6 +1160,20 @@ const SetupCampaign = ({ hierarchyType }) => { } }; + // const findHighestStepCount = () => { + // const totalFormDataKeys = Object.keys(totalFormData); + + // const relatedSteps = campaignConfig?.[0]?.form.filter((step) => totalFormDataKeys.includes(step.name)); + + // const highestStep = relatedSteps.reduce((max, step) => Math.max(max, parseInt(step.stepCount)), 0); + + // setActive(highestStep); + // }; + + // useEffect(() => { + // findHighestStepCount(); + // }, [totalFormData, campaignConfig]); + const onSecondayActionClick = () => { if (currentKey > 1) { setShouldUpdate(false); @@ -1225,6 +1242,7 @@ const SetupCampaign = ({ hierarchyType }) => { ]} currentStep={currentStep + 1} onStepClick={onStepClick} + // activeSteps={active} /> )} deleteAttribute(item, deliveryRuleIndex)} @@ -658,7 +661,7 @@ const AddDeliveryRule = ({ targetedData, deliveryRules, setDeliveryRules, index, variation="secondary" className={"add-product-btn hover"} label={t(`CAMPAIGN_ADD_PRODUCTS_BUTTON_TEXT`)} - icon={} + icon={} onButtonClick={() => setShowModal(true)} /> @@ -696,12 +699,12 @@ const AddDeliveryRule = ({ targetedData, deliveryRules, setDeliveryRules, index, const AddDeliveryRuleWrapper = ({}) => { const { campaignData, dispatchCampaignData, filteredDeliveryConfig } = useContext(CycleContext); - const [targetedData, setTargetedData] = useState(campaignData.find((i) => i.active === true).deliveries.find((d) => d.active === true)); + const [targetedData, setTargetedData] = useState(campaignData?.find((i) => i?.active === true)?.deliveries?.find((d) => d?.active === true)); const [deliveryRules, setDeliveryRules] = useState(targetedData?.deliveryRules); const { t } = useTranslation(); useEffect(() => { - const dd = campaignData.find((i) => i.active === true).deliveries.find((d) => d.active === true); + const dd = campaignData?.find((i) => i?.active === true)?.deliveries?.find((d) => d?.active === true); setTargetedData(dd); }, [campaignData]); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/MultiTabcontext.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/MultiTabcontext.js index 8fe47a69528..c02ce7d4863 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/MultiTabcontext.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/MultiTabcontext.js @@ -168,8 +168,8 @@ const SubTabs = ({ onSubTabChange }) => { return (
{campaignData - .find((i) => i.active === true) - .deliveries.map((_, index) => ( + ?.find((i) => i?.active === true) + ?.deliveries.map((_, index) => ( + ); +}; + +CloseButton.propTypes = { + clickHandler: PropTypes.func.isRequired, + style: PropTypes.object, +}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CustomScaleControl.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CustomScaleControl.js new file mode 100644 index 00000000000..f2deacbd46d --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CustomScaleControl.js @@ -0,0 +1,41 @@ +import React, { useEffect, useState } from "react"; + +const CustomScaleControl = ({ map }) => { + if (!map) return null; + const [scaleText, setScaleText] = useState(""); + // Function to calculate and update the scale text + const updateScale = () => { + // Calculate the scale based on the map's current zoom level + const maxWidthMeters = map.containerPointToLatLng([0, map.getSize().y]).distanceTo(map.containerPointToLatLng([100, map.getSize().y])); + const scale = maxWidthMeters / 1000; // Convert to kilometers + + // Format the scale text + const scaleTextData = scale < 1 ? `${Math.round(scale * 1000)} m` : `${Math.round(Math.round(scale.toFixed(0) / 10) * 10)} km`; + + // Update the scale text in the container element + setScaleText(scaleTextData); + }; + + // Effect to update the scale text when the map component mounts and on map zoom change + useEffect(() => { + // Update the scale text initially + updateScale(); + + // Register the map's zoom events to update the scale text + map.on("zoomend", updateScale); + + // Clean up event listener when the component unmounts + return () => { + map.off("zoomend", updateScale); + }; + }, [map]); + + return ( +
+ {scaleText} + + ); +}; + +export default CustomScaleControl; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Hypothesis.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Hypothesis.js new file mode 100644 index 00000000000..03015c427e9 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Hypothesis.js @@ -0,0 +1,608 @@ +import React, { useState, useEffect, useCallback, Fragment, useRef } from "react"; +import { useTranslation } from "react-i18next"; +import { Trash } from "@egovernments/digit-ui-svg-components"; +import { CloseButton, ModalHeading } from "./CommonComponents"; +import { Dropdown, TextInput, Toast } from "@egovernments/digit-ui-components"; +import { useMyContext } from "../utils/context"; +import { tourSteps } from "../configs/tourSteps"; +import { v4 as uuidv4 } from "uuid"; +import { PlusWithSurroundingCircle } from "../icons/Svg"; +import { PRIMARY_THEME_COLOR } from "../configs/constants"; +import { Button, Modal } from "@egovernments/digit-ui-react-components"; +const page = "hypothesis"; + +const Hypothesis = ({ + campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, + microplanData, + setMicroplanData, + checkDataCompletion, + setCheckDataCompletion, + currentPage, + pages, + setToast, +}) => { + const { t } = useTranslation(); + + // States + const [editable, setEditable] = useState(true); + const [modal, setModalState] = useState("none"); + const [assumptions, setAssumptions] = useState([]); + const [hypothesisAssumptionsList, setHypothesisAssumptionsList] = useState([]); + const [itemForDeletion, setItemForDeletion] = useState(); + const [exampleOption, setExampleOption] = useState(""); + // const [toast, setToast] = useState(); + const [autofillHypothesis, setAutofillHypothesis] = useState([]); + const { state, dispatch } = useMyContext(); + const [orignalHypothesisCount, setOrignalHypothesisCount] = useState(0); + + // Set TourSteps + useEffect(() => { + const tourData = tourSteps(t)?.[page] || {}; + if (state?.tourStateData?.name === page) return; + dispatch({ + type: "SETINITDATA", + state: { tourStateData: tourData }, + }); + }, []); + + const setModal = (modalString) => { + const elements = document.querySelectorAll(".popup-wrap-rest-unfocus"); + elements.forEach((element) => { + element.classList.toggle("popup-wrap-rest-unfocus-active"); + }); + setModalState(modalString); + }; + + // UseEffect to extract data on first render + useEffect(() => { + if (pages) { + const previouspage = pages[currentPage?.id - 1]; + if (previouspage?.checkForCompleteness && !microplanData?.status?.[previouspage?.name]) setEditable(false); + else setEditable(true); + } + if (microplanData?.hypothesis) { + const temp = microplanData?.hypothesis; + setAssumptions(temp); + } + + fetchDataAndUpdateState(); + }, []); + + const fetchDataAndUpdateState = useCallback(() => { + let hypothesisAssumptions = state?.HypothesisAssumptions; + if (!hypothesisAssumptions) return; + let temp = hypothesisAssumptions.find((item) => item.campaignType === campaignType); + if (!temp?.assumptions) return; + const hypothesisAssumptionsList = Array.isArray(temp.assumptions) ? temp.assumptions : []; + setOrignalHypothesisCount(hypothesisAssumptionsList.length); + setExampleOption(hypothesisAssumptionsList.length !== 0 ? hypothesisAssumptionsList[0] : ""); + + let newAssumptions = setAutofillHypothesisData( + hypothesisAssumptionsList, + microplanData?.hypothesis ? microplanData?.hypothesis : assumptions, + setAssumptions + ); + + let newHypothesislist = filterHypothesisList(newAssumptions.length !== 0 ? newAssumptions : microplanData.hypothesis, hypothesisAssumptionsList); + setHypothesisAssumptionsList(newHypothesislist); + }, [campaignType, microplanData, setAutofillHypothesisData, filterHypothesisList, assumptions, setAssumptions]); + + // UseEffect for checking completeness of data before moveing to next section + useEffect(() => { + if (!assumptions || checkDataCompletion !== "true" || !setCheckDataCompletion) return; + // uncomment to activate data change save check + // if (!microplanData?.hypothesis || !_.isEqual(assumptions, microplanData.hypothesis)) setModal("data-change-check"); + // else + updateData(true); + }, [checkDataCompletion]); + + // UseEffect to store current data + useEffect(() => { + if (!assumptions || !setMicroplanData) return; + setMicroplanData((previous) => ({ ...previous, hypothesis: assumptions })); + }, [assumptions]); + + // UseEffect to add a event listener for keyboard + useEffect(() => { + window.addEventListener("keydown", handleKeyPress); + + return () => window.removeEventListener("keydown", handleKeyPress); + }, [modal]); + + const handleKeyPress = (event) => { + // if (modal !== "upload-guidelines") return; + if (["x", "Escape"].includes(event.key)) { + // Perform the desired action when "x" or "esc" is pressed + // if (modal === "upload-guidelines") + setCheckDataCompletion("false"); + setModal("none"); + } + }; + + // check if data has changed or not + const updateData = useCallback( + (check) => { + if (!assumptions || !setMicroplanData) return; + if (check) { + if (assumptions.some((item) => item.active && parseFloat(item.value) === 0)) { + setToast({ state: "error", message: t("ERROR_HYPOTHESIS_VALUE_SHOULD_NOT_BE_ZERO") }); + setCheckDataCompletion("false"); + return; + } + let newAssumptions = assumptions.map((item) => { + if (parseFloat(item.value) === 0) { + return { ...item, value: 0.01 }; + } else { + return item; + } + }); + setMicroplanData((previous) => ({ ...previous, hypothesis: newAssumptions })); + setAssumptions(newAssumptions); + let checkValid = validateAssumptions(assumptions); + checkValid = checkValid && assumptions.filter((subItem) => subItem?.active).length !== 0; + if (checkValid) setCheckDataCompletion("valid"); + else setCheckDataCompletion("invalid"); + } else { + let checkValid = microplanData?.hypothesis?.every((item) => Object.values(item).every((data) => data !== "")); + checkValid = checkValid && assumptions.length !== 0; + if (checkValid) setCheckDataCompletion("valid"); + else setCheckDataCompletion("invalid"); + } + }, + [assumptions, setMicroplanData, microplanData, setCheckDataCompletion] + ); + + const validateAssumptions = useCallback((assumptions) => { + return assumptions.filter((item) => item?.active).every((item) => Object.values(item).every((data) => data !== "")) && assumptions.length !== 0; + }, []); + + const cancelUpdateData = useCallback(() => { + setCheckDataCompletion("false"); + setModal("none"); + }, [setCheckDataCompletion, setModal]); + + const closeModal = useCallback(() => { + setModal("none"); + }, []); + + // Function to Delete an assumption + const deleteAssumptionHandlerCallback = useCallback(() => { + deleteAssumptionHandler(itemForDeletion, setItemForDeletion, setAssumptions, setHypothesisAssumptionsList, setToast, t); + closeModal(); + }, [itemForDeletion, deleteAssumptionHandler, setItemForDeletion, setAssumptions, setHypothesisAssumptionsList, closeModal, setToast, t]); + + const sectionClass = `jk-header-btn-wrapper hypothesis-section ${editable ? "" : "non-editable-component"} popup-wrap-rest-unfocus `; + + return ( + <> +
+
+ {/* NonInterractable Section */} + + {/* Interractable Section that includes the example as well as the assumptions */} + +
+
+
+ {modal === "delete-conformation" && ( + } + actionCancelLabel={t("YES")} + actionCancelOnSubmit={deleteAssumptionHandlerCallback} + actionSaveLabel={t("NO")} + actionSaveOnSubmit={closeModal} + > +
+

{t("HYPOTHESIS_INSTRUCTIONS_DELETE_ENTRY_CONFIRMATION")}

+
+
+ )} +
+ + ); +}; + +// Function to add a new assumption +const addAssumptionsHandler = (setAssumptions) => { + let uuid = uuidv4(); + setAssumptions((previous) => [ + ...previous, + { + id: uuid, + // previous.length ? previous[previous.length - 1].id + 1 : 0, + key: "", + value: "", + active: true, + }, + ]); +}; + +// Defination for NonInterractable Section +const NonInterractableSection = React.memo(({ t }) => { + return ( +
+

{t("HEADING_HYPOTHESIS")}

+

{t("INSTRUCTION_HYPOTHESIS")}

+
+ ); +}); + +// Defination for NonInterractable Section +const InterractableSection = React.memo( + ({ assumptions, setAssumptions, hypothesisAssumptionsList, setHypothesisAssumptionsList, setModal, setItemForDeletion, exampleOption, t }) => { + const itemRefs = useRef([]); + const [expandedIndex, setExpandedIndex] = useState(null); + const scrollContainerRef = useRef(null); + const [renderCycle, setRenderCycle] = useState(0); + + useEffect(() => { + if (expandedIndex !== null) { + setRenderCycle(0); // Reset render cycle count when expandedIndex changes + } + }, [expandedIndex]); + + useEffect(() => { + // Scroll to the expanded item after the state has updated and the DOM has re-rendered + if (renderCycle < 2) { + setRenderCycle((prev) => prev + 1); // Increment render cycle count + } else if (expandedIndex !== null && itemRefs.current[expandedIndex]) { + try { + const parentElement = itemRefs.current[expandedIndex]; + const childElement = itemRefs.current[expandedIndex].children[1]; + + if (parentElement) { + const scrollContainer = scrollContainerRef.current; + const parentRect = parentElement.getBoundingClientRect(); + const containerRect = scrollContainer.getBoundingClientRect(); + + // Calculate the offset from the top of the container + const offset = parentRect.top - containerRect.top; + + // Scroll the container + scrollContainer.scrollTo({ + top: scrollContainer.scrollTop + offset - 10, + behavior: "smooth", + }); + } + + if (childElement) { + childElement.focus(); + } + } catch (error) { + console.error("Error scrolling to element:", error); + } + } + }, [renderCycle, expandedIndex]); + + useEffect(() => { + if (expandedIndex !== null) { + const observer = new MutationObserver(() => { + setRenderCycle((prev) => prev + 1); // Trigger render cycle when the DOM changes + }); + + if (itemRefs.current[expandedIndex]) { + observer.observe(itemRefs.current[expandedIndex], { childList: true, subtree: true }); + } + + return () => observer.disconnect(); + } + }, [expandedIndex]); + + const toggleExpand = (index) => { + setExpandedIndex(index === expandedIndex ? null : index); + }; + + // Handler for deleting an assumption on conformation + const deleteHandler = useCallback( + (item) => { + setModal("delete-conformation"); + setItemForDeletion(item); + }, + [setModal, setItemForDeletion] + ); + + return ( +
+ +
+
+
+

{t("KEY")}

+
+
+

{t("VALUE")}

+
+
+ +
+
+ {assumptions + ?.filter((item) => item.active) + ?.map((item, index) => ( +
item.active)?.length - 1 ? "last-container" : "" + } `} + > +
{ + itemRefs.current[index] = el; + }} + onClick={() => { + toggleExpand(index); + }} + > + +
+
+ +
+
+ ))} +
+
+ ); + } +); + +const Example = ({ exampleOption, t }) => { + return ( +
+

{t("EXAMPLE")}

+
+
+

{t("KEY")}

+ +

{t("HYPOTHESIS_KEY_HELP_TEXT")}

+
+
+

{t("VALUE")}

+ +

{t("HYPOTHESIS_VALUE_HELP_TEXT")}

+
+
+
+ ); +}; + +const deleteAssumptionHandler = (item, setItemForDeletion, setAssumptions, setHypothesisAssumptionsList, setToast, t) => { + let add = true; + setAssumptions((previous) => { + if (!previous.length) return []; + if (previous.filter((item) => item.active)?.length <= 1) { + setToast({ state: "error", message: t("ERROR_CANNOT_DELETE_LAST_HYPOTHESIS") }); + add = false; + return previous; + } + // const filteredData = previous.filter((data) => data.id !== item.id); + const deletionElementIndex = previous.findIndex((data) => data.id === item.id); + const filteredData = previous.map((data, index) => (index === deletionElementIndex ? { ...data, active: false } : data)); + return filteredData || []; + }); + if (add && item && item.key) + setHypothesisAssumptionsList((previous) => { + if (!previous.includes(item.key)) return [...previous, item.key]; + return previous; // Return previous array if key already exists + }); + setItemForDeletion(); +}; + +const Select = React.memo(({ item, assumptions, setAssumptions, disabled = false, options, setOptions, t }) => { + const [selected, setSelected] = useState(); + const [filteredOptions, setFilteredOptions] = useState([]); + + useEffect(() => { + if (item?.key) setSelected({ code: item.key }); + }, [item]); + + useEffect(() => { + if (!options) return; + const filteredOptions = options.length ? options : []; + if (item?.key && !filteredOptions.includes(item.key)) { + setFilteredOptions([item.key, ...filteredOptions]); + } else setFilteredOptions(filteredOptions); + }, [options]); + + const selectChangeHandler = useCallback( + (e) => { + const existingEntry = assumptions.find((item) => item?.active && item?.key === e?.code); + if (existingEntry) return; + const newDataSegment = { + ...item, + id: item.id, + key: e?.code, + value: item.value, + }; + setAssumptions((previous) => { + let filteredAssumptionsList = previous.map((data) => { + if (data.id === item.id) return newDataSegment; + return data; + }); + return filteredAssumptionsList; + }); + + setOptions((previous) => { + let newOptions = previous.filter((item) => item !== e?.code); + if (selected && !newOptions.includes(selected?.code)) newOptions.unshift(selected?.code); + return newOptions; + }); + }, + [assumptions, item, selected, setAssumptions, setOptions] + ); + + return ( + ({ code: item }))} + selected={selected} + optionKey="code" + select={selectChangeHandler} + // style={{ width: "100%", backgroundColor: "rgb(0,0,0,0)", position:"sticky" }} + optionCardStyles={{ position: "absolute" }} + placeholder={t("SELECT_OPTION")} + showToolTip={true} + /> + ); +}); + +const Input = React.memo(({ item, setAssumptions, t, disabled = false }) => { + const [inputValue, setInputValue] = useState(""); + + useEffect(() => { + if (item) setInputValue(item.value); + }, [item]); + + const inputChangeHandler = useCallback( + (e) => { + if (e.target.value.includes("+") || e.target.value.includes("e")) return; + if ((e.target.value < 0 || e.target.value > 10000000000) && e.target.value !== "") return; + let value; + const decimalIndex = e.target.value.indexOf("."); + if (decimalIndex !== -1) { + const numDecimals = e.target.value.length - decimalIndex - 1; + value = e.target.value; + if (numDecimals <= 2) { + value = e.target.value; + } else if (numDecimals > 2) { + value = value.substring(0, decimalIndex + 3); + } + } else value = parseFloat(e.target.value); + + setInputValue(!Number.isNaN(value) ? value : ""); + const newDataSegment = { + ...item, + id: item.id, + key: item.key, + value: !Number.isNaN(value) ? value : "", + }; + setAssumptions((previous) => { + let filteredAssumptionsList = previous.map((data) => { + if (data.id === item.id) { + return newDataSegment; + } + return data; + }); + return filteredAssumptionsList; + }); + }, + [item, setAssumptions] + ); + + return ( + + ); +}); + +const setAutofillHypothesisData = (autofillHypothesis, assumptions, setAssumptions) => { + if (assumptions?.length !== 0) return []; + let newAssumptions = []; + for (let i in autofillHypothesis) { + let uuid = uuidv4(); + newAssumptions.push({ + id: uuid, + key: autofillHypothesis[Number(i)], + value: "", + active: true, + }); + } + setAssumptions(newAssumptions); + return newAssumptions; +}; + +const filterHypothesisList = (assumptions, hypothesisList) => { + let alreadySelectedHypothesis = assumptions.filter((item) => item?.active).map((item) => item?.key) || []; + return hypothesisList.filter((item) => !alreadySelectedHypothesis.includes(item)); +}; + +export default Hypothesis; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/JsonPreviewInExcelForm.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/JsonPreviewInExcelForm.js new file mode 100644 index 00000000000..37d2ab46d5d --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/JsonPreviewInExcelForm.js @@ -0,0 +1,111 @@ +import { Button, DownloadIcon, SVG } from "@egovernments/digit-ui-react-components"; +import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { PRIMARY_THEME_COLOR } from "../configs/constants"; + +export const JsonPreviewInExcelForm = (props) => { + const { t } = useTranslation(); + const sheetsData = props?.sheetsData; + const [currentSheetName, setCurrentSheetName] = useState(Object.keys(sheetsData).length > 0 ? Object.keys(sheetsData)[0] : undefined); + return ( +
+
+
+
+ {props?.errorLocationObject?.[currentSheetName] &&

{t("USER_DIRECTIONS_FOR_ERROR_MESSAGE")}

} + {/* {Object.entries(sheetsData).map(([sheetName, sheetData], index) => ( */} +
+ + + + {sheetsData?.[currentSheetName]?.[0].map((header, columnIndex) => ( + + ))} + + + + {sheetsData?.[currentSheetName]?.slice(1).map((rowData, rowIndex) => ( + + {Object.values(sheetsData?.[currentSheetName]?.[0])?.map((_, cellIndex) => { + const headerName = sheetsData?.[currentSheetName]?.[0]?.[cellIndex]; + const error = headerName ? props?.errorLocationObject?.[currentSheetName]?.[rowIndex]?.[headerName] : undefined; + let convertedError; + if (typeof error?.[0] === "object") { + let { error: actualError, ...otherProperties } = error[0]; + convertedError = t(actualError, otherProperties?.values); + } else { + convertedError = t(error); + } + const rowHasError = + typeof props?.errorLocationObject?.[currentSheetName]?.[rowIndex] === "object" + ? Object.keys(props?.errorLocationObject?.[currentSheetName]?.[rowIndex]).length !== 0 + : undefined; + return ( + + ); + })} + + ))} + +
{t(header)}
+ {cellIndex === 0 && rowHasError &&
} + + {rowData[cellIndex] || rowData[cellIndex] === 0 ? rowData[cellIndex] : ""} +
+
+
+ {Object.entries(sheetsData).map(([sheetName, sheetData], index) => ( + + ))} +
+ {/* ))} */} +
+
+ ); +}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js new file mode 100644 index 00000000000..78c8585e23a --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js @@ -0,0 +1,1693 @@ +// Importing necessary modules +import { + Card, + CardLabel, + CustomDropdown, + Dropdown, + Header, + MultiSelectDropdown, + Toast, + TreeSelect, + Button, + CheckBox, + RadioButtons, +} from "@egovernments/digit-ui-components"; +import L, { map } from "leaflet"; +import "leaflet/dist/leaflet.css"; +import React, { memo, useCallback, useEffect, useMemo, useRef, useState, Fragment } from "react"; +import { useTranslation } from "react-i18next"; +import ZoomControl from "./ZoomControl"; +import CustomScaleControl from "./CustomScaleControl"; +import * as DigitSvgs from "@egovernments/digit-ui-svg-components"; +import { CardSectionHeader, InfoIconOutline, LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; +import { processHierarchyAndData, findParent, fetchDropdownValues, findChildren, calculateAggregateForTree } from "../utils/processHierarchyAndData"; +import { EXCEL, GEOJSON, SHAPEFILE, MapChoroplethGradientColors, PRIMARY_THEME_COLOR } from "../configs/constants"; +import { tourSteps } from "../configs/tourSteps"; +import { useMyContext } from "../utils/context"; +import { ClearAllIcon, CloseButton, ModalHeading } from "./CommonComponents"; +import { PopulationSvg } from "../icons/Svg"; +import chroma from "chroma-js"; +import * as MicroplanIconCollection from "../icons/Svg"; + +const IconCollection = { ...MicroplanIconCollection, ...DigitSvgs }; + +const page = "mapping"; + +function checkTruthyKeys(obj) { + for (let key in obj) { + if (Object.hasOwn(obj, key)) { + if (obj[key] && !(Array.isArray(obj[key]) && obj[key].length === 0)) { + return true; + } + } + } + return false; +} + +// Mapping component definition +const Mapping = ({ + campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, + microplanData, + setMicroplanData, + checkDataCompletion, + setCheckDataCompletion, + currentPage, + pages, + setToast, + ...props +}) => { + //fetch campaign data + const { id = "" } = Digit.Hooks.useQueryParams(); + const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( + { + CampaignDetails: { + tenantId: Digit.ULBService.getCurrentTenantId(), + ids: [id], + }, + }, + { + enabled: !!id, + } + ); + + // request body for boundary hierarchy api + var reqCriteria = { + url: `/boundary-service/boundary-hierarchy-definition/_search`, + params: {}, + body: { + BoundaryTypeHierarchySearchCriteria: { + tenantId: Digit.ULBService.getStateId(), + // hierarchyType: "Microplan", + hierarchyType: campaignData?.hierarchyType, + }, + }, + config: { + enabled: !!campaignData?.hierarchyType, + select: (data) => { + return ( + data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map((item) => ({ + ...item, + parentBoundaryType: item?.parentBoundaryType + ? `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.parentBoundaryType)}` + : null, + boundaryType: `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}`, + })) || {} + ); + }, + }, + }; + const { isLoading: ishierarchyLoading, data: hierarchy } = Digit.Hooks.useCustomAPIHook(reqCriteria); + // request body for boundary hierarchy api + var reqCriteria = { + url: `/boundary-service/boundary/_search`, + params: { codes: Digit.ULBService.getCurrentTenantId(), tenantId: Digit.ULBService.getCurrentTenantId() }, + body: {}, + config: { + select: (data) => { + return data?.Boundary || {}; + }, + }, + }; + const { isLoading: isBoundaryLoading, data: Boundary } = Digit.Hooks.useCustomAPIHook(reqCriteria); + + // Setting up state variables + const [editable, setEditable] = useState(true); + const { t } = useTranslation(); + var [map, setMap] = useState(null); + var [_mapNode, set__mapNode] = useState("map"); + const [layers, setLayer] = useState([]); + const [validationSchemas, setValidationSchemas] = useState([]); + const [filterDataOrigin, setFilterDataOrigin] = useState({}); + const [dataAvailability, setDataAvailability] = useState("true"); + // const [toast, setToast] = useState(); + const [baseMaps, setBaseMaps] = useState({}); + const [selectedBaseMap, setSelectedBaseMap] = useState({}); + const [selectedBaseMapName, setSelectedBaseMapName] = useState(""); + const [showBaseMapSelector, setShowBaseMapSelector] = useState(false); + const [boundaryData, setBoundaryData] = useState({}); // State for boundary data + const [filterData, setFilterData] = useState({}); // State for facility data + const [boundarySelections, setBoundarySelections] = useState({}); + const [isboundarySelectionSelected, setIsboundarySelectionSelected] = useState(false); + const { state, dispatch } = useMyContext(); + const [filterPropertyNames, setFilterPropertyNames] = useState(); + const [filterProperties, setFilterProperties] = useState(); + const [showFilterOptions, setShowFilterOptions] = useState(false); + const [filterSelections, setFilterSelections] = useState([]); + const [choroplethProperties, setChoroplethProperties] = useState([]); + const [showChoroplethOptions, setShowChoroplethOptions] = useState(false); + const [choroplethProperty, setChoroplethProperty] = useState(); + const [dataCompleteness, setDataCompleteness] = useState(); + const basemapRef = useRef(); + const filterBoundaryRef = useRef(); + const showChoroplethOptionRef = useRef(); + const showFilterOptionRef = useRef(); + const [loader, setLoader] = useState(false); + + // Set TourSteps + useEffect(() => { + const tourData = tourSteps(t)?.[page] || {}; + if (state?.tourStateData?.name === page) return; + dispatch({ + type: "SETINITDATA", + state: { tourStateData: tourData }, + }); + }, []); + + // Effect to initialize map when data is fetched + useEffect(() => { + if (!state || !Boundary) return; + let UIConfiguration = state?.UIConfiguration; + if (UIConfiguration) { + const filterDataOriginList = UIConfiguration.find((item) => item.name === "mapping"); + setFilterDataOrigin(filterDataOriginList); + } + const BaseMapLayers = state?.BaseMapLayers; + let schemas = state?.Schemas; + if (schemas) setValidationSchemas(schemas); + if (!BaseMapLayers || (BaseMapLayers && BaseMapLayers.length === 0)) return; + let baseMaps = {}; + let defaultBaseMap = undefined; + BaseMapLayers.forEach((item) => { + if (item.url) { + const layer = L.tileLayer(item.url, { + minZoom: item?.minZoom, + maxZoom: item?.maxZoom, + attribution: item?.attribution, + }); + baseMaps[item?.name] = { + metadata: item, + layer, + }; + if (!defaultBaseMap) + defaultBaseMap = { + name: item?.name, + layer, + }; + } + }); + setSelectedBaseMapName(defaultBaseMap?.name); + setBaseMaps(baseMaps); + if (!map) { + init(_mapNode, defaultBaseMap, Boundary); + } + }, [Boundary]); + + useEffect(() => { + if (map && filterDataOrigin && Object.keys(filterDataOrigin).length !== 0) { + setLoader("LOADING"); + // Check if all the data is present or not, if it is then extract it in a format that can be used for mapping and other mapping related operations + extractGeoData( + campaignType, + microplanData, + filterDataOrigin, + validationSchemas, + setToast, + setDataAvailability, + hierarchy, + setBoundaryData, + setFilterData, + setFilterProperties, + setFilterSelections, + setFilterPropertyNames, + state, + setChoroplethProperties, + setDataCompleteness, + t + ); + setLoader(false); + } + }, [filterDataOrigin, hierarchy]); + + // Function to initialize map + const init = (id, defaultBaseMap, Boundary) => { + if (map !== null) return; + + // let bounds = findBounds(Boundary); + + let mapConfig = { + center: [0, 0], + zoomControl: false, + zoom: 3, + scrollwheel: true, + minZoom: 3, + }; + + let map_i = L.map(id, mapConfig); + var verticalBounds = L.latLngBounds(L.latLng(-90, -170), L.latLng(85, 190)); + map_i.on("drag", () => { + map_i.panInsideBounds(verticalBounds, { animate: true }); + }); + map_i.on("zoom", () => { + map_i.panInsideBounds(verticalBounds, { animate: true }); + }); + const defaultBaseLayer = defaultBaseMap?.layer.addTo(map_i); + // if (bounds) map_i.fitBounds(bounds); + setSelectedBaseMap(defaultBaseLayer); + setMap(map_i); + }; + + const handleBaseMapToggle = (newBaseMap) => { + if (map) { + const currentBaseLayer = selectedBaseMap; + if (currentBaseLayer) { + currentBaseLayer.remove(); + } + const newBaseLayer = baseMaps[newBaseMap].layer.addTo(map); + // Add the new base layer to the bottom of the layer stack + newBaseLayer.addTo(map); + + // Update the baseLayer state + setSelectedBaseMap(newBaseLayer); + setSelectedBaseMapName(newBaseMap); + } + }; + + // showing selected boundary data + useEffect(() => { + if (!boundarySelections && !choroplethProperty && !filterSelections) return; + setLoader("LOADING"); + try { + removeAllLayers(map, layers); + const { filteredSelection, childrenList } = filterBoundarySelection(boundaryData, boundarySelections); + let newLayer = []; + let addOn = { + fillColor: "rgba(255, 107, 43, 0)", + weight: 3.5, + opacity: 1, + color: "rgba(176, 176, 176, 1)", + fillOpacity: 0, + fill: "rgb(4,136,219,1)", + child: !childrenList || childrenList.length === 0, // so that this layer also has mounse in and mouse out events + }; + let geojsonsBase = prepareGeojson(boundaryData, "ALL", addOn); + if (geojsonsBase) { + let baseLayer = addGeojsonToMap(map, geojsonsBase, t); + if (baseLayer) newLayer.push(baseLayer); + let bounds = findBounds(geojsonsBase); + if (bounds) map.fitBounds(bounds); + } + + addOn = { + fillColor: "rgba(255, 107, 43, 1)", + weight: 2.5, + opacity: 1, + color: "rgba(255, 255, 255, 1)", + fillOpacity: 0.22, + fill: "rgb(4,136,219)", + }; + + let geojsonLayer; + if (choroplethProperty) { + if (dataCompleteness === "partial" || dataCompleteness === "false" || dataCompleteness === undefined) { + setToast({ + state: "warning", + message: t("DISPLAYING_DATA_ONLY_FOR_UPLOADED_BOUNDARIES"), + }); + } + + let choroplethGeojson = prepareGeojson(boundaryData, "ALL", { ...addOn, child: true, fillColor: "rgb(0,0,0,0)" }) || []; + if (choroplethGeojson && choroplethGeojson.length !== 0) + choroplethGeojson = addChoroplethProperties(choroplethGeojson, choroplethProperty, filteredSelection); + geojsonLayer = addGeojsonToMap(map, choroplethGeojson, t); + if (geojsonLayer) { + newLayer.push(geojsonLayer); + } + } + geojsonLayer = null; + const geojsons = prepareGeojson(boundaryData, filteredSelection, addOn); + if (geojsons && geojsons.length > 0) { + geojsonLayer = addGeojsonToMap(map, geojsons, t); + newLayer.push(geojsonLayer); + let bounds = findBounds(geojsons); + if (bounds) map.fitBounds(bounds); + } + + const childrenGeojson = prepareGeojson(boundaryData, childrenList, { ...addOn, opacity: 0, fillOpacity: 0, child: true }); + let childrenGeojsonLayer = addGeojsonToMap(map, childrenGeojson, t); + if (childrenGeojsonLayer) newLayer.push(childrenGeojsonLayer); + + //filters + const filterGeojsons = prepareGeojson(filterData, filteredSelection && filteredSelection.length !== 0 ? filteredSelection : "ALL", addOn); + const filterGeojsonWithProperties = addFilterProperties(filterGeojsons, filterSelections, filterPropertyNames, state?.MapFilters); + let filterGeojsonLayer = addGeojsonToMap(map, filterGeojsonWithProperties, t); + if (filterGeojsonLayer) newLayer.push(filterGeojsonLayer); + + setLayer(newLayer); + } catch (error) { + console.error("Error while adding geojson to map: ", error.message); + } + setLoader(false); + }, [boundarySelections, choroplethProperty, filterSelections]); + + const handleOutsideClickAndSubmitSimultaneously = useCallback(() => { + if (isboundarySelectionSelected) setIsboundarySelectionSelected(false); + if (showBaseMapSelector) setShowBaseMapSelector(false); + if (showFilterOptions) setShowFilterOptions(false); + if (showChoroplethOptions) setShowChoroplethOptions(false); + }, [ + isboundarySelectionSelected, + showBaseMapSelector, + showFilterOptions, + showChoroplethOptions, + setIsboundarySelectionSelected, + setShowBaseMapSelector, + setShowFilterOptions, + setShowChoroplethOptions, + ]); + Digit?.Hooks.useClickOutside(filterBoundaryRef, handleOutsideClickAndSubmitSimultaneously, isboundarySelectionSelected, { capture: true }); + Digit?.Hooks.useClickOutside(basemapRef, handleOutsideClickAndSubmitSimultaneously, showBaseMapSelector, { capture: true }); + Digit?.Hooks.useClickOutside(showFilterOptionRef, handleOutsideClickAndSubmitSimultaneously, showFilterOptions, { capture: true }); + Digit?.Hooks.useClickOutside(showChoroplethOptionRef, handleOutsideClickAndSubmitSimultaneously, showChoroplethOptions, { capture: true }); + + // function to stop mouse event propogation from custom comopents to leaflet map + const handleMouseDownAndScroll = (event) => { + event?.stopPropagation(); + disableMapInteractions(map); + }; + + const handleMouseUpAndScroll = (event) => { + enableMapInteractions(map); + }; + useEffect(() => { + if (isboundarySelectionSelected || showBaseMapSelector || showFilterOptions || showChoroplethOptions) handleMouseDownAndScroll(); + else handleMouseUpAndScroll(); + }, [isboundarySelectionSelected, showBaseMapSelector, showFilterOptions, showChoroplethOptions, choroplethProperty, filterPropertyNames]); + + // Rendering component + return ( +
+
{t("MAPPING")}
+ + + {/* Container for map */} + +
+
+
+ +
+ {filterProperties && Object.keys(filterProperties).length !== 0 && ( + + )} + +
+ +
+ +
+ {DigitSvgs.NorthArrow && } +
+ +
+ +
+ {filterSelections && filterSelections.length > 0 && ( + + )} + {choroplethProperty && } +
+
+
+
+ {loader && } +
+ ); +}; + +const MapFilterIndex = ({ filterSelections, MapFilters, t }) => { + return ( +
+ {filterSelections && filterSelections.length > 0 ? ( + <> + {filterSelections.map((item) => ( + //
+ + //

{t(item)}

+ //
+ ))} + + ) : ( + "" + )} +
+ ); +}; + +// Function to create the gradient from the colors array for choropleth index +const MapChoroplethIndex = ({ t, choroplethProperty }) => { + const createGradientString = (colors) => { + return colors.map((color) => `${color.color} ${color.percent}%`).join(", "); + }; + + const gradientString = createGradientString(MapChoroplethGradientColors); + const gradientStyle = { + background: `linear-gradient(to right, ${gradientString})`, + }; + + return ( +
+
+

0%

+
+

100%

+
+

{t(choroplethProperty)}

+
+ ); +}; + +const FilterItemBuilder = ({ item, MapFilters, t }) => { + let temp = MapFilters?.find((e) => e?.name == item)?.icon?.index; + let DynamicIcon = IconCollection?.[temp]; + // let icon; + // if (typeof DynamicIcon === "function") icon = DynamicIcon({}); + return DynamicIcon && typeof DynamicIcon === "function" ? ( +
+ +

{t(item)}

+
+ ) : ( + //
+ "" + ); +}; + +const ChoroplethSelection = memo( + ({ + choroplethProperties, + showChoroplethOptions, + showChoroplethOptionRef, + setShowChoroplethOptions, + choroplethProperty, + setChoroplethProperty, + t, + }) => { + const handleChange = useCallback( + (value) => { + setChoroplethProperty(value?.code); + }, + [choroplethProperties] + ); + + return ( +
+
setShowChoroplethOptions((previous) => !previous)} + onKeyUp={() => setShowChoroplethOptions((previous) => !previous)} + tabIndex={0} + > +

{t("VISUALIZATIONS")}

+
+ {DigitSvgs.FilterAlt && } +
+
+ {showChoroplethOptions && ( +
+
+ ({ name: item, id: item, code: item }))} + optionsKey="name" + onSelect={handleChange} + selectedOption={choroplethProperty} + /> +
+
+ )} +
+ ); + } +); + +const FilterSection = memo( + ({ filterProperties, showFilterOptionRef, showFilterOptions, setShowFilterOptions, filterSelections, setFilterSelections, t }) => { + const handleChange = useCallback( + (e, item) => { + let tempFilterSelections = [...filterSelections]; // Clone the array to avoid mutating state directly + if (filterSelections.includes(item)) { + tempFilterSelections = tempFilterSelections.filter((element) => element !== item); + } else { + tempFilterSelections.push(item); + } + setFilterSelections(tempFilterSelections); + }, + [filterSelections] + ); + + return ( +
+
setShowFilterOptions((previous) => !previous)} + onKeyUp={() => setShowFilterOptions((previous) => !previous)} + tabIndex={0} + > +

{t("FILTERS")}

+
+ {DigitSvgs.FilterAlt && } +
+
+ {showFilterOptions && ( +
+
+ {filterProperties.map((item) => ( +
+ handleChange(e, item)} + label={t(item)} + checked={!!filterSelections.includes(item)} + mainClassName="mainClassName" + labelClassName="labelClassName" + inputWrapperClassName="inputWrapperClassName" + inputClassName="inputClassName" + inputIconClassname="inputIconClassname" + iconFill={PRIMARY_THEME_COLOR} + onLabelClick={(e) => handleChange(e, item)} + /> +
+ ))} +
+
+ )} +
+ ); + } +); + +const BoundarySelection = memo( + ({ + boundarySelections, + setBoundarySelections, + boundaryData, + hierarchy, + filterBoundaryRef, + isboundarySelectionSelected, + setIsboundarySelectionSelected, + t, + }) => { + const [processedHierarchy, setProcessedHierarchy] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [showConfirmationModal, setShowConformationModal] = useState(false); + const itemRefs = useRef([]); + const [expandedIndex, setExpandedIndex] = useState(null); + const scrollContainerRef = useRef(null); + const [changedBoundaryType, setChangedBoundaryType] = useState(""); + const [isScrollable, setIsScrollable] = useState(false); + + useEffect(() => { + // Scroll to the expanded item's child element after the state has updated and the DOM has re-rendered + if (expandedIndex !== null && itemRefs.current[expandedIndex]) { + // Use a timeout to ensure the DOM has updated + setTimeout(() => { + const childElement = itemRefs.current[expandedIndex].children[0]; // Assuming child content is the second child + // if (childElement) { + // childElement.scrollIntoView({ behavior: 'smooth' }); + // } + if (childElement) { + const scrollContainer = scrollContainerRef.current; + const childElementBound = childElement.getBoundingClientRect(); + const containerRect = scrollContainer.getBoundingClientRect(); + + // Calculate the offset from the top of the container + const offset = childElementBound.top - containerRect.top; + + // Scroll the container + scrollContainer.scrollTo({ + top: scrollContainer.scrollTop + offset - 10, + behavior: "smooth", + }); + } + }, 0); + } + }, [expandedIndex]); + + const toggleExpand = (index) => { + setExpandedIndex(index === expandedIndex ? null : index); + }; + + // Filtering out dropdown values + useEffect(() => { + if (!boundaryData || !hierarchy) return; + let processedHierarchyTemp = fetchDropdownValues( + boundaryData, + processedHierarchy.length !== 0 ? processedHierarchy : hierarchy, + boundarySelections, + changedBoundaryType + ); + setProcessedHierarchy(processedHierarchyTemp); + setIsLoading(false); + }, [boundaryData, hierarchy, boundarySelections]); + + const handleClearAll = () => { + setShowConformationModal(true); + }; + + const handleSubmitConfModal = () => { + setBoundarySelections({}); + setShowConformationModal(false); + }; + + const handleCancelConfModal = () => { + setShowConformationModal(false); + }; + + const checkScrollbar = () => { + if (scrollContainerRef.current) { + setIsScrollable(scrollContainerRef.current.scrollHeight > scrollContainerRef.current.clientHeight); + } + }; + + useEffect(() => { + // Initial check + checkScrollbar(); + + // Check on resize + window.addEventListener("resize", checkScrollbar); + + // Cleanup event listeners on component unmount + return () => { + window.removeEventListener("resize", checkScrollbar); + }; + }, []); + + useEffect(() => { + const content = scrollContainerRef.current; + content.addEventListener("scroll", checkScrollbar); + + return () => { + content.removeEventListener("scroll", checkScrollbar); + }; + }, [scrollContainerRef]); + + return ( +
+ {isLoading && } +
+ ); + } +); + +const BaseMapSwitcher = ({ baseMaps, showBaseMapSelector, setShowBaseMapSelector, handleBaseMapToggle, selectedBaseMapName, basemapRef, t }) => { + if (!baseMaps) return null; + return ( +
+
setShowBaseMapSelector((previous) => !previous)} + onKeyUp={() => setShowBaseMapSelector((previous) => !previous)} + tabIndex={0} + > +

{t("LAYERS")}

+
{DigitSvgs.Layers && }
+
+
+ {showBaseMapSelector && ( +
+ {Object.entries(baseMaps).map(([name, baseMap], index) => { + return ( +
+ {name} handleBaseMapToggle(name)} + /> +

{t(name)}

+
+ ); + })} +
+ )} +
+
+ ); +}; + +const generatePreviewUrl = (baseMapUrl, center = [0, 0], zoom = 5) => { + const lon = Math.floor(((center[1] + 180) / 360) * Math.pow(0, zoom)); + const lat = Math.floor( + ((1 - Math.log(Math.tan((center[0] * Math.PI) / 180) + 1 / Math.cos((center[0] * Math.PI) / 180)) / Math.PI) / 2) * Math.pow(2, zoom) + ); + if (baseMapUrl) { + return baseMapUrl.replace("{z}", zoom).replace("{x}", lat).replace("{y}", lon); + } + // Return a default preview URL or handle this case as needed + return "default-preview-url.jpg"; // todo +}; + +// get schema for validation +const getSchema = (campaignType, type, section, schemas) => { + return schemas.find((schema) => { + if (!schema.campaignType) { + return schema.type === type && schema.section === section; + } + return schema.campaignType === campaignType && schema.type === type && schema.section === section; + }); +}; + +const calculateAggregateForTreeMicroplanWrapper = (entity) => { + if (!entity || typeof entity !== "object") return {}; + let newObject = {}; + for (let [key, value] of Object.entries(entity)) { + if (!value?.["hierarchicalData"]) continue; + let aggregatedTree = calculateAggregateForTree(value?.["hierarchicalData"]); + newObject[key] = { ...value, hierarchicalData: aggregatedTree }; + } + return newObject; +}; + +const extractGeoData = ( + campaignType, + microplanData, + filterDataOrigin, + validationSchemas, + setToast, + setDataAvailability, + hierarchy, + setBoundaryData, + setFilterData, + setFilterProperties, + setFilterSelections, + setFilterPropertyNames, + state, + setChoroplethProperties, + setDataCompleteness, + t +) => { + if (!hierarchy) return; + + let setBoundary = {}; + let setFilter = {}; + let virtualizationPropertiesCollector = new Set(); + let filterPropertiesCollector = new Set(); + let filterPropertieNameCollector = new Set(); + let resources = state?.Resources?.find((item) => item.campaignType === campaignType)?.data; + let hypothesisAssumptionsList = microplanData?.hypothesis; + let formulaConfiguration = microplanData?.ruleEngine; + // Check if microplanData and its upload property exist + let dataAvailabilityCheck; // Initialize data availability check + if (microplanData?.upload) { + let files = _.cloneDeep(microplanData?.upload); + dataAvailabilityCheck = "initialStage"; // Initialize data availability check + // Loop through each file in the microplan upload + for (let fileData of files) { + if (!fileData.active) continue; // if file is inactive skip it + + // Check if the file is not part of boundary or layer data origins + if (!filterDataOrigin?.boundriesDataOrigin?.includes(fileData?.section) && !filterDataOrigin?.layerDataOrigin?.includes(fileData?.section)) { + dataAvailabilityCheck = "false"; // Set data availability to false if file not found in data origins + } + + // If data availability is not false, proceed with further checks + if (dataAvailabilityCheck !== false) { + if (fileData?.error) { + dataAvailabilityCheck = + dataAvailabilityCheck === "partial" + ? "partial" + : dataAvailabilityCheck === "false" || dataAvailabilityCheck === "initialStage" + ? "false" + : "partial"; + continue; + } + if (!fileData?.fileType || !fileData?.section) continue; // Skip files with errors or missing properties + + // Get validation schema for the file + let schema = getSchema(campaignType, fileData?.fileType, fileData?.section, validationSchemas); + const properties = Object.entries(schema?.schema?.Properties || {}); + const latLngColumns = []; + let filterProperty = []; + + for (const [key, value] of properties) { + if (value?.isLocationDataColumns) { + latLngColumns.push(t(key)); + } + if ( + filterDataOrigin?.layerDataOrigin && + filterDataOrigin?.layerDataOrigin.includes(fileData?.section) && + value?.isFilterPropertyOfMapSection + ) { + filterProperty.push(key); + } + if (value?.isVisualizationPropertyOfMapSection && filterDataOrigin?.boundriesDataOrigin?.includes(fileData?.section)) { + virtualizationPropertiesCollector.add(key); + } + } + + filterProperty.forEach((property) => filterPropertieNameCollector.add(property)); + + // Check if file contains latitude and longitude columns + if (fileData?.data && Object.keys(fileData?.data).length > 0) { + if (dataAvailabilityCheck == "initialStage") dataAvailabilityCheck = "true"; + // Check file type and update data availability accordingly + switch (fileData?.fileType) { + case EXCEL: { + let columnList = Object.values(fileData?.data)?.[0]?.[0]; + let check = true; + if (latLngColumns) { + for (let colName of latLngColumns) { + check = check && columnList.includes(t(colName)); // Check if columns exist in the file + } + } + dataAvailabilityCheck = check + ? dataAvailabilityCheck === "partial" + ? "partial" + : dataAvailabilityCheck === "false" + ? "partial" + : "true" + : dataAvailabilityCheck === "partial" + ? "partial" + : dataAvailabilityCheck === "false" + ? "false" + : "partial"; // Update data availability based on column check + let dataWithResources = Object.values(fileData?.data); + if (resources && formulaConfiguration && hypothesisAssumptionsList && schema?.showResourcesInMappingSection) { + dataWithResources = dataWithResources?.map((item) => { + return Digit.Utils.microplan.addResourcesToFilteredDataToShow( + item, + resources, + hypothesisAssumptionsList, + formulaConfiguration, + microplanData?.microplanPreview?.userEditedResources ? microplanData?.microplanPreview?.userEditedResources : [], + t + ); + }); + } + + let hasLocationData = false; + // has lat lon a points + const convertedData = dataWithResources?.map((item) => + item?.map((row, rowIndex) => { + if (rowIndex === 0) { + if (row.indexOf("features") === -1) { + row.push("feature"); + } + return row; + } + const latIndex = item?.[0].findIndex((cell) => cell === "lat"); + const lonIndex = item?.[0].findIndex((cell) => cell === "long"); + let properties = {}; + row.map((e, index) => { + properties[item?.[0]?.[index]] = e; + }); + if (latIndex !== -1 && lonIndex !== -1) { + if (!hasLocationData) hasLocationData = true; + const lat = row[latIndex]; + const lon = row[lonIndex]; + const feature = { + type: "Feature", + properties: properties, + geometry: { + type: "Point", + coordinates: [lon, lat], + }, + }; + row.push(feature); + } else { + row.push(null); + } + return row; + }) + ); + + if (hasLocationData) { + if (Object.values(fileData?.data).length > 0 && filterProperty) { + filterProperty?.forEach((item) => { + Object.values(fileData?.data).forEach((data) => { + let filterPropertyIndex = data?.[0].indexOf(item); + if (filterPropertyIndex && filterPropertyIndex !== -1) + data.slice(1).forEach((e) => { + return filterPropertiesCollector.add(e[filterPropertyIndex]); + }); + }); + }); + } + } + // extract dada + var { hierarchyLists, hierarchicalData } = processHierarchyAndData(hierarchy, convertedData); + if (filterDataOrigin?.boundriesDataOrigin?.includes(fileData?.section)) + setBoundary = { ...setBoundary, [fileData.section]: { hierarchyLists, hierarchicalData } }; + else if (filterDataOrigin?.layerDataOrigin?.includes(fileData?.section)) + setFilter = { ...setFilter, [fileData.section]: { hierarchyLists, hierarchicalData } }; + break; + } + case GEOJSON: + case SHAPEFILE: { + dataAvailabilityCheck = dataAvailabilityCheck === "partial" ? "partial" : dataAvailabilityCheck === "false" ? "partial" : "true"; // Update data availability for GeoJSON or Shapefile + // Extract keys from the first feature's properties + var keys = Object.keys(fileData?.data.features[0].properties); + keys.push("feature"); + + // Extract corresponding values for each feature + const values = fileData?.data?.features.map((feature) => { + // list with features added to it + const temp = keys.map((key) => { + if (feature.properties[key] === "") { + return null; + } + if (key === "feature") return feature; + return feature.properties[key]; + }); + return temp; + }); + + if (fileData?.data?.features && filterProperty) { + filterProperty?.forEach((item) => { + if (Object.values(fileData?.data).length > 0) { + fileData?.data?.features.forEach((e) => { + if (e?.properties?.[item]) filterPropertiesCollector.add(e?.properties?.[item]); + }); + } + }); + } + + // Group keys and values into the desired format + // Adding resource data + let dataWithResources = [keys, ...values]; + if (resources && formulaConfiguration && hypothesisAssumptionsList) { + dataWithResources = Digit.Utils.microplan.addResourcesToFilteredDataToShow( + dataWithResources, + resources, + hypothesisAssumptionsList, + formulaConfiguration, + microplanData?.microplanPreview?.userEditedResources ? microplanData?.microplanPreview?.userEditedResources : [], + t + ); + let indexOfFeatureInDataWithResources = dataWithResources?.[0]?.indexOf("feature"); + keys.push(...resources); + dataWithResources = dataWithResources.map((item, index) => { + if (index === 0) return item; + let newProperties = {}; + for (const e of keys) { + if (e === "feature") continue; + let index = dataWithResources?.[0]?.indexOf(e); + newProperties[e] = item[index]; + } + let newRow = _.cloneDeep(item); + newRow[indexOfFeatureInDataWithResources] = { ...item[indexOfFeatureInDataWithResources], properties: newProperties }; + return newRow; + }); + } + + // extract dada + var { hierarchyLists, hierarchicalData } = processHierarchyAndData(hierarchy, [dataWithResources]); + if (filterDataOrigin?.boundriesDataOrigin?.includes(fileData?.section)) + setBoundary = { ...setBoundary, [fileData.section]: { hierarchyLists, hierarchicalData } }; + else if (filterDataOrigin?.layerDataOrigin?.includes(fileData?.section)) + setFilter = { ...setFilter, [fileData.section]: { hierarchyLists, hierarchicalData } }; + } + } + } + } + } + + // Set overall data availability + setDataAvailability(dataAvailabilityCheck); + + // Combine boundary and layer data origins + const combineList = [...filterDataOrigin?.boundriesDataOrigin, ...filterDataOrigin?.layerDataOrigin]; + + // Section wise check + if (dataAvailabilityCheck == "true") { + let sectionWiseCheck = true; + combineList.forEach((item) => { + sectionWiseCheck = Object.keys(files).includes(item) && sectionWiseCheck; + }); + if (!sectionWiseCheck) dataAvailabilityCheck = "partial"; // Update data availability if section-wise check fails + } + + // Update data availability based on conditions + if (dataAvailabilityCheck == "initialStage" && (combineList.length === 0 || Object.keys(files).length === 0)) dataAvailabilityCheck = "false"; + switch (dataAvailabilityCheck) { + case "false": + case undefined: + // Set warning toast message for no data to show + setToast({ + state: "warning", + message: t("MAPPING_NO_DATA_TO_SHOW"), + }); + break; + case "partial": + // Set warning toast message for partial data to show + setToast({ + state: "warning", + message: t("MAPPING_PARTIAL_DATA_TO_SHOW"), + }); + break; + } + } else { + setToast({ + state: "error", + message: t("MAPPING_NO_DATA_TO_SHOW"), + }); + } + setDataCompleteness(dataAvailabilityCheck); + setBoundary = calculateAggregateForTreeMicroplanWrapper(setBoundary); + setFilter = calculateAggregateForTreeMicroplanWrapper(setFilter); + setBoundaryData((previous) => ({ ...previous, ...setBoundary })); + setFilterData((previous) => ({ ...previous, ...setFilter })); + setFilterProperties([...filterPropertiesCollector]); + setFilterSelections([...filterPropertiesCollector]); + setFilterPropertyNames([...filterPropertieNameCollector]); + let tempVirtualizationPropertiesCollectorArray = [...virtualizationPropertiesCollector]; + if (tempVirtualizationPropertiesCollectorArray.length !== 0) + setChoroplethProperties([...tempVirtualizationPropertiesCollectorArray, ...(resources ? resources : [])]); +}; + +//prepare geojson to show on the map +const prepareGeojson = (boundaryData, selection, style = {}) => { + if (!boundaryData || Object.keys(boundaryData).length === 0) return []; + let geojsonRawFeatures = []; + if (selection == "ALL") { + for (let data of Object.values(boundaryData)) { + const templist = fetchFeatures(data?.hierarchicalData, selection, [], style); + if (templist?.length !== 0) geojsonRawFeatures = [...geojsonRawFeatures, ...templist]; + } + } else if (Array.isArray(selection)) { + for (let data of Object.values(boundaryData)) { + const templist = fetchFeatures(data?.hierarchicalData, selection, [], style); + if (templist?.length !== 0) geojsonRawFeatures = [...geojsonRawFeatures, ...templist]; + } + } + + return geojsonRawFeatures.filter(Boolean); +}; +const fetchFeatures = (data, parameter = "ALL", outputList = [], addOn = {}) => { + let tempStorage = []; + if (parameter === "ALL") { + // outputList(Object.values(data).flatMap(item=>item?.data?.feature)) + for (let [entityKey, entityValue] of Object.entries(data)) { + if (entityValue?.data?.feature) { + let feature = entityValue.data.feature; + feature.properties["name"] = entityKey; + feature.properties["addOn"] = addOn; + if (entityValue?.children) tempStorage = [...tempStorage, feature, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; + else tempStorage = [...tempStorage, feature]; + } else { + tempStorage = [...tempStorage, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; + } + } + return tempStorage; + } else if (Array.isArray(parameter)) { + for (let [entityKey, entityValue] of Object.entries(data)) { + if (parameter.includes(entityKey) && entityValue && entityValue.data && entityValue.data.feature) { + let feature = entityValue.data.feature; + feature.properties["name"] = entityKey; + feature.properties["addOn"] = addOn; + if (entityValue?.children) tempStorage = [...tempStorage, feature, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; + else tempStorage = [...tempStorage, feature]; + } + if (entityValue?.children) tempStorage = [...tempStorage, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; + } + return tempStorage; + } +}; + +const addChoroplethProperties = (geojson, choroplethProperty, filteredSelection) => { + // Calculate min and max values of the property + const values = geojson.map((feature) => feature.properties[choroplethProperty]).filter((item) => !!item || item === 0) || []; + if (!values || values.length === 0) return []; + const convertedValues = values.map((item) => (!isNaN(item) ? item : 0)); + const minValue = Math.min(...convertedValues); + const maxValue = Math.max(...convertedValues); + + // Create a new geojson object + const newGeojson = geojson.map((feature) => { + const newFeature = { ...feature, properties: { ...feature.properties, addOn: { ...feature.properties.addOn } } }; + let color; + + if (choroplethProperty) { + color = interpolateColor(newFeature.properties[choroplethProperty], minValue, maxValue, MapChoroplethGradientColors); + } + + newFeature.properties.addOn.fillColor = color; + newFeature.properties.addOn.color = "rgba(0, 0, 0, 1)"; + if (!filteredSelection || filteredSelection.length === 0 || filteredSelection.includes(newFeature.properties.name)) { + newFeature.properties.addOn.fillOpacity = 1; + } else { + newFeature.properties.addOn.fillOpacity = 0.4; + newFeature.properties.addOn.opacity = 0.7; + } + + return newFeature; + }); + return newGeojson; +}; + +/** + * filterGeojsons : json + * filterSelection : array + * MapFilters : + */ +const addFilterProperties = (filterGeojsons, filterSelections, filterPropertyNames, iconMapping) => { + try { + if (!filterGeojsons || !iconMapping || !filterSelections) return []; + let newFilterGeojson = []; + filterGeojsons.forEach((item) => { + if (filterPropertyNames && filterPropertyNames.length !== 0 && item.properties) { + let icon; + filterPropertyNames.forEach((name) => { + if (item.properties[name]) { + let temp = item.properties[name]; + if (!filterSelections.includes(temp)) return; + temp = iconMapping?.find((e) => e?.name == temp)?.icon?.marker; + let DynamicIcon = IconCollection?.[temp]; + if (typeof DynamicIcon === "function") { + icon = L.divIcon({ + className: "custom-svg-icon", + html: DynamicIcon({}), + iconAnchor: [25, 50], + }); + newFilterGeojson.push({ ...item, properties: { ...item?.properties, addOn: { ...item?.properties?.addOn, icon: icon } } }); + } else { + icon = DefaultMapMarker({}); + newFilterGeojson.push({ ...item, properties: { ...item?.properties, addOn: { ...item?.properties?.addOn, icon: icon } } }); + } + } + }); + } + return item; + }); + return newFilterGeojson; + } catch (error) { + console.error(error.message); + } +}; + +/** + * map: map + * geojson: geojson + * t: translator + */ + +const addGeojsonToMap = (map, geojson, t) => { + try { + if (!map || !geojson) return false; + const geojsonLayer = L.geoJSON(geojson, { + style: function (feature) { + if (Object.keys(feature.properties.addOn).length !== 0) { + return feature.properties.addOn; + } else { + return { + weight: 2, + opacity: 1, + color: "rgba(176, 176, 176, 1)", + fillColor: "rgb(0,0,0,0)", + // fillColor: choroplethProperty ? color : "rgb(0,0,0,0)", + fillOpacity: 0, + // fillOpacity: choroplethProperty ? (feature?.properties?.style?.fillOpacity ? feature.properties.style.fillOpacity : 0.7) : 0, + }; + } + }, + pointToLayer: function (feature, latlng) { + if (feature.properties.addOn.icon) { + let icon = feature.properties.addOn.icon; + if (icon) { + return L.marker(latlng, { + icon: icon, + }); + } + } + return L.marker(latlng, { + icon: MapMarker(feature.properties.addOn), + }); + }, + onEachFeature: function (feature, layer) { + let popupContent; + popupContent = "
"; + popupContent += ""; + popupContent += + "
" + + feature.properties["name"] + + "
"; + for (let prop in feature.properties) { + if (prop !== "name" && prop !== "addOn" && prop !== "feature") { + let data = !!feature.properties[prop] ? feature.properties[prop] : t("NO_DATA"); + popupContent += + ""; + } + } + popupContent += "
" + + t(prop) + + "" + + data + + "
"; + layer.bindPopup(popupContent, { + minWidth: "28rem", + padding: "0", + }); + // Adjust map here when pop up closes + layer.on("popupclose", function () { + map.fitBounds(geojsonLayer.getBounds()); + }); + layer.on({ + mouseover: function (e) { + const layer = e.target; + if (layer.feature.properties.addOn && !layer.feature.properties.addOn.child) { + return; + } + if (layer.setStyle) + layer.setStyle({ + weight: 2.7, + opacity: 1, + color: "rgba(255, 255, 255, 1)", + }); + // layer.openPopup(); + }, + mouseout: function (e) { + const layer = e.target; + if (layer.feature.properties.addOn && !layer.feature.properties.addOn.child) { + return; + } + if (layer.setStyle) { + if (layer.feature.properties.addOn && Object.keys(layer.feature.properties.addOn).length !== 0) + layer.setStyle({ + ...layer.feature.properties.addOn, + }); + else + layer.setStyle({ + weight: 2, + color: "rgba(176, 176, 176, 1)", + }); + } + // layer.closePopup(); + }, + }); + }, + }); + geojsonLayer.addTo(map); + return geojsonLayer; + } catch (error) { + console.error(error.message); + } +}; + +function interpolateColor(value, minValue, maxValue, colors) { + // Handle case where min and max values are the same + if (minValue === maxValue) { + // Return a default color or handle the case as needed + return colors[0].color; + } + + // Normalize the value to a percentage between 0 and 100 + const percent = !isNaN(value) ? ((value - minValue) / (maxValue - minValue)) * 100 : 0; + // Find the two colors to interpolate between + let lowerColor, upperColor; + for (let i = 0; i < colors.length - 1; i++) { + if (!isNaN(percent) && percent >= colors[i].percent && percent <= colors[i + 1].percent) { + lowerColor = colors[i]; + upperColor = colors[i + 1]; + break; + } + } + // Interpolate between the two colors + const t = (percent - lowerColor.percent) / (upperColor.percent - lowerColor.percent); + return chroma.mix(lowerColor.color, upperColor.color, t, "lab").hex(); +} + +// Find bounds for multiple geojson together +const findBounds = (data, buffer = 0.1) => { + if (!Array.isArray(data) || data.length === 0) { + return null; + } + + // Initialize variables to store bounds + var minLat = Number.MAX_VALUE; + var maxLat = -Number.MAX_VALUE; + var minLng = Number.MAX_VALUE; + var maxLng = -Number.MAX_VALUE; + + // Iterate through the data to find bounds + data.forEach(function (feature) { + if (!feature || !feature.geometry || !feature.geometry.type || !feature.geometry.coordinates) { + return null; + } + + var coords = feature.geometry.coordinates; + var geometryType = feature.geometry.type; + + switch (geometryType) { + case "Point": + var coord = coords; + var lat = coord[1]; + var lng = coord[0]; + minLat = Math.min(minLat, lat); + maxLat = Math.max(maxLat, lat); + minLng = Math.min(minLng, lng); + maxLng = Math.max(maxLng, lng); + break; + case "MultiPoint": + coords.forEach(function (coord) { + var lat = coord[1]; + var lng = coord[0]; + minLat = Math.min(minLat, lat); + maxLat = Math.max(maxLat, lat); + minLng = Math.min(minLng, lng); + maxLng = Math.max(maxLng, lng); + }); + break; + case "LineString": + case "MultiLineString": + case "Polygon": + case "MultiPolygon": + coords.forEach(function (polygons) { + if ((geometryType === "Polygon" || geometryType === "MultiPolygon") && Array.isArray(polygons[0][0])) { + polygons.forEach(function (coordinates) { + coordinates.forEach(function (coord) { + if (!Array.isArray(coord) || coord.length !== 2 || typeof coord[0] !== "number" || typeof coord[1] !== "number") { + return null; + } + + var lat = coord[1]; + var lng = coord[0]; + minLat = Math.min(minLat, lat); + maxLat = Math.max(maxLat, lat); + minLng = Math.min(minLng, lng); + maxLng = Math.max(maxLng, lng); + }); + }); + } else { + polygons.forEach(function (coord) { + if (!Array.isArray(coord) || coord.length !== 2 || typeof coord[0] !== "number" || typeof coord[1] !== "number") { + return null; + } + + var lat = coord[1]; + var lng = coord[0]; + minLat = Math.min(minLat, lat); + maxLat = Math.max(maxLat, lat); + minLng = Math.min(minLng, lng); + maxLng = Math.max(maxLng, lng); + }); + } + }); + break; + default: + return null; + } + }); + + // Check if valid bounds found + if (minLat === Number.MAX_VALUE || maxLat === -Number.MAX_VALUE || minLng === Number.MAX_VALUE || maxLng === -Number.MAX_VALUE) { + return null; + } + // Apply buffer to bounds + minLat -= buffer; + maxLat += buffer; + minLng -= buffer; + maxLng += buffer; + + // Set bounds for the Leaflet map + var bounds = [ + [minLat, minLng], + [maxLat, maxLng], + ]; + + return bounds; +}; + +const filterBoundarySelection = (boundaryData, boundarySelections) => { + if (Object.keys(boundaryData).length === 0 || Object.keys(boundarySelections).length === 0) return []; + let selectionList = []; + Object.values(boundarySelections).forEach((item) => (selectionList = [...selectionList, ...item.map((e) => e.name)])); + let childrenList = []; + const set1 = new Set(selectionList); + selectionList = selectionList.filter((item) => { + const children = findChildren([item], Object.values(boundaryData)?.[0]?.hierarchicalData); + if (children) { + let childrenKeyList = getAllKeys(children); + childrenList = [...childrenList, ...childrenKeyList]; + const nonePresent = childrenKeyList.every((item) => !set1.has(item)); + const allPresent = childrenKeyList.every((item) => set1.has(item)); + return nonePresent ? true : allPresent ? true : false; + } else { + return true; + } + }); + return { filteredSelection: selectionList, childrenList }; +}; + +// Recursive function to extract all keys +const getAllKeys = (obj, keys = []) => { + for (let [key, value] of Object.entries(obj)) { + keys.push(key); + if (value.children) { + getAllKeys(value.children, keys); + } + } + return keys; +}; + +// Remove all layers from the map +const removeAllLayers = (map, layer) => { + if (!map) return; + layer.forEach((layer) => { + map.removeLayer(layer); + }); +}; +// Map-Marker +const MapMarker = (style = {}) => { + return L.divIcon({ + className: "custom-svg-icon", + html: PopulationSvg(style), + iconAnchor: [25, 50], + }); +}; +const DefaultMapMarker = (style = {}) => { + return L.divIcon({ + className: "custom-svg-icon", + html: IconCollection.DefaultMapMarkerSvg(style), + iconAnchor: [25, 50], + }); +}; + +const disableMapInteractions = (map) => { + if (!map) return; + map.dragging.disable(); + map.scrollWheelZoom.disable(); + map.touchZoom.disable(); + map.doubleClickZoom.disable(); + map.boxZoom.disable(); + map.keyboard.disable(); +}; + +const enableMapInteractions = (map) => { + if (!map) return; + map.dragging.enable(); + map.scrollWheelZoom.enable(); + map.touchZoom.enable(); + map.doubleClickZoom.enable(); + map.boxZoom.enable(); + map.keyboard.enable(); +}; + +// Exporting Mapping component +export default Mapping; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js new file mode 100644 index 00000000000..92a414cd292 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js @@ -0,0 +1,103 @@ +import React, { memo } from "react"; +import { ActionBar, ArrowForward, Banner } from "@egovernments/digit-ui-components"; +import { useTranslation } from "react-i18next"; +import { ArrowBack, FileDownload } from "@egovernments/digit-ui-svg-components"; +import { convertJsonToXlsx } from "../utils/jsonToExcelBlob"; +import { Button } from "@egovernments/digit-ui-react-components"; +import { useHistory } from "react-router-dom"; +import { Link } from "react-router-dom/cjs/react-router-dom.min"; +import { PRIMARY_THEME_COLOR } from "../configs/constants"; + +const MicroplanCreatedScreen = memo(({ microplanData, ...props }) => { + const { t } = useTranslation(); + const history = useHistory(); + + const downloadMicroplan = async () => { + try { + if (!microplanData?.microplanPreview) return; + let data = _.cloneDeep(microplanData?.microplanPreview?.previewData); + data[0] = data[0].map((item) => t(item)); + for (let i in data) { + data[i] = data[i].map((item) => (item ? t(item) : t("NO_DATA"))); + } + + const blob = await convertJsonToXlsx({ [microplanData?.microplanDetails?.name]: data }); + + if (!blob) { + return; + } + + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = url; + + const fileNameParts = microplanData?.microplanDetails?.name; + if (!fileNameParts) { + return; + } + + link.download = fileNameParts; + link.click(); + URL.revokeObjectURL(url); + } catch (error) { + console.error(`Failed to download microplan: ${error.message}`, error); + } + }; + + const clickGoHome = () => { + history.push("/microplan-ui/employee"); + }; + + return ( +
+
+
+ +
+

{t("MICROPLAN_GENERATED_SUCCESSFULLY_DESCRIPTIION")}

+
+
+
+ + + {/* Back button */} +
+ ); +}); + +export default MicroplanCreatedScreen; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js new file mode 100644 index 00000000000..798365da95f --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js @@ -0,0 +1,294 @@ +import React, { Fragment, useState, useEffect, useCallback } from "react"; +import { + Card, + CardSubHeader, + CardSectionHeader, + StatusTable, + Row, + Loader, + LabelFieldPair, + CardLabel, + TextInput, + LoaderWithGap, +} from "@egovernments/digit-ui-react-components"; +import { useTranslation } from "react-i18next"; +import { tourSteps } from "../configs/tourSteps"; +import { useMyContext } from "../utils/context"; +import { InfoCard, Modal, Toast } from "@egovernments/digit-ui-components"; +import { CloseButton, ModalHeading } from "./CommonComponents"; +import { PRIMARY_THEME_COLOR } from "../configs/constants"; +import SearchPlanConfig from "../services/SearchPlanConfig"; + +const page = "microplanDetails"; + +const MicroplanDetails = ({ + MicroplanName = "default", + campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, + microplanData, + setMicroplanData, + checkDataCompletion, + setCheckDataCompletion, + currentPage, + pages, + setToast, + ...props +}) => { + const { t } = useTranslation(); + const [microplan, setMicroplan] = useState(Digit.SessionStorage.get("microplanData")?.microplanDetails?.name); + const { state, dispatch } = useMyContext(); + const [modal, setModal] = useState("none"); + // const [toast, setToast] = useState(); + const [showNamingConventions, setShowNamingConventions] = useState(false); + const [loader, setLoader] = useState(false); + + //fetch campaign data + const { id = "" } = Digit.Hooks.useQueryParams(); + const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( + { + CampaignDetails: { + tenantId: Digit.ULBService.getCurrentTenantId(), + ids: [id], + }, + }, + { + enabled: !!id, + select: (data) => { + const campaignCard = [ + { + label: t("CAMPAIGN_NAME"), + value: data?.campaignName ? data?.campaignName : t("ES_COMMON_NA"), + }, + { + label: t(`CAMPAIGN_TYPE`), + value: data?.projectType ? t(`CAMPAIGN_TYPE_${data?.projectType}`) : t("ES_COMMON_NA"), + }, + { + label: t(`CAMPAIGN_BENEFICIARY_TYPE`), + value: data?.additionalDetails?.beneficiaryType + ? t(`CAMPAIGN_BENEFICIARY_TYPE${data?.additionalDetails?.beneficiaryType}`) + : t("ES_COMMON_NA"), + }, + { + label: t("CAMPAIGN_DATE"), + value: data.startDate + ? data.endDate + ? `${Digit.DateUtils.ConvertEpochToDate(data.startDate)} - ${Digit.DateUtils.ConvertEpochToDate(data.endDate)}` + : Digit.DateUtils.ConvertEpochToDate(data.startDate) + : t("ES_COMMON_NA"), + }, + ]; + return campaignCard; + }, + } + ); + + // Set TourSteps + useEffect(() => { + const tourData = tourSteps(t)?.[page] || {}; + if (state?.tourStateData?.name === page) return; + dispatch({ + type: "SETINITDATA", + state: { tourStateData: tourData }, + }); + }, []); + + // Save data to ssn of data change + useEffect(() => { + setMicroplanData((previous) => ({ + ...previous, + microplanDetails: { + name: microplan, + }, + })); + }, [microplan]); + + useEffect(() => { + if (checkDataCompletion !== "true" || !setCheckDataCompletion) return; + + updateData(true); + }, [checkDataCompletion]); + + // UseEffect to add a event listener for keyboard + useEffect(() => { + window.addEventListener("keydown", handleKeyPress); + + return () => window.removeEventListener("keydown", handleKeyPress); + }, [modal]); + + const handleKeyPress = (event) => { + // if (modal !== "upload-guidelines") return; + if (["x", "Escape"].includes(event.key)) { + // Perform the desired action when "x" or "esc" is pressed + // if (modal === "upload-guidelines") + setCheckDataCompletion("false"); + setModal("none"); + } + }; + const validateMicroplanName = async () => { + try { + setLoader("LOADING"); + const body = { + PlanConfigurationSearchCriteria: { + name: microplan, + tenantId: Digit.ULBService.getCurrentTenantId(), + }, + }; + const response = await SearchPlanConfig(body); + if (response?.PlanConfiguration?.length === 0) { + return true; + } + if (response?.PlanConfiguration?.length === 1) { + if (response?.PlanConfiguration[0].id === microplanData?.planConfigurationId) { + setLoader(); + return true; + } + } + setLoader(); + return false; + } catch (error) { + console.error("Error while checking microplan name duplication: ", error.message); + setLoader(); + return false; + } + }; + // check if data has changed or not + const updateData = useCallback( + async (check) => { + if (checkDataCompletion !== "true" || !setCheckDataCompletion) return; + if (!microplan || !validateName(microplan)) { + setCheckDataCompletion("false"); + setShowNamingConventions(true); + return setToast({ state: "error", message: t("ERROR_MICROPLAN_NAME_CRITERIA") }); + } + const valid = await validateMicroplanName(); + if (!valid) { + setToast({ state: "error", message: t("ERROR_DUPLICATE_MICROPLAN_NAME") }); + setCheckDataCompletion("false"); + return; + } + if (check) { + setMicroplanData((previous) => ({ + ...previous, + microplanDetails: { + name: microplan, + }, + })); + if (!["", null, undefined].includes(microplan)) { + setCheckDataCompletion("valid"); + } else { + setCheckDataCompletion("invalid"); + } + } else { + if (!["", null, undefined].includes(microplanData?.microplanDetails?.name)) { + setCheckDataCompletion("valid"); + } else { + setCheckDataCompletion("invalid"); + } + } + }, + [checkDataCompletion, microplan, microplanData, setCheckDataCompletion, setMicroplanData, validateMicroplanName] + ); + + // const cancelUpdateData = useCallback(() => { + // setCheckDataCompletion(false); + // setModal('none'); + // }, [setCheckDataCompletion, setModal]); + function validateName(name) { + const microplanNamingRegxString = state?.UIConfiguration?.find((item) => item.name === "microplanNamingRegx")?.microplanNamingRegx; + const namePattern = new RegExp(microplanNamingRegxString); + return namePattern.test(name); + } + const onChangeMicroplanName = (e) => { + setMicroplan(e.target.value); + }; + + if (isCampaignLoading) { + return ; + } + + return ( + <> + {loader && } + + + {t("CAMPAIGN_DETAILS")} + + + + {campaignData?.length > 0 && + campaignData?.map((row, idx) => { + return ( + + ); + })} + + + + {t("NAME_YOUR_MP")} +

{t("MP_FOOTER")}

+ + + {`${t("NAME_OF_MP")} `}

*

+
+
+ +
+
+
+ + {state?.UIConfiguration?.find((item) => item.name === "microplanNamingConvention")?.microplanNamingConvention?.map((item, index) => ( +
+

+ {t(index + 1)}. +

+

+ {t(item)} +

+
+ ))} +
, + ]} + /> + + ); +}; + +export default MicroplanDetails; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js new file mode 100644 index 00000000000..644a1fa3a95 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js @@ -0,0 +1,1292 @@ +import { CardLabel, Header, Loader, MultiSelectDropdown, TextInput, Toast } from "@egovernments/digit-ui-components"; +import React, { memo, useCallback, useEffect, useMemo, useState, Fragment, useRef } from "react"; +import { useTranslation } from "react-i18next"; +import { processHierarchyAndData, findParent, fetchDropdownValues } from "../utils/processHierarchyAndData"; +import { CloseButton, ModalHeading } from "./CommonComponents"; +import { EXCEL, GEOJSON, PRIMARY_THEME_COLOR, SHAPEFILE, commonColumn } from "../configs/constants"; +import { Button, LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; +import { tourSteps } from "../configs/tourSteps"; +import { useMyContext } from "../utils/context"; +import { timeLineOptions } from "../configs/timeLineOptions.json"; +import { useNumberFormatter } from "../hooks/useNumberFormatter"; + +const page = "microplanPreview"; + +const MicroplanPreview = ({ + campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, + microplanData, + setMicroplanData, + checkDataCompletion, + setCheckDataCompletion, + currentPage, + pages, + navigationEvent, + setToast, + ...props +}) => { + const { mutate: UpdateMutate } = Digit.Hooks.microplan.useUpdatePlanConfig(); + const userInfo = Digit.SessionStorage.get("User")?.info; + const { id: campaignId = "" } = Digit.Hooks.useQueryParams(); + const { t } = useTranslation(); + const [hypothesisAssumptionsList, setHypothesisAssumptionsList] = useState([]); + const [data, setData] = useState([]); + const [dataToShow, setDataToShow] = useState([]); + const [joinByColumns, setJoinByColumns] = useState([]); + const [validationSchemas, setValidationSchemas] = useState([]); + const [resources, setResources] = useState([]); + const [formulaConfiguration, setFormulaConfiguration] = useState([]); + const [boundarySelections, setBoundarySelections] = useState({}); // state for hierarchy from the data available from uploaded data + const [boundaryData, setBoundaryData] = useState({}); // State for boundary data + // const [toast, setToast] = useState(); + const [modal, setModal] = useState("none"); + const [operatorsObject, setOperatorsObject] = useState([]); + + const [loaderActivation, setLoaderActivation] = useState(false); + + const [userEditedResources, setUserEditedResources] = useState({}); // state to maintain a record of the resources that the user has edited ( boundaryCode : {resource : value}) + const [microplanPreviewAggregates, setMicroplaPreviewAggregates] = useState(); + const { state, dispatch } = useMyContext(); + const [updateHypothesis, setUpdateHypothesis] = useState(false); + //fetch campaign data + const { id = "" } = Digit.Hooks.useQueryParams(); + const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( + { + CampaignDetails: { + tenantId: Digit.ULBService.getCurrentTenantId(), + ids: [id], + }, + }, + { + enabled: !!id, + } + ); + + // request body for boundary hierarchy api + const reqCriteria = { + url: `/boundary-service/boundary-hierarchy-definition/_search`, + params: {}, + body: { + BoundaryTypeHierarchySearchCriteria: { + tenantId: Digit.ULBService.getStateId(), + hierarchyType: campaignData?.hierarchyType, + }, + }, + config: { + enabled: !!campaignData?.hierarchyType, + select: (data) => { + return ( + data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map((item) => ({ + ...item, + parentBoundaryType: item?.parentBoundaryType + ? `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.parentBoundaryType)}` + : null, + boundaryType: `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}`, + })) || {} + ); + }, + }, + }; + const { isLoading: ishierarchyLoading, data: hierarchyRawData } = Digit.Hooks.useCustomAPIHook(reqCriteria); + const hierarchy = useMemo(() => { + return hierarchyRawData?.map((item) => item?.boundaryType); + }, [hierarchyRawData]); + // Set TourSteps + useEffect(() => { + const tourData = tourSteps(t)?.[page] || {}; + if (state?.tourStateData?.name === page) return; + dispatch({ + type: "SETINITDATA", + state: { tourStateData: tourData }, + }); + }, []); + + // UseEffect to extract data on first render + useEffect(() => { + if (microplanData && (microplanData?.ruleEngine || microplanData?.hypothesis)) { + const hypothesisAssumptions = microplanData?.hypothesis || []; + const formulaConfiguration = microplanData?.ruleEngine?.filter((item) => Object.values(item).every((key) => key !== "")) || []; + if (hypothesisAssumptions.length !== 0 && hypothesisAssumptionsList.length === 0) { + setHypothesisAssumptionsList(hypothesisAssumptions); + } + if (formulaConfiguration.length !== 0) { + setFormulaConfiguration(formulaConfiguration); + } + } + if (microplanData?.microplanPreview?.userEditedResources) { + setUserEditedResources(microplanData?.microplanPreview?.userEditedResources); + } + }, []); + + // Fetch and assign MDMS data + useEffect(() => { + if (!state) return; + let UIConfiguration = state?.UIConfiguration; + let schemas = state?.Schemas; + let resourcelist = state?.Resources; + let microplanPreviewAggregatesList = state?.MicroplanPreviewAggregates; + microplanPreviewAggregatesList = microplanPreviewAggregatesList.find((item) => item.campaignType === campaignType)?.data; + if (schemas) setValidationSchemas(schemas); + resourcelist = resourcelist.find((item) => item.campaignType === campaignType)?.data; + if (resourcelist) setResources(resourcelist); + if (UIConfiguration) { + const joinWithColumns = UIConfiguration.find((item) => item.name === "microplanPreview")?.joinWithColumns; + setJoinByColumns(joinWithColumns); + } + let temp; + if (UIConfiguration) temp = UIConfiguration.find((item) => item.name === "ruleConfigure"); + if (temp?.ruleConfigureOperators) { + setOperatorsObject(temp.ruleConfigureOperators); + } + if (microplanPreviewAggregatesList) setMicroplaPreviewAggregates(microplanPreviewAggregatesList); + }, []); + + // UseEffect for checking completeness of data before moveing to next section + useEffect(() => { + if (!dataToShow || checkDataCompletion !== "true" || !setCheckDataCompletion) return; + let check = filterObjects(hypothesisAssumptionsList, microplanData?.hypothesis); + if (check.length === 0) { + if (navigationEvent?.name === "next") return setModal("confirm-microplan-generation"); + return createMicroplan(false); + } + setModal("confirm-apply-changed-hypothesis"); + }, [checkDataCompletion]); + + // check if data has changed or not + const updateData = useCallback( + (doPerform) => { + // Update the microplan data with selected hierarchy and resources + // This function also handles setting the completion check based on the action to be performed + if (!setMicroplanData) return; + try { + let tempData = filterMicroplanDataToShowWithHierarchySelection(data, {}, hierarchy); + // Adding resources to the data we need to show + tempData = Digit.Utils.microplan.addResourcesToFilteredDataToShow( + tempData, + resources, + hypothesisAssumptionsList, + formulaConfiguration, + userEditedResources, + t + ); + setMicroplanData((previous) => ({ + ...previous, + microplanPreview: { + previewData: tempData, + userEditedResources, + }, + })); + if (doPerform) { + return setCheckDataCompletion("perform-action"); + } + setCheckDataCompletion("false"); + } catch (error) { + console.error("Failed to update data:", error); + } + }, + [ + resources, + boundarySelections, + hierarchy, + hypothesisAssumptionsList, + formulaConfiguration, + userEditedResources, + setMicroplanData, + setCheckDataCompletion, + ] + ); + + const cancelUpdateData = useCallback(() => { + setUpdateHypothesis(false); + setModal("confirm-microplan-generation"); + }, [setCheckDataCompletion, setModal]); + + useEffect(() => { + if (boundarySelections && Object.values(boundarySelections).every((item) => item.length === 0) && hierarchy) { + let tempBoundarySelection = {}; + for (const item of hierarchy) { + tempBoundarySelection[item] = []; + } + setBoundarySelections(tempBoundarySelection); + } + }, [hierarchy]); + + // UseEffect to add a event listener for keyboard + useEffect(() => { + window.addEventListener("keydown", handleKeyPress); + + return () => window.removeEventListener("keydown", handleKeyPress); + }, [modal]); + + const handleKeyPress = (event) => { + // if (modal !== "upload-guidelines") return; + if (["x", "Escape"].includes(event.key)) { + // Perform the desired action when "x" or "esc" is pressed + setCheckDataCompletion("false"); + setModal("none"); + } + }; + + const cancleNavigation = () => { + if (navigationEvent?.name !== "next") setCheckDataCompletion("false"); + setModal("none"); + }; + + const createMicroplan = useCallback( + (doCreation) => { + if (!hypothesisAssumptionsList || !setMicroplanData) return; + const updateDataWrapper = () => { + if (doCreation || navigationEvent?.name !== "next") { + return updateData(true); + } + updateData(false); + }; + const setCheckDataCompletionWrapper = (value) => { + if (!doCreation) { + return setCheckDataCompletion("false"); + } + setCheckDataCompletion(value); + }; + const microData = updateHypothesis ? updateMicroplanData(hypothesisAssumptionsList) : microplanData; + setLoaderActivation(true); + updateHyothesisAPICall( + microData, + setMicroplanData, + operatorsObject, + microData?.microplanDetails?.name, + campaignId, + UpdateMutate, + setToast, + updateDataWrapper, + setLoaderActivation, + doCreation && navigationEvent?.name === "next" ? "GENERATED" : "DRAFT", + cancleNavigation, + state, + campaignType, + navigationEvent, + setCheckDataCompletionWrapper, + t + ); + + setModal("none"); + }, + [ + hypothesisAssumptionsList, + setMicroplanData, + operatorsObject, + campaignId, + UpdateMutate, + setToast, + updateData, + setLoaderActivation, + navigationEvent, + t, + ] + ); + + const updateMicroplanData = useCallback( + (hypothesisAssumptionsList) => { + let microData = {}; + setMicroplanData((previous) => { + microData = { ...previous, hypothesis: hypothesisAssumptionsList }; + return microData; + }); + return microData; + }, + [setMicroplanData] + ); + + // Set microplan preview data + useEffect(() => { + if (data?.length !== 0 || !hierarchyRawData || !hierarchy || validationSchemas?.length === 0) return; + + let combinedData = fetchMicroplanPreviewData(campaignType, microplanData, validationSchemas, hierarchy); + // process and form hierarchy + if (combinedData && hierarchy) { + var { hierarchyLists, hierarchicalData } = processHierarchyAndData(hierarchyRawData, [combinedData]); + setBoundaryData({ Microplan: { hierarchyLists, hierarchicalData } }); + } + if (combinedData) { + setData(combinedData); + setDataToShow(combinedData); + } + }, [hierarchy, hierarchyRawData, microplanData]); + + useEffect(() => { + if (!boundarySelections && !resources) return; + let tempData = filterMicroplanDataToShowWithHierarchySelection(data, boundarySelections, hierarchy); + // Adding resources to the data we need to show + tempData = Digit.Utils.microplan.addResourcesToFilteredDataToShow( + tempData, + resources, + hypothesisAssumptionsList, + formulaConfiguration, + userEditedResources, + t + ); + setDataToShow(tempData); + setMicroplanData((previous) => ({ ...previous, microplanPreview: { ...previous.microplanPreview, previewData: tempData, userEditedResources } })); + }, [boundarySelections, resources, hypothesisAssumptionsList, userEditedResources]); + + if (isCampaignLoading || ishierarchyLoading) { + return ( +
+ +
+ ); + } + + return ( + <> +
+
+

{t(campaignData?.campaignName)}

+
{t(microplanData?.microplanDetails?.name)}
+

{t("MICROPLAN_PREVIEW_CREATE_BY", { username: userInfo?.name })}

+
+
+
+ +
+
+ +
+
+

{t("MICROPLAN_PREVIEW_HYPOTHESIS_HEADING")}

+

{t("MICROPLAN_PREVIEW_HYPOTHESIS_INSTRUCTIONS")}

+ +
+
+ {dataToShow?.length != 0 ? ( + + ) : ( +
{t("NO_DATA_AVAILABLE")}
+ )} +
+
+ {modal === "confirm-apply-changed-hypothesis" && ( + } + actionCancelLabel={t("YES")} + actionCancelOnSubmit={() => { + setUpdateHypothesis(true); + setModal("confirm-microplan-generation"); + }} + actionSaveLabel={t("NO")} + actionSaveOnSubmit={cancelUpdateData} + formId="modal-action" + > + + + )} + {modal === "confirm-microplan-generation" && ( + } + actionCancelLabel={t("YES")} + actionCancelOnSubmit={() => createMicroplan(true)} + actionSaveLabel={t("NO")} + actionSaveOnSubmit={() => createMicroplan(false)} + formId="modal-action" + > +
+

{t("INSTRUCTIONS_MICROPLAN_GENERATION_CONFIRMATION")}

+
+
+ )} +
+ {loaderActivation && } + + ); +}; + +const HypothesisValues = memo(({ boundarySelections, hypothesisAssumptionsList, setHypothesisAssumptionsList, setToast, setModal, t }) => { + const [tempHypothesisList, setTempHypothesisList] = useState(hypothesisAssumptionsList || []); + const { valueChangeHandler } = useHypothesis(tempHypothesisList, hypothesisAssumptionsList); + const contentRef = useRef(null); + const [isScrollable, setIsScrollable] = useState(false); + + const applyNewHypothesis = () => { + if (tempHypothesisList.some((item) => item.active && parseFloat(item.value) === 0)) { + setToast({ state: "error", message: t("ERROR_HYPOTHESIS_VALUE_SHOULD_NOT_BE_ZERO") }); + return; + } + if (Object.keys(boundarySelections).length !== 0 && Object.values(boundarySelections)?.every((item) => item?.length !== 0)) + return setToast({ state: "error", message: t("HYPOTHESIS_CAN_BE_ONLY_APPLIED_ON_ADMIN_LEVEL_ZORO") }); + setHypothesisAssumptionsList(tempHypothesisList); + }; + const checkScrollbar = () => { + if (contentRef.current) { + setIsScrollable(contentRef.current.scrollHeight > contentRef.current.clientHeight); + } + }; + + useEffect(() => { + // Initial check + checkScrollbar(); + + // Check on resize + window.addEventListener("resize", checkScrollbar); + + // Cleanup event listeners on component unmount + return () => { + window.removeEventListener("resize", checkScrollbar); + }; + }, []); + + useEffect(() => { + const content = contentRef.current; + content.addEventListener("scroll", checkScrollbar); + + return () => { + content.removeEventListener("scroll", checkScrollbar); + }; + }, [contentRef]); + + return ( +
+
+ {tempHypothesisList + .filter((item) => item?.active) + ?.filter((item) => item.key !== "") + .map((item, index) => ( +
+

{t(item?.key)}

+
+ {/* Dropdown for boundaries */} + + valueChangeHandler({ item, newValue: value?.target?.value }, setTempHypothesisList, boundarySelections, setToast, t) + } + disable={false} + /> +
+
+ ))} +
+
+
+
+ ); +}); + +const BoundarySelection = memo(({ boundarySelections, setBoundarySelections, boundaryData, hierarchy, t }) => { + const [processedHierarchy, setProcessedHierarchy] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [changedBoundaryType, setChangedBoundaryType] = useState(""); + + // Filtering out dropdown values + useEffect(() => { + if (!boundaryData || !hierarchy) return; + + let processedHierarchyTemp = fetchDropdownValues( + boundaryData, + processedHierarchy.length !== 0 ? processedHierarchy : hierarchy, + boundarySelections, + changedBoundaryType + ); + setProcessedHierarchy(processedHierarchyTemp); + setIsLoading(false); + }, [boundaryData, hierarchy, boundarySelections]); + + return ( +
+ {isLoading && } + {processedHierarchy?.map((item, index) => ( +
+ {t(item?.boundaryType)} + {item?.parentBoundaryType === null ? ( + 5 ? { height: "13.75rem" } : {}} + type={"multiselectdropdown"} + t={t} + options={item?.dropDownOptions || []} + optionsKey="name" + addSelectAllCheck={true} + onSelect={(e) => { + setChangedBoundaryType(item?.boundaryType); + Digit.Utils.microplan.handleSelection( + e, + item?.boundaryType, + boundarySelections, + hierarchy, + setBoundarySelections, + boundaryData, + setIsLoading + ); + }} + /> + ) : ( + 5 ? { height: "13.75rem" } : {}} + type={"multiselectdropdown"} + t={t} + options={Digit.Utils.microplan.processDropdownForNestedMultiSelect(item?.dropDownOptions) || []} + optionsKey="name" + addSelectAllCheck={true} + onSelect={(e) => { + setChangedBoundaryType(item?.boundaryType); + Digit.Utils.microplan.handleSelection( + e, + item?.boundaryType, + boundarySelections, + hierarchy, + setBoundarySelections, + boundaryData, + setIsLoading + ); + }} + variant="nestedmultiselect" + /> + )} +
+ ))} +
+ ); +}); + +const DataPreview = memo( + ({ previewData, isCampaignLoading, ishierarchyLoading, resources, userEditedResources, setUserEditedResources, modal, setModal, data, t }) => { + if (!previewData) return; + const [tempResourceChanges, setTempResourceChanges] = useState(userEditedResources); + const [selectedRow, setSelectedRow] = useState(); + const conmmonColumnIndex = useMemo(() => { + return previewData?.[0]?.indexOf(commonColumn); + }, [previewData]); + if (isCampaignLoading || ishierarchyLoading) { + return ( +
+ +
+ ); + } + + const rowClick = useCallback((rowIndex) => { + setSelectedRow(rowIndex); + setModal("change-preview-data"); + }, []); + + const finaliseRowDataChange = () => { + setUserEditedResources(tempResourceChanges); + setModal("none"); + setSelectedRow(undefined); + }; + + const modalCloseHandler = () => { + setModal("none"); + setSelectedRow(undefined); + }; + + return ( +
+
+ + + + {previewData[0].map((header, columnIndex) => ( + + ))} + + + + {previewData.slice(1).map((rowData, rowIndex) => { + const rowDataList = Object.values(previewData[0]).map((header, cellIndex) => ( + + )); + return ( + { + rowClick(rowIndex + 1); + }} + // style={{...(userEditedResources?.[rowData?.[conmmonColumnIndex]] && Object.keys(userEditedResources?.[rowData?.[conmmonColumnIndex]]).length !==0 + // ? { borderL: "1px solid rgba(244, 119, 56, 0.12)" } + // : {}),}} + > + {rowDataList} + + ); + })} + +
+ {t(header)} +
+ {cellIndex === 0 && + userEditedResources?.[rowData?.[conmmonColumnIndex]] && + Object.keys(userEditedResources?.[rowData?.[conmmonColumnIndex]]).length !== 0 &&
} + + {rowData[cellIndex] || rowData[cellIndex] === 0 ? rowData[cellIndex] : t("NO_DATA")} +
+
+ {modal === "change-preview-data" && ( +
+ } + headerBarEnd={} + actionCancelLabel={t("CANCLE")} + actionCancelOnSubmit={modalCloseHandler} + actionSaveLabel={t("SAVE_CHANGES")} + actionSaveOnSubmit={finaliseRowDataChange} + formId="modal-action" + > + + +
+ )} +
+ ); + } +); + +// get schema for validation +const getRequiredColumnsFromSchema = (campaignType, microplanData, schemas) => { + if (!schemas || !microplanData || !microplanData?.upload || !campaignType) return []; + let sortData = []; + if (microplanData?.upload) { + for (const value of microplanData.upload) { + if (value.active && value?.error === null) { + sortData.push({ section: value.section, fileType: value?.fileType }); + } + } + } + const filteredSchemas = + schemas?.filter((schema) => { + if (schema.campaignType) { + return schema.campaignType === campaignType && sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); + } + return sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); + }) || []; + + let finalData = []; + let tempdata; + // tempdata = filteredSchemas + // ?.map((item) => + // Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => { + // if (value?.isLocationDataColumns) { + // acc.push(key); + // } + // return acc; + // }, []) + // ) + // .flatMap((item) => item) + // .filter((item) => !!item); + // finalData = [...finalData, ...tempdata]; + tempdata = filteredSchemas + ?.map((item) => + Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.isRuleConfigureInputs && value?.toShowInMicroplanPreview) { + acc.push(key); + } + return acc; + }, []) + ) + .flat() + .filter((item) => !!item); + finalData = [...finalData, ...tempdata]; + + tempdata = filteredSchemas + ?.map((item) => + Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.toShowInMicroplanPreview) acc.push(key); + return acc; + }, []) + ) + .flat() + .filter((item) => !!item); + finalData = [...finalData, ...tempdata]; + return [...new Set(finalData)]; +}; + +/** + * Combines two datasets based on a common column, duplicating rows from data1 for each matching row in data2. + * The final dataset's columns and their order are determined by listOfColumnsNeededInFinalData. + * If data2 is not provided, rows from data1 are included with null values for missing columns. + */ +const innerJoinLists = (data1, data2, commonColumnName, listOfColumnsNeededInFinalData) => { + // Error handling: Check if data1 array is provided + if (!Array.isArray(data1)) { + throw new Error("The first data input must be an array."); + } + + // Error handling: Check if common column name is provided + if (typeof commonColumnName !== "string") { + throw new Error("Common column name must be a string."); + } + + // Error handling: Check if listOfColumnsNeededInFinalData is provided and is an array + if (!Array.isArray(listOfColumnsNeededInFinalData)) { + throw new Error("listOfColumnsNeededInFinalData must be an array."); + } + + // Find the index of the common column in the first dataset + const commonColumnIndex1 = data1[0].indexOf(commonColumnName); + + // Error handling: Check if common column exists in the first dataset + if (commonColumnIndex1 === -1) { + throw new Error(`Common column "${commonColumnName}" not found in the first dataset.`); + } + + let commonColumnIndex2 = -1; + const data2Map = new Map(); + if (data2) { + // Find the index of the common column in the second dataset + commonColumnIndex2 = data2[0].indexOf(commonColumnName); + + // Error handling: Check if common column exists in the second dataset + if (commonColumnIndex2 === -1) { + throw new Error(`Common column "${commonColumnName}" not found in the second dataset.`); + } + + // Create a map for the second dataset for quick lookup by the common column value + for (let i = 1; i < data2.length; i++) { + const row = data2[i]; + const commonValue = row[commonColumnIndex2]; + if (!data2Map.has(commonValue)) { + data2Map.set(commonValue, []); + } + data2Map.get(commonValue).push(row); + } + } + + // Determine the headers for the final combined dataset based on listOfColumnsNeededInFinalData + const combinedHeaders = listOfColumnsNeededInFinalData.filter((header) => data1[0].includes(header) || (data2 && data2[0].includes(header))); + + // Combine rows + const combinedData = [combinedHeaders]; + const addedCommonValues = new Set(); + for (let i = 1; i < data1.length; i++) { + const row1 = data1[i]; + const commonValue = row1[commonColumnIndex1]; + const rows2 = data2 ? data2Map.get(commonValue) || [[null]] : [[null]]; // Handle missing common values with a placeholder array of null + + // Check if rows2 is the placeholder array + const isPlaceholderArray = rows2.length === 1 && rows2[0].every((value) => value === null); + + // Create combined rows for each row in data2 + if (isPlaceholderArray) { + // If no corresponding row found in data2, use row from data1 with null values for missing columns + const combinedRow = combinedHeaders.map((header) => { + const index1 = data1[0].indexOf(header); + return index1 !== -1 ? row1[index1] : null; + }); + combinedData.push(combinedRow); + } else { + // If corresponding rows found in data2, combine each row from data2 with row from data1 + rows2.forEach((row2) => { + const combinedRow = combinedHeaders.map((header) => { + const index1 = data1[0].indexOf(header); + const index2 = data2 ? data2[0].indexOf(header) : -1; + return index1 !== -1 ? row1[index1] : index2 !== -1 ? row2[index2] : null; + }); + combinedData.push(combinedRow); + }); + } + addedCommonValues.add(commonValue); + } + // Add rows from data2 that do not have a matching row in data1 + if (data2) { + for (let i = 1; i < data2.length; i++) { + const row2 = data2[i]; + const commonValue = row2[commonColumnIndex2]; + if (!addedCommonValues.has(commonValue)) { + const combinedRow = combinedHeaders.map((header) => { + // const index1 = data1[0].indexOf(header); + const index2 = data2[0].indexOf(header); + return index2 !== -1 ? row2[index2] : null; + }); + combinedData.push(combinedRow); + } + } + } + + return combinedData; +}; + +// function to filter the microplan data with respect to the hierarchy selected by the user +const filterMicroplanDataToShowWithHierarchySelection = (data, selections, hierarchy, hierarchyIndex = 0) => { + if (!selections || selections?.length === 0) return data; + if (hierarchyIndex >= hierarchy?.length) return data; + const filteredHirarchyLevelList = selections?.[hierarchy?.[hierarchyIndex]]?.map((item) => item?.name); + if (!filteredHirarchyLevelList || filteredHirarchyLevelList?.length === 0) return data; + const columnDataIndexForHierarchyLevel = data?.[0]?.indexOf(hierarchy?.[hierarchyIndex]); + if (columnDataIndexForHierarchyLevel === -1) return data; + const levelFilteredData = data.filter((item, index) => { + if (index === 0) return true; + if (item?.[columnDataIndexForHierarchyLevel] && filteredHirarchyLevelList.includes(item?.[columnDataIndexForHierarchyLevel])) return true; + return false; + }); + return filterMicroplanDataToShowWithHierarchySelection(levelFilteredData, selections, hierarchy, hierarchyIndex + 1); +}; + +const AppplyChangedHypothesisConfirmation = ({ newhypothesisList, hypothesisList, t }) => { + const data = filterObjects(newhypothesisList, hypothesisList); + return ( +
+
+

{t("INSTRUCTION_PROCEED_WITH_NEW_HYPOTHESIS")}

+
+ + {t("MICROPLAN_PREVIEW_HYPOTHESIS")} + +
+ + + + + + + + + + {data?.map((row, index) => ( + + + + + + ))} + +
{t("KEYS")}{t("OLD_VALUE")}{t("NEW_VALUE")}
{t(row?.key)}{t(row?.oldValue)}{t(row?.value)}
+
+
+ ); +}; + +function filterObjects(arr1, arr2) { + if (!arr1 || !arr2) return []; + // Create a new array to store the filtered objects + let filteredArray = []; + + // Iterate through the first array + arr1.forEach((obj1) => { + // Find the corresponding object in the second array + let obj2 = _.cloneDeep(arr2.find((item) => item.key === obj1.key)); + + // If the object with the same key is found in the second array and their values are the same + if (obj2 && obj1.value !== obj2.value) { + // Push the object to the filtered array + obj1.oldValue = obj2.value; + filteredArray.push(obj1); + } + }); + + return filteredArray; +} + +const useHypothesis = (tempHypothesisList, hypothesisAssumptionsList) => { + // Handles the change in hypothesis value + const valueChangeHandler = (e, setTempHypothesisList, boundarySelections, setToast, t) => { + // Checks it the boundary filters at at root level ( given constraints ) + if (Object.keys(boundarySelections).length !== 0 && Object.values(boundarySelections)?.every((item) => item?.length !== 0)) + return setToast({ state: "error", message: t("HYPOTHESIS_CAN_BE_ONLY_APPLIED_ON_ADMIN_LEVEL_ZORO") }); + + // validating user input + if (e?.newValue.includes("+") || e?.newValue.includes("e")) return; + if ((e?.newValue < 0 || e.newValue > 10000000000) && e?.newValue !== "") return; + let value; + const decimalIndex = e.newValue.indexOf("."); + if (decimalIndex !== -1) { + const numDecimals = e.newValue.length - decimalIndex - 1; + if (numDecimals <= 2) { + value = e.newValue; + } else if (numDecimals > 2) { + value = e.newValue.substring(0, decimalIndex + 3); + } + } else value = parseFloat(e.newValue); + value = !isNaN(value) ? value : ""; + + // update the state with user input + let newhypothesisEntityIndex = hypothesisAssumptionsList.findIndex((item) => item?.id === e?.item?.id); + let unprocessedHypothesisList = _.cloneDeep(tempHypothesisList); + if (newhypothesisEntityIndex !== -1) unprocessedHypothesisList[newhypothesisEntityIndex].value = value; + setTempHypothesisList(unprocessedHypothesisList); + }; + + return { + valueChangeHandler, + }; +}; + +const updateHyothesisAPICall = async ( + microplanData, + setMicroplanData, + operatorsObject, + MicroplanName, + campaignId, + UpdateMutate, + setToast, + updateData, + setLoaderActivation, + status, + cancleNavigation, + state, + campaignType, + navigationEvent, + setCheckDataCompletion, + t +) => { + try { + let body = Digit.Utils.microplan.mapDataForApi(microplanData, operatorsObject, MicroplanName, campaignId, status); + body.PlanConfiguration["id"] = microplanData?.planConfigurationId; + body.PlanConfiguration["auditDetails"] = microplanData?.auditDetails; + if (!Digit.Utils.microplan.planConfigRequestBodyValidator(body, state, campaignType)) { + setLoaderActivation(false); + if (navigationEvent.name === "next") { + setToast({ + message: t("ERROR_DATA_NOT_SAVED"), + state: "error", + }); + setCheckDataCompletion("false"); + } else setCheckDataCompletion("perform-action"); + return; + } + await UpdateMutate(body, { + onSuccess: async (data) => { + updateData(); + setLoaderActivation(false); + setMicroplanData((previous) => ({ ...previous, microplanStatus: status })); + }, + onError: (error, variables) => { + setLoaderActivation(false); + setToast({ + message: t("ERROR_DATA_NOT_SAVED"), + state: "error", + }); + if (status === "GENERATED") cancleNavigation(); + else updateData(); + }, + }); + } catch (error) { + setLoaderActivation(false); + setToast({ + message: t("ERROR_DATA_NOT_SAVED"), + state: "error", + }); + } +}; + +// get schema for validation +const getSchema = (campaignType, type, section, schemas) => { + return schemas.find((schema) => + schema.campaignType + ? schema.campaignType === campaignType && schema.type === type && schema.section === section + : schema.type === type && schema.section === section + ); +}; + +const fetchMicroplanPreviewData = (campaignType, microplanData, validationSchemas, hierarchy) => { + try { + //Decide columns to take and their sequence + const getfilteredSchemaColumnsList = () => { + let filteredSchemaColumns = getRequiredColumnsFromSchema(campaignType, microplanData, validationSchemas) || []; + if (hierarchy) filteredSchemaColumns = [...hierarchy, commonColumn, ...filteredSchemaColumns.filter((e) => e !== commonColumn)]; + return filteredSchemaColumns; + }; + let filteredSchemaColumns = getfilteredSchemaColumnsList(); + const fetchedData = fetchMicroplanData(microplanData, campaignType, validationSchemas); + // Perform inner joins using reduce + const dataAfterJoins = fetchedData.reduce((accumulator, currentData, index) => { + if (index === 0) { + return innerJoinLists(currentData, null, commonColumn, filteredSchemaColumns); + } else { + return innerJoinLists(accumulator, currentData, commonColumn, filteredSchemaColumns); + } + }, null); + return dataAfterJoins; + } catch (error) { + console.error("Error in fetch microplan data: ", error.message); + } +}; + +const fetchMicroplanData = (microplanData, campaignType, validationSchemas) => { + if (!microplanData) return []; + + let combinesDataList = []; + // Check if microplanData and its upload property exist + if (microplanData?.upload) { + let files = microplanData?.upload; + // Loop through each file in the microplan upload + for (let fileData of files) { + const schema = getSchema(campaignType, fileData.fileType, fileData.templateIdentifier, validationSchemas); + + // Check if the file is not part of boundary or layer data origins + if (!fileData.active || !fileData.fileType || !fileData?.section) continue; // Skip files with errors or missing properties + + // Check if file contains latitude and longitude columns + if (fileData?.data) { + // Check file type and update data availability accordingly + switch (fileData?.fileType) { + case EXCEL: { + // extract dada + const mergedData = schema?.template?.hierarchyLevelWiseSheets + ? Object.values(fileData?.data).flatMap((data) => data) + : Object.values(fileData?.data)?.[0]; + + let commonColumnIndex = mergedData?.[0]?.indexOf(commonColumn); + + let uniqueEntries; + if (commonColumnIndex !== undefined) + uniqueEntries = schema?.template?.hierarchyLevelWiseSheets + ? Array.from(new Map(mergedData.map((entry) => [entry[commonColumnIndex], entry])).values()) + : mergedData; + if (uniqueEntries) combinesDataList.push(uniqueEntries); + break; + } + case GEOJSON: + case SHAPEFILE: { + // Extract keys from the first feature's properties + var keys = Object.keys(fileData?.data.features[0].properties); + + // Extract corresponding values for each feature + const values = fileData?.data?.features.map((feature) => { + // list with features added to it + const temp = keys.map((key) => { + // if (feature.properties[key] === "") { + // return null; + // } + return feature.properties[key]; + }); + return temp; + }); + + let data = [keys, ...values]; + combinesDataList.push(data); + } + } + } + } + } + return combinesDataList; +}; + +const EditResourceData = ({ previewData, selectedRow, resources, tempResourceChanges, setTempResourceChanges, data, t }) => { + const conmmonColumnData = useMemo(() => { + const index = previewData?.[0]?.indexOf(commonColumn); + if (index == -1) return; + return previewData?.[selectedRow]?.[index]; + }, [previewData]); + + const valueChangeHandler = (item, value) => { + if (!conmmonColumnData) return; + if (isNaN(value) || (!isFinite(value) && value !== "")) return; + let changedDataAgainstBoundaryCode = tempResourceChanges?.[conmmonColumnData] || {}; + changedDataAgainstBoundaryCode[item] = value == "" ? undefined : parseFloat(value); + setTempResourceChanges((previous) => ({ ...previous, [conmmonColumnData]: changedDataAgainstBoundaryCode })); + }; + + return ( +
+ + + + + + + + + + {data[0].map((item) => { + let index = data?.[0]?.indexOf(item); + if (index === -1) return; + const currentData = data?.[selectedRow]?.[index]; + return ( + + + + + + ); + })} + {resources.map((item) => { + let index = previewData?.[0]?.indexOf(item); + if (index === -1) return; + const currentData = previewData?.[selectedRow]?.[index]; + + return ( + + + + + + ); + })} + +
{t("COLUMNS")}{t("OLD_VALUE")}{t("NEW_VALUE")}
+

{t(item)}

+
+

{currentData || t("NO_DATA")}

+
+ +
+

{t(item)}

+
+

{currentData || t("NO_DATA")}

+
+ valueChangeHandler(item, value.target.value)} + /> +
+
+ ); +}; + +const Aggregates = memo(({ microplanPreviewAggregates, dataToShow, NumberFormatMappingForTranslation, t }) => { + const { formatNumber } = useNumberFormatter(NumberFormatMappingForTranslation?.reduce((acc, obj) => Object.assign(acc, obj), {})); + + if (!microplanPreviewAggregates) return null; + return ( +
+ {microplanPreviewAggregates.map((item, index) => { + const aggregate = calculateAggregateValue(item, dataToShow); + return ( +
+

{isNaN(parseInt(aggregate)) ? 0 : formatNumber(parseInt(aggregate))}

+

{typeof item === "object" && item.name ? t(item.name) : t(item)}

+
+ ); + })} +
+ ); +}); + +const calculateAggregateValue = (aggregateName, dataToShow) => { + if (!aggregateName || !dataToShow || dataToShow.length === 0) return; + let aggregateNameList = aggregateName; + if (typeof aggregateName !== "object") aggregateNameList = { name: aggregateName, entities: [aggregateName] }; + let aggregateData = 0; + if (aggregateNameList) + for (const item of aggregateNameList.entities) { + const columnIndex = dataToShow?.[0].indexOf(item); + dataToShow.slice(1).forEach((e) => { + if (e?.[columnIndex]) aggregateData = aggregateData + Number(e[columnIndex]); + }); + } + return aggregateData; +}; + +export default MicroplanPreview; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js new file mode 100644 index 00000000000..9a1dd8f5500 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js @@ -0,0 +1,34 @@ +import { EmployeeModuleCard, WorksMgmtIcon } from "@egovernments/digit-ui-react-components"; +import React from "react"; +import { useTranslation } from "react-i18next"; + +const ROLES = { + MICROPLAN: ["MICROPLAN_ADMIN"], +}; + +const MicroplanningCard = () => { + const { t } = useTranslation(); + const tenantId = Digit.ULBService.getCurrentTenantId(); + + const generateLink = (labelKey, pathSuffix) => { + return { + label: t(labelKey), + link: `/${window?.contextPath}/employee/microplanning/${pathSuffix}`, + roles: ROLES.MICROPLAN, + }; + }; + + let links = [generateLink("CREATE_NEW_MICROPLAN", "select-campaign"), generateLink("OPEN_SAVED_MICROPLANS", "saved-microplans")]; + + links = links.filter((link) => (link?.roles && link?.roles?.length > 0 ? Digit.Utils.didEmployeeHasAtleastOneRole(link?.roles) : true)); + + const propsForModuleCard = { + Icon: , + moduleName: t("Microplanning"), + kpis: [], + links: links, + }; + return ; +}; + +export default MicroplanningCard; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js new file mode 100644 index 00000000000..2a35e9c0995 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js @@ -0,0 +1,29 @@ +import { Help, Tutorial, useTourState } from "@egovernments/digit-ui-react-components"; +import React, { Fragment } from "react"; +import { useTranslation } from "react-i18next"; +import { useLocation } from "react-router-dom"; +import { useMyContext } from "../utils/context"; +import { PRIMARY_THEME_COLOR } from "../configs/constants"; + +const MicroplanningHeader = () => { + const { tourState, setTourState } = useTourState(); + const { state } = useMyContext(); + const { t } = useTranslation(); + //using location.pathname we can update the stepIndex accordingly when help is clicked from any other screen(other than home screen) + const { pathname } = useLocation(); + + const startTour = () => { + if (state?.tourStateData) setTourState(state.tourStateData); + }; + + return ( + <> + +
+ +
+ + ); +}; + +export default MicroplanningHeader; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js new file mode 100644 index 00000000000..0792ee2e52d --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js @@ -0,0 +1,158 @@ +import React, { useEffect } from "react"; +import { PopUp, HeaderBar, Toast, CloseButton, ButtonSelector } from "@egovernments/digit-ui-react-components"; +import { Close } from "@egovernments/digit-ui-svg-components"; +import { PRIMARY_THEME_COLOR } from "../configs/constants"; + +const Modal = ({ + headerBarMain, + headerBarEnd, + popupStyles, + children = {}, + actionCancelLabel, + actionCancelOnSubmit, + actionSaveLabel, + actionSaveOnSubmit, + error, + setError, + formId, + isDisabled, + hideSubmit, + style = {}, + footerLeftButtonstyle = {}, + footerRightButtonstyle = {}, + footerLeftButtonBody, + footerRightButtonBody, + popupModuleMianStyles, + headerBarMainStyle, + isOBPSFlow = false, + popupModuleActionBarStyles = {}, +}) => { + /** + * TODO: It needs to be done from the desgin changes + */ + const mobileView = Digit.Utils.browser.isMobile(); + useEffect(() => { + document.body.style.overflowY = "hidden"; + return () => { + document.body.style.overflowY = "auto"; + }; + }, []); + + return ( + +
+ +
+ {children} +
+ {actionCancelLabel || footerLeftButtonBody ? ( + 0 ? style : footerLeftButtonstyle} + /> + ) : null} + {!hideSubmit ? ( + 0 ? style : footerRightButtonstyle} + /> + ) : null} +
+
+
+ {error && setError(null)} type="error" />} +
+ ); +}; + +const moduleActionBarStyle = (isOBPSFlow, popupModuleActionBarStyles) => { + return isOBPSFlow + ? !mobileView + ? { marginRight: "18px" } + : { position: "absolute", bottom: "5%", right: "10%", left: window.location.href.includes("employee") ? "0%" : "7%" } + : popupModuleActionBarStyles; +}; + +// Wrapper for modal +export const ModalWrapper = ({ + closeModal, + LeftButtonHandler, + RightButtonHandler, + footerLeftButtonBody, + footerRightButtonBody, + header, + bodyText, + body, + popupStyles, + headerBarMainStyle, + popupModuleActionBarStyles, + hideSubmit, + closeButton = false, + actionCancelLabel, +}) => { + return ( + + {" "} + + + ) : ( + "" + ) + } + actionCancelOnSubmit={LeftButtonHandler} + actionSaveOnSubmit={RightButtonHandler} + formId="microplanning" + popupStyles={{ width: "33.375rem", borderRadius: "0.25rem", ...(popupStyles ? popupStyles : {}) }} + headerBarMainStyle={{ margin: 0, width: "33.375rem", overflow: "hidden", ...(headerBarMainStyle ? headerBarMainStyle : {}) }} + popupModuleMianStyles={{ margin: 0, padding: 0 }} + popupModuleActionBarStyles={popupModuleActionBarStyles ? popupModuleActionBarStyles : { justifyContent: "space-between", padding: "1rem" }} + style={{}} + hideSubmit={hideSubmit ? hideSubmit : false} + footerLeftButtonstyle={{ + padding: 0, + alignSelf: "flex-start", + height: "fit-content", + textStyles: { fontWeight: "600" }, + backgroundColor: "rgba(255, 255, 255, 1)", + color: PRIMARY_THEME_COLOR, + minWidth: "15.063rem", + border: `0.063rem solid ${PRIMARY_THEME_COLOR}`, + }} + footerRightButtonstyle={{ + padding: 0, + alignSelf: "flex-end", + height: "fit-content", + textStyles: { fontWeight: "500" }, + backgroundColor: PRIMARY_THEME_COLOR, + color: "rgba(255, 255, 255, 1)", + minWidth: "15.063rem", + boxShadow: "0px -2px 0px 0px rgba(11, 12, 12, 1) inset", + }} + footerLeftButtonBody={footerLeftButtonBody} + footerRightButtonBody={footerRightButtonBody} + actionCancelLabel={actionCancelLabel} + > + {bodyText && ( +
+

{bodyText}

+
+ )} + {body ? body : ""} +
+ ); +}; + +export default Modal; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js new file mode 100644 index 00000000000..1254e25c093 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js @@ -0,0 +1,272 @@ +import { ActionBar, Stepper, Toast } from "@egovernments/digit-ui-components"; +import PropTypes from "prop-types"; +import React, { useState, useEffect, useCallback } from "react"; +import { useTranslation } from "react-i18next"; +import { Button } from "@egovernments/digit-ui-react-components"; +import { ArrowBack, ArrowForward } from "@egovernments/digit-ui-svg-components"; +import { PRIMARY_THEME_COLOR } from "../configs/constants"; +import { memo } from "react"; + +/** + * + * @param { config: Object, checkDataCompleteness: boolean, components: Object, childProps: Object, stepNavigationActive: boolean, nextEventAddon: function, setCurrentPageExternally: function, completeNavigation } props + * @returns + * + */ +// Main component for creating a microplan +const Navigator = memo((props) => { + // States + const [currentPage, setCurrentPage] = useState(); + // const [toast, setToast] = useState(); + const [navigationEvent, setNavigationEvent] = useState(); + const [activeSteps, setActiveSteps] = useState(Digit.SessionStorage.get("microplanHelperData")?.activeSteps || -1); + /** + * checkDataCompletion + * "true": check for data completeness + * "false": do nothing + * "valid": data is present + * "invalid": whole or a part of the data is missing + * "perform-action": move to the respective step ( had to add this as mutate addons need some buffer time) + */ + const [checkDataCompletion, setCheckDataCompletion] = useState("false"); + + const { t } = useTranslation(); + + // Effect to set initial current page when timeline options change + useEffect(() => { + if (!props.config || props.config.length === 0) return; + let response; + if (props.setCurrentPageExternally) { + response = props.setCurrentPageExternally({ setCurrentPage, method: "set" }); + } + if (!response) setCurrentPage(props.config[0]); + }, [props.config]); + + // Might need it later + // Effect to handle data completion validation and show toast + useEffect(() => { + if (checkDataCompletion === "invalid") { + if (navigationEvent && navigationEvent.name === "next") { + props?.setToast({ state: "error", message: t("MICROPLAN_PLEASE_FILL_ALL_THE_FIELDS_AND_RESOLVE_ALL_THE_ERRORS") }); + } else if (navigationEvent && navigationEvent.name === "step" && navigationEvent.step != undefined) { + if (navigationEvent.step > currentPage.id) + props?.setToast({ state: "error", message: t("MICROPLAN_PLEASE_FILL_ALL_THE_FIELDS_AND_RESOLVE_ALL_THE_ERRORS") }); + else onStepClick(navigationEvent.step); + } else if (navigationEvent && navigationEvent.name === "previousStep") previousStep(); + setCheckDataCompletion("false"); + } + }, [checkDataCompletion]); + + // Effect to handle navigation events and transition between steps + useEffect(() => { + // if (checkDataCompletion !== "valid" || navigationEvent === undefined) return; + if ( + checkDataCompletion === "valid" && + ((navigationEvent.step && currentPage.id + 1 === navigationEvent.step) || currentPage.id > navigationEvent.step || !navigationEvent.step) + ) { + if (typeof props.nextEventAddon === "function") { + if (LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null) + props.nextEventAddon(currentPage, checkDataCompletion, setCheckDataCompletion); + else props.nextEventAddon(currentPage, true, setCheckDataCompletion); + } else { + setCheckDataCompletion("perform-action"); + } + } + }, [navigationEvent, checkDataCompletion, props.nextEventAddon]); + + useEffect(() => { + handleNavigationEvent( + checkDataCompletion, + navigationEvent, + currentPage, + setCheckDataCompletion, + setNavigationEvent, + onStepClick, + nextStep, + previousStep, + props + ); + }, [checkDataCompletion, navigationEvent]); + + // Function to navigate to the next step + const nextStep = useCallback(() => { + if (!currentPage) return; + changeCurrentPage(props.config[currentPage?.id + 1]); + if (currentPage?.id + 1 > props.config.length - 1) return; + setCurrentPage((previous) => props.config[previous?.id + 1]); + }, [currentPage]); + + // Function to navigate to the previous step + const previousStep = useCallback(() => { + changeCurrentPage(props.config[currentPage?.id - 1]); + setCurrentPage((previous) => props.config[previous?.id - 1]); + }, [currentPage]); + + // Function to handle step click and navigate to the selected step + const onStepClick = useCallback((index) => { + const newCurrentPage = props.config.find((item) => item.id === index); + changeCurrentPage(newCurrentPage); + setCurrentPage(newCurrentPage); + }); + + // Function to handle next button click + const previousbuttonClickHandler = useCallback(() => { + if ( + (props.checkDataCompleteness && + props?.config[currentPage?.id]?.checkForCompleteness && + LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null) || + currentPage?.id === props.config[props.config.length - 1].id + ) { + setNavigationEvent({ name: "previousStep" }); + setCheckDataCompletion("true"); + } else previousStep(); + }, [props.checkDataCompleteness, previousStep, setNavigationEvent]); + + // Function to handle next button click + const nextbuttonClickHandler = useCallback(() => { + if ( + props.checkDataCompleteness && + props?.config[currentPage?.id]?.checkForCompleteness && + LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null + ) { + setCheckDataCompletion("true"); + setNavigationEvent({ name: "next" }); + } else nextStep(); + }, [props.checkDataCompleteness, nextStep, setNavigationEvent]); + + // Function to handle step click + const stepClickHandler = useCallback( + (index) => { + if (index === currentPage?.id) return; + if (!props.stepNavigationActive) return; + if ( + (props.checkDataCompleteness && + props?.config[currentPage?.id]?.checkForCompleteness && + LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null) || + currentPage?.id === props.config[props.config.length - 1].id + ) { + setCheckDataCompletion("true"); + setNavigationEvent({ name: "step", step: index }); + } else { + onStepClick(index); + } + }, + [props.checkDataCompleteness, props.stepNavigationActive, onStepClick] + ); + + // Function to set current page + const changeCurrentPage = (newPage) => { + if (props.setCurrentPageExternally) { + props.setCurrentPageExternally({ currentPage: newPage, method: "save" }); + } + }; + + const completeNavigation = () => { + setNavigationEvent({ name: "next" }); + setCheckDataCompletion("true"); + }; + + // changing active state + useEffect(() => { + if (currentPage?.id > activeSteps) { + setActiveSteps(currentPage?.id); + Digit.SessionStorage.set("microplanHelperData", { ...(Digit.SessionStorage.get("microplanHelperData") || {}), activeSteps: currentPage?.id }); + } + }, [currentPage]); + + return ( +
+ {/* Stepper component */} + t(item.name))} + direction="horizontal" + activeSteps={activeSteps >= 0 ? activeSteps + 1 : null} + onStepClick={stepClickHandler} + /> + + {/* Load custom component based on current page */} + {props?.components[currentPage?.component] ? ( + LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null ? ( + + ) : ( +
{t("COMMON_DATA_NOT_PRESENT")}
+ ) + ) : ( + "" + )} + + {/* Action bar */} + + {/* Back button */} + {currentPage?.id > 0 && ( + + +
+ ); +}); + +// Component to load custom component based on current page +const LoadCustomComponent = (props) => { + if (props && !props.component) return null; + const secondaryProps = props.secondaryProps; + return ; +}; +LoadCustomComponent.propTypes = { + component: PropTypes.elementType.isRequired, + secondaryProps: PropTypes.object, +}; + +const handleNavigationEvent = ( + checkDataCompletion, + navigationEvent, + currentPage, + setCheckDataCompletion, + setNavigationEvent, + onStepClick, + nextStep, + previousStep, + props +) => { + if (checkDataCompletion === "perform-action") { + if (navigationEvent && navigationEvent.name === "next") { + if (currentPage?.id >= props.config.length - 1 && typeof props?.completeNavigation == "function") { + return props?.completeNavigation(); + } + nextStep(); + } else if (navigationEvent && navigationEvent.name === "step" && navigationEvent.step != undefined) onStepClick(navigationEvent.step); + else if (navigationEvent && navigationEvent.name === "previousStep") previousStep(); + setCheckDataCompletion("false"); + setNavigationEvent(undefined); + } +}; + +export default Navigator; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js new file mode 100644 index 00000000000..be023befbfe --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js @@ -0,0 +1,878 @@ +import React, { useState, useEffect, useCallback, Fragment, useRef } from "react"; +import { useTranslation } from "react-i18next"; +import { Info, Trash } from "@egovernments/digit-ui-svg-components"; +import { ModalHeading } from "./CommonComponents"; +import { Button, Modal } from "@egovernments/digit-ui-react-components"; +import { Dropdown, InfoCard, Toast } from "@egovernments/digit-ui-components"; +import { tourSteps } from "../configs/tourSteps"; +import { useMyContext } from "../utils/context"; +import { v4 as uuidv4 } from "uuid"; +import { PlusWithSurroundingCircle } from "../icons/Svg"; +import { PRIMARY_THEME_COLOR } from "../configs/constants"; + +const page = "ruleEngine"; + +const RuleEngine = ({ + campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, + microplanData, + setMicroplanData, + checkDataCompletion, + setCheckDataCompletion, + currentPage, + pages, + setToast, +}) => { + const { t } = useTranslation(); + + // States + const [editable, setEditable] = useState(true); + const [modal, setModalState] = useState("none"); + const [rules, setRules] = useState([]); + const [hypothesisAssumptionsList, setHypothesisAssumptionsList] = useState([]); + const [itemForDeletion, setItemForDeletion] = useState(); + const [exampleOption, setExampleOption] = useState(""); + const [inputs, setInputs] = useState([]); + const [outputs, setOutputs] = useState([]); + const [operators, setOperators] = useState([]); + const [validationSchemas, setValidationSchemas] = useState([]); + const [autofillData, setAutoFillData] = useState([]); + const { state, dispatch } = useMyContext(); + const [originalRuleOutputCount, setOriginalRuleOutputCount] = useState(0); + // const [toast, setToast] = useState(); + const [pureInputList, setPureInputList] = useState([]); + // Set TourSteps + useEffect(() => { + const tourData = tourSteps(t)?.[page] || {}; + if (state?.tourStateData?.name === page) return; + dispatch({ + type: "SETINITDATA", + state: { tourStateData: tourData }, + }); + }, []); + + const setModal = (modalString) => { + const elements = document.querySelectorAll(".popup-wrap-rest-unfocus"); + elements.forEach((element) => { + element.classList.toggle("popup-wrap-rest-unfocus-active"); + }); + setModalState(modalString); + }; + + // UseEffect to extract data on first render + useEffect(() => { + if (pages) { + const previouspage = pages[currentPage?.id - 1]; + if (previouspage?.checkForCompleteness && !microplanData?.status?.[previouspage?.name]) setEditable(false); + else setEditable(true); + } + }, []); + + // UseEffect for checking completeness of data before moveing to next section + useEffect(() => { + if (!rules || checkDataCompletion !== "true" || !setCheckDataCompletion) return; + // uncomment to activate data change save check + // if (!microplanData?.ruleEngine || !_.isEqual(rules, microplanData.ruleEngine)) setModal("data-change-check"); + // else + updateData(true); + }, [checkDataCompletion]); + + // UseEffect to store current data + useEffect(() => { + if (!rules || !setMicroplanData) return; + setMicroplanData((previous) => ({ ...previous, ruleEngine: rules })); + }, [rules]); + + // UseEffect to add a event listener for keyboard + useEffect(() => { + window.addEventListener("keydown", handleKeyPress); + + return () => window.removeEventListener("keydown", handleKeyPress); + }, [modal]); + + const handleKeyPress = (event) => { + // if (modal !== "upload-guidelines") return; + if (["x", "Escape"].includes(event.key)) { + // Perform the desired action when "x" or "esc" is pressed + // if (modal === "upload-guidelines") + setCheckDataCompletion("false"); + setModal("none"); + } + }; + + // check if data has changed or not + const updateData = useCallback( + (check) => { + if (!rules || !setMicroplanData) return; + if (check) { + setMicroplanData((previous) => ({ ...previous, ruleEngine: rules })); + const activeRules = rules.filter((item) => item.active); + const isValid = activeRules.every((item) => Object.values(item).every((data) => data !== "")) && activeRules.length !== 0; + if (isValid) setCheckDataCompletion("valid"); + else setCheckDataCompletion("invalid"); + } else { + let isValid = microplanData?.ruleEngine?.every((item) => Object.values(item).every((data) => data !== "")); + isValid = isValid && rules.length !== 0; + if (isValid) setCheckDataCompletion("valid"); + else setCheckDataCompletion("invalid"); + } + }, + [rules, setMicroplanData, microplanData, setCheckDataCompletion] + ); + + const cancelUpdateData = useCallback(() => { + setCheckDataCompletion(false); + setModal("none"); + }, [setCheckDataCompletion, setModal]); + + // useEffect to initialise the data from MDMS + useEffect(() => { + if (!state) return; + let schemas = state?.Schemas; + let hypothesisAssumptions = []; + microplanData?.hypothesis?.filter((item) => item.active).forEach((item) => (item.key !== "" ? hypothesisAssumptions.push(item.key) : null)); + let ruleConfigureOutput = state?.RuleConfigureOutput; + let UIConfiguration = state?.UIConfiguration; + let ruleConfigureInputs = getRuleConfigInputsFromSchema(campaignType, microplanData, schemas) || []; + let AutoFilledRuleConfigurationsList = state?.AutoFilledRuleConfigurations; + AutoFilledRuleConfigurationsList = AutoFilledRuleConfigurationsList.find((item) => item.campaignType === campaignType)?.data; + microplanData?.ruleEngine?.forEach((item) => { + if (Object.values(item).every((e) => e !== "")) ruleConfigureInputs.push(item?.output); + }); + if (schemas) setValidationSchemas(schemas); + + let temp; + setHypothesisAssumptionsList(hypothesisAssumptions); + let outputs; + if (ruleConfigureOutput) temp = ruleConfigureOutput?.find((item) => item.campaignType === campaignType); + if (temp?.data) { + let data = temp.data; + setOriginalRuleOutputCount(data.length); + microplanData?.ruleEngine?.forEach((item) => { + if (item.active) { + let filteredData = data.filter((e) => e !== item?.output); + data = filteredData; + } + }); + outputs = data; + setOutputs(data); + } + + if (ruleConfigureInputs) setInputs(ruleConfigureInputs); + let operator; + if (UIConfiguration) temp = UIConfiguration.find((item) => item.name === "ruleConfigure"); + if (temp?.ruleConfigureOperators) { + temp = temp.ruleConfigureOperators.map((item) => item.name); + operator = temp; + setOperators(temp); + } + // if (AutoFilledRuleConfigurationsList) setAutoFillData(AutoFilledRuleConfigurationsList); + // Pure inputs - output not there + const pureInputs = getRuleConfigInputsFromSchema(campaignType, microplanData, schemas); + setPureInputList(pureInputs); + + const ssnRuleOutputs = microplanData?.ruleEngine?.reduce((acc, item) => { + if (item?.active && item?.output) acc.push(item?.output); + return acc; + }, []); + const tempOutput = [...outputs, ...(ssnRuleOutputs ? ssnRuleOutputs : [])]; + setExampleOption({ + output: tempOutput.length ? tempOutput[0] : "", + input: pureInputs.length ? pureInputs[0] : "", + operator: operator.length ? operator[0] : "", + assumptionValue: hypothesisAssumptions.length ? hypothesisAssumptions[0] : "", + }); + + let filteredRules = []; + let response; + if (microplanData?.ruleEngine && microplanData?.hypothesis) { + const hypothesisAssumptions = microplanData?.hypothesis?.filter((item) => item.active && item.key !== "").map((item) => item.key) || []; + if (hypothesisAssumptions.length !== 0) { + setHypothesisAssumptionsList(hypothesisAssumptions); + response = filterRulesAsPerConstrains( + microplanData.ruleEngine, + [], + hypothesisAssumptions, + tempOutput, + operator, + pureInputs, + setInputs, + setOutputs, + false + ); + filteredRules = response?.rules; + + // setRuleEngineDataFromSsn(microplanData.ruleEngine, hypothesisAssumptions, setRules); + } + } + if (response?.rulesDeleted) + setToast({ + state: "warning", + message: t("WARNING_RULES_DELETED_DUE_TO_PRIOR_SECTION_DATA_CHANGES"), + }); + if (!AutoFilledRuleConfigurationsList || !outputs || !hypothesisAssumptions || !schemas) return; + + response = filterRulesAsPerConstrains( + AutoFilledRuleConfigurationsList, + filteredRules, + hypothesisAssumptions, + outputs, + operator, + pureInputs, + setInputs, + setOutputs, + true + ); + + if (response?.rules) setRules(response?.rules); + }, []); + + const closeModal = useCallback(() => { + setModal("none"); + }, [setModal]); + + // Function to Delete an assumption + const deleteAssumptionHandlerCallback = useCallback(() => { + deleteAssumptionHandler(itemForDeletion, setItemForDeletion, setRules, setOutputs, setInputs, pureInputList); + closeModal(); + }, [itemForDeletion, deleteAssumptionHandler, setItemForDeletion, setRules, setOutputs, setInputs, closeModal, pureInputList]); + + const sectionClass = `jk-header-btn-wrapper rule-engine-section ${editable ? "" : "non-editable-component"} popup-wrap-rest-unfocus`; + return ( + <> +
+
+
+ {/* NonInterractable Section */} + + {/* Interractable Section that includes the example as well as the rules */} + +
+ +
+
+ {/* delete conformation */} +
+ {modal === "delete-conformation" && ( + } + actionCancelLabel={t("YES")} + actionCancelOnSubmit={deleteAssumptionHandlerCallback} + actionSaveLabel={t("NO")} + actionSaveOnSubmit={closeModal} + > +
+

{t("RULE_ENGINE_INSTRUCTIONS_DELETE_ENTRY_CONFIRMATION")}

+
+
+ )} +
+ + ); +}; + +// Function to add a new assumption +const addRulesHandler = (setRules) => { + let uuid = uuidv4(); + setRules((previous) => [ + ...previous, + { + id: uuid, + // previous.length ? previous[previous.length - 1].id + 1 : 0, + output: "", + input: "", + operator: "", + assumptionValue: "", + active: true, + }, + ]); +}; + +// Defination for NonInterractable Section +const NonInterractableSection = React.memo(({ t }) => { + return ( +
+

{t("HEADING_RULE_ENGINE")}

+

{t("INSTRUCTION_RULE_ENGINE")}

+
+ ); +}); + +// Defination for NonInterractable Section +const InterractableSection = React.memo( + ({ + rules, + setRules, + hypothesisAssumptionsList, + setHypothesisAssumptionsList, + setModal, + setItemForDeletion, + exampleOption, + inputs, + outputs, + operators, + setInputs, + setOutputs, + setOperators, + pureInputList, + t, + }) => { + // References to the items in the list + const itemRefs = useRef([]); + // State to keep track of the currently expanded item index + const [expandedIndex, setExpandedIndex] = useState(null); + // Reference to the scroll container + const scrollContainerRef = useRef(null); + // State to track the render cycle count + const [renderCycle, setRenderCycle] = useState(0); + + // Effect to reset the render cycle count whenever the expandedIndex changes + useEffect(() => { + if (expandedIndex !== null) { + setRenderCycle(0); + } + }, [expandedIndex]); + + // Effect to handle scrolling to the expanded item after the DOM has updated + useEffect(() => { + if (renderCycle < 3) { + // Increment render cycle count to ensure multiple render checks + setRenderCycle((prev) => prev + 1); + } else if (expandedIndex !== null && itemRefs.current[expandedIndex]) { + try { + const parentElement = itemRefs.current[expandedIndex]; + const childElement = itemRefs.current[expandedIndex].children[1]; + + if (parentElement) { + const scrollContainer = scrollContainerRef.current; + const parentRect = parentElement.getBoundingClientRect(); + const containerRect = scrollContainer.getBoundingClientRect(); + + // Calculate the offset from the top of the container + const offset = parentRect.top - containerRect.top; + + // Scroll the container to the target position + scrollContainer.scrollTo({ + top: scrollContainer.scrollTop + offset - 100, + behavior: "smooth", + }); + } + + if (childElement) { + // Focus the child element if it exists + childElement.focus(); + } + } catch (error) { + console.error("Error scrolling to element:", error); + } + } + }, [renderCycle, expandedIndex]); + + // Effect to observe DOM changes in the expanded item and trigger render cycle + useEffect(() => { + if (expandedIndex !== null) { + const observer = new MutationObserver(() => { + setRenderCycle((prev) => prev + 1); + }); + + if (itemRefs.current[expandedIndex]) { + observer.observe(itemRefs.current[expandedIndex], { childList: true, subtree: true }); + } + + return () => observer.disconnect(); + } + }, [expandedIndex]); + + // Function to toggle the expanded state of an item + const toggleExpand = (index) => { + setExpandedIndex(index === expandedIndex ? null : index); + }; + + // Handler for deleting an assumption on conformation + const deleteHandler = useCallback( + (item) => { + setModal("delete-conformation"); + setItemForDeletion(item); + }, + [setModal, setItemForDeletion] + ); + + return ( +
+ +
+
+
+

{t("VALUE")}

+
+
=
+
+

{t("RULE_ENGINE_INPUT")}

+
+
+

{t("RULE_ENGINE_OPERATOR")}

+
+
+

{t("KEY")}

+
+
+ +
+
+ {rules + .filter((item) => item.active) + .map((item, index) => ( +
{ + itemRefs.current[index] = el; + }} + onClick={() => toggleExpand(index)} + > +
+ +
+
+ +
+
+ +
+
+ ))} +
+
+ ); + } +); + +const Example = ({ exampleOption, t }) => { + return ( +
+
+

{t("EXAMPLE")}

+
+
+

{t("VALUE")}

+ +

{t("RULE_ENGINE_VALUE_HELP_TEXT")}

+
+ +
+

{"="}

+ +
=
+

{"="}

+
+ +
+

{t("RULE_ENGINE_INPUT")}

+ +

{t("RULE_ENGINE_INPUT_HELP_TEXT")}

+
+
+

{t("RULE_ENGINE_OPERATOR")}

+ +

{t("RULE_ENGINE_OPERATOR_HELP_TEXT")}

+
+
+

{t("KEY")}

+ +

{t("RULE_ENGINE_KEY_HELP_TEXT")}

+
+
+
+
+ +
+
+ ); +}; + +const deleteAssumptionHandler = (item, setItemForDeletion, setRules, setOutputs, setInputs, pureInputList) => { + try { + let outputToRemove = []; + setRules((previous) => { + if (!previous.length) return []; + const deletionElementIndex = previous.findIndex((data) => data.id === item.id); + const filteredData = previous.map((data, index) => (index === deletionElementIndex ? { ...data, active: false } : data)); + let newRules = filteredData.reduce((acc, dataItem, index) => { + if (dataItem.active) { + let possibleOutputs = acc.reduce((reducedData, element, index) => { + if (element.active && !Object.values(element).some((e) => e === "")) reducedData.push(element?.output); + return reducedData; + }, []); + possibleOutputs.push(...pureInputList); + if (!possibleOutputs.includes(dataItem?.input)) { + if (dataItem?.output !== "") outputToRemove.push(dataItem.output); + acc.push({ ...dataItem, input: "", oldInput: dataItem?.input ? dataItem?.input : dataItem?.oldInput }); + } else { + acc.push(dataItem); + } + } else { + acc.push(dataItem); + } + return acc; + }, []); + + return newRules || []; + }); + if (item?.output) { + setOutputs((previous) => { + if (!previous?.includes(item.output)) return previous ? [...previous, item.output] : [item.output]; + }); + setInputs((previous) => { + return previous?.filter((e) => e !== item.output && !outputToRemove.includes(e)); + }); + } + setItemForDeletion(); + } catch (error) { + console.error("Error while deleting a rule: ", error.message); + } +}; + +const Select = React.memo( + ({ item, rules, setRules, disabled = false, options, setOptions, toChange, unique, setInputs, outputs, pureInputList, t }) => { + const [selected, setSelected] = useState(""); + const [filteredOptions, setFilteredOptions] = useState([]); + + useEffect(() => { + if (item) { + if (outputs?.some((e) => e === item.input)) { + if (rules.filter((item) => item.active).some((e) => e?.output === item?.input)) setSelected({ code: item?.[toChange] }); + } else setSelected({ code: item[toChange] }); + } + }, [item]); + + useEffect(() => { + if (!options) return; + let filteredOptions = options.length ? options : []; + let filteredOptionPlaceHolder = []; + if (item?.[toChange] && !filteredOptions.includes(item[toChange])) { + filteredOptionPlaceHolder = [item[toChange], ...filteredOptions]; + } else filteredOptionPlaceHolder = filteredOptions; + + if (toChange === "input") { + const currentRuleIndex = rules.findIndex((e) => e?.id === item?.id); + filteredOptionPlaceHolder = filteredOptionPlaceHolder.filter((data) => { + let priorOutputs = []; + if (currentRuleIndex !== -1) { + priorOutputs = rules.reduce((acc, item, index) => { + if (item.active && index < currentRuleIndex) acc.push(item?.output); + return acc; + }, []); + } + priorOutputs.push(...pureInputList); + return data !== item.output && priorOutputs.includes(data); + }); + } + setFilteredOptions(filteredOptionPlaceHolder); + }, [options]); + + const selectChangeHandler = useCallback( + (e) => { + if (e.code === "SELECT_OPTION") return; + const existingEntry = rules.find((item) => item.active && item[toChange] === e.code); + if (existingEntry && unique) { + console.error("Attempted to add a duplicate entry where uniqueness is required."); + return; + } + const newDataSegment = { ...item }; + newDataSegment[toChange] = e.code; + setRules((previous) => { + let filteredAssumptionsList = previous.map((data) => { + if (data.id === item.id) return newDataSegment; + return data; + }); + return filteredAssumptionsList; + }); + if (typeof setInputs === "function") { + setInputs((previous) => { + let temp = _.cloneDeep(previous); + if (toChange === "output") { + temp = temp.filter((item) => item !== selected?.code); + } + if (!temp.includes(newDataSegment.output) && Object.values(newDataSegment).every((item) => item !== "")) + temp = [...temp, newDataSegment.output]; + + const currentRuleIndex = rules.findIndex((e) => e?.id === item?.id); + temp = temp.filter((data) => { + let priorOutputs = []; + if (currentRuleIndex !== -1) { + priorOutputs = rules.reduce((acc, item, index) => { + if (index < currentRuleIndex) acc.push(item?.output); + return acc; + }, []); + } + priorOutputs.push(...pureInputList); + return data !== item.output && priorOutputs.includes(data); + }); + return temp; + }); + } + if (unique) + setOptions((previous) => { + let newOptions = previous.filter((item) => item !== e.code); + if (selected?.code && !newOptions.includes(selected?.code)) newOptions.unshift(selected?.code); + return newOptions; + }); + }, + [rules, item, selected, setRules, setOptions, setInputs] + ); + + return ( + ({ code: item }))} + selected={selected} + select={selectChangeHandler} + optionKey="code" + placeholder={t("SELECT_OPTION")} + showToolTip={true} + /> + ); + } +); + +// get schema for validation +const getRuleConfigInputsFromSchema = (campaignType, microplanData, schemas) => { + if (!schemas || !microplanData || !microplanData?.upload || !campaignType) return []; + let sortData = []; + if (!schemas) return; + for (const value of microplanData?.upload?.filter((value) => value?.active && value?.error === null) || []) { + sortData.push({ section: value?.section, fileType: value?.fileType }); + } + const filteredSchemas = + schemas?.filter((schema) => { + if (schema.campaignType) { + return schema.campaignType === campaignType && sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); + } + return sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); + }) || []; + const finalData = filteredSchemas + ?.map((item) => + Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.isRuleConfigureInputs) { + acc.push(key); + } + return acc; + }, []) + ) + .flat() + .filter((item) => !!item); + return [...new Set(finalData)]; +}; + +// This function adding the rules configures in MDMS with respect to the canpaign when rule section is empty +const filterRulesAsPerConstrains = (autofillData, rules, hypothesisAssumptionsList, outputs, operators, inputs, setInputs, setOutputs, autofill) => { + if (rules && rules.filter((item) => item.active).length !== 0) return { rules }; + + let wereRulesNotDeleted = true; + let newRules = []; + const ruleOuputList = rules ? rules.filter((item) => item.active).map((item) => item?.output) : []; + let rulePlusInputs; + if (ruleOuputList) rulePlusInputs = [...inputs, ...ruleOuputList]; + else rulePlusInputs = inputs; + for (const item of autofillData) { + let active = !(item && item.active === false); + const ruleNotCompleteCheck = (!autofill && item && Object.values(item).filter((e) => e === "").length === 0) || autofill; + if ( + (ruleOuputList?.includes(item?.output) || + (outputs && !outputs.includes(item?.output)) || + (rulePlusInputs && !rulePlusInputs.includes(item?.input)) || + (operators && !operators.includes(item?.operator)) || + (hypothesisAssumptionsList && !hypothesisAssumptionsList.includes(item?.assumptionValue)) || + !outputs || + !rulePlusInputs || + !operators || + !hypothesisAssumptionsList) && + ruleNotCompleteCheck + ) { + if (autofill) { + continue; + } else { + if (active) { + wereRulesNotDeleted = false; + active = false; + } + } + } + if (!item["id"]) { + let uuid = uuidv4(); + item["id"] = uuid; + } + item.active = active; + newRules.push(item); + if (active && ruleNotCompleteCheck) { + rulePlusInputs?.push(item?.output); + ruleOuputList?.push(item?.output); + } + } + if (newRules.length !== 0) { + let newOutputs = []; + outputs.forEach((e) => { + if (!ruleOuputList.includes(e)) { + newOutputs.push(e); + } + }); + setOutputs(newOutputs); + setInputs(rulePlusInputs); + // setRules((previous) => [...previous, ...newRules]); + } + + return { rules: [...(rules ? rules : []), ...newRules], rulesDeleted: !autofill && !wereRulesNotDeleted }; +}; + +export default RuleEngine; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js new file mode 100644 index 00000000000..316eef6113c --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js @@ -0,0 +1,2166 @@ +import React, { useState, useEffect, useMemo, Fragment, useCallback } from "react"; +import { useTranslation } from "react-i18next"; +import { LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; +import * as Icons from "@egovernments/digit-ui-svg-components"; +import { FileUploader } from "react-drag-drop-files"; +import { convertJsonToXlsx } from "../utils/jsonToExcelBlob"; +import { parseXlsxToJsonMultipleSheets } from "../utils/exceltojson"; +import { ModalWrapper } from "./Modal"; +import { checkForErrorInUploadedFileExcel } from "../utils/excelValidations"; +import { geojsonPropetiesValidation, geojsonValidations } from "../utils/geojsonValidations"; +import JSZip from "jszip"; +import { SpatialDataPropertyMapping } from "./resourceMapping"; +import shp from "shpjs"; +import { JsonPreviewInExcelForm } from "./JsonPreviewInExcelForm"; +import { ButtonType1, ButtonType2, CloseButton, ModalHeading } from "./CommonComponents"; +import { InfoButton, InfoCard, Loader, Toast } from "@egovernments/digit-ui-components"; +import { + ACCEPT_HEADERS, + BOUNDARY_DATA_SHEET, + EXCEL, + FACILITY_DATA_SHEET, + FILE_STORE, + GEOJSON, + LOCALITY, + PRIMARY_THEME_COLOR, + SCHEMA_PROPERTIES_PREFIX, + SHAPEFILE, + SHEET_COLUMN_WIDTH, + SHEET_PASSWORD, + commonColumn, +} from "../configs/constants"; +import { tourSteps } from "../configs/tourSteps"; +import { useMyContext } from "../utils/context"; +import { v4 as uuidv4 } from "uuid"; +import { addBoundaryData, createTemplate, fetchBoundaryData, filterBoundaries } from "../utils/createTemplate"; +import XLSX from "xlsx"; +import ExcelJS from "exceljs"; +import { + freezeSheetValues, + freezeWorkbookValues, + hideUniqueIdentifierColumn, + performUnfreezeCells, + unfreezeColumnsByHeader, + updateFontNameToRoboto, +} from "../utils/excelUtils"; +const page = "upload"; + +const Upload = ({ + MicroplanName = "default", + campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, + microplanData, + setMicroplanData, + checkDataCompletion, + setCheckDataCompletion, + currentPage, + pages, + navigationEvent, + setToast, +}) => { + const { t } = useTranslation(); + + // States + const [editable, setEditable] = useState(true); + const [sections, setSections] = useState([]); + const [selectedSection, setSelectedSection] = useState(null); + const [modal, setModalState] = useState("none"); + const [selectedFileType, setSelectedFileType] = useState(null); + const [dataPresent, setDataPresent] = useState(false); + const [dataUpload, setDataUpload] = useState(false); + const [loader, setLoader] = useState(false); + const [fileData, setFileData] = useState(); + // const [toast, setToast] = useState(); + const [uploadedFileError, setUploadedFileError] = useState(); + const [fileDataList, setFileDataList] = useState([]); + const [validationSchemas, setValidationSchemas] = useState([]); + const [template, setTemplate] = useState([]); + const [resourceMapping, setResourceMapping] = useState([]); + const [previewUploadedData, setPreviewUploadedData] = useState(); + const { state, dispatch } = useMyContext(); + + //fetch campaign data + const { id = "" } = Digit.Hooks.useQueryParams(); + const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( + { + CampaignDetails: { + tenantId: Digit.ULBService.getCurrentTenantId(), + ids: [id], + }, + }, + { + enabled: !!id, + } + ); + + // request body for boundary hierarchy api + const reqCriteria = { + url: `/boundary-service/boundary-hierarchy-definition/_search`, + params: {}, + body: { + BoundaryTypeHierarchySearchCriteria: { + tenantId: Digit.ULBService.getCurrentTenantId(), + hierarchyType: campaignData?.hierarchyType, + // hierarchyType: "Microplan", + }, + }, + config: { + enabled: !!campaignData?.hierarchyType, + select: (data) => { + return ( + data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map( + (item) => `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}` + ) || {} + ); + }, + }, + }; + const { isLoading: ishierarchyLoading, data: hierarchy } = Digit.Hooks.useCustomAPIHook(reqCriteria); + // Set TourSteps + useEffect(() => { + const tourData = tourSteps(t)?.[page] || {}; + if (state?.tourStateData?.name === page) return; + dispatch({ + type: "SETINITDATA", + state: { tourStateData: tourData }, + }); + }, [t]); + + const setModal = (modalString) => { + const elements = document.querySelectorAll(".popup-wrap-rest-unfocus"); + elements.forEach((element) => { + element.classList.toggle("popup-wrap-rest-unfocus-active"); + }); + setModalState(modalString); + }; + + // UseEffect for checking completeness of data before moveing to next section + useEffect(() => { + if (!fileDataList || checkDataCompletion !== "true" || !setCheckDataCompletion) return; + // uncomment to activate data change save check + // if (!microplanData?.upload || !_.isEqual(fileDataList, microplanData.upload)) setModal("data-change-check"); + // else + updateData(true); + }, [checkDataCompletion]); + + // UseEffect to store current data + useEffect(() => { + if (!fileDataList || !setMicroplanData) return; + setMicroplanData((previous) => ({ ...previous, upload: fileDataList })); + }, [fileDataList]); + + // check if data has changed or not + const updateData = useCallback( + (check) => { + if (!fileDataList || !setMicroplanData) return; + + // if user has selected a file type and wants to go back to file type selection he/she can click back buttom + const currentSectionIndex = sections.findIndex((item) => item.id === selectedSection.id); + if (!dataPresent) { + if (navigationEvent?.name !== "step") { + if (navigationEvent?.name === "next") { + if (currentSectionIndex < sections.length - 1) { + setSelectedSection(sections[currentSectionIndex + 1]); + setCheckDataCompletion("false"); + return; + } + } else if (navigationEvent?.name === "previousStep") { + if (dataUpload) { + setDataUpload(false); + setSelectedFileType(null); + setCheckDataCompletion("false"); + return; + } + if (currentSectionIndex > 0) { + setSelectedSection(sections[currentSectionIndex - 1]); + setCheckDataCompletion("false"); + return; + } + } + } + } else { + if (navigationEvent?.name === "next") { + if (currentSectionIndex < sections.length - 1) { + setSelectedSection(sections[currentSectionIndex + 1]); + setCheckDataCompletion("false"); + return; + } + } else if (navigationEvent?.name === "previousStep") { + if (currentSectionIndex > 0) { + setSelectedSection(sections[currentSectionIndex - 1]); + setCheckDataCompletion("false"); + return; + } + } + } + + if (check) { + setMicroplanData((previous) => ({ ...previous, upload: fileDataList })); + const valueList = fileDataList ? fileDataList : []; + const sectionCheckList = sections?.filter((item) => item.required); + + if ( + valueList.length !== 0 && + sectionCheckList.every((item) => { + let filteredList = fileDataList?.filter((e) => e.active && e.templateIdentifier === item.id); + if (filteredList?.length === 0) return false; + return filteredList?.every((element) => element?.error === null) && fileDataList && !fileDataList.some((e) => e?.active && e?.error); + }) + ) + setCheckDataCompletion("valid"); + else setCheckDataCompletion("invalid"); + } else { + const valueList = microplanData?.Upload ? Object.values(microplanData?.Upload) : []; + if ( + valueList.length !== 0 && + sectionCheckList.every((item) => + fileDataList?.filter((e) => e.templateIdentifier === item.id)?.every((element) => element.active && element?.error === null) + ) + ) + setCheckDataCompletion("valid"); + else setCheckDataCompletion("invalid"); + } + }, + [fileDataList, setMicroplanData, microplanData, setCheckDataCompletion, dataPresent, dataUpload, navigationEvent] + ); + + // UseEffect to extract data on first render + useEffect(() => { + if (microplanData?.upload) { + setFileDataList(microplanData.upload); + } + + if (pages) { + const previouspage = pages[currentPage?.id - 1]; + if (previouspage?.checkForCompleteness && !microplanData?.status?.[previouspage?.name]) setEditable(false); + else setEditable(true); + } + }, []); + + // UseEffect to add a event listener for keyboard + useEffect(() => { + window.addEventListener("keydown", handleKeyPress); + + return () => window.removeEventListener("keydown", handleKeyPress); + }, [modal, previewUploadedData]); + + const handleKeyPress = (event) => { + // if (modal !== "upload-guidelines") return; + if (["x", "Escape"].includes(event.key)) { + // Perform the desired action when "x" or "esc" is pressed + if (modal === "upload-guidelines") { + setModal("none"); + } + if (previewUploadedData) setPreviewUploadedData(undefined); + } + }; + + // Effect to update sections and selected section when data changes + useEffect(() => { + if (state) { + let uploadSections = state?.UploadConfiguration; + let schemas = state?.Schemas; + let UIConfiguration = state?.UIConfiguration; + if (schemas) setValidationSchemas(schemas); + if (uploadSections) { + setSelectedSection(uploadSections.length > 0 ? uploadSections[0] : null); + setSections(uploadSections); + } + } + }, []); + + // Memoized section options to prevent unnecessary re-renders + const sectionOptions = useMemo(() => { + if (!sections) return []; + return sections.map((item) => ( + e.active && e.templateIdentifier === item.id && !e.error)?.length !== 0} + /> + )); + }, [sections, selectedSection, fileDataList]); + + const showDownloadTemplate = () => { + if (selectedSection?.UploadFileTypes) { + const schema = getSchema(campaignType, selectedFileType?.id, selectedSection.id, validationSchemas); + if (schema?.template?.showTemplateDownload) return true; + } + return false; + }; + + // Handler for when a file type is selected for uplaod + const selectFileTypeHandler = (e) => { + if (selectedSection?.UploadFileTypes) { + const schema = getSchema(campaignType, e.target.name, selectedSection.id, validationSchemas); + setSelectedFileType(selectedSection.UploadFileTypes.find((item) => item.id === e.target.name)); + if (schema?.template?.showTemplateDownload) setModal("upload-modal"); + else UploadFileClickHandler(false); + return; + } + setToast({ + state: "error", + message: t("ERROR_UNKNOWN"), + }); + setLoader(false); + return; + }; + + // Memoized section components to prevent unnecessary re-renders + const sectionComponents = useMemo(() => { + if (!sections) return; + return sections.map((item) => ( + + )); + }, [sections, selectedSection, selectedFileType]); + + // Close model click handler + const closeModal = () => { + setResourceMapping([]); + setModal("none"); + }; + + // handler for show file upload screen + const UploadFileClickHandler = (download = false) => { + if (download) { + downloadTemplateHandler(); + } + setModal("none"); + setDataUpload(true); + }; + + const downloadTemplateHandler = () => { + const downloadParams = { + campaignType, + type: selectedFileType.id, + section: selectedSection.id, + setToast, + campaignData, + hierarchyType: campaignData?.hierarchyType, + Schemas: validationSchemas, + HierarchyConfigurations: state?.HierarchyConfigurations, + setLoader, + hierarchy, + t, + }; + downloadTemplate(downloadParams); + }; + // Effect for updating current session data in case of section change + useEffect(() => { + if (selectedSection) { + let file = fileDataList?.find((item) => item.active && item.templateIdentifier === selectedSection.id); + if (file?.resourceMapping) { + setSelectedFileType(selectedSection.UploadFileTypes.find((item) => item?.id === file?.fileType)); + setUploadedFileError(file?.error); + setFileData(file); + setDataPresent(true); + } else { + resetSectionState(); + } + } else { + resetSectionState(); + } + }, [selectedSection]); + + const resetSectionState = () => { + setUploadedFileError(null); + setSelectedFileType(null); + setDataPresent(false); + setResourceMapping([]); + setDataUpload(false); + }; + + // Function for handling upload file event + const UploadFileToFileStorage = async (file) => { + if (!file) return; + try { + // setting loader + setLoader("FILE_UPLOADING"); + let check; + let fileDataToStore; + let errorMsg; + let errorLocationObject; // object containing the location and type of error + let response; + let callMapping = false; + // Checking if the file follows name convention rules + if (!validateNamingConvention(file, selectedFileType["namingConvention"], setToast, t)) { + setLoader(false); + return; + } + + let schemaData; + if (selectedFileType.id !== SHAPEFILE) { + // Check if validation schema is present or not + schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); + if (!schemaData) { + setToast({ + state: "error", + message: t("ERROR_VALIDATION_SCHEMA_ABSENT"), + }); + setLoader(false); + return; + } + } + let resourceMappingData = []; + + // Handling different filetypes + switch (selectedFileType.id) { + case EXCEL: + // let response = handleExcelFile(file,schemaData); + try { + response = await handleExcelFile(file, schemaData, hierarchy, selectedFileType, {}, setUploadedFileError, t, campaignData); + check = response.check; + errorMsg = response.errorMsg; + errorLocationObject = response.errors; + fileDataToStore = response.fileDataToStore; + resourceMappingData = response?.tempResourceMappingData; + if (check === true) { + if (response?.toast) setToast(response.toast); + else setToast({ state: "success", message: t("FILE_UPLOADED_SUCCESSFULLY") }); + } else if (response.toast) { + setToast(response.toast); + } else { + setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); + } + if (response.interruptUpload) { + setLoader(false); + return; + } + } catch (error) { + console.error("Excel parsing error", error.message); + setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); + handleValidationErrorResponse(t("ERROR_UPLOADED_FILE")); + return; + } + break; + case GEOJSON: + try { + response = await handleGeojsonFile(file, schemaData, setUploadedFileError, t); + file = new File([file], file.name, { type: "application/geo+json" }); + if (response.check === false && response.stopUpload) { + setLoader(false); + setToast(response.toast); + return; + } + check = response.check; + errorMsg = response.error; + fileDataToStore = response.fileDataToStore; + callMapping = true; + } catch (error) { + // console.error("Geojson parsing error", error.message); + setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); + handleValidationErrorResponse(t("ERROR_UPLOADED_FILE")); + return; + } + break; + case SHAPEFILE: + try { + response = await handleShapefiles(file, schemaData, setUploadedFileError, selectedFileType, setToast, t); + file = new File([file], file.name, { type: "application/octet-stream" }); + check = response.check; + errorMsg = response.error; + fileDataToStore = response.fileDataToStore; + callMapping = true; + } catch (error) { + console.error("Shapefile parsing error", error.message); + setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); + handleValidationErrorResponse(t("ERROR_UPLOADED_FILE")); + return; + } + break; + default: + setToast({ + state: "error", + message: t("ERROR_UNKNOWN_FILETYPE"), + }); + setLoader(false); + return; + } + let filestoreId; + if (!errorMsg && !callMapping) { + try { + const filestoreResponse = await Digit.UploadServices.Filestorage(FILE_STORE, file, Digit.ULBService.getCurrentTenantId()); + if (filestoreResponse?.data?.files?.length > 0) { + filestoreId = filestoreResponse?.data?.files[0]?.fileStoreId; + } else { + errorMsg = t("ERROR_UPLOADING_FILE"); + setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); + setFileData((previous) => ({ ...previous, error: errorMsg })); + setUploadedFileError(errorMsg); + } + } catch (errorData) { + console.error(errorData.message); + errorMsg = t("ERROR_UPLOADING_FILE"); + setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); + setUploadedFileError(errorMsg); + handleValidationErrorResponse(t("ERROR_UPLOADING_FILE")); + } + } + + if (selectedFileType.id === EXCEL) { + resourceMappingData = resourceMappingData.map((item) => ({ ...item, filestoreId })); + } + let uuid = uuidv4(); + // creating a fileObject to save all the data collectively + let fileObject = { + id: uuid, + templateIdentifier: `${selectedSection.id}`, + fileName: file.name, + section: selectedSection.id, + fileType: selectedFileType.id, + data: fileDataToStore, + file, + error: errorMsg ? errorMsg : null, + filestoreId, + resourceMapping: resourceMappingData, + active: true, + errorLocationObject, // contains location and type of error + }; + setFileDataList((prevFileDataList) => { + let temp = _.cloneDeep(prevFileDataList); + if (!temp) return temp; + let index = prevFileDataList?.findIndex((item) => item.active && item.templateIdentifier === selectedSection.id); + if (index !== -1) + temp[index] = { ...temp[index], resourceMapping: temp[index]?.resourceMapping.map((e) => ({ active: false, ...e })), active: false }; + temp.push(fileObject); + return temp; + }); + setFileData(fileObject); + if (errorMsg === undefined && callMapping) { + setModal("spatial-data-property-mapping"); + } + setDataPresent(true); + setLoader(false); + } catch (error) { + console.error(error.message); + console.error("File Upload error", error?.message); + setUploadedFileError("ERROR_UPLOADING_FILE"); + setLoader(false); + } + }; + + // Reupload the selected file + const reuplaodFile = () => { + setResourceMapping([]); + setFileData(undefined); + setDataPresent(false); + setUploadedFileError(null); + setDataUpload(false); + setSelectedFileType(null); + closeModal(); + }; + + // Function for creating blob out of data + const dataToBlob = async () => { + try { + let blob; + const schema = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); + switch (fileData.fileType) { + case EXCEL: + if (fileData?.errorLocationObject?.length !== 0) + blob = await prepareExcelFileBlobWithErrors(fileData.data, fileData.errorLocationObject, schema, hierarchy, t); + else blob = fileData.file; + break; + case SHAPEFILE: + case GEOJSON: + if (fileData?.data) { + const result = Digit.Utils.microplan.convertGeojsonToExcelSingleSheet(fileData?.data?.features, fileData?.section); + if (fileData?.errorLocationObject?.length !== 0) + blob = await prepareExcelFileBlobWithErrors(result, fileData.errorLocationObject, schema, hierarchy, t); + } + break; + } + return blob; + } catch (error) { + console.error("Error generating blob:", error); + return; + } + }; + + // Download the selected file + const downloadFile = async () => { + setLoader("LOADING"); + try { + let blob = await dataToBlob(); + if (blob) { + // Crating a url object for the blob + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = url; + + // Forming a name for downloaded file + let fileNameParts = fileData.fileName.split("."); + fileNameParts.pop(); + fileNameParts.push("xlsx"); + fileNameParts.join("."); + + //Downloading the file + link.download = fileNameParts.join("."); + link.click(); + URL.revokeObjectURL(url); + } else { + let downloadUrl = await Digit.UploadServices.Filefetch([fileData.filestoreId], Digit.ULBService.getCurrentTenantId()); + const link = document.createElement("a"); + link.href = downloadUrl; + // Forming a name for downloaded file + let fileNameParts = fileData.fileName.split("."); + fileNameParts.pop(); + fileNameParts.push("xlsx"); + fileNameParts.join("."); + link.download = fileNameParts; // Replace with the desired file name and extension + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } + } catch (error) { + console.error(error.message); + setToast({ + state: "error", + message: t("ERROR_UNKNOWN_ERROR"), + }); + } + setLoader(false); + }; + + // delete the selected file + const deleteFile = () => { + setResourceMapping([]); + setFileDataList((previous) => { + let temp = _.cloneDeep(previous); + if (!temp) return temp; + let index = temp?.findIndex((item) => { + return item.id === fileData.id; + }); + if (index !== -1) + temp[index] = { ...temp[index], resourceMapping: temp[index]?.resourceMapping.map((e) => ({ active: false, ...e })), active: false }; + return temp; + }); + setFileData(undefined); + setDataPresent(false); + setUploadedFileError(null); + setDataUpload(false); + setSelectedFileType(null); + closeModal(); + }; + + // Function for handling the validations for geojson and shapefiles after mapping of properties + const validationForMappingAndDataSaving = async () => { + try { + setLoader("LOADING"); + const schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); + let error; + if (!checkForSchemaData(schemaData)) return; + const { data, valid, errors } = computeMappedDataAndItsValidations(schemaData); + error = errors; + if (!valid) return; + let filestoreId; + if (!error) { + filestoreId = await saveFileToFileStore(); + } + let resourceMappingData; + if (filestoreId) { + resourceMappingData = resourceMapping.map((item) => { + return { ...item, filestoreId }; + }); + } + setResourceMapping([]); + + let boundaryDataAgainstBoundaryCode = (await boundaryDataGeneration(schemaData, campaignData, t)) || {}; + const mappedToList = resourceMappingData.map((item) => item.mappedTo); + if (hierarchy.every((item) => !mappedToList.includes(t(item)))) { + data.features.forEach((feature) => { + const boundaryCode = feature.properties.boundaryCode; + let additionalDetails = {}; + for (let i = 0; i < hierarchy.length; i++) { + if (boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] || boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] === "") { + additionalDetails[hierarchy[i]] = boundaryDataAgainstBoundaryCode[boundaryCode][i]; + } else { + additionalDetails[hierarchy[i]] = ""; + } + } + feature.properties = { ...additionalDetails, ...feature.properties }; + }); + } + + let fileObject = _.cloneDeep(fileData); + fileObject = { ...fileData, data, resourceMapping: resourceMappingData, error: error ? error : null, filestoreId }; + setFileData(fileObject); + setFileDataList((prevFileDataList) => { + let temp = _.cloneDeep(prevFileDataList); + if (!temp) return temp; + let index = prevFileDataList?.findIndex((item) => item.id === fileData.id); + if (index !== -1) temp[index] = fileObject; + // temp.push(fileObject); + return temp; + }); + + setToast({ state: "success", message: t("FILE_UPLOADED_SUCCESSFULLY") }); + setLoader(false); + } catch (error) { + console.error(error.message); + setUploadedFileError(t("ERROR_UPLOADING_FILE")); + setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); + setLoader(false); + handleValidationErrorResponse("ERROR_UPLOADING_FILE"); + } + }; + const saveFileToFileStore = async () => { + try { + const filestoreResponse = await Digit.UploadServices.Filestorage(FILE_STORE, fileData.file, Digit.ULBService.getCurrentTenantId()); + if (filestoreResponse?.data?.files?.length > 0) { + return filestoreResponse?.data?.files[0]?.fileStoreId; + } + error = t("ERROR_UPLOADING_FILE"); + setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); + setResourceMapping([]); + setUploadedFileError(error); + } catch (errorData) { + console.error("Error while uploading file to filestore: ", errorData?.message); + let error = t("ERROR_UPLOADING_FILE"); + handleValidationErrorResponse(error); + setResourceMapping([]); + return; + } + }; + const computeMappedDataAndItsValidations = (schemaData) => { + const data = computeGeojsonWithMappedProperties(); + const response = geojsonPropetiesValidation(data, schemaData.schema, fileData?.section, t); + if (!response.valid) { + handleValidationErrorResponse(response.message, response.errors); + return { data: data, errors: response.errors, valid: response.valid }; + } + return { data: data, valid: response.valid }; + }; + + const handleValidationErrorResponse = (error, errorLocationObject = {}) => { + const fileObject = fileData; + if (fileObject) { + fileObject.error = [error]; + if (errorLocationObject) fileObject.errorLocationObject = errorLocationObject; + setFileData((previous) => ({ ...previous, error, errorLocationObject })); + setFileDataList((prevFileDataList) => { + let temp = _.cloneDeep(prevFileDataList); + if (!temp) return temp; + let index = prevFileDataList?.findIndex((item) => item.id === fileData.id); + temp[index] = fileObject; + return temp; + }); + setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); + if (error) setUploadedFileError(error); + } + setLoader(false); + }; + + const checkForSchemaData = (schemaData) => { + if (resourceMapping?.length === 0) { + setToast({ state: "warning", message: t("WARNING_INCOMPLETE_MAPPING") }); + setLoader(false); + return false; + } + + if (!schemaData || !schemaData.schema || !schemaData.schema["Properties"]) { + setToast({ state: "error", message: t("ERROR_VALIDATION_SCHEMA_ABSENT") }); + setLoader(false); + return; + } + + let columns = []; + if (schemaData?.doHierarchyCheckInUploadedData) { + columns.push(...hierarchy); + } + columns.push( + ...Object.entries(schemaData?.schema?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.isRequired) { + acc.push(key); + } + return acc; + }, []) + ); + + const resourceMappingLength = resourceMapping.filter((e) => !!e?.mappedFrom && columns.includes(e?.mappedTo)).length; + if (resourceMappingLength !== columns?.length) { + setToast({ state: "warning", message: t("WARNING_INCOMPLETE_MAPPING") }); + setLoader(false); + return false; + } + setModal("none"); + return true; + }; + + const computeGeojsonWithMappedProperties = () => { + const schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); + let schemaKeys; + if (schemaData?.schema?.["Properties"]) schemaKeys = hierarchy.concat(Object.keys(schemaData.schema["Properties"])); + // Sorting the resourceMapping list inorder to maintain the column sequence + const sortedSecondList = Digit.Utils.microplan.sortSecondListBasedOnFirstListOrder(schemaKeys, resourceMapping); + // Creating a object with input data with MDMS keys + const newFeatures = fileData.data["features"].map((item) => { + let newProperties = {}; + + sortedSecondList.forEach((e) => { + newProperties[e["mappedTo"]] = item["properties"][e["mappedFrom"]]; + }); + item["properties"] = newProperties; + return item; + }); + let data = fileData.data; + data["features"] = newFeatures; + return data; + }; + + // Handler for checing file extension and showing errors in case it is wrong + const onTypeErrorWhileFileUpload = () => { + switch (selectedFileType.id) { + case EXCEL: + setToast({ state: "error", message: t("ERROR_EXCEL_EXTENSION") }); + break; + case GEOJSON: + setToast({ state: "error", message: t("ERROR_GEOJSON_EXTENSION") }); + break; + case SHAPEFILE: + setToast({ state: "error", message: t("ERROR_SHAPE_FILE_EXTENSION") }); + break; + } + }; + + // Cancle mapping and uplaod in case of geojson and shapefiles + const cancelUpload = () => { + setFileDataList((previous) => { + let temp = previous?.filter((item) => item.id !== fileData?.id); + return temp; + }); + setFileData(undefined); + setDataPresent(false); + setUploadedFileError(null); + setDataUpload(false); + setSelectedFileType(null); + closeModal(); + }; + + const openDataPreview = () => { + let data; + switch (fileData.fileType) { + case EXCEL: + data = fileData.data; + break; + case SHAPEFILE: + case GEOJSON: + if (!fileData || !fileData.data) { + setToast({ + state: "error", + message: t("ERROR_DATA_NOT_PRESENT"), + }); + return; + } + data = Digit.Utils.microplan.convertGeojsonToExcelSingleSheet(fileData?.data?.features, fileData?.section); + break; + } + if (!data || Object.keys(data).length === 0) { + setToast({ + state: "error", + message: t("ERROR_DATA_NOT_PRESENT"), + }); + return; + } + setPreviewUploadedData(data); + }; + + if (isCampaignLoading || ishierarchyLoading) { + return ( +
+ +
+ ); + } + + return ( + <> +
+
+
+ {!dataPresent ? ( + dataUpload ? ( +
+ e.id === selectedSection.id)[0]} + selectedSection={selectedSection} + selectedFileType={selectedFileType} + UploadFileToFileStorage={UploadFileToFileStorage} + onTypeError={onTypeErrorWhileFileUpload} + downloadTemplateHandler={downloadTemplateHandler} + showDownloadTemplate={showDownloadTemplate} + /> +
+ ) : ( +
{sectionComponents}
+ ) + ) : ( +
+ {selectedSection != null && fileData !== null && ( + { + setModal("reupload-conformation"); + }} + DownloadFile={downloadFile} + DeleteFile={() => { + setModal("delete-conformation"); + }} + error={uploadedFileError} + openDataPreview={openDataPreview} + downloadTemplateHandler={downloadTemplateHandler} + showDownloadTemplate={showDownloadTemplate} + /> + )} +
+ )} + {!dataPresent && dataUpload && ( + { + setModal("upload-guidelines"); + }} + t={t} + /> + )} +
+ +
{sectionOptions}
+
+ +
+ {modal === "upload-modal" && ( + { + closeModal(); + setSelectedFileType(null); + }} + LeftButtonHandler={() => UploadFileClickHandler(false)} + RightButtonHandler={() => UploadFileClickHandler(true)} + sections={sections} + popupModuleActionBarStyles={{ + flex: 1, + justifyContent: "space-between", + padding: "1rem", + gap: "1rem", + }} + footerLeftButtonBody={} + footerRightButtonBody={} + header={ + + } + bodyText={t("INSTRUCTIONS_DOWNLOAD_TEMPLATE_FOR_" + selectedSection.code + "_" + selectedFileType.code)} + /> + )} + {modal === "delete-conformation" && ( + } + actionCancelLabel={t("YES")} + actionCancelOnSubmit={deleteFile} + actionSaveLabel={t("NO")} + actionSaveOnSubmit={closeModal} + > +
+

{t("INSTRUCTIONS_DELETE_FILE_CONFIRMATION")}

+
+
+ )} + {modal === "reupload-conformation" && ( + } + actionCancelLabel={t("YES")} + actionCancelOnSubmit={reuplaodFile} + actionSaveLabel={t("NO")} + actionSaveOnSubmit={closeModal} + > +
+

{t("INSTRUCTIONS_REUPLOAD_FILE_CONFIRMATION")}

+
+
+ )} + {modal === "spatial-data-property-mapping" && ( + } + actionSaveOnSubmit={validationForMappingAndDataSaving} + actionSaveLabel={t("COMPLETE_MAPPING")} + headerBarEnd={} + > +
+

{t("INSTRUCTION_SPATIAL_DATA_PROPERTY_MAPPING")}

+
+ +
+ )} + {modal === "upload-guidelines" && ( + + } + headerBarEnd={} + > + + + )} + {loader && } + + {previewUploadedData && ( +
+ setPreviewUploadedData(undefined)} + onDownload={downloadFile} + /> +
+ )} +
+
+ + ); +}; + +//find guideline +const findGuideLine = (campaignType, type, section, guidelineArray) => { + if (!guidelineArray) return guidelineArray; + return guidelineArray.find( + (guideline) => + guideline.fileType === type && guideline.templateIdentifier === section && (!guideline.campaignType || guideline.campaignType === campaignType) + )?.guidelines; +}; + +// Component for rendering individual section option +const UploadSection = ({ item, selected, setSelectedSection, uploadDone }) => { + const { t } = useTranslation(); + // Handle click on section option + const handleClick = () => { + setSelectedSection(item); + }; + + return ( +
+
+ +
+

{t(item.code)}

+ {uploadDone && ( +
+ +
+ )} +
+ ); +}; + +const UploadInstructions = ({ setModal, t }) => { + return ( + + {t("REFER")} +
+ {t("INFORMATION_DESCRIPTION_LINK")} +
+
, + ]} + /> + ); +}; + +// Component for rendering individual upload option +const UploadComponents = ({ item, selected, uploadOptions, selectedFileType, selectFileTypeHandler }) => { + const { t } = useTranslation(); + const title = item.code; + + // Component for rendering individual upload option container + const UploadOptionContainer = ({ item, selectedFileType, selectFileTypeHandler }) => { + const [isHovered, setIsHovered] = useState(false); + + const handleMouseEnter = () => { + setIsHovered(true); + }; + + const handleMouseLeave = () => { + setIsHovered(false); + }; + + return ( +
+ +

{t(item.code)}

+ +
+ ); + }; + + return ( +
+
+
+

{t(`HEADING_UPLOAD_DATA_${title}`)}

+
+ +

{t(`INSTRUCTIONS_DATA_UPLOAD_OPTIONS_${title}`)}

+
+
+ {uploadOptions && + uploadOptions.map((item) => ( + + ))} +
+
+ ); +}; + +// Component for uploading file +const FileUploadComponent = ({ + selectedSection, + selectedFileType, + UploadFileToFileStorage, + section, + onTypeError, + downloadTemplateHandler, + showDownloadTemplate, +}) => { + if (!selectedSection || !selectedFileType) return
; + const { t } = useTranslation(); + let types; + section["UploadFileTypes"].forEach((item) => { + if (item.id === selectedFileType.id) types = item.fileExtension; + }); + return ( +
+
+
+

{t(`HEADING_FILE_UPLOAD_${selectedSection.code}_${selectedFileType.code}`)}

+ {showDownloadTemplate() && ( + + )} +
+

{t(`INSTRUCTIONS_FILE_UPLOAD_FROM_TEMPLATE_${selectedSection.code}`)}

+ +
+ +
+ {t(`INSTRUCTIONS_UPLOAD_${selectedFileType.code}`)} 
{t("INSTRUCTIONS_UPLOAD_BROWSE_FILES")}
+
+
+
+
+
+ ); +}; + +// Component to display uploaded file +const UploadedFile = ({ + selectedSection, + selectedFileType, + file, + ReuplaodFile, + DownloadFile, + DeleteFile, + error, + openDataPreview, + downloadTemplateHandler, + showDownloadTemplate, +}) => { + const { t } = useTranslation(); + const [errorList, setErrorList] = useState([]); + useEffect(() => { + let tempErrorList = []; + if (file?.errorLocationObject) { + for (const [sheetName, values] of Object.entries(file?.errorLocationObject)) { + for (const [row, columns] of Object.entries(values)) { + for (const [column, errors] of Object.entries(columns)) { + for (const error of errors) { + let convertedError; + if (typeof error === "object") { + let { error: actualError, ...otherProperties } = error; + convertedError = t(actualError, otherProperties?.values); + } else { + convertedError = t(error); + } + tempErrorList.push( + t("ERROR_UPLOAD_DATA_LOCATION_AND_MESSAGE", { + rowNumber: row, + columnName: t(column), + error: convertedError, + sheetName: sheetName, + }) + ); + } + } + } + } + } + if (tempErrorList.length !== 0) { + setErrorList(tempErrorList); + } + }, [file]); + return ( +
+
+
+

{t(`HEADING_FILE_UPLOAD_${selectedSection.code}_${selectedFileType.code}`)}

+ {showDownloadTemplate() && ( + + )} +
+

{t(`INSTRUCTIONS_FILE_UPLOAD_FROM_TEMPLATE_${selectedSection.code}`)}

+ +
+
+
+ +
+

{file.fileName}

+
+
+ + + +
+
+
+ {error && Array.isArray(error) && ( + , +
+ {error?.map((item) => { + if (item !== "ERROR_REFER_UPLOAD_PREVIEW_TO_SEE_THE_ERRORS") { + return

{t(item)}

; + } + return null; + })} + {errorList.length !== 0 && errorList.map((item) =>

{item}

)} +
, + ]} + /> + )} +
+ ); +}; + +// Function for checking the uploaded file for nameing conventions +const validateNamingConvention = (file, namingConvention, setToast, t) => { + try { + let processedConvention = namingConvention.replace("$", ".[^.]*$"); + const regx = new RegExp(processedConvention); + + if (regx && !regx.test(file.name)) { + setToast({ + state: "error", + message: t("ERROR_NAMING_CONVENSION"), + }); + return false; + } + return true; + } catch (error) { + console.error(error.message); + setToast({ + state: "error", + message: t("ERROR_UNKNOWN"), + }); + } +}; + +// Function for reading ancd checking geojson data +const readGeojson = async (file, t) => { + return new Promise((resolve, reject) => { + if (!file) return resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } }); + + const reader = new FileReader(); + reader.onload = (e) => { + try { + const geoJSONData = JSON.parse(e.target.result); + const trimmedGeoJSONData = trimJSON(geoJSONData); + resolve({ valid: true, geojsonData: trimmedGeoJSONData }); + } catch (error) { + resolve({ valid: false, toast: { state: "error", message: t("ERROR_INCORRECT_FORMAT") } }); + } + }; + reader.onerror = (error) => { + resolve({ valid: false, toast: { state: "error", message: t("ERROR_CORRUPTED_FILE") } }); + }; + + reader.readAsText(file); + }); +}; + +// Function to recursively trim leading and trailing spaces from string values in a JSON object +const trimJSON = (jsonObject) => { + if (typeof jsonObject !== "object") { + return jsonObject; // If not an object, return as is + } + + if (Array.isArray(jsonObject)) { + return jsonObject.map((item) => trimJSON(item)); // If it's an array, recursively trim each item + } + + const trimmedObject = {}; + for (const key in jsonObject) { + if (Object.hasOwn(jsonObject, key)) { + const value = jsonObject[key]; + // Trim string values, recursively trim objects + trimmedObject[key.trim()] = typeof value === "string" ? value.trim() : typeof value === "object" ? trimJSON(value) : value; + } + } + return trimmedObject; +}; +// Function for reading and validating shape file data +const readAndValidateShapeFiles = async (file, t, namingConvention) => { + return new Promise(async (resolve, reject) => { + if (!file) { + resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } }); + } + const fileRegex = new RegExp(namingConvention.replace("$", ".*$")); + // File Size Check + const fileSizeInBytes = file.size; + const maxSizeInBytes = 2 * 1024 * 1024 * 1024; // 2 GB + + // Check if file size is within limit + if (fileSizeInBytes > maxSizeInBytes) + resolve({ valid: false, message: t("ERROR_FILE_SIZE"), toast: { state: "error", message: t("ERROR_FILE_SIZE") } }); + + try { + const zip = await JSZip.loadAsync(file); + const isEPSG4326 = await checkProjection(zip); + if (!isEPSG4326) { + resolve({ valid: false, message: t("ERROR_WRONG_PRJ"), toast: { state: "error", message: t("ERROR_WRONG_PRJ") } }); + } + const files = Object.keys(zip.files); + const allFilesMatchRegex = files.every((fl) => { + return fileRegex.test(fl); + }); + let regx = new RegExp(namingConvention.replace("$", "\\.shp$")); + const shpFile = zip.file(regx)[0]; + regx = new RegExp(namingConvention.replace("$", "\\.shx$")); + const shxFile = zip.file(regx)[0]; + regx = new RegExp(namingConvention.replace("$", "\\.dbf$")); + const dbfFile = zip.file(regx)[0]; + + let geojson; + if (shpFile && dbfFile) { + const shpArrayBuffer = await shpFile.async("arraybuffer"); + const dbfArrayBuffer = await dbfFile.async("arraybuffer"); + + geojson = shp.combine([shp.parseShp(shpArrayBuffer), shp.parseDbf(dbfArrayBuffer)]); + } + if (shpFile && dbfFile && shxFile && allFilesMatchRegex) resolve({ valid: true, data: geojson }); + else if (!allFilesMatchRegex) + resolve({ + valid: false, + message: [t("ERROR_CONTENT_NAMING_CONVENSION")], + toast: { state: "error", data: geojson, message: t("ERROR_CONTENT_NAMING_CONVENSION") }, + }); + else if (!shpFile) + resolve({ valid: false, message: [t("ERROR_SHP_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_SHP_MISSING") } }); + else if (!dbfFile) + resolve({ valid: false, message: [t("ERROR_DBF_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_DBF_MISSING") } }); + else if (!shxFile) + resolve({ valid: false, message: [t("ERROR_SHX_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_SHX_MISSING") } }); + } catch (error) { + resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } }); + } + }); +}; + +// Function for projections check in case of shapefile data +const checkProjection = async (zip) => { + const prjFile = zip.file(/.prj$/i)[0]; + if (!prjFile) { + return "absent"; + } + + const prjText = await prjFile.async("text"); + + if (prjText.includes("GEOGCS") && prjText.includes("WGS_1984") && prjText.includes("DATUM") && prjText.includes("D_WGS_1984")) { + return "EPSG:4326"; + } + return false; +}; + +// Function to handle the template download +const downloadTemplate = async ({ + campaignType, + type, + section, + setToast, + campaignData, + hierarchyType, + Schemas, + HierarchyConfigurations, + setLoader, + hierarchy, + t, +}) => { + try { + setLoader("LOADING"); + // Find the template based on the provided parameters + const schema = getSchema(campaignType, type, section, Schemas); + const hierarchyLevelName = HierarchyConfigurations?.find((item) => item.name === "devideBoundaryDataBy")?.value; + let template = await createTemplate({ + hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets, + hierarchyLevelName, + addFacilityData: schema?.template?.includeFacilityData, + schema, + boundaries: campaignData?.boundaries, + tenantId: Digit.ULBService.getCurrentTenantId(), + hierarchyType, + t, + }); + const translatedTemplate = translateTemplate(template, t); + + // Create a new workbook + const workbook = new ExcelJS.Workbook(); + + formatTemplate(translatedTemplate, workbook); + + // Color headers + colorHeaders( + workbook, + [...hierarchy.map((item) => t(item)), t(commonColumn)], + schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [], + [] + ); + // protextData + await protectData({ + workbook, + hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets, + addFacilityData: schema?.template?.includeFacilityData, + schema, + t, + }); + + // Write the workbook to a buffer + workbook.xlsx.writeBuffer({ compression: true }).then((buffer) => { + // Create a Blob from the buffer + const blob = new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); + // Create a URL for the Blob + const url = URL.createObjectURL(blob); + // Create a link element and simulate click to trigger download + const link = document.createElement("a"); + link.href = url; + link.download = t(section) + ".xlsx"; + link.click(); + // Revoke the URL to release the Blob + URL.revokeObjectURL(url); + setLoader(false); + }); + } catch (error) { + setLoader(false); + console.error(error?.message); + setToast({ state: "error", message: t("ERROR_DOWNLOADING_TEMPLATE") }); + } +}; + +const protectData = async ({ workbook, hierarchyLevelWiseSheets = true, addFacilityData = false, schema, t }) => { + if (hierarchyLevelWiseSheets) { + if (addFacilityData) { + await freezeSheetValues(workbook, t(BOUNDARY_DATA_SHEET)); + await performUnfreezeCells(workbook, t(FACILITY_DATA_SHEET)); + if (schema?.template?.propertiesToHide && Array.isArray(schema.template.propertiesToHide)) { + let tempPropertiesToHide = schema?.template?.propertiesToHide.map((item) => t(generateLocalisationKeyForSchemaProperties(item))); + await hideUniqueIdentifierColumn(workbook, t(FACILITY_DATA_SHEET), tempPropertiesToHide); + } + if (schema?.template?.facilitySchemaApiMapping) { + } else { + } + } else { + await freezeWorkbookValues(workbook); + await unfreezeColumnsByHeader( + workbook, + schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [] + ); + } + } else { + // total boundary Data in one sheet + if (addFacilityData) { + await freezeSheetValues(workbook, t(BOUNDARY_DATA_SHEET)); + await performUnfreezeCells(workbook, t(FACILITY_DATA_SHEET)); + if (schema?.template?.propertiesToHide && Array.isArray(schema.template.propertiesToHide)) { + let tempPropertiesToHide = schema?.template?.propertiesToHide.map((item) => t(generateLocalisationKeyForSchemaProperties(item))); + await hideUniqueIdentifierColumn(workbook, t(FACILITY_DATA_SHEET), tempPropertiesToHide); + } + + if (schema?.template?.facilitySchemaApiMapping) { + } else { + } + } else { + await freezeWorkbookValues(workbook); + await unfreezeColumnsByHeader( + workbook, + schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [] + ); + } + } +}; + +const colorHeaders = async (workbook, headerList1, headerList2, headerList3) => { + try { + // Iterate through each sheet + workbook.eachSheet((sheet, sheetId) => { + // Get the first row + const firstRow = sheet.getRow(1); + + // Iterate through each cell in the first row + firstRow.eachCell((cell, colNumber) => { + const cellValue = cell.value.toString(); + + // Check conditions and set colors + if (headerList1?.includes(cellValue)) { + cell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "ff9248" }, + }; + } else if (headerList2?.includes(cellValue)) { + cell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "93C47D" }, + }; + } else if (headerList3?.includes(cellValue)) { + cell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "CCCC00" }, + }; + } + }); + }); + } catch (error) { + console.error("Error coloring headers:", error); + } +}; + +const formatTemplate = (template, workbook) => { + template.forEach(({ sheetName, data }) => { + // Create a new worksheet with properties + const worksheet = workbook.addWorksheet(sheetName, { + // properties: { + // outlineLevelCol: 1, + // defaultRowHeight: 15, + // }, + }); + data?.forEach((row, index) => { + const worksheetRow = worksheet.addRow(row); + + // Apply fill color to each cell in the first row and make cells bold + if (index === 0) { + worksheetRow.eachCell((cell, colNumber) => { + // // Set cell fill color + // cell.fill = { + // type: "pattern", + // pattern: "solid", + // fgColor: { + // argb: headerToColorwithColor1.includes(cell.value) ? "ff9248" : headerToColorwithColor2.includes(cell.value) ? "93C47D" : undefined, + // }, + // }; + + // Set font to bold + cell.font = { bold: true }; + + // Enable text wrapping + cell.alignment = { wrapText: true }; + + // Update column width based on the length of the cell's text + const currentWidth = worksheet.getColumn(colNumber).width || SHEET_COLUMN_WIDTH; // Default width or current width + const newWidth = Math.max(currentWidth, cell.value.toString().length + 2); // Add padding + worksheet.getColumn(colNumber).width = newWidth; + }); + } + }); + updateFontNameToRoboto(worksheet); + }); +}; + +const translateTemplate = (template, t) => { + // Initialize an array to hold the transformed result + const transformedResult = []; + + // Iterate over each sheet in the divided data + for (const sheet of template) { + const sheetData = sheet.data; + + // Find the index of the boundaryCode column in the header row + const boundaryCodeIndex = sheetData[0].indexOf(commonColumn); + + const sheetName = t(sheet.sheetName); + const transformedSheet = { + sheetName: sheetName.length > 31 ? sheetName.slice(0, 31) : sheetName, + data: [], + }; + + // Iterate over each row in the sheet data + for (const [rowIndex, row] of sheetData.entries()) { + // Transform each entity in the row using the transformFunction + const transformedRow = row.map((entity, index) => { + // Skip transformation for the boundaryCode column + if ((index === boundaryCodeIndex && rowIndex !== 0) || typeof entity === "number") { + return entity; + } + return t(entity); + }); + transformedSheet.data.push(transformedRow); + } + + // Add the transformed sheet to the transformed result + transformedResult.push(transformedSheet); + } + + return transformedResult; +}; + +// get schema for validation +const getSchema = (campaignType, type, section, schemas) => { + return schemas.find((schema) => { + if (!schema.campaignType) { + return schema.type === type && schema.section === section; + } + return schema.campaignType === campaignType && schema.type === type && schema.section === section; + }); +}; + +// Uplaod GuideLines +const UploadGuideLines = ({ uploadGuideLines, t }) => { + const formMsgFromObject = (item) => { + if (!item?.hasLink) { + return t(item?.name); + } + return ( + <> + {t(item?.name)} {t(item?.linkName)}{" "} + + ); + }; + return ( +
+ {uploadGuideLines?.map((item, index) => ( +
+

+ {t(index + 1)}. +

+
+ {formMsgFromObject(item)} +
+
+ ))} +
+ ); +}; + +const CustomIcon = (props) => { + if (!props.Icon) return null; + return ; +}; + +const generateLocalisationKeyForSchemaProperties = (code) => { + if (!code) return code; + return SCHEMA_PROPERTIES_PREFIX + "_" + code; +}; +// Performs resource mapping and data filtering for Excel files based on provided schema data, hierarchy, and file data. +const resourceMappingAndDataFilteringForExcelFiles = (schemaData, hierarchy, selectedFileType, fileDataToStore, t) => { + let resourceMappingData = []; + let newFileData = {}; + let toAddInResourceMapping; + if (selectedFileType.id === EXCEL && fileDataToStore) { + // Extract all unique column names from fileDataToStore and then doing thir resource mapping + const columnForMapping = new Set(Object.values(fileDataToStore).flatMap((value) => value?.[0] || [])); + if (schemaData?.schema?.["Properties"]) { + const schemaKeys = Object.keys(schemaData.schema["Properties"]) + .map((item) => generateLocalisationKeyForSchemaProperties(item)) + .concat([...hierarchy, commonColumn]); + schemaKeys.forEach((item) => { + if (columnForMapping.has(t(item))) { + resourceMappingData.push({ + mappedFrom: t(item), + mappedTo: item, + }); + } + }); + } + + // Filtering the columns with respect to the resource mapping and removing the columns that are not needed + Object.entries(fileDataToStore).forEach(([key, value]) => { + let data = []; + let headers = []; + let toRemove = []; + if (value && value.length > 0) { + value[0].forEach((item, index) => { + const mappedTo = resourceMappingData.find((e) => e.mappedFrom === item)?.mappedTo; + if (!mappedTo) { + toRemove.push(index); + return; + } + headers.push(revertLocalisationKey(mappedTo)); + return; + }); + for (let i = 1; i < value?.length; i++) { + let temp = []; + for (let j = 0; j < value[i].length; j++) { + if (!toRemove.includes(j)) { + temp.push(value[i][j]); + } + } + data.push(temp); + } + } + newFileData[key] = [headers, ...data]; + }); + } + return { tempResourceMappingData: resourceMappingData, tempFileDataToStore: newFileData }; +}; +const revertLocalisationKey = (localisedCode) => { + if (!localisedCode || !localisedCode.startsWith(SCHEMA_PROPERTIES_PREFIX + "_")) { + return localisedCode; + } + return localisedCode.substring(SCHEMA_PROPERTIES_PREFIX.length + 1); +}; +const prepareExcelFileBlobWithErrors = async (data, errors, schema, hierarchy, t) => { + let tempData = { ...data }; + // Process each dataset within the data object + const processedData = {}; + let headerList1 = []; + let headerList2 = [t("MICROPLAN_ERROR_COLUMN")]; + const schemaCols = schema?.schema?.Properties ? Object.keys(schema.schema.Properties) : []; + for (const key in tempData) { + if (Object.hasOwn(tempData, key)) { + const dataset = [...tempData[key]]; + + // Add the 'error' column to the header + dataset[0] = dataset[0].map((item) => { + if (item !== commonColumn && schemaCols.includes(item)) { + return t(generateLocalisationKeyForSchemaProperties(item)); + } + return t(item); + }); + headerList1.push(...dataset[0]); + // Process each data row + if (errors) { + dataset[0].push(t("MICROPLAN_ERROR_COLUMN")); + let headerCount = 0; + for (let i = 1; i < dataset.length; i++) { + const row = dataset[i]; + if (i === 1 && row) { + headerCount = row.length; + } + + if (headerCount > row.length) { + row.push(...Array(headerCount - row.length).fill("")); + } + + // Check if there are errors for the given commonColumnData + const errorInfo = errors?.[key]?.[i - 1]; + if (errorInfo) { + let rowDataAddOn = Object.entries(errorInfo) + .map(([key, value]) => { + return t(key) + ": " + value.map((item) => t(item)).join(", "); + }) + .join("\n"); + row.push(rowDataAddOn); + } else { + row.push(""); + } + } + } + processedData[key] = dataset; + } + } + const errorColumn = "MICROPLAN_ERROR_COLUMN"; + const style = { + font: { color: { argb: "B91900" } }, + border: { + top: { style: "thin", color: { argb: "B91900" } }, + left: { style: "thin", color: { argb: "B91900" } }, + bottom: { style: "thin", color: { argb: "B91900" } }, + right: { style: "thin", color: { argb: "B91900" } }, + }, + }; + const workbook = await convertToWorkBook(processedData, { errorColumn, style }); + colorHeaders( + workbook, + [...hierarchy.map((item) => t(item)), t(commonColumn)], + schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [], + [] + ); + + // protextData + await protectData({ + workbook, + hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets, + addFacilityData: schema?.template?.includeFacilityData, + schema, + t, + }); + return await workbook.xlsx.writeBuffer({ compression: true }).then((buffer) => { + // Create a Blob from the buffer + return new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); + }); + // return xlsxBlob; +}; +const convertToWorkBook = async (jsonData, columnWithStyle) => { + const workbook = new ExcelJS.Workbook(); + + // Iterate over each sheet in jsonData + for (const [sheetName, data] of Object.entries(jsonData)) { + // Create a new worksheet + const worksheet = workbook.addWorksheet(sheetName); + + // Convert data to worksheet + for (const row of data) { + const newRow = worksheet.addRow(row); + // Apply red font color to the errorColumn if it exists + let errorColumnIndex = data[0].indexOf(columnWithStyle?.errorColumn); + if (columnWithStyle?.errorColumn && errorColumnIndex !== -1) { + const columnIndex = errorColumnIndex + 1; + if (columnIndex > 0) { + const newCell = newRow.getCell(columnIndex); + if (columnWithStyle.style && newCell) for (const key in columnWithStyle.style) newCell[key] = columnWithStyle.style[key]; + } + } + } + + // Make the first row bold + if (worksheet.getRow(1)) { + worksheet.getRow(1).font = { bold: true }; + } + + // Set column widths + const columnCount = data?.[0]?.length || 0; + const wscols = Array(columnCount).fill({ width: 30 }); + wscols.forEach((col, colIndex) => { + worksheet.getColumn(colIndex + 1).width = col.width; + }); + } + return workbook; +}; +const boundaryDataGeneration = async (schemaData, campaignData, t) => { + let boundaryDataAgainstBoundaryCode = {}; + if (schemaData && !schemaData.doHierarchyCheckInUploadedData) { + try { + const rootBoundary = campaignData?.boundaries?.filter((boundary) => boundary.isRoot); // Retrieve session storage data once and store it in a variable + const sessionData = Digit.SessionStorage.get("microplanHelperData") || {}; + let boundaryData = sessionData.filteredBoundaries; + let filteredBoundaries; + if (!boundaryData) { + // Only fetch boundary data if not present in session storage + boundaryData = await fetchBoundaryData(Digit.ULBService.getCurrentTenantId(), campaignData?.hierarchyType, rootBoundary?.[0]?.code); + filteredBoundaries = filterBoundaries(boundaryData, campaignData?.boundaries); + + // Update the session storage with the new filtered boundaries + Digit.SessionStorage.set("microplanHelperData", { + ...sessionData, + filteredBoundaries: filteredBoundaries, + }); + } else { + filteredBoundaries = boundaryData; + } + const xlsxData = addBoundaryData([], filteredBoundaries, campaignData?.hierarchyType)?.[0]?.data; + xlsxData.forEach((item, i) => { + if (i === 0) return; + let boundaryCodeIndex = xlsxData?.[0]?.indexOf(commonColumn); + if (boundaryCodeIndex >= item.length) { + // If boundaryCodeIndex is out of bounds, return the item as is + boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item.slice().map(t); + } else { + // Otherwise, remove the element at boundaryCodeIndex + boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item + .slice(0, boundaryCodeIndex) + .concat(item.slice(boundaryCodeIndex + 1)) + .map(t); + } + }); + return boundaryDataAgainstBoundaryCode; + } catch (error) { + console.error(error?.message); + } + } +}; + +export const handleExcelFile = async ( + file, + schemaData, + hierarchy, + selectedFileType, + boundaryDataAgainstBoundaryCode, + setUploadedFileError, + t, + campaignData +) => { + try { + // Converting the file to preserve the sequence of columns so that it can be stored + let fileDataToStore = await parseXlsxToJsonMultipleSheets(file, { header: 0 }); + if (fileDataToStore[t(BOUNDARY_DATA_SHEET)]) delete fileDataToStore[t(BOUNDARY_DATA_SHEET)]; + let { tempResourceMappingData, tempFileDataToStore } = resourceMappingAndDataFilteringForExcelFiles( + schemaData, + hierarchy, + selectedFileType, + fileDataToStore, + t + ); + fileDataToStore = await convertJsonToXlsx(tempFileDataToStore); + // Converting the input file to json format + let result = await parseXlsxToJsonMultipleSheets(fileDataToStore, { header: 1 }); + if (result?.error) { + return { + check: false, + interruptUpload: true, + error: result.error, + fileDataToStore: {}, + toast: { state: "error", message: t("ERROR_CORRUPTED_FILE") }, + }; + } + let extraColumns = [commonColumn]; + // checking if the hierarchy and common column is present the uploaded data + extraColumns = [...hierarchy, commonColumn]; + let data = Object.values(tempFileDataToStore); + let errorMsg; + let errors; // object containing the location and type of error + let toast; + let hierarchyDataPresent = true; + let latLngColumns = + Object.entries(schemaData?.schema?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.isLocationDataColumns) { + acc.push(key); + } + return acc; + }, []) || []; + data.forEach((item) => { + const keys = item[0]; + if (keys?.length !== 0) { + if (!extraColumns?.every((e) => keys.includes(e))) { + if (schemaData && !schemaData.doHierarchyCheckInUploadedData) { + hierarchyDataPresent = false; + } else { + errorMsg = { + check: false, + interruptUpload: true, + error: t("ERROR_BOUNDARY_DATA_COLUMNS_ABSENT"), + fileDataToStore: {}, + toast: { state: "error", message: t("ERROR_BOUNDARY_DATA_COLUMNS_ABSENT") }, + }; + } + } + if (!latLngColumns?.every((e) => keys.includes(e))) { + toast = { state: "warning", message: t("ERROR_UPLOAD_EXCEL_LOCATION_DATA_MISSING") }; + } + } + }); + if (errorMsg && !errorMsg?.check) return errorMsg; + // Running Validations for uploaded file + let response = await checkForErrorInUploadedFileExcel(result, schemaData.schema, t); + if (!response.valid) setUploadedFileError(response.message); + errorMsg = response.message; + errors = response.errors; + const missingProperties = response.missingProperties; + let check = response.valid; + try { + if (schemaData && !schemaData.doHierarchyCheckInUploadedData && !hierarchyDataPresent && boundaryDataAgainstBoundaryCode) { + let tempBoundaryDataAgainstBoundaryCode = (await boundaryDataGeneration(schemaData, campaignData, t)) || {}; + for (const sheet in tempFileDataToStore) { + const commonColumnIndex = tempFileDataToStore[sheet]?.[0]?.indexOf(commonColumn); + if (commonColumnIndex !== -1) + tempFileDataToStore[sheet] = tempFileDataToStore[sheet].map((item, index) => [ + ...(tempBoundaryDataAgainstBoundaryCode[item[commonColumnIndex]] + ? tempBoundaryDataAgainstBoundaryCode[item[commonColumnIndex]] + : index !== 0 + ? new Array(hierarchy.length).fill("") + : []), + ...item, + ]); + + tempFileDataToStore[sheet][0] = [...hierarchy, ...tempFileDataToStore[sheet][0]]; + } + } + } catch (error) { + console.error("Error in boundary adding operaiton: ", error); + } + tempFileDataToStore = addMissingPropertiesToFileData(tempFileDataToStore, missingProperties); + return { check, errors, errorMsg, fileDataToStore: tempFileDataToStore, tempResourceMappingData, toast }; + } catch (error) { + console.error("Error in handling Excel file:", error.message); + } +}; +const addMissingPropertiesToFileData = (data, missingProperties) => { + if (!data || !missingProperties) return data; + let tempData = {}; + Object.entries(data).forEach(([key, value], index) => { + const filteredMissingProperties = [...missingProperties]?.reduce((acc, item) => { + if (!value?.[0]?.includes(item)) { + acc.push(item); + } + return acc; + }, []); + const newTempHeaders = value?.[0].length !== 0 ? [...value[0], ...filteredMissingProperties] : [...filteredMissingProperties]; + console.error(newTempHeaders); + tempData[key] = [newTempHeaders, ...value.slice(1)]; + }); + return tempData; +}; + +const handleGeojsonFile = async (file, schemaData, setUploadedFileError, t) => { + // Reading and checking geojson data + const data = await readGeojson(file, t); + if (!data.valid) { + return { check: false, stopUpload: true, toast: data.toast }; + } + + // Running geojson validaiton on uploaded file + let response = geojsonValidations(data.geojsonData, schemaData.schema, t); + if (!response.valid) setUploadedFileError(response.message); + let check = response.valid; + let error = response.message; + let fileDataToStore = data.geojsonData; + return { check, error, fileDataToStore }; +}; + +const handleShapefiles = async (file, schemaData, setUploadedFileError, selectedFileType, setToast, t) => { + // Reading and validating the uploaded geojson file + let response = await readAndValidateShapeFiles(file, t, selectedFileType["namingConvention"]); + if (!response.valid) { + setUploadedFileError(response.message); + setToast(response.toast); + } + let check = response.valid; + let error = response.message; + let fileDataToStore = response.data; + return { check, error, fileDataToStore }; +}; + +export default Upload; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js new file mode 100644 index 00000000000..5a0cdabf735 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js @@ -0,0 +1,29 @@ +import React, { memo, useCallback } from "react"; +import { useTranslation } from "react-i18next"; + +const ZoomControl = memo(({ map, t }) => { + if (!map) return
{t("LOADING_MAP")}
; + + const zoomIn = useCallback(() => { + map.zoomIn(); + }, [map]); + + const zoomOut = useCallback(() => { + map.zoomOut(); + }, [map]); + + return ( +
+
+ + +
+
+ ); +}); + +export default ZoomControl; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js new file mode 100644 index 00000000000..77922c81675 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js @@ -0,0 +1,188 @@ +import { Dropdown } from "@egovernments/digit-ui-components"; +import { Table } from "@egovernments/digit-ui-react-components"; +import { PaginationFirst, PaginationLast, PaginationNext, PaginationPrevious } from "@egovernments/digit-ui-svg-components"; +import React, { useState, useEffect, useMemo, useRef, useCallback } from "react"; +const SCROLL_OFFSET = 100; + +export const SpatialDataPropertyMapping = ({ uploadedData, resourceMapping, setResourceMapping, schema, setToast, hierarchy, close, t }) => { + // If no data is uploaded, display a message + if (!uploadedData) return
{t("NO_DATA_TO_DO_MAPPING")}
; + + const itemRefs = useRef([]); + const [expandedIndex, setExpandedIndex] = useState(null); + // State to track the render cycle count + const [renderCycle, setRenderCycle] = useState(0); + const scrollContainerRef = useRef(null); + + // Effect to reset the render cycle count whenever the expandedIndex changes + useEffect(() => { + if (expandedIndex !== null) { + setRenderCycle(0); + } + }, [expandedIndex]); + + // Effect to handle scrolling to the expanded item after the DOM has updated + useEffect(() => { + if (renderCycle < 3) { + // Increment render cycle count to ensure multiple render checks + setRenderCycle((prev) => prev + 1); + } else if (expandedIndex !== null && itemRefs.current[expandedIndex]) { + try { + const parentElement = itemRefs.current[expandedIndex]; + const childElement = itemRefs.current[expandedIndex].children[1]; + + if (parentElement) { + const scrollContainer = scrollContainerRef.current; + const parentRect = parentElement.getBoundingClientRect(); + const containerRect = scrollContainer.getBoundingClientRect(); + + // Calculate the offset from the top of the container + const offset = parentRect.top - containerRect.top; + // Scroll the container to the target position + scrollContainer.scrollTo({ + top: scrollContainer.scrollTop + offset - SCROLL_OFFSET, + behavior: "smooth", + }); + } + + if (childElement) { + // Focus the child element if it exists + childElement.focus(); + } + } catch (error) { + console.error("Error scrolling to element:", error); + } + } + }, [renderCycle, expandedIndex]); + + // Effect to observe DOM changes in the expanded item and trigger render cycle + useEffect(() => { + if (expandedIndex !== null) { + const observer = new MutationObserver(() => { + setRenderCycle((prev) => prev + 1); + }); + + if (itemRefs.current[expandedIndex]) { + observer.observe(itemRefs.current[expandedIndex], { childList: true, subtree: true }); + } + + return () => observer.disconnect(); + } + }, [expandedIndex]); + + // State variables + const [userColumns, setUserColumns] = useState([]); + const [templateColumns, setTemplateColumns] = useState([]); + + // Fetch template columns when schema changes + useEffect(() => { + if (!schema || !schema["schema"] || !schema.schema["Properties"]) + return setToast({ state: "error", message: t("ERROR_VALIDATION_SCHEMA_ABSENT") }); + + const columns = Object.keys(schema.schema["Properties"]); + if (columns) { + const newTemplateColumns = schema && !schema.doHierarchyCheckInUploadedData ? columns : [...hierarchy, ...columns]; + setTemplateColumns(newTemplateColumns); + } + }, [schema]); + + // Update user columns when uploaded data changes + useEffect(() => { + let userUploadedColumns = new Set(); + uploadedData?.["features"]?.forEach((item) => { + Object.keys(item["properties"]).forEach((key) => userUploadedColumns.add(key)); + }); + + //field level validations + for (const item of userUploadedColumns) { + if (item.length < 2) { + setToast({ state: "error", message: t("ERROR_FIELD_LENGTH") }); + close(); + } + } + setUserColumns((preUserColumns) => [...preUserColumns, ...userUploadedColumns]); + }, [uploadedData]); + + // Dropdown component for selecting user columns + const DropDownUserColumnSelect = ({ id, index }) => { + const [selectedOption, setSelectedOption] = useState(""); + useEffect(() => { + const obj = resourceMapping.find((item) => item["mappedTo"] === id); + if (obj) setSelectedOption({ code: obj["mappedFrom"] }); + else setSelectedOption(); + }, [id, resourceMapping]); + + const handleSelectChange = (event) => { + const newValue = event.code; + setSelectedOption(event); + setResourceMapping((previous) => { + const revisedData = previous.filter((item) => !(item["mappedTo"] === id || item["mappedFrom"] === newValue)); + return [...revisedData, { mappedTo: id, mappedFrom: newValue }]; + }); + }; + + const toggleExpand = (index) => { + setExpandedIndex(index === expandedIndex ? null : index); + }; + + return ( +
{ + itemRefs.current[index] = el; + }} + onClick={() => toggleExpand(index)} + onKeyDown={() => toggleExpand(index)} + tabIndex="0" + > + ({ code: item }))} + selected={selectedOption} + optionKey="code" + select={handleSelectChange} + style={{ width: "100%", backgroundColor: "rgb(0,0,0,0)" }} + showToolTip={true} + /> +
+ ); + }; + + const tableColumns = useMemo( + () => [ + { + Header: t("COLUMNS_IN_TEMPLATE"), + accessor: "COLUMNS_IN_TEMPLATE", + }, + { + Header: t("COLUMNS_IN_USER_UPLOAD"), + accessor: "COLUMNS_IN_USER_UPLOAD", + Cell: ({ cell: { value }, row: { index } }) => + useMemo(() => , [value, index]), + }, + ], + [userColumns, setResourceMapping, resourceMapping, t, itemRefs] + ); + const data = useMemo(() => templateColumns.map((item) => ({ COLUMNS_IN_TEMPLATE: t(item), COLUMNS_IN_USER_UPLOAD: item })), [templateColumns]); + return ( +
+ { + return { style: {} }; + }} + getHeaderProps={(cellInfo) => { + return { style: {} }; + }} + /> + + ); +}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/UICustomizations.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/UICustomizations.js new file mode 100644 index 00000000000..e312c36d6f4 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/UICustomizations.js @@ -0,0 +1,324 @@ +import _ from "lodash"; + +//create functions here based on module name set in mdms(eg->SearchProjectConfig) +//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName] +// these functions will act as middlewares +// var Digit = window.Digit || {}; + +const businessServiceMap = { + "muster roll": "MR", +}; + +const inboxModuleNameMap = { + "muster-roll-approval": "muster-roll-service", +}; + +function filterUniqueByKey(arr, key) { + const uniqueValues = new Set(); + const result = []; + + arr.forEach((obj) => { + const value = obj[key]; + if (!uniqueValues.has(value)) { + uniqueValues.add(value); + result.push(obj); + } + }); + + return result; +} + +const epochTimeForTomorrow12 = () => { + const now = new Date(); + + // Create a new Date object for tomorrow at 12:00 PM + const tomorrowNoon = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 12, 0, 0, 0); + + // Format the date as "YYYY-MM-DD" + const year = tomorrowNoon.getFullYear(); + const month = String(tomorrowNoon.getMonth() + 1).padStart(2, "0"); // Months are 0-indexed + const day = String(tomorrowNoon.getDate()).padStart(2, "0"); + + return Digit.Utils.date.convertDateToEpoch(`${year}-${month}-${day}`); +}; + +function cleanObject(obj) { + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + if (Array.isArray(obj[key])) { + if (obj[key].length === 0) { + delete obj[key]; + } + } else if ( + obj[key] === undefined || + obj[key] === null || + obj[key] === false || + obj[key] === "" || // Check for empty string + (typeof obj[key] === "object" && Object.keys(obj[key]).length === 0) + ) { + delete obj[key]; + } + } + } + return obj; +} + +export const UICustomizations = { + businessServiceMap, + updatePayload: (applicationDetails, data, action, businessService) => { + if (businessService === businessServiceMap.estimate) { + const workflow = { + comment: data.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + estimate: applicationDetails, + workflow, + }; + } + if (businessService === businessServiceMap.contract) { + const workflow = { + comment: data?.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + contract: applicationDetails, + workflow, + }; + } + if (businessService === businessServiceMap?.["muster roll"]) { + const workflow = { + comment: data?.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + musterRoll: applicationDetails, + workflow, + }; + } + if (businessService === businessServiceMap?.["works.purchase"]) { + const workflow = { + comment: data.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + const additionalFieldsToSet = { + projectId: applicationDetails.additionalDetails.projectId, + invoiceDate: applicationDetails.billDate, + invoiceNumber: applicationDetails.referenceId.split("_")?.[1], + contractNumber: applicationDetails.referenceId.split("_")?.[0], + documents: applicationDetails.additionalDetails.documents, + }; + return { + bill: { ...applicationDetails, ...additionalFieldsToSet }, + workflow, + }; + } + }, + enableModalSubmit: (businessService, action, setModalSubmit, data) => { + if (businessService === businessServiceMap?.["muster roll"] && action.action === "APPROVE") { + setModalSubmit(data?.acceptTerms); + } + }, + enableHrmsSearch: (businessService, action) => { + if (businessService === businessServiceMap.estimate) { + return action.action.includes("TECHNICALSANCTION") || action.action.includes("VERIFYANDFORWARD"); + } + if (businessService === businessServiceMap.contract) { + return action.action.includes("VERIFY_AND_FORWARD"); + } + if (businessService === businessServiceMap?.["muster roll"]) { + return action.action.includes("VERIFY"); + } + if (businessService === businessServiceMap?.["works.purchase"]) { + return action.action.includes("VERIFY_AND_FORWARD"); + } + return false; + }, + getBusinessService: (moduleCode) => { + if (moduleCode?.includes("estimate")) { + return businessServiceMap?.estimate; + } else if (moduleCode?.includes("contract")) { + return businessServiceMap?.contract; + } else if (moduleCode?.includes("muster roll")) { + return businessServiceMap?.["muster roll"]; + } else if (moduleCode?.includes("works.purchase")) { + return businessServiceMap?.["works.purchase"]; + } else if (moduleCode?.includes("works.wages")) { + return businessServiceMap?.["works.wages"]; + } else if (moduleCode?.includes("works.supervision")) { + return businessServiceMap?.["works.supervision"]; + } else { + return businessServiceMap; + } + }, + getInboxModuleName: (moduleCode) => { + if (moduleCode?.includes("estimate")) { + return inboxModuleNameMap?.estimate; + } else if (moduleCode?.includes("contract")) { + return inboxModuleNameMap?.contracts; + } else if (moduleCode?.includes("attendence")) { + return inboxModuleNameMap?.attendencemgmt; + } else { + return inboxModuleNameMap; + } + }, + SearchCampaign: { + preProcess: (data, additionalDetails) => { + const { campaignName = "", endDate = "", projectType = "", startDate = "" } = data?.state?.searchForm || {}; + data.body.CampaignDetails = {}; + data.body.CampaignDetails.pagination = data?.state?.tableForm; + data.body.CampaignDetails.tenantId = Digit.ULBService.getCurrentTenantId(); + // data.body.CampaignDetails.boundaryCode = boundaryCode; + data.body.CampaignDetails.createdBy = Digit.UserService.getUser().info.uuid; + data.body.CampaignDetails.campaignName = campaignName; + data.body.CampaignDetails.status = ["drafted"]; + if (startDate) { + data.body.CampaignDetails.startDate = Digit.Utils.date.convertDateToEpoch(startDate); + } else { + data.body.CampaignDetails.startDate = epochTimeForTomorrow12(); + } + if (endDate) { + data.body.CampaignDetails.endDate = Digit.Utils.date.convertDateToEpoch(endDate); + } + data.body.CampaignDetails.projectType = projectType?.[0]?.code; + + cleanObject(data.body.CampaignDetails); + + return data; + }, + populateProjectType: () => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + + return { + url: "/egov-mdms-service/v1/_search", + params: { tenantId }, + body: { + MdmsCriteria: { + tenantId, + moduleDetails: [ + { + moduleName: "HCM-PROJECT-TYPES", + masterDetails: [ + { + name: "projectTypes", + }, + ], + }, + ], + }, + }, + changeQueryName: "projectType", + config: { + enabled: true, + select: (data) => { + const dropdownData = filterUniqueByKey(data?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes, "code").map((row) => { + return { + ...row, + i18nKey: Digit.Utils.locale.getTransformedLocale(`CAMPAIGN_TYPE_${row.code}`), + }; + }); + return dropdownData; + }, + }, + }; + }, + customValidationCheck: (data) => { + //checking if both to and from date are present then they should be startDate<=endDate + const { startDate, endDate } = data; + const startDateEpoch = Digit.Utils.date.convertDateToEpoch(startDate); + const endDateEpoch = Digit.Utils.date.convertDateToEpoch(endDate); + + if (startDate && endDate && startDateEpoch > endDateEpoch) { + return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; + } + return false; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + if (key === "CAMPAIGN_DATE") { + return `${Digit.DateUtils.ConvertEpochToDate(value)} - ${Digit.DateUtils.ConvertEpochToDate(row?.endDate)}`; + } + }, + }, + SearchMicroplan: { + preProcess: (data, additionalDetails) => { + const { name, status } = data?.state?.searchForm || {}; + + data.body.PlanConfigurationSearchCriteria = {}; + data.body.PlanConfigurationSearchCriteria.limit = data?.state?.tableForm?.limit; + // data.body.PlanConfigurationSearchCriteria.limit = 10 + data.body.PlanConfigurationSearchCriteria.offset = data?.state?.tableForm?.offset; + data.body.PlanConfigurationSearchCriteria.name = name; + data.body.PlanConfigurationSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); + data.body.PlanConfigurationSearchCriteria.userUuid = Digit.UserService.getUser().info.uuid; + // delete data.body.PlanConfigurationSearchCriteria.pagination + data.body.PlanConfigurationSearchCriteria.status = status?.status; + cleanObject(data.body.PlanConfigurationSearchCriteria); + return data; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + if (key === "CAMPAIGN_DATE") { + return `${Digit.DateUtils.ConvertEpochToDate(value)} - ${Digit.DateUtils.ConvertEpochToDate(row?.CampaignDetails?.endDate)}`; + } + }, + }, +}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js new file mode 100644 index 00000000000..4ac715407c5 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js @@ -0,0 +1,36 @@ +export const LOCALITY = "Locality"; + +export const EXCEL = "Excel"; + +export const GEOJSON = "GeoJSON"; + +export const SHAPEFILE = "Shapefile"; + +export const commonColumn = "boundaryCode"; + +export const ACCEPT_HEADERS = { + GeoJSON: "application/geo+json", + Shapefile: "application/shapefile", + Excel: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", +}; + +// Define the colors of the gradient for choropleth mapping +export const MapChoroplethGradientColors = [ + { percent: 0, color: "#edd1cf" }, + { percent: 100, color: "#b52626" }, +]; + +export const PRIMARY_THEME_COLOR = "#C84C0E"; + +export const BOUNDARY_DATA_SHEET = "boundaryData"; +export const FACILITY_DATA_SHEET = "facilityData"; + +export const FILE_STORE = "microplan"; + +export const SHEET_PASSWORD = "eGov_sheet_password"; + +export const SHEET_COLUMN_WIDTH = 40; + +export const SCHEMA_PROPERTIES_PREFIX = "DISPLAY"; + +export const UNPROTECT_TILL_ROW = "10000"; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json new file mode 100644 index 00000000000..768e323ef86 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json @@ -0,0 +1,40 @@ +{ + "timeLineOptions": [ + { + "id": 0, + "name": "MICROPLAN_DETAILS", + "component": "MicroplanDetails", + "checkForCompleteness": true + }, + { + "id": 1, + "name": "UPLOAD_DATA", + "component": "Upload", + "checkForCompleteness": true + }, + { + "id": 2, + "name": "HYPOTHESIS", + "component": "Hypothesis", + "checkForCompleteness": true + }, + { + "id": 3, + "name": "FORMULA_CONFIGURATION", + "component": "RuleEngine", + "checkForCompleteness": true + }, + { + "id": 4, + "name": "MAPPING", + "component": "Mapping", + "checkForCompleteness": false + }, + { + "id": 5, + "name": "MICROPLAN_GENERATION", + "component": "MicroplanPreview", + "checkForCompleteness": false + } + ] +} diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js new file mode 100644 index 00000000000..241f8ec64ec --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js @@ -0,0 +1,193 @@ +export const tourSteps = (t) => { + return { + microplanDetails: { + name: "microplanDetails", + run: true, + steps: [ + { + content: t("HELP_MICROPLAN_DETAILS_CAMPAIGN_DETAILS"), + target: ".microplan-campaign-detials", + disableBeacon: true, + placement: "bottom", + title: "", + disableScrolling: true, + disableOverlay :true, + }, + { + content: t("HELP_MICROPLAN_DETAILS_MICROPLAN_NAME"), + target: ".microplan-name", + disableBeacon: true, + placement: "bottom", + title: "", + disableScrolling: true, + disableOverlay :true, + }, + ], + tourActive: true, + }, + upload: { + name: "upload", + run: true, + steps: [ + { + content: t("HELP_UPLOAD_FILETYPE_OPTION_CONTAINER"), + target: ".upload-option-container", + disableBeacon: true, + placement: "top-end", + title: "", + disableScrolling: true, + disableOverlay :true, + }, + ], + tourActive: true, + }, + hypothesis: { + name: "hypothesis", + run: true, + steps: [ + { + content: t("HELP_HYPOTHESIS_INTERACTABLE_SECTION"), + target: ".hypothesis-help", + disableBeacon: true, + placement: "right-start", + title: "", + disableScrolling: true, + disableOverlay :true, + }, + // { + // content: + // t("HELP_RULE_ENGINE_INPUT"), + // target: ".last-container .key", + // disableBeacon: true, + // placement: "top-start", + // title: "", + // }, + // { + // content: + // t("HELP_HYPOTHESIS_DELETE_BUTTON"), + // target: ".last-containe .delete-button-help-locator", + // disableBeacon: true, + // placement: "top-start", + // title: "", + // }, + { + content: t("HELP_HYPOTHESIS_ADD_BUTTON"), + target: ".add-button-help", + disableBeacon: true, + placement: "top-start", + title: "", + disableOverlay :true, + }, + ], + tourActive: true, + }, + ruleEngine: { + name: "ruleEngine", + run: true, + steps: [ + { + content: t("HELP_RULE_ENGINE_INTERACTABLE_SECTION"), + target: ".rule-engine-help", + disableBeacon: true, + placement: "right-start", + title: "", + disableScrolling: true, + disableOverlay :true, + }, + { + content: t("HELP_RULE_ENGINE_INPUT"), + target: ".user-input-section .interactable-section .select-and-input-wrapper-first .input", + disableBeacon: true, + placement: "top-end", + title: "", + disableOverlay :true, + }, + { + content: t("HELP_RULE_ENGINE_DELETE_BUTTON"), + target: ".select-and-input-wrapper-first .delete-button", + disableBeacon: true, + placement: "left-start", + title: "", + disableOverlay :true, + }, + { + content: t("HELP_RULE_ENGINE_ADD_BUTTON"), + target: ".add-button-help", + disableBeacon: true, + placement: "top-start", + title: "", + disableOverlay :true, + }, + ], + tourActive: true, + }, + mapping: { + name: "mapping", + run: true, + steps: [ + { + content: t("HELP_MAPPING_BOUNDARY_SELECTION"), + target: ".filter-by-boundary .button-primary", + disableBeacon: true, + placement: "right-end", + title: "", + disableScrolling: true, + disableOverlay :true, + }, + { + content: t("HELP_MAPPING_BASE_MAP"), + target: ".base-map-selector .icon-first", + disableBeacon: true, + placement: "left-start", + title: "", + disableScrolling: true, + disableOverlay :true, + }, + { + content: t("HELP_MAPPING_FILTER"), + target: ".filter-icon p", + disableBeacon: true, + placement: "left-start", + title: "", + disableScrolling: true, + disableOverlay :true, + }, + { + content: t("HELP_MAPPING_VIRTUALIZATION"), + target: ".virtualization-icon p", + disableBeacon: true, + placement: "left-start", + title: "", + disableScrolling: true, + disableOverlay :true, + }, + { + content: t("HELP_MAPPING_MAP_GEOMETRIES"), + target: ".map-container", + disableBeacon: true, + placement: "top-end", + title: "", + disableScrolling: true, + disableOverlay :true, + }, + ], + tourActive: true, + }, + microplanPreview: { + name: "microplanPreview", + run: true, + steps: [ + { + content: t("HELP_MICROPLAN_DETAILS_EDIT_ROWS"), + target: ".preview-container", + disableBeacon: true, + placement: "top-end", + title: "", + disableOverlay :true, + disableScrolling: true, + }, + ], + tourActive: true, + }, + }; +}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js new file mode 100644 index 00000000000..4503647b641 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js @@ -0,0 +1,45 @@ +import { logoutV1 } from "./logout"; +import utils from "../utils"; +import useCreatePlanConfig from "./useCreatePlanConfig"; +import useSearchPlanConfig from "./useSearchPlanConfig"; +import useUpdatePlanConfig from "./useUpdatePlanConfig"; +import useSavedMicroplans from "./useSavedMicroplans"; +import useSearchCampaign from "./useSearchCampaign"; +import { useGenerateIdCampaign } from "./useGenerateIdCampaign"; +const UserService = { + logoutV1, +}; + +const microplan = { + useCreatePlanConfig, + useSearchPlanConfig, + useUpdatePlanConfig, + useSavedMicroplans, + useSearchCampaign, + useGenerateIdCampaign, +}; + +const contracts = {}; + +const Hooks = { + attendance: { + update: () => {}, + }, + microplan, + contracts, +}; + +const Utils = { + browser: { + sample: () => {}, + }, + microplan: { + ...utils, + }, +}; + +export const CustomisedHooks = { + Hooks, + UserService, + Utils, +}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/logout.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/logout.js new file mode 100644 index 00000000000..38415d5a63a --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/logout.js @@ -0,0 +1,48 @@ +var Digit = window.Digit || {}; + +/* Recreated a new hook in same name*/ +export const logoutV1 = async () => { + let user = Digit.UserService.getUser(); + if (!user || !user.info || !user.access_token) return false; + const { type } = user.info; + const access_token = user?.access_token; + const tenantId = type === "CITIZEN" ? Digit.ULBService.getStateId() : Digit.ULBService.getCurrentTenantId(); + const myHeaders = new Headers(); + myHeaders.append("accept", "application/json, text/plain, */*"); + myHeaders.append("content-type", "application/json;charset=UTF-8"); + const raw = { + RequestInfo: { + apiId: "Rainmaker", + ver: ".01", + ts: "", + action: "_logout", + did: "1", + key: "", + msgId: "20170310130900|en_IN", + authToken: access_token, + }, + access_token: access_token, + }; + + var requestOptions = { + method: "POST", + headers: myHeaders, + body: JSON.stringify(raw), + redirect: "follow", + }; + const userType = Digit.UserService.getType(); + try { + await fetch(`${window.location.origin}/user/v1/_logout?tenantId=${tenantId}`, requestOptions) + .then((response) => response.json()) + .catch((error) => console.log("error", error)); + } catch (e) { + } finally { + window.localStorage.clear(); + window.sessionStorage.clear(); + if (userType === "citizen") { + window.location.replace("/digit-ui/citizen"); + } else { + window.location.replace("/digit-ui/employee/user/language-selection"); + } + } +}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js new file mode 100644 index 00000000000..6afb891b15b --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js @@ -0,0 +1,8 @@ +import { useMutation } from "react-query"; +import CreatePlanConfig from "../services/CreatePlanConfig"; + +const useCreatePlanConfig = () => { + return useMutation(data => CreatePlanConfig(data)) +} + +export default useCreatePlanConfig; \ No newline at end of file diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js new file mode 100644 index 00000000000..f315dda5ff8 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js @@ -0,0 +1,26 @@ +export const useGenerateIdCampaign = ({ type, hierarchyType, filters, campaignId, config = {} }) => { + const updatedFilters = filters?.map(({ type, ...rest }) => ({ + ...rest, + boundaryType: type, + })); + const reqCriteria = { + url: `/project-factory/v1/data/_generate`, + changeQueryName: `${type}${hierarchyType}${filters}`, + params: { + tenantId: Digit.ULBService.getCurrentTenantId(), + type: type, + forceUpdate: true, + hierarchyType: hierarchyType, + campaignId: campaignId, + }, + body: type === "boundary" ? (updatedFilters === undefined ? { Filters: null } : { Filters: { boundaries: updatedFilters } }) : {}, + config: { + ...config, + cacheTime: 0, + staleTime: 0, + }, + }; + const { data: Data, refetch, isLoading } = Digit.Hooks.useCustomAPIHook(reqCriteria); + + return { isLoading: isLoading, data: Data?.GeneratedResource?.[0]?.id, refetch }; +}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js new file mode 100644 index 00000000000..15e423d59e0 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js @@ -0,0 +1,21 @@ +import { useTranslation } from "react-i18next"; + +export const useNumberFormatter = (FormatMapping) => { + const { i18n } = useTranslation(); + + const formatNumber = (value, options) => { + try { + const currentLanguage = i18n.language; + const fallbackLanguage = i18n.options.fallbackLng[0]; // Get the first language in the fallback list + const locale = FormatMapping?.[currentLanguage] || FormatMapping?.[fallbackLanguage] || currentLanguage || ""; + return new Intl.NumberFormat(locale, options).format(value); + } catch (error) { + console.error("Error formatting number:", error); + return value; + } + }; + + return { formatNumber }; +}; + +export default useNumberFormatter; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js new file mode 100644 index 00000000000..62c4c2ecd1c --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js @@ -0,0 +1,22 @@ +import { useQuery } from "react-query"; +import SearchSavedPlans from "../services/searchSavedPlans"; + +const useSavedMicroplans = (reqCriteria) => { + const { body, config, params, state, url } = reqCriteria; + const { isLoading, data, isFetching, refetch } = useQuery(["SAVED_MICROPLANS", url], () => SearchSavedPlans(body), { + ...config, + cacheTime: 0, + staleTime: 0, + }); + + return { + isLoading, + isFetching, + data, + refetch, + revalidate: () => {}, + }; +}; + +// () => SearchSavedPlans(data) +export default useSavedMicroplans; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js new file mode 100644 index 00000000000..e2644f00ca9 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js @@ -0,0 +1,8 @@ +import { useQuery } from "react-query"; +import SearchCampaignConfig from "../services/SearchCampaignConfig"; + +const useSearchCampaign = (data, config = {}) => { + return useQuery(["SEARCH_CAMPAIGN",data], () => SearchCampaignConfig(data), { ...config }); +}; + +export default useSearchCampaign; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js new file mode 100644 index 00000000000..003fdaa4f51 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js @@ -0,0 +1,8 @@ +import { useMutation } from "react-query"; +import SearchPlanConfig from "../services/SearchPlanConfig"; + +const useSearchPlanConfig = (data, config = {}) => { + return useQuery([data?.tenantId, data?.id, data?.name, data?.executionPlanId, data?.userUuid, data?.offset, data?.limit], () => SearchPlanConfig(data), { ...config }); +}; + +export default useSearchPlanConfig; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js new file mode 100644 index 00000000000..17b16145a08 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js @@ -0,0 +1,8 @@ +import { useMutation } from "react-query"; +import UpdatePlanConfig from "../services/UpdatePlanConfig"; + +const useUpdatePlanConfig = () => { + return useMutation(data => UpdatePlanConfig(data)) +} + +export default useUpdatePlanConfig; \ No newline at end of file diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js new file mode 100644 index 00000000000..03f82f59456 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js @@ -0,0 +1,217 @@ +import React from "react"; + +export const PopulationSvg = (style) => { + return ` + + + + + + + + + + + + `; +}; + +export const HelpOutlineIcon = ({ className = "", fill = "", style = {} }) => ( + + + + + + + + + + +); + +export const DefaultMapMarkerSvg = (style) => { + return ` + + + + + `; +}; + + +export const WarehouseMarker = ({ + className = "", + fill = "white", + fillBackground = "#42BBFF", + style = {}, + width = "3.125rem", + height = "3.125rem", +}) => { + return ` + + + + + + + + + + + + `; +}; + +export const Warehouse = ({ className = "", fill = "white", fillBackground = "#42BBFF", style = {}, width = "1.5rem", height = "1.5rem" }) => { + return ( + + + + + + + + + + + + ); +}; + +export const Church = ({ className = "", fill = "white", fillBackground = "#064466", style = {}, width = "1.5rem", height = "1.5rem" }) => { + return ( + + + + + + + + + + + + + ); +}; + +export const School = ({ className = "", fill = "white", fillBackground = "#FF7B42", style = {}, width = "1.5rem", height = "1.5rem" }) => { + return ( + + + + + + + + + + + + + + + + + ); +}; + +export const HealthFacility = ({ className = "", fill = "white", fillBackground = "#0C9219", style = {}, width = "1.5rem", height = "1.5rem" , onClick=null}) => { + return ( + + + + + + + + + + + + ); +}; + +export const ChurchMarker = ({ className = "", fill = "white", fillBackground = "#064466", style = {}, width = "3.125rem", height = "3.125rem" }) => { + return ` + + + + + +`; +}; + +export const SchoolMarker = ({ className = "", fill = "white", fillBackground = "#FF7B42", style = {}, width = "3.125rem", height = "3.125rem" }) => { + return ` + + + + + + + + + + + + + + + + +`; +}; + +export const HealthFacilityMarker = ({ + className = "", + fill = "white", + fillBackground = "#0C9219", + style = {}, + width = "3.125rem", + height = "3.125rem", +}) => { + return ` + + + + + + + + + + + +`; +}; + + + + + +export const PlusWithSurroundingCircle = ({ className = "", fill = "white", fillBackground = "#FF7B42", style = {}, width = "1rem", height = "1rem" ,onClick=null }) => { + return ( + + + + ); +}; \ No newline at end of file diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js new file mode 100644 index 00000000000..3dc963e042b --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js @@ -0,0 +1,278 @@ +import React, { useState, useEffect, useCallback, Fragment } from "react"; +import { useTranslation } from "react-i18next"; +import { timeLineOptions } from "../../configs/timeLineOptions.json"; +import Upload from "../../components/Upload"; +import Hypothesis from "../../components/Hypothesis"; +import RuleEngine from "../../components/RuleEngine"; +import Mapping from "../../components/Mapping"; +import Navigator from "../../components/Nagivator"; +import { Toast } from "@egovernments/digit-ui-components"; +import MicroplanPreview from "../../components/MicroplanPreview"; +import MicroplanDetails from "../../components/MicroplanDetails"; + +export const components = { + MicroplanDetails, + Upload, + Hypothesis, + RuleEngine, + Mapping, + MicroplanPreview, +}; + +import MicroplanCreatedScreen from "../../components/MicroplanCreatedScreen"; +import { LoaderWithGap, Tutorial } from "@egovernments/digit-ui-react-components"; +import { useMyContext } from "../../utils/context"; +import { updateSessionUtils } from "../../utils/updateSessionUtils"; +import { render } from "react-dom"; + +// Main component for creating a microplan +const CreateMicroplan = () => { + // Fetching data using custom MDMS hook + const { id: campaignId = "" } = Digit.Hooks.useQueryParams(); + const { mutate: CreateMutate } = Digit.Hooks.microplan.useCreatePlanConfig(); + const { mutate: UpdateMutate } = Digit.Hooks.microplan.useUpdatePlanConfig(); + const [toRender, setToRender] = useState("navigator"); + const { t } = useTranslation(); + + // States + const [microplanData, setMicroplanData] = useState(); + const [operatorsObject, setOperatorsObject] = useState([]); + const [toast, setToast] = useState(); + const [checkForCompleteness, setCheckForCompletion] = useState([]); + const [loaderActivation, setLoaderActivation] = useState(false); + const { state } = useMyContext(); + + //fetch campaign data + const { id = "" } = Digit.Hooks.useQueryParams(); + const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( + { + CampaignDetails: { + tenantId: Digit.ULBService.getCurrentTenantId(), + ids: [id], + }, + }, + { + enabled: !!id, + } + ); + // to save microplan helper data to ssn + useEffect(() => { + if (campaignData) Digit.SessionStorage.set("microplanHelperData", { ...Digit.SessionStorage.get("microplanHelperData"), campaignData }); + }, [campaignData]); + + const campaignType = campaignData?.projectType; + + // request body for boundary hierarchy api + const reqCriteria = { + url: `/boundary-service/boundary-hierarchy-definition/_search`, + params: {}, + body: { + BoundaryTypeHierarchySearchCriteria: { + tenantId: Digit.ULBService.getStateId(), + hierarchyType: campaignData?.hierarchyType, + }, + }, + config: { + enabled: !!campaignData?.hierarchyType, + select: (data) => { + return data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map((item) => item?.boundaryType) || {}; + }, + }, + }; + const { isLoading: ishierarchyLoading, data: heirarchyData } = Digit.Hooks.useCustomAPIHook(reqCriteria); + + // useEffect to initialise the data from MDMS + useEffect(() => { + let temp; + if (!state || !state.UIConfiguration) return; + let UIConfiguration = state.UIConfiguration; + if (UIConfiguration) temp = UIConfiguration.find((item) => item.name === "ruleConfigure"); + if (!(temp && temp.ruleConfigureOperators)) return; + setOperatorsObject(temp.ruleConfigureOperators); + }, []); + + // useEffect to store data in session storage + useEffect(() => { + if (!microplanData) return; + Digit.SessionStorage.set("microplanData", microplanData); + }, [microplanData]); + + // useEffect to store data in session storage + useEffect(() => { + const data = Digit.SessionStorage.get("microplanData"); + if (data?.microplanStatus === "GENERATED") setToRender("success-screen"); + let statusData = {}; + let toCheckCompletenesData = []; + timeLineOptions.forEach((item) => { + statusData[item.name] = false; + if (item?.checkForCompleteness) toCheckCompletenesData.push(item.name); + }); + if (data && data?.status) { + if (Object.keys(data?.status) === 0) setMicroplanData({ ...data, status: statusData }); + else setMicroplanData({ ...data }); + } + setCheckForCompletion(toCheckCompletenesData); + }, []); + + // An addon function to pass to Navigator + const nextEventAddon = useCallback( + async (currentPage, checkDataCompletion, setCheckDataCompletion) => { + if (!microplanData) { + setCheckDataCompletion("perform-action"); + return; + } + setMicroplanData((previous) => ({ + ...previous, + status: { ...previous?.status, [currentPage?.name]: checkDataCompletion === "valid" }, + })); + + setCheckDataCompletion("false"); + let body = Digit.Utils.microplan.mapDataForApi( + microplanData, + operatorsObject, + microplanData?.microplanDetails?.name, + campaignId, + "DRAFT", + microplanData?.planConfigurationId ? "update" : "create" + ); + if (!Digit.Utils.microplan.planConfigRequestBodyValidator(body, state, campaignType)) { + setCheckDataCompletion("perform-action"); + return; + } + setLoaderActivation(true); + if (!microplanData?.planConfigurationId) { + await createPlanConfiguration(body, setCheckDataCompletion, setLoaderActivation); + } else if (microplanData && microplanData.planConfigurationId) { + await updatePlanConfiguration(body, setCheckDataCompletion, setLoaderActivation); + } + }, + [microplanData, UpdateMutate, CreateMutate] + ); + + const createPlanConfiguration = async (body, setCheckDataCompletion, setLoaderActivation) => { + await CreateMutate(body, { + onSuccess: async (data) => { + const additionalProps = { + heirarchyData: heirarchyData, + t, + campaignType, + campaignData, + }; + const computedSession = await updateSessionUtils.computeSessionObject(data?.PlanConfiguration[0], state, additionalProps); + if (computedSession) { + computedSession.microplanStatus = "DRAFT"; + setMicroplanData(computedSession); + } else { + console.error("Failed to compute session data."); + } + setLoaderActivation(false); + setCheckDataCompletion("perform-action"); + }, + onError: (error, variables) => { + setToast({ + message: t("ERROR_DATA_NOT_SAVED"), + state: "error", + transitionTime: 10000, + }); + setTimeout(() => { + setLoaderActivation(false); + setCheckDataCompletion("false"); + }, 2000); + }, + }); + }; + + const updatePlanConfiguration = async (body, setCheckDataCompletion, setLoaderActivation) => { + body.PlanConfiguration["id"] = microplanData?.planConfigurationId; + body.PlanConfiguration["auditDetails"] = microplanData?.auditDetails; + await UpdateMutate(body, { + onSuccess: async (data) => { + const additionalProps = { + heirarchyData: heirarchyData, + t, + campaignType, + campaignData, + }; + const computedSession = await updateSessionUtils.computeSessionObject(data?.PlanConfiguration[0], state, additionalProps); + if (computedSession) { + computedSession.microplanStatus = "DRAFT"; + setMicroplanData(computedSession); + } else { + console.error("Failed to compute session data."); + } + setLoaderActivation(false); + setCheckDataCompletion("perform-action"); + }, + onError: (error, variables) => { + setToast({ + message: t("ERROR_DATA_NOT_SAVED"), + state: "error", + transitionTime: 10000, + }); + setTimeout(() => { + setLoaderActivation(false); + setCheckDataCompletion("false"); + }, 2000); + }, + }); + }; + + const setCurrentPageExternally = useCallback( + (props) => { + switch (props.method) { + case "set": + let currentPage; + const data = Digit.SessionStorage.get("microplanData"); + if (data && data?.currentPage) currentPage = data.currentPage; + if (currentPage && props && props?.setCurrentPage && timeLineOptions.find((item) => item.id === currentPage?.id)) { + props.setCurrentPage(currentPage); + return true; + } + break; + case "save": + if (props && props.currentPage) { + setMicroplanData((previous) => ({ ...previous, currentPage: props.currentPage })); + } + break; + } + }, + [microplanData, setMicroplanData, Navigator] + ); + + const completeNavigation = useCallback(() => { + setToRender("success-screen"); + }, [setToRender]); + + return ( + <> +
+ {toRender === "navigator" && ( + + )} + {toRender === "success-screen" && } +
+ {toast && ( + setToast(undefined)} + /> + )} + {loaderActivation && } + + ); +}; + +export default CreateMicroplan; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js new file mode 100644 index 00000000000..7534c1b2af1 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js @@ -0,0 +1,54 @@ +import React, { Fragment } from "react"; +import { useTranslation } from "react-i18next"; +import { Link } from "react-router-dom"; +import { ArrowForward } from "@egovernments/digit-ui-svg-components"; +import { Button } from "@egovernments/digit-ui-react-components"; +import { useHistory } from "react-router-dom"; +import { ActionBar } from "@egovernments/digit-ui-components"; + +const Guidelines = ({ path }) => { + const { t } = useTranslation(); + const history = useHistory() + // Keeping inline style for now because design for this screen is not given yet + const { id = "" } = Digit.Hooks.useQueryParams(); + const onNextClick = ()=>{ + history.push(`/${window.contextPath}/employee/microplanning/create-microplan?id=${id}`); + } + return ( + <> + +
+ {t("CREATE_MICROPLAN_GUIDELINES")} +
+ + {/* Action bar */} + + {/* Next/Submit button */} + + + + ); +}; + +export default Guidelines; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js new file mode 100644 index 00000000000..bcfbdfd0db5 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js @@ -0,0 +1,178 @@ +import React,{useState} from "react"; +import { useTranslation } from "react-i18next"; +import { Header, InboxSearchComposerV2, Loader } from "@egovernments/digit-ui-react-components"; +import { useHistory } from "react-router-dom"; +import { updateSessionUtils } from "../../utils/updateSessionUtils"; +import { useMyContext } from "../../utils/context"; + +const configs = { + label: "SAVED_MICROPLANS", + type: "search", + apiDetails: { + serviceName: "/plan-service/config/_search", + requestParam: {}, + requestBody: {}, + minParametersForSearchForm: 0, + masterName: "commonUiConfig", + moduleName: "SearchMicroplan", + tableFormJsonPath: "requestBody.PlanConfigurationSearchCriteria.pagination", + searchFormJsonPath: "requestBody.PlanConfigurationSearchCriteria", + }, + sections: { + search: { + uiConfig: { + type: "search", + typeMobile: "filter", + headerLabel: "SAVED_MICROPLANS", + headerStyle: null, + primaryLabel: "ES_COMMON_SEARCH", + secondaryLabel: "ES_COMMON_CLEAR_SEARCH", + minReqFields: 0, + // "showFormInstruction": "TQM_SEARCH_HINT", + defaultValues: { + name: "", + status: "", + }, + fields: [ + { + label: "MICROPLAN_NAME", + type: "text", + isMandatory: false, + disable: false, + populators: { + name: "name", + style: { + marginBottom: "0px", + }, + }, + }, + { + label: "MICROPLAN_STATUS", + type: "dropdown", + isMandatory: false, + disable: false, + populators: { + name: "status", + optionsKey: "status", + optionsCustomStyle: { + top: "2.3rem", + }, + mdmsConfig: { + masterName: "MicroplanStatus", + moduleName: "hcm-microplanning", + localePrefix: "MICROPLAN_STATUS", + }, + }, + }, + ], + }, + label: "", + children: {}, + show: true, + // "labelMobile": "TQM_INBOX_SEARCH" + }, + searchResult: { + uiConfig: { + columns: [ + { + label: "MICROPLAN_NAME", + jsonPath: "name", + }, + { + label: "MICROPLAN_STATUS", + jsonPath: "status", + prefix: "MICROPLAN_STATUS_COLUMN_", + translate: true, + }, + { + label: "CAMPAIGNS_ASSIGNED", + jsonPath: "CampaignDetails.campaignName", + }, + { + label: "CAMPAIGN_DATE", + jsonPath: "CampaignDetails.startDate", + additionalCustomization: true, + }, + ], + showActionBarMobileCard: true, + actionButtonLabelMobileCard: "TQM_VIEW_RESULTS", + enableGlobalSearch: false, + enableColumnSort: true, + resultsJsonPath: "PlanConfiguration", + tableClassName: "table pqm-table", + noColumnBorder: true, + rowClassName: "table-row-mdms table-row-mdms-hover", + }, + children: {}, + show: true, + }, + }, + additionalSections: {}, + persistFormData: true, + showAsRemovableTagsInMobile: false, + customHookName: "microplan.useSavedMicroplans", +}; + +const SavedMicroplans = () => { + const [showLoader,setShowLoader] = useState(false) + const {state} = useMyContext() + const history = useHistory() + const { t } = useTranslation(); + + const onClickRow = async (row) => { + setShowLoader(true) + try { + const campaignType = row?.original?.CampaignDetails?.projectType; + const heirarchyData = await Digit.CustomService.getResponse({ + url: "/boundary-service/boundary-hierarchy-definition/_search", + useCache: false, + method: "POST", + userService: false, + body:{ + BoundaryTypeHierarchySearchCriteria: { + tenantId: Digit.ULBService.getStateId(), + hierarchyType: row?.original?.CampaignDetails?.hierarchyType, + }, + }, + }); + const additionalProps = { + heirarchyData:heirarchyData?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map((item) => item?.boundaryType), + t, + campaignType, + campaignData: row?.original?.CampaignDetails + } + //here compute the sessionObject based on the row?.original data and then re-route + const computedSession = await updateSessionUtils.computeSessionObject(row.original,state,additionalProps) + Digit.SessionStorage.set("microplanData", computedSession); + setShowLoader(false) + history.push(`/${window.contextPath}/employee/microplanning/create-microplan?id=${row?.original?.executionPlanId}`); + } catch (error) { + console.error(error.message) + } + }; + + const savedMircoplanSession = Digit.Hooks.useSessionStorage("SAVED_MICROPLAN_SESSION", {}); + + if(showLoader){ + return + } + + return ( + +
{t(configs?.label)}
+
+ +
+
+ ); +}; + +export default SavedMicroplans; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js new file mode 100644 index 00000000000..1dae49ee262 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js @@ -0,0 +1,226 @@ +import React, { useEffect, useMemo } from "react"; +import { useTranslation } from "react-i18next"; +import { Header, InboxSearchComposer, InboxSearchComposerV2, Loader } from "@egovernments/digit-ui-react-components"; +import { useHistory, useParams } from "react-router-dom"; + +const configs = { + label: "SELECT_CAMPAIGN", + type: "search", + apiDetails: { + serviceName: "/project-factory/v1/project-type/search", + requestParam: {}, + requestBody: {}, + minParametersForSearchForm: 0, + masterName: "commonUiConfig", + moduleName: "SearchCampaign", + tableFormJsonPath: "requestBody.CampaignDetails.pagination", + searchFormJsonPath: "requestBody.CampaignDetails", + }, + sections: { + search: { + uiConfig: { + type: "search", + // typeMobile: "filter", + headerLabel: "SELECT_CAMPAIGN", + headerStyle: null, + primaryLabel: "ES_COMMON_SEARCH", + secondaryLabel: "ES_COMMON_CLEAR_SEARCH", + minReqFields: 1, + // "showFormInstruction": "TQM_SEARCH_HINT", + defaultValues: { + campaignName: "", + projectType: "", + startDate: "", + endDate: "", + boundaryCode: "", + }, + fields: [ + { + label: "CAMPAIGN_NAME", + type: "text", + isMandatory: false, + disable: false, + populators: { + name: "campaignName", + style: { + marginBottom: "0px", + }, + error: "ERR_MIN_LENGTH_CAMPAIGN_NAME", + validationErrorStyles: { + marginTop: "0.3rem", + }, + validation: { + minLength: 2, + }, + }, + }, + // { + // label: "CAMPAIGN_TYPE", + // type: "dropdown", + // isMandatory: false, + // disable: false, + // populators: { + // name: "projectType", + // optionsKey: "name", + // optionsCustomStyle: { + // top: "2.3rem", + // }, + // mdmsConfig: { + // masterName: "projectTypes", + // moduleName: "HCM-PROJECT-TYPES", + // localePrefix: "CAMPAIGN_TYPE", + // }, + // }, + // }, + { + label: "CAMPAIGN_TYPE", + type: "apidropdown", + isMandatory: false, + disable: false, + populators: { + name: "projectType", + optionsKey: "i18nKey", + optionsCustomStyle: { + top: "2.3rem", + }, + allowMultiSelect: false, + masterName: "commonUiConfig", + moduleName: "SearchCampaign", + customfn: "populateProjectType", + }, + }, + { + label: "CAMPAIGN_START_DATE", + type: "date", + isMandatory: false, + key: "startDate", + disable: false, + preProcess: { + updateDependent: ["populators.max"], + }, + populators: { + name: "startDate", + style: { + marginBottom: "0px", + }, + error: "DATE_VALIDATION_MSG", + }, + }, + { + label: "CAMPAIGN_END_DATE", + type: "date", + isMandatory: false, + disable: false, + key: "endDate", + preProcess: { + updateDependent: ["populators.max"], + }, + populators: { + name: "endDate", + error: "DATE_VALIDATION_MSG", + min: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString().slice(0,10), + style: { + marginBottom: "0px", + }, + }, + }, + // { + // label: "CAMPAIGN_BOUNDARY", + // type: "text", + // isMandatory: false, + // disable: false, + // populators: { + // name: "boundaryCode", + // style: { + // marginBottom: "0px", + // }, + // }, + // }, + ], + }, + label: "", + children: {}, + show: true, + // "labelMobile": "TQM_INBOX_SEARCH" + }, + searchResult: { + uiConfig: { + columns: [ + { + label: "CAMPAIGN_NAME", + jsonPath: "campaignName", + // "additionalCustomization": true + }, + { + label: "CAMPAIGN_TYPE", + jsonPath: "projectType", + // "additionalCustomization": false, + prefix: "CAMPAIGN_TYPE_", + translate: true, + }, + { + label: "CAMPAIGN_BOUNDARY_CAMP", + jsonPath: "boundaryCode", + // "additionalCustomization": false, + prefix: "CAMPAIGN_BOUNDARY_", + translate: true, + }, + { + label: "CAMPAIGN_BENEFICIARY_TYPE", + jsonPath: "additionalDetails.beneficiaryType", + prefix: "CAMPAIGN_BENEFICIARY_TYPE_", + translate: true, + }, + { + label: "CAMPAIGN_DATE", + jsonPath: "startDate", + additionalCustomization: true, + }, + ], + showActionBarMobileCard: true, + actionButtonLabelMobileCard: "TQM_VIEW_RESULTS", + enableGlobalSearch: false, + enableColumnSort: true, + resultsJsonPath: "CampaignDetails", + tableClassName: "table pqm-table", + rowClassName: "table-row-mdms table-row-mdms-hover", + noColumnBorder: true, + }, + children: {}, + show: true, + }, + }, + additionalSections: {}, + persistFormData: true, + showAsRemovableTagsInMobile: false, +}; +const SelectCampaign = () => { + const { t } = useTranslation(); + const history = useHistory(); + + const onClickRow = (row) => { + // history.push(`/${window.contextPath}/employee/microplanning/help-guidelines?id=${row?.original?.id}`); + history.push(`/${window.contextPath}/employee/microplanning/create-microplan?id=${row?.original?.id}`); + }; + + const SelectCampaignSession = Digit.Hooks.useSessionStorage("SELECT_CAMPAIGN_SESSION", {}); + + return ( + +
{t(configs?.label)}
+
+ +
+
+ ); +}; + +export default SelectCampaign; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js new file mode 100644 index 00000000000..4a06ca843e7 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js @@ -0,0 +1,126 @@ +import React, { useEffect } from "react"; +import { Switch, useLocation } from "react-router-dom"; +import { useTranslation } from "react-i18next"; +import { PrivateRoute, AppContainer, BreadCrumb, Loader } from "@egovernments/digit-ui-react-components"; +import MicroplanningHeader from "../../components/MicroplanningHeader"; +import Guidelines from "./Guidelines"; +import CreateMicroplan from "./CreateMicroplan"; +import SavedMicroplans from "./SavedMicroplans"; +import SelectCampaign from "./SelectCampaign"; +import { useMyContext } from "../../utils/context"; + +const MicroplanningBreadCrumb = ({ location, defaultPath }) => { + const { t } = useTranslation(); + const pathVar = location.pathname.replace(defaultPath + "/", "").split("?")?.[0]; + const { masterName, moduleName, uniqueIdentifier } = Digit.Hooks.useQueryParams(); + + const crumbs = [ + { + path: `/${window?.contextPath}/employee`, + content: t("Home"), + show: true, + }, + // { + // content: t(`UPLOAD`) , + // show: pathVar.includes("upload")?true: false, + // }, + // { + // content: t(`HYPOTHESIS`) , + // show: pathVar.includes("hypothesis")?true: false, + // }, + // { + // content: t(`RULE_ENGINE`) , + // show: pathVar.includes("rule-engine")?true: false, + // }, + { + content: t(`CREATE_MICROPLAN`), + show: pathVar.includes("create-microplan"), + }, + { + content: t(`SAVED_MICROPLANS_TEXT`), + show: pathVar.includes("saved-microplan"), + }, + { + content: t(`CREATE_MICROPLAN`), + show: pathVar.includes("select-campaign"), + }, + ]; + return ; +}; + +const App = ({ path }) => { + const { dispatch } = useMyContext(); + + const location = useLocation(); + const MDMSCreateSession = Digit.Hooks.useSessionStorage("MDMS_add", {}); + const [sessionFormData, setSessionFormData, clearSessionFormData] = MDMSCreateSession; + + const MDMSViewSession = Digit.Hooks.useSessionStorage("MDMS_view", {}); + const [sessionFormDataView, setSessionFormDataView, clearSessionFormDataView] = MDMSViewSession; + + const { isLoading: isLoadingMdmsBaseData, data } = Digit.Hooks.useCustomMDMS( + "mz", + "hcm-microplanning", + [ + { name: "UploadConfiguration" }, + { name: "UIConfiguration" }, + { name: "Schemas" }, + { name: "RuleConfigureOutput" }, + { name: "Resources" }, + { name: "HypothesisAssumptions" }, + { name: "BaseMapLayers" }, + { name: "MicroplanPreviewAggregates" }, + { name: "AutoFilledRuleConfigurations" }, + { name: "MapFilters" }, + { name: "HierarchyConfigurations" }, + { name: "NumberFormatMappingForTranslation" }, + { name: "UploadGuidelines" }, + ], + { + select: (data) => { + dispatch({ + type: "SETINITDATA", + state: { + ...data?.["hcm-microplanning"], + }, + }); + }, + } + ); + + //destroying session + useEffect(() => { + const pathVar = location.pathname.replace(path + "/", "").split("?")?.[0]; + Digit.Utils.microplan.destroySessionHelper(pathVar, ["create-microplan"], "microplanData"); + Digit.Utils.microplan.destroySessionHelper(pathVar, ["create-microplan"], "microplanHelperData"); + Digit.Utils.microplan.destroySessionHelper(pathVar, ["select-campaign"], "SELECT_CAMPAIGN_SESSION"); + Digit.Utils.microplan.destroySessionHelper(pathVar, ["saved-microplans"], "SAVED_MICROPLAN_SESSION"); + }, [location]); + + if (isLoadingMdmsBaseData) { + return ; + } + + return ( + +
+ + +
+ + + {/* } /> + } /> + } /> */} + } /> + + } /> + } /> + } /> + + +
+ ); +}; + +export default App; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js new file mode 100644 index 00000000000..c4f39680eb6 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js @@ -0,0 +1,16 @@ +const CreatePlanConfig = async (body) => { + try { + const response = await Digit.CustomService.getResponse({ + url: "/plan-service/config/_create", + useCache: false, + method: "POST", + userService: true, + body, + }); + return response + } catch (error) { + throw new Error(error?.response?.data?.Errors[0].message); + } +}; + +export default CreatePlanConfig; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js new file mode 100644 index 00000000000..15b948907cb --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js @@ -0,0 +1,182 @@ +import _ from "lodash"; + +const createProjectsArray = (t, project, searchParams, headerLocale) => { + let totalProjects = { + searchedProject: {}, + subProjects: [], + }; + let basicDetails = {}; + let totalProjectsLength = project.length; + // for(let projectIndex = 0; projectIndex < totalProjectsLength; projectIndex++) { + let currentProject = project[0]; + const headerDetails = { + title: " ", + asSectionHeader: true, + values: [ + { title: "WORKS_PROJECT_ID", value: currentProject?.projectNumber || "NA" }, + { title: "ES_COMMON_PROPOSAL_DATE", value: Digit.Utils.pt.convertEpochToDate(currentProject?.additionalDetails?.dateOfProposal) || "NA" }, + { title: "WORKS_PROJECT_NAME", value: currentProject?.name || "NA" }, + { title: "PROJECT_PROJECT_DESC", value: currentProject?.description || "NA" }, + ], + }; + + const projectDetails = { + title: "WORKS_PROJECT_DETAILS", + asSectionHeader: true, + values: [ + { title: "PROJECT_LOR", value: currentProject?.referenceID || "NA" }, + { + title: "WORKS_PROJECT_TYPE", + value: currentProject?.projectType ? t(`COMMON_MASTERS_${Digit.Utils.locale.getTransformedLocale(currentProject?.projectType)}`) : "NA", + }, + { + title: "PROJECT_TARGET_DEMOGRAPHY", + value: currentProject?.additionalDetails?.targetDemography + ? t(`COMMON_MASTERS_${currentProject?.additionalDetails?.targetDemography}`) + : "NA", + }, + { + title: "PROJECT_ESTIMATED_COST", + value: currentProject?.additionalDetails?.estimatedCostInRs + ? `₹ ${Digit.Utils.dss.formatterWithoutRound(currentProject?.additionalDetails?.estimatedCostInRs, "number")}` + : "NA", + }, + ], + }; + + const locationDetails = { + title: "WORKS_LOCATION_DETAILS", + asSectionHeader: true, + values: [ + { + title: "WORKS_GEO_LOCATION", + value: + currentProject?.address?.latitude || currentProject?.address?.longitude + ? `${currentProject?.address?.latitude}, ${currentProject?.address?.longitude}` + : "NA", + }, + { + title: "WORKS_CITY", + value: currentProject?.address?.city ? t(`TENANT_TENANTS_${Digit.Utils.locale.getTransformedLocale(currentProject?.address?.city)}`) : "NA", + }, //will check with Backend + { title: "WORKS_WARD", value: currentProject?.address?.boundary ? t(`${headerLocale}_ADMIN_${currentProject?.address?.boundary}`) : "NA" }, ///backend to update this + { + title: "WORKS_LOCALITY", + value: currentProject?.additionalDetails?.locality ? t(`${headerLocale}_ADMIN_${currentProject?.additionalDetails?.locality}`) : "NA", + }, + ], + }; + + // const financialDetails = { + // title: "WORKS_FINANCIAL_DETAILS", + // asSectionHeader: false, + // values: [ + // { title: "WORKS_HEAD_OF_ACCOUNTS", value: currentProject?.additionalDetails?.fund ? t(`COMMON_MASTERS_FUND_${currentProject?.additionalDetails?.fund}`) : "NA" }, + // ], + // }; + + let documentDetails = { + title: "", + asSectionHeader: true, + additionalDetails: { + documents: [ + { + title: "WORKS_RELEVANT_DOCUMENTS", + BS: "Works", + values: currentProject?.documents?.map((document) => { + if (document?.status !== "INACTIVE") { + return { + title: document?.documentType === "OTHERS" ? document?.additionalDetails?.otherCategoryName : t(`PROJECT_${document?.documentType}`), + documentType: document?.documentType, + documentUid: document?.fileStore, + fileStoreId: document?.fileStore, + }; + } + return {}; + }), + }, + ], + }, + }; + + //filter any empty object + documentDetails.additionalDetails.documents[0].values = documentDetails?.additionalDetails?.documents?.[0]?.values?.filter((value) => { + if (value?.title) { + return value; + } + }); + + // if(currentProject?.projectNumber === searchParams?.Projects?.[0]?.projectNumber) { + basicDetails = { + projectID: currentProject?.projectNumber, + projectProposalDate: Digit.Utils.pt.convertEpochToDate(currentProject?.additionalDetails?.dateOfProposal) || "NA", + projectName: currentProject?.name || "NA", + projectDesc: currentProject?.description || "NA", + projectHasSubProject: totalProjectsLength > 1 ? "COMMON_YES" : "COMMON_NO", + projectParentProjectID: currentProject?.ancestors?.[0]?.projectNumber || "NA", + uuid: currentProject?.id, + address: currentProject?.address, + ward: currentProject?.address?.boundary, + locality: currentProject?.additionalDetails?.locality, + }; + totalProjects.searchedProject = { + basicDetails, + headerDetails, + projectDetails, + locationDetails, + documentDetails, + }; + // } + // } + return totalProjects; +}; + +export const Search = { + viewProjectDetailsScreen: async ( + t, + tenantId, + searchParams, + filters = { limit: 10, offset: 0, includeAncestors: true, includeDescendants: true }, + headerLocale + ) => { + const response = await Digit.WorksService?.searchProject(tenantId, searchParams, filters); + + let projectDetails = { + searchedProject: { + basicDetails: {}, + details: { + projectDetails: [], + }, + }, + }; + + if (response?.Project) { + let projects = createProjectsArray(t, response?.Project, searchParams, headerLocale); + + //searched Project details + projectDetails.searchedProject["basicDetails"] = projects?.searchedProject?.basicDetails; + projectDetails.searchedProject["details"]["projectDetails"] = { + applicationDetails: [ + projects?.searchedProject?.headerDetails, + projects?.searchedProject?.projectDetails, + projects?.searchedProject?.locationDetails, + projects?.searchedProject?.documentDetails, + ], + }; //rest categories will come here + } + + return { + projectDetails: response?.Project ? projectDetails : [], + response: response?.Project, + processInstancesDetails: [], + applicationData: {}, + workflowDetails: [], + applicationData: {}, + isNoDataFound: response?.Project?.length === 0, + }; + }, + searchEstimate: async (tenantId, filters) => { + const response = await Digit.WorksService?.estimateSearch({ tenantId, filters }); + return response?.estimates; + }, +}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js new file mode 100644 index 00000000000..3138d5a6df8 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js @@ -0,0 +1,19 @@ +const SearchCampaignConfig = async (body) => { + try { + const response = await Digit.CustomService.getResponse({ + url: "/project-factory/v1/project-type/search", + useCache: false, + method: "POST", + userService: false, + body, + }); + if(response?.CampaignDetails?.length===0){ + throw new Error("Campaign not found with the given id"); + } + return response?.CampaignDetails?.[0] + } catch (error) { + throw new Error(error?.response?.data?.Errors[0].message); + } +}; + +export default SearchCampaignConfig; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js new file mode 100644 index 00000000000..5fb8001da1b --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js @@ -0,0 +1,16 @@ +const SearchPlanConfig = async (body) => { + try { + const response = await Digit.CustomService.getResponse({ + url: "/plan-service/config/_search", + useCache: false, + method: "POST", + userService: true, + body, + }); + return response + } catch (error) { + throw new Error(error?.response?.data?.Errors[0].message); + } +}; + +export default SearchPlanConfig; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js new file mode 100644 index 00000000000..875529d35f3 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js @@ -0,0 +1,15 @@ +const UpdatePlanConfig = async (body) => { + try { + const response = await Digit.CustomService.getResponse({ + url: "/plan-service/config/_update", + useCache: false, + method: "POST", + userService: true, + body, + }); + return response + } catch (error) { + throw new Error(error?.response?.data?.Errors[0].message); + } +}; +export default UpdatePlanConfig; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js new file mode 100644 index 00000000000..18914b95338 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js @@ -0,0 +1,64 @@ +function mergeArrays(array1, key1, array2, key2) { + const mergedArray = []; + + // Create a map of values from array2 using key2 + const map = new Map(); + array2.forEach((item) => { + map.set(item[key2], item); + }); + + // Iterate over array1 and merge with matching items from array2 + array1.forEach((item) => { + const matchingItem = map.get(item[key1]); + if (matchingItem) { + // Merge properties from both items and append to 'CampaignDetails' + const mergedItem = { ...item, CampaignDetails: { ...matchingItem } }; + mergedArray.push(mergedItem); + } else { + // No matching item found in array2, add array1 item with empty 'CampaignDetails' + const mergedItem = { ...item, CampaignDetails: {} }; + mergedArray.push(mergedItem); + } + }); + return mergedArray; +} + +const SearchSavedPlans = async (body) => { + try { + //here get response from both apis and process data and return + const responsePlan = await Digit.CustomService.getResponse({ + url: "/plan-service/config/_search", + useCache: false, + method: "POST", + userService: false, + body, + }); + + const { PlanConfiguration } = responsePlan; + if(!PlanConfiguration || PlanConfiguration.length === 0) return []; + + const executionPlanIds = PlanConfiguration?.map((row) => row?.executionPlanId)?.filter((item) => item); + const CampaignDetails = { + tenantId: Digit.ULBService.getCurrentTenantId(), + ids: executionPlanIds, + }; + + const responseCampaign = await Digit.CustomService.getResponse({ + url: "/project-factory/v1/project-type/search", + useCache: false, + method: "POST", + userService: false, + body: { + CampaignDetails, + }, + }); + const finalResult = { + PlanConfiguration: mergeArrays(responsePlan?.PlanConfiguration, "executionPlanId", responseCampaign?.CampaignDetails, "id"), + }; + return finalResult; + } catch (error) { + throw new Error(error?.response?.data?.Errors[0].message); + } +}; + +export default SearchSavedPlans; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js new file mode 100644 index 00000000000..5e6c18f699e --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js @@ -0,0 +1,31 @@ +import React,{useContext,createContext,useReducer} from "react" + +const MyContext = createContext() +const initialState = { + +} + +const reducer = (state=initialState,action) => { + switch (action.type) { + case "SETINITDATA": + return {...state,...action.state} + default: + return state; + } +} + +export const useMyContext = () => { + + return useContext(MyContext) +} + +export const ProviderContext = ({children}) => { + + const [state,dispatch] = useReducer(reducer,initialState) + + return ( + + {children} + + ) +} \ No newline at end of file diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js new file mode 100644 index 00000000000..a473399dbf1 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js @@ -0,0 +1,480 @@ +import { BOUNDARY_DATA_SHEET, FACILITY_DATA_SHEET, SCHEMA_PROPERTIES_PREFIX, commonColumn } from "../configs/constants"; + +export const fetchBoundaryData = async (tenantId, hierarchyType, codes) => { + // request for boundary relation api + const reqCriteria = { + url: "/boundary-service/boundary-relationships/_search", + params: { tenantId, hierarchyType, codes, includeChildren: true }, + body: {}, + }; + let response; + try { + response = (await Digit.CustomService.getResponse(reqCriteria))?.TenantBoundary?.[0]?.boundary || {}; + } catch (error) { + console.error("Error in fetching boundary Data: ", error.message); + } + return response; +}; + +export const getFacilities = async (params, body) => { + // request for boundary relation api + const reqCriteria = { + url: "/facility/v1/_search", + params: params, + body: body, + }; + let response; + try { + response = (await Digit.CustomService.getResponse(reqCriteria))?.Facilities || {}; + } catch (error) { + if (error.response) { + throw new Error("Failed to fetch facility data: " + error.response.data.message); + } else if (error.request) { + // Network error + throw new Error("Network error while fetching facility data"); + } else { + // Other errors + throw new Error("Error while fetching facility data: " + error.message); + } + } + return response; +}; + +// export const fetchColumnsFromMdms = (schema)=>{ +// return +// } + +/** + * + * @param {*} xlsxData + * @param {*} boundaryData + * @returns xlsxData with boundary data added + */ +export const addBoundaryData = (xlsxData, boundaryData, hierarchyType) => { + // Return the original data if there is no boundary data to add + if (!boundaryData) return xlsxData; + + // Initialize the array to hold new data + let newXlsxData = []; + + // Recursive function to convert boundary data into sheet format + const convertBoundaryDataToSheets = (boundaryData, currentBoundaryPredecessor = [], hierarchyAccumulator = [], dataAccumulator = []) => { + // Return if boundary data is not valid or not an array + if (!boundaryData || !Array.isArray(boundaryData)) return; + + // Clone the current boundary predecessor to avoid modifying the original data + let rowData = [...currentBoundaryPredecessor]; + // Clone the data accumulator to preserve the accumulated data + let tempDataAccumulator = [...dataAccumulator]; + // Use a set to accumulate unique hierarchy levels + let tempHierarchyAccumulator = new Set(hierarchyAccumulator); + + // Iterate over each item in the boundary data array + for (const item of boundaryData) { + if (item?.code) { + // Create a new row with the current item's code + let tempRow = [...rowData, item?.code]; + let response; + // Add the current item's boundary type to the hierarchy + tempHierarchyAccumulator.add(item.boundaryType); + + // If the current item has children, recursively process them + if (item.children) + response = convertBoundaryDataToSheets(item.children, tempRow, tempHierarchyAccumulator, [...tempDataAccumulator, tempRow]); + + // Update the accumulators with the response from the recursive call + if (response) { + tempDataAccumulator = response.tempDataAccumulator; + tempHierarchyAccumulator = response.tempHierarchyAccumulator; + } + } + } + + // Return the accumulated data and hierarchy + return { tempDataAccumulator, tempHierarchyAccumulator }; + }; + + // Convert the boundary data into sheet format and extract the sorted data and hierarchy + let { tempDataAccumulator: sortedBoundaryDataForXlsxSheet, tempHierarchyAccumulator: hierarchy } = convertBoundaryDataToSheets(boundaryData); + + // Add the hierarchy as the first row of the sheet + hierarchy = [...hierarchy].map((item) => `${hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item)}`); + sortedBoundaryDataForXlsxSheet = [[...hierarchy], ...sortedBoundaryDataForXlsxSheet]; + + // Determine the maximum row length to ensure all rows have the same length + const topIndex = Math.max(...sortedBoundaryDataForXlsxSheet.map((row) => row.length)) - 1; + + // Ensure all rows are of the same length by filling them with empty strings + sortedBoundaryDataForXlsxSheet = sortedBoundaryDataForXlsxSheet.map((item, index) => { + if (index !== 0) { + if (!item) { + item = []; + } + let itemLength = item.length; + while (item.length <= topIndex) { + item.push(""); + } + item.push(item[itemLength - 1]); + } else { + item.push(commonColumn); + } + + return item; + }); + + // Add the new sheet data to the original data + newXlsxData = [...xlsxData, ...newXlsxData, { sheetName: BOUNDARY_DATA_SHEET, data: sortedBoundaryDataForXlsxSheet }]; + + // Return the updated data + return newXlsxData; +}; + +const fillDataWithBlanks = (data, tillRow) => { + while (data.length < tillRow) { + data.push([]); + } + + const maxLength = Math.max(...data.map((row) => row.length)); + return data.map((row) => [...row, ...new Array(maxLength - row.length).fill("")]); +}; +const generateLocalisationKeyForSchemaProperties = (code) => { + if (!code) return code; + return SCHEMA_PROPERTIES_PREFIX + "_" + code; +}; +/** + * + * @param {array} xlsxData , xlsx data + * @param {object} schema , schema to refer to + * @returns {Array of Object} , xlsxData with schema data added + * + * adds schema data to sheets + */ +const addSchemaData = (xlsxData, schema, extraColumnsToAdd) => { + if (!schema) return xlsxData; + let columnSchema = schema.schema?.Properties || {}; + let newXlsxData = []; + let columnList = [[], [], [], []]; // Initialize columnList with four empty arrays + + for (const [key, value] of Object.entries(columnSchema)) { + if (key === commonColumn) continue; + + columnList[0].push(generateLocalisationKeyForSchemaProperties(key)); // Add key to the first array + + // columnList[1].push(value.type || ""); // Add type to the second array + + // columnList[2].push(value.isRequired ? "MANDATORY" : "OPTIONAL"); // Add requirement status to the third array + + // columnList[3].push(value.pattern || ""); // Add pattern to the fourth array + } + + if (extraColumnsToAdd) columnList[0].push(...extraColumnsToAdd); + + for (let { sheetName, data } of xlsxData) { + data = fillDataWithBlanks(data, 4); + columnList.forEach((item, index) => { + // Append the new items to the row + if (data[index]) { + data[index] = [...data[index], ...item]; + } else { + data[index] = [...item]; + } + }); + + newXlsxData.push({ sheetName, data }); + } + + return newXlsxData; +}; + +/** + * + * @param {Array of Object} xlsxData + * @param {string} hierarchyLevelName + */ +const devideXlsxDataHierarchyLevelWise = (xlsxData, hierarchyLevelName) => { + // If no hierarchyLevelName is provided, return the original data + if (!hierarchyLevelName) return xlsxData; + + // Initialize an array to hold the result + const result = []; + + // Array to store the row with empty hierarchy level value + let emptyHierarchyRow = []; + + // Iterate over each sheet in the xlsxData + for (const sheet of xlsxData) { + const sheetData = sheet.data; + + // Find the index of the hierarchy level name in the header row + const hierarchyLevelIndex = sheetData[0].indexOf(hierarchyLevelName); + + // If the hierarchy level name is not found, skip this sheet + if (hierarchyLevelIndex === -1) { + result.push(sheet); + return result; + } + + // Create a map to hold new sheets data based on hierarchy level values + const sheetsMap = {}; + // Create a map to hold dangling data for each hierarchy value + const danglingDataMap = {}; + // Flag to track if the last processed row had an empty hierarchy level value + let lastWasEmpty = true; + + // Iterate through the sheet data starting from the second row (skipping header) + for (let i = 1; i < sheetData.length; i++) { + const row = sheetData[i]; + const hierarchyValue = row[hierarchyLevelIndex]; + + // If the hierarchy value is not empty and there was previous empty data, + if (emptyHierarchyRow.length && hierarchyValue !== "") { + danglingDataMap[hierarchyValue] = emptyHierarchyRow; + } + + // If hierarchy value is empty, store this row + if (hierarchyValue === "" && lastWasEmpty) { + emptyHierarchyRow.push(row); + } else { + // store the empty data in the danglingDataMap for the current hierarchy value + if (emptyHierarchyRow.length && hierarchyValue === "") { + emptyHierarchyRow = []; // Reset emptyHierarchyRow + } + } + + // If this hierarchy value hasn't been seen before, create a new sheet for it + if (!sheetsMap[hierarchyValue] && hierarchyValue !== "") { + // Include all rows with empty hierarchy level data or different hierarchy values + sheetsMap[hierarchyValue] = { + sheetName: hierarchyValue, + data: [sheetData[0]], // Start with the header row + }; + } + + // Include the current row if its hierarchy level data matches the sheet's hierarchy value + if (hierarchyValue === row[hierarchyLevelIndex] && hierarchyValue !== "") { + sheetsMap[hierarchyValue].data.push(row); + } + + // Update the lastWasEmpty flag + if (hierarchyValue === "" && !lastWasEmpty) { + lastWasEmpty = true; + } else if (hierarchyValue !== "") { + lastWasEmpty = false; + } + } + + // Combine danglingDataMap with sheetsMap + for (const key of Object.keys(danglingDataMap)) { + if (sheetsMap[key]) { + // Combine dangling data with existing sheet data + sheetsMap[key].data = [sheetData[0], ...danglingDataMap[key], ...sheetsMap[key].data.slice(1)]; + } else { + // Create a new sheet for dangling data + sheetsMap[key] = { + sheetName: key, + data: [...danglingDataMap[key], sheetData[0]], // Include header row + }; + } + } + + // Convert the sheets map to an array of objects and add to the result + result.push(...Object.values(sheetsMap)); + } + + return result || xlsxData; +}; + +export const filterBoundaries = (boundaryData, boundaryFilters) => { + if (!boundaryFilters) return boundaryData; + // Define a helper function to recursively filter boundaries + function filterRecursive(boundary) { + // Find the filter that matches the current boundary + const filter = boundaryFilters?.find((f) => f.code === boundary.code && f.type === boundary.boundaryType); + + // If no filter is found, return the boundary with its children filtered recursively + if (!filter) { + return { + ...boundary, + children: boundary.children.map(filterRecursive), + }; + } + + // If the boundary has no children, handle the case where includeAllChildren is false + if (!boundary.children.length) { + // Return the boundary with an empty children array + return { + ...boundary, + children: [], + }; + } + + // If includeAllChildren is true, return the boundary with all children + if (filter.includeAllChildren) { + return { + ...boundary, + children: boundary.children.map(filterRecursive), + }; + } + + // Filter children based on the filters + const filteredChildren = boundary.children + .filter((child) => boundaryFilters.some((f) => f.code === child.code && f.type === child.boundaryType)) + .map(filterRecursive); + + // Return the boundary with filtered children + return { + ...boundary, + children: filteredChildren, + }; + } + + // Map through the boundary data and apply the recursive filter function to each boundary + const filteredData = boundaryData.map(filterRecursive); + return filteredData; +}; + +/** + * Retrieves all facilities for a given tenant ID. + * @param tenantId The ID of the tenant. + * @returns An array of facilities. + */ +async function getAllFacilities(tenantId) { + // Retrieve all facilities for the given tenant ID + const facilitySearchBody = { + Facility: { isPermanent: true }, + }; + + const facilitySearchParams = { + limit: 50, + offset: 0, + tenantId: tenantId, + }; + + const searchedFacilities = []; + let searchAgain = true; + + while (searchAgain) { + const response = await getFacilities(facilitySearchParams, facilitySearchBody); + if (response) { + searchAgain = response.length >= 50; + searchedFacilities.push(...response); + facilitySearchParams.offset += 50; + } else searchAgain = false; + } + + return searchedFacilities; +} + +const addFacilitySheet = (xlsxData, mapping, facilities, schema, t) => { + if (!mapping) return xlsxData; + // Create header row + const headers = Object.keys(mapping); + + // Create data rows + const dataRow = []; + for (const facility of facilities) { + facility.isPermanent = facility.isPermanent ? t("PERMAENENT") : t("TEMPORARY"); + dataRow.push(headers.map((header) => facility[mapping[header]])); + } + headers.push(commonColumn); + let additionalCols = []; + if (schema?.schema?.Properties) { + const properties = Object.keys(schema.schema.Properties); + for (const col of properties) { + if (!headers.includes(col)) { + additionalCols.push(col); + } + } + } + headers.push(...additionalCols); + // Combine headers and data rows + const arrayOfArrays = [headers.map((item) => generateLocalisationKeyForSchemaProperties(item)), ...dataRow]; + + let facilitySheet = { + sheetName: FACILITY_DATA_SHEET, + data: arrayOfArrays, + }; + xlsxData = [facilitySheet, ...xlsxData]; + return xlsxData; +}; + +/** + * + * @param {boolean} hierarchyLevelWiseSheets + * @param {string} hierarchyLevelName , if district Wise is true, then this must be present, + * @param {boolean} addFacilityData + * @param {Object} schema + * + */ +export const createTemplate = async ({ + hierarchyLevelWiseSheets = true, + hierarchyLevelName, + addFacilityData = false, + schema, + boundaries, + tenantId, + hierarchyType, + t, +}) => { + const rootBoundary = boundaries?.filter((boundary) => boundary.isRoot); // Retrieve session storage data once and store it in a variable + const sessionData = Digit.SessionStorage.get("microplanHelperData") || {}; + let boundaryData = sessionData.filteredBoundaries; + let filteredBoundaries; + + if (!boundaryData) { + // Only fetch boundary data if not present in session storage + boundaryData = await fetchBoundaryData(tenantId, hierarchyType, rootBoundary?.[0]?.code); + filteredBoundaries = await filterBoundaries(boundaryData, boundaries); + + // Update the session storage with the new filtered boundaries + Digit.SessionStorage.set("microplanHelperData", { + ...sessionData, + filteredBoundaries: filteredBoundaries, + }); + } else { + filteredBoundaries = boundaryData; + } + + // const filteredBoundaryData = boundaryData; + let xlsxData = []; + // adding boundary data to xlsxData + xlsxData = addBoundaryData(xlsxData, filteredBoundaries, hierarchyType); + + if (hierarchyLevelWiseSheets) { + // district wise boundary Data sheets + xlsxData = devideXlsxDataHierarchyLevelWise(xlsxData, hierarchyLevelName); + if (addFacilityData) { + // adding facility sheet + const facilities = await getAllFacilities(tenantId); + if (schema?.template?.facilitySchemaApiMapping) + xlsxData = addFacilitySheet(xlsxData, schema?.template?.facilitySchemaApiMapping, facilities, schema, t); + else xlsxData = addSchemaData(xlsxData, schema); + } else { + // not adding facility sheet + // adding schema data to xlsxData + xlsxData = addSchemaData(xlsxData, schema); + } + } else { + // total boundary Data in one sheet + if (addFacilityData) { + // adding facility sheet + const facilities = await getAllFacilities(tenantId); + if (schema?.template?.facilitySchemaApiMapping) + xlsxData = addFacilitySheet(xlsxData, schema?.template?.facilitySchemaApiMapping, facilities, schema, t); + else { + let facilitySheet = { + sheetName: FACILITY_DATA_SHEET, + data: [], + }; + facilitySheet = addSchemaData([facilitySheet], schema, [commonColumn]); + xlsxData = [...facilitySheet, ...xlsxData]; + } + } else { + // not adding facility sheet + + // adding schema data to xlsxData + xlsxData = addSchemaData(xlsxData, schema); + } + } + return xlsxData; +}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js new file mode 100644 index 00000000000..b50b2ad48a6 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js @@ -0,0 +1,150 @@ +import { SHEET_PASSWORD, UNPROTECT_TILL_ROW } from "../configs/constants"; + +export function updateFontNameToRoboto(worksheet) { + worksheet.eachRow({ includeEmpty: true }, (row) => { + row.eachCell({ includeEmpty: true }, (cell) => { + // Preserve existing font properties + const existingFont = cell.font || {}; + + // Update only the font name to Roboto + cell.font = { + ...existingFont, // Spread existing properties + name: "Roboto", // Update the font name + }; + }); + }); +} + +export const freezeWorkbookValues = async (workbook) => { + workbook.eachSheet((worksheet) => { + worksheet.eachRow((row) => { + row.eachCell((cell) => { + // Lock each cell + cell.protection = { + locked: true, + }; + }); + }); + // Protect the worksheet + worksheet.protect(SHEET_PASSWORD, { + selectLockedCells: true, + selectUnlockedCells: true, + }); + }); + + return workbook; +}; + +export const unfreezeColumnsByHeader = async (workbook, headers) => { + workbook.eachSheet((worksheet) => { + const headerRow = worksheet.getRow(1); // Assuming headers are in the first row + const columnsToUnfreeze = []; + + headerRow.eachCell((cell, colNumber) => { + if (headers.includes(cell.value)) { + columnsToUnfreeze.push(colNumber); + } + }); + + worksheet.eachRow((row, rowNumber) => { + if (rowNumber === 1) return; + columnsToUnfreeze.forEach((colNumber) => { + const cell = row.getCell(colNumber); + cell.protection = { + locked: false, + }; + }); + }); + + // Re-protect the worksheet after modifying cell protection + worksheet.protect(SHEET_PASSWORD, { + selectLockedCells: true, + selectUnlockedCells: true, + }); + }); + + return workbook; +}; + +export const freezeSheetValues = async (workbook, sheetName) => { + const worksheet = workbook.getWorksheet(sheetName); + if (worksheet) { + worksheet.eachRow((row) => { + row.eachCell((cell) => { + // Lock each cell + cell.protection = { + locked: true, + }; + }); + }); + // Protect the worksheet + worksheet.protect(SHEET_PASSWORD, { + selectLockedCells: true, + selectUnlockedCells: true, + }); + } + + return workbook; +}; + +export const freezeCellsWithData = async (workbook, sheetName) => { + const worksheet = workbook.getWorksheet(sheetName); + if (worksheet) { + worksheet.eachRow((row) => { + row.eachCell((cell) => { + if (cell.value) { + // Check if the cell has data + cell.protection = { + locked: true, + }; + } else { + cell.protection = { + locked: false, + }; + } + }); + }); + // Protect the worksheet + worksheet.protect(SHEET_PASSWORD, { + selectLockedCells: true, + selectUnlockedCells: true, + }); + } + + return workbook; +}; +export const performUnfreezeCells = async (workbook, sheetName) => { + const sheet = workbook.getWorksheet(sheetName); + + let lastFilledColumn = 1; + sheet.getRow(1).eachCell((cell, colNumber) => { + if (cell.value !== undefined && cell.value !== null && cell.value !== "") { + lastFilledColumn = colNumber; + } + }); + + for (let row = 1; row <= parseInt(UNPROTECT_TILL_ROW); row++) { + for (let col = 1; col <= lastFilledColumn; col++) { + const cell = sheet.getCell(row, col); + if (!cell.value && cell.value !== 0) { + cell.protection = { locked: false }; + } + } + } + sheet.protect(SHEET_PASSWORD, { selectLockedCells: true, selectUnlockedCells: true }); +}; + +export const hideUniqueIdentifierColumn = async (workbook, sheetName, column) => { + const sheet = workbook.getWorksheet(sheetName); + for (const item of column) { + let colIndex; + sheet.getRow(1).eachCell((cell, colNumber) => { + if (cell.value === item) { + colIndex = colNumber; + } + }); + if (column && sheet.getColumn(colIndex)) { + sheet.getColumn(colIndex).hidden = true; + } + } +}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js new file mode 100644 index 00000000000..176743cdfdb --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js @@ -0,0 +1,182 @@ +import Ajv from "ajv"; +const ajv = new Ajv({ allErrors: true }); +ajv.addKeyword("isRequired"); +ajv.addKeyword("isLocationDataColumns"); +ajv.addKeyword("isRuleConfigureInputs"); +ajv.addKeyword("isFilterPropertyOfMapSection"); +ajv.addKeyword("isVisualizationPropertyOfMapSection"); +ajv.addKeyword("toShowInMicroplanPreview"); + +// Function responsible for excel data validation with respect to the template/schema provided +export const excelValidations = (data, schemaData, t) => { + const translate = () => { + const required = Object.entries(schemaData?.Properties || {}) + .reduce((acc, [key, value]) => { + if (value?.isRequired) { + acc.push(key); + } + return acc; + }, []) + .map((item) => item); + return { required, properties: schemaData.Properties }; + }; + const { required, properties } = translate(); + const schema = { + type: "object", + patternProperties: { + ".*": { + type: "array", + items: { + type: "object", + properties: properties, + required: required, + additionalProperties: true, + }, + }, + }, + minProperties: 1, + additionalProperties: false, + }; + const validateExcel = ajv.compile(schema); + const valid = validateExcel(data); + let locationDataColumns = Object.entries(schemaData?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.isLocationDataColumns) { + acc.push(key); + } + return acc; + }, []); + if (!valid) { + let errors = {}; + let hasDataErrors = "false"; // true, false, missing_properties, unknown + let missingColumnsList = new Set(); + let errorMessages = {}; + for (let i = 0; i < validateExcel.errors.length; i++) { + let tempErrorStore = ""; + let instancePathTypeGlobal; // = validateExcel.errors[i].instancePath.split("/"); + switch (validateExcel.errors[i].keyword) { + case "additionalProperties": { + tempErrorStore = "ERROR_ADDITIONAL_PROPERTIES"; + hasDataErrors = "true"; + break; + } + case "type": + { + const instancePathType = validateExcel.errors[i].instancePath.split("/"); + const neededType = validateExcel.errors[i].params?.type; + instancePathTypeGlobal = instancePathType; + tempErrorStore = locationDataColumns.includes(instancePathType[instancePathType.length - 1]) + ? "ERROR_INCORRECT_LOCATION_COORDINATES" + : neededType === "number" + ? "ERROR_MUST_BE_A_NUMBER" + : "ERROR_MUST_BE_A_STRING"; + hasDataErrors = "true"; + } + break; + case "required": { + const missing = validateExcel.errors[i].params.missingProperty; + const instancePathType = validateExcel.errors[i].instancePath.split("/"); + instancePathTypeGlobal = [...instancePathType, missing]; + tempErrorStore = "ERROR_MANDATORY_FIELDS_CANT_BE_EMPTY"; + missingColumnsList.add(missing); + // hasDataErrors = "missing_properties"; + hasDataErrors = "true"; + break; + } + case "maximum": + case "minimum": { + const instancePathMinMax = validateExcel.errors[i].instancePath.split("/"); + instancePathTypeGlobal = instancePathMinMax; + tempErrorStore = locationDataColumns.includes(instancePathMinMax[instancePathTypeGlobal.length - 1]) + ? "ERROR_INCORRECT_LOCATION_COORDINATES" + : "ERROR_DATA_EXCEEDS_LIMIT_CONSTRAINTS"; + hasDataErrors = "true"; + break; + } + case "pattern": { + tempErrorStore = "ERROR_VALUE_NOT_ALLOWED"; + hasDataErrors = "true"; + break; + } + case "minProperties": { + hasDataErrors = "minProperties"; + break; + } + case "enum": { + const instancePathType = validateExcel.errors[i].instancePath.split("/"); + instancePathTypeGlobal = instancePathType; + tempErrorStore = { + error: "ERROR_UPLOAD_DATA_ENUM", + values: { allowedValues: validateExcel.errors[i]?.params?.allowedValues?.map((item) => t(item)).join(", ") }, + }; + hasDataErrors = "true"; + break; + } + default: { + hasDataErrors = "unknown"; + } + } + if (tempErrorStore && instancePathTypeGlobal) + errors[instancePathTypeGlobal[1]] = { + ...(errors[instancePathTypeGlobal[1]] ? errors[instancePathTypeGlobal[1]] : {}), + [instancePathTypeGlobal[2]]: { + ...(errors?.[instancePathTypeGlobal[1]]?.[instancePathTypeGlobal[2]] + ? errors?.[instancePathTypeGlobal[1]]?.[instancePathTypeGlobal[2]] + : {}), + [instancePathTypeGlobal[3]]: [ + ...new Set( + ...(errors?.[instancePathTypeGlobal[1]]?.[instancePathTypeGlobal[2]]?.[instancePathTypeGlobal[3]] + ? errors?.[instancePathTypeGlobal[1]]?.[instancePathTypeGlobal[2]]?.[instancePathTypeGlobal[3]] + : []) + ), + tempErrorStore, + ], + }, + }; + + switch (hasDataErrors) { + case "true": + errorMessages = { dataError: "ERROR_REFER_UPLOAD_PREVIEW_TO_SEE_THE_ERRORS" }; + break; + case "minProperties": + errorMessages = { minProperties: "ERROR_UPLOADED_DATA_IS_EMPTY" }; + break; + case "unknown": + errorMessages = { unkown: "ERROR_UNKNOWN" }; + break; + case "false": + break; + } + } + + ajv.removeSchema(); + + return { + valid: !hasDataErrors, + message: errorMessages ? [...new Set(Object.values(errorMessages))] : [], + errors, + validationError: validateExcel.errors, + missingColumnsList, + }; + } + ajv.removeSchema(); + return { valid }; +}; + +export const checkForErrorInUploadedFileExcel = async (fileInJson, schemaData, t) => { + try { + const valid = excelValidations(fileInJson, schemaData, t); + if (valid.valid) { + return { valid: true }; + } else { + return { + valid: false, + message: valid.message, + errors: valid.errors, + missingProperties: valid.missingColumnsList, + }; + } + } catch (error) { + console.error("Error in excel validations: ", error?.message); + return { valid: false, message: ["ERROR_PARSING_FILE"] }; + } +}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js new file mode 100644 index 00000000000..130043f2d45 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js @@ -0,0 +1,97 @@ +import ExcelJS from "exceljs"; + +// input is a xlsx blob +// options {header} +// header: true -> have seperate header so data will be in key: value pair +export const parseXlsxToJsonMultipleSheets = async (file, options = {}) => { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + + reader.onload = async (event) => { + try { + const arrayBuffer = event.target.result; + const workbook = new ExcelJS.Workbook(); + await workbook.xlsx.load(arrayBuffer); + + const jsonData = {}; + workbook.eachSheet((worksheet, sheetId) => { + const jsonSheetData = []; + let headers = []; + + worksheet.eachRow({ includeEmpty: true }, (row, rowNumber) => { + const rowData = row.values.slice(1); // Remove the first element (it's always undefined due to ExcelJS indexing from 1) + for (let i = 0; i < rowData.length; i++) { + if (typeof rowData[i] === "string") { + rowData[i] = rowData[i].trim(); + } + } + + if (options.header && rowNumber === 1) { + headers = rowData; + } else if (options.header && headers.length > 0) { + const rowObject = {}; + headers.forEach((header, index) => { + rowObject[header] = rowData[index]; + }); + jsonSheetData.push(rowObject); + } else { + jsonSheetData.push(rowData); + } + }); + + if (jsonSheetData.length !== 0 && jsonSheetData?.[0].length !== 0) jsonData[worksheet.name] = jsonSheetData; + }); + resolve(jsonData); + } catch (error) { + console.error(error); + resolve({ error: true }); + } + }; + + reader.onerror = (error) => { + console.error(error); + resolve({ error: true, details: error }); + }; + + reader.readAsArrayBuffer(file); + }); +}; + +// export const parseXlsxToJsonMultipleSheetsForSessionUtil = (file, options, fileData) => { +// return new Promise((resolve, reject) => { +// const reader = new FileReader(); + +// reader.onload = function (event) { +// try { +// const arrayBuffer = event.target.result; +// const workbook = XLSX.read(arrayBuffer, { type: "arraybuffer" }); +// const jsonData = {}; + +// workbook.SheetNames.forEach((sheetName) => { +// const worksheet = workbook.Sheets[sheetName]; +// // const options = { header: 1 }; +// const jsonSheetData = XLSX.utils.sheet_to_json(worksheet, options); +// for (let i = 0; i < jsonSheetData.length; i++) { +// for (let j = 0; j < jsonSheetData[i].length; j++) { +// const cell = jsonSheetData[i][j]; +// if (typeof cell === "string") { +// jsonSheetData[i][j] = cell.trim(); +// } +// } +// } +// if (jsonSheetData.length !== 0 && jsonSheetData?.[0].length !== 0) jsonData[sheetName] = jsonSheetData; +// }); + +// resolve({ jsonData, file: fileData }); +// } catch (error) { +// resolve({ error: true }); +// } +// }; + +// reader.onerror = function (error) { +// resolve({ error: true, details: error }); +// }; + +// reader.readAsArrayBuffer(file); +// }); +// }; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js new file mode 100644 index 00000000000..5e6b42ee060 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js @@ -0,0 +1,242 @@ +import gjv from "geojson-validation"; +import Ajv from "ajv"; +const ajv = new Ajv({ allErrors: true }); +ajv.addKeyword("isRequired"); +ajv.addKeyword("isLocationDataColumns"); +ajv.addKeyword("isRuleConfigureInputs"); +ajv.addKeyword("isFilterPropertyOfMapSection"); +ajv.addKeyword("isVisualizationPropertyOfMapSection"); +ajv.addKeyword("toShowInMicroplanPreview"); + +//the postion must be valid point on the earth, x between -180 and 180 +gjv.define("Position", (position) => { + let errors = []; + if (position[0] < -180 || position[0] > 180) { + errors.push("Location Coordinates Error: the x must be between -180 and 180"); + } + if (position[1] < -90 || position[1] > 90) { + errors.push("Location Coordinates Error: the y must be between -90 and 90"); + } + return errors; +}); + +// Main functino for geojson validation that includes structural and property validations +export const geojsonValidations = (data, schemaData, t) => { + let valid = geojsonStructureValidation(data); + if (valid.valid) { + return { valid: true }; + } + if (valid.message) { + return { valid: false, message: valid.message }; + } + return { valid: false, message: ["ERROR_INVALID_GEOJSON"] }; +}; + +// Funciton responsible for structural verification of geojson data +export const geojsonStructureValidation = (data) => { + let valid = true; + let trace = {}; + for (let i = 0; i < data["features"].length; i++) { + const check = gjv.valid(data["features"][i]); + valid = valid && check; + const errors = gjv.isFeature(data["features"][i], true); + // check if the location coordinates are according to the provided guidlines + if (errors.some((str) => str.includes("Location Coordinates Error:"))) return { valid: false, message: ["ERROR_INCORRECT_LOCATION_COORDINATES"] }; + if (!check) trace[i] = [errors]; + // let error; + // Object.keys(data["features"][i]["properties"]).forEach((j) => { + // if (j.length > 10) error = { valid: false, trace, message: ["ERROR_FIELD_NAME"] }; + // return j; + // }); + // if (error) return error; + } + return { valid, trace }; +}; + +const geometryValidation = (data) => { + let firstType; + for (const feature of data.features) { + if (!feature.geometry || !feature.geometry.type) { + return false; // Missing geometry or geometry type + } + if (!firstType) { + firstType = feature.geometry.type; + } else { + // Check if the current geometry type matches the first one + if (feature.geometry.type !== firstType) { + return false; // Different geometry types found + } + } + } + return true; +}; + +// Function responsible for property verification of geojson data +export const geojsonPropetiesValidation = (data, schemaData, name, t) => { + const translate = () => { + const required = Object.entries(schemaData?.Properties || {}) + .reduce((acc, [key, value]) => { + if (value?.isRequired) { + acc.push(key); + } + return acc; + }, []) + .map((item) => item); + + // const properties = prepareProperties(schemaData.Properties, t); + return { required, properties: schemaData.Properties }; + }; + const { required, properties } = translate(); + const schema = { + type: "object", + properties: { + type: { const: "FeatureCollection" }, + }, + patternProperties: { + "^features$": { + type: "array", + items: { + type: "object", + patternProperties: { + "^properties$": { + type: "object", + patternProperties: properties, + required: required, + additionalProperties: true, + }, + }, + }, + }, + }, + additionalProperties: true, + }; + const validateGeojson = ajv.compile(schema); + const valid = validateGeojson(data); + let errors = {}; + let hasDataErrors = "false"; // true, false, missing_properties, unknown + let missingColumnsList = new Set(); + let errorMessages = []; + if (!valid) { + for (let i = 0; i < validateGeojson.errors.length; i++) { + let tempErrorStore = ""; + let instancePathTypeGlobal = validateGeojson.errors[i].instancePath.split("/"); + switch (validateGeojson.errors[i].keyword) { + case "additionalProperties": { + tempErrorStore = "ERROR_ADDITIONAL_PROPERTIES"; + hasDataErrors = "true"; + break; + } + case "type": + { + const instancePathType = validateGeojson.errors[i].instancePath.split("/"); + const neededType = validateGeojson.errors[i].params?.type; + instancePathTypeGlobal = instancePathType; + tempErrorStore = neededType === "number" ? "ERROR_MUST_BE_A_NUMBER" : "ERROR_MUST_BE_A_STRING"; + hasDataErrors = "true"; + } + break; + case "const": { + if (validateGeojson.errors[i].params.allowedValue === "FeatureCollection") tempErrorStore = "ERROR_FEATURECOLLECTION"; + hasDataErrors = "true"; + break; + } + case "required": { + const missing = validateGeojson.errors[i].params.missingProperty; + const instancePathType = validateGeojson.errors[i].instancePath.split("/"); + instancePathTypeGlobal = [...instancePathType, missing]; + tempErrorStore = "ERROR_MANDATORY_FIELDS_CANT_BE_EMPTY"; + missingColumnsList.add(missing); + // hasDataErrors = "missing_properties"; + hasDataErrors = "true"; + break; + } + case "pattern": + tempErrorStore = "ERROR_VALUE_NOT_ALLOWED"; + hasDataErrors = "true"; + break; + case "minProperties": { + hasDataErrors = "minProperties"; + break; + } + case "enum": { + const instancePathType = validateGeojson.errors[i].instancePath.split("/"); + instancePathTypeGlobal = instancePathType; + tempErrorStore = { + error: "ERROR_UPLOAD_DATA_ENUM", + values: { allowedValues: validateGeojson.errors[i]?.params?.allowedValues?.map((item) => t(item)).join(", ") }, + }; + hasDataErrors = "true"; + break; + } + default: + hasDataErrors = "unknown"; + break; + } + if (tempErrorStore) + errors[name] = { + ...(errors[name] ? errors[name] : {}), + [instancePathTypeGlobal[2]]: { + ...(errors?.[name]?.[instancePathTypeGlobal[2]] ? errors?.[name]?.[instancePathTypeGlobal[2]] : {}), + [instancePathTypeGlobal[4]]: [ + ...new Set( + ...(errors?.[name]?.[instancePathTypeGlobal[2]]?.[instancePathTypeGlobal[4]] + ? errors?.[name]?.[instancePathTypeGlobal[2]]?.[instancePathTypeGlobal[4]] + : []) + ), + tempErrorStore, + ], + }, + }; + + switch (hasDataErrors) { + case "true": + errorMessages = { ...errorMessages, dataError: t("ERROR_REFER_UPLOAD_PREVIEW_TO_SEE_THE_ERRORS") }; + break; + case "unknown": + errorMessages = { ...errorMessages, unkown: t("ERROR_UNKNOWN") }; + break; + case "missing_properties": + errorMessages = { + ...errorMessages, + missingProperty: t("ERROR_MISSING_PROPERTY", { properties: [...missingColumnsList].map((item) => t(item)).join(", ") }), + }; + break; + case "false": + break; + } + } + + ajv.removeSchema(); + return { + valid: !hasDataErrors, + message: errorMessages ? [...new Set(Object.values(errorMessages))] : [], + errors, + validationError: validateGeojson.errors, + }; + } + ajv.removeSchema(); + if (!geometryValidation(data)) return { valid: false, message: t("ERROR_MULTIPLE_GEOMETRY_TYPES") }; + return { valid: true }; +}; + +//////////////////////////// +// // Might be needed +// function filterOutWordAndLocalise(inputString, operation) { +// // Define a regular expression to match the string parts +// var regex = /(\w+)/g; // Matches one or more word characters + +// // Replace each match using the provided function +// var replacedString = inputString.replace(regex, function (match) { +// // Apply the function to each matched string part +// return operation(match); +// }); + +// return replacedString; +// } +// const prepareProperties = (properties, t) => { +// let newProperties = {}; +// Object.keys(properties).forEach((item) => (newProperties[filterOutWordAndLocalise(item, t)] = properties[item])); +// return newProperties; +// }; + +//////////////////////////// diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js new file mode 100644 index 00000000000..3f3d1d95b40 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js @@ -0,0 +1,533 @@ +import _ from "lodash"; +import { findChildren, findParent } from "../utils/processHierarchyAndData"; +import { EXCEL, LOCALITY, commonColumn } from "../configs/constants"; + +const formatDates = (value, type) => { + if (type !== "EPOC" && (!value || Number.isNaN(Number(value)))) { + value = new Date(); + } + switch (type) { + case "date": + return new Date(value)?.toISOString?.()?.split?.("T")?.[0]; + case "datetime": + return new Date(value).toISOString(); + case "EPOC": + return String(new Date(value)?.getTime()); + } +}; + +// get schema for validation +const getSchema = (campaignType, type, section, schemas) => { + if (!campaignType || !type || !section || !schemas) return {}; + return schemas.find((schema) => { + if (!schema.campaignType) { + return schema.type === type && schema.section === section; + } + return schema.campaignType === campaignType && schema.type === type && schema.section === section; + }); +}; + +// Sorting 2 lists, The first list is a list of string and second one is list of Objects +const sortSecondListBasedOnFirstListOrder = (firstList, secondList) => { + if (!firstList) return []; + // Create a map to store the indices of elements in the first list + const indexMap = {}; + firstList.forEach((value, index) => { + indexMap[value] = index; + }); + + // Sort the second list based on the order of elements in the first list + secondList.sort((objecta, objectb) => { + // Get the mappedTo values of each object + const mappedToA = objecta.mappedTo; + const mappedToB = objectb.mappedTo; + + // Get the indices of mappedTo values in the first list + const indexA = indexMap[mappedToA]; + const indexB = indexMap[mappedToB]; + + // Compare the indices + return indexA - indexB; + }); + + return secondList; +}; + +const computeGeojsonWithMappedProperties = ({ campaignType, fileType, templateIdentifier, validationSchemas }) => { + const schemaData = getSchema(campaignType, fileType, templateIdentifier, validationSchemas); + let schemaKeys; + if (schemaData?.schema?.["Properties"]) schemaKeys = hierarchy.concat(Object.keys(schemaData.schema["Properties"])); + // Sorting the resourceMapping list inorder to maintain the column sequence + const sortedSecondList = sortSecondListBasedOnFirstListOrder(schemaKeys, resourceMapping); + // Creating a object with input data with MDMS keys + const newFeatures = fileData.data["features"].map((item) => { + let newProperties = {}; + + sortedSecondList.forEach((e) => { + newProperties[e["mappedTo"]] = item["properties"][e["mappedFrom"]]; + }); + item["properties"] = newProperties; + return item; + }); + let data = fileData.data; + data["features"] = newFeatures; + return data; +}; + +const destroySessionHelper = (currentPath, pathList, sessionName) => { + if (!pathList.includes(currentPath)) { + sessionStorage.removeItem(`Digit.${sessionName}`); + } +}; + +const convertGeojsonToExcelSingleSheet = (InputData, fileName) => { + if (!InputData || !Array.isArray(InputData) || InputData.length === 0) { + return null; + } + + // Extract keys from the first feature's properties + const keys = Object.keys(InputData?.[0]?.properties); + + if (!keys || keys.length === 0) { + return null; + } + + // Extract corresponding values for each feature + const values = InputData?.map((feature) => { + return keys.map((key) => feature.properties[key]); + }); + + // Group keys and values into the desired format + return { [fileName]: [keys, ...values] }; +}; + +const areObjectsEqual = (obj1, obj2) => { + return obj1.name === obj2.name && obj1.code === obj2.code; +}; + +const computeDifferences = (data1, data2) => { + const removed = {}; + const added = {}; + + for (const key in data1) { + if (Object.hasOwn(data2, key)) { + removed[key] = data1[key].filter((item1) => !data2[key].some((item2) => areObjectsEqual(item1, item2))); + added[key] = data2[key].filter((item2) => !data1[key].some((item1) => areObjectsEqual(item1, item2))); + } else { + removed[key] = data1[key]; + added[key] = []; + } + } + + for (const key in data2) { + if (!data1.hasOwnProperty(key)) { + added[key] = data2[key]; + removed[key] = []; + } + } + + return { removed, added }; +}; + +const extractNames = (data) => { + let names = []; + + for (let key in data) { + if (Array.isArray(data[key])) { + data[key].forEach((item) => { + if (item.name) { + names.push(item.name); + } + }); + } + } + + return names; +}; +// function that handles dropdown selection. used in: mapping and microplan preview +const handleSelection = (e, boundaryType, boundarySelections, hierarchy, setBoundarySelections, boundaryData, setIsLoading) => { + setIsLoading(true); + if (!e || !boundaryType) return; + let selections = e.map((item) => item?.[1]); + let newComputedSelection = { ...boundarySelections, [boundaryType]: selections }; + const { removed, added } = computeDifferences(boundarySelections, newComputedSelection); + // for(const item in removed){ + if (removed && Object.keys(removed).length !== 0 && Object.values(removed)?.flatMap((item) => item).length !== 0) { + let filteredRemoved = extractNames(removed); + let children = Object.values(findChildren(filteredRemoved, Object.values(boundaryData)?.[0]?.hierarchicalData))?.map((item) => item?.name); + for (const key in newComputedSelection) { + newComputedSelection[key] = newComputedSelection[key].filter((item) => !children.includes(item?.name)); + } + } + setBoundarySelections(newComputedSelection); +}; + +// Preventing default action when we scroll on input[number] is that it increments or decrements the number +const inputScrollPrevention = (e) => { + e.target.addEventListener( + "wheel", + function (e) { + e.preventDefault(); + }, + { passive: false } + ); +}; + +// Construct api request body +const mapDataForApi = (data, Operators, microplanName, campaignId, status, reqType = "update") => { + let files = [], + resourceMapping = []; + if (data && data.upload) { + Object.values(data?.upload).forEach((item) => { + if (!item || item.error || !item.filestoreId) return; + if (reqType === "create" && !item?.active) return; + const data = { + active: item?.active, + filestoreId: item?.filestoreId, + inputFileType: item?.fileType, + templateIdentifier: item?.section, + id: item?.fileId, + }; + files.push(data); + }); + Object.values(data?.upload).forEach((item) => { + if (reqType === "create" && item.resourceMapping && item.resourceMapping.every((item) => item.active === false)) return; + if ( + !item || + !item.resourceMapping || + item.error || + !Array.isArray(item.resourceMapping) || + !item.resourceMapping.every((item) => item.mappedFrom) || + !item.resourceMapping.every((item) => item.mappedTo) + ) + return; + resourceMapping.push(item?.resourceMapping); + }); + resourceMapping = resourceMapping.flatMap((inner) => inner); + } + + // return a Create API body + return { + PlanConfiguration: { + status, + tenantId: Digit.ULBService.getStateId(), + name: microplanName, + executionPlanId: campaignId, + files, + assumptions: data?.hypothesis?.reduce((acc, item) => { + if (reqType === "create" && !item?.active) return acc; + if (item.key && item.value) { + acc.push(JSON.parse(JSON.stringify(item))); + } + return acc; + }, []), + operations: data?.ruleEngine?.reduce((acc, item) => { + if (reqType === "create" && !item?.active) return acc; + if (!item.active && !item.input) { + const data = { ...item }; + const operator = Operators.find((e) => e.name === data.operator); + if (operator && operator.code) data.operator = operator?.code; + if (data?.oldInput) data.input = data.oldInput; + acc.push(data); + return acc; + } + if (!item.active && !item.operator && !item.output && !item.input && !item.assumptionValue) return acc; + const data = { ...item }; + const operator = Operators.find((e) => e.name === data.operator); + if (operator && operator.code) data.operator = operator?.code; + acc.push(data); + // } + return acc; + }, []), + resourceMapping, + }, + }; +}; + +const resourceMappingAndDataFilteringForExcelFiles = (schemaData, hierarchy, selectedFileType, fileDataToStore, t, translatedData = true) => { + let resourceMappingData = []; + let newFileData = {}; + let toAddInResourceMapping; + + if (selectedFileType.id === EXCEL && fileDataToStore) { + // Extract all unique column names from the first row of each sheet in fileDataToStore for resource mapping + const columnForMapping = new Set(Object.values(fileDataToStore).flatMap((value) => value?.[0] || [])); + + if (schemaData?.schema?.["Properties"]) { + let toChange; + if (LOCALITY && hierarchy[hierarchy?.length - 1] !== LOCALITY) { + toChange = hierarchy[hierarchy?.length - 1]; + } + + // Get schema keys and hierarchy to map columns + const schemaKeys = Object.keys(schemaData.schema["Properties"]).concat(hierarchy); + + schemaKeys.forEach((item) => { + // Check if the column is present in the file, either in translated form or original form based on translatedData flag + if ((translatedData && columnForMapping.has(t(item))) || (!translatedData && columnForMapping.has(item))) { + // Special case for LOCALITY + if (LOCALITY && toChange === item) { + toAddInResourceMapping = { + mappedFrom: t(item), + mappedTo: LOCALITY, + }; + } + // Add the mapping information + resourceMappingData.push({ + mappedFrom: t(item), + mappedTo: item, + }); + } + }); + } + + // Filter and map the columns of fileDataToStore based on resource mapping + Object.entries(fileDataToStore).forEach(([key, value]) => { + let data = []; + let headers = []; + let toRemove = []; + + if (value && value.length > 0) { + // Process header row + value[0].forEach((item, index) => { + // Find the corresponding mapped column name + const mappedTo = resourceMappingData.find((e) => (translatedData && e.mappedFrom === item) || (!translatedData && e.mappedFrom === t(item))) + ?.mappedTo; + if (!mappedTo) { + toRemove.push(index); // Mark column for removal if not mapped + return; + } + headers.push(mappedTo); // Add mapped column name to headers + }); + + // Process data rows + for (let i = 1; i < value?.length; i++) { + let temp = []; + for (let j = 0; j < value[i].length; j++) { + if (!toRemove.includes(j)) { + temp.push(value[i][j]); // Keep only the columns that are mapped + } + } + data.push(temp); + } + } + + // Combine headers and data for each sheet + newFileData[key] = [headers, ...data]; + }); + } + + // Finalize the resource mapping data + resourceMappingData.pop(); + resourceMappingData.push(toAddInResourceMapping); + + return { tempResourceMappingData: resourceMappingData, tempFileDataToStore: newFileData }; +}; + +const addResourcesToFilteredDataToShow = (previewData, resources, hypothesisAssumptionsList, formulaConfiguration, userEditedResources, t) => { + // Clone the preview data to avoid mutating the original data + const data = _.cloneDeep(previewData); + + // Helper function to check for user-edited data + const checkUserEditedData = (commonColumnData, resourceName) => { + if (userEditedResources && userEditedResources[commonColumnData]) { + return userEditedResources[commonColumnData][resourceName]; + } + }; + + // Ensure the previewData has at least one row and the first row is an array + if (!Array.isArray(data) || !Array.isArray(data[0])) { + return []; + } + + // Identify the index of the common column + const conmmonColumnIndex = data[0].indexOf(commonColumn); + if (conmmonColumnIndex === -1) { + return []; + } + + // Ensure resources is a valid array + if (!Array.isArray(resources)) { + return data; + } + + // Process each row of the data + const combinedData = data.map((item, index) => { + if (!Array.isArray(item)) { + return item; + } + + if (index === 0) { + // Add resource names to the header row + resources.forEach((e) => item.push(e)); + return item; + } + + // Process each resource for the current row + resources.forEach((resourceName, resourceIndex) => { + let savedData = checkUserEditedData(item[conmmonColumnIndex], resourceName); + if (savedData !== undefined) { + item.push(savedData); + } else { + let calculations = calculateResource(resourceName, item, formulaConfiguration, previewData[0], hypothesisAssumptionsList, t); + if (calculations !== null) calculations = Math.round(calculations); + item.push(calculations !== null && calculations !== undefined ? calculations : undefined); + } + }); + + return item; + }); + + return combinedData; +}; + +const calculateResource = (resourceName, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t) => { + let formula = formulaConfiguration?.find((item) => item?.active && item?.output === resourceName); + if (!formula) return null; + + // Finding Input + // check for Uploaded Data + let inputValue = findInputValue(formula, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t); + if (inputValue == undefined || inputValue === null) return null; + let assumptionValue = hypothesisAssumptionsList?.find((item) => item?.active && item?.key === formula?.assumptionValue)?.value; + if (assumptionValue == undefined) return null; + + return findResult(inputValue, assumptionValue, formula?.operator); +}; + +// function to find input value, it calls calculateResource fucntion recurcively until it get a proper value +const findInputValue = (formula, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t) => { + const inputIndex = headers?.indexOf(formula?.input); + if (inputIndex === -1 || !rowData[inputIndex]) { + // let tempFormula = formulaConfiguration.find((item) => item?.output === formula?.input); + return calculateResource(formula?.input, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t); + } else return rowData[inputIndex]; +}; + +const findResult = (inputValue, assumptionValue, operator) => { + switch (operator) { + case "DEVIDED_BY": + if (assumptionValue === 0) return; + return inputValue / assumptionValue; + case "MULTIPLIED_BY": + return inputValue * assumptionValue; + case "ADDITION": + return inputValue + assumptionValue; + case "SUBSTRACTION": + return inputValue - assumptionValue; + case "RAISE_TO": + return inputValue ** assumptionValue; + default: + return; + } +}; + +const fetchData = (state, campaignType) => { + let hypothesis = []; + let rulesOutputs = []; + let uploadList = []; + + hypothesis = state?.HypothesisAssumptions?.find((item) => item.campaignType === campaignType)?.assumptions; + rulesOutputs = state?.RuleConfigureOutput?.find((item) => item.campaignType === campaignType)?.data; + uploadList = state?.UploadConfiguration?.reduce((acc, item) => { + if (item.required) acc.push(item.id); + return acc; + }, []); + return { hypothesisList: hypothesis, rulesOutputs, uploadList }; +}; +const hypothesisCheck = (hypothesis, validList) => { + if (hypothesis && Array.isArray(hypothesis) && hypothesis.length !== 0 && validList && Array.isArray(validList) && validList.length !== 0) { + return hypothesis.filter((item) => item.active).every((item) => validList.includes(item.key)); + } + return false; +}; +const ruleOutputCheck = (rules, ruleOuputList) => { + if ( + rules && + Array.isArray(rules) && + rules.filter((item) => item.active).length !== 0 && + ruleOuputList && + Array.isArray(ruleOuputList) && + ruleOuputList.length !== 0 + ) { + return rules.filter((item) => item.active).every((item) => ruleOuputList.includes(item.output)); + } + return false; +}; +const emptyRuleCheck = (rules) => { + return !rules || rules.filter((item) => item.active && Object.values(item)?.filter((e) => e === "").length !== 0).length === 0; +}; +const ruleHypothesisCheck = (rules, ruleHypothesis) => { + if (rules && Array.isArray(rules) && rules.length !== 0 && ruleHypothesis && Array.isArray(ruleHypothesis) && ruleHypothesis.length !== 0) { + return rules.filter((item) => item.active).every((item) => ruleHypothesis.includes(item.assumptionValue)); + } + return false; +}; +const uploadCheck = (uploads, uploadList) => { + if (uploads && Array.isArray(uploads) && uploads.length !== 0 && uploadList && Array.isArray(uploadList) && uploadList.length !== 0) { + return uploads.some((item) => uploadList.includes(item.templateIdentifier) && item.active); + } + return false; +}; +const planConfigRequestBodyValidator = (data, state, campaignType) => { + if (!data || !campaignType || !state) return false; + + const { hypothesisList, rulesOutputs, uploadList } = fetchData(state, campaignType); + let checks = + // microplan name check + (!data || !data.name) && + hypothesisCheck(data?.PlanConfiguration?.assumptions, hypothesisList) && + emptyRuleCheck(data?.PlanConfiguration?.operations) && + ruleOutputCheck(data?.PlanConfiguration?.operations, rulesOutputs) && + ruleHypothesisCheck( + data?.PlanConfiguration?.operations, + data?.PlanConfiguration?.assumptions?.filter((item) => item.active)?.map((item) => item.key) + ) && + uploadCheck(data?.PlanConfiguration?.files, uploadList); + return checks; + // if() +}; + +const processDropdownForNestedMultiSelect = (dropDownOptions) => { + if (!dropDownOptions) return dropDownOptions; + const result = dropDownOptions.reduce((acc, item) => { + const { parent, ...rest } = item; + + // Find the group by parentBoundaryType + let group = acc.find((g) => g.name === parent?.name); + + // If not found, create a new group + if (!group) { + group = { name: parent?.name, options: [] }; + acc.push(group); + } + + // Add the item to the options of the found/created group + group.options.push(rest); + + return acc; + }, []); + return result; +}; + +const transformIntoLocalisationCode = (code) => { + return code?.toUpperCase(); +}; + +export default { + formatDates, + computeGeojsonWithMappedProperties, + destroySessionHelper, + mapDataForApi, + inputScrollPrevention, + handleSelection, + convertGeojsonToExcelSingleSheet, + resourceMappingAndDataFilteringForExcelFiles, + sortSecondListBasedOnFirstListOrder, + addResourcesToFilteredDataToShow, + calculateResource, + planConfigRequestBodyValidator, + getSchema, + processDropdownForNestedMultiSelect, + transformIntoLocalisationCode, +}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js new file mode 100644 index 00000000000..2e1796f781a --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js @@ -0,0 +1,44 @@ +import ExcelJS from "exceljs"; + +export const convertJsonToXlsx = async (jsonData, columnWithStyle) => { + // Create a new workbook + const workbook = new ExcelJS.Workbook(); + + // Iterate over each sheet in jsonData + for (const [sheetName, data] of Object.entries(jsonData)) { + // Create a new worksheet + const worksheet = workbook.addWorksheet(sheetName); + + // Convert data to worksheet + for (const row of data) { + const newRow = worksheet.addRow(row); + // Apply red font color to the errorColumn if it exists + let errorColumnIndex = data[0].indexOf(columnWithStyle?.errorColumn); + if (columnWithStyle?.errorColumn && errorColumnIndex !== -1) { + const columnIndex = errorColumnIndex + 1; + if (columnIndex > 0) { + const newCell = newRow.getCell(columnIndex); + if (columnWithStyle.style && newCell) for (const key in columnWithStyle.style) newCell[key] = columnWithStyle.style[key]; + } + } + } + + // Make the first row bold + if (worksheet.getRow(1)) { + worksheet.getRow(1).font = { bold: true }; + } + + // Set column widths + const columnCount = data?.[0]?.length || 0; + const wscols = Array(columnCount).fill({ width: 30 }); + wscols.forEach((col, colIndex) => { + worksheet.getColumn(colIndex + 1).width = col.width; + }); + } + + // Write the workbook to a buffer + return await workbook.xlsx.writeBuffer({ compression: true }).then((buffer) => { + // Create a Blob from the buffer + return new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); + }); +}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js new file mode 100644 index 00000000000..f5508322f31 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js @@ -0,0 +1,339 @@ +export const processHierarchyAndData = (hierarchy, allData) => { + const hierarchyLists = {}; + let hierarchicalData = {}; + try { + // Process hierarchy + hierarchy.forEach((item) => { + hierarchyLists[item.boundaryType] = []; + }); + + // Process all sets of data + allData.forEach((data) => { + const dataHierarchicalData = {}; + + // Process data for this set + data.slice(1).forEach((row) => { + // Exclude the header row + let currentNode = dataHierarchicalData; + let parent = null; + hierarchy.forEach((item, index) => { + const boundaryType = item.boundaryType; + const dataIndex = data?.[0].indexOf(boundaryType); + if (dataIndex === -1) return; + const cellValue = row[dataIndex]; + if (!cellValue) return; + // Populate hierarchy lists + if (!hierarchyLists[boundaryType].includes(cellValue) && cellValue !== null && cellValue !== "" && cellValue !== undefined) { + hierarchyLists[boundaryType].push(cellValue); + } + + // Populate hierarchical data + if (!currentNode[cellValue]) { + currentNode[cellValue] = { + name: cellValue, + boundaryType: boundaryType, + children: {}, + data: null, + }; + } + + // Assign row data to the correct hierarchical level + if (cellValue) { + if (index === hierarchy.length - 1) { + currentNode[cellValue].data = createDataObject(data[0], row); + } else if (index + 1 < hierarchy.length) { + let nextHierarchyList = hierarchy.slice(index + 1); + let check = true; + nextHierarchyList.forEach((e) => { + const boundaryType = e.boundaryType; + const dataIndex = data?.[0].indexOf(boundaryType); + if (dataIndex === -1) return; + check = check && !row[dataIndex]; + }); + if (check) currentNode[cellValue].data = createDataObject(data[0], row); + } + } + currentNode = currentNode[cellValue].children; + }); + }); + + // Merge dataHierarchicalData into hierarchicalData + hierarchicalData = mergeHierarchicalData(hierarchicalData, dataHierarchicalData); + }); + + // Remove null element from children of each province + Object.values(hierarchicalData).forEach((country) => { + if (country.children[null]) { + country.data = country.children[null].data; + delete country.children[null]; + } + }); + } catch (error) { + console.error("Error in processing hierarchy and uploaded data: ", error.message); + // Return empty objects in case of error + return { hierarchyLists: {}, hierarchicalData: {} }; + } + + return { hierarchyLists, hierarchicalData }; +}; + +// Function to merge two hierarchical data objects +const mergeHierarchicalData = (data1, data2) => { + for (const [key, value] of Object.entries(data2)) { + if (!data1[key]) { + if (!value.data) value.data = {}; + data1[key] = value || {}; + } else { + data1[key].data = value.data; // Merge data + mergeHierarchicalData(data1[key].children, value.children); // Recursively merge children + } + if (data1[key].data?.feature) { + const { feature, ...temp } = value.data ? _.cloneDeep(value.data) : {}; + data1[key].data.feature.properties = { ...data1[key].data?.feature?.properties, ...temp }; + } + } + return data1; +}; + +// Function to create a data object with key-value pairs from headers and row data +const createDataObject = (headers, row) => { + const dataObject = {}; + headers.forEach((header, index) => { + dataObject[header] = row[index]; + }); + return dataObject; +}; + +// Find parent in hierarchy +export const findParent = (name, hierarchy, parent, accumulator = []) => { + if (!name || !hierarchy) return null; + for (let key in hierarchy) { + if (hierarchy[key]?.name == name) { + accumulator.push(parent); + } + if (hierarchy[key]?.children) { + let response = findParent(name, hierarchy[key]?.children, hierarchy[key], accumulator); + if (response) + response.forEach((item) => { + if (!accumulator.includes(item)) { + accumulator.push(item); + } + }); + } else { + return accumulator; + } + } + return accumulator; +}; + +/** + * + * @param {Array of parents} parents + * @param {hierarchycal Object data} hierarchy + * @returns An Array containing all the cummulative children + */ +export const findChildren = (parents, hierarchy) => { + const hierarchyTraveller = (parents, hierarchy, accumulator = {}) => { + let tempData = []; + if (accumulator && Object.keys(accumulator).length !== 0) + tempData = { + ...accumulator, + ...hierarchy.reduce((data, item) => { + if (parents.includes(item?.name) && item?.children) data = { ...data, ...item?.children }; + return data; + }, {}), + }; + else + tempData = hierarchy.reduce((data, item) => { + if (parents.includes(item?.name) && item?.children) data = { ...data, ...item?.children }; + return data; + }, {}); + for (let parent of hierarchy) { + if (parent?.children) tempData = hierarchyTraveller(parents, Object.values(parent?.children), tempData); + } + return tempData; + }; + return hierarchyTraveller(parents, Object.values(hierarchy), {}); +}; + +// Fetched data from tree +export const fetchDropdownValues = (boundaryData, hierarchy, boundarySelections, changedBoundaryType) => { + if ( + !hierarchy || + !boundaryData || + !boundarySelections || + hierarchy.length === 0 || + Object.keys(hierarchy).length === 0 || + Object.keys(boundaryData).length === 0 + ) + return []; + let TempHierarchy = _.cloneDeep(hierarchy); + if (!boundarySelections || Object.values(boundarySelections)?.every((item) => item?.length === 0)) { + for (let i in TempHierarchy) { + if (i === "0") { + TempHierarchy[0].dropDownOptions = findByBoundaryType( + TempHierarchy?.[0]?.boundaryType, + Object.values(boundaryData)?.[0]?.hierarchicalData + ).map((data, index) => ({ + name: data, + code: data, + boundaryType: TempHierarchy?.[0]?.boundaryType, + parentBoundaryType: undefined, + })); + } else TempHierarchy[i].dropDownOptions = []; + } + } else { + const currentHierarchy = findCurrentFilteredHierarchy(Object.values(boundaryData)?.[0]?.hierarchicalData, boundarySelections, TempHierarchy); + let currentDropdownIndex = 0; + hierarchy.forEach((e, index) => { + if (e && e?.boundaryType == changedBoundaryType) { + // && boundarySelections && boundarySelections[e.boundaryType] && boundarySelections[e.boundaryType].length !== 0) { + currentDropdownIndex = index; + } + }); + Object.entries(boundarySelections)?.forEach(([key, value]) => { + let currentindex = hierarchy.findIndex((e) => e?.boundaryType === key); + if (currentDropdownIndex !== currentindex) return; + let childIndex = hierarchy.findIndex((e) => e?.parentBoundaryType === key); + if (childIndex == -1) return; + if (TempHierarchy?.[childIndex]) { + let newDropDownValuesForChild = []; + for (const element of value) { + let tempStore = Object.values(findChildren([element.name], currentHierarchy)).map((value) => ({ + name: value?.name, + code: value?.name, + parent: element, + boundaryType: TempHierarchy[childIndex]?.boundaryType, + parentBoundaryType: TempHierarchy[childIndex]?.parentBoundaryType, + })); + if (tempStore) newDropDownValuesForChild.push(...tempStore); + } + // if (TempHierarchy[childIndex].dropDownOptions) + // TempHierarchy[childIndex].dropDownOptions = [...TempHierarchy[childIndex].dropDownOptions, ...newDropDownValuesForChild]; + TempHierarchy[childIndex].dropDownOptions = newDropDownValuesForChild; + } + }); + } + return TempHierarchy; +}; + +const findByBoundaryType = (boundaryType, hierarchy) => { + for (let [key, value] of Object.entries(hierarchy)) { + if (value?.boundaryType === boundaryType) return Object.keys(hierarchy).filter(Boolean); + else if (value?.children) return findByBoundaryType(boundaryType, value?.children); + else return []; + } + return []; +}; + +// makes a tree with the boundary selections as there might be duplicates in different branches that are not yet selected +const findCurrentFilteredHierarchy = (hierarchyTree, boundarySelections, hierarchy) => { + const newtree = constructNewHierarchyTree(hierarchy, hierarchyTree, boundarySelections); + return newtree; +}; + +const constructNewHierarchyTree = (hierarchy, oldTree, boundarySelection, level = 0) => { + // let newTree = { ...oldTree }; // Initialize a new hierarchy tree + let newTree = {}; // Initialize a new hierarchy tree + if (!hierarchy?.[level]) return; + const levelName = hierarchy[level].boundaryType; + + // Get the selections for this level from the boundary selection object + const selections = boundarySelection[levelName] || []; + // If there are selections for this level + if (selections.length > 0) { + // Construct the new hierarchy tree based on selections + for (const selection of selections) { + const { name } = selection; + // If the selection exists in the existing hierarchy tree + if (oldTree[name]) { + // Add the selected division to the new hierarchy tree + newTree[name] = { ...oldTree[name] }; + // If there are children, recursively construct the children + if (oldTree[name].children) { + oldTree[name].children; + const nonNullObject = Object.entries(oldTree[name].children).reduce((acc, [key, value]) => { + if (value.name !== null) { + acc[key] = value; + } + return acc; + }, {}); + newTree[name].children = constructNewHierarchyTree(hierarchy, nonNullObject, boundarySelection, level + 1); + } + } + } + } else { + const nonNullObject = Object.entries(oldTree).reduce((acc, [key, value]) => { + if (value.name !== null) { + acc[key] = value; + } + return acc; + }, {}); + newTree = nonNullObject; + } + + return newTree; +}; + +// Recursively calculates aggregate values for numerical properties within the `data` objects of each node in a hierarchical tree structure. +// Updates the `properties` object within the `feature` object of each node with the aggregate values, if present. +export const calculateAggregateForTree = (tree) => { + try { + function calculateAggregate(node) { + if (!node.children || Object.keys(node.children).length === 0) { + // if the node has no children, return a new node with its own data + return { ...node, data: { ...node.data } }; + } + + // Recursively calculate aggregate values for each child + const newChildren = {}; + + for (const childKey in node.children) { + const child = node.children[childKey]; + const newChild = calculateAggregate(child); + newChildren[childKey] = newChild; + } + + // Aggregate numerical values dynamically + const aggregate = {}; + for (const childKey in newChildren) { + const child = newChildren[childKey]; + for (const prop in child.data) { + if (typeof child.data[prop] === "number") { + aggregate[prop] = (aggregate[prop] || 0) + child.data[prop]; + } + } + } + + // Create a new node with updated data + const newNode = { + ...node, + data: { ...node.data, ...aggregate }, + children: newChildren, + }; + + // Update properties in the feature object + if (newNode.data.feature) { + newNode.data.feature.properties = { ...newNode.data.feature.properties, ...aggregate }; + } + + return newNode; + } + + const newTree = {}; + + // Iterate over each node object + for (const nodeKey in tree) { + const node = tree[nodeKey]; + // Calculate aggregate values for the current node + const newNode = calculateAggregate(node); + // Add the updated node to the new tree + newTree[nodeKey] = newNode; + } + + return newTree; + } catch (error) { + console.error("Failed to calculate treenode aggregates"); + return {}; + } +}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js new file mode 100644 index 00000000000..003165d6ac0 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js @@ -0,0 +1,485 @@ +import { Request } from "@egovernments/digit-ui-libraries"; +import { parseXlsxToJsonMultipleSheetsForSessionUtil } from "../utils/exceltojson"; +import JSZip from "jszip"; +import * as XLSX from "xlsx"; +import axios from "axios"; +import shp from "shpjs"; +import { EXCEL, GEOJSON, SHAPEFILE, ACCEPT_HEADERS, LOCALITY, commonColumn } from "../configs/constants"; +import { handleExcelFile } from "../components/Upload"; +import { addBoundaryData, fetchBoundaryData, filterBoundaries } from "./createTemplate"; + +function handleExcelArrayBuffer(arrayBuffer, file) { + return new Promise((resolve, reject) => { + try { + // Read the response as an array buffer + // const arrayBuffer = response.arrayBuffer(); + + // Convert the array buffer to binary string + const data = new Uint8Array(arrayBuffer); + const binaryString = String.fromCharCode.apply(null, data); + + // Parse the binary string into a workbook + const workbook = XLSX.read(binaryString, { type: "binary" }); + + // Assuming there's only one sheet in the workbook + const sheetName = workbook.SheetNames[0]; + const sheet = workbook.Sheets[sheetName]; + + // Convert the sheet to JSON object + const jsonData = XLSX.utils.sheet_to_json(sheet); + + resolve(jsonData); + } catch (error) { + reject(error); + } + }); +} + +function shpToGeoJSON(shpBuffer, file) { + return new Promise((resolve, reject) => { + try { + shp(shpBuffer) + .then((geojson) => { + resolve({ jsonData: geojson, file }); + }) + .catch((error) => reject(error)); + } catch (error) { + reject(error); + } + }); +} + +function parseGeoJSONResponse(arrayBuffer, file) { + return new Promise((resolve, reject) => { + try { + const decoder = new TextDecoder("utf-8"); + const jsonString = decoder.decode(arrayBuffer); + const jsonData = JSON.parse(jsonString); + resolve({ jsonData, file }); + } catch (error) { + reject(error); + } + }); +} + +// Function to read blob data and parse it into JSON +function parseBlobToJSON(blob, file) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + + reader.onload = function (event) { + const data = new Uint8Array(event.target.result); + const workbook = XLSX.read(data, { type: "array" }); + const jsonData = {}; + + workbook.SheetNames.forEach((sheetName) => { + const sheetData = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName]); + jsonData[sheetName] = sheetData; + }); + + resolve({ jsonData, file }); + }; + + reader.onerror = function () { + reject(new Error("Error reading the blob data")); + }; + + reader.readAsArrayBuffer(blob); + }); +} + +export const updateSessionUtils = { + computeSessionObject: async (row, state, additionalProps) => { + const sessionObj = {}; + const setCurrentPage = () => { + sessionObj.currentPage = { + id: 0, + name: "MICROPLAN_DETAILS", + component: "MicroplanDetails", + checkForCompleteness: true, + }; + }; + + //currently hardcoded + const setMicroplanStatus = () => { + sessionObj.status = { + MICROPLAN_DETAILS: true, + UPLOAD_DATA: true, + HYPOTHESIS: true, + FORMULA_CONFIGURATION: true, + }; + }; + + const setMicroplanDetails = () => { + if (row.name) { + sessionObj.microplanDetails = { + name: row?.name, + }; + } + }; + + const setMicroplanHypothesis = () => { + if (row.assumptions.length > 0) { + sessionObj.hypothesis = row.assumptions?.filter((item) => item?.active); + } + }; + + const sortRules = (rules) => { + // Step 1: Identify all unique rule outputs + const allOutputs = [...new Set(rules.map((rule) => rule.output))]; + + // Step 2: Build input-output relationships + const inputOutputMap = new Map(); // Map to store input -> output relationship + rules.forEach((rule) => { + const { input, output } = rule; + if (!inputOutputMap.has(input)) { + inputOutputMap.set(input, []); + } + inputOutputMap.get(input).push(output); + }); + + // Step 3: Sort the output list based on dependencies + const sortedOutputList = []; + const visited = new Set(); + + const dfs = (output) => { + if (!visited.has(output)) { + visited.add(output); + if (inputOutputMap.has(output)) { + inputOutputMap.get(output).forEach((input) => { + dfs(input); + }); + } + sortedOutputList.push(output); + } + }; + + // Sort outputs based on dependencies + allOutputs.forEach((output) => { + dfs(output); + }); + + // Reverse to get outputs in the correct order (outputs first) + sortedOutputList.reverse(); + + // Step 4: Arrange rules based on sorted output list + const sortedRules = []; + const ruleMap = new Map(rules.map((rule) => [rule.id, rule])); + + sortedOutputList.forEach((output) => { + rules + .filter((rule) => rule.output === output) + .forEach((rule) => { + sortedRules.push(rule); + }); + }); + + return sortedRules; + }; + + const setMicroplanRuleEngine = () => { + const rulesList = state.UIConfiguration?.filter((item) => item.name === "ruleConfigure")?.[0]?.ruleConfigureOperators; + let sortedRules = sortRules(row.operations); + if (row.operations.length > 0) { + sessionObj.ruleEngine = sortedRules?.map((item) => { + return { + ...item, + operator: rulesList.filter((rule) => rule.code === item.operator)?.[0]?.name, + }; + }); + } + }; + + const setDraftValues = () => { + sessionObj.planConfigurationId = row?.id; + sessionObj.auditDetails = row.auditDetails; + }; + + const fetchBoundaryDataWrapper = async (schemaData) => { + let boundaryDataAgainstBoundaryCode = {}; + // if (!schemaData?.doHierarchyCheckInUploadedData) { + try { + const rootBoundary = additionalProps.campaignData?.boundaries?.filter((boundary) => boundary.isRoot); // Retrieve session storage data once and store it in a variable + const sessionData = Digit.SessionStorage.get("microplanHelperData") || {}; + let boundaryData = sessionData.filteredBoundaries; + let filteredBoundaries; + if (!boundaryData) { + // Only fetch boundary data if not present in session storage + boundaryData = await fetchBoundaryData( + await Digit.ULBService.getCurrentTenantId(), + additionalProps.campaignData?.hierarchyType, + rootBoundary?.[0]?.code + ); + filteredBoundaries = await filterBoundaries(boundaryData, additionalProps.campaignData?.boundaries); + + // Update the session storage with the new filtered boundaries + Digit.SessionStorage.set("microplanHelperData", { + ...sessionData, + filteredBoundaries: filteredBoundaries, + }); + } else { + filteredBoundaries = boundaryData; + } + const xlsxData = addBoundaryData([], filteredBoundaries, additionalProps.campaignData?.hierarchyType)?.[0]?.data; + xlsxData.forEach((item, i) => { + if (i === 0) return; + let boundaryCodeIndex = xlsxData?.[0]?.indexOf(commonColumn); + if (boundaryCodeIndex >= item.length) { + // If boundaryCodeIndex is out of bounds, return the item as is + boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item.slice().map(additionalProps.t); + } else { + // Otherwise, remove the element at boundaryCodeIndex + boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item + .slice(0, boundaryCodeIndex) + .concat(item.slice(boundaryCodeIndex + 1)) + .map(additionalProps.t); + } + }); + } catch (error) { + console.error(error?.message); + } + // } + return boundaryDataAgainstBoundaryCode; + }; + + const handleGeoJson = async (file, result, upload, translatedData, active, processedData, shapefileOrigin = false) => { + if (!file) { + console.error(`${shapefileOrigin ? "Shapefile" : "Geojson"} file is undefined`); + return upload; + } + + const { inputFileType, templateIdentifier, filestoreId, id: fileId } = file || {}; + let uploadObject = createUploadObject(templateIdentifier, inputFileType, fileId, filestoreId, shapefileOrigin ? ".zip" : ".geojson", active); + + const schema = findSchema(inputFileType, templateIdentifier, additionalProps?.campaignType); + if (!schema) { + console.error("Schema got undefined while handling geojson at handleGeoJson"); + return [...upload, uploadObject]; + } + + await handleGeoJsonSpecific(schema, uploadObject, templateIdentifier, result, translatedData, filestoreId, processedData); + upload.push(uploadObject); + return upload; + }; + + const handleExcel = (file, result, upload, translatedData, active) => { + if (!file) { + console.error("Excel file is undefined"); + return upload; + } + + const { inputFileType, templateIdentifier, filestoreId, id: fileId } = file || {}; + let uploadObject = createUploadObject(templateIdentifier, inputFileType, fileId, filestoreId, ".xlsx", active), + schema = findSchema(inputFileType, templateIdentifier, additionalProps.campaignType); + if (!schema) { + console.error("Schema got undefined while handling excel at handleExcel"); + return [...upload, uploadObject]; + } + + uploadObject.data = result; //resultAfterMapping?.tempFileDataToStore; + upload.push(uploadObject); + return upload; + }; + + const createUploadObject = (templateIdentifier, inputFileType, fileId, filestoreId, extension, active) => ({ + id: fileId, + templateIdentifier, + section: templateIdentifier, + fileName: `${templateIdentifier}${extension}`, + fileType: inputFileType, + file: null, + fileId: fileId, + filestoreId: filestoreId, + error: null, + resourceMapping: row?.resourceMapping?.filter((resourse) => resourse.filestoreId === filestoreId).map((item) => ({ ...item, filestoreId })), + data: {}, + active, + }); + + const findSchema = (inputFileType, templateIdentifier, campaignType) => { + return state?.Schemas?.find( + (schema) => + schema.type === inputFileType && schema.section === templateIdentifier && (!schema.campaignType || schema.campaignType === campaignType) + ); + }; + + const handleGeoJsonSpecific = async (schema, upload, templateIdentifier, result, translatedData, filestoreId, processedData) => { + let schemaKeys; + if (schema?.schema?.["Properties"]) { + schemaKeys = additionalProps.heirarchyData?.concat(Object.keys(schema.schema["Properties"])); + } + upload.data = result; + if (processedData) return; + const mappedToList = upload?.resourceMapping.map((item) => item.mappedTo); + let sortedSecondList = Digit.Utils.microplan.sortSecondListBasedOnFirstListOrder(schemaKeys, upload?.resourceMapping); + const newFeatures = result["features"].map((item) => { + let newProperties = {}; + sortedSecondList + ?.filter((resourse) => resourse.filestoreId === filestoreId) + .forEach((e) => { + newProperties[e["mappedTo"]] = item["properties"][e["mappedFrom"]]; + }); + item["properties"] = newProperties; + return item; + }); + upload.data.features = newFeatures; + if ( + additionalProps.heirarchyData?.every( + (item) => + !mappedToList.includes(`${additionalProps.campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item)}`) + ) + ) { + let boundaryDataAgainstBoundaryCode = await fetchBoundaryDataWrapper(schema); + upload.data.features.forEach((feature) => { + const boundaryCode = feature.properties.boundaryCode; + let additionalDetails = {}; + for (let i = 0; i < additionalProps.heirarchyData?.length; i++) { + if (boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] || boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] === "") { + additionalDetails[additionalProps.heirarchyData?.[i]] = boundaryDataAgainstBoundaryCode[boundaryCode][i]; + } else { + additionalDetails[additionalProps.heirarchyData?.[i]] = ""; + } + } + feature.properties = { ...additionalDetails, ...feature.properties }; + }); + } + }; + + const fetchFiles = async () => { + const files = row?.files; + if (!files || files.length === 0) { + return []; + } + + const promises = []; + let storedData = []; + for (const { filestoreId, inputFileType, templateIdentifier, id, active } of files) { + if (!active) continue; + const schemaData = findSchema(inputFileType, templateIdentifier, additionalProps?.campaignType); + if (!schemaData) { + console.error("Schema got undefined while handling geojson at handleGeoJson"); + return [...upload, uploadObject]; + } + const boundaryDataAgainstBoundaryCode = {}; + let fileData = { + filestoreId, + inputFileType, + templateIdentifier, + id, + }; + let dataInSsn = Digit.SessionStorage.get("microplanData")?.upload?.find((item) => item.active && item.id === id); + if (dataInSsn && dataInSsn.filestoreId === filestoreId) { + storedData.push({ file: fileData, jsonData: dataInSsn?.data, processedData: true, translatedData: false, active }); + } else { + const promiseToAttach = axios + .get("/filestore/v1/files/id", { + responseType: "arraybuffer", + headers: { + "Content-Type": "application/json", + Accept: ACCEPT_HEADERS[inputFileType], + "auth-token": Digit.UserService.getUser()?.["access_token"], + }, + params: { + tenantId: Digit.ULBService.getCurrentTenantId(), + fileStoreId: filestoreId, + }, + }) + .then(async (res) => { + if (inputFileType === EXCEL) { + try { + const file = new Blob([res.data], { type: ACCEPT_HEADERS[inputFileType] }); + const response = await handleExcelFile( + file, + schemaData, + additionalProps.heirarchyData.map( + (item) => `${additionalProps.campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item)}` + ), + { id: inputFileType }, + boundaryDataAgainstBoundaryCode, + () => {}, + additionalProps.t, + additionalProps.campaignData + ); + let fileData = { + filestoreId, + inputFileType, + templateIdentifier, + id, + }; + + return { jsonData: response.fileDataToStore, file: fileData, translatedData: true, active }; + } catch (error) { + console.error(error); + } + } else if (inputFileType === GEOJSON) { + let response = await parseGeoJSONResponse(res.data, { + filestoreId, + inputFileType, + templateIdentifier, + id, + }); + return { ...response, translatedData: true, active }; + } else if (inputFileType === SHAPEFILE) { + const geoJson = await shpToGeoJSON(res.data, { + filestoreId, + inputFileType, + templateIdentifier, + id, + }); + return { ...geoJson, translatedData: true, active }; + } + }); + promises.push(promiseToAttach); + } + } + + const resolvedPromises = await Promise.all(promises); + let result = storedData; + if (resolvedPromises) result = [...storedData, ...resolvedPromises]; + return result; + }; + const setMicroplanUpload = async (filesResponse) => { + //here based on files response set data in session + if (filesResponse.length === 0) { + return {}; + } + //populate this object based on the files and return + let upload = []; + + await filesResponse.forEach(async ({ jsonData, file, translatedData, active, processedData }, idx) => { + switch (file?.inputFileType) { + case "Shapefile": + upload = await handleGeoJson(file, jsonData, upload, translatedData, active, processedData, true); + break; + case "Excel": + upload = handleExcel(file, jsonData, upload, translatedData, active); + break; + case "GeoJSON": + upload = await handleGeoJson(file, jsonData, upload, translatedData, active, processedData); + break; + default: + break; + } + }); + //here basically parse the files data from filestore parse it and populate upload object based on file type -> excel,shape,geojson + return upload; + }; + + try { + setCurrentPage(); + setMicroplanStatus(); + setMicroplanDetails(); + setMicroplanHypothesis(); + setMicroplanRuleEngine(); + setDraftValues(); + // calling fucntion to cache filtered boundary data + await fetchBoundaryDataWrapper({}); + const filesResponse = await fetchFiles(); + const upload = await setMicroplanUpload(filesResponse); + sessionObj.upload = upload; + return sessionObj; + } catch (error) { + console.error(error.message); + } + }, +}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/publish-develop.sh b/frontend/microplan-ui/web/micro-ui-internals/publish-develop.sh new file mode 100644 index 00000000000..cd9a49b0b4f --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/publish-develop.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +BASEDIR="$(cd "$(dirname "$0")" && pwd)" + +msg() { + echo -e "\n\n\033[32;32m$1\033[0m" +} + + +# msg "Pre-building all packages" +# yarn build +# sleep 5 + +msg "Building and publishing css" +cd "$BASEDIR/packages/css" && rm -rf dist && yarn && npm publish --tag microplan-1.0 + + +# msg "Building and publishing libraries" +# cd "$BASEDIR/packages/modules/hcm-microplanning" && rm -rf dist && yarn&& npm publish --tag microplan-1.0 + diff --git a/frontend/microplan-ui/web/micro-ui-internals/publish.sh b/frontend/microplan-ui/web/micro-ui-internals/publish.sh new file mode 100644 index 00000000000..cd9a49b0b4f --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/publish.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +BASEDIR="$(cd "$(dirname "$0")" && pwd)" + +msg() { + echo -e "\n\n\033[32;32m$1\033[0m" +} + + +# msg "Pre-building all packages" +# yarn build +# sleep 5 + +msg "Building and publishing css" +cd "$BASEDIR/packages/css" && rm -rf dist && yarn && npm publish --tag microplan-1.0 + + +# msg "Building and publishing libraries" +# cd "$BASEDIR/packages/modules/hcm-microplanning" && rm -rf dist && yarn&& npm publish --tag microplan-1.0 + diff --git a/frontend/microplan-ui/web/micro-ui-internals/scripts/create.sh b/frontend/microplan-ui/web/micro-ui-internals/scripts/create.sh new file mode 100644 index 00000000000..9de72331774 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/scripts/create.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +./scripts/run.sh core utilities diff --git a/frontend/microplan-ui/web/micro-ui-internals/scripts/deploy.sh b/frontend/microplan-ui/web/micro-ui-internals/scripts/deploy.sh new file mode 100644 index 00000000000..5b0c7b831ed --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/scripts/deploy.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +curl -v -X POST https://builds.digit.org/job/builds/job/digit-ui/buildWithParameters \ + --user saurabh-egov:114cbf3df675835931688b2d3f0014a1f7 \ + --data-urlencode json='{"parameter": [{"name":"BRANCH", "value":"origin/'$1'"}]}' + +# curl https://builds.digit.org/job/builds/job/digit-ui/lastBuild/api/json | grep --color result\":null + diff --git a/frontend/microplan-ui/web/micro-ui-internals/scripts/jenkins.sh b/frontend/microplan-ui/web/micro-ui-internals/scripts/jenkins.sh new file mode 100644 index 00000000000..a1711fec55b --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/scripts/jenkins.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +./scripts/deploy.sh dev \ No newline at end of file diff --git a/frontend/microplan-ui/web/micro-ui-internals/scripts/run.sh b/frontend/microplan-ui/web/micro-ui-internals/scripts/run.sh new file mode 100644 index 00000000000..f00c59f13b8 --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/scripts/run.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +MODULES=( "components" "core" "libraries" "example" ) + +RUNARGS=() +BUILDARGS=() + +for var in "$@" +do + BUILDARGS=( ${BUILDARGS[@]} build:"$var" ) + RUNARGS=( ${RUNARGS[@]} dev:"$var" ) +done + +a=0 +while [ "$a" -lt 3 ] +do + BUILD[$a]=build:${MODULES[$a]} + a=` expr $a + 1 ` +done + +echo "BUILDING MODULES:-" ${BUILD[*]} ${BUILDARGS[*]} +yarn run-p ${BUILD[*]} ${BUILDARGS[*]} + +b=0 +while [ "$b" -lt 4 ] +do + RUN[$b]=dev:${MODULES[$b]} + b=` expr $b + 1 ` +done + +echo "SERVING MODULES:-" ${RUN[*]} ${RUNARGS[*]} +yarn run-p ${RUN[*]} ${RUNARGS[*]} \ No newline at end of file diff --git a/frontend/microplan-ui/web/micro-ui-internals/test.js b/frontend/microplan-ui/web/micro-ui-internals/test.js new file mode 100644 index 00000000000..60c958d0bac --- /dev/null +++ b/frontend/microplan-ui/web/micro-ui-internals/test.js @@ -0,0 +1,31 @@ +const middleWare_1 = (data, _break, _next) => { + data.a = "a"; + _next(data); +}; + + +const middleWare_2 = (data, _break, _next) => { + data.b = "b"; + // _break(); + _next(data); +}; + +const middleWare_3 = (data, _break, _next) => { + data.c = "c"; + _next(data); +}; + +let middleWares = [middleWare_1, middleWare_2, middleWare_3]; + +const callMiddlewares = () => { + let applyBreak = false; + let itr = -1; + let _break = () => (applyBreak = true); + let _next = (data) => { + if (!applyBreak && ++itr < middleWares.length) middleWares[itr](data, _break, _next); + else return; + }; + _next({}); +}; + +callMiddlewares(); diff --git a/frontend/microplan-ui/web/microplan/App.js b/frontend/microplan-ui/web/microplan/App.js new file mode 100644 index 00000000000..afcd26669c6 --- /dev/null +++ b/frontend/microplan-ui/web/microplan/App.js @@ -0,0 +1,61 @@ +import React from "react"; +import { initLibraries } from "@egovernments/digit-ui-libraries"; + +import { DigitUI } from "@egovernments/digit-ui-module-core"; + +import { UICustomizations } from "./Customisations/UICustomizations"; +import { initMicroplanningComponents } from "@egovernments/digit-ui-module-hcmmicroplanning"; + + +window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); + +const enabledModules = [ + "DSS", + "NDSS", + "Utilities", + "HRMS", + "Engagement", + "Workbench", + "Microplanning" +]; + +const moduleReducers = (initData) => ({ + initData, +}); + +const initDigitUI = () => { + window.Digit.ComponentRegistryService.setupRegistry({ + + }); + + + initMicroplanningComponents() + window.Digit.Customizations = { + PGR: {}, + commonUiConfig: UICustomizations, + }; +}; + +initLibraries().then(() => { + initDigitUI(); +}); + +function App() { + window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); + const stateCode = + window.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || + process.env.REACT_APP_STATE_LEVEL_TENANT_ID; + if (!stateCode) { + return

stateCode is not defined

; + } + return ( + + ); +} + +export default App; diff --git a/frontend/microplan-ui/web/microplan/Dockerfile b/frontend/microplan-ui/web/microplan/Dockerfile new file mode 100644 index 00000000000..56388b8e2d7 --- /dev/null +++ b/frontend/microplan-ui/web/microplan/Dockerfile @@ -0,0 +1,30 @@ +FROM egovio/alpine-node-builder-14:yarn AS build +#FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build +RUN apk update && apk upgrade +RUN apk add --no-cache git>2.30.0 +ARG WORK_DIR +WORKDIR /app +ENV NODE_OPTIONS "--max-old-space-size=4792" + +COPY ${WORK_DIR} . +RUN ls -lah + +#RUN node web/envs.js +RUN cd web/ \ + && node -e 'console.log(v8.getHeapStatistics().heap_size_limit/(1024*1024))' \ + && node -e 'console.log("core only")' \ + && cd microplan/ \ + && chmod +x ./install-deps.sh \ + && ./install-deps.sh \ + && cd ../ \ + && yarn install \ + && yarn build:webpack + +FROM nginx:mainline-alpine +#FROM ghcr.io/egovernments/nginx:mainline-alpine +ENV WORK_DIR=/var/web/microplan-ui + +RUN mkdir -p ${WORK_DIR} + +COPY --from=build /app/web/build ${WORK_DIR}/ +COPY --from=build /app/web/microplan/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/microplan-ui/web/microplan/install-deps.sh b/frontend/microplan-ui/web/microplan/install-deps.sh new file mode 100644 index 00000000000..b090c8d6f04 --- /dev/null +++ b/frontend/microplan-ui/web/microplan/install-deps.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +BRANCH="$(git branch --show-current)" + +echo "Main Branch: $BRANCH" + +INTERNALS="micro-ui-internals" +cd .. + +cp microplan/App.js src +cp microplan/package.json package.json +cp microplan/webpack.config.js webpack.config.js +cp microplan/inter-package.json $INTERNALS/package.json + +cp $INTERNALS/example/src/UICustomizations.js src/Customisations + +echo "UI :: microplan " && echo "Branch: $(git branch --show-current)" && echo "$(git log -1 --pretty=%B)" && echo "installing packages" + diff --git a/frontend/microplan-ui/web/microplan/inter-package.json b/frontend/microplan-ui/web/microplan/inter-package.json new file mode 100644 index 00000000000..635c9cc954b --- /dev/null +++ b/frontend/microplan-ui/web/microplan/inter-package.json @@ -0,0 +1,61 @@ +{ + "name": "egovernments", + "version": "1.0.0", + "main": "index.js", + "workspaces": [ + "example", + "packages/css", + "packages/modules/*" + ], + "author": "JaganKumar ", + "license": "MIT", + "private": true, + "engines": { + "node": ">=14" + }, + "scripts": { + "start": "SKIP_PREFLIGHT_CHECK=true run-s build start:dev", + "sprint": "SKIP_PREFLIGHT_CHECK=true run-s start:script", + "start:dev": "run-p dev:**", + "start:script": "./scripts/create.sh", + "dev:css": "cd packages/css && yarn start", + "publish:css": "cd packages/css && yarn publish --access public", + "dev:example": "cd example && yarn start", + "dev:hcm-microplanning": "cd packages/modules/hcm-microplanning && yarn start", + "build": "run-p build:**", + "build:hcm-microplanning": "cd packages/modules/hcm-microplanning && yarn build", + "deploy:jenkins": "./scripts/jenkins.sh", + "clean": "rm -rf node_modules" + }, + "resolutions": { + "**/@babel/runtime": "7.20.1", + "**/babel-preset-react-app": "10.0.0", + "**/babel-loader": "8.2.2", + "**/@babel/core": "7.14.0", + "**/@babel/preset-env": "7.14.0", + "**/@babel/plugin-transform-modules-commonjs": "7.14.0", + "**/polished":"4.2.2", + "fast-uri":"2.1.0" + }, + "devDependencies": { + "husky": "7.0.4", + "lint-staged": "12.3.7", + "npm-run-all": "4.1.5", + "prettier": "2.1.2" + }, + "husky": {}, + "lint-staged": { + "*.{js,css,md}": "prettier --write" + }, + "dependencies": { + "lodash": "4.17.21", + "microbundle-crl": "0.13.11", + "@egovernments/digit-ui-react-components": "1.8.1-beta.2", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "react-router-dom": "5.3.0" + } +} diff --git a/frontend/microplan-ui/web/microplan/nginx.conf b/frontend/microplan-ui/web/microplan/nginx.conf new file mode 100644 index 00000000000..9c84c01c4be --- /dev/null +++ b/frontend/microplan-ui/web/microplan/nginx.conf @@ -0,0 +1,12 @@ +server +{ + listen 80; + underscores_in_headers on; + + location /microplan-ui + { + root /var/web; + index index.html index.htm; + try_files $uri $uri/ /microplan-ui/index.html; + } +} \ No newline at end of file diff --git a/frontend/microplan-ui/web/microplan/package.json b/frontend/microplan-ui/web/microplan/package.json new file mode 100644 index 00000000000..dff749d1780 --- /dev/null +++ b/frontend/microplan-ui/web/microplan/package.json @@ -0,0 +1,80 @@ +{ + "name": "micro-ui", + "version": "1.0.0", + "author": "Jagankumar ", + "license": "MIT", + "private": true, + "engines": { + "node": ">=14" + }, + "workspaces": [ + "micro-ui-internals/packages/modules/*" + ], + "homepage": "/microplan-ui", + "dependencies": { + "@egovernments/digit-ui-libraries": "1.8.2-beta.1", + "@egovernments/digit-ui-module-core": "1.8.2-beta.1", + "@egovernments/digit-ui-module-utilities": "1.0.1-beta.23", + "@egovernments/digit-ui-react-components": "1.8.2-beta.1", + "@egovernments/digit-ui-module-hcmmicroplanning":"0.0.1", + "@egovernments/digit-ui-components": "0.0.2-beta.2", + "babel-loader": "8.1.0", + "clean-webpack-plugin": "4.0.0", + "react": "17.0.2", + "react-dom": "17.0.2", + "jsonpath": "^1.1.1", + "react-router-dom": "5.3.0", + "react-scripts": "4.0.1", + "web-vitals": "1.1.2", + "terser-brunch": "^4.1.0", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "css-loader": "5.2.6", + "style-loader": "2.0.0", + "webpack-cli": "4.10.0" + }, + "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "7.21.0", + "file-loader": "^6.2.0", + "http-proxy-middleware": "1.3.1", + "lodash": "4.17.21", + "microbundle-crl": "0.13.11", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "react-router-dom": "5.3.0", + "husky": "7.0.4", + "lint-staged": "12.3.7", + "npm-run-all": "4.1.5", + "prettier": "2.1.2" + }, + "scripts": { + "start": "react-scripts start", + "build": "GENERATE_SOURCEMAP=false SKIP_PREFLIGHT_CHECK=true react-scripts build", + "build:prepare": "./build.sh", + "build:libraries": "cd micro-ui-internals && yarn build", + "build:prod": "webpack --mode production", + "build:webpack": "yarn build:libraries &&cd .. && ls && cd ./web && ls && yarn build:prod", + "clean": "rm -rf node_modules" + }, + "eslintConfig": { + "extends": [ + "react-app" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} \ No newline at end of file diff --git a/frontend/microplan-ui/web/microplan/webpack.config.js b/frontend/microplan-ui/web/microplan/webpack.config.js new file mode 100644 index 00000000000..c8036364605 --- /dev/null +++ b/frontend/microplan-ui/web/microplan/webpack.config.js @@ -0,0 +1,52 @@ +const path = require("path"); +const HtmlWebpackPlugin = require("html-webpack-plugin"); +const { CleanWebpackPlugin } = require("clean-webpack-plugin"); +// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; + +module.exports = { + // mode: 'development', + entry: "./src/index.js", + devtool: "none", + module: { + rules: [ + { + test: /\.(js)$/, + exclude: /node_modules/, + use: ["babel-loader"], + }, + { + test: /\.css$/i, + use: ["style-loader", "css-loader"], + }, + { + test: /\.(png|jpe?g|gif)$/i, + use: [ + { + loader: 'file-loader', + }, + ], + }, + ], + }, + output: { + filename: "[name].bundle.js", + path: path.resolve(__dirname, "build"), + publicPath: "/microplan-ui/", + }, + optimization: { + splitChunks: { + chunks: 'all', + minSize:20000, + maxSize:50000, + enforceSizeThreshold:50000, + minChunks:1, + maxAsyncRequests:30, + maxInitialRequests:30 + }, + }, + plugins: [ + new CleanWebpackPlugin(), + // new BundleAnalyzerPlugin(), + new HtmlWebpackPlugin({ inject: true, template: "public/index.html" }), + ], +}; \ No newline at end of file diff --git a/frontend/microplan-ui/web/package.json b/frontend/microplan-ui/web/package.json new file mode 100644 index 00000000000..f47fcd5fb80 --- /dev/null +++ b/frontend/microplan-ui/web/package.json @@ -0,0 +1,85 @@ +{ + "name": "micro-ui", + "version": "1.0.0", + "author": "Jagankumar ", + "license": "MIT", + "private": true, + "engines": { + "node": ">=14" + }, + "workspaces": [ + "micro-ui-internals/packages/libraries", + "micro-ui-internals/packages/react-components", + "micro-ui-internals/packages/modules/*" + ], + "homepage": "/digit-ui", + "dependencies": { + "@egovernments/digit-ui-libraries": "1.8.2-beta.1", + "@egovernments/digit-ui-module-workbench": "1.0.2-beta.1", + "@egovernments/digit-ui-module-core": "1.8.2-beta.1", + "@egovernments/digit-ui-module-hrms": "1.8.0-beta.2", + "@egovernments/digit-ui-react-components": "1.8.2-beta.1", + "@egovernments/digit-ui-module-dss": "1.8.0-beta", + "@egovernments/digit-ui-module-common": "1.8.0-beta", + "@egovernments/digit-ui-module-utilities": "1.0.1-beta.23", + "@egovernments/digit-ui-module-engagement": "1.5.20", + "babel-loader": "8.1.0", + "clean-webpack-plugin": "4.0.0", + "react": "17.0.2", + "react-dom": "17.0.2", + "jsonpath": "^1.1.1", + "react-router-dom": "5.3.0", + "react-scripts": "4.0.1", + "web-vitals": "1.1.2", + "terser-brunch": "^4.1.0", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "css-loader": "5.2.6", + "style-loader": "2.0.0", + "webpack-cli": "4.10.0" + }, + "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "7.21.0", + "http-proxy-middleware": "1.3.1", + "lodash": "4.17.21", + "file-loader": "^6.2.0", + "microbundle-crl": "0.13.11", + "react": "17.0.2", + "react-dom": "17.0.2", + "react-hook-form": "6.15.8", + "react-i18next": "11.16.2", + "react-query": "3.6.1", + "react-router-dom": "5.3.0", + "husky": "7.0.4", + "lint-staged": "12.3.7", + "npm-run-all": "4.1.5", + "prettier": "2.1.2" + }, + "scripts": { + "start": "react-scripts start", + "build": "GENERATE_SOURCEMAP=false SKIP_PREFLIGHT_CHECK=true react-scripts build", + "build:prepare": "./build.sh", + "build:libraries": "cd micro-ui-internals && yarn build", + "build:prod": "webpack --mode production", + "build:webpack": "yarn build:libraries &&cd .. && ls && cd ./web && ls && yarn build:prod", + "clean": "rm -rf node_modules" + }, + "eslintConfig": { + "extends": [ + "react-app" + ] + }, + "browserslist": { + "production": [ + ">0.2%", + "not dead", + "not op_mini all" + ], + "development": [ + "last 1 chrome version", + "last 1 firefox version", + "last 1 safari version" + ] + } +} \ No newline at end of file diff --git a/frontend/microplan-ui/web/public/index.html b/frontend/microplan-ui/web/public/index.html new file mode 100644 index 00000000000..11a58320150 --- /dev/null +++ b/frontend/microplan-ui/web/public/index.html @@ -0,0 +1,47 @@ + + + + + + + + + + + + DIGIT + + + + + + +
+ + + diff --git a/frontend/microplan-ui/web/public/robots.txt b/frontend/microplan-ui/web/public/robots.txt new file mode 100644 index 00000000000..e9e57dc4d41 --- /dev/null +++ b/frontend/microplan-ui/web/public/robots.txt @@ -0,0 +1,3 @@ +# https://www.robotstxt.org/robotstxt.html +User-agent: * +Disallow: diff --git a/frontend/microplan-ui/web/src/App.js b/frontend/microplan-ui/web/src/App.js new file mode 100644 index 00000000000..4a60913eee0 --- /dev/null +++ b/frontend/microplan-ui/web/src/App.js @@ -0,0 +1,53 @@ +import React from "react"; +import { initLibraries } from "@egovernments/digit-ui-libraries"; +import { DigitUI } from "@egovernments/digit-ui-module-core"; +import { UICustomizations } from "./Customisations/UICustomizations"; +import { initMicroplanningComponents } from "@egovernments/digit-ui-module-hcmmicroplanning"; + +window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); + +const enabledModules = [ + "Microplanning" +]; + +const moduleReducers = (initData) => ({ + initData, +}); + +const initDigitUI = () => { + window.Digit.ComponentRegistryService.setupRegistry({ + + }); + + + initMicroplanningComponents(); + + window.Digit.Customizations = { + PGR: {}, + commonUiConfig: UICustomizations, + }; +}; + +initLibraries().then(() => { + initDigitUI(); +}); + +function App() { + window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); + const stateCode = + window.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || + process.env.REACT_APP_STATE_LEVEL_TENANT_ID; + if (!stateCode) { + return

stateCode is not defined

; + } + return ( + + ); +} + +export default App; diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/ComponentRegistry.js b/frontend/microplan-ui/web/src/ComponentRegistry.js similarity index 100% rename from frontend/micro-ui/web/micro-ui-internals/example/src/ComponentRegistry.js rename to frontend/microplan-ui/web/src/ComponentRegistry.js diff --git a/frontend/microplan-ui/web/src/Customisations/UICustomizations.js b/frontend/microplan-ui/web/src/Customisations/UICustomizations.js new file mode 100644 index 00000000000..6d17ab0d51b --- /dev/null +++ b/frontend/microplan-ui/web/src/Customisations/UICustomizations.js @@ -0,0 +1,428 @@ +import { Link } from "react-router-dom"; +import _ from "lodash"; + +//create functions here based on module name set in mdms(eg->SearchProjectConfig) +//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName] +// these functions will act as middlewares +var Digit = window.Digit || {}; + + + +const businessServiceMap = { + + "muster roll": "MR" +}; + +const inboxModuleNameMap = { + "muster-roll-approval": "muster-roll-service", +}; + +export const UICustomizations = { + businessServiceMap, + updatePayload: (applicationDetails, data, action, businessService) => { + + if (businessService === businessServiceMap.estimate) { + const workflow = { + comment: data.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + estimate: applicationDetails, + workflow, + }; + } + if (businessService === businessServiceMap.contract) { + const workflow = { + comment: data?.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + contract: applicationDetails, + workflow, + }; + } + if (businessService === businessServiceMap?.["muster roll"]) { + const workflow = { + comment: data?.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + return { + musterRoll: applicationDetails, + workflow, + }; + } + if(businessService === businessServiceMap?.["works.purchase"]){ + const workflow = { + comment: data.comments, + documents: data?.documents?.map((document) => { + return { + documentType: action?.action + " DOC", + fileName: document?.[1]?.file?.name, + fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, + documentUid: document?.[1]?.fileStoreId?.fileStoreId, + tenantId: document?.[1]?.fileStoreId?.tenantId, + }; + }), + assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, + action: action.action, + }; + //filtering out the data + Object.keys(workflow).forEach((key, index) => { + if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; + }); + + const additionalFieldsToSet = { + projectId:applicationDetails.additionalDetails.projectId, + invoiceDate:applicationDetails.billDate, + invoiceNumber:applicationDetails.referenceId.split('_')?.[1], + contractNumber:applicationDetails.referenceId.split('_')?.[0], + documents:applicationDetails.additionalDetails.documents + } + return { + bill: {...applicationDetails,...additionalFieldsToSet}, + workflow, + }; + } + }, + enableModalSubmit:(businessService,action,setModalSubmit,data)=>{ + if(businessService === businessServiceMap?.["muster roll"] && action.action==="APPROVE"){ + setModalSubmit(data?.acceptTerms) + } + }, + enableHrmsSearch: (businessService, action) => { + if (businessService === businessServiceMap.estimate) { + return action.action.includes("TECHNICALSANCTION") || action.action.includes("VERIFYANDFORWARD"); + } + if (businessService === businessServiceMap.contract) { + return action.action.includes("VERIFY_AND_FORWARD"); + } + if (businessService === businessServiceMap?.["muster roll"]) { + return action.action.includes("VERIFY"); + } + if(businessService === businessServiceMap?.["works.purchase"]){ + return action.action.includes("VERIFY_AND_FORWARD") + } + return false; + }, + getBusinessService: (moduleCode) => { + if (moduleCode?.includes("estimate")) { + return businessServiceMap?.estimate; + } else if (moduleCode?.includes("contract")) { + return businessServiceMap?.contract; + } else if (moduleCode?.includes("muster roll")) { + return businessServiceMap?.["muster roll"]; + } + else if (moduleCode?.includes("works.purchase")) { + return businessServiceMap?.["works.purchase"]; + } + else if (moduleCode?.includes("works.wages")) { + return businessServiceMap?.["works.wages"]; + } + else if (moduleCode?.includes("works.supervision")) { + return businessServiceMap?.["works.supervision"]; + } + else { + return businessServiceMap; + } + }, + getInboxModuleName: (moduleCode) => { + if (moduleCode?.includes("estimate")) { + return inboxModuleNameMap?.estimate; + } else if (moduleCode?.includes("contract")) { + return inboxModuleNameMap?.contracts; + } else if (moduleCode?.includes("attendence")) { + return inboxModuleNameMap?.attendencemgmt; + } else { + return inboxModuleNameMap; + } + }, + + AttendanceInboxConfig: { + preProcess: (data) => { + + //set tenantId + data.body.inbox.tenantId = Digit.ULBService.getCurrentTenantId(); + data.body.inbox.processSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); + + const musterRollNumber = data?.body?.inbox?.moduleSearchCriteria?.musterRollNumber?.trim(); + if(musterRollNumber) data.body.inbox.moduleSearchCriteria.musterRollNumber = musterRollNumber + + const attendanceRegisterName = data?.body?.inbox?.moduleSearchCriteria?.attendanceRegisterName?.trim(); + if(attendanceRegisterName) data.body.inbox.moduleSearchCriteria.attendanceRegisterName = attendanceRegisterName + + // deleting them for now(assignee-> need clarity from pintu,ward-> static for now,not implemented BE side) + const assignee = _.clone(data.body.inbox.moduleSearchCriteria.assignee); + delete data.body.inbox.moduleSearchCriteria.assignee; + if (assignee?.code === "ASSIGNED_TO_ME") { + data.body.inbox.moduleSearchCriteria.assignee = Digit.UserService.getUser().info.uuid; + } + + //cloning locality and workflow states to format them + // let locality = _.clone(data.body.inbox.moduleSearchCriteria.locality ? data.body.inbox.moduleSearchCriteria.locality : []); + + let selectedOrg = _.clone(data.body.inbox.moduleSearchCriteria.orgId ? data.body.inbox.moduleSearchCriteria.orgId : null); + delete data.body.inbox.moduleSearchCriteria.orgId; + if(selectedOrg) { + data.body.inbox.moduleSearchCriteria.orgId = selectedOrg?.[0]?.applicationNumber; + } + + // let selectedWard = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : null); + // delete data.body.inbox.moduleSearchCriteria.ward; + // if(selectedWard) { + // data.body.inbox.moduleSearchCriteria.ward = selectedWard?.[0]?.code; + // } + + let states = _.clone(data.body.inbox.moduleSearchCriteria.state ? data.body.inbox.moduleSearchCriteria.state : []); + let ward = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : []); + // delete data.body.inbox.moduleSearchCriteria.locality; + delete data.body.inbox.moduleSearchCriteria.state; + delete data.body.inbox.moduleSearchCriteria.ward; + + // locality = locality?.map((row) => row?.code); + states = Object.keys(states)?.filter((key) => states[key]); + ward = ward?.map((row) => row?.code); + + + // //adding formatted data to these keys + // if (locality.length > 0) data.body.inbox.moduleSearchCriteria.locality = locality; + if (states.length > 0) data.body.inbox.moduleSearchCriteria.status = states; + if (ward.length > 0) data.body.inbox.moduleSearchCriteria.ward = ward; + const projectType = _.clone(data.body.inbox.moduleSearchCriteria.projectType ? data.body.inbox.moduleSearchCriteria.projectType : {}); + if (projectType?.code) data.body.inbox.moduleSearchCriteria.projectType = projectType.code; + + //adding tenantId to moduleSearchCriteria + data.body.inbox.moduleSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); + + //setting limit and offset becoz somehow they are not getting set in muster inbox + data.body.inbox .limit = data.state.tableForm.limit + data.body.inbox.offset = data.state.tableForm.offset + delete data.state + return data; + }, + postProcess: (responseArray, uiConfig) => { + const statusOptions = responseArray?.statusMap + ?.filter((item) => item.applicationstatus) + ?.map((item) => ({ code: item.applicationstatus, i18nKey: `COMMON_MASTERS_${item.applicationstatus}` })); + if (uiConfig?.type === "filter") { + let fieldConfig = uiConfig?.fields?.filter((item) => item.type === "dropdown" && item.populators.name === "musterRollStatus"); + if (fieldConfig.length) { + fieldConfig[0].populators.options = statusOptions; + } + } + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + if (key === "ATM_MUSTER_ROLL_ID") { + return ( + + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + ); + } + if (key === "ATM_ATTENDANCE_WEEK") { + const week = `${Digit.DateUtils.ConvertTimestampToDate(value?.startDate, "dd/MM/yyyy")}-${Digit.DateUtils.ConvertTimestampToDate( + value?.endDate, + "dd/MM/yyyy" + )}`; + return
{week}
; + } + if (key === "ATM_NO_OF_INDIVIDUALS") { + return
{value?.length}
; + } + if(key === "ATM_AMOUNT_IN_RS"){ + return {value ? Digit.Utils.dss.formatterWithoutRound(value, "number") : t("ES_COMMON_NA")}; + } + if (key === "ATM_SLA") { + return parseInt(value) > 0 ? ( + {t(value) || ""} + ) : ( + {t(value) || ""} + ); + } + if (key === "COMMON_WORKFLOW_STATES") { + return {t(`WF_MUSTOR_${value}`)} + } + //added this in case we change the key and not updated here , it'll throw that nothing was returned from cell error if that case is not handled here. To prevent that error putting this default + return {t(`CASE_NOT_HANDLED`)} + }, + MobileDetailsOnClick: (row, tenantId) => { + let link; + Object.keys(row).map((key) => { + if (key === "ATM_MUSTER_ROLL_ID") + link = `/${window.contextPath}/employee/attendencemgmt/view-attendance?tenantId=${tenantId}&musterRollNumber=${row[key]}`; + }); + return link; + }, + populateReqCriteria: () => { + const tenantId = Digit.ULBService.getCurrentTenantId(); + return { + url: "/org-services/organisation/v1/_search", + params: { limit: 50, offset: 0 }, + body: { + SearchCriteria: { + tenantId: tenantId, + functions : { + type : "CBO" + } + }, + }, + config: { + enabled: true, + select: (data) => { + return data?.organisations; + }, + }, + }; + }, + }, + SearchWageSeekerConfig: { + customValidationCheck: (data) => { + //checking both to and from date are present + const { createdFrom, createdTo } = data; + if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === "")) + return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; + + return false; + }, + preProcess: (data) => { + data.params = { ...data.params, tenantId: Digit.ULBService.getCurrentTenantId() }; + + let requestBody = { ...data.body.Individual }; + const pathConfig = { + name: "name.givenName", + }; + const dateConfig = { + createdFrom: "daystart", + createdTo: "dayend", + }; + const selectConfig = { + wardCode: "wardCode[0].code", + socialCategory: "socialCategory.code", + }; + const textConfig = ["name", "individualId"] + let Individual = Object.keys(requestBody) + .map((key) => { + if (selectConfig[key]) { + requestBody[key] = _.get(requestBody, selectConfig[key], null); + } else if (typeof requestBody[key] == "object") { + requestBody[key] = requestBody[key]?.code; + } else if (textConfig?.includes(key)) { + requestBody[key] = requestBody[key]?.trim() + } + return key; + }) + .filter((key) => requestBody[key]) + .reduce((acc, curr) => { + if (pathConfig[curr]) { + _.set(acc, pathConfig[curr], requestBody[curr]); + } else if (dateConfig[curr] && dateConfig[curr]?.includes("day")) { + _.set(acc, curr, Digit.Utils.date.convertDateToEpoch(requestBody[curr], dateConfig[curr])); + } else { + _.set(acc, curr, requestBody[curr]); + } + return acc; + }, {}); + + data.body.Individual = { ...Individual }; + return data; + }, + additionalCustomizations: (row, key, column, value, t, searchResult) => { + //here we can add multiple conditions + //like if a cell is link then we return link + //first we can identify which column it belongs to then we can return relevant result + switch (key) { + case "MASTERS_WAGESEEKER_ID": + return ( + + + {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} + + + ); + + case "MASTERS_SOCIAL_CATEGORY": + return value ? {String(t(`MASTERS_${value}`))} : t("ES_COMMON_NA"); + + case "CORE_COMMON_PROFILE_CITY": + return value ? {String(t(Digit.Utils.locale.getCityLocale(value)))} : t("ES_COMMON_NA"); + + case "MASTERS_WARD": + return value ? ( + {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} + ) : ( + t("ES_COMMON_NA") + ); + + case "MASTERS_LOCALITY": + return value ? ( + {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} + ) : ( + t("ES_COMMON_NA") + ); + default: + return t("ES_COMMON_NA"); + } + }, + MobileDetailsOnClick: (row, tenantId) => { + let link; + Object.keys(row).map((key) => { + if (key === "MASTERS_WAGESEEKER_ID") + link = `/${window.contextPath}/employee/masters/view-wageseeker?tenantId=${tenantId}&wageseekerId=${row[key]}`; + }); + return link; + }, + additionalValidations: (type, data, keys) => { + if (type === "date") { + return data[keys.start] && data[keys.end] ? () => new Date(data[keys.start]).getTime() <= new Date(data[keys.end]).getTime() : true; + } + } + }, +}; diff --git a/frontend/microplan-ui/web/src/Customisations/index.js b/frontend/microplan-ui/web/src/Customisations/index.js new file mode 100644 index 00000000000..60fcbe8ac77 --- /dev/null +++ b/frontend/microplan-ui/web/src/Customisations/index.js @@ -0,0 +1,9 @@ +var Digit = window.Digit || {}; + +const customisedComponent = {}; + +export const initCustomisationComponents = () => { + Object.entries(customisedComponent).forEach(([key, value]) => { + Digit.ComponentRegistryService.setComponent(key, value); + }); +}; diff --git a/frontend/microplan-ui/web/src/index.css b/frontend/microplan-ui/web/src/index.css new file mode 100644 index 00000000000..e69de29bb2d diff --git a/frontend/microplan-ui/web/src/index.js b/frontend/microplan-ui/web/src/index.js new file mode 100644 index 00000000000..492c14421c8 --- /dev/null +++ b/frontend/microplan-ui/web/src/index.js @@ -0,0 +1,68 @@ +import React from "react"; +import ReactDOM from "react-dom"; +import { initLibraries } from "@egovernments/digit-ui-libraries"; +import "./index.css"; +import App from "./App"; +import { initMicroplanningComponents } from "@egovernments/digit-ui-module-hcmmicroplanning"; +import { UICustomizations } from "./Customisations/UICustomizations"; + +initLibraries(); +initMicroplanningComponents(); + +window.Digit.Customizations = { PGR: {}, commonUiConfig: UICustomizations }; + +const user = window.Digit.SessionStorage.get("User"); + +if (!user || !user.access_token || !user.info) { + // login detection + + const parseValue = (value) => { + try { + return JSON.parse(value); + } catch (e) { + return value; + } + }; + + const getFromStorage = (key) => { + const value = window.localStorage.getItem(key); + return value && value !== "undefined" ? parseValue(value) : null; + }; + + const token = getFromStorage("token"); + + const citizenToken = getFromStorage("Citizen.token"); + const citizenInfo = getFromStorage("Citizen.user-info"); + const citizenTenantId = getFromStorage("Citizen.tenant-id"); + + const employeeToken = getFromStorage("Employee.token"); + const employeeInfo = getFromStorage("Employee.user-info"); + const employeeTenantId = getFromStorage("Employee.tenant-id"); + const userType = token === citizenToken ? "citizen" : "employee"; + + window.Digit.SessionStorage.set("user_type", userType); + window.Digit.SessionStorage.set("userType", userType); + + const getUserDetails = (access_token, info) => ({ + token: access_token, + access_token, + info, + }); + + const userDetails = + userType === "citizen" + ? getUserDetails(citizenToken, citizenInfo) + : getUserDetails(employeeToken, employeeInfo); + + window.Digit.SessionStorage.set("User", userDetails); + window.Digit.SessionStorage.set("Citizen.tenantId", citizenTenantId); + window.Digit.SessionStorage.set("Employee.tenantId", employeeTenantId); + // end +} + +ReactDOM.render( + + + , + document.getElementById("root") +); diff --git a/frontend/microplan-ui/web/src/setupProxy.js b/frontend/microplan-ui/web/src/setupProxy.js new file mode 100644 index 00000000000..1b8eda94a19 --- /dev/null +++ b/frontend/microplan-ui/web/src/setupProxy.js @@ -0,0 +1,30 @@ +const { createProxyMiddleware } = require("http-proxy-middleware"); +const createProxy = createProxyMiddleware({ + target: process.env.REACT_APP_PROXY_URL, + changeOrigin: true, +}); +module.exports = function (app) { + [ + "/egov-mdms-service", + "/egov-location", + "/localization", + "/egov-workflow-v2", + "/pgr-services", + "/filestore", + "/egov-hrms", + "/user-otp", + "/user", + "/fsm", + "/billing-service", + "/collection-services", + "/pdf-service", + "/pg-service", + "/vehicle", + "/vendor", + "/property-services", + "/fsm-calculator/v1/billingSlab/_search", + "/muster-roll" + ].forEach((location) => + app.use(location, createProxy) + ); +}; diff --git a/frontend/microplan-ui/web/webpack.config.js b/frontend/microplan-ui/web/webpack.config.js new file mode 100644 index 00000000000..b15cf021f19 --- /dev/null +++ b/frontend/microplan-ui/web/webpack.config.js @@ -0,0 +1,51 @@ +const path = require("path"); +const HtmlWebpackPlugin = require("html-webpack-plugin"); +const { CleanWebpackPlugin } = require("clean-webpack-plugin"); +// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; + +module.exports = { + // mode: 'development', + entry: "./src/index.js", + devtool: "none", + module: { + rules: [ + { + test: /\.(js)$/, + use: ["babel-loader"], + }, + { + test: /\.css$/i, + use: ["style-loader", "css-loader"], + }, + { + test: /\.(png|jpe?g|gif)$/i, + use: [ + { + loader: 'file-loader', + }, + ], + }, + ], + }, + output: { + filename: "[name].bundle.js", + path: path.resolve(__dirname, "build"), + publicPath: "/digit-ui/", + }, + optimization: { + splitChunks: { + chunks: 'all', + minSize:20000, + maxSize:50000, + enforceSizeThreshold:50000, + minChunks:1, + maxAsyncRequests:30, + maxInitialRequests:30 + }, + }, + plugins: [ + new CleanWebpackPlugin(), + // new BundleAnalyzerPlugin(), + new HtmlWebpackPlugin({ inject: true, template: "public/index.html" }), + ], +}; \ No newline at end of file From 6caaf2700e4f748b6ce23de94972757d90edd042 Mon Sep 17 00:00:00 2001 From: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Date: Thu, 20 Jun 2024 10:54:10 +0530 Subject: [PATCH 261/283] Admin console Improved performance, sheets freezed, implemented caching, delivery type integarted (#790) * Update campaignValidators.ts (#655) * fixes-> cyclenumber issue, hover issue, dropdown height issue, * css * fixes-> cyclenumber issue, hover issue, dropdown height issue, (#656) * fixes-> cyclenumber issue, hover issue, dropdown height issue, * css --------- Co-authored-by: nabeelmd-eGov * Update campaignUtils.ts * fixed HLM-5970 * Feat : added boundary validation at data level * fixes * local add * Added boundary validation * Refactor * fixed HLM-5935 and HLM-5749 * Refactor * Feat : updated table * change campaignid in payload * Feat : added campaignId * Update campaignApis.ts * Update campaignValidators.ts * refactored * Refactor * assigned campaignId * Refactor * updated createRequest Schema * Feat : invalid Status Persist * status fix * version-fix * Update CODEOWNERS * core version updated and css fix for language dropdown * refactor (#676) * Uat signoff (#678) * change in filter recursive * lowest level * added validation related to target sheet headers * HLM-5916 * download button fixes in summary (#682) Co-authored-by: nabeelmd-eGov * Hlm 5927 (#687) * change in filter recursive * lowest level * added validation for boundary codes to be invalid other than that selected from UI in target upload * Added Delivery and cycle config for LLIN and SMC both (#688) * no of cycle and deivery drafted changes * fixes * add localisation code for boundaries * fixes * fixes * Value localise in summary screen, api error change * fixes * genarate api call fix * font size change for summary * login css change * HLM-5718: SMC delivery config enhancement * config update * added config for in between * fix config for llin * added mdms integration --------- Co-authored-by: nabeelmd-eGov * Fixed HLM-5988_warning message (#689) Co-authored-by: nabeelmd-eGov <94039229+nabeelmd-eGov@users.noreply.github.com> * download filename fixes (#693) * download button fixes in summary * download filename with custom name changes added --------- Co-authored-by: nabeelmd-eGov * download filename fixes (#694) * download button fixes in summary * download filename with custom name changes added * config fix for llin --------- Co-authored-by: nabeelmd-eGov * successful toast message is fixed (#695) * successful toast message is fixed * Update UploadData.js * HLM-5991: Alert Pop UP CR (#696) Co-authored-by: nabeelmd-eGov * HLM-5718 changes (#703) Co-authored-by: nabeelmd-eGov * Localization cache (#706) * change in filter recursive * lowest level * refactored localization cache logic * Update README.md (#707) * Update README.md * Update README.md * Update utilities/project-factory/README.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update README.md --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * HLM-5985_made lowest level changes (#708) * HLM-5985_made lowest level changes * resolved codeRabbit comments * Create LOCALSETUP.md (#709) * Create LOCALSETUP.md * Refactored config * Update LOCALSETUP.md * Update utilities/project-factory/LOCALSETUP.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/LOCALSETUP.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/LOCALSETUP.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/LOCALSETUP.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update LOCALSETUP.md --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * updated the localisation module config * Refactor config (#713) * Refactor config * Update utilities/project-factory/src/server/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update postman_collection.json (#714) * Update postman_collection.json * Update postman_collection.json * Delete utilities/project-factory/project_factory_swagger.yml (#715) * Feat : removed campaignId validation for boundary upload (#718) * updated the delay for boundary relationship * added logger for request TODO TEST will be reverted * Revert "added logger for request TODO TEST" This reverts commit d5c2bf570400ada8183eebfec71f0a3449143117. * Schema validation (#719) * Feat : removed campaignId validation for boundary upload * Feat : added schema validation * Fixed mdms host * updated the logger messages * updated the loggers * delivery new changes, toast fix, error fix (#716) * delivery new changes, toast fix, error fix * new fixes * fixes * change text component to field component * added hierarchy * fix * fix * fix * fix * passing hierarchy from props --------- Co-authored-by: nabeelmd-eGov * Schema validation2 (#721) * Feat : removed campaignId validation for boundary upload * Feat : added schema validation * Fixed mdms host * Feat : added boundary validation * Feat : optimized product search * Fix : project mapping fixed (#722) * Fixed project search (#723) * smc fixes (#724) Co-authored-by: nabeelmd-eGov * Feat : added boundary confirmation (#727) * Fix: fixed processing boundary * Refactor * fixed HLM-6109 (#729) * gate fixes validation, ui ux (#731) Co-authored-by: nabeelmd-eGov * integrated panelcard component (#732) * integrated panelcard component * Update micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/Response.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update genericUtils.ts (#733) * updated the folder structure * Create CHANGELOG.md (#717) * updated the versions * Update .gitignore * Update request.ts (#735) * fixed generate api issue (#734) Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Create CHANGELOG.md * gate fixes (#736) * gate fixes validation, ui ux * gate fix --------- Co-authored-by: nabeelmd-eGov * added loader in the selecting boundaries (#737) * Update createAndSearch.ts (#738) * fix (#739) * fix * fix --------- Co-authored-by: nabeelmd-eGov * Patch 3 (#740) * change in filter recursive * lowest level * trimmed underscore and empty spaces * boundary fix (#742) Co-authored-by: nabeelmd-eGov * Update genericUtils.ts (#746) * fixed the delivery products issue * Fixed delivery conditions issue * Update campaignApis.ts (#747) * fixed warning toast (#748) * fixed warning toast * Update UploadData.js * fix (#749) * fix * fx * fix --------- Co-authored-by: nabeelmd-eGov * core -update (#751) Co-authored-by: nabeelmd-eGov * fixed stepper issue (#752) * fixed stepper issue * Update index.html * Feat : added user validation via individual (#753) * fixes (#754) Co-authored-by: nabeelmd-eGov * code fix nabeel (#756) * fixes * fix --------- Co-authored-by: nabeelmd-eGov * Updated few loggers (#759) * updated few loggers flow * Update utilities/project-factory/src/server/api/campaignApis.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/utils/campaignMappingUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/utils/campaignUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/api/campaignApis.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/utils/campaignMappingUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/utils/genericUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Updated the user Password generation logic #761 * Update Listener.ts (#730) * Update Listener.ts * added try catch logic in producer * Feat : added parallel batch execution (#767) * Feat : added parallel batch execution * Refactor * Update utilities/project-factory/src/server/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fixed the stepper (#765) * changes config (#769) * Project type config and added loggers for process of campaign (#772) * Feat : added themes in generate template (#773) * fixed the ajv package version for build issue * Feat : removed xlsx (#776) * HLM-6177: PARALLEL SEARCH IMPLEMENT, DELIVERY TYPE IMPLEMENT (#778) Co-authored-by: nabeelmd-eGov * css update (#780) Co-authored-by: nabeelmd-eGov * HLM-6179 and HLM-6180 (#777) * HLM-6179 and HLM-6180 * campaign name changes --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Feat : fixed target generation (#781) * fixed tenantId issue (#784) * fix: resolved AJV-related Jenkins build issue reference #783 #786 (#787) * module ui fix * updated all the package version for build fixes * fixed kafka-error at target generation (#789) * updated core version (#791) * updated core version * updated css also * Update campaignValidators.ts (#794) * Updated the excel generation logic and files * added changes for configurable column in target sheet (#779) * change in filter recursive * lowest level * made target headers genearte through mdms schema * changed config index.ts * changed config index.ts * changes for now * added configurable column logic from schema HLM-6169 * updated validate of target columns through schema * added masterForColumnSchema in index.ts * formatted dataManageService * refactored lock TargetFields func * removed console.log * User creation performance improved (#800) * Feat : Improved user creation performance * Change status color * Update utilities/project-factory/src/server/utils/campaignUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update genericUtils.ts (#801) * Hlm 6170 (#802) * change in filter recursive * lowest level * HLM -6170 added logic for only village level data in target sheet and some refactoring * updated css (#804) * fixed button issue (#805) * HLM 6177: Error card implementation in summary screen (#806) * HLM-6177: PARALLEL SEARCH IMPLEMENT, DELIVERY TYPE IMPLEMENT * Added Error Cards in summary screen and redirection --------- Co-authored-by: nabeelmd-eGov * added error button styles (#807) Co-authored-by: nabeelmd-eGov * updated popUp css (#808) * HLM 6178: Implementing New Pop up screen in boundaries (#809) * added error button styles * Implementing New Pop up screen in boundaries --------- Co-authored-by: nabeelmd-eGov * Facility changes (#812) * Feat : changed facility Template * Feat : locked target templates * fixed colour issue (#813) * Updated the project type conversion logic for the "deliveryType" dont1 and n config * Unique field added (#814) * Feat : changed facility Template * Feat : locked target templates * Feat : added unique check logic * Target schema update (#815) * change in filter recursive * lowest level * updated shcema of target columns to be configurable * removed empty spaces from config index.ts * Active mapping (#817) * Feat : changed facility Template * Feat : locked target templates * Feat : added unique check logic * Feat : added mapping via active field * changes in the schema validation (#816) * Updated the workbench and css module version * Feat : added active inactive boundary check (#818) * Update campaignValidators.ts (#819) * added active inactive validation (#820) * changed api call time (#826) * Feat : added target sum mapping (#825) * added campaign type as filter (#827) * Update genericApis.ts (#828) * Update excelUtils.ts (#829) * UI issue fixes, icon fix in summary error (#831) Co-authored-by: nabeelmd-eGov * Target columns (#830) * change in filter recursive * lowest level * commit * Feat : target flow fixed for LLIN-mz * uat to dev --------- Co-authored-by: admin1 * Feat : freezed target columns (#833) * Target mr dn (#834) * change in filter recursive * lowest level * Feat : skipped validation temporarily * changes in the target validation (#835) * fixed error info (#837) * Added roboto font (#840) * Feat : added roboto font * Fixed config * target validation based on diff campaign types (#843) * change in filter recursive * lowest level * updated validation of target based on campaign type * fixed validation issue (#844) * Updated the workbench package version * fixed validation logic (#846) * fixed validation logic * Update micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Error messages improved (#848) * Feat : imporved error messages and initilised utils for tracking process * Fix ; unused variables fixed * Feat : improved error messages * Fix : download error fix (#850) * Update campaignUtils.ts (#851) * Update campaignUtils.ts * Update utilities/project-factory/src/server/utils/campaignUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update campaignValidators.ts (#853) * HLM 6210: Toast, error focus fix and project type reset delivery data fix (#854) * HLM-6210: campaign type change reset delivery data fix, summary error focus fix * summary error focus fix --------- Co-authored-by: nabeelmd-eGov * HLM-6225_added time out according to data (#855) * Update campaignValidators.ts (#859) * HLM 6210 (#858) * HLM-6210: campaign type change reset delivery data fix, summary error focus fix * summary error focus fix * parallel search fixes --------- Co-authored-by: nabeelmd-eGov * Remove validation (#852) * change in filter recursive * lowest level * removed unnecessary validation for target * spacing refactor * Update campaignValidators.ts (#863) * Header validation (#861) * change in filter recursive * lowest level * removed unnecessary validation for target * changed the logic of header validation * space refactor * Update campaignUtils.ts (#864) * fixed ui error (#865) * Read me (#867) * change in filter recursive * lowest level * removed unnecessary validation for target * changed the logic of header validation * fixed portugese language error * space refactoring * Update Dockerfile * Update Dockerfile * Update migrate.sh * Update Dockerfile * Update campaignValidators.ts (#868) * HLM 6210:campaign type change reset fix (#869) * HLM-6210: campaign type change reset delivery data fix, summary error focus fix * summary error focus fix * parallel search fixes * campaign type change reset fix --------- Co-authored-by: nabeelmd-eGov * Update excelUtils.ts for sheetHeaders wraping (#870) * Update package.json * updated error messages (#871) * feat : added jaeger-client tracing (#872) * updated the table config * Update campaignApis.ts (#875) * removed the schema and updated the db name * fixing generate API call, file auto delete, date error (#877) Co-authored-by: nabeelmd-eGov * Trim resource (#878) * Feat : trimmed resource persist message * Refactor * Removed reject error in produce message * fixed min time, draft logic (#879) * Update index.ts (#880) * added min ui error and facility usage (#883) * added min ui error and facility usage * changes * Update campaignUtils.ts (#884) * HLM 6007 (#885) * fixing generate API call, file auto delete, date error * generate api fix --------- Co-authored-by: nabeelmd-eGov * Update Dockerfile * Feat : docker config update (#886) * Update Dockerfile (#887) * Create buildWorkbenchUI.yml * Update README.md (#917) * Update buildWorkbenchUI.yml * Update README.md * Updated the DB Schema issue of Project-factory * fixed hierarchy order (#919) * User flag hcm (#920) * Feat : docker config update * Feat : added user create flag * Refactored * Update campaignUtils.ts * Update campaignMappingUtils.ts (#922) * Ashish egov patch 2 (#921) * Update index.ts * Update campaignApis.ts * Fixed the project type conversion and product duplicate issue * Update campaignApis.ts (#924) * Update campaignMappingUtils.ts (#925) * Update campaignMappingUtils.ts * Refactored * Update publishProjectFactory.yml * Update buildWorkbenchUI.yml * Update campaignMappingUtils.ts (#926) * Update request.ts (#928) * Update request.ts * Feat : updated httprequest * Feat : warning response added * Refactor * added start and enddate in cycles * Update campaignApis.ts (#930) * Update request.ts (#932) * fixed generate issue (#933) * Fixed project-type resources duplication * updated target error messages (#936) * fixed stepper from draft (#937) * Update Listener.ts * delivery type disable fix, product sku name change (#939) Co-authored-by: nabeelmd-eGov * fixed error message issue (#941) * Redis integration (#940) * Feat : added redis * Feat : added redis retry * updated migration * fixed * updated migration * Delete .vscode/launch.json * Delete .vscode/settings.json --------- Co-authored-by: ashish-egov <137176738+ashish-egov@users.noreply.github.com> Co-authored-by: nabeelmd-eGov Co-authored-by: nabeelmd-eGov <94039229+nabeelmd-eGov@users.noreply.github.com> Co-authored-by: Bhavya-egov Co-authored-by: ashish-egov Co-authored-by: nitish-egov <137176807+nitish-egov@users.noreply.github.com> Co-authored-by: Bhavya-egov <137176879+Bhavya-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Swathi-eGov <137176788+Swathi-eGov@users.noreply.github.com> Co-authored-by: admin1 --- .github/workflows/buildWorkbenchUI.yml | 64 + .github/workflows/publishProjectFactory.yml | 2 + frontend/micro-ui/README.md | 3 +- .../micro-ui-internals/example/package.json | 12 +- .../example/public/index.html | 7 +- .../example/src/ComponentRegistry.js | 11 + .../example/src/complaintConfig.js | 31 + .../example/src/components/SelectName.js | 8 + .../web/micro-ui-internals/example/src/fsm.js | 38 + .../web/micro-ui-internals/example/src/pgr.js | 15 + .../example/src/setupProxy.js | 100 ++ .../web/micro-ui-internals/package.json | 6 +- .../packages/css/package.json | 2 +- .../css/src/pages/employee/campaign.scss | 30 + .../css/src/pages/employee/campaignCycle.scss | 3 + .../css/src/pages/employee/coreOverride.scss | 21 +- .../css/src/pages/employee/index.scss | 82 ++ .../packages/css/tailwind.config.js | 1 + .../modules/campaign-manager/package.json | 6 +- .../src/components/BulkUpload.js | 3 +- .../components/CampaignDocumentsPreview.js | 16 +- .../src/components/CampaignName.js | 3 +- .../src/components/CampaignSummary.js | 225 +-- .../src/components/CampaignType.js | 64 +- .../src/components/CycleDataPreview.js | 17 +- .../src/components/SelectingBoundaries.js | 291 ++-- .../src/components/UploadData.js | 465 ++++-- .../src/configs/CampaignConfig.js | 61 +- .../src/configs/baseTimeOut.js | 6 + .../src/configs/deliveryConfig.js | 8 + .../campaign-manager/src/hooks/index.js | 2 + .../src/hooks/useGenerateIdCampaign.js | 4 +- .../src/hooks/useParallelSearch.js | 98 +- .../src/hooks/useResourceData.js | 40 +- .../src/pages/employee/AddProduct.js | 4 +- .../src/pages/employee/CycleConfiguration.js | 53 +- .../src/pages/employee/SetupCampaign.js | 342 ++++- .../deliveryRule/AddDeliverycontext.js | 48 +- .../employee/deliveryRule/MultiTabcontext.js | 23 + .../src/pages/employee/deliveryRule/index.js | 16 +- frontend/micro-ui/web/package.json | 6 +- frontend/micro-ui/web/public/index.html | 6 +- .../micro-ui/web/workbench/inter-package.json | 8 +- frontend/micro-ui/web/workbench/package.json | 20 +- .../project-factory/migration/Dockerfile | 8 +- .../V20240315110400__resource_details_ddl.sql | 0 .../V20240315110513__campaign_details_ddl.sql | 0 ...01154500__campaign_details_add_columns.sql | 0 ...2134500__campaign_details_alter_column.sql | 0 ...0154500__campaign_details_alter_column.sql | 0 .../V20240416170000__generate_add_column.sql | 0 .../V20240427174100__campaign_add_column.sql | 0 ...2143500__resource_details_alter_column.sql | 0 .../project-factory/migration/migrate.sh | 3 +- .../project-factory/package-lock.json | 1113 ++++++++++++--- health-services/project-factory/package.json | 23 +- .../src/server/api/campaignApis.ts | 415 ++++-- .../src/server/api/genericApis.ts | 570 ++++---- .../project-factory/src/server/app.ts | 23 +- .../src/server/config/constants.ts | 18 +- .../src/server/config/createAndSearch.ts | 2 + .../src/server/config/dbPoolConfig.ts | 8 +- .../src/server/config/index.ts | 36 +- .../src/server/kafka/Listener.ts | 66 +- .../src/server/service/dataManageService.ts | 53 +- .../project-factory/src/server/tracing.ts | 45 + .../src/server/utils/campaignMappingUtils.ts | 55 +- .../src/server/utils/campaignUtils.ts | 637 ++++++--- .../src/server/utils/excelUtils.ts | 234 +++ .../src/server/utils/genericUtils.ts | 356 +++-- .../src/server/utils/processTrackUtils.ts | 52 + .../src/server/utils/redisUtils.ts | 29 + .../src/server/utils/request.ts | 190 ++- .../utils/transforms/projectTypeUtils.ts | 357 ++--- .../transforms/searchResponseConstructor.ts | 1 + .../server/validators/campaignValidators.ts | 419 +++--- .../src/server/validators/genericValidator.ts | 178 +-- health-services/project-factory/yarn.lock | 1263 +++++++++++------ 78 files changed, 5918 insertions(+), 2507 deletions(-) create mode 100644 .github/workflows/buildWorkbenchUI.yml create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/ComponentRegistry.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/complaintConfig.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/components/SelectName.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/fsm.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/pgr.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/setupProxy.js create mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/baseTimeOut.js rename health-services/project-factory/migration/{ddl => main}/V20240315110400__resource_details_ddl.sql (100%) rename health-services/project-factory/migration/{ddl => main}/V20240315110513__campaign_details_ddl.sql (100%) rename health-services/project-factory/migration/{ddl => main}/V20240401154500__campaign_details_add_columns.sql (100%) rename health-services/project-factory/migration/{ddl => main}/V20240402134500__campaign_details_alter_column.sql (100%) rename health-services/project-factory/migration/{ddl => main}/V20240410154500__campaign_details_alter_column.sql (100%) rename health-services/project-factory/migration/{ddl => main}/V20240416170000__generate_add_column.sql (100%) rename health-services/project-factory/migration/{ddl => main}/V20240427174100__campaign_add_column.sql (100%) rename health-services/project-factory/migration/{ddl => main}/V20240522143500__resource_details_alter_column.sql (100%) create mode 100644 health-services/project-factory/src/server/tracing.ts create mode 100644 health-services/project-factory/src/server/utils/excelUtils.ts create mode 100644 health-services/project-factory/src/server/utils/processTrackUtils.ts create mode 100644 health-services/project-factory/src/server/utils/redisUtils.ts diff --git a/.github/workflows/buildWorkbenchUI.yml b/.github/workflows/buildWorkbenchUI.yml new file mode 100644 index 00000000000..1a0c526d1bf --- /dev/null +++ b/.github/workflows/buildWorkbenchUI.yml @@ -0,0 +1,64 @@ +name: Digit Admin Console Build workflow +on: + push: + branches: + - campaign + paths: + - 'micro-ui/web/micro-ui-internals/**' + pull_request: + branches: + - campaign + workflow_dispatch: +jobs: + docker_image-build: + outputs: + run_job_digit_ui: ${{ steps.check_files.outputs.run_job_digit_ui }} + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + fetch-depth: 2 + - name: Setup Docker + uses: docker/setup-buildx-action@v1 + - name: check modified files + id: check_files + run: | + echo "=============== list modified files ===============" + git diff --name-only HEAD^ HEAD + + echo "========== check paths of modified files ==========" + git diff --name-only HEAD^ HEAD > files.txt + run_job_digit_ui=false + while IFS= read -r file + do + if [[ $file == micro-ui/* ]]; then + echo "This modified file is under the 'digit_ui' folder." + run_job_digit_ui=true + fi + done < files.txt + + # Set the output based on whether the job should run + echo "::set-output name=run_job_digit_ui::$run_job_digit_ui" + echo "ACTION_NUMBER=${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV + echo "COMMIT_ID=${GITHUB_SHA: -8}" >> $GITHUB_ENV # Extract last 8 characters of SHA + echo "BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV + + + + + - name: Login to egovio docker Container Registry + env: + DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }} + DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }} + run: | + # Authenticate with Docker Hub + echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin + + - name: Build and Push Docker image for digit-ui + if: ${{ steps.check_files.outputs.run_job_digit_ui == 'true' }} + run: | + docker build -t workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} -f web/workbench/Dockerfile . + docker tag workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} egovio/workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} + docker push egovio/workbench-ui:${{ env.BRANCH_NAME }}-${{ env.COMMIT_ID }}-${{ env.ACTION_NUMBER }} + working-directory: micro-ui diff --git a/.github/workflows/publishProjectFactory.yml b/.github/workflows/publishProjectFactory.yml index a606c08c952..19fde98c7ab 100644 --- a/.github/workflows/publishProjectFactory.yml +++ b/.github/workflows/publishProjectFactory.yml @@ -3,6 +3,8 @@ name: project factory service docker Image CI on: push: branches: [ "campaign" ] + paths: + - 'utilities/project-factory/**' pull_request: branches: [ "campaign" ] diff --git a/frontend/micro-ui/README.md b/frontend/micro-ui/README.md index 9420dbb760d..9f559d81783 100644 --- a/frontend/micro-ui/README.md +++ b/frontend/micro-ui/README.md @@ -1,5 +1,5 @@ -# workbench ui +# DIGIT ui A React App built on top of DIGIT UI Core. @@ -136,5 +136,4 @@ Start the server yarn start ``` - ![Logo](https://s3.ap-south-1.amazonaws.com/works-dev-asset/mseva-white-logo.png) diff --git a/frontend/micro-ui/web/micro-ui-internals/example/package.json b/frontend/micro-ui/web/micro-ui-internals/example/package.json index ccd8104bdb1..7c60f4a1d6c 100644 --- a/frontend/micro-ui/web/micro-ui-internals/example/package.json +++ b/frontend/micro-ui/web/micro-ui-internals/example/package.json @@ -9,12 +9,12 @@ "start": "react-scripts start" }, "devDependencies": { - "@egovernments/digit-ui-libraries": "1.8.1-beta.4", - "@egovernments/digit-ui-module-core": "1.8.1-beta.23", - "@egovernments/digit-ui-module-utilities": "1.0.1-beta.2", - "@egovernments/digit-ui-components": "0.0.1-beta.31", - "@egovernments/digit-ui-react-components": "1.8.1-beta.24", - "@egovernments/digit-ui-module-workbench": "1.0.1-beta.16", + "@egovernments/digit-ui-libraries": "1.8.2-beta.1", + "@egovernments/digit-ui-module-workbench": "1.0.2-beta.3", + "@egovernments/digit-ui-components": "0.0.2-beta.1", + "@egovernments/digit-ui-module-core": "1.8.2-beta.2", + "@egovernments/digit-ui-module-utilities": "1.0.1-beta.30", + "@egovernments/digit-ui-react-components": "1.8.2-beta.6", "@egovernments/digit-ui-module-hcmworkbench":"0.0.38", "@egovernments/digit-ui-module-campaign-manager": "0.0.1", "http-proxy-middleware": "^1.0.5", diff --git a/frontend/micro-ui/web/micro-ui-internals/example/public/index.html b/frontend/micro-ui/web/micro-ui-internals/example/public/index.html index 63af0a10bac..d42798fc275 100644 --- a/frontend/micro-ui/web/micro-ui-internals/example/public/index.html +++ b/frontend/micro-ui/web/micro-ui-internals/example/public/index.html @@ -14,11 +14,10 @@ rel="stylesheet" href="https://unpkg.com/@egovernments/digit-ui-css@1.8.0-alpha.6/dist/index.css" /> --> - - - + + + - diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/ComponentRegistry.js b/frontend/micro-ui/web/micro-ui-internals/example/src/ComponentRegistry.js new file mode 100644 index 00000000000..9bafce3dc89 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/src/ComponentRegistry.js @@ -0,0 +1,11 @@ +class Registry { + constructor(registry = {}) { + this._registry = registry; + } + + getComponent(id) { + return this._registry[id]; + } +} + +export default Registry; diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/complaintConfig.js b/frontend/micro-ui/web/micro-ui-internals/example/src/complaintConfig.js new file mode 100644 index 00000000000..28c85515205 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/src/complaintConfig.js @@ -0,0 +1,31 @@ +export const config = { + routes: { + "complaint-type": { + nextStep: "pincode", + }, + landmark: { + nextStep: "apartment", + }, + apartment: { + component: "SelectName", + texts: { + header: "Apartment or Society", + cardText: "CS_COMPLAINT_SUBTYPE_TEXT", + submitBarLabel: "PT_COMMONS_NEXT", + }, + inputs: [ + { + label: "Apartment", + type: "text", + name: "custom.additionalDetails.apartment", + validation: { + minLength: 6, + maxLength: 7, + }, + error: "CORE_COMMON_PINCODE_INVALID", + }, + ], + nextStep: "upload-photos", + }, + }, +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/components/SelectName.js b/frontend/micro-ui/web/micro-ui-internals/example/src/components/SelectName.js new file mode 100644 index 00000000000..56d2a195c12 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/src/components/SelectName.js @@ -0,0 +1,8 @@ +import React from "react"; +import { FormStep } from "@egovernments/digit-ui-react-components"; + +const SelectName = ({ config, onSelect, onSkip, t }) => { + return ; +}; + +export default SelectName; diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/fsm.js b/frontend/micro-ui/web/micro-ui-internals/example/src/fsm.js new file mode 100644 index 00000000000..271d3ddad56 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/src/fsm.js @@ -0,0 +1,38 @@ +const fsmCustomizations = { + getEmployeeApplicationCustomization: (config, t) => { + const employeeConfig = [ + { + name: "applicationDetails", + // fields: ["sanitationType", "applicationChannel"], + // fieldsOrder: {sanitationType: 0, applicationChannel: 1}, // TODO + allFields: true, // for example: If in applicationDetails you have 10 fields and in fieldsOrder you only enter 3 fields name then on browser you will only see 3 fields in that order but if you want to see rest of 7 fields at the bottom. + // removeFields: ["applicantName"], // type the name of the field in camelCase to remove it + addFields: [ + // by default all the custom fields will add at the bottom, you can add "field name" to "fieldsOrder" if you want them in your custom order. + { + name: "example", + label: t("EXAMPLE"), + type: "text", + isMandatory: true, + populators: { + name: "example", + validation: { + required: true, + pattern: /[A-Za-z]/, + }, + }, + }, + ], + }, + ]; + + return { + config: employeeConfig, + defaultConfig: true, // You want to use defaultConfig and you only want to update one field section. The above employeeConfig is also an order for all the field section. So if defaultConfig is false then on browser you will only see those field section who are inside employeeConfig + }; + }, +}; + +const fsmComponents = {}; + +export { fsmCustomizations, fsmComponents }; diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/pgr.js b/frontend/micro-ui/web/micro-ui-internals/example/src/pgr.js new file mode 100644 index 00000000000..48a498e4582 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/src/pgr.js @@ -0,0 +1,15 @@ +import SelectName from "./components/SelectName"; + +// import { config as complaintConfig } from "./complaintConfig"; + +const pgrCustomizations = { + // complaintConfig, + getComplaintDetailsTableRows: ({ id, service, role, t }) => { + return {}; + }, +}; + +const pgrComponents = { + SelectName: SelectName, +}; +export { pgrCustomizations, pgrComponents }; diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/setupProxy.js b/frontend/micro-ui/web/micro-ui-internals/example/src/setupProxy.js new file mode 100644 index 00000000000..fbc52c4a879 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/example/src/setupProxy.js @@ -0,0 +1,100 @@ +const { createProxyMiddleware } = require("http-proxy-middleware"); + +const createProxy = createProxyMiddleware({ + //target: process.env.REACT_APP_PROXY_API || "https://uat.digit.org", + // target: process.env.REACT_APP_PROXY_API || "https://qa.digit.org", + target: process.env.REACT_APP_PROXY_API || "https://works-dev.digit.org", + changeOrigin: true, + secure: false, +}); +const assetsProxy = createProxyMiddleware({ + target: process.env.REACT_APP_PROXY_ASSETS || "https://works-dev.digit.org", + changeOrigin: true, + secure: false, +}); +const mdmsProxy = createProxyMiddleware({ + target: process.env.REACT_APP_PROXY_ASSETS || "http://localhost:8080", + changeOrigin: true, + secure: false, +}); +module.exports = function (app) { + ["/mdms-v2/v2/_create"].forEach((location) => app.use(location, mdmsProxy)); + [ + "/access/v1/actions/mdms", + "/egov-mdms-service", + "/mdms-v2", + "/egov-idgen", + "/egov-location", + "/localization", + "/egov-workflow-v2", + "/pgr-services", + "/filestore", + "/egov-hrms", + "/user-otp", + "/user", + "/fsm", + "/billing-service", + "/collection-services", + "/pdf-service", + "/pg-service", + "/vehicle", + "/vendor", + "/property-services", + "/fsm-calculator/v1/billingSlab/_search", + "/pt-calculator-v2", + "/dashboard-analytics", + "/echallan-services", + "/egov-searcher/bill-genie/mcollectbills/_get", + "/egov-searcher/bill-genie/billswithaddranduser/_get", + "/egov-searcher/bill-genie/waterbills/_get", + "/egov-searcher/bill-genie/seweragebills/_get", + "/egov-pdf/download/UC/mcollect-challan", + "/egov-hrms/employees/_count", + "/tl-services/v1/_create", + "/tl-services/v1/_search", + "/egov-url-shortening/shortener", + "/inbox/v1/_search", + "/inbox/v2/_search", + "/tl-services", + "/tl-calculator", + "/org-services", + "/edcr", + "/bpa-services", + "/noc-services", + "/egov-user-event", + "/egov-document-uploader", + "/egov-pdf", + "/egov-survey-services", + "/ws-services", + "/sw-services", + "/ws-calculator", + "/sw-calculator/", + "/egov-searcher", + "/report", + "/inbox/v1/dss/_search", + "/loi-service", + "/project/v1/", + "/estimate-service", + "/loi-service", + "/works-inbox-service/v2/_search", + "/egov-pdf/download/WORKSESTIMATE/estimatepdf", + "/muster-roll", + "/individual", + "/mdms-v2", + "/hcm-moz-impl", + "/project", + "/project/staff/v1/_search", + "/project/v1/_search", + "/facility/v1/_search", + "/product/v1/_search", + "/product/variant/v1/_search", + "/hcm-bff/bulk/_transform", + "/hcm-bff/hcm/_processmicroplan", + "/health-hrms", + "/project-factory", + "/boundary-service", + "/product", + ].forEach((location) => app.use(location, createProxy)); + ["/pb-egov-assets"].forEach((location) => app.use(location, assetsProxy)); + ["/mdms-v2/v2/_create"].forEach((location) => app.use(location, mdmsProxy)); +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/package.json b/frontend/micro-ui/web/micro-ui-internals/package.json index 072483e9f0c..92f1e334d77 100644 --- a/frontend/micro-ui/web/micro-ui-internals/package.json +++ b/frontend/micro-ui/web/micro-ui-internals/package.json @@ -42,11 +42,11 @@ "*.{js,css,md}": "prettier --write" }, "dependencies": { - "ajv": "^8.12.0", + "ajv": "8.12.0", "lodash": "4.17.21", "microbundle-crl": "0.13.11", - "@egovernments/digit-ui-react-components": "1.8.1-beta.24", - "@egovernments/digit-ui-components": "0.0.1-beta.31", + "@egovernments/digit-ui-react-components": "1.8.2-beta.6", + "@egovernments/digit-ui-components": "0.0.2-beta.1", "react": "17.0.2", "react-dom": "17.0.2", "react-hook-form": "6.15.8", diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json b/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json index e91bf430a29..5f503a9ebf5 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json @@ -1,6 +1,6 @@ { "name": "@egovernments/digit-ui-css", - "version": "1.0.49-campaign", + "version": "1.0.56-campaign", "license": "MIT", "main": "dist/index.css", "author": "Jagankumar ", diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss index ff5cdb24093..5c6b56289d3 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss @@ -77,3 +77,33 @@ gap: 0.5rem; margin-bottom: 0.5rem; } +.infoClass{ + margin-bottom: 1.5rem +} +.headerWrapperClassName{ + display: none +} +.popup-close-svg{ + display: none; +} +.whoLogo{ + margin-top: -1rem; + margin-bottom: -1rem; +} + +.digit-popup-wrapper{ + &.popUpClass{ + width:45rem; + + .popUpFooter{ + .digit-popup-footer-buttons{ + margin-left: 0px; + width: 100%; + + button{ + flex:1; + } + } + } + } +} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss index 2506d8ea136..74296abb568 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss @@ -265,6 +265,9 @@ .label-field-pair { flex-direction: column; align-items: flex-start !important; + .card-label.card-label-smaller { + font-weight: 700; + } .employee-select-wrap.form-field { width: 100%; } diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss index 448357784b2..295d90c1264 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss @@ -134,9 +134,18 @@ header { @extend .typography.text-heading-xl; } +.digit-button-primary{ + background-color: theme(digitv2.lightTheme.primary) !important; +} +.digit-button-secondary{ + .icon-label-container{ + h2{ + color: theme(digitv2.lightTheme.primary) !important; + } + } +} - -.digit-popup-wrap { +/*.digit-popup-wrap { background: rgba(0, 0, 0, 0.7); @apply flex fixed w-full h-full overflow-auto top-0 left-0 min-h-screen; z-index: 10000; @@ -153,4 +162,12 @@ header { .digit-popup-close-icon { @apply flex justify-end; +}*/ + +.employee{ + .digit-employeeSidebar{ + .sidebar{ + z-index:999 + } + } } \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss index fb8aca4ee84..2b989e87305 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss @@ -116,6 +116,7 @@ overflow: hidden; border-radius: 4px; table { + border-width: 0px !important; background-color: #fafafa; border: 1px solid #d6d5d4; border-collapse: collapse; @@ -151,6 +152,7 @@ border: 1px solid #d6d5d4; border-collapse: collapse; border-radius: 1rem; + border-width: 0px !important; tbody { background-color: #fff; tr:nth-child(odd) { @@ -276,12 +278,34 @@ tbody { } } } + .digit-infobanner-wrap.error { + margin-left: 0; + margin-bottom: 1.5rem; + min-width: 100%; + .digit-button-primary { + height: 1.5rem; + background-color: #d4351c !important; + .icon-label-container.primary.large { + font-size: 14px; + .digit-button-label { + font-size: 14px; + color: #ffffff; + } + } + } + } } .view-composer-header-section { .employee-card-sub-header { @extend .typography.text-heading-m; margin-bottom: 1.5rem; } + .employee-card-sub-header.error { + color: #d4351c; + display: flex; + align-items: center; + gap: 0.5rem; + } } .add-new-product-container { border: 1px solid #d6d5d4; @@ -311,6 +335,16 @@ tbody { .page-padding-fix { margin-top: 1.5rem; } +.addProductActionClass { + display: flex; + flex-direction: row-reverse; + justify-content: space-between; + .submit-bar { + width: max-content; + padding-left: 1.5rem; + padding-right: 1.5rem; + } +} .loginFormStyleEmployee { .loginCardClassName { .digit-header-content { @@ -339,6 +373,27 @@ tbody { min-width: fit-content; } } +.digit-popup-wrapper.boundaries-pop-module.default { + width: 36rem; + .digit-popup-footer { + .digit-popup-footer-buttons { + width: 100% !important; + display: grid; + grid-template-columns: 1fr 1fr; + .digit-button-secondary { + width: 100%; + } + .digit-button-primary { + width: 100%; + } + } + } +} +.campaign-type-alert-button { + .digit-button-label { + width: 100% !important; + } +} .campaign-pop-module { padding: 1.5rem; border-radius: 4px; @@ -397,3 +452,30 @@ tbody { .link { color: #c84c0e !important; } +.employeeCard.employeeCard-override.card-error { + border: 1px solid #d4351c; +} +.label-field-pair.delivery-type-radio { + gap: 5rem; + .digit-radio-options-wrap { + gap: 2rem; + margin-bottom: 0 !important; + .radio-option-container { + margin-bottom: 0; + align-items: center; + } + } +} +.bold { + font-weight: 700; +} +.summary-doc-error { + p { + margin-top: 0; + margin-bottom: 0; + } + .digit-infobanner-wrap.error { + margin-bottom: 0.5rem; + margin-top: 1.5rem; + } +} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js b/frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js index e59e972d1ad..c9b2a06dedf 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js @@ -115,6 +115,7 @@ module.exports = { "input-border": "#505A5F", "primary-bg": "#FEEFE7", "text-primary": "#363636", + "error-v2": "#D4351C", }, alert: { error: "#b91900", diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json index ba8776efd9b..41e43fdb6fd 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json @@ -18,12 +18,12 @@ "react-router-dom": "5.3.0" }, "dependencies": { - "@egovernments/digit-ui-react-components": "1.8.1-beta.24", - "@egovernments/digit-ui-components": "0.0.1-beta.31", + "@egovernments/digit-ui-react-components": "1.8.2-beta.6", + "@egovernments/digit-ui-components": "0.0.2-beta.1", "@rjsf/core": "5.10.0", "@rjsf/utils": "5.10.0", "@rjsf/validator-ajv8": "5.10.0", - "ajv": "^8.12.0", + "ajv": "8.12.0", "react": "17.0.2", "react-date-range": "1.4.0", "react-dom": "17.0.2", diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/BulkUpload.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/BulkUpload.js index 81476daad66..5f854cfac79 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/BulkUpload.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/BulkUpload.js @@ -128,7 +128,8 @@ const BulkUpload = ({ multiple = true, onSubmit, fileData, onFileDelete, onFileD
{ + onClick={(e) => { + e.stopPropagation(); setShowPreview(true); }} > diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDocumentsPreview.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDocumentsPreview.js index 86518ffdfc5..2c8bbf77eaf 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDocumentsPreview.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDocumentsPreview.js @@ -4,8 +4,9 @@ import { DocumentIcon } from "./DocumentIcon"; import XlsPreview from "./XlsPreview"; import { XlsxFile } from "./icons/XlsxFile"; import { downloadExcelWithCustomName } from "../utils"; +import { InfoCard } from "@egovernments/digit-ui-components"; -function CampaignDocumentsPreview({ documents = [], svgStyles = {}, isUserGenerate = false }) { +function CampaignDocumentsPreview({ documents = [], svgStyles = {}, isUserGenerate = false, cardErrors }) { const { t } = useTranslation(); const tenantId = Digit.ULBService.getCurrentTenantId(); const [filesArray, setFilesArray] = useState(null); @@ -68,8 +69,19 @@ function CampaignDocumentsPreview({ documents = [], svgStyles = {}, isUserGenera ) ) ) : ( -
+

{t("ES_CAMPAIGN_NO_DOCUMENTS_AVAILABLE")}

+ {cardErrors?.map((i) => ( + ]} + /> + ))}
)}
diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignName.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignName.js index 59bae87777a..4540e3f46f4 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignName.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignName.js @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from "react"; +import React, { useState, useEffect ,Fragment} from "react"; import { Header } from "@egovernments/digit-ui-react-components"; import { useTranslation } from "react-i18next"; import { LabelFieldPair } from "@egovernments/digit-ui-react-components"; @@ -51,6 +51,7 @@ const CampaignName = ({ onSelect, formData, control, formState, ...props }) => { error={error?.message ? t(error?.message) : ""} style={{ width: "40rem", marginBottom: "0" }} populators={{ name: "campaignName" }} + placeholder={t("HCM_CAMPAIGN_NAME_EXAMPLE")} value={name} onChange={(event) => { setStartValidation(true); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignSummary.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignSummary.js index 270fc03736b..6f37dfb6ae2 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignSummary.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignSummary.js @@ -1,8 +1,8 @@ -import React, { Fragment, useEffect, useState } from "react"; +import React, { Fragment, useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { useHistory } from "react-router-dom"; import { Button, EditIcon, Header, Loader, ViewComposer } from "@egovernments/digit-ui-react-components"; -import { Toast } from "@egovernments/digit-ui-components"; +import { InfoBannerIcon, Toast } from "@egovernments/digit-ui-components"; import { DownloadIcon } from "@egovernments/digit-ui-react-components"; import { PRIMARY_COLOR, downloadExcelWithCustomName } from "../utils"; @@ -68,7 +68,7 @@ function loopAndReturn(dataa, t) { if (i.operator === "IN_BETWEEN") { return { ...i, - value: `${i?.toValue} to ${i?.fromValue}`, + value: `${i?.toValue ? i?.toValue : "N/A"} to ${i?.fromValue ? i?.fromValue : "N/A"}`, }; } return { @@ -134,7 +134,7 @@ const fetchResourceFile = async (tenantId, resourceIdArr) => { return res?.ResourceDetails; }; -const CampaignSummary = () => { +const CampaignSummary = (props) => { const { t } = useTranslation(); const history = useHistory(); const tenantId = Digit.ULBService.getCurrentTenantId(); @@ -143,7 +143,59 @@ const CampaignSummary = () => { const noAction = searchParams.get("action"); const [showToast, setShowToast] = useState(null); const [userCredential, setUserCredential] = useState(null); - const { isLoading, data, error } = Digit.Hooks.campaign.useSearchCampaign({ + const [deliveryErrors, setDeliveryErrors] = useState(null); + const [targetErrors, setTargetErrors] = useState(null); + const [facilityErrors, setFacilityErrors] = useState(null); + const [userErrors, setUserErrors] = useState(null); + const [cycleDatesError, setCycleDatesError] = useState(null); + const [summaryErrors, setSummaryErrors] = useState(null); + const handleRedirect = (step, activeCycle) => { + const urlParams = new URLSearchParams(window.location.search); + const id = urlParams.get("id"); + urlParams.set("key", step); + urlParams.set("preview", false); + if (activeCycle) { + urlParams.set("activeCycle", activeCycle); + } + const newUrl = `${window.location.pathname}?${urlParams.toString()}`; + history.push(newUrl); + }; + + useEffect(() => { + if (props?.props?.summaryErrors) { + if (props?.props?.summaryErrors?.deliveryErrors) { + const temp = props?.props?.summaryErrors?.deliveryErrors?.map((i) => { + return { + ...i, + onClick: i?.dateError ? () => handleRedirect(5) : () => handleRedirect(6, i?.cycle), + }; + }); + setSummaryErrors({ ...props?.props?.summaryErrors, deliveryErrors: temp }); + } else { + setSummaryErrors(props?.props?.summaryErrors); + } + } + // if (props?.props?.summaryErrors?.deliveryErrors) { + // const temp = props?.props?.summaryErrors?.deliveryErrors?.map((i) => { + // return { + // ...i, + // onClick: () => handleRedirect(6, i?.cycle), + // }; + // }); + // setDeliveryErrors(temp); + // } + // if (props?.props?.summaryErrors?.targetErrors) { + // setTargetErrors(props?.props?.summaryErrors?.targetErrors); + // } + // if (props?.props?.summaryErrors?.facilityErrors) { + // setFacilityErrors(props?.props?.summaryErrors?.facilityErrors); + // } + // if (props?.props?.summaryErrors?.userErrors) { + // setUserErrors(props?.props?.summaryErrors?.userErrors); + // } + }, [props?.props?.summaryErrors]); + + const { isLoading, data, error, refetch } = Digit.Hooks.campaign.useSearchCampaign({ tenantId: tenantId, filter: { ids: [id], @@ -200,66 +252,75 @@ const CampaignSummary = () => { }, ], }, - data?.[0]?.resources?.find((i) => i?.type === "boundaryWithTarget") - ? { - sections: [ - { - type: "COMPONENT", - component: "CampaignDocumentsPreview", - props: { - documents: data?.[0]?.resources?.filter((i) => i.type === "boundaryWithTarget"), - }, - cardHeader: { value: t("TARGET_DETAILS"), inlineStyles: { marginTop: 0, fontSize: "1.5rem" } }, - cardSecondaryAction: noAction !== "false" && ( -
handleRedirect(7)}> - {t(`CAMPAIGN_EDIT`)} - -
- ), - }, - ], - } - : {}, - data?.[0]?.resources?.find((i) => i?.type === "facility") - ? { - sections: [ - { - type: "COMPONENT", - component: "CampaignDocumentsPreview", - props: { - documents: data?.[0]?.resources?.filter((i) => i.type === "facility"), - }, - cardHeader: { value: t("FACILITY_DETAILS"), inlineStyles: { marginTop: 0, fontSize: "1.5rem" } }, - cardSecondaryAction: noAction !== "false" && ( -
handleRedirect(8)}> - {t(`CAMPAIGN_EDIT`)} - -
- ), - }, - ], - } - : {}, - data?.[0]?.resources?.find((i) => i?.type === "user") - ? { - sections: [ - { - type: "COMPONENT", - component: "CampaignDocumentsPreview", - props: { - documents: data?.[0]?.resources?.filter((i) => i.type === "user"), - }, - cardHeader: { value: t("USER_DETAILS"), inlineStyles: { marginTop: 0, fontSize: "1.5rem" } }, - cardSecondaryAction: noAction !== "false" && ( -
handleRedirect(9)}> - {t(`CAMPAIGN_EDIT`)} - -
- ), - }, - ], - } - : {}, + // data?.[0]?.resources?.find((i) => i?.type === "boundaryWithTarget") ? + { + name: "target", + errorName: "target", + sections: [ + { + name: "target", + type: "COMPONENT", + component: "CampaignDocumentsPreview", + props: { + documents: data?.[0]?.resources?.filter((i) => i?.type === "boundaryWithTarget"), + }, + cardHeader: { value: t("TARGET_DETAILS"), inlineStyles: { marginTop: 0, fontSize: "1.5rem" } }, + cardSecondaryAction: noAction !== "false" && ( +
handleRedirect(7)}> + {t(`CAMPAIGN_EDIT`)} + +
+ ), + }, + ], + }, + // : {} + // data?.[0]?.resources?.find((i) => i?.type === "facility") ? + { + name: "facility", + errorName: "facility", + sections: [ + { + name: "facility", + type: "COMPONENT", + component: "CampaignDocumentsPreview", + props: { + documents: data?.[0]?.resources?.filter((i) => i.type === "facility"), + }, + cardHeader: { value: t("FACILITY_DETAILS"), inlineStyles: { marginTop: 0, fontSize: "1.5rem" } }, + cardSecondaryAction: noAction !== "false" && ( +
handleRedirect(8)}> + {t(`CAMPAIGN_EDIT`)} + +
+ ), + }, + ], + }, + // : {} + // data?.[0]?.resources?.find((i) => i?.type === "user") ? + { + name: "user", + errorName: "user", + sections: [ + { + name: "user", + type: "COMPONENT", + component: "CampaignDocumentsPreview", + props: { + documents: data?.[0]?.resources?.filter((i) => i.type === "user"), + }, + cardHeader: { value: t("USER_DETAILS"), inlineStyles: { marginTop: 0, fontSize: "1.5rem" } }, + cardSecondaryAction: noAction !== "false" && ( +
handleRedirect(9)}> + {t(`CAMPAIGN_EDIT`)} + +
+ ), + }, + ], + }, + // : {} resourceIdArr?.length > 0 ? { sections: [ @@ -282,7 +343,7 @@ const CampaignSummary = () => { type: "DATA", cardHeader: { value: t("CAMPAIGN_DELIVERY_DETAILS"), inlineStyles: { marginTop: 0, fontSize: "1.5rem" } }, cardSecondaryAction: noAction !== "false" && ( -
handleRedirect(4)}> +
handleRedirect(5)}> {t(`CAMPAIGN_EDIT`)}
@@ -290,13 +351,15 @@ const CampaignSummary = () => { values: [ { key: "CAMPAIGN_NO_OF_CYCLES", - value: data?.[0]?.deliveryRules + value: + data?.[0]?.deliveryRules && data?.[0]?.deliveryRules.map((item) => item.cycleNumber)?.length > 0 ? Math.max(...data?.[0]?.deliveryRules.map((item) => item.cycleNumber)) : t("CAMPAIGN_SUMMARY_NA"), }, { key: "CAMPAIGN_NO_OF_DELIVERIES", - value: data?.[0]?.deliveryRules + value: + data?.[0]?.deliveryRules && data?.[0]?.deliveryRules.map((item) => item.deliveryNumber)?.length > 0 ? Math.max(...data?.[0]?.deliveryRules.map((item) => item.deliveryNumber)) : t("CAMPAIGN_SUMMARY_NA"), }, @@ -306,8 +369,11 @@ const CampaignSummary = () => { }, ...cycleData?.map((item, index) => { return { + name: `CYCLE_${index + 1}`, + errorName: "deliveryErrors", sections: [ { + name: `CYCLE_${index + 1}`, type: "COMPONENT", cardHeader: { value: `${t("CYCLE")} ${item?.cycleIndex}`, inlineStyles: { marginTop: 0, fontSize: "1.5rem" } }, cardSecondaryAction: noAction !== "false" && ( @@ -337,25 +403,6 @@ const CampaignSummary = () => { }, }); - const handleRedirect = (step) => { - const urlParams = new URLSearchParams(window.location.search); - - // Get the values of other parameters - const id = urlParams.get("id"); - // If there are more parameters, you can get them similarly - - // Modify the 'key' parameter - urlParams.set("key", step); - urlParams.set("preview", false); - - // Reconstruct the URL with the modified parameters - const newUrl = `${window.location.pathname}?${urlParams.toString()}`; - - // Push the new URL to history - history.push(newUrl); - // history.push(`/${window?.contextPath}/employee/campaign/setup-campaign?key=${step}`); - }; - if (isLoading) { return ; } @@ -421,12 +468,10 @@ const CampaignSummary = () => { )}
- + {showToast && ( diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignType.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignType.js index 22d47594cd7..a57ceb7008f 100644 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignType.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignType.js @@ -2,7 +2,7 @@ import React, { useState, useMemo, useRef, useEffect } from "react"; import { UploadIcon, FileIcon, DeleteIconv2, Toast, Card, Header } from "@egovernments/digit-ui-react-components"; import { useTranslation } from "react-i18next"; import { LabelFieldPair } from "@egovernments/digit-ui-react-components"; -import { Dropdown, ErrorMessage } from "@egovernments/digit-ui-components"; +import { Button, CardText, Dropdown, ErrorMessage, PopUp } from "@egovernments/digit-ui-components"; const CampaignSelection = ({ onSelect, formData, formState, ...props }) => { const { t } = useTranslation(); @@ -14,6 +14,8 @@ const CampaignSelection = ({ onSelect, formData, formState, ...props }) => { const [executionCount, setExecutionCount] = useState(0); const [error, setError] = useState(null); const [startValidation, setStartValidation] = useState(null); + const [showPopUp, setShowPopUp] = useState(null); + const [canUpdate, setCanUpdate] = useState(null); useEffect(() => { if (props?.props?.isSubmitting && !type) { @@ -56,7 +58,23 @@ const CampaignSelection = ({ onSelect, formData, formState, ...props }) => { {`${t("HCM_CAMPAIGN_TYPE")}`} *
-
+
{ + if (props?.props?.sessionData?.HCM_CAMPAIGN_TYPE?.projectType && !canUpdate) { + setShowPopUp(true); + return; + } + return; + }} + onFocus={(e) => { + if (props?.props?.sessionData?.HCM_CAMPAIGN_TYPE?.projectType && !canUpdate) { + setShowPopUp(true); + return; + } + return; + }} + > { handleChange(value); }} /> - {error?.message && } + {error?.message && }
{showBeneficiary && ( @@ -78,6 +96,46 @@ const CampaignSelection = ({ onSelect, formData, formState, ...props }) => {
{t(`CAMPAIGN_TYPE_${beneficiaryType}`)}
)} + {showPopUp && ( + + {t("ES_CAMPAIGN_UPDATE_TYPE_MODAL_TEXT") + " "} +
, + ]} + onOverlayClick={() => { + setShowPopUp(false); + }} + footerChildren={[ +
*/}
{data?.startDate && ( item.includeAllChildren).map(item => item.code) || null); const [parentArray, setParentArray] = useState(null); @@ -43,7 +44,7 @@ function SelectingBoundaries({ onSelect, formData, ...props }) { // const lowestHierarchy = hierarchyConfig?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.lowestHierarchy; const lowestHierarchy = useMemo(() => hierarchyConfig?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.lowestHierarchy, [hierarchyConfig]); - const lowestChild = hierarchyTypeDataresult?.boundaryHierarchy.filter((item => item.parentBoundaryType === lowestHierarchy))?.[0]?.boundaryType; + const lowestChild = hierarchyTypeDataresult?.boundaryHierarchy.filter((item) => item.parentBoundaryType === lowestHierarchy)?.[0]?.boundaryType; const searchParams = new URLSearchParams(location.search); const isDraft = searchParams.get("draft"); @@ -74,7 +75,35 @@ function SelectingBoundaries({ onSelect, formData, ...props }) { }, [params?.hierarchyType]); useEffect(() => { - setHierarchyTypeDataresult(params?.hierarchy); + if (params?.hierarchy) { + const sortHierarchy = (hierarchy) => { + const boundaryMap = new Map(); + hierarchy.forEach(item => { + boundaryMap.set(item.boundaryType, item); + }); + + const sortedHierarchy = []; + let currentType = null; + + while (sortedHierarchy.length < hierarchy.length) { + for (let i = 0; i < hierarchy.length; i++) { + if (hierarchy[i].parentBoundaryType === currentType) { + sortedHierarchy.push(hierarchy[i]); + currentType = hierarchy[i].boundaryType; + break; + } + } + } + + return sortedHierarchy; + }; + + const sortedHierarchy = sortHierarchy(params.hierarchy.boundaryHierarchy); + setHierarchyTypeDataresult({ + ...params.hierarchy, + boundaryHierarchy: sortedHierarchy + }); + } }, [params?.hierarchy]); useEffect(() => { @@ -119,7 +148,6 @@ function SelectingBoundaries({ onSelect, formData, ...props }) { setParentBoundaryTypeRoot(boundaryWithTypeNullParent?.boundaryType); } createHierarchyStructure(hierarchyTypeDataresult); - } }, [hierarchyTypeDataresult]); @@ -177,33 +205,42 @@ function SelectingBoundaries({ onSelect, formData, ...props }) { setBoundaryTypeDataresult([{ parentCode: null, boundaryTypeData: boundaryTypeData }]); // closeToast(); } else { - for (const parentCode of parentArray) { - const reqCriteriaBoundaryTypeSearch = Digit.CustomService.getResponse({ - url: "/boundary-service/boundary-relationships/_search", - params: { - tenantId: tenantId, - hierarchyType: hierarchy, - boundaryType: boundaryType, - parent: parentCode, - }, - body: {}, - }); - // setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_LOADING_BOUNDARY") }); - setLoaderEnabled(true); - const boundaryTypeData = await reqCriteriaBoundaryTypeSearch; - newData.push({ parentCode, boundaryTypeData }); - } - setBoundaryTypeDataresult(newData); + // for (const parentCode of parentArray) { + // const reqCriteriaBoundaryTypeSearch = Digit.CustomService.getResponse({ + // url: "/boundary-service/boundary-relationships/_search", + // params: { + // tenantId: tenantId, + // hierarchyType: hierarchy, + // boundaryType: boundaryType, + // parent: parentCode, + // }, + // body: {}, + // }); + // // setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_LOADING_BOUNDARY") }); + // setLoaderEnabled(true); + // const boundaryTypeData = await reqCriteriaBoundaryTypeSearch; + // newData.push({ parentCode, boundaryTypeData }); + // } + setLoaderEnabled(true); + const temp = await Digit.Hooks.campaign.useParallelSearch({ + parentArray: parentArray, + tenantId: tenantId, + boundaryType: boundaryType, + hierarchy: hierarchy, + targetedData: targetedData, + }); + const newDataArray = [...newData, ...temp]; + setBoundaryTypeDataresult(newDataArray); setTimeout(() => { setLoaderEnabled(false); - }, 1000); + }, 100); // closeToast(); } }; useEffect(() => { fetchBoundaryTypeData(); - }, [boundaryType, parentArray ,selectedData]); + }, [boundaryType, parentArray, selectedData]); useEffect(() => { if (boundaryTypeDataresult) { @@ -238,6 +275,7 @@ function SelectingBoundaries({ onSelect, formData, ...props }) { }; const handleBoundaryChange = (data, boundary) => { + setTargetedData(boundary?.boundaryType); if ( !updateBoundary && restrictSelection && @@ -283,21 +321,8 @@ function SelectingBoundaries({ onSelect, formData, ...props }) { // parent: item?.parent, // })); - let transformedRes =[]; - if(!isDraft){ - transformedRes = res?.map((item) => ({ - code: item.code, - type: item.type || item.boundaryType, - isRoot: item.boundaryType === parentBoundaryTypeRoot, - includeAllChildren: item.type === lowestHierarchy || item.boundaryType === lowestHierarchy, - parent: item?.parent, - })); - } - else{ - // transformedRes = selectedData.filter((item) => item?.type === boundary?.boundaryType) - const filteredData = selectedData.filter((item) => item?.type === boundary?.boundaryType); - if (filteredData.length === 0) { - // If no selected data for the particular boundary type, run the transformation logic + let transformedRes = []; + if (!isDraft) { transformedRes = res?.map((item) => ({ code: item.code, type: item.type || item.boundaryType, @@ -306,9 +331,21 @@ function SelectingBoundaries({ onSelect, formData, ...props }) { parent: item?.parent, })); } else { - transformedRes = filteredData; + // transformedRes = selectedData.filter((item) => item?.type === boundary?.boundaryType) + const filteredData = selectedData.filter((item) => item?.type === boundary?.boundaryType); + if (filteredData.length === 0) { + // If no selected data for the particular boundary type, run the transformation logic + transformedRes = res?.map((item) => ({ + code: item.code, + type: item.type || item.boundaryType, + isRoot: item.boundaryType === parentBoundaryTypeRoot, + includeAllChildren: item.type === lowestHierarchy || item.boundaryType === lowestHierarchy, + parent: item?.parent, + })); + } else { + transformedRes = filteredData; + } } - } const newBoundaryType = transformedRes?.[0]?.type; const existingBoundaryType = selectedData?.length > 0 ? selectedData?.[0]?.type : null; @@ -363,7 +400,7 @@ function SelectingBoundaries({ onSelect, formData, ...props }) { return ( <> - {loaderEnabled && } + {loaderEnabled && }
{t(`CAMPAIGN_SELECT_BOUNDARY`)}
@@ -375,64 +412,66 @@ function SelectingBoundaries({ onSelect, formData, ...props }) { // Include only those boundaries that are above or equal to the lowest hierarchy return index <= lowestIndex; }) - .map((boundary, index) => - boundary?.parentBoundaryType == null ? ( - - - {/* {t(`${hierarchy}_${boundary?.boundaryType}`?.toUpperCase())} */} - {t((hierarchy + "_" + boundary?.boundaryType).toUpperCase())} - - * - -
- item?.boundaryTypeData?.TenantBoundary?.[0]?.boundary)?.flat() || []} - optionsKey={"code"} - selected={selectedData?.filter((item) => item?.type === boundary?.boundaryType) || []} - onSelect={(value) => { - handleBoundaryChange(value, boundary); - }} - /> -
-
- ) : ( - - - {t((hierarchy + "_" + boundary?.boundaryType).toUpperCase())} - * - -
- ({ - code: item?.parentCode, - options: - item?.boundaryTypeData?.TenantBoundary?.[0]?.boundary?.map((child) => ({ - code: child?.code, - type: child?.boundaryType, - parent: item?.parentCode, - })) || [], - })) || [] - } - optionsKey={"code"} - onSelect={(value) => { - handleBoundaryChange(value, boundary); - }} - selected={selectedData?.filter((item) => item?.type === boundary?.boundaryType) || []} - addCategorySelectAllCheck={true} - addSelectAllCheck={true} - variant="nestedmultiselect" - /> -
-
- ) - )} + .map((boundary, index) => + boundary?.parentBoundaryType == null ? ( + + + {/* {t(`${hierarchy}_${boundary?.boundaryType}`?.toUpperCase())} */} + {t((hierarchy + "_" + boundary?.boundaryType).toUpperCase())} + + * + +
+ item?.boundaryTypeData?.TenantBoundary?.[0]?.boundary)?.flat() || [] + } + optionsKey={"code"} + selected={selectedData?.filter((item) => item?.type === boundary?.boundaryType) || []} + onSelect={(value) => { + handleBoundaryChange(value, boundary); + }} + /> +
+
+ ) : ( + + + {t((hierarchy + "_" + boundary?.boundaryType).toUpperCase())} + * + +
+ ({ + code: item?.parentCode, + options: + item?.boundaryTypeData?.TenantBoundary?.[0]?.boundary?.map((child) => ({ + code: child?.code, + type: child?.boundaryType, + parent: item?.parentCode, + })) || [], + })) || [] + } + optionsKey={"code"} + onSelect={(value) => { + handleBoundaryChange(value, boundary); + }} + selected={selectedData?.filter((item) => item?.type === boundary?.boundaryType) || []} + addCategorySelectAllCheck={true} + addSelectAllCheck={true} + variant="nestedmultiselect" + /> +
+
+ ) + )}
{showPopUp && ( - + {t("ES_CAMPAIGN_UPDATE_BOUNDARY_MODAL_TEXT") + " "} +
, + ]} + onOverlayClick={() => { + setShowPopUp(false); }} - popmoduleClassName="campaign-pop-module" - popupModuleActionBarClass="campaign-pop-action" - style={{ flex: 1 }} - popupMainModuleClass="campaign-pop-main" - headerBarMain={

{t("ES_CAMPAIGN_UPDATE_BOUNDARY_MODAL_HEADER")}

} - actionCancelLabel={t("ES_CAMPAIGN_BOUNDARY_MODAL_BACK")} - actionCancelOnSubmit={() => checkDataPresent({ action: false })} - actionSaveLabel={t("ES_CAMPAIGN_BOUNDARY_MODAL_SUBMIT")} - actionSaveOnSubmit={() => checkDataPresent({ action: true })} - customTheme="v-campaign" - formId="modal-action" - > -
- {t("ES_CAMPAIGN_UPDATE_BOUNDARY_MODAL_TEXT") + " "} -
- + footerChildren={[ +
- {sheetsData?.[currentSheetName]?.[0].map((header, columnIndex) => ( - - ))} + {sheetsData?.[currentSheetName]?.[0] + ?.filter((header) => header) + .map((header) => ( + + ))} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js new file mode 100644 index 00000000000..75f953c8804 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js @@ -0,0 +1,445 @@ +// Importing necessary modules +import { Card, Header } from "@egovernments/digit-ui-components"; +import L from "leaflet"; +import "leaflet/dist/leaflet.css"; +import React, { useCallback, useEffect, useRef, useState, Fragment } from "react"; +import { useTranslation } from "react-i18next"; +import ZoomControl from "./ZoomControl"; +import CustomScaleControl from "./CustomScaleControl"; +import * as DigitSvgs from "@egovernments/digit-ui-svg-components"; +import { LoaderWithGap } from "@egovernments/digit-ui-react-components"; +import { tourSteps } from "../configs/tourSteps"; +import { useMyContext } from "../utils/context"; +import { + MapFilterIndex, + MapChoroplethIndex, + ChoroplethSelection, + FilterSection, + BoundarySelection, + BaseMapSwitcher, +} from "./MappingHelperComponents"; +import { + enableMapInteractions, + disableMapInteractions, + removeAllLayers, + filterBoundarySelection, + findBounds, + addGeojsonToMap, + addFilterProperties, + addChoroplethProperties, + prepareGeojson, + extractGeoData, +} from "../utils/mappingUtils"; + +const page = "mapping"; + +// Mapping component definition +const Mapping = ({ + campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, + microplanData, + setMicroplanData, + checkDataCompletion, + setCheckDataCompletion, + currentPage, + pages, + setToast, + ...props +}) => { + //fetch campaign data + const { id = "" } = Digit.Hooks.useQueryParams(); + const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( + { + CampaignDetails: { + tenantId: Digit.ULBService.getCurrentTenantId(), + ids: [id], + }, + }, + { + enabled: !!id, + } + ); + + // request body for boundary hierarchy api + var reqCriteria = { + url: `/boundary-service/boundary-hierarchy-definition/_search`, + params: {}, + body: { + BoundaryTypeHierarchySearchCriteria: { + tenantId: Digit.ULBService.getStateId(), + // hierarchyType: "Microplan", + hierarchyType: campaignData?.hierarchyType, + }, + }, + config: { + enabled: !!campaignData?.hierarchyType, + select: (data) => { + return ( + data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map((item) => ({ + ...item, + parentBoundaryType: item?.parentBoundaryType + ? `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.parentBoundaryType)}` + : null, + boundaryType: `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}`, + })) || {} + ); + }, + }, + }; + const { isLoading: ishierarchyLoading, data: hierarchy } = Digit.Hooks.useCustomAPIHook(reqCriteria); + // request body for boundary hierarchy api + var reqCriteria = { + url: `/boundary-service/boundary/_search`, + params: { codes: Digit.ULBService.getCurrentTenantId(), tenantId: Digit.ULBService.getCurrentTenantId() }, + body: {}, + config: { + select: (data) => { + return data?.Boundary || {}; + }, + }, + }; + const { isLoading: isBoundaryLoading, data: Boundary } = Digit.Hooks.useCustomAPIHook(reqCriteria); + + // Setting up state variables + const [editable, setEditable] = useState(true); + const { t } = useTranslation(); + var [map, setMap] = useState(null); + var [_mapNode, set__mapNode] = useState("map"); + const [layers, setLayer] = useState([]); + const [validationSchemas, setValidationSchemas] = useState([]); + const [filterDataOrigin, setFilterDataOrigin] = useState({}); + const [dataAvailability, setDataAvailability] = useState("true"); + // const [toast, setToast] = useState(); + const [baseMaps, setBaseMaps] = useState({}); + const [selectedBaseMap, setSelectedBaseMap] = useState({}); + const [selectedBaseMapName, setSelectedBaseMapName] = useState(""); + const [showBaseMapSelector, setShowBaseMapSelector] = useState(false); + const [boundaryData, setBoundaryData] = useState({}); // State for boundary data + const [filterData, setFilterData] = useState({}); // State for facility data + const [boundarySelections, setBoundarySelections] = useState({}); + const [isboundarySelectionSelected, setIsboundarySelectionSelected] = useState(false); + const { state, dispatch } = useMyContext(); + const [filterPropertyNames, setFilterPropertyNames] = useState(); + const [filterProperties, setFilterProperties] = useState(); + const [showFilterOptions, setShowFilterOptions] = useState(false); + const [filterSelections, setFilterSelections] = useState([]); + const [choroplethProperties, setChoroplethProperties] = useState([]); + const [showChoroplethOptions, setShowChoroplethOptions] = useState(false); + const [choroplethProperty, setChoroplethProperty] = useState(); + const [dataCompleteness, setDataCompleteness] = useState(); + const basemapRef = useRef(); + const filterBoundaryRef = useRef(); + const showChoroplethOptionRef = useRef(); + const showFilterOptionRef = useRef(); + const [loader, setLoader] = useState(false); + + // Set TourSteps + useEffect(() => { + const tourData = tourSteps(t)?.[page] || {}; + if (state?.tourStateData?.name === page) return; + dispatch({ + type: "SETINITDATA", + state: { tourStateData: tourData }, + }); + }, []); + + // Effect to initialize map when data is fetched + useEffect(() => { + if (!state || !Boundary) return; + const UIConfiguration = state?.UIConfiguration; + if (UIConfiguration) { + const filterDataOriginList = UIConfiguration.find((item) => item.name === "mapping"); + setFilterDataOrigin(filterDataOriginList); + } + const BaseMapLayers = state?.BaseMapLayers; + const schemas = state?.Schemas; + if (schemas) setValidationSchemas(schemas); + if (!BaseMapLayers || (BaseMapLayers && BaseMapLayers.length === 0)) return; + let baseMaps = {}; + let defaultBaseMap = undefined; + BaseMapLayers.forEach((item) => { + if (item.url) { + const layer = L.tileLayer(item.url, { + minZoom: item?.minZoom, + maxZoom: item?.maxZoom, + attribution: item?.attribution, + }); + baseMaps[item?.name] = { + metadata: item, + layer, + }; + if (!defaultBaseMap) + defaultBaseMap = { + name: item?.name, + layer, + }; + } + }); + setSelectedBaseMapName(defaultBaseMap?.name); + setBaseMaps(baseMaps); + if (!map) { + init(_mapNode, defaultBaseMap, Boundary); + } + }, [Boundary]); + + useEffect(() => { + if (map && filterDataOrigin && Object.keys(filterDataOrigin).length !== 0) { + setLoader("LOADING"); + // Check if all the data is present or not, if it is then extract it in a format that can be used for mapping and other mapping related operations + extractGeoData( + campaignType, + microplanData, + filterDataOrigin, + validationSchemas, + setToast, + setDataAvailability, + hierarchy, + setBoundaryData, + setFilterData, + setFilterProperties, + setFilterSelections, + setFilterPropertyNames, + state, + setChoroplethProperties, + setDataCompleteness, + t + ); + setLoader(false); + } + }, [filterDataOrigin, hierarchy]); + + // Function to initialize map + const init = (id, defaultBaseMap, Boundary) => { + if (map !== null) return; + + // let bounds = findBounds(Boundary); + + let mapConfig = { + center: [0, 0], + zoomControl: false, + zoom: 3, + scrollwheel: true, + minZoom: 3, + }; + + let map_i = L.map(id, mapConfig); + var verticalBounds = L.latLngBounds(L.latLng(-90, -170), L.latLng(85, 190)); + map_i.on("drag", () => { + map_i.panInsideBounds(verticalBounds, { animate: true }); + }); + map_i.on("zoom", () => { + map_i.panInsideBounds(verticalBounds, { animate: true }); + }); + const defaultBaseLayer = defaultBaseMap?.layer.addTo(map_i); + // if (bounds) map_i.fitBounds(bounds); + setSelectedBaseMap(defaultBaseLayer); + setMap(map_i); + }; + + const handleBaseMapToggle = (newBaseMap) => { + if (map) { + const currentBaseLayer = selectedBaseMap; + if (currentBaseLayer) { + currentBaseLayer.remove(); + } + const newBaseLayer = baseMaps[newBaseMap].layer.addTo(map); + // Add the new base layer to the bottom of the layer stack + newBaseLayer.addTo(map); + + // Update the baseLayer state + setSelectedBaseMap(newBaseLayer); + setSelectedBaseMapName(newBaseMap); + } + }; + + // showing selected boundary data + useEffect(() => { + if (!boundarySelections && !choroplethProperty && !filterSelections) return; + setLoader("LOADING"); + try { + removeAllLayers(map, layers); + const { filteredSelection, childrenList } = filterBoundarySelection(boundaryData, boundarySelections); + let newLayer = []; + let addOn = { + fillColor: "rgba(255, 107, 43, 0)", + weight: 3.5, + opacity: 1, + color: "rgba(176, 176, 176, 1)", + fillOpacity: 0, + fill: "rgb(4,136,219,1)", + child: !childrenList || childrenList.length === 0, // so that this layer also has mounse in and mouse out events + }; + let geojsonsBase = prepareGeojson(boundaryData, "ALL", addOn); + if (geojsonsBase) { + let baseLayer = addGeojsonToMap(map, geojsonsBase, t); + if (baseLayer) newLayer.push(baseLayer); + let bounds = findBounds(geojsonsBase); + if (bounds) map.fitBounds(bounds); + } + + addOn = { + fillColor: "rgba(255, 107, 43, 1)", + weight: 2.5, + opacity: 1, + color: "rgba(255, 255, 255, 1)", + fillOpacity: 0.22, + fill: "rgb(4,136,219)", + }; + + let geojsonLayer; + if (choroplethProperty) { + if (dataCompleteness === "partial" || dataCompleteness === "false" || dataCompleteness === undefined) { + setToast({ + state: "warning", + message: t("DISPLAYING_DATA_ONLY_FOR_UPLOADED_BOUNDARIES"), + }); + } + + let choroplethGeojson = prepareGeojson(boundaryData, "ALL", { ...addOn, child: true, fillColor: "rgb(0,0,0,0)" }) || []; + if (choroplethGeojson && choroplethGeojson.length !== 0) + choroplethGeojson = addChoroplethProperties(choroplethGeojson, choroplethProperty, filteredSelection); + geojsonLayer = addGeojsonToMap(map, choroplethGeojson, t); + if (geojsonLayer) { + newLayer.push(geojsonLayer); + } + } + geojsonLayer = null; + const geojsons = prepareGeojson(boundaryData, filteredSelection, addOn); + if (geojsons && geojsons.length > 0) { + geojsonLayer = addGeojsonToMap(map, geojsons, t); + newLayer.push(geojsonLayer); + let bounds = findBounds(geojsons); + if (bounds) map.fitBounds(bounds); + } + + const childrenGeojson = prepareGeojson(boundaryData, childrenList, { ...addOn, opacity: 0, fillOpacity: 0, child: true }); + let childrenGeojsonLayer = addGeojsonToMap(map, childrenGeojson, t); + if (childrenGeojsonLayer) newLayer.push(childrenGeojsonLayer); + + //filters + const filterGeojsons = prepareGeojson(filterData, filteredSelection && filteredSelection.length !== 0 ? filteredSelection : "ALL", addOn); + const filterGeojsonWithProperties = addFilterProperties(filterGeojsons, filterSelections, filterPropertyNames, state?.MapFilters); + let filterGeojsonLayer = addGeojsonToMap(map, filterGeojsonWithProperties, t); + if (filterGeojsonLayer) newLayer.push(filterGeojsonLayer); + + setLayer(newLayer); + } catch (error) { + console.error("Error while adding geojson to map: ", error.message); + } + setLoader(false); + }, [boundarySelections, choroplethProperty, filterSelections]); + + const handleOutsideClickAndSubmitSimultaneously = useCallback(() => { + if (isboundarySelectionSelected) setIsboundarySelectionSelected(false); + if (showBaseMapSelector) setShowBaseMapSelector(false); + if (showFilterOptions) setShowFilterOptions(false); + if (showChoroplethOptions) setShowChoroplethOptions(false); + }, [ + isboundarySelectionSelected, + showBaseMapSelector, + showFilterOptions, + showChoroplethOptions, + setIsboundarySelectionSelected, + setShowBaseMapSelector, + setShowFilterOptions, + setShowChoroplethOptions, + ]); + Digit?.Hooks.useClickOutside(filterBoundaryRef, handleOutsideClickAndSubmitSimultaneously, isboundarySelectionSelected, { capture: true }); + Digit?.Hooks.useClickOutside(basemapRef, handleOutsideClickAndSubmitSimultaneously, showBaseMapSelector, { capture: true }); + Digit?.Hooks.useClickOutside(showFilterOptionRef, handleOutsideClickAndSubmitSimultaneously, showFilterOptions, { capture: true }); + Digit?.Hooks.useClickOutside(showChoroplethOptionRef, handleOutsideClickAndSubmitSimultaneously, showChoroplethOptions, { capture: true }); + + // function to stop mouse event propogation from custom comopents to leaflet map + const handleMouseDownAndScroll = (event) => { + event?.stopPropagation(); + disableMapInteractions(map); + }; + + const handleMouseUpAndScroll = (event) => { + enableMapInteractions(map); + }; + useEffect(() => { + if (isboundarySelectionSelected || showBaseMapSelector || showFilterOptions || showChoroplethOptions) handleMouseDownAndScroll(); + else handleMouseUpAndScroll(); + }, [isboundarySelectionSelected, showBaseMapSelector, showFilterOptions, showChoroplethOptions, choroplethProperty, filterPropertyNames]); + + // Rendering component + return ( +
+
{t("MAPPING")}
+ + + {/* Container for map */} + +
+
+
+ +
+ {filterProperties && Object.keys(filterProperties).length !== 0 && ( + + )} + +
+ +
+ +
+ {DigitSvgs.NorthArrow && } +
+ +
+ +
+ {filterSelections && filterSelections.length > 0 && ( + + )} + {choroplethProperty && } +
+
+
+
+ {loader && } +
+ ); +}; + +// Exporting Mapping component +export default Mapping; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MappingHelperComponents.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MappingHelperComponents.js new file mode 100644 index 00000000000..9cea19a943f --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MappingHelperComponents.js @@ -0,0 +1,513 @@ +// Importing necessary modules +import { Card, CardLabel, MultiSelectDropdown, Button, CheckBox, RadioButtons } from "@egovernments/digit-ui-components"; +import "leaflet/dist/leaflet.css"; +import React, { memo, useCallback, useEffect, useMemo, useRef, useState, Fragment } from "react"; +import * as DigitSvgs from "@egovernments/digit-ui-svg-components"; +import { CardSectionHeader, InfoIconOutline, LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; +import { fetchDropdownValues } from "../utils/processHierarchyAndData"; +import { MapChoroplethGradientColors, PRIMARY_THEME_COLOR } from "../configs/constants"; +import { ModalHeading } from "./CommonComponents"; +import * as MicroplanIconCollection from "../icons/Svg"; +import { generatePreviewUrl } from "../utils/mappingUtils"; + +const IconCollection = { ...MicroplanIconCollection, ...DigitSvgs }; + +export function checkTruthyKeys(obj) { + for (let key in obj) { + if (Object.hasOwn(obj, key)) { + if (obj[key] && !(Array.isArray(obj[key]) && obj[key].length === 0)) { + return true; + } + } + } + return false; +} + +export const MapFilterIndex = ({ filterSelections, MapFilters, t }) => { + return ( +
+ {filterSelections && filterSelections.length > 0 ? ( + <> + {filterSelections.map((item, index) => ( + //
+ + //

{t(item)}

+ //
+ ))} + + ) : ( + "" + )} +
+ ); +}; + +// Function to create the gradient from the colors array for choropleth index +export const MapChoroplethIndex = ({ t, choroplethProperty }) => { + const createGradientString = (colors) => { + return colors.map((color) => `${color.color} ${color.percent}%`).join(", "); + }; + + const gradientString = createGradientString(MapChoroplethGradientColors); + const gradientStyle = { + background: `linear-gradient(to right, ${gradientString})`, + }; + + return ( +
+
+

0%

+
+

100%

+
+

{t(choroplethProperty)}

+
+ ); +}; + +export const FilterItemBuilder = ({ item, MapFilters, t }) => { + let temp = MapFilters?.find((e) => e?.name === item)?.icon?.index; + let DynamicIcon = IconCollection?.[temp]; + // let icon; + // if (typeof DynamicIcon === "function") icon = DynamicIcon({}); + return DynamicIcon && typeof DynamicIcon === "function" ? ( +
+ +

{t(item)}

+
+ ) : ( + //
+ "" + ); +}; + +export const ChoroplethSelection = memo( + ({ + choroplethProperties, + showChoroplethOptions, + showChoroplethOptionRef, + setShowChoroplethOptions, + choroplethProperty, + setChoroplethProperty, + t, + }) => { + const handleChange = useCallback( + (value) => { + setChoroplethProperty(value?.code); + }, + [choroplethProperties] + ); + + return ( +
+
setShowChoroplethOptions((previous) => !previous)} + onKeyUp={() => setShowChoroplethOptions((previous) => !previous)} + tabIndex={0} + > +

{t("VISUALIZATIONS")}

+
+ {DigitSvgs.FilterAlt && } +
+
+ {showChoroplethOptions && ( +
+
+ ({ name: item, id: item, code: item }))} + optionsKey="name" + onSelect={handleChange} + selectedOption={choroplethProperty} + /> +
+
+ )} +
+ ); + } +); + +export const FilterSection = memo( + ({ filterProperties, showFilterOptionRef, showFilterOptions, setShowFilterOptions, filterSelections, setFilterSelections, t }) => { + const handleChange = useCallback( + (e, item) => { + let tempFilterSelections = [...filterSelections]; // Clone the array to avoid mutating state directly + if (filterSelections.includes(item)) { + tempFilterSelections = tempFilterSelections.filter((element) => element !== item); + } else { + tempFilterSelections.push(item); + } + setFilterSelections(tempFilterSelections); + }, + [filterSelections] + ); + + return ( +
+
setShowFilterOptions((previous) => !previous)} + onKeyUp={() => setShowFilterOptions((previous) => !previous)} + tabIndex={0} + > +

{t("FILTERS")}

+
+ {DigitSvgs.FilterAlt && } +
+
+ {showFilterOptions && ( +
+
+ {filterProperties.map((item) => ( +
+ handleChange(e, item)} + label={t(item)} + checked={!!filterSelections.includes(item)} + mainClassName="mainClassName" + labelClassName="labelClassName" + inputWrapperClassName="inputWrapperClassName" + inputClassName="inputClassName" + inputIconClassname="inputIconClassname" + iconFill={PRIMARY_THEME_COLOR} + onLabelClick={(e) => handleChange(e, item)} + /> +
+ ))} +
+
+ )} +
+ ); + } +); + +export const BoundarySelection = memo( + ({ + boundarySelections, + setBoundarySelections, + boundaryData, + hierarchy, + filterBoundaryRef, + isboundarySelectionSelected, + setIsboundarySelectionSelected, + t, + }) => { + const [processedHierarchy, setProcessedHierarchy] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [showConfirmationModal, setShowConformationModal] = useState(false); + const itemRefs = useRef([]); + const [expandedIndex, setExpandedIndex] = useState(null); + const scrollContainerRef = useRef(null); + const [changedBoundaryType, setChangedBoundaryType] = useState(""); + const [isScrollable, setIsScrollable] = useState(false); + + useEffect(() => { + // Scroll to the expanded item's child element after the state has updated and the DOM has re-rendered + if (expandedIndex !== null && itemRefs.current[expandedIndex]) { + // Use a timeout to ensure the DOM has updated + setTimeout(() => { + const childElement = itemRefs.current[expandedIndex].children[0]; // Assuming child content is the second child + // if (childElement) { + // childElement.scrollIntoView({ behavior: 'smooth' }); + // } + if (childElement) { + const scrollContainer = scrollContainerRef.current; + const childElementBound = childElement.getBoundingClientRect(); + const containerRect = scrollContainer.getBoundingClientRect(); + + // Calculate the offset from the top of the container + const offset = childElementBound.top - containerRect.top; + + // Scroll the container + scrollContainer.scrollTo({ + top: scrollContainer.scrollTop + offset - 10, + behavior: "smooth", + }); + } + }, 0); + } + }, [expandedIndex]); + + const toggleExpand = (index) => { + setExpandedIndex(index === expandedIndex ? null : index); + }; + + // Filtering out dropdown values + useEffect(() => { + if (!boundaryData || !hierarchy) return; + const processedHierarchyTemp = fetchDropdownValues( + boundaryData, + processedHierarchy.length !== 0 ? processedHierarchy : hierarchy, + boundarySelections, + changedBoundaryType + ); + setProcessedHierarchy(processedHierarchyTemp); + setIsLoading(false); + }, [boundaryData, hierarchy, boundarySelections]); + + const handleClearAll = () => { + setShowConformationModal(true); + }; + + const handleSubmitConfModal = () => { + setBoundarySelections({}); + setShowConformationModal(false); + }; + + const handleCancelConfModal = () => { + setShowConformationModal(false); + }; + + const checkScrollbar = () => { + if (scrollContainerRef.current) { + setIsScrollable(scrollContainerRef.current.scrollHeight > scrollContainerRef.current.clientHeight); + } + }; + + useEffect(() => { + // Initial check + checkScrollbar(); + + // Check on resize + window.addEventListener("resize", checkScrollbar); + + // Cleanup event listeners on component unmount + return () => { + window.removeEventListener("resize", checkScrollbar); + }; + }, [isboundarySelectionSelected]); + + useEffect(() => { + const content = scrollContainerRef.current; + content.addEventListener("scroll", checkScrollbar); + + return () => { + content.removeEventListener("scroll", checkScrollbar); + }; + }, [scrollContainerRef]); + + return ( +
+ {isLoading && } +
+ ); + } +); + +export const BaseMapSwitcher = ({ + baseMaps, + showBaseMapSelector, + setShowBaseMapSelector, + handleBaseMapToggle, + selectedBaseMapName, + basemapRef, + t, +}) => { + if (!baseMaps) return null; + return ( +
+
setShowBaseMapSelector((previous) => !previous)} + onKeyUp={() => setShowBaseMapSelector((previous) => !previous)} + tabIndex={0} + > +

{t("LAYERS")}

+
{DigitSvgs.Layers && }
+
+
+ {showBaseMapSelector && ( +
+ {Object.entries(baseMaps).map(([name, baseMap], index) => { + return ( +
+ {t("ERROR_LOADING_BASE_MAP")} handleBaseMapToggle(name)} + /> +

{t(name)}

+
+ ); + })} +
+ )} +
+
+ ); +}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js similarity index 79% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js index 92a414cd292..b6a2fb9a205 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js @@ -2,11 +2,12 @@ import React, { memo } from "react"; import { ActionBar, ArrowForward, Banner } from "@egovernments/digit-ui-components"; import { useTranslation } from "react-i18next"; import { ArrowBack, FileDownload } from "@egovernments/digit-ui-svg-components"; -import { convertJsonToXlsx } from "../utils/jsonToExcelBlob"; +import { convertJsonToXlsx, writeWorkbookToBuffer } from "../utils/jsonToExcelBlob"; import { Button } from "@egovernments/digit-ui-react-components"; import { useHistory } from "react-router-dom"; import { Link } from "react-router-dom/cjs/react-router-dom.min"; -import { PRIMARY_THEME_COLOR } from "../configs/constants"; +import { PRIMARY_THEME_COLOR, commonColumn } from "../configs/constants"; +import { colorHeaders } from "../utils/uploadUtils"; const MicroplanCreatedScreen = memo(({ microplanData, ...props }) => { const { t } = useTranslation(); @@ -15,13 +16,20 @@ const MicroplanCreatedScreen = memo(({ microplanData, ...props }) => { const downloadMicroplan = async () => { try { if (!microplanData?.microplanPreview) return; - let data = _.cloneDeep(microplanData?.microplanPreview?.previewData); + const data = _.cloneDeep(microplanData?.microplanPreview?.previewData); + const commonColumnIndex = data[0]?.findIndex((item) => item === commonColumn); data[0] = data[0].map((item) => t(item)); - for (let i in data) { - data[i] = data[i].map((item) => (item ? t(item) : t("NO_DATA"))); + + for (const i in data) { + data[i] = data[i].map((item, index) => + item ? (typeof item === "number" ? item : index === commonColumnIndex ? item : t(item)) : t("NO_DATA") + ); } - const blob = await convertJsonToXlsx({ [microplanData?.microplanDetails?.name]: data }); + const headers = data?.[0] || []; + const workbook = await convertJsonToXlsx({ [microplanData?.microplanDetails?.name]: data }, {}, true); + colorHeaders(workbook, headers, [], []); + const blob = await writeWorkbookToBuffer(workbook); if (!blob) { return; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js similarity index 98% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js index 798365da95f..fbc73bd6569 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js @@ -275,7 +275,7 @@ const MicroplanDetails = ({ additionalElements={[
{state?.UIConfiguration?.find((item) => item.name === "microplanNamingConvention")?.microplanNamingConvention?.map((item, index) => ( -
+

{t(index + 1)}.

diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js new file mode 100644 index 00000000000..1be6619e7a7 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js @@ -0,0 +1,478 @@ +import { Header, Loader } from "@egovernments/digit-ui-components"; +import React, { useCallback, useEffect, useMemo, useState, Fragment } from "react"; +import { useTranslation } from "react-i18next"; +import { processHierarchyAndData } from "../utils/processHierarchyAndData"; +import { ModalHeading } from "./CommonComponents"; +import { PRIMARY_THEME_COLOR } from "../configs/constants"; +import { LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; +import { tourSteps } from "../configs/tourSteps"; +import { useMyContext } from "../utils/context"; +import { + fetchMicroplanPreviewData, + filterObjects, + updateHyothesisAPICall, + filterMicroplanDataToShowWithHierarchySelection, +} from "../utils/microplanPreviewUtils"; +import { + HypothesisValues, + BoundarySelection, + DataPreview, + AppplyChangedHypothesisConfirmation, + Aggregates, +} from "./MicroplanPreviewHelperCompoenents"; + +const page = "microplanPreview"; + +const MicroplanPreview = ({ + campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, + microplanData, + setMicroplanData, + checkDataCompletion, + setCheckDataCompletion, + currentPage, + pages, + navigationEvent, + setToast, + ...props +}) => { + const { mutate: UpdateMutate } = Digit.Hooks.microplan.useUpdatePlanConfig(); + const userInfo = Digit.SessionStorage.get("User")?.info; + const { id: campaignId = "" } = Digit.Hooks.useQueryParams(); + const { t } = useTranslation(); + const [hypothesisAssumptionsList, setHypothesisAssumptionsList] = useState([]); + const [data, setData] = useState([]); + const [dataToShow, setDataToShow] = useState([]); + const [joinByColumns, setJoinByColumns] = useState([]); + const [validationSchemas, setValidationSchemas] = useState([]); + const [resources, setResources] = useState([]); + const [formulaConfiguration, setFormulaConfiguration] = useState([]); + const [boundarySelections, setBoundarySelections] = useState({}); // state for hierarchy from the data available from uploaded data + const [boundaryData, setBoundaryData] = useState({}); // State for boundary data + // const [toast, setToast] = useState(); + const [modal, setModal] = useState("none"); + const [operatorsObject, setOperatorsObject] = useState([]); + + const [loaderActivation, setLoaderActivation] = useState(false); + + const [userEditedResources, setUserEditedResources] = useState({}); // state to maintain a record of the resources that the user has edited ( boundaryCode : {resource : value}) + const [microplanPreviewAggregates, setMicroplaPreviewAggregates] = useState(); + const { state, dispatch } = useMyContext(); + const [updateHypothesis, setUpdateHypothesis] = useState(false); + //fetch campaign data + const { id = "" } = Digit.Hooks.useQueryParams(); + const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( + { + CampaignDetails: { + tenantId: Digit.ULBService.getCurrentTenantId(), + ids: [id], + }, + }, + { + enabled: !!id, + } + ); + + // request body for boundary hierarchy api + const reqCriteria = { + url: `/boundary-service/boundary-hierarchy-definition/_search`, + params: {}, + body: { + BoundaryTypeHierarchySearchCriteria: { + tenantId: Digit.ULBService.getStateId(), + hierarchyType: campaignData?.hierarchyType, + }, + }, + config: { + enabled: !!campaignData?.hierarchyType, + select: (data) => { + return ( + data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map((item) => ({ + ...item, + parentBoundaryType: item?.parentBoundaryType + ? `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.parentBoundaryType)}` + : null, + boundaryType: `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}`, + })) || {} + ); + }, + }, + }; + const { isLoading: ishierarchyLoading, data: hierarchyRawData } = Digit.Hooks.useCustomAPIHook(reqCriteria); + const hierarchy = useMemo(() => { + return hierarchyRawData?.map((item) => item?.boundaryType); + }, [hierarchyRawData]); + // Set TourSteps + useEffect(() => { + const tourData = tourSteps(t)?.[page] || {}; + if (state?.tourStateData?.name === page) return; + dispatch({ + type: "SETINITDATA", + state: { tourStateData: tourData }, + }); + }, []); + + // UseEffect to extract data on first render + useEffect(() => { + if (microplanData && (microplanData?.ruleEngine || microplanData?.hypothesis)) { + const hypothesisAssumptions = microplanData?.hypothesis || []; + const formulaConfiguration = microplanData?.ruleEngine?.filter((item) => Object.values(item).every((key) => key !== "")) || []; + if (hypothesisAssumptions.length !== 0 && hypothesisAssumptionsList.length === 0) { + setHypothesisAssumptionsList(hypothesisAssumptions); + } + if (formulaConfiguration.length !== 0) { + setFormulaConfiguration(formulaConfiguration); + } + } + if (microplanData?.microplanPreview?.userEditedResources) { + setUserEditedResources(microplanData?.microplanPreview?.userEditedResources); + } + }, []); + + // Fetch and assign MDMS data + useEffect(() => { + if (!state) return; + const UIConfiguration = state?.UIConfiguration; + const schemas = state?.Schemas; + let resourcelist = state?.Resources; + let microplanPreviewAggregatesList = state?.MicroplanPreviewAggregates; + microplanPreviewAggregatesList = microplanPreviewAggregatesList.find((item) => item.campaignType === campaignType)?.data; + if (schemas) setValidationSchemas(schemas); + resourcelist = resourcelist.find((item) => item.campaignType === campaignType)?.data; + if (resourcelist) setResources(resourcelist); + if (UIConfiguration) { + const joinWithColumns = UIConfiguration.find((item) => item.name === "microplanPreview")?.joinWithColumns; + setJoinByColumns(joinWithColumns); + } + let temp; + if (UIConfiguration) temp = UIConfiguration.find((item) => item.name === "ruleConfigure"); + if (temp?.ruleConfigureOperators) { + setOperatorsObject(temp.ruleConfigureOperators); + } + if (microplanPreviewAggregatesList) setMicroplaPreviewAggregates(microplanPreviewAggregatesList); + }, []); + + // UseEffect for checking completeness of data before moveing to next section + useEffect(() => { + if (!dataToShow || checkDataCompletion !== "true" || !setCheckDataCompletion) return; + const check = filterObjects(hypothesisAssumptionsList, microplanData?.hypothesis); + if (check.length === 0) { + if (navigationEvent?.name === "next") return setModal("confirm-microplan-generation"); + return createMicroplan(false, false); + } + setModal("confirm-apply-changed-hypothesis"); + }, [checkDataCompletion]); + + // check if data has changed or not + const updateData = useCallback( + (doPerform) => { + // Update the microplan data with selected hierarchy and resources + // This function also handles setting the completion check based on the action to be performed + if (!setMicroplanData) return; + try { + let tempData = filterMicroplanDataToShowWithHierarchySelection(data, {}, hierarchy); + // Adding resources to the data we need to show + tempData = Digit.Utils.microplan.addResourcesToFilteredDataToShow( + tempData, + resources, + hypothesisAssumptionsList, + formulaConfiguration, + userEditedResources, + t + ); + setMicroplanData((previous) => ({ + ...previous, + microplanPreview: { + previewData: tempData, + userEditedResources, + }, + })); + if (doPerform) { + return setCheckDataCompletion("perform-action"); + } + setCheckDataCompletion("false"); + } catch (error) { + console.error("Failed to update data:", error); + } + }, + [ + resources, + boundarySelections, + hierarchy, + hypothesisAssumptionsList, + formulaConfiguration, + userEditedResources, + setMicroplanData, + setCheckDataCompletion, + ] + ); + + const cancelUpdateData = useCallback(() => { + setUpdateHypothesis(false); + if (navigationEvent?.name === "next") setModal("confirm-microplan-generation"); + else createMicroplan(false, false); + }, [setCheckDataCompletion, setModal]); + + useEffect(() => { + if (boundarySelections && Object.values(boundarySelections).every((item) => item.length === 0) && hierarchy) { + const tempBoundarySelection = {}; + for (const item of hierarchy) { + tempBoundarySelection[item] = []; + } + setBoundarySelections(tempBoundarySelection); + } + }, [hierarchy]); + + // UseEffect to add a event listener for keyboard + useEffect(() => { + window.addEventListener("keydown", handleKeyPress); + + return () => window.removeEventListener("keydown", handleKeyPress); + }, [modal]); + + const handleKeyPress = (event) => { + // if (modal !== "upload-guidelines") return; + if (["x", "Escape"].includes(event.key)) { + // Perform the desired action when "x" or "esc" is pressed + setCheckDataCompletion("false"); + setModal("none"); + } + }; + + const cancleNavigation = () => { + if (navigationEvent?.name !== "next") setCheckDataCompletion("false"); + setModal("none"); + }; + + const createMicroplan = useCallback( + (doCreation, updateHypothesis) => { + if (!hypothesisAssumptionsList || !setMicroplanData) return; + const updateDataWrapper = () => { + if (doCreation || navigationEvent?.name !== "next") { + return updateData(true); + } + updateData(false); + }; + const setCheckDataCompletionWrapper = (value) => { + if (!doCreation) { + return setCheckDataCompletion("false"); + } + setCheckDataCompletion(value); + }; + const microData = updateHypothesis ? updateMicroplanData(hypothesisAssumptionsList) : microplanData; + setLoaderActivation(true); + updateHyothesisAPICall( + microData, + setMicroplanData, + operatorsObject, + microData?.microplanDetails?.name, + campaignId, + UpdateMutate, + setToast, + updateDataWrapper, + setLoaderActivation, + doCreation && navigationEvent?.name === "next" ? "GENERATED" : "DRAFT", + cancleNavigation, + state, + campaignType, + navigationEvent, + setCheckDataCompletionWrapper, + t + ); + + setUpdateHypothesis(false); + setModal("none"); + }, + [ + hypothesisAssumptionsList, + setMicroplanData, + operatorsObject, + campaignId, + UpdateMutate, + setToast, + updateData, + setLoaderActivation, + navigationEvent, + t, + ] + ); + + const updateMicroplanData = useCallback( + (hypothesisAssumptionsList) => { + let microData = {}; + setMicroplanData((previous) => { + microData = { ...previous, hypothesis: hypothesisAssumptionsList }; + return microData; + }); + return microData; + }, + [setMicroplanData] + ); + + // Set microplan preview data + useEffect(() => { + if (data?.length !== 0 || !hierarchyRawData || !hierarchy || validationSchemas?.length === 0) return; + + const combinedData = fetchMicroplanPreviewData(campaignType, microplanData, validationSchemas, hierarchy); + // process and form hierarchy + if (combinedData && hierarchy) { + const { hierarchyLists, hierarchicalData } = processHierarchyAndData(hierarchyRawData, [combinedData]); + setBoundaryData({ Microplan: { hierarchyLists, hierarchicalData } }); + } + if (combinedData) { + setData(combinedData); + setDataToShow(combinedData); + } + }, [hierarchy, hierarchyRawData, microplanData]); + + useEffect(() => { + if (!boundarySelections && !resources) return; + let tempData = filterMicroplanDataToShowWithHierarchySelection(data, boundarySelections, hierarchy); + // Adding resources to the data we need to show + tempData = Digit.Utils.microplan.addResourcesToFilteredDataToShow( + tempData, + resources, + hypothesisAssumptionsList, + formulaConfiguration, + userEditedResources, + t + ); + setDataToShow(tempData); + setMicroplanData((previous) => ({ ...previous, microplanPreview: { ...previous.microplanPreview, previewData: tempData, userEditedResources } })); + }, [boundarySelections, resources, hypothesisAssumptionsList, userEditedResources]); + + if (isCampaignLoading || ishierarchyLoading) { + return ( +
+ +
+ ); + } + + return ( + <> +
+
+

{t(campaignData?.campaignName)}

+
{t(microplanData?.microplanDetails?.name)}
+

{t("MICROPLAN_PREVIEW_CREATE_BY", { username: userInfo?.name })}

+
+
+
+ +
+
+ +
+
+

{t("MICROPLAN_PREVIEW_HYPOTHESIS_HEADING")}

+

{t("MICROPLAN_PREVIEW_HYPOTHESIS_INSTRUCTIONS")}

+ +
+
+ {dataToShow?.length != 0 ? ( + + ) : ( +
{t("NO_DATA_AVAILABLE")}
+ )} +
+
+ {modal === "confirm-apply-changed-hypothesis" && ( + } + actionCancelLabel={t("YES")} + actionCancelOnSubmit={() => { + setUpdateHypothesis(true); + if (navigationEvent?.name === "next") setModal("confirm-microplan-generation"); + else createMicroplan(false, true); + }} + actionSaveLabel={t("NO")} + actionSaveOnSubmit={cancelUpdateData} + formId="modal-action" + > + + + )} + {modal === "confirm-microplan-generation" && ( + } + actionCancelLabel={t("YES")} + actionCancelOnSubmit={() => createMicroplan(true, updateHypothesis)} + actionSaveLabel={t("NO")} + actionSaveOnSubmit={() => createMicroplan(false, updateHypothesis)} + formId="modal-action" + > +
+

{t("INSTRUCTIONS_MICROPLAN_GENERATION_CONFIRMATION")}

+
+
+ )} +
+ {loaderActivation && } + + ); +}; + +export default MicroplanPreview; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js new file mode 100644 index 00000000000..e92335d6581 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js @@ -0,0 +1,434 @@ +import { CardLabel, Loader, MultiSelectDropdown, TextInput } from "@egovernments/digit-ui-components"; +import React, { memo, useCallback, useEffect, useMemo, useState, Fragment, useRef } from "react"; +import { fetchDropdownValues } from "../utils/processHierarchyAndData"; +import { CloseButton, ModalHeading } from "./CommonComponents"; +import { PRIMARY_THEME_COLOR, commonColumn } from "../configs/constants"; +import { Button, LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; +import { useNumberFormatter } from "../hooks/useNumberFormatter"; +import { calculateAggregateValue, filterObjects, useHypothesis } from "../utils/microplanPreviewUtils"; + +export const HypothesisValues = memo(({ boundarySelections, hypothesisAssumptionsList, setHypothesisAssumptionsList, setToast, setModal, t }) => { + const [tempHypothesisList, setTempHypothesisList] = useState(hypothesisAssumptionsList || []); + const { valueChangeHandler } = useHypothesis(tempHypothesisList, hypothesisAssumptionsList); + const contentRef = useRef(null); + const [isScrollable, setIsScrollable] = useState(false); + + const applyNewHypothesis = () => { + if (tempHypothesisList.some((item) => item.active && (Number.isNaN(parseFloat(item.value)) || parseFloat(item.value) === 0))) { + setToast({ state: "error", message: t("ERROR_HYPOTHESIS_VALUE_SHOULD_NOT_BE_ZERO") }); + return; + } + if (Object.keys(boundarySelections).length !== 0 && Object.values(boundarySelections)?.every((item) => item?.length !== 0)) + return setToast({ state: "error", message: t("HYPOTHESIS_CAN_BE_ONLY_APPLIED_ON_ADMIN_LEVEL_ZORO") }); + setHypothesisAssumptionsList(tempHypothesisList); + }; + const checkScrollbar = () => { + if (contentRef.current) { + setIsScrollable(contentRef.current.scrollHeight > contentRef.current.clientHeight); + } + }; + + useEffect(() => { + // Initial check + checkScrollbar(); + + // Check on resize + window.addEventListener("resize", checkScrollbar); + + // Cleanup event listeners on component unmount + return () => { + window.removeEventListener("resize", checkScrollbar); + }; + }, []); + + useEffect(() => { + const content = contentRef.current; + content.addEventListener("scroll", checkScrollbar); + + return () => { + content.removeEventListener("scroll", checkScrollbar); + }; + }, [contentRef]); + + return ( +
+
+ {tempHypothesisList + .filter((item) => item?.active) + ?.filter((item) => item.key !== "") + .map((item, index) => ( +
+

{t(item?.key)}

+
+ {/* Dropdown for boundaries */} + + valueChangeHandler({ item, newValue: value?.target?.value }, setTempHypothesisList, boundarySelections, setToast, t) + } + disable={false} + /> +
+
+ ))} +
+
+
+
+ ); +}); + +export const BoundarySelection = memo(({ boundarySelections, setBoundarySelections, boundaryData, hierarchy, t }) => { + const [processedHierarchy, setProcessedHierarchy] = useState([]); + const [isLoading, setIsLoading] = useState(false); + const [changedBoundaryType, setChangedBoundaryType] = useState(""); + + // Filtering out dropdown values + useEffect(() => { + if (!boundaryData || !hierarchy) return; + + const processedHierarchyTemp = fetchDropdownValues( + boundaryData, + processedHierarchy.length !== 0 ? processedHierarchy : hierarchy, + boundarySelections, + changedBoundaryType + ); + setProcessedHierarchy(processedHierarchyTemp); + setIsLoading(false); + }, [boundaryData, hierarchy, boundarySelections]); + + return ( +
+ {isLoading && } + {processedHierarchy?.map((item, index) => ( +
+ {t(item?.boundaryType)} + {item?.parentBoundaryType === null ? ( + 5 ? { height: "13.75rem" } : {}} + type={"multiselectdropdown"} + t={t} + options={item?.dropDownOptions || []} + optionsKey="name" + addSelectAllCheck={true} + onSelect={(e) => { + setChangedBoundaryType(item?.boundaryType); + Digit.Utils.microplan.handleSelection( + e, + item?.boundaryType, + boundarySelections, + hierarchy, + setBoundarySelections, + boundaryData, + setIsLoading + ); + }} + /> + ) : ( + 5 ? { height: "13.75rem" } : {}} + type={"multiselectdropdown"} + t={t} + options={Digit.Utils.microplan.processDropdownForNestedMultiSelect(item?.dropDownOptions) || []} + optionsKey="name" + addSelectAllCheck={true} + onSelect={(e) => { + setChangedBoundaryType(item?.boundaryType); + Digit.Utils.microplan.handleSelection( + e, + item?.boundaryType, + boundarySelections, + hierarchy, + setBoundarySelections, + boundaryData, + setIsLoading + ); + }} + variant="nestedmultiselect" + /> + )} +
+ ))} +
+ ); +}); + +export const DataPreview = memo( + ({ previewData, isCampaignLoading, ishierarchyLoading, resources, userEditedResources, setUserEditedResources, modal, setModal, data, t }) => { + if (!previewData) return; + const [tempResourceChanges, setTempResourceChanges] = useState(userEditedResources); + const [selectedRow, setSelectedRow] = useState(); + const conmmonColumnIndex = useMemo(() => { + return previewData?.[0]?.indexOf(commonColumn); + }, [previewData]); + if (isCampaignLoading || ishierarchyLoading) { + return ( +
+ +
+ ); + } + + const rowClick = useCallback((rowIndex) => { + setSelectedRow(rowIndex); + setModal("change-preview-data"); + }, []); + + const finaliseRowDataChange = () => { + setUserEditedResources(tempResourceChanges); + setModal("none"); + setSelectedRow(undefined); + }; + + const modalCloseHandler = () => { + setModal("none"); + setSelectedRow(undefined); + }; + + return ( +
+
+
{t(header)}{t(header)}
+ + + {previewData[0].map((header, columnIndex) => ( + + ))} + + + + {previewData.slice(1).map((rowData, rowIndex) => { + const rowDataList = Object.values(previewData[0]).map((header, cellIndex) => ( + + )); + return ( + { + rowClick(rowIndex + 1); + }} + // style={{...(userEditedResources?.[rowData?.[conmmonColumnIndex]] && Object.keys(userEditedResources?.[rowData?.[conmmonColumnIndex]]).length !==0 + // ? { borderL: "1px solid rgba(244, 119, 56, 0.12)" } + // : {}),}} + > + {rowDataList} + + ); + })} + +
+ {t(header)} +
+ {cellIndex === 0 && + userEditedResources?.[rowData?.[conmmonColumnIndex]] && + Object.keys(userEditedResources?.[rowData?.[conmmonColumnIndex]]).length !== 0 &&
} + + {rowData[cellIndex] || rowData[cellIndex] === 0 ? rowData[cellIndex] : t("NO_DATA")} +
+
+ {modal === "change-preview-data" && ( +
+ } + headerBarEnd={} + actionCancelLabel={t("CANCLE")} + actionCancelOnSubmit={modalCloseHandler} + actionSaveLabel={t("SAVE_CHANGES")} + actionSaveOnSubmit={finaliseRowDataChange} + formId="modal-action" + > + + +
+ )} +
+ ); + } +); + +export const AppplyChangedHypothesisConfirmation = ({ newhypothesisList, hypothesisList, t }) => { + const data = filterObjects(newhypothesisList, hypothesisList); + return ( +
+
+

{t("INSTRUCTION_PROCEED_WITH_NEW_HYPOTHESIS")}

+
+ + {t("MICROPLAN_PREVIEW_HYPOTHESIS")} + +
+ + + + + + + + + + {data?.map((row, index) => ( + + + + + + ))} + +
{t("KEYS")}{t("OLD_VALUE")}{t("NEW_VALUE")}
{t(row?.key)}{t(row?.oldValue)}{t(row?.value)}
+
+
+ ); +}; + +export const EditResourceData = ({ previewData, selectedRow, resources, tempResourceChanges, setTempResourceChanges, data, t }) => { + const conmmonColumnData = useMemo(() => { + const index = previewData?.[0]?.indexOf(commonColumn); + if (index === -1) return; + return previewData?.[selectedRow]?.[index]; + }, [previewData]); + + const valueChangeHandler = (item, value) => { + if (!conmmonColumnData) return; + if (isNaN(value) || (!isFinite(value) && value !== "")) return; + let changedDataAgainstBoundaryCode = tempResourceChanges?.[conmmonColumnData] || {}; + changedDataAgainstBoundaryCode[item] = value === "" ? undefined : parseFloat(value); + setTempResourceChanges((previous) => ({ ...previous, [conmmonColumnData]: changedDataAgainstBoundaryCode })); + }; + + return ( +
+ + + + + + + + + + {data[0].map((item) => { + let index = data?.[0]?.indexOf(item); + if (index === -1) return; + const currentData = data?.[selectedRow]?.[index]; + return ( + + + + + + ); + })} + {resources.map((item) => { + let index = previewData?.[0]?.indexOf(item); + if (index === -1) return; + const currentData = previewData?.[selectedRow]?.[index]; + + return ( + + + + + + ); + })} + +
{t("COLUMNS")}{t("OLD_VALUE")}{t("NEW_VALUE")}
+

{t(item)}

+
+

{currentData || t("NO_DATA")}

+
+ +
+

{t(item)}

+
+

{currentData || t("NO_DATA")}

+
+ valueChangeHandler(item, value.target.value)} + /> +
+
+ ); +}; + +export const Aggregates = memo(({ microplanPreviewAggregates, dataToShow, NumberFormatMappingForTranslation, t }) => { + const { formatNumber } = useNumberFormatter(NumberFormatMappingForTranslation?.reduce((acc, obj) => Object.assign(acc, obj), {})); + + if (!microplanPreviewAggregates) return null; + return ( +
+ {microplanPreviewAggregates.map((item, index) => { + const aggregate = calculateAggregateValue(item, dataToShow); + return ( +
+

{isNaN(parseInt(aggregate)) ? 0 : formatNumber(parseInt(aggregate))}

+

{typeof item === "object" && item.name ? t(item.name) : t(item)}

+
+ ); + })} +
+ ); +}); diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js similarity index 100% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js similarity index 100% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js similarity index 100% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js similarity index 97% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js index 1254e25c093..06d04ef2296 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js @@ -48,7 +48,7 @@ const Navigator = memo((props) => { if (checkDataCompletion === "invalid") { if (navigationEvent && navigationEvent.name === "next") { props?.setToast({ state: "error", message: t("MICROPLAN_PLEASE_FILL_ALL_THE_FIELDS_AND_RESOLVE_ALL_THE_ERRORS") }); - } else if (navigationEvent && navigationEvent.name === "step" && navigationEvent.step != undefined) { + } else if (navigationEvent && navigationEvent.name === "step" && navigationEvent.step !== undefined) { if (navigationEvent.step > currentPage.id) props?.setToast({ state: "error", message: t("MICROPLAN_PLEASE_FILL_ALL_THE_FIELDS_AND_RESOLVE_ALL_THE_ERRORS") }); else onStepClick(navigationEvent.step); @@ -258,11 +258,11 @@ const handleNavigationEvent = ( ) => { if (checkDataCompletion === "perform-action") { if (navigationEvent && navigationEvent.name === "next") { - if (currentPage?.id >= props.config.length - 1 && typeof props?.completeNavigation == "function") { + if (currentPage?.id === props.config.length - 1 && typeof props?.completeNavigation === "function") { return props?.completeNavigation(); } nextStep(); - } else if (navigationEvent && navigationEvent.name === "step" && navigationEvent.step != undefined) onStepClick(navigationEvent.step); + } else if (navigationEvent && navigationEvent.name === "step" && navigationEvent.step !== undefined) onStepClick(navigationEvent.step); else if (navigationEvent && navigationEvent.name === "previousStep") previousStep(); setCheckDataCompletion("false"); setNavigationEvent(undefined); diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js similarity index 97% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js index be023befbfe..7ece3cce04d 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js @@ -127,12 +127,12 @@ const RuleEngine = ({ // useEffect to initialise the data from MDMS useEffect(() => { if (!state) return; - let schemas = state?.Schemas; - let hypothesisAssumptions = []; + const schemas = state?.Schemas; + const hypothesisAssumptions = []; microplanData?.hypothesis?.filter((item) => item.active).forEach((item) => (item.key !== "" ? hypothesisAssumptions.push(item.key) : null)); - let ruleConfigureOutput = state?.RuleConfigureOutput; - let UIConfiguration = state?.UIConfiguration; - let ruleConfigureInputs = getRuleConfigInputsFromSchema(campaignType, microplanData, schemas) || []; + const ruleConfigureOutput = state?.RuleConfigureOutput; + const UIConfiguration = state?.UIConfiguration; + const ruleConfigureInputs = getRuleConfigInputsFromSchema(campaignType, microplanData, schemas) || []; let AutoFilledRuleConfigurationsList = state?.AutoFilledRuleConfigurations; AutoFilledRuleConfigurationsList = AutoFilledRuleConfigurationsList.find((item) => item.campaignType === campaignType)?.data; microplanData?.ruleEngine?.forEach((item) => { @@ -149,7 +149,7 @@ const RuleEngine = ({ setOriginalRuleOutputCount(data.length); microplanData?.ruleEngine?.forEach((item) => { if (item.active) { - let filteredData = data.filter((e) => e !== item?.output); + const filteredData = data.filter((e) => e !== item?.output); data = filteredData; } }); @@ -312,7 +312,7 @@ const RuleEngine = ({ // Function to add a new assumption const addRulesHandler = (setRules) => { - let uuid = uuidv4(); + const uuid = uuidv4(); setRules((previous) => [ ...previous, { @@ -641,14 +641,14 @@ const Example = ({ exampleOption, t }) => { const deleteAssumptionHandler = (item, setItemForDeletion, setRules, setOutputs, setInputs, pureInputList) => { try { - let outputToRemove = []; + const outputToRemove = []; setRules((previous) => { if (!previous.length) return []; const deletionElementIndex = previous.findIndex((data) => data.id === item.id); const filteredData = previous.map((data, index) => (index === deletionElementIndex ? { ...data, active: false } : data)); - let newRules = filteredData.reduce((acc, dataItem, index) => { + const newRules = filteredData.reduce((acc, dataItem, index) => { if (dataItem.active) { - let possibleOutputs = acc.reduce((reducedData, element, index) => { + const possibleOutputs = acc.reduce((reducedData, element, index) => { if (element.active && !Object.values(element).some((e) => e === "")) reducedData.push(element?.output); return reducedData; }, []); @@ -696,7 +696,7 @@ const Select = React.memo( useEffect(() => { if (!options) return; - let filteredOptions = options.length ? options : []; + const filteredOptions = options.length ? options : []; let filteredOptionPlaceHolder = []; if (item?.[toChange] && !filteredOptions.includes(item[toChange])) { filteredOptionPlaceHolder = [item[toChange], ...filteredOptions]; @@ -730,7 +730,7 @@ const Select = React.memo( const newDataSegment = { ...item }; newDataSegment[toChange] = e.code; setRules((previous) => { - let filteredAssumptionsList = previous.map((data) => { + const filteredAssumptionsList = previous.map((data) => { if (data.id === item.id) return newDataSegment; return data; }); @@ -762,7 +762,7 @@ const Select = React.memo( } if (unique) setOptions((previous) => { - let newOptions = previous.filter((item) => item !== e.code); + const newOptions = previous.filter((item) => item !== e.code); if (selected?.code && !newOptions.includes(selected?.code)) newOptions.unshift(selected?.code); return newOptions; }); @@ -789,7 +789,7 @@ const Select = React.memo( // get schema for validation const getRuleConfigInputsFromSchema = (campaignType, microplanData, schemas) => { if (!schemas || !microplanData || !microplanData?.upload || !campaignType) return []; - let sortData = []; + const sortData = []; if (!schemas) return; for (const value of microplanData?.upload?.filter((value) => value?.active && value?.error === null) || []) { sortData.push({ section: value?.section, fileType: value?.fileType }); @@ -802,7 +802,7 @@ const getRuleConfigInputsFromSchema = (campaignType, microplanData, schemas) => return sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); }) || []; const finalData = filteredSchemas - ?.map((item) => + ?.flatMap((item) => Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => { if (value?.isRuleConfigureInputs) { acc.push(key); @@ -810,7 +810,6 @@ const getRuleConfigInputsFromSchema = (campaignType, microplanData, schemas) => return acc; }, []) ) - .flat() .filter((item) => !!item); return [...new Set(finalData)]; }; @@ -820,7 +819,7 @@ const filterRulesAsPerConstrains = (autofillData, rules, hypothesisAssumptionsLi if (rules && rules.filter((item) => item.active).length !== 0) return { rules }; let wereRulesNotDeleted = true; - let newRules = []; + const newRules = []; const ruleOuputList = rules ? rules.filter((item) => item.active).map((item) => item?.output) : []; let rulePlusInputs; if (ruleOuputList) rulePlusInputs = [...inputs, ...ruleOuputList]; @@ -842,15 +841,14 @@ const filterRulesAsPerConstrains = (autofillData, rules, hypothesisAssumptionsLi ) { if (autofill) { continue; - } else { - if (active) { - wereRulesNotDeleted = false; - active = false; - } + } + if (active) { + wereRulesNotDeleted = false; + active = false; } } if (!item["id"]) { - let uuid = uuidv4(); + const uuid = uuidv4(); item["id"] = uuid; } item.active = active; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js new file mode 100644 index 00000000000..e6309dd74f3 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js @@ -0,0 +1,1137 @@ +import React, { useState, useEffect, useMemo, Fragment, useCallback } from "react"; +import { useTranslation } from "react-i18next"; +import { LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; +import { ModalWrapper } from "./Modal"; +import { geojsonPropertiesValidation } from "../utils/geojsonValidations"; +import { SpatialDataPropertyMapping } from "./resourceMapping"; +import { JsonPreviewInExcelForm } from "./JsonPreviewInExcelForm"; +import { ButtonType1, ButtonType2, CloseButton, ModalHeading } from "./CommonComponents"; +import { Loader } from "@egovernments/digit-ui-components"; +import { EXCEL, FILE_STORE, GEOJSON, PRIMARY_THEME_COLOR, SHAPEFILE } from "../configs/constants"; +import { tourSteps } from "../configs/tourSteps"; +import { useMyContext } from "../utils/context"; +import { v4 as uuidv4 } from "uuid"; +import { + handleExcelFile, + validateNamingConvention, + findReadMe, + downloadTemplate, + getSchema, + prepareExcelFileBlobWithErrors, + boundaryDataGeneration, + handleGeojsonFile, + handleShapefiles, + convertToSheetArray, + findGuideLine, + delay, +} from "../utils/uploadUtils"; +import { UploadGuideLines, UploadedFile, FileUploadComponent, UploadComponents, UploadInstructions, UploadSection } from "./UploadHelperComponents"; + +const page = "upload"; + +const Upload = ({ + MicroplanName = "default", + campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, + microplanData, + setMicroplanData, + checkDataCompletion, + setCheckDataCompletion, + currentPage, + pages, + navigationEvent, + setToast, +}) => { + const { t } = useTranslation(); + + // States + const [editable, setEditable] = useState(true); + const [sections, setSections] = useState([]); + const [selectedSection, setSelectedSection] = useState(null); + const [modal, setModalState] = useState("none"); + const [selectedFileType, setSelectedFileType] = useState(null); + const [dataPresent, setDataPresent] = useState(false); + const [dataUpload, setDataUpload] = useState(false); + const [loader, setLoader] = useState(false); + const [fileData, setFileData] = useState(); + const [uploadedFileError, setUploadedFileError] = useState(); + const [fileDataList, setFileDataList] = useState([]); + const [validationSchemas, setValidationSchemas] = useState([]); + const [template, setTemplate] = useState([]); + const [resourceMapping, setResourceMapping] = useState([]); + const [previewUploadedData, setPreviewUploadedData] = useState(); + const { state, dispatch } = useMyContext(); + + //fetch campaign data + const { id = "" } = Digit.Hooks.useQueryParams(); + const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( + { + CampaignDetails: { + tenantId: Digit.ULBService.getCurrentTenantId(), + ids: [id], + }, + }, + { + enabled: !!id, + } + ); + + // request body for boundary hierarchy api + const reqCriteria = { + url: `/boundary-service/boundary-hierarchy-definition/_search`, + params: {}, + body: { + BoundaryTypeHierarchySearchCriteria: { + tenantId: Digit.ULBService.getCurrentTenantId(), + hierarchyType: campaignData?.hierarchyType, + // hierarchyType: "Microplan", + }, + }, + config: { + enabled: !!campaignData?.hierarchyType, + select: (data) => { + return ( + data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map( + (item) => `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}` + ) || {} + ); + }, + }, + }; + const { isLoading: ishierarchyLoading, data: hierarchy } = Digit.Hooks.useCustomAPIHook(reqCriteria); + // Set TourSteps + useEffect(() => { + const tourData = tourSteps(t)?.[page] || {}; + if (state?.tourStateData?.name === page) return; + dispatch({ + type: "SETINITDATA", + state: { tourStateData: tourData }, + }); + }, [t]); + + const setModal = (modalString) => { + const elements = document.querySelectorAll(".popup-wrap-rest-unfocus"); + elements.forEach((element) => { + element.classList.toggle("popup-wrap-rest-unfocus-active"); + }); + setModalState(modalString); + }; + + // UseEffect for checking completeness of data before moveing to next section + useEffect(() => { + if (!fileDataList || checkDataCompletion !== "true" || !setCheckDataCompletion) return; + updateData(true); + }, [checkDataCompletion]); + + // UseEffect to store current data + useEffect(() => { + if (!fileDataList || !setMicroplanData) return; + setMicroplanData((previous) => ({ ...previous, upload: fileDataList })); + }, [fileDataList]); + + // check if data has changed or not + const updateData = useCallback( + (check) => { + if (!fileDataList || !setMicroplanData) return; + + // if user has selected a file type and wants to go back to file type selection he/she can click back buttom + const currentSectionIndex = sections.findIndex((item) => item.id === selectedSection.id); + if (!dataPresent) { + if (navigationEvent?.name !== "step") { + if (navigationEvent?.name === "next") { + if (currentSectionIndex < sections.length - 1) { + setSelectedSection(sections[currentSectionIndex + 1]); + setCheckDataCompletion("false"); + return; + } + } else if (navigationEvent?.name === "previousStep") { + if (dataUpload) { + setDataUpload(false); + setSelectedFileType(null); + setCheckDataCompletion("false"); + return; + } + if (currentSectionIndex > 0) { + setSelectedSection(sections[currentSectionIndex - 1]); + setCheckDataCompletion("false"); + return; + } + } + } + } else { + if (navigationEvent?.name === "next") { + if (currentSectionIndex < sections.length - 1) { + setSelectedSection(sections[currentSectionIndex + 1]); + setCheckDataCompletion("false"); + return; + } + } else if (navigationEvent?.name === "previousStep") { + if (currentSectionIndex > 0) { + setSelectedSection(sections[currentSectionIndex - 1]); + setCheckDataCompletion("false"); + return; + } + } + } + + if (check) { + setMicroplanData((previous) => ({ ...previous, upload: fileDataList })); + const valueList = fileDataList ? fileDataList : []; + const sectionCheckList = sections?.filter((item) => item.required); + + if ( + valueList.length !== 0 && + sectionCheckList.every((item) => { + const filteredList = fileDataList?.filter((e) => e.active && e.templateIdentifier === item.id); + if (filteredList?.length === 0) return false; + return filteredList?.every((element) => element?.error === null) && fileDataList && !fileDataList.some((e) => e?.active && e?.error); + }) + ) + setCheckDataCompletion("valid"); + else setCheckDataCompletion("invalid"); + } else { + const valueList = microplanData?.Upload ? Object.values(microplanData?.Upload) : []; + if ( + valueList.length !== 0 && + sectionCheckList.every((item) => + fileDataList?.filter((e) => e.templateIdentifier === item.id)?.every((element) => element.active && element?.error === null) + ) + ) + setCheckDataCompletion("valid"); + else setCheckDataCompletion("invalid"); + } + }, + [fileDataList, setMicroplanData, microplanData, setCheckDataCompletion, dataPresent, dataUpload, navigationEvent] + ); + + // UseEffect to extract data on first render + useEffect(() => { + if (microplanData?.upload) { + setFileDataList(microplanData.upload); + } + + if (pages) { + const previouspage = pages[currentPage?.id - 1]; + if (previouspage?.checkForCompleteness && !microplanData?.status?.[previouspage?.name]) setEditable(false); + else setEditable(true); + } + }, []); + + // UseEffect to add a event listener for keyboard + useEffect(() => { + window.addEventListener("keydown", handleKeyPress); + + return () => window.removeEventListener("keydown", handleKeyPress); + }, [modal, previewUploadedData]); + + const handleKeyPress = (event) => { + // if (modal !== "upload-guidelines") return; + if (["x", "Escape"].includes(event.key)) { + // Perform the desired action when "x" or "esc" is pressed + if (modal === "upload-guidelines") { + setModal("none"); + } + if (previewUploadedData) setPreviewUploadedData(undefined); + } + }; + + // Effect to update sections and selected section when data changes + useEffect(() => { + if (state) { + const uploadSections = state?.UploadConfiguration; + const schemas = state?.Schemas; + if (schemas) setValidationSchemas(schemas); + if (uploadSections) { + setSelectedSection(uploadSections.length > 0 ? uploadSections[0] : null); + setSections(uploadSections); + } + } + }, []); + + // Memoized section options to prevent unnecessary re-renders + const sectionOptions = useMemo(() => { + if (!sections) return []; + return sections.map((item) => ( + e.active && e.templateIdentifier === item.id && !e.error)?.length !== 0} + /> + )); + }, [sections, selectedSection, fileDataList]); + + const showDownloadTemplate = () => { + if (selectedSection?.UploadFileTypes) { + const schema = getSchema(campaignType, selectedFileType?.id, selectedSection.id, validationSchemas); + if (schema?.template?.showTemplateDownload) return true; + } + return false; + }; + + // Handler for when a file type is selected for uplaod + const selectFileTypeHandler = (e) => { + if (selectedSection?.UploadFileTypes) { + const schema = getSchema(campaignType, e.target.name, selectedSection.id, validationSchemas); + setSelectedFileType(selectedSection.UploadFileTypes.find((item) => item.id === e.target.name)); + if (schema?.template?.showTemplateDownload) setModal("upload-modal"); + else UploadFileClickHandler(false); + return; + } + setToast({ + state: "error", + message: t("ERROR_UNKNOWN"), + }); + setLoader(false); + return; + }; + + // Memoized section components to prevent unnecessary re-renders + const sectionComponents = useMemo(() => { + if (!sections) return; + return sections.map((item) => ( + + )); + }, [sections, selectedSection, selectedFileType]); + + // Close model click handler + const closeModal = () => { + setResourceMapping([]); + setModal("none"); + }; + + // handler for show file upload screen + const UploadFileClickHandler = (download = false) => { + if (download) { + downloadTemplateHandler(); + } + setModal("none"); + setDataUpload(true); + }; + const readMeConstant = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName"); + const downloadTemplateHandler = () => { + const downloadParams = { + campaignType, + type: selectedFileType.id, + section: selectedSection.id, + setToast, + campaignData, + hierarchyType: campaignData?.hierarchyType, + Schemas: validationSchemas, + HierarchyConfigurations: state?.HierarchyConfigurations, + setLoader, + hierarchy, + readMeData: state?.ReadMeData, + readMeSheetName: readMeConstant ? readMeConstant.value : undefined, + t, + }; + downloadTemplate(downloadParams); + }; + // Effect for updating current session data in case of section change + useEffect(() => { + if (selectedSection) { + let file = fileDataList?.find((item) => item.active && item.templateIdentifier === selectedSection.id); + if (file?.resourceMapping) { + setSelectedFileType(selectedSection.UploadFileTypes.find((item) => item?.id === file?.fileType)); + setUploadedFileError(file?.error); + setFileData(file); + setDataPresent(true); + } else { + resetSectionState(); + } + } else { + resetSectionState(); + } + }, [selectedSection]); + + const resetSectionState = () => { + setUploadedFileError(null); + setSelectedFileType(null); + setDataPresent(false); + setResourceMapping([]); + setDataUpload(false); + }; + + // Function for handling upload file event + const UploadFileToFileStorage = async (file) => { + if (!file) return; + try { + // setting loader + setLoader("FILE_UPLOADING"); + let check; + let fileDataToStore; + let errorMsg; + let errorLocationObject; // object containing the location and type of error + let response; + let callMapping = false; + // Checking if the file follows name convention rules + if (!validateNamingConvention(file, selectedFileType["namingConvention"], setToast, t)) { + setLoader(false); + return; + } + + let schemaData; + if (selectedFileType.id !== SHAPEFILE) { + // Check if validation schema is present or not + schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); + if (!schemaData) { + setToast({ + state: "error", + message: t("ERROR_VALIDATION_SCHEMA_ABSENT"), + }); + setLoader(false); + return; + } + } + let resourceMappingData = []; + let additionalSheets = []; + // Handling different filetypes + switch (selectedFileType.id) { + case EXCEL: + // let response = handleExcelFile(file,schemaData); + try { + response = await handleExcelFile( + file, + schemaData, + hierarchy, + selectedFileType, + {}, + setUploadedFileError, + t, + campaignData, + state?.CommonConstants?.find((item) => item?.name === "readMeSheetName")?.value + ); + check = response.check; + errorMsg = response.errorMsg; + errorLocationObject = response.errors; + fileDataToStore = response.fileDataToStore; + resourceMappingData = response?.tempResourceMappingData || []; + additionalSheets = response?.additionalSheets; + if (check === true) { + if (response?.toast) setToast(response.toast); + else setToast({ state: "success", message: t("FILE_UPLOADED_SUCCESSFULLY") }); + } else if (response.toast) { + setToast(response.toast); + } else { + setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); + } + if (response.interruptUpload) { + setLoader(false); + return; + } + } catch (error) { + console.error("Excel parsing error", error.message); + setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); + handleValidationErrorResponse(t("ERROR_UPLOADED_FILE")); + return; + } + break; + case GEOJSON: + try { + response = await handleGeojsonFile(file, schemaData, setUploadedFileError, t); + file = new File([file], file.name, { type: "application/geo+json" }); + if (response.check === false && response.stopUpload) { + setLoader(false); + setToast(response.toast); + return; + } + check = response.check; + errorMsg = response.error; + fileDataToStore = response.fileDataToStore; + callMapping = true; + } catch (error) { + // console.error("Geojson parsing error", error.message); + setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); + handleValidationErrorResponse(t("ERROR_UPLOADED_FILE")); + return; + } + break; + case SHAPEFILE: + try { + response = await handleShapefiles(file, schemaData, setUploadedFileError, selectedFileType, setToast, t); + file = new File([file], file.name, { type: "application/octet-stream" }); + check = response.check; + errorMsg = response.error; + fileDataToStore = response.fileDataToStore; + callMapping = true; + } catch (error) { + console.error("Shapefile parsing error", error.message); + setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); + handleValidationErrorResponse(t("ERROR_UPLOADED_FILE")); + return; + } + break; + default: + setToast({ + state: "error", + message: t("ERROR_UNKNOWN_FILETYPE"), + }); + setLoader(false); + return; + } + let filestoreId; + if (!errorMsg && !callMapping) { + try { + const filestoreResponse = await Digit.UploadServices.Filestorage(FILE_STORE, file, Digit.ULBService.getCurrentTenantId()); + if (filestoreResponse?.data?.files?.length > 0) { + filestoreId = filestoreResponse?.data?.files[0]?.fileStoreId; + } else { + errorMsg = t("ERROR_UPLOADING_FILE"); + setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); + setFileData((previous) => ({ ...previous, error: errorMsg })); + setUploadedFileError(errorMsg); + } + } catch (errorData) { + console.error(errorData.message); + errorMsg = t("ERROR_UPLOADING_FILE"); + setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); + setUploadedFileError(errorMsg); + handleValidationErrorResponse(t("ERROR_UPLOADING_FILE")); + return; + } + } + + if (selectedFileType.id === EXCEL) { + resourceMappingData = resourceMappingData.map((item) => ({ ...item, filestoreId })); + } + const uuid = uuidv4(); + // creating a fileObject to save all the data collectively + let fileObject = { + id: uuid, + templateIdentifier: `${selectedSection.id}`, + fileName: file.name, + section: selectedSection.id, + fileType: selectedFileType.id, + data: fileDataToStore, + file, + error: errorMsg ? errorMsg : null, + filestoreId, + resourceMapping: resourceMappingData, + active: true, + additionalSheets, + errorLocationObject, // contains location and type of error + }; + setFileDataList((prevFileDataList) => { + let temp = _.cloneDeep(prevFileDataList); + if (!temp) return temp; + let index = prevFileDataList?.findIndex((item) => item.active && item.templateIdentifier === selectedSection.id); + if (index !== -1) + temp[index] = { ...temp[index], resourceMapping: temp[index]?.resourceMapping.map((e) => ({ active: false, ...e })), active: false }; + temp.push(fileObject); + return temp; + }); + setFileData(fileObject); + if (errorMsg === undefined && callMapping) { + setModal("spatial-data-property-mapping"); + } + setDataPresent(true); + setLoader(false); + } catch (error) { + console.error(error.message); + console.error("File Upload error", error?.message); + setUploadedFileError("ERROR_UPLOADING_FILE"); + setLoader(false); + } + }; + + // Reupload the selected file + const reuplaodFile = () => { + setResourceMapping([]); + setFileData(undefined); + setDataPresent(false); + setUploadedFileError(null); + setDataUpload(false); + setSelectedFileType(null); + closeModal(); + }; + + const convertAndCombineFileData = () => { + let combinedData = fileData?.data ? Object.entries(fileData.data)?.map(([key, value]) => ({ sheetName: key, data: value })) : []; + if (fileData?.additionalSheets) { + for (const sheet of fileData.additionalSheets) { + if (sheet?.data && sheet.sheetName) { + const index = sheet?.position < combinedData.length && sheet.position !== -1 ? sheet.position : combinedData.length; + combinedData.splice(index, 0, sheet); + } + } + } + return combinedData; + }; + + // Function for creating blob out of data + const dataToBlob = async () => { + try { + let blob; + const schema = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); + const filteredReadMeData = findReadMe(state?.ReadMeData, campaignType, selectedFileType.id, selectedSection.id); + let combinedData = convertAndCombineFileData(); + const readMeSheetName = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName")?.value; + switch (fileData.fileType) { + case EXCEL: + if (fileData?.errorLocationObject?.length !== 0) + blob = await prepareExcelFileBlobWithErrors( + combinedData, + fileData.errorLocationObject, + schema, + hierarchy, + filteredReadMeData, + readMeSheetName, + t + ); + else blob = fileData.file; + break; + case SHAPEFILE: + case GEOJSON: + if (fileData?.data) { + const result = convertToSheetArray(Digit.Utils.microplan.convertGeojsonToExcelSingleSheet(fileData?.data?.features, fileData?.section)); + + if (fileData?.errorLocationObject?.length !== 0) + blob = await prepareExcelFileBlobWithErrors( + result, + fileData.errorLocationObject, + schema, + hierarchy, + filteredReadMeData, + readMeSheetName, + t + ); + } + break; + } + return blob; + } catch (error) { + console.error("Error generating blob:", error); + return; + } + }; + + // Download the selected file + const downloadFile = async () => { + setLoader("LOADING"); + try { + await delay(100); + let blob = await dataToBlob(); + if (blob) { + // Crating a url object for the blob + const url = URL.createObjectURL(blob); + const link = document.createElement("a"); + link.href = url; + + // Forming a name for downloaded file + let fileNameParts = fileData.fileName.split("."); + fileNameParts.pop(); + fileNameParts.push("xlsx"); + fileNameParts.join("."); + + //Downloading the file + link.download = fileNameParts.join("."); + link.click(); + URL.revokeObjectURL(url); + } else { + let downloadUrl = await Digit.UploadServices.Filefetch([fileData.filestoreId], Digit.ULBService.getCurrentTenantId()); + const link = document.createElement("a"); + link.href = downloadUrl; + // Forming a name for downloaded file + let fileNameParts = fileData.fileName.split("."); + fileNameParts.pop(); + fileNameParts.push("xlsx"); + fileNameParts.join("."); + link.download = fileNameParts; // Replace with the desired file name and extension + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } + } catch (error) { + console.error(error.message); + setToast({ + state: "error", + message: t("ERROR_UNKNOWN_ERROR"), + }); + } + setLoader(false); + }; + + // delete the selected file + const deleteFile = () => { + setResourceMapping([]); + setFileDataList((previous) => { + let temp = _.cloneDeep(previous); + if (!temp) return temp; + let index = temp?.findIndex((item) => { + return item.id === fileData.id; + }); + if (index !== -1) + temp[index] = { ...temp[index], resourceMapping: temp[index]?.resourceMapping.map((e) => ({ active: false, ...e })), active: false }; + return temp; + }); + setFileData(undefined); + setDataPresent(false); + setUploadedFileError(null); + setDataUpload(false); + setSelectedFileType(null); + closeModal(); + }; + + // Function for handling the validations for geojson and shapefiles after mapping of properties + const validationForMappingAndDataSaving = async () => { + try { + setLoader("LOADING"); + const schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); + let error; + if (!checkForSchemaData(schemaData)) return; + const { data, valid, errors } = computeMappedDataAndItsValidations(schemaData); + error = errors; + if (!valid) return; + let filestoreId; + if (!error) { + filestoreId = await saveFileToFileStore(); + } + let resourceMappingData; + if (filestoreId) { + resourceMappingData = resourceMapping.map((item) => { + return { ...item, filestoreId }; + }); + } + setResourceMapping([]); + + let boundaryDataAgainstBoundaryCode = (await boundaryDataGeneration(schemaData, campaignData, t)) || {}; + const mappedToList = resourceMappingData.map((item) => item.mappedTo); + if (hierarchy.every((item) => !mappedToList.includes(t(item)))) { + data.features.forEach((feature) => { + const boundaryCode = feature.properties.boundaryCode; + let additionalDetails = {}; + for (let i = 0; i < hierarchy.length; i++) { + if (boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] || boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] === "") { + additionalDetails[hierarchy[i]] = boundaryDataAgainstBoundaryCode[boundaryCode][i]; + } else { + additionalDetails[hierarchy[i]] = ""; + } + } + feature.properties = { ...additionalDetails, ...feature.properties }; + }); + } + + let fileObject = _.cloneDeep(fileData); + fileObject = { ...fileData, data, resourceMapping: resourceMappingData, error: error ? error : null, filestoreId }; + setFileData(fileObject); + setFileDataList((prevFileDataList) => { + let temp = _.cloneDeep(prevFileDataList); + if (!temp) return temp; + let index = prevFileDataList?.findIndex((item) => item.id === fileData.id); + if (index !== -1) temp[index] = fileObject; + // temp.push(fileObject); + return temp; + }); + + setToast({ state: "success", message: t("FILE_UPLOADED_SUCCESSFULLY") }); + setLoader(false); + } catch (error) { + console.error(error.message); + setUploadedFileError(t("ERROR_UPLOADING_FILE")); + setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); + setLoader(false); + handleValidationErrorResponse("ERROR_UPLOADING_FILE"); + } + }; + const saveFileToFileStore = async () => { + try { + const filestoreResponse = await Digit.UploadServices.Filestorage(FILE_STORE, fileData.file, Digit.ULBService.getCurrentTenantId()); + if (filestoreResponse?.data?.files?.length > 0) { + return filestoreResponse?.data?.files[0]?.fileStoreId; + } + error = t("ERROR_UPLOADING_FILE"); + setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); + setResourceMapping([]); + setUploadedFileError(error); + } catch (errorData) { + console.error("Error while uploading file to filestore: ", errorData?.message); + let error = t("ERROR_UPLOADING_FILE"); + handleValidationErrorResponse(error); + setResourceMapping([]); + return; + } + }; + const computeMappedDataAndItsValidations = (schemaData) => { + const data = computeGeojsonWithMappedProperties(); + const response = geojsonPropertiesValidation(data, schemaData.schema, fileData?.section, t); + if (!response.valid) { + handleValidationErrorResponse(response.message, response.errors); + return { data: data, errors: response.errors, valid: response.valid }; + } + return { data: data, valid: response.valid }; + }; + + const handleValidationErrorResponse = (error, errorLocationObject = {}) => { + const fileObject = fileData; + if (fileObject) { + fileObject.error = [error]; + if (errorLocationObject) fileObject.errorLocationObject = errorLocationObject; + setFileData((previous) => ({ ...previous, error, errorLocationObject })); + setFileDataList((prevFileDataList) => { + let temp = _.cloneDeep(prevFileDataList); + if (!temp) return temp; + let index = prevFileDataList?.findIndex((item) => item.id === fileData.id); + temp[index] = fileObject; + return temp; + }); + setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); + if (error) setUploadedFileError(error); + } + setLoader(false); + }; + + const checkForSchemaData = (schemaData) => { + if (resourceMapping?.length === 0) { + setToast({ state: "warning", message: t("WARNING_INCOMPLETE_MAPPING") }); + setLoader(false); + return false; + } + + if (!schemaData || !schemaData.schema || !schemaData.schema["Properties"]) { + setToast({ state: "error", message: t("ERROR_VALIDATION_SCHEMA_ABSENT") }); + setLoader(false); + return; + } + + let columns = []; + if (schemaData?.doHierarchyCheckInUploadedData) { + columns.push(...hierarchy); + } + columns.push( + ...Object.entries(schemaData?.schema?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.isRequired) { + acc.push(key); + } + return acc; + }, []) + ); + + const resourceMappingLength = resourceMapping.filter((e) => !!e?.mappedFrom && columns.includes(e?.mappedTo)).length; + if (resourceMappingLength !== columns?.length) { + setToast({ state: "warning", message: t("WARNING_INCOMPLETE_MAPPING") }); + setLoader(false); + return false; + } + setModal("none"); + return true; + }; + + const computeGeojsonWithMappedProperties = () => { + const schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); + let schemaKeys; + if (schemaData?.schema?.["Properties"]) schemaKeys = hierarchy.concat(Object.keys(schemaData.schema["Properties"])); + // Sorting the resourceMapping list inorder to maintain the column sequence + const sortedSecondList = Digit.Utils.microplan.sortSecondListBasedOnFirstListOrder(schemaKeys, resourceMapping); + // Creating a object with input data with MDMS keys + const newFeatures = fileData.data["features"].map((item) => { + let newProperties = {}; + + sortedSecondList.forEach((e) => { + newProperties[e["mappedTo"]] = item["properties"][e["mappedFrom"]]; + }); + item["properties"] = newProperties; + return item; + }); + let data = fileData.data; + data["features"] = newFeatures; + return data; + }; + + // Handler for checing file extension and showing errors in case it is wrong + const onTypeErrorWhileFileUpload = () => { + switch (selectedFileType.id) { + case EXCEL: + setToast({ state: "error", message: t("ERROR_EXCEL_EXTENSION") }); + break; + case GEOJSON: + setToast({ state: "error", message: t("ERROR_GEOJSON_EXTENSION") }); + break; + case SHAPEFILE: + setToast({ state: "error", message: t("ERROR_SHAPE_FILE_EXTENSION") }); + break; + } + }; + + // Cancle mapping and uplaod in case of geojson and shapefiles + const cancelUpload = () => { + setFileDataList((previous) => { + let temp = previous?.filter((item) => item.id !== fileData?.id); + return temp; + }); + setFileData(undefined); + setDataPresent(false); + setUploadedFileError(null); + setDataUpload(false); + setSelectedFileType(null); + closeModal(); + }; + + const openDataPreview = () => { + let data; + switch (fileData.fileType) { + case EXCEL: + data = fileData.data; + break; + case SHAPEFILE: + case GEOJSON: + if (!fileData || !fileData.data) { + setToast({ + state: "error", + message: t("ERROR_DATA_NOT_PRESENT"), + }); + return; + } + data = Digit.Utils.microplan.convertGeojsonToExcelSingleSheet(fileData?.data?.features, fileData?.section); + break; + } + if (!data || Object.keys(data).length === 0) { + setToast({ + state: "error", + message: t("ERROR_DATA_NOT_PRESENT"), + }); + return; + } + setPreviewUploadedData(data); + }; + + if (isCampaignLoading || ishierarchyLoading) { + return ( +
+ +
+ ); + } + + return ( + <> +
+
+
+ {!dataPresent ? ( + dataUpload ? ( +
+ e.id === selectedSection.id)[0]} + selectedSection={selectedSection} + selectedFileType={selectedFileType} + UploadFileToFileStorage={UploadFileToFileStorage} + onTypeError={onTypeErrorWhileFileUpload} + downloadTemplateHandler={downloadTemplateHandler} + showDownloadTemplate={showDownloadTemplate} + /> +
+ ) : ( +
{sectionComponents}
+ ) + ) : ( +
+ {selectedSection != null && fileData !== null && ( + { + setModal("reupload-conformation"); + }} + DownloadFile={downloadFile} + DeleteFile={() => { + setModal("delete-conformation"); + }} + error={uploadedFileError} + openDataPreview={openDataPreview} + downloadTemplateHandler={downloadTemplateHandler} + showDownloadTemplate={showDownloadTemplate} + /> + )} +
+ )} + {!dataPresent && dataUpload && ( + { + setModal("upload-guidelines"); + }} + t={t} + /> + )} +
+ +
{sectionOptions}
+
+ +
+ {modal === "upload-modal" && ( + { + closeModal(); + setSelectedFileType(null); + }} + LeftButtonHandler={() => UploadFileClickHandler(false)} + RightButtonHandler={() => UploadFileClickHandler(true)} + sections={sections} + popupModuleActionBarStyles={{ + flex: 1, + justifyContent: "space-between", + padding: "1rem", + gap: "1rem", + }} + footerLeftButtonBody={} + footerRightButtonBody={} + header={ + + } + bodyText={t(`INSTRUCTIONS_DOWNLOAD_TEMPLATE_FOR_${selectedSection.code}_${selectedFileType.code}`)} + /> + )} + {modal === "delete-conformation" && ( + } + actionCancelLabel={t("YES")} + actionCancelOnSubmit={deleteFile} + actionSaveLabel={t("NO")} + actionSaveOnSubmit={closeModal} + > +
+

{t("INSTRUCTIONS_DELETE_FILE_CONFIRMATION")}

+
+
+ )} + {modal === "reupload-conformation" && ( + } + actionCancelLabel={t("YES")} + actionCancelOnSubmit={reuplaodFile} + actionSaveLabel={t("NO")} + actionSaveOnSubmit={closeModal} + > +
+

{t("INSTRUCTIONS_REUPLOAD_FILE_CONFIRMATION")}

+
+
+ )} + {modal === "spatial-data-property-mapping" && ( + } + actionSaveOnSubmit={validationForMappingAndDataSaving} + actionSaveLabel={t("COMPLETE_MAPPING")} + headerBarEnd={} + > +
+

{t("INSTRUCTION_SPATIAL_DATA_PROPERTY_MAPPING")}

+
+ +
+ )} + {modal === "upload-guidelines" && ( + + } + headerBarEnd={} + > + + + )} + {loader && } + + {previewUploadedData && ( +
+ setPreviewUploadedData(undefined)} + onDownload={downloadFile} + /> +
+ )} +
+
+ + ); +}; + +export default Upload; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/UploadHelperComponents.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/UploadHelperComponents.js new file mode 100644 index 00000000000..5a520c4a1bd --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/UploadHelperComponents.js @@ -0,0 +1,299 @@ +import React, { useState, useEffect } from "react"; +import { useTranslation } from "react-i18next"; +import * as Icons from "@egovernments/digit-ui-svg-components"; +import { FileUploader } from "react-drag-drop-files"; +import { InfoButton, InfoCard } from "@egovernments/digit-ui-components"; +import { PRIMARY_THEME_COLOR } from "../configs/constants"; + +// Component for rendering individual section option +export const UploadSection = ({ item, selected, setSelectedSection, uploadDone }) => { + const { t } = useTranslation(); + // Handle click on section option + const handleClick = () => { + setSelectedSection(item); + }; + + return ( +
+
+ +
+

{t(item.code)}

+ {uploadDone && ( +
+ +
+ )} +
+ ); +}; + +export const UploadInstructions = ({ setModal, t }) => { + return ( + + {t("REFER")} +
+ {t("INFORMATION_DESCRIPTION_LINK")} +
+
, + ]} + /> + ); +}; + +// Component for rendering individual upload option +export const UploadComponents = ({ item, selected, uploadOptions, selectedFileType, selectFileTypeHandler }) => { + const { t } = useTranslation(); + const title = item.code; + + // Component for rendering individual upload option container + const UploadOptionContainer = ({ item, selectedFileType, selectFileTypeHandler }) => { + const [isHovered, setIsHovered] = useState(false); + + const handleMouseEnter = () => { + setIsHovered(true); + }; + + const handleMouseLeave = () => { + setIsHovered(false); + }; + + return ( +
+ +

{t(item.code)}

+ +
+ ); + }; + + return ( +
+
+
+

{t(`HEADING_UPLOAD_DATA_${title}`)}

+
+ +

{t(`INSTRUCTIONS_DATA_UPLOAD_OPTIONS_${title}`)}

+
+
+ {uploadOptions?.map((item) => ( + + ))} +
+
+ ); +}; + +// Component for uploading file +export const FileUploadComponent = ({ + selectedSection, + selectedFileType, + UploadFileToFileStorage, + section, + onTypeError, + downloadTemplateHandler, + showDownloadTemplate, +}) => { + if (!selectedSection || !selectedFileType) return
; + const { t } = useTranslation(); + let types; + section["UploadFileTypes"].forEach((item) => { + if (item.id === selectedFileType.id) types = item.fileExtension; + }); + return ( +
+
+
+

{t(`HEADING_FILE_UPLOAD_${selectedSection.code}_${selectedFileType.code}`)}

+ {showDownloadTemplate() && ( + + )} +
+

{t(`INSTRUCTIONS_FILE_UPLOAD_FROM_TEMPLATE_${selectedSection.code}`)}

+ +
+ +
+ {t(`INSTRUCTIONS_UPLOAD_${selectedFileType.code}`)} 
{t("INSTRUCTIONS_UPLOAD_BROWSE_FILES")}
+
+
+
+
+
+ ); +}; + +// Component to display uploaded file +export const UploadedFile = ({ + selectedSection, + selectedFileType, + file, + ReuplaodFile, + DownloadFile, + DeleteFile, + error, + openDataPreview, + downloadTemplateHandler, + showDownloadTemplate, +}) => { + const { t } = useTranslation(); + const [errorList, setErrorList] = useState([]); + useEffect(() => { + let tempErrorList = []; + if (file?.errorLocationObject) { + for (const [sheetName, values] of Object.entries(file?.errorLocationObject)) { + for (const [row, columns] of Object.entries(values)) { + for (const [column, errors] of Object.entries(columns)) { + for (const error of errors) { + let convertedError; + if (typeof error === "object") { + let { error: actualError, ...otherProperties } = error; + convertedError = t(actualError, otherProperties?.values); + } else { + convertedError = t(error); + } + tempErrorList.push( + t("ERROR_UPLOAD_DATA_LOCATION_AND_MESSAGE", { + rowNumber: Number(row) + 1, + columnName: t(column), + error: convertedError, + sheetName: sheetName, + }) + ); + } + } + } + } + } + if (tempErrorList.length !== 0) { + setErrorList(tempErrorList); + } + }, [file]); + return ( +
+
+
+

{t(`HEADING_FILE_UPLOAD_${selectedSection.code}_${selectedFileType.code}`)}

+ {showDownloadTemplate() && ( + + )} +
+

{t(`INSTRUCTIONS_FILE_UPLOAD_FROM_TEMPLATE_${selectedSection.code}`)}

+ +
+
+
+ +
+

{file.fileName}

+
+
+ + + +
+
+
+ {error && Array.isArray(error) && ( + , +
+ {error?.map((item) => { + if (item !== "ERROR_REFER_UPLOAD_PREVIEW_TO_SEE_THE_ERRORS") { + return

{t(item)}

; + } + return null; + })} + {errorList.length !== 0 && errorList.map((item) =>

{item}

)} +
, + ]} + /> + )} +
+ ); +}; + +// Uplaod GuideLines +export const UploadGuideLines = ({ uploadGuideLines, t }) => { + const formMsgFromObject = (item) => { + if (!item?.hasLink) { + return t(item?.name); + } + return ( + <> + {t(item?.name)} {t(item?.linkName)}{" "} + + ); + }; + return ( +
+ {uploadGuideLines?.map((item, index) => ( +
+

+ {t(index + 1)}. +

+
+ {formMsgFromObject(item)} +
+
+ ))} +
+ ); +}; + +export const CustomIcon = (props) => { + if (!props.Icon) return null; + return ; +}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js similarity index 100% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js similarity index 99% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js index 77922c81675..df1eb78c135 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js @@ -88,7 +88,7 @@ export const SpatialDataPropertyMapping = ({ uploadedData, resourceMapping, setR // Update user columns when uploaded data changes useEffect(() => { - let userUploadedColumns = new Set(); + const userUploadedColumns = new Set(); uploadedData?.["features"]?.forEach((item) => { Object.keys(item["properties"]).forEach((key) => userUploadedColumns.add(key)); }); @@ -132,7 +132,6 @@ export const SpatialDataPropertyMapping = ({ uploadedData, resourceMapping, setR }} onClick={() => toggleExpand(index)} onKeyDown={() => toggleExpand(index)} - tabIndex="0" > { function cleanObject(obj) { for (const key in obj) { - if (obj.hasOwnProperty(key)) { + if (Object.hasOwn(obj, key)) { if (Array.isArray(obj[key])) { if (obj[key].length === 0) { delete obj[key]; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js similarity index 85% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js index 4ac715407c5..c9f5af95d46 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js @@ -22,8 +22,8 @@ export const MapChoroplethGradientColors = [ export const PRIMARY_THEME_COLOR = "#C84C0E"; -export const BOUNDARY_DATA_SHEET = "boundaryData"; -export const FACILITY_DATA_SHEET = "facilityData"; +export const BOUNDARY_DATA_SHEET = "MICROPLAN_BOUNDARY_DATA_SHEET"; +export const FACILITY_DATA_SHEET = "MICROPLAN_FACILITY_DATA_SHEET"; export const FILE_STORE = "microplan"; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json similarity index 100% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js similarity index 100% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js similarity index 91% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js index 4503647b641..1241d678738 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js @@ -1,4 +1,3 @@ -import { logoutV1 } from "./logout"; import utils from "../utils"; import useCreatePlanConfig from "./useCreatePlanConfig"; import useSearchPlanConfig from "./useSearchPlanConfig"; @@ -6,9 +5,7 @@ import useUpdatePlanConfig from "./useUpdatePlanConfig"; import useSavedMicroplans from "./useSavedMicroplans"; import useSearchCampaign from "./useSearchCampaign"; import { useGenerateIdCampaign } from "./useGenerateIdCampaign"; -const UserService = { - logoutV1, -}; +const UserService = {}; const microplan = { useCreatePlanConfig, diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js similarity index 100% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js similarity index 100% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js similarity index 100% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js similarity index 87% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js index 62c4c2ecd1c..23c1259c6c4 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js @@ -7,6 +7,7 @@ const useSavedMicroplans = (reqCriteria) => { ...config, cacheTime: 0, staleTime: 0, + onError: (err) => console.error("Error fetching saved microplans:", err), }); return { diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js similarity index 100% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js similarity index 100% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js similarity index 100% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js similarity index 100% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js similarity index 86% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js index 3dc963e042b..3885795450c 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js @@ -79,15 +79,15 @@ const CreateMicroplan = () => { }, }, }; - const { isLoading: ishierarchyLoading, data: heirarchyData } = Digit.Hooks.useCustomAPIHook(reqCriteria); + const { isLoading: ishierarchyLoading, data: hierarchyData } = Digit.Hooks.useCustomAPIHook(reqCriteria); // useEffect to initialise the data from MDMS useEffect(() => { let temp; if (!state || !state.UIConfiguration) return; - let UIConfiguration = state.UIConfiguration; + const UIConfiguration = state?.UIConfiguration || {}; if (UIConfiguration) temp = UIConfiguration.find((item) => item.name === "ruleConfigure"); - if (!(temp && temp.ruleConfigureOperators)) return; + if (!temp?.ruleConfigureOperators) return; setOperatorsObject(temp.ruleConfigureOperators); }, []); @@ -140,23 +140,29 @@ const CreateMicroplan = () => { return; } setLoaderActivation(true); - if (!microplanData?.planConfigurationId) { - await createPlanConfiguration(body, setCheckDataCompletion, setLoaderActivation); - } else if (microplanData && microplanData.planConfigurationId) { - await updatePlanConfiguration(body, setCheckDataCompletion, setLoaderActivation); + try { + if (!microplanData?.planConfigurationId) { + await createPlanConfiguration(body, setCheckDataCompletion, setLoaderActivation, state); + } else if (microplanData?.planConfigurationId) { + await updatePlanConfiguration(body, setCheckDataCompletion, setLoaderActivation, state); + } + } catch (error) { + console.error("Failed to create/update plan configuration:", error); } }, [microplanData, UpdateMutate, CreateMutate] ); - const createPlanConfiguration = async (body, setCheckDataCompletion, setLoaderActivation) => { + const createPlanConfiguration = async (body, setCheckDataCompletion, setLoaderActivation, state) => { await CreateMutate(body, { onSuccess: async (data) => { + const readMeConstant = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName"); const additionalProps = { - heirarchyData: heirarchyData, + hierarchyData: hierarchyData, t, campaignType, campaignData, + readMeSheetName: readMeConstant ? readMeConstant.value : undefined, }; const computedSession = await updateSessionUtils.computeSessionObject(data?.PlanConfiguration[0], state, additionalProps); if (computedSession) { @@ -182,16 +188,18 @@ const CreateMicroplan = () => { }); }; - const updatePlanConfiguration = async (body, setCheckDataCompletion, setLoaderActivation) => { + const updatePlanConfiguration = async (body, setCheckDataCompletion, setLoaderActivation, state) => { body.PlanConfiguration["id"] = microplanData?.planConfigurationId; body.PlanConfiguration["auditDetails"] = microplanData?.auditDetails; await UpdateMutate(body, { onSuccess: async (data) => { + const readMeConstant = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName"); const additionalProps = { - heirarchyData: heirarchyData, + hierarchyData: hierarchyData, t, campaignType, campaignData, + readMeSheetName: readMeConstant ? readMeConstant.value : undefined, }; const computedSession = await updateSessionUtils.computeSessionObject(data?.PlanConfiguration[0], state, additionalProps); if (computedSession) { @@ -220,20 +228,22 @@ const CreateMicroplan = () => { const setCurrentPageExternally = useCallback( (props) => { switch (props.method) { - case "set": + case "set": { let currentPage; const data = Digit.SessionStorage.get("microplanData"); - if (data && data?.currentPage) currentPage = data.currentPage; - if (currentPage && props && props?.setCurrentPage && timeLineOptions.find((item) => item.id === currentPage?.id)) { + if (data?.currentPage) currentPage = data.currentPage; + if (currentPage && props?.setCurrentPage && timeLineOptions.find((item) => item.id === currentPage?.id)) { props.setCurrentPage(currentPage); return true; } break; - case "save": - if (props && props.currentPage) { + } + case "save": { + if (props.currentPage) { setMicroplanData((previous) => ({ ...previous, currentPage: props.currentPage })); } break; + } } }, [microplanData, setMicroplanData, Navigator] diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js similarity index 100% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js similarity index 64% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js index bcfbdfd0db5..bbb0aef7628 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js @@ -1,4 +1,4 @@ -import React,{useState} from "react"; +import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { Header, InboxSearchComposerV2, Loader } from "@egovernments/digit-ui-react-components"; import { useHistory } from "react-router-dom"; @@ -114,47 +114,69 @@ const configs = { }; const SavedMicroplans = () => { - const [showLoader,setShowLoader] = useState(false) - const {state} = useMyContext() - const history = useHistory() + const [showLoader, setShowLoader] = useState(false); + const { state } = useMyContext(); + const history = useHistory(); const { t } = useTranslation(); - const onClickRow = async (row) => { - setShowLoader(true) - try { - const campaignType = row?.original?.CampaignDetails?.projectType; - const heirarchyData = await Digit.CustomService.getResponse({ - url: "/boundary-service/boundary-hierarchy-definition/_search", - useCache: false, - method: "POST", - userService: false, - body:{ - BoundaryTypeHierarchySearchCriteria: { - tenantId: Digit.ULBService.getStateId(), - hierarchyType: row?.original?.CampaignDetails?.hierarchyType, - }, + const fetchHierarchyData = async (hierarchyType) => { + const response = await Digit.CustomService.getResponse({ + url: "/boundary-service/boundary-hierarchy-definition/_search", + useCache: false, + method: "POST", + userService: false, + body: { + BoundaryTypeHierarchySearchCriteria: { + tenantId: Digit.ULBService.getStateId(), + hierarchyType, }, - }); - const additionalProps = { - heirarchyData:heirarchyData?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map((item) => item?.boundaryType), - t, - campaignType, - campaignData: row?.original?.CampaignDetails - } - //here compute the sessionObject based on the row?.original data and then re-route - const computedSession = await updateSessionUtils.computeSessionObject(row.original,state,additionalProps) - Digit.SessionStorage.set("microplanData", computedSession); - setShowLoader(false) - history.push(`/${window.contextPath}/employee/microplanning/create-microplan?id=${row?.original?.executionPlanId}`); - } catch (error) { - console.error(error.message) + }, + }); + if (response?.BoundaryHierarchy?.length) { + return response.BoundaryHierarchy[0].boundaryHierarchy.map((item) => item.boundaryType); } + console.error("Invalid response structure"); + }; + + const computeAdditionalProps = (row, state, t, hierarchyData) => { + const campaignDetails = row?.original?.CampaignDetails; + const readMeSheetName = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName")?.value; + return { + hierarchyData, + t, + campaignType: campaignDetails?.projectType, + campaignData: campaignDetails, + readMeSheetName, + }; + }; + + const onClickRow = (row) => { + const handleClick = async () => { + setShowLoader(true); + try { + const campaignType = row?.original?.CampaignDetails?.projectType; + const hierarchyData = await fetchHierarchyData(row?.original?.CampaignDetails?.hierarchyType); + const additionalProps = computeAdditionalProps(row, state, t, hierarchyData); + + // Compute the session object based on the row?.original data and then re-route + const computedSession = await updateSessionUtils.computeSessionObject(row.original, state, additionalProps); + Digit.SessionStorage.set("microplanData", computedSession); + + setShowLoader(false); + history.push(`/${window.contextPath}/employee/microplanning/create-microplan?id=${row?.original?.executionPlanId}`); + } catch (error) { + console.error(`Failed to process the request: ${error.message}`); + setShowLoader(false); + } + }; + + handleClick(); }; const savedMircoplanSession = Digit.Hooks.useSessionStorage("SAVED_MICROPLAN_SESSION", {}); - if(showLoader){ - return + if (showLoader) { + return ; } return ( @@ -169,7 +191,7 @@ const SavedMicroplans = () => { onClickRow, }, }} - > + />
); diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js similarity index 99% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js index 1dae49ee262..8f2131eefdd 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js @@ -118,7 +118,7 @@ const configs = { populators: { name: "endDate", error: "DATE_VALIDATION_MSG", - min: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString().slice(0,10), + min: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString().slice(0, 10), style: { marginBottom: "0px", }, @@ -217,7 +217,7 @@ const SelectCampaign = () => { onClickRow, }, }} - > + />
); diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js similarity index 95% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js index 4a06ca843e7..6f58779637a 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js @@ -11,7 +11,7 @@ import { useMyContext } from "../../utils/context"; const MicroplanningBreadCrumb = ({ location, defaultPath }) => { const { t } = useTranslation(); - const pathVar = location.pathname.replace(defaultPath + "/", "").split("?")?.[0]; + const pathVar = location.pathname.replace(`${defaultPath}/`, "").split("?")?.[0]; const { masterName, moduleName, uniqueIdentifier } = Digit.Hooks.useQueryParams(); const crumbs = [ @@ -59,7 +59,7 @@ const App = ({ path }) => { const [sessionFormDataView, setSessionFormDataView, clearSessionFormDataView] = MDMSViewSession; const { isLoading: isLoadingMdmsBaseData, data } = Digit.Hooks.useCustomMDMS( - "mz", + Digit.ULBService.getCurrentTenantId(), "hcm-microplanning", [ { name: "UploadConfiguration" }, @@ -75,6 +75,8 @@ const App = ({ path }) => { { name: "HierarchyConfigurations" }, { name: "NumberFormatMappingForTranslation" }, { name: "UploadGuidelines" }, + { name: "ReadMeData" }, + { name: "CommonConstants" }, ], { select: (data) => { @@ -90,7 +92,7 @@ const App = ({ path }) => { //destroying session useEffect(() => { - const pathVar = location.pathname.replace(path + "/", "").split("?")?.[0]; + const pathVar = location.pathname.replace(`${path}/`, "").split("?")?.[0]; Digit.Utils.microplan.destroySessionHelper(pathVar, ["create-microplan"], "microplanData"); Digit.Utils.microplan.destroySessionHelper(pathVar, ["create-microplan"], "microplanHelperData"); Digit.Utils.microplan.destroySessionHelper(pathVar, ["select-campaign"], "SELECT_CAMPAIGN_SESSION"); diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js similarity index 62% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js index c4f39680eb6..cabc9b67b56 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js @@ -7,9 +7,12 @@ const CreatePlanConfig = async (body) => { userService: true, body, }); - return response + return response; } catch (error) { - throw new Error(error?.response?.data?.Errors[0].message); + if (error?.response?.data?.Errors) { + throw new Error(error.response.data.Errors[0].message); + } + throw new Error("An unknown error occurred"); } }; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js similarity index 99% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js index 15b948907cb..83d4fb5fc72 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js @@ -169,7 +169,6 @@ export const Search = { projectDetails: response?.Project ? projectDetails : [], response: response?.Project, processInstancesDetails: [], - applicationData: {}, workflowDetails: [], applicationData: {}, isNoDataFound: response?.Project?.length === 0, diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js similarity index 60% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js index 3138d5a6df8..bb6a9f26916 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js @@ -7,12 +7,15 @@ const SearchCampaignConfig = async (body) => { userService: false, body, }); - if(response?.CampaignDetails?.length===0){ + if (response?.CampaignDetails?.length === 0) { throw new Error("Campaign not found with the given id"); } - return response?.CampaignDetails?.[0] + return response?.CampaignDetails?.[0]; } catch (error) { - throw new Error(error?.response?.data?.Errors[0].message); + if (error?.response?.data?.Errors) { + throw new Error(error.response.data.Errors[0].message); + } + throw new Error("An unknown error occurred"); } }; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js similarity index 62% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js index 5fb8001da1b..1fe11f206a7 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js @@ -7,9 +7,12 @@ const SearchPlanConfig = async (body) => { userService: true, body, }); - return response + return response; } catch (error) { - throw new Error(error?.response?.data?.Errors[0].message); + if (error?.response?.data?.Errors) { + throw new Error(error.response.data.Errors[0].message); + } + throw new Error("An unknown error occurred"); } }; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js similarity index 62% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js index 875529d35f3..d1623cbd167 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js @@ -7,9 +7,12 @@ const UpdatePlanConfig = async (body) => { userService: true, body, }); - return response + return response; } catch (error) { - throw new Error(error?.response?.data?.Errors[0].message); + if (error?.response?.data?.Errors) { + throw new Error(error.response.data.Errors[0].message); + } + throw new Error("An unknown error occurred"); } }; export default UpdatePlanConfig; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js similarity index 89% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js index 18914b95338..ba4342526a8 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js @@ -35,8 +35,8 @@ const SearchSavedPlans = async (body) => { }); const { PlanConfiguration } = responsePlan; - if(!PlanConfiguration || PlanConfiguration.length === 0) return []; - + if (!PlanConfiguration || PlanConfiguration.length === 0) return []; + const executionPlanIds = PlanConfiguration?.map((row) => row?.executionPlanId)?.filter((item) => item); const CampaignDetails = { tenantId: Digit.ULBService.getCurrentTenantId(), @@ -57,7 +57,10 @@ const SearchSavedPlans = async (body) => { }; return finalResult; } catch (error) { - throw new Error(error?.response?.data?.Errors[0].message); + if (error?.response?.data?.Errors) { + throw new Error(error.response.data.Errors[0].message); + } + throw new Error("An unknown error occurred"); } }; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js similarity index 100% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js similarity index 66% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js index a473399dbf1..a3f79c2358e 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js @@ -28,14 +28,14 @@ export const getFacilities = async (params, body) => { response = (await Digit.CustomService.getResponse(reqCriteria))?.Facilities || {}; } catch (error) { if (error.response) { - throw new Error("Failed to fetch facility data: " + error.response.data.message); - } else if (error.request) { + throw new Error(`Failed to fetch facility data: ${error.response.data.message}`); + } + if (error.request) { // Network error throw new Error("Network error while fetching facility data"); - } else { - // Other errors - throw new Error("Error while fetching facility data: " + error.message); } + // Other errors + throw new Error(`Error while fetching facility data: ${error.message}`); } return response; }; @@ -63,7 +63,7 @@ export const addBoundaryData = (xlsxData, boundaryData, hierarchyType) => { if (!boundaryData || !Array.isArray(boundaryData)) return; // Clone the current boundary predecessor to avoid modifying the original data - let rowData = [...currentBoundaryPredecessor]; + const rowData = [...currentBoundaryPredecessor]; // Clone the data accumulator to preserve the accumulated data let tempDataAccumulator = [...dataAccumulator]; // Use a set to accumulate unique hierarchy levels @@ -73,7 +73,7 @@ export const addBoundaryData = (xlsxData, boundaryData, hierarchyType) => { for (const item of boundaryData) { if (item?.code) { // Create a new row with the current item's code - let tempRow = [...rowData, item?.code]; + const tempRow = [...rowData, item?.code]; let response; // Add the current item's boundary type to the hierarchy tempHierarchyAccumulator.add(item.boundaryType); @@ -106,20 +106,21 @@ export const addBoundaryData = (xlsxData, boundaryData, hierarchyType) => { // Ensure all rows are of the same length by filling them with empty strings sortedBoundaryDataForXlsxSheet = sortedBoundaryDataForXlsxSheet.map((item, index) => { + let newItem = item; if (index !== 0) { - if (!item) { - item = []; + if (!newItem) { + newItem = []; } - let itemLength = item.length; - while (item.length <= topIndex) { - item.push(""); + const itemLength = newItem.length; + while (newItem.length <= topIndex) { + newItem.push(""); } - item.push(item[itemLength - 1]); + newItem.push(newItem[itemLength - 1]); } else { - item.push(commonColumn); + newItem.push(commonColumn); } - return item; + return newItem; }); // Add the new sheet data to the original data @@ -139,7 +140,7 @@ const fillDataWithBlanks = (data, tillRow) => { }; const generateLocalisationKeyForSchemaProperties = (code) => { if (!code) return code; - return SCHEMA_PROPERTIES_PREFIX + "_" + code; + return `${SCHEMA_PROPERTIES_PREFIX}_${code}`; }; /** * @@ -152,8 +153,8 @@ const generateLocalisationKeyForSchemaProperties = (code) => { const addSchemaData = (xlsxData, schema, extraColumnsToAdd) => { if (!schema) return xlsxData; let columnSchema = schema.schema?.Properties || {}; - let newXlsxData = []; - let columnList = [[], [], [], []]; // Initialize columnList with four empty arrays + const newXlsxData = []; + const columnList = [[], [], [], []]; // Initialize columnList with four empty arrays for (const [key, value] of Object.entries(columnSchema)) { if (key === commonColumn) continue; @@ -192,96 +193,79 @@ const addSchemaData = (xlsxData, schema, extraColumnsToAdd) => { * @param {string} hierarchyLevelName */ const devideXlsxDataHierarchyLevelWise = (xlsxData, hierarchyLevelName) => { - // If no hierarchyLevelName is provided, return the original data - if (!hierarchyLevelName) return xlsxData; + if (!hierarchyLevelName) return xlsxData; // Return original data if no hierarchy level name - // Initialize an array to hold the result - const result = []; - - // Array to store the row with empty hierarchy level value - let emptyHierarchyRow = []; + const result = []; // Initialize result array // Iterate over each sheet in the xlsxData for (const sheet of xlsxData) { const sheetData = sheet.data; - - // Find the index of the hierarchy level name in the header row const hierarchyLevelIndex = sheetData[0].indexOf(hierarchyLevelName); - // If the hierarchy level name is not found, skip this sheet + // If hierarchy level name not found, skip this sheet if (hierarchyLevelIndex === -1) { result.push(sheet); - return result; + continue; } - // Create a map to hold new sheets data based on hierarchy level values - const sheetsMap = {}; - // Create a map to hold dangling data for each hierarchy value - const danglingDataMap = {}; - // Flag to track if the last processed row had an empty hierarchy level value - let lastWasEmpty = true; - - // Iterate through the sheet data starting from the second row (skipping header) - for (let i = 1; i < sheetData.length; i++) { - const row = sheetData[i]; - const hierarchyValue = row[hierarchyLevelIndex]; - - // If the hierarchy value is not empty and there was previous empty data, - if (emptyHierarchyRow.length && hierarchyValue !== "") { - danglingDataMap[hierarchyValue] = emptyHierarchyRow; - } - - // If hierarchy value is empty, store this row - if (hierarchyValue === "" && lastWasEmpty) { - emptyHierarchyRow.push(row); - } else { - // store the empty data in the danglingDataMap for the current hierarchy value - if (emptyHierarchyRow.length && hierarchyValue === "") { - emptyHierarchyRow = []; // Reset emptyHierarchyRow - } - } - - // If this hierarchy value hasn't been seen before, create a new sheet for it - if (!sheetsMap[hierarchyValue] && hierarchyValue !== "") { - // Include all rows with empty hierarchy level data or different hierarchy values - sheetsMap[hierarchyValue] = { - sheetName: hierarchyValue, - data: [sheetData[0]], // Start with the header row - }; - } - - // Include the current row if its hierarchy level data matches the sheet's hierarchy value - if (hierarchyValue === row[hierarchyLevelIndex] && hierarchyValue !== "") { - sheetsMap[hierarchyValue].data.push(row); - } - - // Update the lastWasEmpty flag - if (hierarchyValue === "" && !lastWasEmpty) { - lastWasEmpty = true; - } else if (hierarchyValue !== "") { - lastWasEmpty = false; - } - } + const { sheetsMap, danglingDataMap } = processSheetData(sheetData, hierarchyLevelIndex); // Combine danglingDataMap with sheetsMap for (const key of Object.keys(danglingDataMap)) { if (sheetsMap[key]) { - // Combine dangling data with existing sheet data sheetsMap[key].data = [sheetData[0], ...danglingDataMap[key], ...sheetsMap[key].data.slice(1)]; } else { - // Create a new sheet for dangling data sheetsMap[key] = { sheetName: key, - data: [...danglingDataMap[key], sheetData[0]], // Include header row + data: [...danglingDataMap[key], sheetData[0]], }; } } - // Convert the sheets map to an array of objects and add to the result + // Add sheetsMap values to result result.push(...Object.values(sheetsMap)); } - return result || xlsxData; + return result.length > 0 ? result : xlsxData; // Return result or original data if result is empty +}; + +// Function to process sheet data and return sheetsMap and danglingDataMap +const processSheetData = (sheetData, hierarchyLevelIndex) => { + const sheetsMap = {}; + const danglingDataMap = {}; + let emptyHierarchyRow = []; + let lastWasEmpty = true; + + // Iterate through sheet data starting from the second row (skipping header) + for (let i = 1; i < sheetData.length; i++) { + const row = sheetData[i]; + const hierarchyValue = row[hierarchyLevelIndex]; + + if (emptyHierarchyRow.length && hierarchyValue !== "") { + danglingDataMap[hierarchyValue] = emptyHierarchyRow; + } + + if (hierarchyValue === "" && lastWasEmpty) { + emptyHierarchyRow.push(row); + } else { + emptyHierarchyRow = []; + } + + if (!sheetsMap[hierarchyValue] && hierarchyValue !== "") { + sheetsMap[hierarchyValue] = { + sheetName: hierarchyValue, + data: [sheetData[0]], + }; + } + + if (hierarchyValue === row[hierarchyLevelIndex] && hierarchyValue !== "") { + sheetsMap[hierarchyValue].data.push(row); + } + + lastWasEmpty = hierarchyValue === ""; + } + + return { sheetsMap, danglingDataMap }; }; export const filterBoundaries = (boundaryData, boundaryFilters) => { @@ -377,7 +361,7 @@ const addFacilitySheet = (xlsxData, mapping, facilities, schema, t) => { dataRow.push(headers.map((header) => facility[mapping[header]])); } headers.push(commonColumn); - let additionalCols = []; + const additionalCols = []; if (schema?.schema?.Properties) { const properties = Object.keys(schema.schema.Properties); for (const col of properties) { @@ -390,21 +374,43 @@ const addFacilitySheet = (xlsxData, mapping, facilities, schema, t) => { // Combine headers and data rows const arrayOfArrays = [headers.map((item) => generateLocalisationKeyForSchemaProperties(item)), ...dataRow]; - let facilitySheet = { + const facilitySheet = { sheetName: FACILITY_DATA_SHEET, data: arrayOfArrays, }; - xlsxData = [facilitySheet, ...xlsxData]; + const updatedXlsxData = [facilitySheet, ...xlsxData]; + return updatedXlsxData; +}; + +const addReadMeSheet = (xlsxData, readMeData, readMeSheetName) => { + if (!readMeSheetName) return xlsxData; + const data = readMeData.reduce((acc, item) => { + if (item?.header) { + acc.push([item.header], ...(item.points || []).map((item) => [item]), [], [], [], []); + } + return acc; + }, []); + + const readMeSheet = { + sheetName: readMeSheetName, + data: [["MICROPLAN_TEMPLATE_README_MAIN_HEADER"], [], [], [], ...data], + }; + xlsxData.unshift(readMeSheet); return xlsxData; }; /** - * - * @param {boolean} hierarchyLevelWiseSheets - * @param {string} hierarchyLevelName , if district Wise is true, then this must be present, - * @param {boolean} addFacilityData - * @param {Object} schema - * + * @param {Object} options + * @param {boolean} options.hierarchyLevelWiseSheets + * @param {string} options.hierarchyLevelName + * @param {boolean} options.addFacilityData + * @param {Object} options.schema + * @param {Object[]} options.boundaries + * @param {string} options.tenantId + * @param {string} options.hierarchyType + * @param {Object} options.readMeData + * @param {string} options.readMeSheetName + * @param {string} options.t // Assuming t is some context or translation object */ export const createTemplate = async ({ hierarchyLevelWiseSheets = true, @@ -414,67 +420,66 @@ export const createTemplate = async ({ boundaries, tenantId, hierarchyType, + readMeData, + readMeSheetName, t, }) => { - const rootBoundary = boundaries?.filter((boundary) => boundary.isRoot); // Retrieve session storage data once and store it in a variable + // Fetch or retrieve boundary data + const filteredBoundaries = await fetchFilteredBoundaries(boundaries, tenantId, hierarchyType); + + // Initialize xlsxData array + let xlsxData = []; + + // Add boundary data to xlsxData + xlsxData = addBoundaryData(xlsxData, filteredBoundaries, hierarchyType); + + // Handle hierarchy level sheets + if (hierarchyLevelWiseSheets) { + xlsxData = devideXlsxDataHierarchyLevelWise(xlsxData, hierarchyLevelName); + } + + // Handle facility data addition + if (addFacilityData) { + xlsxData = await addFacilityDataToSheets(xlsxData, schema, tenantId, t); + } else { + // If no facility data, add schema data directly + xlsxData = addSchemaData(xlsxData, schema); + } + + // Add readme sheet data if provided + xlsxData = addReadMeSheet(xlsxData, readMeData, readMeSheetName); + + return xlsxData; +}; + +// Function to fetch filtered boundaries +const fetchFilteredBoundaries = async (boundaries, tenantId, hierarchyType) => { + const rootBoundary = boundaries?.find((boundary) => boundary.isRoot); const sessionData = Digit.SessionStorage.get("microplanHelperData") || {}; let boundaryData = sessionData.filteredBoundaries; - let filteredBoundaries; if (!boundaryData) { - // Only fetch boundary data if not present in session storage - boundaryData = await fetchBoundaryData(tenantId, hierarchyType, rootBoundary?.[0]?.code); - filteredBoundaries = await filterBoundaries(boundaryData, boundaries); - - // Update the session storage with the new filtered boundaries + boundaryData = await fetchBoundaryData(tenantId, hierarchyType, rootBoundary?.code); + const filteredBoundaries = await filterBoundaries(boundaryData, boundaries); Digit.SessionStorage.set("microplanHelperData", { ...sessionData, filteredBoundaries: filteredBoundaries, }); - } else { - filteredBoundaries = boundaryData; + return filteredBoundaries; } + return boundaryData; +}; - // const filteredBoundaryData = boundaryData; - let xlsxData = []; - // adding boundary data to xlsxData - xlsxData = addBoundaryData(xlsxData, filteredBoundaries, hierarchyType); - - if (hierarchyLevelWiseSheets) { - // district wise boundary Data sheets - xlsxData = devideXlsxDataHierarchyLevelWise(xlsxData, hierarchyLevelName); - if (addFacilityData) { - // adding facility sheet - const facilities = await getAllFacilities(tenantId); - if (schema?.template?.facilitySchemaApiMapping) - xlsxData = addFacilitySheet(xlsxData, schema?.template?.facilitySchemaApiMapping, facilities, schema, t); - else xlsxData = addSchemaData(xlsxData, schema); - } else { - // not adding facility sheet - // adding schema data to xlsxData - xlsxData = addSchemaData(xlsxData, schema); - } - } else { - // total boundary Data in one sheet - if (addFacilityData) { - // adding facility sheet - const facilities = await getAllFacilities(tenantId); - if (schema?.template?.facilitySchemaApiMapping) - xlsxData = addFacilitySheet(xlsxData, schema?.template?.facilitySchemaApiMapping, facilities, schema, t); - else { - let facilitySheet = { - sheetName: FACILITY_DATA_SHEET, - data: [], - }; - facilitySheet = addSchemaData([facilitySheet], schema, [commonColumn]); - xlsxData = [...facilitySheet, ...xlsxData]; - } - } else { - // not adding facility sheet - - // adding schema data to xlsxData - xlsxData = addSchemaData(xlsxData, schema); - } +// Function to add facility data to sheets +const addFacilityDataToSheets = async (xlsxData, schema, tenantId, t) => { + const facilities = await getAllFacilities(tenantId); + if (schema?.template?.facilitySchemaApiMapping) { + return addFacilitySheet(xlsxData, schema.template.facilitySchemaApiMapping, facilities, schema, t); } - return xlsxData; + // If no specific facility schema mapping, add default facility data + const facilitySheet = { + sheetName: FACILITY_DATA_SHEET, + data: [], + }; + return addSchemaData([facilitySheet], schema); }; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js similarity index 100% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js new file mode 100644 index 00000000000..0d2a344a8f1 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js @@ -0,0 +1,199 @@ +import Ajv from "ajv"; +const ajv = new Ajv({ allErrors: true }); +ajv.addKeyword("isRequired"); +ajv.addKeyword("isLocationDataColumns"); +ajv.addKeyword("isRuleConfigureInputs"); +ajv.addKeyword("isFilterPropertyOfMapSection"); +ajv.addKeyword("isVisualizationPropertyOfMapSection"); +ajv.addKeyword("toShowInMicroplanPreview"); + +// Function responsible for excel data validation with respect to the template/schema provided +const translateSchema = (schemaData) => { + const required = Object.entries(schemaData?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.isRequired) { + acc.push(key); + } + return acc; + }, []); + + return { required, properties: schemaData.Properties }; +}; + +const createSchema = (properties, required) => { + return { + type: "object", + patternProperties: { + ".*": { + type: "array", + items: { + type: "object", + properties: properties, + required: required, + additionalProperties: true, + }, + }, + }, + minProperties: 1, + additionalProperties: false, + }; +}; + +const extractLocationDataColumns = (schemaData) => { + return Object.entries(schemaData?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.isLocationDataColumns) { + acc.push(key); + } + return acc; + }, []); +}; + +const setNestedError = (errors, path, error) => { + if (!path.length) return; + + let current = errors; + for (let i = 0; i < path.length - 1; i++) { + if (!current[path[i]]) { + current[path[i]] = {}; + } + current = current[path[i]]; + } + + if (!current[path[path.length - 1]]) { + current[path[path.length - 1]] = []; + } + + current[path[path.length - 1]] = [...new Set([...current[path[path.length - 1]], error])]; +}; + +const formatErrors = (validateExcelErrors, locationDataColumns, t) => { + const errors = {}; + let hasDataErrors = "false"; // true, false, missing_properties, unknown + const missingColumnsList = new Set(); + let errorMessages = {}; + + validateExcelErrors.forEach((error) => { + let tempErrorStore = ""; + let instancePathTypeGlobal; + + switch (error.keyword) { + case "additionalProperties": + tempErrorStore = "ERROR_ADDITIONAL_PROPERTIES"; + hasDataErrors = "true"; + break; + case "type": + { + const instancePathType = error.instancePath.split("/"); + const neededType = error.params?.type; + instancePathTypeGlobal = instancePathType; + tempErrorStore = locationDataColumns.includes(instancePathType[instancePathType.length - 1]) + ? "ERROR_INCORRECT_LOCATION_COORDINATES" + : neededType === "number" + ? "ERROR_MUST_BE_A_NUMBER" + : "ERROR_MUST_BE_A_STRING"; + hasDataErrors = "true"; + } + break; + case "required": + { + const missing = error.params.missingProperty; + const instancePathType = error.instancePath.split("/"); + instancePathTypeGlobal = [...instancePathType, missing]; + tempErrorStore = "ERROR_MANDATORY_FIELDS_CANT_BE_EMPTY"; + missingColumnsList.add(missing); + hasDataErrors = "true"; + } + break; + case "maximum": + case "minimum": + { + const instancePathMinMax = error.instancePath.split("/"); + instancePathTypeGlobal = instancePathMinMax; + tempErrorStore = locationDataColumns.includes(instancePathMinMax[instancePathTypeGlobal.length - 1]) + ? "ERROR_INCORRECT_LOCATION_COORDINATES" + : "ERROR_DATA_EXCEEDS_LIMIT_CONSTRAINTS"; + hasDataErrors = "true"; + } + break; + case "pattern": + tempErrorStore = "ERROR_VALUE_NOT_ALLOWED"; + hasDataErrors = "true"; + break; + case "minProperties": + hasDataErrors = "minProperties"; + break; + case "enum": + { + const instancePathType = error.instancePath.split("/"); + instancePathTypeGlobal = instancePathType; + tempErrorStore = { + error: "ERROR_UPLOAD_DATA_ENUM", + values: { allowedValues: error.params?.allowedValues?.map((item) => t(item)).join(", ") }, + }; + hasDataErrors = "true"; + } + break; + default: + hasDataErrors = "unknown"; + } + + if (tempErrorStore && instancePathTypeGlobal) { + setNestedError(errors, instancePathTypeGlobal.slice(1, 4), tempErrorStore); + } + + switch (hasDataErrors) { + case "true": + errorMessages = { dataError: "ERROR_REFER_UPLOAD_PREVIEW_TO_SEE_THE_ERRORS" }; + break; + case "minProperties": + errorMessages = { minProperties: "ERROR_UPLOADED_DATA_IS_EMPTY" }; + break; + case "unknown": + errorMessages = { unknown: "ERROR_UNKNOWN" }; + break; + case "false": + break; + } + }); + + return { + valid: !hasDataErrors, + message: errorMessages ? [...new Set(Object.values(errorMessages))] : [], + errors, + missingColumnsList, + }; +}; + +export const excelValidations = (data, schemaData, t) => { + const { required, properties } = translateSchema(schemaData); + const schema = createSchema(properties, required); + const validateExcel = ajv.compile(schema); + const valid = validateExcel(data); + const locationDataColumns = extractLocationDataColumns(schemaData); + + if (!valid) { + const validationResult = formatErrors(validateExcel.errors, locationDataColumns, t); + ajv.removeSchema(); + return validationResult; + } + + ajv.removeSchema(); + return { valid }; +}; + +export const checkForErrorInUploadedFileExcel = async (fileInJson, schemaData, t) => { + try { + const valid = excelValidations(fileInJson, schemaData, t); + if (valid.valid) { + return { valid: true }; + } + return { + valid: false, + message: valid.message, + errors: valid.errors, + missingProperties: valid.missingColumnsList, + }; + } catch (error) { + console.error("Error in excel validations: ", error?.message); + return { valid: false, message: ["ERROR_PARSING_FILE"] }; + } +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js new file mode 100644 index 00000000000..f2d4f277ba6 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js @@ -0,0 +1,99 @@ +import ExcelJS from "exceljs"; + +// input is a xlsx blob +// options {header} +// header: true -> have seperate header so data will be in key: value pair +export const parseXlsxToJsonMultipleSheets = async (file, options = {}) => { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + + reader.onload = async (event) => { + try { + const arrayBuffer = event.target.result; + const workbook = await loadWorkbook(arrayBuffer); + const jsonData = processWorkbook(workbook, options); + resolve(jsonData); + } catch (error) { + console.error(error); + resolve({ error: true }); + } + }; + + reader.onerror = (error) => { + console.error(error); + resolve({ error: true, details: error }); + }; + + reader.readAsArrayBuffer(file); + }); +}; + +const loadWorkbook = async (arrayBuffer) => { + const workbook = new ExcelJS.Workbook(); + await workbook.xlsx.load(arrayBuffer); + return workbook; +}; + +const processWorkbook = (workbook, options) => { + const jsonData = {}; + workbook.eachSheet((worksheet) => { + const jsonSheetData = processSheet(worksheet, options); + if (jsonSheetData.length !== 0 && jsonSheetData?.[0].length !== 0) { + jsonData[worksheet.name] = jsonSheetData; + } + }); + return jsonData; +}; + +const processSheet = (worksheet, options) => { + const jsonSheetData = []; + let headers = []; + + worksheet.eachRow({ includeEmpty: true }, (row, rowNumber) => { + const rowData = cleanRowData(row.values); + if (options.header && rowNumber === 1) { + headers = rowData; + } else if (options.header && headers.length > 0) { + jsonSheetData.push(mapRowToHeaders(rowData, headers)); + } else { + jsonSheetData.push(rowData); + } + }); + + removeTrailingEmptyRows(jsonSheetData); + return jsonSheetData; +}; + +const cleanRowData = (rowData) => { + return rowData.slice(1).map((cell) => (typeof cell === "string" ? cell.trim() : cell)); +}; + +const mapRowToHeaders = (rowData, headers) => { + const rowObject = {}; + headers.forEach((header, index) => { + rowObject[header] = rowData[index]; + }); + return rowObject; +}; + +const removeTrailingEmptyRows = (data) => { + while (data.length > 0) { + const lastRow = data[data.length - 1]; + const isEmptyRow = checkIfRowIsEmpty(lastRow); + if (isEmptyRow) { + data.pop(); + } else { + break; + } + } +}; + +const checkIfRowIsEmpty = (row) => { + if (Array.isArray(row)) { + return row.filter((item) => item !== "").length === 0; + } + if (typeof row === "object" && row !== null) { + return Object.values(row).filter((item) => item !== "").length === 0; + } + return false; +}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js similarity index 93% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js index 5e6b42ee060..42a465740b5 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js @@ -22,20 +22,14 @@ gjv.define("Position", (position) => { // Main functino for geojson validation that includes structural and property validations export const geojsonValidations = (data, schemaData, t) => { - let valid = geojsonStructureValidation(data); - if (valid.valid) { - return { valid: true }; - } - if (valid.message) { - return { valid: false, message: valid.message }; - } - return { valid: false, message: ["ERROR_INVALID_GEOJSON"] }; + const valid = geojsonStructureValidation(data); + return valid.valid ? { valid: true } : { valid: false, message: valid.message || ["ERROR_INVALID_GEOJSON"] }; }; // Funciton responsible for structural verification of geojson data export const geojsonStructureValidation = (data) => { let valid = true; - let trace = {}; + const trace = {}; for (let i = 0; i < data["features"].length; i++) { const check = gjv.valid(data["features"][i]); valid = valid && check; @@ -72,16 +66,14 @@ const geometryValidation = (data) => { }; // Function responsible for property verification of geojson data -export const geojsonPropetiesValidation = (data, schemaData, name, t) => { +export const geojsonPropertiesValidation = (data, schemaData, name, t) => { const translate = () => { - const required = Object.entries(schemaData?.Properties || {}) - .reduce((acc, [key, value]) => { - if (value?.isRequired) { - acc.push(key); - } - return acc; - }, []) - .map((item) => item); + const required = Object.entries(schemaData?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.isRequired) { + acc.push(key); + } + return acc; + }, []); // const properties = prepareProperties(schemaData.Properties, t); return { required, properties: schemaData.Properties }; @@ -112,9 +104,9 @@ export const geojsonPropetiesValidation = (data, schemaData, name, t) => { }; const validateGeojson = ajv.compile(schema); const valid = validateGeojson(data); - let errors = {}; + const errors = {}; let hasDataErrors = "false"; // true, false, missing_properties, unknown - let missingColumnsList = new Set(); + const missingColumnsList = new Set(); let errorMessages = []; if (!valid) { for (let i = 0; i < validateGeojson.errors.length; i++) { diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js similarity index 63% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js index 3f3d1d95b40..0d21a93ca46 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js @@ -3,16 +3,17 @@ import { findChildren, findParent } from "../utils/processHierarchyAndData"; import { EXCEL, LOCALITY, commonColumn } from "../configs/constants"; const formatDates = (value, type) => { - if (type !== "EPOC" && (!value || Number.isNaN(Number(value)))) { - value = new Date(); + let newValue = value; + if (type !== "EPOC" && (!newValue || Number.isNaN(Number(newValue)))) { + newValue = new Date(); } switch (type) { case "date": - return new Date(value)?.toISOString?.()?.split?.("T")?.[0]; + return new Date(newValue)?.toISOString?.()?.split?.("T")?.[0]; case "datetime": - return new Date(value).toISOString(); + return new Date(newValue).toISOString(); case "EPOC": - return String(new Date(value)?.getTime()); + return String(new Date(newValue)?.getTime()); } }; @@ -61,15 +62,17 @@ const computeGeojsonWithMappedProperties = ({ campaignType, fileType, templateId const sortedSecondList = sortSecondListBasedOnFirstListOrder(schemaKeys, resourceMapping); // Creating a object with input data with MDMS keys const newFeatures = fileData.data["features"].map((item) => { - let newProperties = {}; - - sortedSecondList.forEach((e) => { - newProperties[e["mappedTo"]] = item["properties"][e["mappedFrom"]]; - }); + const newProperties = sortedSecondList.reduce( + (acc, e) => ({ + ...acc, + [e["mappedTo"]]: item["properties"][e["mappedFrom"]], + }), + {} + ); item["properties"] = newProperties; return item; }); - let data = fileData.data; + const data = fileData.data; data["features"] = newFeatures; return data; }; @@ -130,31 +133,22 @@ const computeDifferences = (data1, data2) => { }; const extractNames = (data) => { - let names = []; - - for (let key in data) { - if (Array.isArray(data[key])) { - data[key].forEach((item) => { - if (item.name) { - names.push(item.name); - } - }); - } - } - - return names; + return Object.values(data) + .flatMap((items) => items) + .filter((item) => item.name) + .map((item) => item.name); }; // function that handles dropdown selection. used in: mapping and microplan preview const handleSelection = (e, boundaryType, boundarySelections, hierarchy, setBoundarySelections, boundaryData, setIsLoading) => { setIsLoading(true); if (!e || !boundaryType) return; - let selections = e.map((item) => item?.[1]); - let newComputedSelection = { ...boundarySelections, [boundaryType]: selections }; + const selections = e.map((item) => item?.[1]); + const newComputedSelection = { ...boundarySelections, [boundaryType]: selections }; const { removed, added } = computeDifferences(boundarySelections, newComputedSelection); // for(const item in removed){ if (removed && Object.keys(removed).length !== 0 && Object.values(removed)?.flatMap((item) => item).length !== 0) { - let filteredRemoved = extractNames(removed); - let children = Object.values(findChildren(filteredRemoved, Object.values(boundaryData)?.[0]?.hierarchicalData))?.map((item) => item?.name); + const filteredRemoved = extractNames(removed); + const children = Object.values(findChildren(filteredRemoved, Object.values(boundaryData)?.[0]?.hierarchicalData))?.map((item) => item?.name); for (const key in newComputedSelection) { newComputedSelection[key] = newComputedSelection[key].filter((item) => !children.includes(item?.name)); } @@ -164,166 +158,118 @@ const handleSelection = (e, boundaryType, boundarySelections, hierarchy, setBoun // Preventing default action when we scroll on input[number] is that it increments or decrements the number const inputScrollPrevention = (e) => { - e.target.addEventListener( - "wheel", - function (e) { - e.preventDefault(); - }, - { passive: false } - ); + e.target.addEventListener("wheel", (e) => e.preventDefault(), { passive: false }); }; -// Construct api request body const mapDataForApi = (data, Operators, microplanName, campaignId, status, reqType = "update") => { - let files = [], - resourceMapping = []; + const files = extractFiles(data, reqType); + const resourceMapping = extractResourceMapping(data, reqType); + const assumptions = extractAssumptions(data, reqType); + const operations = extractOperations(data, Operators, reqType); + + return createApiRequestBody(status, microplanName, campaignId, files, assumptions, operations, resourceMapping); +}; + +const extractFiles = (data, reqType) => { + const files = []; if (data && data.upload) { - Object.values(data?.upload).forEach((item) => { - if (!item || item.error || !item.filestoreId) return; - if (reqType === "create" && !item?.active) return; - const data = { - active: item?.active, - filestoreId: item?.filestoreId, - inputFileType: item?.fileType, - templateIdentifier: item?.section, - id: item?.fileId, - }; - files.push(data); - }); - Object.values(data?.upload).forEach((item) => { - if (reqType === "create" && item.resourceMapping && item.resourceMapping.every((item) => item.active === false)) return; - if ( - !item || - !item.resourceMapping || - item.error || - !Array.isArray(item.resourceMapping) || - !item.resourceMapping.every((item) => item.mappedFrom) || - !item.resourceMapping.every((item) => item.mappedTo) - ) - return; - resourceMapping.push(item?.resourceMapping); + Object.values(data.upload).forEach((item) => { + if (isValidFile(item, reqType)) { + files.push(mapFile(item)); + } }); - resourceMapping = resourceMapping.flatMap((inner) => inner); } - - // return a Create API body - return { - PlanConfiguration: { - status, - tenantId: Digit.ULBService.getStateId(), - name: microplanName, - executionPlanId: campaignId, - files, - assumptions: data?.hypothesis?.reduce((acc, item) => { - if (reqType === "create" && !item?.active) return acc; - if (item.key && item.value) { - acc.push(JSON.parse(JSON.stringify(item))); - } - return acc; - }, []), - operations: data?.ruleEngine?.reduce((acc, item) => { - if (reqType === "create" && !item?.active) return acc; - if (!item.active && !item.input) { - const data = { ...item }; - const operator = Operators.find((e) => e.name === data.operator); - if (operator && operator.code) data.operator = operator?.code; - if (data?.oldInput) data.input = data.oldInput; - acc.push(data); - return acc; - } - if (!item.active && !item.operator && !item.output && !item.input && !item.assumptionValue) return acc; - const data = { ...item }; - const operator = Operators.find((e) => e.name === data.operator); - if (operator && operator.code) data.operator = operator?.code; - acc.push(data); - // } - return acc; - }, []), - resourceMapping, - }, - }; + return files; }; -const resourceMappingAndDataFilteringForExcelFiles = (schemaData, hierarchy, selectedFileType, fileDataToStore, t, translatedData = true) => { - let resourceMappingData = []; - let newFileData = {}; - let toAddInResourceMapping; +const isValidFile = (item, reqType) => { + if (!item || item.error || !item.filestoreId) return false; + if (reqType === "create" && !item.active) return false; + return true; +}; - if (selectedFileType.id === EXCEL && fileDataToStore) { - // Extract all unique column names from the first row of each sheet in fileDataToStore for resource mapping - const columnForMapping = new Set(Object.values(fileDataToStore).flatMap((value) => value?.[0] || [])); +const mapFile = (item) => ({ + active: item.active, + filestoreId: item.filestoreId, + inputFileType: item.fileType, + templateIdentifier: item.section, + id: item.fileId, +}); - if (schemaData?.schema?.["Properties"]) { - let toChange; - if (LOCALITY && hierarchy[hierarchy?.length - 1] !== LOCALITY) { - toChange = hierarchy[hierarchy?.length - 1]; +const extractResourceMapping = (data, reqType) => { + let resourceMapping = []; + if (data && data.upload) { + Object.values(data.upload).forEach((item) => { + if (isValidResourceMapping(item, reqType)) { + resourceMapping.push(item.resourceMapping); } + }); + resourceMapping = resourceMapping.flat(); + } + return resourceMapping; +}; - // Get schema keys and hierarchy to map columns - const schemaKeys = Object.keys(schemaData.schema["Properties"]).concat(hierarchy); - - schemaKeys.forEach((item) => { - // Check if the column is present in the file, either in translated form or original form based on translatedData flag - if ((translatedData && columnForMapping.has(t(item))) || (!translatedData && columnForMapping.has(item))) { - // Special case for LOCALITY - if (LOCALITY && toChange === item) { - toAddInResourceMapping = { - mappedFrom: t(item), - mappedTo: LOCALITY, - }; - } - // Add the mapping information - resourceMappingData.push({ - mappedFrom: t(item), - mappedTo: item, - }); - } - }); +const isValidResourceMapping = (item, reqType) => { + if (reqType === "create" && item.resourceMapping && item.resourceMapping.every((i) => i.active === false)) return false; + if (!item || !item.resourceMapping || item.error || !Array.isArray(item.resourceMapping)) return false; + if (!item.resourceMapping.every((i) => i.mappedFrom && i.mappedTo)) return false; + return true; +}; + +const extractAssumptions = (data, reqType) => { + if (!data || !data.hypothesis) return []; + return data.hypothesis.reduce((acc, item) => { + if (isValidAssumption(item, reqType)) { + acc.push({ ...item }); } + return acc; + }, []); +}; - // Filter and map the columns of fileDataToStore based on resource mapping - Object.entries(fileDataToStore).forEach(([key, value]) => { - let data = []; - let headers = []; - let toRemove = []; - - if (value && value.length > 0) { - // Process header row - value[0].forEach((item, index) => { - // Find the corresponding mapped column name - const mappedTo = resourceMappingData.find((e) => (translatedData && e.mappedFrom === item) || (!translatedData && e.mappedFrom === t(item))) - ?.mappedTo; - if (!mappedTo) { - toRemove.push(index); // Mark column for removal if not mapped - return; - } - headers.push(mappedTo); // Add mapped column name to headers - }); - - // Process data rows - for (let i = 1; i < value?.length; i++) { - let temp = []; - for (let j = 0; j < value[i].length; j++) { - if (!toRemove.includes(j)) { - temp.push(value[i][j]); // Keep only the columns that are mapped - } - } - data.push(temp); - } - } +const isValidAssumption = (item, reqType) => { + if (reqType === "create" && !item.active) return false; + if (!item.key || !item.value) return false; + return true; +}; - // Combine headers and data for each sheet - newFileData[key] = [headers, ...data]; - }); - } +const extractOperations = (data, Operators, reqType) => { + if (!data || !data.ruleEngine) return []; + return data.ruleEngine.reduce((acc, item) => { + if (isValidOperation(item, reqType)) { + acc.push(mapOperation(item, Operators)); + } + return acc; + }, []); +}; - // Finalize the resource mapping data - resourceMappingData.pop(); - resourceMappingData.push(toAddInResourceMapping); +const isValidOperation = (item, reqType) => { + if (reqType === "create" && !item.active) return false; + if (!item.active && !item.input) return true; + if (!item.active && !item.operator && !item.output && !item.input && !item.assumptionValue) return false; + return true; +}; - return { tempResourceMappingData: resourceMappingData, tempFileDataToStore: newFileData }; +const mapOperation = (item, Operators) => { + const data = { ...item }; + const operator = Operators.find((e) => e.name === data.operator); + if (operator && operator.code) data.operator = operator.code; + if (data.oldInput) data.input = data.oldInput; + return data; }; +const createApiRequestBody = (status, microplanName, campaignId, files, assumptions, operations, resourceMapping) => ({ + PlanConfiguration: { + status, + tenantId: Digit.ULBService.getStateId(), + name: microplanName, + executionPlanId: campaignId, + files, + assumptions, + operations, + resourceMapping, + }, +}); + const addResourcesToFilteredDataToShow = (previewData, resources, hypothesisAssumptionsList, formulaConfiguration, userEditedResources, t) => { // Clone the preview data to avoid mutating the original data const data = _.cloneDeep(previewData); @@ -387,10 +333,10 @@ const calculateResource = (resourceName, rowData, formulaConfiguration, headers, // Finding Input // check for Uploaded Data - let inputValue = findInputValue(formula, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t); - if (inputValue == undefined || inputValue === null) return null; - let assumptionValue = hypothesisAssumptionsList?.find((item) => item?.active && item?.key === formula?.assumptionValue)?.value; - if (assumptionValue == undefined) return null; + const inputValue = findInputValue(formula, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t); + if (inputValue === undefined || inputValue === null) return null; + const assumptionValue = hypothesisAssumptionsList?.find((item) => item?.active && item?.key === formula?.assumptionValue)?.value; + if (assumptionValue === undefined) return null; return findResult(inputValue, assumptionValue, formula?.operator); }; @@ -522,7 +468,6 @@ export default { inputScrollPrevention, handleSelection, convertGeojsonToExcelSingleSheet, - resourceMappingAndDataFilteringForExcelFiles, sortSecondListBasedOnFirstListOrder, addResourcesToFilteredDataToShow, calculateResource, diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js new file mode 100644 index 00000000000..ae470038a91 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js @@ -0,0 +1,72 @@ +import ExcelJS from "exceljs"; +import { SHEET_COLUMN_WIDTH } from "../configs/constants"; + +export const convertJsonToXlsx = async (jsonData, columnWithStyle, returnWorkbook = false) => { + const workbook = new ExcelJS.Workbook(); + + for (const [sheetName, data] of Object.entries(jsonData)) { + const worksheet = workbook.addWorksheet(sheetName); + populateWorksheet(worksheet, data, columnWithStyle); + } + + if (returnWorkbook) return workbook; + return await writeWorkbookToBuffer(workbook); +}; + +const populateWorksheet = (worksheet, data, columnWithStyle) => { + data.forEach((row, rowIndex) => { + const newRow = worksheet.addRow(row); + if (columnWithStyle?.errorColumn && rowIndex > 0) { + applyStyleToColumn(newRow, data[0], columnWithStyle); + } + }); + + styleHeaderRow(worksheet); + setColumnWidths(worksheet); +}; + +/** + * Applies a specified style to a column in a given row of a spreadsheet. + * + * @param {Object} newRow - The row object where the style will be applied. + * @param {Array} headerRow - The header row array containing column names. + * @param {Object} columnWithStyle - An object containing the column name and the style to be applied. + * @param {string} columnWithStyle.errorColumn - The name of the column where the style should be applied. + * @param {Object} columnWithStyle.style - The style properties to be applied to the cell. + */ +const applyStyleToColumn = (newRow, headerRow, columnWithStyle) => { + const errorColumnIndex = headerRow.indexOf(columnWithStyle.errorColumn); + if (errorColumnIndex !== -1) { + const columnIndex = errorColumnIndex + 1; + const newCell = newRow.getCell(columnIndex); + if (columnWithStyle.style && newCell) { + for (const key in columnWithStyle.style) { + newCell[key] = columnWithStyle.style[key]; + } + } + } +}; + +const styleHeaderRow = (worksheet) => { + const headerRow = worksheet.getRow(1); + if (headerRow) { + headerRow.font = { bold: true }; + } +}; + +const setColumnWidths = (worksheet) => { + // Iterate over all rows in the worksheet + worksheet.eachRow((worksheetRow, rowNumber) => { + worksheetRow.eachCell((cell, colNumber) => { + // Update column width based on the length of the cell's text + const currentWidth = worksheet.getColumn(colNumber).width || SHEET_COLUMN_WIDTH; // Default width or current width + const newWidth = Math.max(currentWidth, cell.value.toString().length + 2); // Add padding + worksheet.getColumn(colNumber).width = newWidth; + }); + }); +}; + +export const writeWorkbookToBuffer = async (workbook) => { + const buffer = await workbook.xlsx.writeBuffer({ compression: true }); + return new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/mappingUtils.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/mappingUtils.js new file mode 100644 index 00000000000..f742ffd5e47 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/mappingUtils.js @@ -0,0 +1,760 @@ +import L from "leaflet"; +import "leaflet/dist/leaflet.css"; +import { processHierarchyAndData, findChildren, calculateAggregateForTree } from "../utils/processHierarchyAndData"; +import { EXCEL, GEOJSON, SHAPEFILE, MapChoroplethGradientColors } from "../configs/constants"; +import { PopulationSvg } from "../icons/Svg"; +import chroma from "chroma-js"; +import * as MicroplanIconCollection from "../icons/Svg"; +import * as DigitSvgs from "@egovernments/digit-ui-svg-components"; + +const IconCollection = { ...MicroplanIconCollection, ...DigitSvgs }; + +export const generatePreviewUrl = (baseMapUrl, center = [0, 0], zoom = 5) => { + const lon = Math.floor(((center[1] + 180) / 360) * Math.pow(0, zoom)); + const lat = Math.floor( + ((1 - Math.log(Math.tan((center[0] * Math.PI) / 180) + 1 / Math.cos((center[0] * Math.PI) / 180)) / Math.PI) / 2) * Math.pow(2, zoom) + ); + if (baseMapUrl) { + return baseMapUrl.replace("{z}", zoom).replace("{x}", lat).replace("{y}", lon); + } + // Return a default preview URL or handle this case as needed + return "default-preview-url.jpg"; // todo +}; + +// get schema for validation +export const getSchema = (campaignType, type, section, schemas) => { + return schemas.find((schema) => { + if (!schema.campaignType) { + return schema.type === type && schema.section === section; + } + return schema.campaignType === campaignType && schema.type === type && schema.section === section; + }); +}; + +export const calculateAggregateForTreeMicroplanWrapper = (entity) => { + if (!entity || typeof entity !== "object") return {}; + let newObject = {}; + for (let [key, value] of Object.entries(entity)) { + if (!value?.["hierarchicalData"]) continue; + let aggregatedTree = calculateAggregateForTree(value?.["hierarchicalData"]); + newObject[key] = { ...value, hierarchicalData: aggregatedTree }; + } + return newObject; +}; + +export const extractGeoData = ( + campaignType, + microplanData, + filterDataOrigin, + validationSchemas, + setToast, + setDataAvailability, + hierarchy, + setBoundaryData, + setFilterData, + setFilterProperties, + setFilterSelections, + setFilterPropertyNames, + state, + setChoroplethProperties, + setDataCompleteness, + t +) => { + if (!hierarchy) return; + + const initializeDataAvailability = (microplanData) => (microplanData?.upload ? "initialStage" : undefined); + + const checkFileActivity = (fileData) => fileData.active; + + const checkFileSection = (fileData, filterDataOrigin) => + filterDataOrigin?.boundriesDataOrigin?.includes(fileData?.section) || filterDataOrigin?.layerDataOrigin?.includes(fileData?.section); + + const getFileValidationSchema = (campaignType, fileData, validationSchemas) => + getSchema(campaignType, fileData?.fileType, fileData?.section, validationSchemas); + + const updateDataAvailabilityCheck = (dataAvailabilityCheck, condition, partialState) => + condition ? partialState : dataAvailabilityCheck === "initialStage" ? "false" : partialState; + + const handleFileDataError = (dataAvailabilityCheck, fileData) => + fileData?.error ? updateDataAvailabilityCheck(dataAvailabilityCheck, true, "partial") : dataAvailabilityCheck; + + const addResourcesToFilteredData = (data, resources, hypothesisAssumptionsList, formulaConfiguration, microplanData, t) => + Digit.Utils.microplan.addResourcesToFilteredDataToShow( + data, + resources, + hypothesisAssumptionsList, + formulaConfiguration, + microplanData?.microplanPreview?.userEditedResources || [], + t + ); + + const processFileData = ( + fileData, + schema, + filterDataOrigin, + virtualizationPropertiesCollector, + filterPropertiesCollector, + filterPropertieNameCollector, + resources, + hypothesisAssumptionsList, + formulaConfiguration, + t + ) => { + const properties = Object.entries(schema?.schema?.Properties || {}); + const latLngColumns = []; + const filterProperty = []; + + for (const [key, value] of properties) { + if (value?.isLocationDataColumns) latLngColumns.push(t(key)); + if (filterDataOrigin?.layerDataOrigin?.includes(fileData?.section) && value?.isFilterPropertyOfMapSection) filterProperty.push(key); + if (value?.isVisualizationPropertyOfMapSection && filterDataOrigin?.boundriesDataOrigin?.includes(fileData?.section)) + virtualizationPropertiesCollector.add(key); + } + + filterProperty.forEach((property) => filterPropertieNameCollector.add(property)); + + return { latLngColumns, filterProperty }; + }; + + const processExcelFile = (fileData, latLngColumns, resources, formulaConfiguration, hypothesisAssumptionsList, schema, t) => { + let dataAvailabilityCheck = "true"; + const columnList = Object.values(fileData?.data)?.[0]?.[0]; + const check = latLngColumns.every((colName) => columnList.includes(t(colName))); + + if (!check) dataAvailabilityCheck = "partial"; + + let dataWithResources = Object.values(fileData?.data); + if (resources && formulaConfiguration && hypothesisAssumptionsList && schema?.showResourcesInMappingSection) { + dataWithResources = dataWithResources.map((item) => + addResourcesToFilteredData(item, resources, hypothesisAssumptionsList, formulaConfiguration, microplanData, t) + ); + } + + const hasLocationData = dataWithResources.some((item) => item.some((row) => row.includes("lat") && row.includes("long"))); + + const convertedData = dataWithResources.map((item) => + item.map((row, rowIndex) => { + if (rowIndex === 0) { + if (row.indexOf("features") === -1) row.push("feature"); + return row; + } + const latIndex = item[0].findIndex((cell) => cell === "lat"); + const lonIndex = item[0].findIndex((cell) => cell === "long"); + const properties = item[0].reduce((acc, cell, index) => ({ ...acc, [cell]: row[index] }), {}); + const feature = + latIndex !== -1 && lonIndex !== -1 + ? { + type: "Feature", + properties, + geometry: { + type: "Point", + coordinates: [row[lonIndex], row[latIndex]], + }, + } + : null; + row.push(feature); + return row; + }) + ); + + return { dataAvailabilityCheck, hasLocationData, convertedData }; + }; + + const processGeoJsonFile = (fileData, filterProperty, resources, formulaConfiguration, hypothesisAssumptionsList, t) => { + const dataAvailabilityCheck = "true"; + const keys = [...Object.keys(fileData?.data.features[0].properties), "feature"]; + const values = fileData?.data.features.map((feature) => keys.map((key) => (key === "feature" ? feature : feature.properties[key] || null))); + + const dataWithResources = [[...keys, ...resources], ...values]; + const processedDataWithResources = dataWithResources.map((item, index) => { + if (index === 0) return item; + const newProperties = keys.reduce((acc, key, i) => (key !== "feature" ? { ...acc, [key]: item[i] } : acc), {}); + item[item.length - 1] = { ...item[item.length - 1], properties: newProperties }; + return item; + }); + + return { dataAvailabilityCheck, dataWithResources: processedDataWithResources }; + }; + + const updateFilterPropertiesCollector = (fileData, filterProperty, filterPropertiesCollector) => { + filterProperty.forEach((item) => { + Object.values(fileData?.data).forEach((data) => { + const filterPropertyIndex = data[0].indexOf(item); + if (filterPropertyIndex !== -1) data.slice(1).forEach((e) => filterPropertiesCollector.add(e[filterPropertyIndex])); + }); + }); + }; + + const setAvailabilityAndToastMessages = (dataAvailabilityCheck, combineList, files, setToast, t) => { + if (dataAvailabilityCheck === "true") { + const sectionWiseCheck = combineList.every((item) => Object.keys(files).includes(item)); + if (!sectionWiseCheck) dataAvailabilityCheck = "partial"; + } + + if (dataAvailabilityCheck === "initialStage" && (combineList.length === 0 || Object.keys(files).length === 0)) dataAvailabilityCheck = "false"; + + const toastMessages = { + false: { state: "warning", message: t("MAPPING_NO_DATA_TO_SHOW") }, + partial: { state: "warning", message: t("MAPPING_PARTIAL_DATA_TO_SHOW") }, + undefined: { state: "error", message: t("MAPPING_NO_DATA_TO_SHOW") }, + }; + + setToast(toastMessages[dataAvailabilityCheck]); + return dataAvailabilityCheck; + }; + + const setFinalDataAndProperties = ( + dataAvailabilityCheck, + setBoundary, + setFilter, + setBoundaryData, + setFilterData, + setFilterProperties, + setFilterSelections, + setFilterPropertyNames, + filterPropertiesCollector, + filterPropertieNameCollector, + virtualizationPropertiesCollector, + setChoroplethProperties, + resources + ) => { + setDataCompleteness(dataAvailabilityCheck); + setBoundary = calculateAggregateForTreeMicroplanWrapper(setBoundary); + setFilter = calculateAggregateForTreeMicroplanWrapper(setFilter); + setBoundaryData((previous) => ({ ...previous, ...setBoundary })); + setFilterData((previous) => ({ ...previous, ...setFilter })); + setFilterProperties([...filterPropertiesCollector]); + setFilterSelections([...filterPropertiesCollector]); + setFilterPropertyNames([...filterPropertieNameCollector]); + const tempVirtualizationPropertiesCollectorArray = [...virtualizationPropertiesCollector]; + if (tempVirtualizationPropertiesCollectorArray.length !== 0) + setChoroplethProperties([...tempVirtualizationPropertiesCollectorArray, ...(resources || [])]); + }; + + let setBoundary = {}; + let setFilter = {}; + const virtualizationPropertiesCollector = new Set(); + const filterPropertiesCollector = new Set(); + const filterPropertieNameCollector = new Set(); + const resources = state?.Resources?.find((item) => item.campaignType === campaignType)?.data; + const hypothesisAssumptionsList = microplanData?.hypothesis; + const formulaConfiguration = microplanData?.ruleEngine; + + let dataAvailabilityCheck = initializeDataAvailability(microplanData); + if (!dataAvailabilityCheck) return setToast({ state: "error", message: t("MAPPING_NO_DATA_TO_SHOW") }); + + const files = _.cloneDeep(microplanData.upload); + for (const fileData of files) { + if (!checkFileActivity(fileData) || !checkFileSection(fileData, filterDataOrigin)) { + dataAvailabilityCheck = "false"; + continue; + } + + if (!fileData?.fileType || !fileData?.section) continue; + + const schema = getFileValidationSchema(campaignType, fileData, validationSchemas); + dataAvailabilityCheck = handleFileDataError(dataAvailabilityCheck, fileData); + + const { latLngColumns, filterProperty } = processFileData( + fileData, + schema, + filterDataOrigin, + virtualizationPropertiesCollector, + filterPropertiesCollector, + filterPropertieNameCollector, + resources, + hypothesisAssumptionsList, + formulaConfiguration, + t + ); + + if (fileData?.data && Object.keys(fileData?.data).length > 0) { + switch (fileData?.fileType) { + case EXCEL: + const { dataAvailabilityCheck: excelDataAvailabilityCheck, hasLocationData, convertedData } = processExcelFile( + fileData, + latLngColumns, + resources, + formulaConfiguration, + hypothesisAssumptionsList, + schema, + t + ); + dataAvailabilityCheck = excelDataAvailabilityCheck; + if (hasLocationData) updateFilterPropertiesCollector(fileData, filterProperty, filterPropertiesCollector); + const { hierarchyLists: excelHierarchyLists, hierarchicalData: excelHierarchicalData } = processHierarchyAndData(hierarchy, convertedData); + if (filterDataOrigin?.boundriesDataOrigin?.includes(fileData.section)) + setBoundary = { ...setBoundary, [fileData.section]: { hierarchyLists: excelHierarchyLists, hierarchicalData: excelHierarchicalData } }; + else if (filterDataOrigin?.layerDataOrigin?.includes(fileData.section)) + setFilter = { ...setFilter, [fileData.section]: { hierarchyLists: excelHierarchyLists, hierarchicalData: excelHierarchicalData } }; + break; + case GEOJSON: + case SHAPEFILE: + const { dataAvailabilityCheck: geoJsonDataAvailabilityCheck, dataWithResources } = processGeoJsonFile( + fileData, + filterProperty, + resources, + formulaConfiguration, + hypothesisAssumptionsList, + t + ); + dataAvailabilityCheck = geoJsonDataAvailabilityCheck; + const { hierarchyLists: geoJsonHierarchyLists, hierarchicalData: geoJsonHierarchicalData } = processHierarchyAndData(hierarchy, [ + dataWithResources, + ]); + if (filterDataOrigin?.boundriesDataOrigin?.includes(fileData.section)) + setBoundary = { + ...setBoundary, + [fileData.section]: { hierarchyLists: geoJsonHierarchyLists, hierarchicalData: geoJsonHierarchicalData }, + }; + else if (filterDataOrigin?.layerDataOrigin?.includes(fileData.section)) + setFilter = { ...setFilter, [fileData.section]: { hierarchyLists: geoJsonHierarchyLists, hierarchicalData: geoJsonHierarchicalData } }; + break; + default: + break; + } + } + } + + const combineList = [...(filterDataOrigin?.boundriesDataOrigin || []), ...(filterDataOrigin?.layerDataOrigin || [])]; + dataAvailabilityCheck = setAvailabilityAndToastMessages(dataAvailabilityCheck, combineList, files, setToast, t); + + setFinalDataAndProperties( + dataAvailabilityCheck, + setBoundary, + setFilter, + setBoundaryData, + setFilterData, + setFilterProperties, + setFilterSelections, + setFilterPropertyNames, + filterPropertiesCollector, + filterPropertieNameCollector, + virtualizationPropertiesCollector, + setChoroplethProperties, + resources + ); +}; + +//prepare geojson to show on the map +export const prepareGeojson = (boundaryData, selection, style = {}) => { + if (!boundaryData || Object.keys(boundaryData).length === 0) return []; + let geojsonRawFeatures = []; + if (selection === "ALL") { + for (let data of Object.values(boundaryData)) { + const templist = fetchFeatures(data?.hierarchicalData, selection, [], style); + if (templist?.length !== 0) geojsonRawFeatures = [...geojsonRawFeatures, ...templist]; + } + } else if (Array.isArray(selection)) { + for (let data of Object.values(boundaryData)) { + const templist = fetchFeatures(data?.hierarchicalData, selection, [], style); + if (templist?.length !== 0) geojsonRawFeatures = [...geojsonRawFeatures, ...templist]; + } + } + + return geojsonRawFeatures.filter(Boolean); +}; +export const fetchFeatures = (data, parameter = "ALL", outputList = [], addOn = {}) => { + let tempStorage = []; + if (parameter === "ALL") { + // outputList(Object.values(data).flatMap(item=>item?.data?.feature)) + for (let [entityKey, entityValue] of Object.entries(data)) { + if (entityValue?.data?.feature) { + let feature = entityValue.data.feature; + feature.properties["name"] = entityKey; + feature.properties["addOn"] = addOn; + if (entityValue?.children) tempStorage = [...tempStorage, feature, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; + else tempStorage = [...tempStorage, feature]; + } else { + tempStorage = [...tempStorage, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; + } + } + return tempStorage; + } + if (Array.isArray(parameter)) { + for (let [entityKey, entityValue] of Object.entries(data)) { + if (parameter.includes(entityKey) && entityValue && entityValue.data && entityValue.data.feature) { + let feature = entityValue.data.feature; + feature.properties["name"] = entityKey; + feature.properties["addOn"] = addOn; + if (entityValue?.children) tempStorage = [...tempStorage, feature, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; + else tempStorage = [...tempStorage, feature]; + } + if (entityValue?.children) tempStorage = [...tempStorage, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; + } + return tempStorage; + } +}; + +export const addChoroplethProperties = (geojson, choroplethProperty, filteredSelection) => { + // Calculate min and max values of the property + const values = geojson.map((feature) => feature.properties[choroplethProperty]).filter((item) => !!item || item === 0) || []; + if (!values || values.length === 0) return []; + const convertedValues = values.map((item) => (!isNaN(item) ? item : 0)); + const minValue = Math.min(...convertedValues); + const maxValue = Math.max(...convertedValues); + + // Create a new geojson object + const newGeojson = geojson.map((feature) => { + const newFeature = { ...feature, properties: { ...feature.properties, addOn: { ...feature.properties.addOn } } }; + let color; + + if (choroplethProperty) { + color = interpolateColor(newFeature.properties[choroplethProperty], minValue, maxValue, MapChoroplethGradientColors); + } + + newFeature.properties.addOn.fillColor = color; + newFeature.properties.addOn.color = "rgba(0, 0, 0, 1)"; + if (!filteredSelection || filteredSelection.length === 0 || filteredSelection.includes(newFeature.properties.name)) { + newFeature.properties.addOn.fillOpacity = 1; + } else { + newFeature.properties.addOn.fillOpacity = 0.4; + newFeature.properties.addOn.opacity = 0.7; + } + + return newFeature; + }); + return newGeojson; +}; + +/** + * filterGeojsons : json + * filterSelection : array + * MapFilters : + */ +export const addFilterProperties = (filterGeojsons, filterSelections, filterPropertyNames, iconMapping) => { + try { + if (!filterGeojsons || !iconMapping || !filterSelections) return []; + let newFilterGeojson = []; + filterGeojsons.forEach((item) => { + if (filterPropertyNames && filterPropertyNames.length !== 0 && item.properties) { + let icon; + filterPropertyNames.forEach((name) => { + if (item.properties[name]) { + let temp = item.properties[name]; + if (!filterSelections.includes(temp)) return; + temp = iconMapping?.find((e) => e?.name == temp)?.icon?.marker; + let DynamicIcon = IconCollection?.[temp]; + if (typeof DynamicIcon === "function") { + icon = L.divIcon({ + className: "custom-svg-icon", + html: DynamicIcon({}), + iconAnchor: [25, 50], + }); + newFilterGeojson.push({ ...item, properties: { ...item?.properties, addOn: { ...item?.properties?.addOn, icon: icon } } }); + } else { + icon = DefaultMapMarker({}); + newFilterGeojson.push({ ...item, properties: { ...item?.properties, addOn: { ...item?.properties?.addOn, icon: icon } } }); + } + } + }); + } + return item; + }); + return newFilterGeojson; + } catch (error) { + console.error(error.message); + } +}; + +/** + * map: map + * geojson: geojson + * t: translator + */ + +export const addGeojsonToMap = (map, geojson, t) => { + try { + if (!map || !geojson) return false; + const geojsonLayer = L.geoJSON(geojson, { + style: (feature) => { + if (Object.keys(feature.properties.addOn).length !== 0) { + return feature.properties.addOn; + } + return { + weight: 2, + opacity: 1, + color: "rgba(176, 176, 176, 1)", + fillColor: "rgb(0,0,0,0)", + // fillColor: choroplethProperty ? color : "rgb(0,0,0,0)", + fillOpacity: 0, + // fillOpacity: choroplethProperty ? (feature?.properties?.style?.fillOpacity ? feature.properties.style.fillOpacity : 0.7) : 0, + }; + }, + pointToLayer: (feature, latlng) => { + if (feature.properties.addOn.icon) { + let icon = feature.properties.addOn.icon; + if (icon) { + return L.marker(latlng, { + icon: icon, + }); + } + } + return L.marker(latlng, { + icon: MapMarker(feature.properties.addOn), + }); + }, + onEachFeature: (feature, layer) => { + let popupContent; + popupContent = "
"; + popupContent += ""; + popupContent += `
${feature.properties["name"]}
`; + for (let prop in feature.properties) { + if (prop !== "name" && prop !== "addOn" && prop !== "feature") { + let data = feature.properties[prop] ? feature.properties[prop] : t("NO_DATA"); + popupContent += + ""; + } + } + popupContent += "
" + + t(prop) + + "" + + data + + "
"; + layer.bindPopup(popupContent, { + minWidth: "28rem", + padding: "0", + }); + // Adjust map here when pop up closes + layer.on("popupclose", () => { + map.fitBounds(geojsonLayer.getBounds()); + }); + layer.on({ + mouseover: (e) => { + const layer = e.target; + if (layer.feature.properties.addOn && !layer.feature.properties.addOn.child) { + return; + } + if (layer.setStyle) + layer.setStyle({ + weight: 2.7, + opacity: 1, + color: "rgba(255, 255, 255, 1)", + }); + // layer.openPopup(); + }, + mouseout: (e) => { + const layer = e.target; + if (layer.feature.properties.addOn && !layer.feature.properties.addOn.child) { + return; + } + if (layer.setStyle) { + if (layer.feature.properties.addOn && Object.keys(layer.feature.properties.addOn).length !== 0) + layer.setStyle({ + ...layer.feature.properties.addOn, + }); + else + layer.setStyle({ + weight: 2, + color: "rgba(176, 176, 176, 1)", + }); + } + // layer.closePopup(); + }, + }); + }, + }); + geojsonLayer.addTo(map); + return geojsonLayer; + } catch (error) { + console.error(error.message); + } +}; + +export const interpolateColor = (value, minValue, maxValue, colors) => { + // Handle case where min and max values are the same + if (minValue === maxValue) { + // Return a default color or handle the case as needed + return colors[0].color; + } + + // Normalize the value to a percentage between 0 and 100 + const percent = !isNaN(value) ? ((value - minValue) / (maxValue - minValue)) * 100 : 0; + // Find the two colors to interpolate between + let lowerColor, upperColor; + for (let i = 0; i < colors.length - 1; i++) { + if (!isNaN(percent) && percent >= colors[i].percent && percent <= colors[i + 1].percent) { + lowerColor = colors[i]; + upperColor = colors[i + 1]; + break; + } + } + // Interpolate between the two colors + const t = (percent - lowerColor.percent) / (upperColor.percent - lowerColor.percent); + return chroma.mix(lowerColor.color, upperColor.color, t, "lab").hex(); +}; + +// Find bounds for multiple geojson together +export const findBounds = (data, buffer = 0.1) => { + if (!Array.isArray(data) || data.length === 0) { + return null; + } + + // Initialize variables to store bounds + var minLat = Number.MAX_VALUE; + var maxLat = -Number.MAX_VALUE; + var minLng = Number.MAX_VALUE; + var maxLng = -Number.MAX_VALUE; + + // Iterate through the data to find bounds + data.forEach(function (feature) { + if (!feature || !feature.geometry || !feature.geometry.type || !feature.geometry.coordinates) { + return null; + } + + var coords = feature.geometry.coordinates; + var geometryType = feature.geometry.type; + + switch (geometryType) { + case "Point": + var coord = coords; + var lat = coord[1]; + var lng = coord[0]; + minLat = Math.min(minLat, lat); + maxLat = Math.max(maxLat, lat); + minLng = Math.min(minLng, lng); + maxLng = Math.max(maxLng, lng); + break; + case "MultiPoint": + coords.forEach(function (coord) { + var lat = coord[1]; + var lng = coord[0]; + minLat = Math.min(minLat, lat); + maxLat = Math.max(maxLat, lat); + minLng = Math.min(minLng, lng); + maxLng = Math.max(maxLng, lng); + }); + break; + case "LineString": + case "MultiLineString": + case "Polygon": + case "MultiPolygon": + coords.forEach(function (polygons) { + if ((geometryType === "Polygon" || geometryType === "MultiPolygon") && Array.isArray(polygons[0][0])) { + polygons.forEach(function (coordinates) { + coordinates.forEach(function (coord) { + if (!Array.isArray(coord) || coord.length !== 2 || typeof coord[0] !== "number" || typeof coord[1] !== "number") { + return null; + } + + var lat = coord[1]; + var lng = coord[0]; + minLat = Math.min(minLat, lat); + maxLat = Math.max(maxLat, lat); + minLng = Math.min(minLng, lng); + maxLng = Math.max(maxLng, lng); + }); + }); + } else { + polygons.forEach(function (coord) { + if (!Array.isArray(coord) || coord.length !== 2 || typeof coord[0] !== "number" || typeof coord[1] !== "number") { + return null; + } + + var lat = coord[1]; + var lng = coord[0]; + minLat = Math.min(minLat, lat); + maxLat = Math.max(maxLat, lat); + minLng = Math.min(minLng, lng); + maxLng = Math.max(maxLng, lng); + }); + } + }); + break; + default: + return null; + } + }); + + // Check if valid bounds found + if (minLat === Number.MAX_VALUE || maxLat === -Number.MAX_VALUE || minLng === Number.MAX_VALUE || maxLng === -Number.MAX_VALUE) { + return null; + } + // Apply buffer to bounds + minLat -= buffer; + maxLat += buffer; + minLng -= buffer; + maxLng += buffer; + + // Set bounds for the Leaflet map + var bounds = [ + [minLat, minLng], + [maxLat, maxLng], + ]; + + return bounds; +}; + +export const filterBoundarySelection = (boundaryData, boundarySelections) => { + if (Object.keys(boundaryData).length === 0 || Object.keys(boundarySelections).length === 0) return []; + let selectionList = []; + Object.values(boundarySelections).forEach((item) => (selectionList = [...selectionList, ...item.map((e) => e.name)])); + let childrenList = []; + const set1 = new Set(selectionList); + selectionList = selectionList.filter((item) => { + const children = findChildren([item], Object.values(boundaryData)?.[0]?.hierarchicalData); + if (children) { + let childrenKeyList = getAllKeys(children); + childrenList = [...childrenList, ...childrenKeyList]; + const nonePresent = childrenKeyList.every((item) => !set1.has(item)); + const allPresent = childrenKeyList.every((item) => set1.has(item)); + return nonePresent ? true : allPresent ? true : false; + } + return true; + }); + return { filteredSelection: selectionList, childrenList }; +}; + +// Recursive function to extract all keys +export const getAllKeys = (obj, keys = []) => { + for (let [key, value] of Object.entries(obj)) { + keys.push(key); + if (value.children) { + getAllKeys(value.children, keys); + } + } + return keys; +}; + +// Remove all layers from the map +export const removeAllLayers = (map, layer) => { + if (!map) return; + layer.forEach((layer) => { + map.removeLayer(layer); + }); +}; +// Map-Marker +export const MapMarker = (style = {}) => { + return L.divIcon({ + className: "custom-svg-icon", + html: PopulationSvg(style), + iconAnchor: [25, 50], + }); +}; +export const DefaultMapMarker = (style = {}) => { + return L.divIcon({ + className: "custom-svg-icon", + html: IconCollection.DefaultMapMarkerSvg(style), + iconAnchor: [25, 50], + }); +}; + +export const disableMapInteractions = (map) => { + if (!map) return; + map.dragging.disable(); + map.scrollWheelZoom.disable(); + map.touchZoom.disable(); + map.doubleClickZoom.disable(); + map.boxZoom.disable(); + map.keyboard.disable(); +}; + +export const enableMapInteractions = (map) => { + if (!map) return; + map.dragging.enable(); + map.scrollWheelZoom.enable(); + map.touchZoom.enable(); + map.doubleClickZoom.enable(); + map.boxZoom.enable(); + map.keyboard.enable(); +}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js new file mode 100644 index 00000000000..ff5cd55208f --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js @@ -0,0 +1,413 @@ +import { EXCEL, GEOJSON, SHAPEFILE, commonColumn } from "../configs/constants"; + +export const calculateAggregateValue = (aggregateName, dataToShow) => { + if (!aggregateName || !dataToShow || dataToShow.length === 0) return; + let aggregateNameList = aggregateName; + if (typeof aggregateName !== "object") aggregateNameList = { name: aggregateName, entities: [aggregateName] }; + let aggregateData = 0; + if (aggregateNameList) + for (const item of aggregateNameList.entities) { + const columnIndex = dataToShow?.[0].indexOf(item); + dataToShow.slice(1).forEach((e) => { + if (e?.[columnIndex]) aggregateData = aggregateData + Number(e[columnIndex]); + }); + } + return aggregateData; +}; + +export const fetchMicroplanData = (microplanData, campaignType, validationSchemas) => { + if (!microplanData) return []; + + let combinesDataList = []; + // Check if microplanData and its upload property exist + if (microplanData?.upload) { + let files = microplanData?.upload; + // Loop through each file in the microplan upload + for (let fileData of files) { + const schema = getSchema(campaignType, fileData.fileType, fileData.templateIdentifier, validationSchemas); + + // Check if the file is not part of boundary or layer data origins + if (!fileData.active || !fileData.fileType || !fileData?.section) continue; // Skip files with errors or missing properties + + // Check if file contains latitude and longitude columns + if (fileData?.data) { + // Check file type and update data availability accordingly + switch (fileData?.fileType) { + case EXCEL: { + // extract dada + const mergedData = schema?.template?.hierarchyLevelWiseSheets ? Object.values(fileData?.data).flat() : Object.values(fileData?.data)?.[0]; + + let commonColumnIndex = mergedData?.[0]?.indexOf(commonColumn); + + let uniqueEntries; + if (commonColumnIndex !== undefined) + uniqueEntries = schema?.template?.hierarchyLevelWiseSheets + ? Array.from(new Map(mergedData.map((entry) => [entry[commonColumnIndex], entry])).values()) + : mergedData; + if (uniqueEntries) combinesDataList.push(uniqueEntries); + break; + } + case GEOJSON: + case SHAPEFILE: { + // Extract keys from the first feature's properties + let keys = Object.keys(fileData?.data.features[0].properties); + + // Extract corresponding values for each feature + const values = fileData?.data?.features.map((feature) => { + // list with features added to it + const temp = keys.map((key) => { + // if (feature.properties[key] === "") { + // return null; + // } + return feature.properties[key]; + }); + return temp; + }); + + let data = [keys, ...values]; + combinesDataList.push(data); + } + } + } + } + } + return combinesDataList; +}; + +// get schema for validation +export const getSchema = (campaignType, type, section, schemas) => { + return schemas.find((schema) => + schema.campaignType + ? schema.campaignType === campaignType && schema.type === type && schema.section === section + : schema.type === type && schema.section === section + ); +}; + +export const fetchMicroplanPreviewData = (campaignType, microplanData, validationSchemas, hierarchy) => { + try { + const filteredSchemaColumns = getFilteredSchemaColumnsList(campaignType, microplanData, validationSchemas, hierarchy); + const fetchedData = fetchMicroplanData(microplanData, campaignType, validationSchemas); + const dataAfterJoins = performDataJoins(fetchedData, filteredSchemaColumns); + return dataAfterJoins; + } catch (error) { + console.error("Error in fetch microplan data: ", error.message); + } +}; + +const getFilteredSchemaColumnsList = (campaignType, microplanData, validationSchemas, hierarchy) => { + let filteredSchemaColumns = getRequiredColumnsFromSchema(campaignType, microplanData, validationSchemas) || []; + if (hierarchy) { + filteredSchemaColumns = [...hierarchy, commonColumn, ...filteredSchemaColumns.filter((e) => e !== commonColumn)]; + } + return filteredSchemaColumns; +}; + +const performDataJoins = (fetchedData, filteredSchemaColumns) => { + return fetchedData.reduce((accumulator, currentData, index) => { + if (index === 0) { + return innerJoinLists(currentData, null, commonColumn, filteredSchemaColumns); + } + return innerJoinLists(accumulator, currentData, commonColumn, filteredSchemaColumns); + }, null); +}; + +export const filterObjects = (arr1, arr2) => { + if (!arr1 || !arr2) return []; + // Create a new array to store the filtered objects + let filteredArray = []; + + // Iterate through the first array + arr1.forEach((obj1) => { + // Find the corresponding object in the second array + let obj2 = _.cloneDeep(arr2.find((item) => item.key === obj1.key)); + + // If the object with the same key is found in the second array and their values are the same + if (obj2 && obj1.value !== obj2.value) { + // Push the object to the filtered array + obj1.oldValue = obj2.value; + filteredArray.push(obj1); + } + }); + + return filteredArray; +}; + +export const useHypothesis = (tempHypothesisList, hypothesisAssumptionsList) => { + // Handles the change in hypothesis value + const valueChangeHandler = (e, setTempHypothesisList, boundarySelections, setToast, t) => { + // Checks it the boundary filters at at root level ( given constraints ) + if (Object.keys(boundarySelections).length !== 0 && Object.values(boundarySelections)?.every((item) => item?.length !== 0)) + return setToast({ state: "error", message: t("HYPOTHESIS_CAN_BE_ONLY_APPLIED_ON_ADMIN_LEVEL_ZORO") }); + + // validating user input + if (e?.newValue.includes("+") || e?.newValue.includes("e")) return; + if ((e?.newValue < 0 || e.newValue > 10000000000) && e?.newValue !== "") return; + let value; + const decimalIndex = e.newValue.indexOf("."); + if (decimalIndex !== -1) { + const numDecimals = e.newValue.length - decimalIndex - 1; + if (numDecimals <= 2) { + value = e.newValue; + } else if (numDecimals > 2) { + value = e.newValue.substring(0, decimalIndex + 3); + } + } else value = parseFloat(e.newValue); + value = !isNaN(value) ? value : ""; + + // update the state with user input + let newhypothesisEntityIndex = hypothesisAssumptionsList.findIndex((item) => item?.id === e?.item?.id); + let unprocessedHypothesisList = _.cloneDeep(tempHypothesisList); + if (newhypothesisEntityIndex !== -1) unprocessedHypothesisList[newhypothesisEntityIndex].value = value; + setTempHypothesisList(unprocessedHypothesisList); + }; + + return { + valueChangeHandler, + }; +}; + +const validateRequestBody = (body, state, campaignType, setLoaderActivation, setToast, setCheckDataCompletion, navigationEvent, t) => { + if (!Digit.Utils.microplan.planConfigRequestBodyValidator(body, state, campaignType)) { + setLoaderActivation(false); + if (navigationEvent.name === "next") { + setToast({ + message: t("ERROR_DATA_NOT_SAVED"), + state: "error", + }); + setCheckDataCompletion("false"); + } else { + setCheckDataCompletion("perform-action"); + } + return false; + } + return true; +}; + +const handleApiSuccess = (data, updateData, setLoaderActivation, setMicroplanData, status) => { + updateData(); + setLoaderActivation(false); + setMicroplanData((previous) => ({ ...previous, microplanStatus: status })); +}; + +const handleApiError = (error, variables, setLoaderActivation, setToast, status, cancleNavigation, updateData, t) => { + setLoaderActivation(false); + setToast({ + message: t("ERROR_DATA_NOT_SAVED"), + state: "error", + }); + if (status === "GENERATED") { + cancleNavigation(); + } else { + updateData(); + } +}; + +const constructRequestBody = (microplanData, operatorsObject, MicroplanName, campaignId, status) => { + const body = Digit.Utils.microplan.mapDataForApi(microplanData, operatorsObject, MicroplanName, campaignId, status); + body.PlanConfiguration["id"] = microplanData?.planConfigurationId; + body.PlanConfiguration["auditDetails"] = microplanData?.auditDetails; + return body; +}; + +export const updateHyothesisAPICall = async ( + microplanData, + setMicroplanData, + operatorsObject, + MicroplanName, + campaignId, + UpdateMutate, + setToast, + updateData, + setLoaderActivation, + status, + cancleNavigation, + state, + campaignType, + navigationEvent, + setCheckDataCompletion, + t +) => { + try { + const body = constructRequestBody(microplanData, operatorsObject, MicroplanName, campaignId, status); + const isValid = validateRequestBody(body, state, campaignType, setLoaderActivation, setToast, setCheckDataCompletion, navigationEvent, t); + if (!isValid) return; + + await UpdateMutate(body, { + onSuccess: (data) => handleApiSuccess(data, updateData, setLoaderActivation, setMicroplanData, status), + onError: (error, variables) => handleApiError(error, variables, setLoaderActivation, setToast, status, cancleNavigation, updateData, t), + }); + } catch (error) { + setLoaderActivation(false); + setToast({ + message: t("ERROR_DATA_NOT_SAVED"), + state: "error", + }); + } +}; + +// get schema for validation +export const getRequiredColumnsFromSchema = (campaignType, microplanData, schemas) => { + if (!schemas || !microplanData || !microplanData?.upload || !campaignType) return []; + const sortData = []; + if (microplanData?.upload) { + for (const value of microplanData.upload) { + if (value.active && value?.error === null) { + sortData.push({ section: value.section, fileType: value?.fileType }); + } + } + } + const filteredSchemas = + schemas?.filter((schema) => { + if (schema.campaignType) { + return schema.campaignType === campaignType && sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); + } + return sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); + }) || []; + + let finalData = []; + let tempdata; + + tempdata = filteredSchemas + ?.flatMap((item) => + Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.isRuleConfigureInputs && value?.toShowInMicroplanPreview) { + acc.push(key); + } + return acc; + }, []) + ) + .filter((item) => !!item); + finalData = [...finalData, ...tempdata]; + + tempdata = filteredSchemas + ?.flatMap((item) => + Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.toShowInMicroplanPreview) acc.push(key); + return acc; + }, []) + ) + .filter((item) => !!item); + finalData = [...finalData, ...tempdata]; + return [...new Set(finalData)]; +}; + +/** + * Combines two datasets based on a common column, duplicating rows from data1 for each matching row in data2. + * The final dataset's columns and their order are determined by listOfColumnsNeededInFinalData. + * If data2 is not provided, rows from data1 are included with null values for missing columns. + */ +export const innerJoinLists = (data1, data2, commonColumnName, listOfColumnsNeededInFinalData) => { + // Error handling: Check if data1 array is provided + if (!Array.isArray(data1)) { + throw new Error("The first data input must be an array."); + } + + // Error handling: Check if common column name is provided + if (typeof commonColumnName !== "string") { + throw new Error("Common column name must be a string."); + } + + // Error handling: Check if listOfColumnsNeededInFinalData is provided and is an array + if (!Array.isArray(listOfColumnsNeededInFinalData)) { + throw new Error("listOfColumnsNeededInFinalData must be an array."); + } + + // Find the index of the common column in the first dataset + const commonColumnIndex1 = data1[0].indexOf(commonColumnName); + + // Error handling: Check if common column exists in the first dataset + if (commonColumnIndex1 === -1) { + throw new Error(`Common column "${commonColumnName}" not found in the first dataset.`); + } + + let commonColumnIndex2 = -1; + const data2Map = new Map(); + if (data2) { + // Find the index of the common column in the second dataset + commonColumnIndex2 = data2[0].indexOf(commonColumnName); + + // Error handling: Check if common column exists in the second dataset + if (commonColumnIndex2 === -1) { + throw new Error(`Common column "${commonColumnName}" not found in the second dataset.`); + } + + // Create a map for the second dataset for quick lookup by the common column value + for (let i = 1; i < data2.length; i++) { + const row = data2[i]; + const commonValue = row[commonColumnIndex2]; + if (!data2Map.has(commonValue)) { + data2Map.set(commonValue, []); + } + data2Map.get(commonValue).push(row); + } + } + + // Determine the headers for the final combined dataset based on listOfColumnsNeededInFinalData + const combinedHeaders = listOfColumnsNeededInFinalData.filter((header) => data1[0].includes(header) || data2?.[0].includes(header)); + + // Combine rows + const combinedData = [combinedHeaders]; + const addedCommonValues = new Set(); + for (let i = 1; i < data1.length; i++) { + const row1 = data1[i]; + const commonValue = row1[commonColumnIndex1]; + const rows2 = data2 ? data2Map.get(commonValue) || [[null]] : [[null]]; // Handle missing common values with a placeholder array of null + + // Check if rows2 is the placeholder array + const isPlaceholderArray = rows2.length === 1 && rows2[0].every((value) => value === null); + + // Create combined rows for each row in data2 + if (isPlaceholderArray) { + // If no corresponding row found in data2, use row from data1 with null values for missing columns + const combinedRow = combinedHeaders.map((header) => { + const index1 = data1[0].indexOf(header); + return index1 !== -1 ? row1[index1] : null; + }); + combinedData.push(combinedRow); + } else { + // If corresponding rows found in data2, combine each row from data2 with row from data1 + rows2.forEach((row2) => { + const combinedRow = combinedHeaders.map((header) => { + const index1 = data1[0].indexOf(header); + const index2 = data2 ? data2[0].indexOf(header) : -1; + return index1 !== -1 ? row1[index1] : index2 !== -1 ? row2[index2] : null; + }); + combinedData.push(combinedRow); + }); + } + addedCommonValues.add(commonValue); + } + // Add rows from data2 that do not have a matching row in data1 + if (data2) { + for (let i = 1; i < data2.length; i++) { + const row2 = data2[i]; + const commonValue = row2[commonColumnIndex2]; + if (!addedCommonValues.has(commonValue)) { + const combinedRow = combinedHeaders.map((header) => { + // const index1 = data1[0].indexOf(header); + const index2 = data2[0].indexOf(header); + return index2 !== -1 ? row2[index2] : null; + }); + combinedData.push(combinedRow); + } + } + } + + return combinedData; +}; + +// function to filter the microplan data with respect to the hierarchy selected by the user +export const filterMicroplanDataToShowWithHierarchySelection = (data, selections, hierarchy, hierarchyIndex = 0) => { + if (!selections || selections?.length === 0) return data; + if (hierarchyIndex >= hierarchy?.length) return data; + const filteredHirarchyLevelList = selections?.[hierarchy?.[hierarchyIndex]]?.map((item) => item?.name); + if (!filteredHirarchyLevelList || filteredHirarchyLevelList?.length === 0) return data; + const columnDataIndexForHierarchyLevel = data?.[0]?.indexOf(hierarchy?.[hierarchyIndex]); + if (columnDataIndexForHierarchyLevel === -1) return data; + const levelFilteredData = data.filter((item, index) => { + if (index === 0) return true; + if (item?.[columnDataIndexForHierarchyLevel] && filteredHirarchyLevelList.includes(item?.[columnDataIndexForHierarchyLevel])) return true; + return false; + }); + return filterMicroplanDataToShowWithHierarchySelection(levelFilteredData, selections, hierarchy, hierarchyIndex + 1); +}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js similarity index 95% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js index f5508322f31..09e24a4658e 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js @@ -65,7 +65,7 @@ export const processHierarchyAndData = (hierarchy, allData) => { Object.values(hierarchicalData).forEach((country) => { if (country.children[null]) { country.data = country.children[null].data; - delete country.children[null]; + country.children[null] = undefined; } }); } catch (error) { @@ -139,13 +139,25 @@ export const findChildren = (parents, hierarchy) => { tempData = { ...accumulator, ...hierarchy.reduce((data, item) => { - if (parents.includes(item?.name) && item?.children) data = { ...data, ...item?.children }; + if (parents.includes(item?.name) && item?.children) { + for (const key in item.children) { + if (!data[key]) { + data[key] = item.children[key]; + } + } + } return data; }, {}), }; else tempData = hierarchy.reduce((data, item) => { - if (parents.includes(item?.name) && item?.children) data = { ...data, ...item?.children }; + if (parents.includes(item?.name) && item?.children) { + for (const key in item.children) { + if (!data[key]) { + data[key] = item.children[key]; + } + } + } return data; }, {}); for (let parent of hierarchy) { @@ -220,8 +232,8 @@ export const fetchDropdownValues = (boundaryData, hierarchy, boundarySelections, const findByBoundaryType = (boundaryType, hierarchy) => { for (let [key, value] of Object.entries(hierarchy)) { if (value?.boundaryType === boundaryType) return Object.keys(hierarchy).filter(Boolean); - else if (value?.children) return findByBoundaryType(boundaryType, value?.children); - else return []; + if (value?.children) return findByBoundaryType(boundaryType, value?.children); + return []; } return []; }; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js similarity index 97% rename from frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js rename to frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js index 003165d6ac0..129ec488b43 100644 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js @@ -5,8 +5,8 @@ import * as XLSX from "xlsx"; import axios from "axios"; import shp from "shpjs"; import { EXCEL, GEOJSON, SHAPEFILE, ACCEPT_HEADERS, LOCALITY, commonColumn } from "../configs/constants"; -import { handleExcelFile } from "../components/Upload"; import { addBoundaryData, fetchBoundaryData, filterBoundaries } from "./createTemplate"; +import { handleExcelFile } from "./uploadUtils"; function handleExcelArrayBuffer(arrayBuffer, file) { return new Promise((resolve, reject) => { @@ -306,7 +306,7 @@ export const updateSessionUtils = { const handleGeoJsonSpecific = async (schema, upload, templateIdentifier, result, translatedData, filestoreId, processedData) => { let schemaKeys; if (schema?.schema?.["Properties"]) { - schemaKeys = additionalProps.heirarchyData?.concat(Object.keys(schema.schema["Properties"])); + schemaKeys = additionalProps.hierarchyData?.concat(Object.keys(schema.schema["Properties"])); } upload.data = result; if (processedData) return; @@ -324,7 +324,7 @@ export const updateSessionUtils = { }); upload.data.features = newFeatures; if ( - additionalProps.heirarchyData?.every( + additionalProps.hierarchyData?.every( (item) => !mappedToList.includes(`${additionalProps.campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item)}`) ) @@ -333,11 +333,11 @@ export const updateSessionUtils = { upload.data.features.forEach((feature) => { const boundaryCode = feature.properties.boundaryCode; let additionalDetails = {}; - for (let i = 0; i < additionalProps.heirarchyData?.length; i++) { + for (let i = 0; i < additionalProps.hierarchyData?.length; i++) { if (boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] || boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] === "") { - additionalDetails[additionalProps.heirarchyData?.[i]] = boundaryDataAgainstBoundaryCode[boundaryCode][i]; + additionalDetails[additionalProps.hierarchyData?.[i]] = boundaryDataAgainstBoundaryCode[boundaryCode][i]; } else { - additionalDetails[additionalProps.heirarchyData?.[i]] = ""; + additionalDetails[additionalProps.hierarchyData?.[i]] = ""; } } feature.properties = { ...additionalDetails, ...feature.properties }; @@ -391,14 +391,15 @@ export const updateSessionUtils = { const response = await handleExcelFile( file, schemaData, - additionalProps.heirarchyData.map( + additionalProps.hierarchyData.map( (item) => `${additionalProps.campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item)}` ), { id: inputFileType }, boundaryDataAgainstBoundaryCode, () => {}, additionalProps.t, - additionalProps.campaignData + additionalProps.campaignData, + additionalProps.readMeSheetName ); let fileData = { filestoreId, diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js new file mode 100644 index 00000000000..066f47c47f3 --- /dev/null +++ b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js @@ -0,0 +1,880 @@ +import ExcelJS from "exceljs"; +import { + freezeSheetValues, + freezeWorkbookValues, + hideUniqueIdentifierColumn, + performUnfreezeCells, + unfreezeColumnsByHeader, + updateFontNameToRoboto, +} from "../utils/excelUtils"; +import { addBoundaryData, createTemplate, fetchBoundaryData, filterBoundaries } from "../utils/createTemplate"; +import { BOUNDARY_DATA_SHEET, EXCEL, FACILITY_DATA_SHEET, SCHEMA_PROPERTIES_PREFIX, SHEET_COLUMN_WIDTH, commonColumn } from "../configs/constants"; +import shp from "shpjs"; +import JSZip from "jszip"; +import { checkForErrorInUploadedFileExcel } from "../utils/excelValidations"; +import { convertJsonToXlsx } from "../utils/jsonToExcelBlob"; +import { parseXlsxToJsonMultipleSheets } from "../utils/exceltojson"; +import { geojsonValidations } from "../utils/geojsonValidations"; + +// Function for checking the uploaded file for nameing conventions +export const validateNamingConvention = (file, namingConvention, setToast, t) => { + try { + let processedConvention = namingConvention.replace("$", ".[^.]*$"); + const regx = new RegExp(processedConvention); + + if (regx && !regx.test(file.name)) { + setToast({ + state: "error", + message: t("ERROR_NAMING_CONVENSION"), + }); + return false; + } + return true; + } catch (error) { + console.error(error.message); + setToast({ + state: "error", + message: t("ERROR_UNKNOWN"), + }); + } +}; + +// Function for reading ancd checking geojson data +export const readGeojson = async (file, t) => { + return new Promise((resolve, reject) => { + if (!file) return resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } }); + + const reader = new FileReader(); + reader.onload = (e) => { + try { + const geoJSONData = JSON.parse(e.target.result); + const trimmedGeoJSONData = trimJSON(geoJSONData); + resolve({ valid: true, geojsonData: trimmedGeoJSONData }); + } catch (error) { + resolve({ valid: false, toast: { state: "error", message: t("ERROR_INCORRECT_FORMAT") } }); + } + }; + reader.onerror = (error) => { + resolve({ valid: false, toast: { state: "error", message: t("ERROR_CORRUPTED_FILE") } }); + }; + + reader.readAsText(file); + }); +}; + +// Function to recursively trim leading and trailing spaces from string values in a JSON object +export const trimJSON = (jsonObject) => { + if (typeof jsonObject !== "object") { + return jsonObject; // If not an object, return as is + } + + if (Array.isArray(jsonObject)) { + return jsonObject.map((item) => trimJSON(item)); // If it's an array, recursively trim each item + } + + const trimmedObject = {}; + for (const key in jsonObject) { + if (Object.hasOwn(jsonObject, key)) { + const value = jsonObject[key]; + // Trim string values, recursively trim objects + trimmedObject[key.trim()] = typeof value === "string" ? value.trim() : typeof value === "object" ? trimJSON(value) : value; + } + } + return trimmedObject; +}; +// Function for reading and validating shape file data +export const readAndValidateShapeFiles = async (file, t, namingConvention) => { + return new Promise((resolve, reject) => { + const readAndValidate = async () => { + if (!file) { + resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } }); + } + const fileRegex = new RegExp(namingConvention.replace("$", ".*$")); + // File Size Check + const fileSizeInBytes = file.size; + const maxSizeInBytes = 2 * 1024 * 1024 * 1024; // 2 GB + + // Check if file size is within limit + if (fileSizeInBytes > maxSizeInBytes) + resolve({ valid: false, message: t("ERROR_FILE_SIZE"), toast: { state: "error", message: t("ERROR_FILE_SIZE") } }); + + try { + const zip = await JSZip.loadAsync(file); + const isEPSG4326 = await checkProjection(zip); + if (!isEPSG4326) { + resolve({ valid: false, message: t("ERROR_WRONG_PRJ"), toast: { state: "error", message: t("ERROR_WRONG_PRJ") } }); + } + const files = Object.keys(zip.files); + const allFilesMatchRegex = files.every((fl) => { + return fileRegex.test(fl); + }); + let regx = new RegExp(namingConvention.replace("$", "\\.shp$")); + const shpFile = zip.file(regx)[0]; + regx = new RegExp(namingConvention.replace("$", "\\.shx$")); + const shxFile = zip.file(regx)[0]; + regx = new RegExp(namingConvention.replace("$", "\\.dbf$")); + const dbfFile = zip.file(regx)[0]; + + let geojson; + if (shpFile && dbfFile) { + const shpArrayBuffer = await shpFile.async("arraybuffer"); + const dbfArrayBuffer = await dbfFile.async("arraybuffer"); + + geojson = shp.combine([shp.parseShp(shpArrayBuffer), shp.parseDbf(dbfArrayBuffer)]); + } + if (shpFile && dbfFile && shxFile && allFilesMatchRegex) resolve({ valid: true, data: geojson }); + else if (!allFilesMatchRegex) + resolve({ + valid: false, + message: [t("ERROR_CONTENT_NAMING_CONVENSION")], + toast: { state: "error", data: geojson, message: t("ERROR_CONTENT_NAMING_CONVENSION") }, + }); + else if (!shpFile) + resolve({ valid: false, message: [t("ERROR_SHP_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_SHP_MISSING") } }); + else if (!dbfFile) + resolve({ valid: false, message: [t("ERROR_DBF_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_DBF_MISSING") } }); + else if (!shxFile) + resolve({ valid: false, message: [t("ERROR_SHX_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_SHX_MISSING") } }); + } catch (error) { + resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } }); + } + }; + readAndValidate(); + }); +}; + +// Function for projections check in case of shapefile data +export const checkProjection = async (zip) => { + const prjFile = zip.file(/.prj$/i)[0]; + if (!prjFile) { + return "absent"; + } + + const prjText = await prjFile.async("text"); + + if (prjText.includes("GEOGCS") && prjText.includes("WGS_1984") && prjText.includes("DATUM") && prjText.includes("D_WGS_1984")) { + return "EPSG:4326"; + } + return false; +}; + +// find readMe as per campaign, template identifier and file type +export const findReadMe = (readMeCollection, campaignType, type, section) => { + if (!readMeCollection) return readMeCollection; + return ( + readMeCollection.find( + (readMe) => readMe.fileType === type && readMe.templateIdentifier === section && (!readMe.campaignType || readMe.campaignType === campaignType) + )?.data || {} + ); +}; + +// Function to handle the template download +export const downloadTemplate = async ({ + campaignType, + type, + section, + setToast, + campaignData, + hierarchyType, + Schemas, + HierarchyConfigurations, + setLoader, + hierarchy, + readMeData, + readMeSheetName, + t, +}) => { + try { + setLoader("LOADING"); + await delay(100); + // Find the template based on the provided parameters + const schema = getSchema(campaignType, type, section, Schemas); + const hierarchyLevelName = HierarchyConfigurations?.find((item) => item.name === "devideBoundaryDataBy")?.value; + const filteredReadMeData = findReadMe(readMeData, campaignType, type, section); + let template = await createTemplate({ + hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets, + hierarchyLevelName, + addFacilityData: schema?.template?.includeFacilityData, + schema, + boundaries: campaignData?.boundaries, + tenantId: Digit.ULBService.getCurrentTenantId(), + hierarchyType, + readMeData: filteredReadMeData, + readMeSheetName, + t, + }); + const translatedTemplate = translateTemplate(template, t); + + // Create a new workbook + const workbook = new ExcelJS.Workbook(); + + formatTemplate(translatedTemplate, workbook); + + // Color headers + colorHeaders( + workbook, + [...hierarchy.map((item) => t(item)), t(commonColumn)], + schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [], + [] + ); + + formatAndColorReadMeFile( + workbook, + filteredReadMeData?.map((item) => item?.header), + readMeSheetName + ); + + // protextData + await protectData({ + workbook, + hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets, + addFacilityData: schema?.template?.includeFacilityData, + schema, + t, + }); + + // Write the workbook to a buffer + workbook.xlsx.writeBuffer({ compression: true }).then((buffer) => { + // Create a Blob from the buffer + const blob = new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); + // Create a URL for the Blob + const url = URL.createObjectURL(blob); + // Create a link element and simulate click to trigger download + const link = document.createElement("a"); + link.href = url; + link.download = `${t(section)}.xlsx`; + link.click(); + // Revoke the URL to release the Blob + URL.revokeObjectURL(url); + setLoader(false); + }); + } catch (error) { + setLoader(false); + console.error(error?.message); + setToast({ state: "error", message: t("ERROR_DOWNLOADING_TEMPLATE") }); + } +}; + +export const formatAndColorReadMeFile = (workbook, headerSet, readMeSheetName) => { + const readMeSheet = workbook.getWorksheet(readMeSheetName); + if (!readMeSheet) return; + setAndFormatHeaders(readMeSheet); + formatWorksheet(readMeSheet, headerSet); +}; + +export function setAndFormatHeaders(worksheet) { + const row = worksheet.getRow(1); + // Color the header cell + row.eachCell((cell) => { + cell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "f25449" }, // Header cell color + }; + cell.alignment = { vertical: "middle", horizontal: "center", wrapText: true }; // Center align and wrap text + cell.font = { bold: true }; + }); +} +export function formatWorksheet(worksheet, headerSet) { + // Add the data rows with text wrapping + const lineHeight = 15; // Set an approximate line height + const maxCharactersPerLine = 100; // Set a maximum number of characters per line for wrapping + + worksheet.eachRow((row) => { + row.eachCell({ includeEmpty: true }, (cell) => { + cell.alignment = { vertical: "middle", horizontal: "left", wrapText: true }; // Apply text wrapping + // Calculate the required row height based on content length + const numberOfLines = Math.ceil(cell?.value.length / maxCharactersPerLine); + row.height = numberOfLines * lineHeight; + + // Make the header text bold + if (headerSet?.includes(cell.value)) { + cell.font = { bold: true }; + } + }); + }); + worksheet.getColumn(1).width = 130; +} + +export const protectData = async ({ workbook, hierarchyLevelWiseSheets = true, addFacilityData = false, schema, t }) => { + if (hierarchyLevelWiseSheets) { + if (addFacilityData) { + await freezeSheetValues(workbook, t(BOUNDARY_DATA_SHEET)); + await performUnfreezeCells(workbook, t(FACILITY_DATA_SHEET)); + if (schema?.template?.propertiesToHide && Array.isArray(schema.template.propertiesToHide)) { + let tempPropertiesToHide = schema?.template?.propertiesToHide.map((item) => t(generateLocalisationKeyForSchemaProperties(item))); + await hideUniqueIdentifierColumn(workbook, t(FACILITY_DATA_SHEET), tempPropertiesToHide); + } + if (schema?.template?.facilitySchemaApiMapping) { + } else { + } + } else { + await freezeWorkbookValues(workbook); + await unfreezeColumnsByHeader( + workbook, + schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [] + ); + } + } else { + // total boundary Data in one sheet + if (addFacilityData) { + await freezeSheetValues(workbook, t(BOUNDARY_DATA_SHEET)); + await performUnfreezeCells(workbook, t(FACILITY_DATA_SHEET)); + if (schema?.template?.propertiesToHide && Array.isArray(schema.template.propertiesToHide)) { + let tempPropertiesToHide = schema?.template?.propertiesToHide.map((item) => t(generateLocalisationKeyForSchemaProperties(item))); + await hideUniqueIdentifierColumn(workbook, t(FACILITY_DATA_SHEET), tempPropertiesToHide); + } + + if (schema?.template?.facilitySchemaApiMapping) { + } else { + } + } else { + await freezeWorkbookValues(workbook); + await unfreezeColumnsByHeader( + workbook, + schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [] + ); + } + } +}; + +export const colorHeaders = async (workbook, headerList1, headerList2, headerList3) => { + try { + // Iterate through each sheet + workbook.eachSheet((sheet, sheetId) => { + // Get the first row + const firstRow = sheet.getRow(1); + + // Iterate through each cell in the first row + firstRow.eachCell((cell, colNumber) => { + const cellValue = cell.value.toString(); + + // Check conditions and set colors + if (headerList1?.includes(cellValue)) { + cell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "ff9248" }, + }; + } else if (headerList2?.includes(cellValue)) { + cell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "93C47D" }, + }; + } else if (headerList3?.includes(cellValue)) { + cell.fill = { + type: "pattern", + pattern: "solid", + fgColor: { argb: "CCCC00" }, + }; + } + }); + }); + } catch (error) { + console.error("Error coloring headers:", error); + } +}; + +export const formatTemplate = (template, workbook) => { + template.forEach(({ sheetName, data }) => { + // Create a new worksheet with properties + const worksheet = workbook.addWorksheet(sheetName); + data?.forEach((row, index) => { + const worksheetRow = worksheet.addRow(row); + + // Apply fill color to each cell in the first row and make cells bold + if (index === 0) { + worksheetRow.eachCell((cell, colNumber) => { + // Set font to bold + cell.font = { bold: true }; + + // Enable text wrapping + cell.alignment = { wrapText: true }; + // Update column width based on the length of the cell's text + const currentWidth = worksheet.getColumn(colNumber).width || SHEET_COLUMN_WIDTH; // Default width or current width + const newWidth = Math.max(currentWidth, cell.value.toString().length + 2); // Add padding + worksheet.getColumn(colNumber).width = newWidth; + }); + } + }); + updateFontNameToRoboto(worksheet); + }); +}; + +export const translateTemplate = (template, t) => { + // Initialize an array to hold the transformed result + const transformedResult = []; + + // Iterate over each sheet in the divided data + for (const sheet of template) { + const sheetData = sheet.data; + + // Find the index of the boundaryCode column in the header row + const boundaryCodeIndex = sheetData[0].indexOf(commonColumn); + + const sheetName = t(sheet.sheetName); + const transformedSheet = { + sheetName: sheetName.length > 31 ? sheetName.slice(0, 31) : sheetName, + data: [], + }; + + // Iterate over each row in the sheet data + for (const [rowIndex, row] of sheetData.entries()) { + // Transform each entity in the row using the transformFunction + const transformedRow = row.map((entity, index) => { + // Skip transformation for the boundaryCode column + if ((index === boundaryCodeIndex && rowIndex !== 0) || typeof entity === "number") { + return entity; + } + return t(entity); + }); + transformedSheet.data.push(transformedRow); + } + + // Add the transformed sheet to the transformed result + transformedResult.push(transformedSheet); + } + + return transformedResult; +}; + +// get schema for validation +export const getSchema = (campaignType, type, section, schemas) => { + return schemas.find((schema) => { + if (!schema.campaignType) { + return schema.type === type && schema.section === section; + } + return schema.campaignType === campaignType && schema.type === type && schema.section === section; + }); +}; + +// Performs resource mapping and data filtering for Excel files based on provided schema data, hierarchy, and file data. +export const resourceMappingAndDataFilteringForExcelFiles = (schemaData, hierarchy, selectedFileType, fileDataToStore, t) => { + const resourceMappingData = []; + const newFileData = {}; + if (selectedFileType.id === EXCEL && fileDataToStore) { + // Extract all unique column names from fileDataToStore and then doing thir resource mapping + const columnForMapping = new Set(Object.values(fileDataToStore).flatMap((value) => value?.[0] || [])); + if (schemaData?.schema?.["Properties"]) { + const schemaKeys = Object.keys(schemaData.schema["Properties"]) + .map((item) => generateLocalisationKeyForSchemaProperties(item)) + .concat([...hierarchy, commonColumn]); + schemaKeys.forEach((item) => { + if (columnForMapping.has(t(item))) { + resourceMappingData.push({ + mappedFrom: t(item), + mappedTo: revertLocalisationKey(item), + }); + } + }); + } + + // Filtering the columns with respect to the resource mapping and removing the columns that are not needed + Object.entries(fileDataToStore).forEach(([key, value]) => { + const data = []; + const headers = []; + const toRemove = []; + if (value && value.length > 0) { + value[0].forEach((item, index) => { + const mappedTo = resourceMappingData.find((e) => e.mappedFrom === item)?.mappedTo; + if (!mappedTo) { + toRemove.push(index); + return; + } + headers.push(mappedTo); + return; + }); + for (let i = 1; i < value?.length; i++) { + let temp = []; + for (let j = 0; j < value[i].length; j++) { + if (!toRemove.includes(j)) { + temp.push(value[i][j]); + } + } + data.push(temp); + } + } + newFileData[key] = [headers, ...data]; + }); + } + return { tempResourceMappingData: resourceMappingData, tempFileDataToStore: newFileData }; +}; +export const revertLocalisationKey = (localisedCode) => { + if (!localisedCode || !localisedCode.startsWith(SCHEMA_PROPERTIES_PREFIX + "_")) { + return localisedCode; + } + return localisedCode.substring(SCHEMA_PROPERTIES_PREFIX.length + 1); +}; +export const prepareExcelFileBlobWithErrors = async (data, errors, schema, hierarchy, readMeData, readMeSheetName, t) => { + let tempData = [...data]; + // Process each dataset within the data object + const processedData = {}; + const schemaCols = schema?.schema?.Properties ? Object.keys(schema.schema.Properties) : []; + for (const sheet of tempData) { + const dataset = [...sheet.data]; + + // Add the 'error' column to the header + dataset[0] = dataset[0].map((item) => { + if (item !== commonColumn && schemaCols.includes(item)) { + return t(generateLocalisationKeyForSchemaProperties(item)); + } + return t(item); + }); + if (sheet.sheetName !== t(BOUNDARY_DATA_SHEET) && sheet.sheetName !== t(readMeSheetName)) { + // Process each data row + if (errors) { + dataset[0].push(t("MICROPLAN_ERROR_STATUS_COLUMN"), t("MICROPLAN_ERROR_COLUMN")); + let headerCount = 0; + for (let i = 1; i < dataset.length; i++) { + const row = dataset[i]; + if (i === 1 && row) { + headerCount = row.length; + } + + if (headerCount > row.length) { + row.push(...Array(headerCount - row.length).fill("")); + } + + // Check if there are errors for the given commonColumnData + const errorInfo = errors?.[sheet.sheetName]?.[i - 1]; + if (errorInfo) { + let rowDataAddOn = Object.entries(errorInfo) + .map(([key, value]) => { + return `${t(key)}: ${value.map((item) => t(item)).join(", ")}`; + }) + .join(". "); + row.push(t("MICROPLAN_ERROR_STATUS_INVALID"), rowDataAddOn); + } else { + row.push(""); + } + } + } + } + processedData[sheet.sheetName] = dataset; + } + const errorColumns = ["MICROPLAN_ERROR_STATUS_COLUMN", "MICROPLAN_ERROR_COLUMN"]; + const style = { + font: { color: { argb: "B91900" } }, + border: { + top: { style: "thin", color: { argb: "B91900" } }, + left: { style: "thin", color: { argb: "B91900" } }, + bottom: { style: "thin", color: { argb: "B91900" } }, + right: { style: "thin", color: { argb: "B91900" } }, + }, + }; + const workbook = await convertToWorkBook(processedData, { errorColumns, style }); + colorHeaders( + workbook, + [...hierarchy.map((item) => t(item)), t(commonColumn)], + schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [], + [t("MICROPLAN_ERROR_STATUS_COLUMN"), t("MICROPLAN_ERROR_COLUMN")] + ); + + formatAndColorReadMeFile( + workbook, + readMeData?.map((item) => item?.header), + readMeSheetName + ); + + // protextData + await protectData({ + workbook, + hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets, + addFacilityData: schema?.template?.includeFacilityData, + schema, + t, + }); + return await workbook.xlsx.writeBuffer({ compression: true }).then((buffer) => { + // Create a Blob from the buffer + return new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); + }); + // return xlsxBlob; +}; +export const convertToWorkBook = async (jsonData, columnWithStyle) => { + const workbook = new ExcelJS.Workbook(); + + // Iterate over each sheet in jsonData + for (const [sheetName, data] of Object.entries(jsonData)) { + // Create a new worksheet + const worksheet = workbook.addWorksheet(sheetName); + + // Convert data to worksheet + for (const row of data) { + const newRow = worksheet.addRow(row); + const rowHasData = row?.filter((item) => item !== "").length !== 0; + // Apply red font color to the errorColumn if it exists + if (rowHasData && columnWithStyle?.errorColumns) { + for (const errorColumn of columnWithStyle?.errorColumns) { + const errorColumnIndex = data[0].indexOf(errorColumn); + if (errorColumnIndex !== -1) { + const columnIndex = errorColumnIndex + 1; + if (columnIndex > 0) { + const newCell = newRow.getCell(columnIndex); + if (columnWithStyle.style && newCell) for (const key in columnWithStyle.style) newCell[key] = columnWithStyle.style[key]; + } + } + } + } + } + + // Make the first row bold + if (worksheet.getRow(1)) { + worksheet.getRow(1).font = { bold: true }; + } + + // Set column widths + const columnCount = data?.[0]?.length || 0; + const wscols = Array(columnCount).fill({ width: 30 }); + wscols.forEach((col, colIndex) => { + worksheet.getColumn(colIndex + 1).width = col.width; + }); + } + return workbook; +}; +export const boundaryDataGeneration = async (schemaData, campaignData, t) => { + let boundaryDataAgainstBoundaryCode = {}; + if (schemaData && !schemaData.doHierarchyCheckInUploadedData) { + try { + const rootBoundary = campaignData?.boundaries?.filter((boundary) => boundary.isRoot); // Retrieve session storage data once and store it in a variable + const sessionData = Digit.SessionStorage.get("microplanHelperData") || {}; + let boundaryData = sessionData.filteredBoundaries; + let filteredBoundaries; + if (!boundaryData) { + // Only fetch boundary data if not present in session storage + boundaryData = await fetchBoundaryData(Digit.ULBService.getCurrentTenantId(), campaignData?.hierarchyType, rootBoundary?.[0]?.code); + filteredBoundaries = filterBoundaries(boundaryData, campaignData?.boundaries); + + // Update the session storage with the new filtered boundaries + Digit.SessionStorage.set("microplanHelperData", { + ...sessionData, + filteredBoundaries: filteredBoundaries, + }); + } else { + filteredBoundaries = boundaryData; + } + const xlsxData = addBoundaryData([], filteredBoundaries, campaignData?.hierarchyType)?.[0]?.data; + xlsxData.forEach((item, i) => { + if (i === 0) return; + let boundaryCodeIndex = xlsxData?.[0]?.indexOf(commonColumn); + if (boundaryCodeIndex >= item.length) { + // If boundaryCodeIndex is out of bounds, return the item as is + boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item.slice().map(t); + } else { + // Otherwise, remove the element at boundaryCodeIndex + boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item + .slice(0, boundaryCodeIndex) + .concat(item.slice(boundaryCodeIndex + 1)) + .map(t); + } + }); + return boundaryDataAgainstBoundaryCode; + } catch (error) { + console.error(error?.message); + } + } +}; + +export const handleExcelFile = async ( + file, + schemaData, + hierarchy, + selectedFileType, + boundaryDataAgainstBoundaryCode, + setUploadedFileError, + t, + campaignData, + readMeSheetName +) => { + try { + // Converting the file to preserve the sequence of columns so that it can be stored + let fileDataToStore = await parseXlsxToJsonMultipleSheets(file, { header: 0 }); + const additionalSheets = []; + if (fileDataToStore[t(BOUNDARY_DATA_SHEET)]) { + additionalSheets.push({ sheetName: t(BOUNDARY_DATA_SHEET), data: fileDataToStore[t(BOUNDARY_DATA_SHEET)], position: -1 }); + delete fileDataToStore[t(BOUNDARY_DATA_SHEET)]; + } + if (fileDataToStore[t(readMeSheetName)]) { + additionalSheets.push({ sheetName: t(readMeSheetName), data: fileDataToStore[t(readMeSheetName)], position: 0 }); + delete fileDataToStore[t(readMeSheetName)]; + } + let { tempResourceMappingData, tempFileDataToStore } = resourceMappingAndDataFilteringForExcelFiles( + schemaData, + hierarchy, + selectedFileType, + fileDataToStore, + t + ); + fileDataToStore = await convertJsonToXlsx(tempFileDataToStore); + // Converting the input file to json format + let result = await parseXlsxToJsonMultipleSheets(fileDataToStore, { header: 1 }); + if (result?.error) { + return { + check: false, + interruptUpload: true, + error: result.error, + fileDataToStore: {}, + toast: { state: "error", message: t("ERROR_CORRUPTED_FILE") }, + }; + } + let extraColumns = [commonColumn]; + // checking if the hierarchy and common column is present the uploaded data + extraColumns = [...hierarchy, commonColumn]; + let data = Object.values(tempFileDataToStore); + let errorMsg; + let errors; // object containing the location and type of error + let toast; + let hierarchyDataPresent = true; + let latLngColumns = + Object.entries(schemaData?.schema?.Properties || {}).reduce((acc, [key, value]) => { + if (value?.isLocationDataColumns) { + acc.push(key); + } + return acc; + }, []) || []; + data.forEach((item) => { + const keys = item[0]; + if (keys?.length !== 0) { + if (!extraColumns?.every((e) => keys.includes(e))) { + if (schemaData && !schemaData.doHierarchyCheckInUploadedData) { + hierarchyDataPresent = false; + } else { + errorMsg = { + check: false, + interruptUpload: true, + error: t("ERROR_BOUNDARY_DATA_COLUMNS_ABSENT"), + fileDataToStore: {}, + toast: { state: "error", message: t("ERROR_BOUNDARY_DATA_COLUMNS_ABSENT") }, + }; + } + } + if (!latLngColumns?.every((e) => keys.includes(e))) { + toast = { state: "warning", message: t("ERROR_UPLOAD_EXCEL_LOCATION_DATA_MISSING") }; + } + } + }); + if (errorMsg && !errorMsg?.check) return errorMsg; + // Running Validations for uploaded file + let response = await checkForErrorInUploadedFileExcel(result, schemaData.schema, t); + if (!response.valid) setUploadedFileError(response.message); + errorMsg = response.message; + errors = response.errors; + const missingProperties = response.missingProperties; + let check = response.valid; + try { + if ( + schemaData && + !schemaData.doHierarchyCheckInUploadedData && + !hierarchyDataPresent && + boundaryDataAgainstBoundaryCode && + (!missingProperties || [...missingProperties]?.includes(commonColumn)) + ) { + let tempBoundaryDataAgainstBoundaryCode = (await boundaryDataGeneration(schemaData, campaignData, t)) || {}; + for (const sheet in tempFileDataToStore) { + const commonColumnIndex = tempFileDataToStore[sheet]?.[0]?.indexOf(commonColumn); + if (commonColumnIndex !== -1) { + const dataCollector = []; + for (let index = 0; index < tempFileDataToStore[sheet].length; index++) { + let row = tempFileDataToStore[sheet][index]; + const commonColumnValues = row[commonColumnIndex]?.split(",").map((item) => item.trim()); + if (!commonColumnValues) { + dataCollector.push([...new Array(hierarchy.length).fill(""), ...row]); + continue; + } + for (const value of commonColumnValues) { + const newRowData = [...row]; + newRowData[commonColumnIndex] = value; + dataCollector.push([ + ...(tempBoundaryDataAgainstBoundaryCode[value] + ? tempBoundaryDataAgainstBoundaryCode[value] + : index !== 0 + ? new Array(hierarchy.length).fill("") + : []), + ...newRowData, + ]); + } + } + tempFileDataToStore[sheet] = dataCollector; + } + + tempFileDataToStore[sheet][0] = [...hierarchy, ...tempFileDataToStore[sheet][0]]; + } + } + } catch (error) { + console.error("Error in boundary adding operaiton: ", error); + } + tempFileDataToStore = addMissingPropertiesToFileData(tempFileDataToStore, missingProperties); + return { check, errors, errorMsg, fileDataToStore: tempFileDataToStore, tempResourceMappingData, toast, additionalSheets }; + } catch (error) { + console.error("Error in handling Excel file:", error.message); + } +}; +export const addMissingPropertiesToFileData = (data, missingProperties) => { + if (!data || !missingProperties) return data; + let tempData = {}; + Object.entries(data).forEach(([key, value], index) => { + const filteredMissingProperties = [...missingProperties]?.reduce((acc, item) => { + if (!value?.[0]?.includes(item)) { + acc.push(item); + } + return acc; + }, []); + const newTempHeaders = value?.[0].length !== 0 ? [...value[0], ...filteredMissingProperties] : [...filteredMissingProperties]; + tempData[key] = [newTempHeaders, ...value.slice(1)]; + }); + return tempData; +}; + +export const handleGeojsonFile = async (file, schemaData, setUploadedFileError, t) => { + // Reading and checking geojson data + const data = await readGeojson(file, t); + if (!data.valid) { + return { check: false, stopUpload: true, toast: data.toast }; + } + + // Running geojson validaiton on uploaded file + let response = geojsonValidations(data.geojsonData, schemaData.schema, t); + if (!response.valid) setUploadedFileError(response.message); + let check = response.valid; + let error = response.message; + let fileDataToStore = data.geojsonData; + return { check, error, fileDataToStore }; +}; + +const generateLocalisationKeyForSchemaProperties = (code) => { + if (!code) return code; + return `${SCHEMA_PROPERTIES_PREFIX}_${code}`; +}; +export const handleShapefiles = async (file, schemaData, setUploadedFileError, selectedFileType, setToast, t) => { + // Reading and validating the uploaded geojson file + let response = await readAndValidateShapeFiles(file, t, selectedFileType["namingConvention"]); + if (!response.valid) { + setUploadedFileError(response.message); + setToast(response.toast); + } + let check = response.valid; + let error = response.message; + let fileDataToStore = response.data; + return { check, error, fileDataToStore }; +}; + +export const convertToSheetArray = (data) => { + if (!data) return []; + const convertedSheetData = []; + for (const [key, value] of Object.entries(data)) { + convertedSheetData.push({ sheetName: key, data: value }); + } + return convertedSheetData; +}; + +//find guideline +export const findGuideLine = (campaignType, type, section, guidelineArray) => { + if (!guidelineArray) return guidelineArray; + return guidelineArray.find( + (guideline) => + guideline.fileType === type && guideline.templateIdentifier === section && (!guideline.campaignType || guideline.campaignType === campaignType) + )?.guidelines; +}; + +// Utility function to introduce a delay +export const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); diff --git a/frontend/microplan-ui/web/microplan/App.js b/frontend/micro-ui/web/microplan/App.js similarity index 100% rename from frontend/microplan-ui/web/microplan/App.js rename to frontend/micro-ui/web/microplan/App.js diff --git a/frontend/microplan-ui/web/microplan/Dockerfile b/frontend/micro-ui/web/microplan/Dockerfile similarity index 100% rename from frontend/microplan-ui/web/microplan/Dockerfile rename to frontend/micro-ui/web/microplan/Dockerfile diff --git a/frontend/microplan-ui/web/microplan/install-deps.sh b/frontend/micro-ui/web/microplan/install-deps.sh similarity index 100% rename from frontend/microplan-ui/web/microplan/install-deps.sh rename to frontend/micro-ui/web/microplan/install-deps.sh diff --git a/frontend/microplan-ui/web/microplan/inter-package.json b/frontend/micro-ui/web/microplan/inter-package.json similarity index 100% rename from frontend/microplan-ui/web/microplan/inter-package.json rename to frontend/micro-ui/web/microplan/inter-package.json diff --git a/frontend/microplan-ui/web/microplan/nginx.conf b/frontend/micro-ui/web/microplan/nginx.conf similarity index 100% rename from frontend/microplan-ui/web/microplan/nginx.conf rename to frontend/micro-ui/web/microplan/nginx.conf diff --git a/frontend/microplan-ui/web/microplan/package.json b/frontend/micro-ui/web/microplan/package.json similarity index 100% rename from frontend/microplan-ui/web/microplan/package.json rename to frontend/micro-ui/web/microplan/package.json diff --git a/frontend/microplan-ui/web/microplan/webpack.config.js b/frontend/micro-ui/web/microplan/webpack.config.js similarity index 100% rename from frontend/microplan-ui/web/microplan/webpack.config.js rename to frontend/micro-ui/web/microplan/webpack.config.js diff --git a/frontend/micro-ui/web/public/index.html b/frontend/micro-ui/web/public/index.html index 9da00f7e1de..661b6fa2425 100644 --- a/frontend/micro-ui/web/public/index.html +++ b/frontend/micro-ui/web/public/index.html @@ -12,6 +12,7 @@ + DIGIT diff --git a/frontend/microplan-ui/README.md b/frontend/microplan-ui/README.md deleted file mode 100644 index 9420dbb760d..00000000000 --- a/frontend/microplan-ui/README.md +++ /dev/null @@ -1,140 +0,0 @@ - -# workbench ui - -A React App built on top of DIGIT UI Core. - -# DIGIT - -DIGIT eGovernance Platform Services - -DIGIT (Digital Infrastructure for Governance, Impact & Transformation) is India's largest platform for governance services. Visit https://core.digit.org/ for more details. - -DIGIT platform is microservices based API platform enabling quick rebundling of services as per specific needs. This is a repo that lays down the core platform on top of which other mission services depend. - - -# DIGIT UI - - -This repository contains source code for web implementation of the new Digit UI modules with dependencies and libraries. - -Workbench module is used to Manage the master data (MDMS V2 Service) used across the DIGIT Services / Applications - -It is also used to manage the Localisation data present in the system (Localisation service) - - -## Run Locally - -Clone the project - -```bash - git clone https://github.com/egovernments/DIGIT-Frontend.git -``` - -Go to the Sub directory to run UI -```bash - cd into micro-ui/web/micro-ui-internals -``` - -Install dependencies - -```bash - yarn install -``` - -Add .env file -```bash - micro-ui/web/micro-ui-internals/example/.env -``` - -Start the server - -```bash - yarn start -``` - - -## Environment Variables - -To run this project, you will need to add the following environment variables to your .env file - -`REACT_APP_PROXY_API` :: `{{server url}}` - -`REACT_APP_GLOBAL` :: `{{server url}}` - -`REACT_APP_PROXY_ASSETS` :: `{{server url}}` - -`REACT_APP_USER_TYPE` :: `{{EMPLOYEE||CITIZEN}}` - -`SKIP_PREFLIGHT_CHECK` :: `true` - -[sample .env file](https://github.com/egovernments/Digit-Core/blob/workbench/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev) - -## Tech Stack - -**Libraries:** - -[React](https://react.dev/) - -[React Hook Form](https://www.react-hook-form.com/) - -[React Query](https://tanstack.com/query/v3/) - -[Tailwind CSS](https://tailwindcss.com/) - -[Webpack](https://webpack.js.org/) - -## License - -[MIT](https://choosealicense.com/licenses/mit/) - - -## Author - -- [@jagankumar-egov](https://www.github.com/jagankumar-egov) - - -## Documentation - -[Documentation](https://https://core.digit.org/guides/developer-guide/ui-developer-guide/digit-ui) - - -## Support - -For support, add the issues in https://github.com/egovernments/DIGIT-core/issues. - - -## Modules - - 1. Core - 2. Workbench - 3. HRMS - 4. Dashboard - 5. Engagement - 6. Payment - -## Starting with Digit-UI App (Impelmentation Teams) - MICRO-UI - - -Go to the Sub directory to run UI - -```bash - cd into micro-ui/web -``` - -```bash - yarn install -``` - -Add .env file -```bash - micro-ui/web/.env -``` - -Start the server - -```bash - yarn start -``` - - -![Logo](https://s3.ap-south-1.amazonaws.com/works-dev-asset/mseva-white-logo.png) diff --git a/frontend/microplan-ui/package.json b/frontend/microplan-ui/package.json deleted file mode 100644 index 19a3c47d6ee..00000000000 --- a/frontend/microplan-ui/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "workbench-ui", - "version": "1.0.0" -} \ No newline at end of file diff --git a/frontend/microplan-ui/web/.babelrc b/frontend/microplan-ui/web/.babelrc deleted file mode 100644 index 5f90443d15e..00000000000 --- a/frontend/microplan-ui/web/.babelrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "presets": [ - "@babel/preset-env","@babel/preset-react" - ] - } \ No newline at end of file diff --git a/frontend/microplan-ui/web/.env.sample b/frontend/microplan-ui/web/.env.sample deleted file mode 100644 index e87c7f586c4..00000000000 --- a/frontend/microplan-ui/web/.env.sample +++ /dev/null @@ -1,3 +0,0 @@ -SKIP_PREFLIGHT_CHECK=true -REACT_APP_STATE_LEVEL_TENANT_ID=pb -REACT_APP_PROXY_URL=https://works-dev.digit.org diff --git a/frontend/microplan-ui/web/docker/Dockerfile b/frontend/microplan-ui/web/docker/Dockerfile deleted file mode 100644 index 48261a589c8..00000000000 --- a/frontend/microplan-ui/web/docker/Dockerfile +++ /dev/null @@ -1,26 +0,0 @@ -# FROM egovio/alpine-node-builder-14:yarn AS build -FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build -RUN apk update && apk upgrade -RUN apk add --no-cache git>2.30.0 -ARG WORK_DIR -WORKDIR /app -ENV NODE_OPTIONS "--max-old-space-size=8168" - -COPY ${WORK_DIR} . -RUN ls -lah - -#RUN node web/envs.js -RUN cd web/ \ - && chmod +x ./install-deps.sh \ - && ./install-deps.sh \ - && yarn install \ - && yarn build:webpack - -FROM nginx:mainline-alpine -#FROM ghcr.io/egovernments/nginx:mainline-alpine -ENV WORK_DIR=/var/web/digit-ui - -RUN mkdir -p ${WORK_DIR} - -COPY --from=build /app/web/build ${WORK_DIR}/ -COPY --from=build /app/web/docker/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/microplan-ui/web/docker/devDockerfile b/frontend/microplan-ui/web/docker/devDockerfile deleted file mode 100644 index d7b1ba1870a..00000000000 --- a/frontend/microplan-ui/web/docker/devDockerfile +++ /dev/null @@ -1,26 +0,0 @@ -#FROM egovio/alpine-node-builder-14:yarn AS build -FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build -RUN apk update && apk upgrade -RUN apk add --no-cache git>2.30.0 -ARG WORK_DIR -WORKDIR /app -ENV NODE_OPTIONS "--max-old-space-size=1792" - -COPY ${WORK_DIR} . -RUN ls -lah - -#RUN node web/envs.js -RUN cd web/ \ - && node envs.js \ - && ./install-deps.sh \ - && yarn install \ - && yarn build - -#FROM nginx:mainline-alpine -FROM ghcr.io/egovernments/nginx:mainline-alpine -ENV WORK_DIR=/var/web/digit-ui - -RUN mkdir -p ${WORK_DIR} - -COPY --from=build /app/web/build ${WORK_DIR}/ -COPY --from=build /app/web/docker/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/microplan-ui/web/docker/masDockerfile b/frontend/microplan-ui/web/docker/masDockerfile deleted file mode 100644 index 5d7cf45dd87..00000000000 --- a/frontend/microplan-ui/web/docker/masDockerfile +++ /dev/null @@ -1,25 +0,0 @@ -#FROM egovio/alpine-node-builder-14:yarn AS build -FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build -RUN apk update && apk upgrade -RUN apk add --no-cache git>2.30.0 -ARG WORK_DIR -WORKDIR /app -ENV NODE_OPTIONS "--max-old-space-size=3792" - -COPY ${WORK_DIR} . -RUN ls -lah - -#RUN node web/envs.js -RUN cd web/ \ - && node envs.js \ - && yarn install \ - && yarn build - -#FROM nginx:mainline-alpine -FROM ghcr.io/egovernments/nginx:mainline-alpine -ENV WORK_DIR=/var/web/digit-ui - -RUN mkdir -p ${WORK_DIR} - -COPY --from=build /app/web/build ${WORK_DIR}/ -COPY --from=build /app/web/docker/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/microplan-ui/web/docker/nginx.conf b/frontend/microplan-ui/web/docker/nginx.conf deleted file mode 100644 index 4f532e4a6ed..00000000000 --- a/frontend/microplan-ui/web/docker/nginx.conf +++ /dev/null @@ -1,12 +0,0 @@ -server -{ - listen 80; - underscores_in_headers on; - - location /digit-ui - { - root /var/web; - index index.html index.htm; - try_files $uri $uri/ /digit-ui/index.html; - } -} \ No newline at end of file diff --git a/frontend/microplan-ui/web/envs.js b/frontend/microplan-ui/web/envs.js deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/frontend/microplan-ui/web/install-deps.sh b/frontend/microplan-ui/web/install-deps.sh deleted file mode 100644 index efaceaee20d..00000000000 --- a/frontend/microplan-ui/web/install-deps.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -BRANCH="$(git branch --show-current)" - -echo "Main Branch: $BRANCH" - -INTERNALS="micro-ui-internals" - -cp $INTERNALS/example/src/UICustomizations.js src/Customisations - -cd $INTERNALS && echo "Branch: $(git branch --show-current)" && echo "$(git log -1 --pretty=%B)" && echo "installing packages" - - -# yarn install diff --git a/frontend/microplan-ui/web/micro-ui-internals/.prettierignore b/frontend/microplan-ui/web/micro-ui-internals/.prettierignore deleted file mode 100644 index d54de016ef0..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/.prettierignore +++ /dev/null @@ -1,23 +0,0 @@ - -# See https://help.github.com/ignore-files/ for more about ignoring files. -# dependencies -node_modules -# builds -build -dist -.rpt2_cache -# dev -dev.css -index.css -index.compat.css -index.min.css -# misc -.DS_Store -.env -.env.local -.env.development.local -.env.test.local -.env.production.local -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/frontend/microplan-ui/web/micro-ui-internals/.prettierrc.json b/frontend/microplan-ui/web/micro-ui-internals/.prettierrc.json deleted file mode 100644 index b975008d6f8..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/.prettierrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "printWidth": 150 -} diff --git a/frontend/microplan-ui/web/micro-ui-internals/README.md b/frontend/microplan-ui/web/micro-ui-internals/README.md deleted file mode 100644 index 17c3165a4fe..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/README.md +++ /dev/null @@ -1,178 +0,0 @@ -# microplan ui - -A React App built on top of DIGIT UI Core. - -# DIGIT UI - -DIGIT (Digital Infrastructure for Governance, Impact & Transformation) is India's largest platform for governance services. Visit https://www.digit.org for more details. - -This repository contains source code for web implementation of the new Digit UI modules with dependencies and libraries. - -Microplan module is used to Manage the master data (MDMS V2 Service) used across the DIGIT Services / Applications - -It is also used to manage the Localisation data present in the system (Localisation service) - -## Run Locally - -Clone the project - -```bash - git clone https://github.com/egovernments/Digit-Core.git -``` - -Go to the Sub directory to run UI - -```bash - cd into frontend/micro-ui/web/micro-ui-internals -``` - -Install dependencies - -```bash - yarn install -``` - -Add .env file - -```bash - frontend/micro-ui/web/micro-ui-internals/example/.env -``` - -Start the server - -```bash - yarn start -``` - -## Environment Variables - -To run this project, you will need to add the following environment variables to your .env file - -`REACT_APP_PROXY_API` :: `{{server url}}` - -`REACT_APP_GLOBAL` :: `{{server url}}` - -`REACT_APP_PROXY_ASSETS` :: `{{server url}}` - -`REACT_APP_USER_TYPE` :: `{{EMPLOYEE||CITIZEN}}` - -`SKIP_PREFLIGHT_CHECK` :: `true` - -[sample .env file]() - -## Tech Stack - -**Libraries:** - -[React](https://react.dev/) - -[React Hook Form](https://www.react-hook-form.com/) - -[React Query](https://tanstack.com/query/v3/) - -[Tailwind CSS](https://tailwindcss.com/) - -[Webpack](https://webpack.js.org/) - -## License - -[MIT](https://choosealicense.com/licenses/mit/) - -# Section Information - -Form composer has not been used in Create Microplan flow - -## Create Flow - -- Users start by selecting a campaign to create a new microplan. -- They fill in basic microplan details such as campaign name, type, start date, and end date. -- After selecting a campaign, users upload relevant files or data required for the microplan. -- They list out any hypotheses or assumptions related to the microplan. -- Users configure any necessary formulas or calculations for the microplan. -- They have the option to visualize uploaded data on a map for better understanding. -- The microplan is generated based on the input provided in previous steps. -- Users can edit hypotheses and observe how they fit their use case best. -- The process is managed by the Create Microplan wrapper, which handles state initialization, session storage for temporary data storage -- and navigation through different creation steps using a stepper component. - -## Opening Saved Microplan: - -- Users navigate to a screen displaying their saved microplan drafts upon clicking "Open Saved Microplan." -- Upon landing, the system initiates a search for plan configurations to populate the table by default with microplan drafts. -- Users can refine their search using fields like Microplan Name and Status. -- Clicking on a row in the table redirects users to edit the selected microplan draft, pre-filling data from the chosen draft. -- Triggered upon row selection, it manages tasks such as setting the current page to the first step of microplan creation, establishing status for sections like MICROPLAN_DETAILS, UPLOAD_DATA, HYPOTHESIS, and FORMULA_CONFIGURATION, and setting necessary data and identifiers (planConfigurationId and auditDetails). - -## Microplan Details - -- The first card contains details about the campaign. -- The second card is a blank field where a name for the microplan needs to be entered. - -## Upload Section - -- Users upload files (Excel, GeoJSON, Shapefile) associated with MDMS configurations, campaign details, and hierarchy data. -- Users trigger UploadFileToFileStorage function upon file selection. -- Validates file name against system requirements. -- Uses switch case based on file type: -- Excel: Validations and conversion via handleExcelFile. -- GeoJSON: Validations and handling with handleGeojsonFile. -- Shapefile: Similar handling to GeoJSON. -- Halts upload on validation failure, provides specific error messages- -- Successfully validated files are uploaded to the file store. -- Requires resource mapping for GeoJSON and Shapefile uploads. -- Modal "SpatialDataPropertyMapping" assists in column mapping. -- Validates against MDMS schemas using Ajv library. -- Fetches missing hierarchy data in case of facility from session storage or API. -- Utilizes fetchBoundaryDataWrapper to process and integrate boundary data. -- Double-clicking stored file displays data in Excel-like format (JsonPreviewInExcelForm). -- Uses Ajv library for validating JSON data against MDMS schemas. - -## Hypothesis Section: - -- The hypothesis autofill data is extracted and inserted into the user interface (UI). -- This action pre-populates the UI with a list of hypothesis keys, leaving the corresponding values blank for the user to fill. -- Customized selects and inputs are employed to enforce constraints on the inputs. -- Users are prompted to select only one hypothesis key from the provided list. - -## Rule Engine Section: - -- Combines input data, DBMS operators, and selected hypotheses to compute flexible outputs. -- Efficiently stores and retrieves rules using Session Storage for consistency. -- Manages rule data and session-specific information to maintain continuity. -- Uses MDMS autofill data to populate rules dynamically based on predefined constraints. -- Includes functions like setRuleEngineDataFromSsn to streamline rule utilization and setAutoFillRules for automated rule configuration. - -## Mapping: - -- The "init" function uses Leaflet to initialize the map, configuring parameters like the map element ID and base map data. -- The system processes uploaded data by sequentially executing functions to extract, format, and plot GeoJSON features on the map. -- Users select boundaries from a dropdown, and the system uses this selection to generate and plot GeoJSON features on the map, enhancing spatial visualization. -- Functions like extractGeoData, processHierarchyAndData, prepareGeoJson, and addGeojsonToMap handle data extraction, hierarchical processing, GeoJSON preparation, and visualization on the map, utilizing helper functions for comprehensive data management and display. - -## Microplan Preview: - -- React component responsible for displaying and managing microplan data. -- Supports viewing, editing, and finalizing changes to microplan data. -- Handles modal states and user interactions effectively. -- Resource Calculation Includes functions like calculateResource, findInputValue, and findResult. -- Calculates resource values based on formulas, assumptions, and input data. -- Facilitates dynamic calculation and display of resource data within the preview. -- Utility Functions provide essential utilities like getRequiredColumnsFromSchema, innerJoinLists, and filterObjects. -- Supports data validation, merging, and filtering operations. -- Enhances data management capabilities within the microplan preview. -- Hierarchy and Data Filtering are the Functionality for filtering microplan data based on user-selected hierarchy levels. -- Improves data visibility and relevance by applying hierarchical filters effectively. - -## Author - -- [@jagankumar-egov](https://www.github.com/jagankumar-egov) - -## Documentation - -[Documentation](https://https://core.digit.org/guides/developer-guide/ui-developer-guide/digit-ui) - -## Support - -For support, add the issues in https://github.com/egovernments/DIGIT-core/issues. - -![Logo](https://s3.ap-south-1.amazonaws.com/works-dev-asset/mseva-white-logo.png) diff --git a/frontend/microplan-ui/web/micro-ui-internals/clean.sh b/frontend/microplan-ui/web/micro-ui-internals/clean.sh deleted file mode 100644 index 2235ef1c1d0..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/clean.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -BASEDIR="$( cd "$( dirname "$0" )" && pwd )" - -msg() { - echo -e "\n\n\033[32;32m$1\033[0m" -} - -msg "Cleaning root" -rm -rf node_modules - -msg "Cleaning css" -cd "$BASEDIR/packages/css" && rm -rf node_modules - -msg "Cleaning libraries" -cd "$BASEDIR/packages/libraries" && rm -rf node_modules - -msg "Cleaning react-components" -cd "$BASEDIR/packages/react-components" && rm -rf node_modules - -msg "Cleaning PGR module" -cd "$BASEDIR/packages/modules/pgr" && rm -rf node_modules - -msg "Cleaning FSM module" -cd "$BASEDIR/packages/modules/fsm" && rm -rf node_modules - -msg "Cleaning Core module" -cd "$BASEDIR/packages/modules/core" && rm -rf node_modules diff --git a/frontend/microplan-ui/web/micro-ui-internals/example/.env-health-qa b/frontend/microplan-ui/web/micro-ui-internals/example/.env-health-qa deleted file mode 100644 index 73b42b7dfad..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/example/.env-health-qa +++ /dev/null @@ -1,7 +0,0 @@ -SKIP_PREFLIGHT_CHECK=true -REACT_APP_USER_TYPE=EMPLOYEE -REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a -REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c -REACT_APP_PROXY_API=https://health-qa.digit.org -REACT_APP_PROXY_ASSETS=https://health-qa.digit.org -REACT_APP_GLOBAL=https://egov-dev-assets.s3.ap-south-1.amazonaws.com/globalConfigsWorkbenchHCM.js diff --git a/frontend/microplan-ui/web/micro-ui-internals/example/.env-mz-prod b/frontend/microplan-ui/web/micro-ui-internals/example/.env-mz-prod deleted file mode 100644 index 2d02707d7eb..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/example/.env-mz-prod +++ /dev/null @@ -1,7 +0,0 @@ -SKIP_PREFLIGHT_CHECK=true -REACT_APP_USER_TYPE=EMPLOYEE -REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a -REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c -REACT_APP_PROXY_API=https://salama.digit.org -REACT_APP_PROXY_ASSETS=https://salama.digit.org -REACT_APP_GLOBAL=https://moz-health-prd.s3.af-south-1.amazonaws.com/globalConfig.js diff --git a/frontend/microplan-ui/web/micro-ui-internals/example/.env-mz-uat b/frontend/microplan-ui/web/micro-ui-internals/example/.env-mz-uat deleted file mode 100644 index bedf28a95b1..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/example/.env-mz-uat +++ /dev/null @@ -1,7 +0,0 @@ -SKIP_PREFLIGHT_CHECK=true -REACT_APP_USER_TYPE=EMPLOYEE -REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a -REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c -REACT_APP_PROXY_API=https://moz-health-uat.digit.org -REACT_APP_PROXY_ASSETS=https://moz-health-uat.digit.org -REACT_APP_GLOBAL=https://moz-health-uat.s3.ap-south-1.amazonaws.com/globalConfig.js diff --git a/frontend/microplan-ui/web/micro-ui-internals/example/.env-unifieddev b/frontend/microplan-ui/web/micro-ui-internals/example/.env-unifieddev deleted file mode 100644 index c1cf23a713e..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/example/.env-unifieddev +++ /dev/null @@ -1,8 +0,0 @@ -SKIP_PREFLIGHT_CHECK=true -REACT_APP_USER_TYPE=EMPLOYEE -REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a -REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c -REACT_APP_PROXY_API=https://unified-dev.digit.org -REACT_APP_PROXY_ASSETS=https://unified-dev.digit.org -REACT_APP_GLOBAL=https://egov-dev-assets.s3.ap-south-1.amazonaws.com/globalConfigsMicroplan.js -REACT_APP_CONTEXT=works \ No newline at end of file diff --git a/frontend/microplan-ui/web/micro-ui-internals/example/package.json b/frontend/microplan-ui/web/micro-ui-internals/example/package.json deleted file mode 100644 index b18cfc98537..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/example/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "@egovernments/digit-ui-example", - "version": "1.0.0", - "main": "index.js", - "license": "MIT", - "private": true, - "homepage": "digit-ui", - "scripts": { - "start": "react-scripts start" - }, - "devDependencies": { - "@egovernments/digit-ui-libraries": "1.8.2-beta.1", - "@egovernments/digit-ui-module-core": "1.8.2-beta.1", - "@egovernments/digit-ui-module-utilities": "1.0.1-beta.23", - "@egovernments/digit-ui-react-components": "1.8.2-beta.1", - "@egovernments/digit-ui-module-hcmmicroplanning":"0.0.1", - "http-proxy-middleware": "^1.0.5", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-i18next": "11.16.2", - "react-router-dom": "5.3.0", - "react-scripts": "^4.0.1" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} diff --git a/frontend/microplan-ui/web/micro-ui-internals/example/public/index.html b/frontend/microplan-ui/web/micro-ui-internals/example/public/index.html deleted file mode 100644 index 57d474efe0e..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/example/public/index.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - DIGIT - - - - - - - - - - - -
- - diff --git a/frontend/microplan-ui/web/micro-ui-internals/example/src/UICustomizations.js b/frontend/microplan-ui/web/micro-ui-internals/example/src/UICustomizations.js deleted file mode 100644 index 35658afdd70..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/example/src/UICustomizations.js +++ /dev/null @@ -1,324 +0,0 @@ -import _ from "lodash"; - -//create functions here based on module name set in mdms(eg->SearchProjectConfig) -//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName] -// these functions will act as middlewares -var Digit = window.Digit || {}; - -const businessServiceMap = { - "muster roll": "MR", -}; - -const inboxModuleNameMap = { - "muster-roll-approval": "muster-roll-service", -}; - -function filterUniqueByKey(arr, key) { - const uniqueValues = new Set(); - const result = []; - - arr.forEach((obj) => { - const value = obj[key]; - if (!uniqueValues.has(value)) { - uniqueValues.add(value); - result.push(obj); - } - }); - - return result; -} - -const epochTimeForTomorrow12 = () => { - const now = new Date(); - - // Create a new Date object for tomorrow at 12:00 PM - const tomorrowNoon = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 12, 0, 0, 0); - - // Format the date as "YYYY-MM-DD" - const year = tomorrowNoon.getFullYear(); - const month = String(tomorrowNoon.getMonth() + 1).padStart(2, "0"); // Months are 0-indexed - const day = String(tomorrowNoon.getDate()).padStart(2, "0"); - - return Digit.Utils.date.convertDateToEpoch(`${year}-${month}-${day}`); -}; - -function cleanObject(obj) { - for (const key in obj) { - if (obj.hasOwnProperty(key)) { - if (Array.isArray(obj[key])) { - if (obj[key].length === 0) { - delete obj[key]; - } - } else if ( - obj[key] === undefined || - obj[key] === null || - obj[key] === false || - obj[key] === "" || // Check for empty string - (typeof obj[key] === "object" && Object.keys(obj[key]).length === 0) - ) { - delete obj[key]; - } - } - } - return obj; -} - -export const UICustomizations = { - businessServiceMap, - updatePayload: (applicationDetails, data, action, businessService) => { - if (businessService === businessServiceMap.estimate) { - const workflow = { - comment: data.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - estimate: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap.contract) { - const workflow = { - comment: data?.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - contract: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap?.["muster roll"]) { - const workflow = { - comment: data?.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - musterRoll: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap?.["works.purchase"]) { - const workflow = { - comment: data.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - const additionalFieldsToSet = { - projectId: applicationDetails.additionalDetails.projectId, - invoiceDate: applicationDetails.billDate, - invoiceNumber: applicationDetails.referenceId.split("_")?.[1], - contractNumber: applicationDetails.referenceId.split("_")?.[0], - documents: applicationDetails.additionalDetails.documents, - }; - return { - bill: { ...applicationDetails, ...additionalFieldsToSet }, - workflow, - }; - } - }, - enableModalSubmit: (businessService, action, setModalSubmit, data) => { - if (businessService === businessServiceMap?.["muster roll"] && action.action === "APPROVE") { - setModalSubmit(data?.acceptTerms); - } - }, - enableHrmsSearch: (businessService, action) => { - if (businessService === businessServiceMap.estimate) { - return action.action.includes("TECHNICALSANCTION") || action.action.includes("VERIFYANDFORWARD"); - } - if (businessService === businessServiceMap.contract) { - return action.action.includes("VERIFY_AND_FORWARD"); - } - if (businessService === businessServiceMap?.["muster roll"]) { - return action.action.includes("VERIFY"); - } - if (businessService === businessServiceMap?.["works.purchase"]) { - return action.action.includes("VERIFY_AND_FORWARD"); - } - return false; - }, - getBusinessService: (moduleCode) => { - if (moduleCode?.includes("estimate")) { - return businessServiceMap?.estimate; - } else if (moduleCode?.includes("contract")) { - return businessServiceMap?.contract; - } else if (moduleCode?.includes("muster roll")) { - return businessServiceMap?.["muster roll"]; - } else if (moduleCode?.includes("works.purchase")) { - return businessServiceMap?.["works.purchase"]; - } else if (moduleCode?.includes("works.wages")) { - return businessServiceMap?.["works.wages"]; - } else if (moduleCode?.includes("works.supervision")) { - return businessServiceMap?.["works.supervision"]; - } else { - return businessServiceMap; - } - }, - getInboxModuleName: (moduleCode) => { - if (moduleCode?.includes("estimate")) { - return inboxModuleNameMap?.estimate; - } else if (moduleCode?.includes("contract")) { - return inboxModuleNameMap?.contracts; - } else if (moduleCode?.includes("attendence")) { - return inboxModuleNameMap?.attendencemgmt; - } else { - return inboxModuleNameMap; - } - }, - SearchCampaign: { - preProcess: (data, additionalDetails) => { - const { campaignName = "", endDate = "", projectType = "", startDate = "" } = data?.state?.searchForm || {}; - data.body.CampaignDetails = {}; - data.body.CampaignDetails.pagination = data?.state?.tableForm; - data.body.CampaignDetails.tenantId = Digit.ULBService.getCurrentTenantId(); - // data.body.CampaignDetails.boundaryCode = boundaryCode; - data.body.CampaignDetails.createdBy = Digit.UserService.getUser().info.uuid; - data.body.CampaignDetails.campaignName = campaignName; - data.body.CampaignDetails.status = ["drafted"]; - if (startDate) { - data.body.CampaignDetails.startDate = Digit.Utils.date.convertDateToEpoch(startDate); - } else { - data.body.CampaignDetails.startDate = epochTimeForTomorrow12(); - } - if (endDate) { - data.body.CampaignDetails.endDate = Digit.Utils.date.convertDateToEpoch(endDate); - } - data.body.CampaignDetails.projectType = projectType?.[0]?.code; - - cleanObject(data.body.CampaignDetails); - - return data; - }, - populateProjectType: () => { - const tenantId = Digit.ULBService.getCurrentTenantId(); - - return { - url: "/egov-mdms-service/v1/_search", - params: { tenantId }, - body: { - MdmsCriteria: { - tenantId, - moduleDetails: [ - { - moduleName: "HCM-PROJECT-TYPES", - masterDetails: [ - { - name: "projectTypes", - }, - ], - }, - ], - }, - }, - changeQueryName: "projectType", - config: { - enabled: true, - select: (data) => { - const dropdownData = filterUniqueByKey(data?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes, "code").map((row) => { - return { - ...row, - i18nKey: Digit.Utils.locale.getTransformedLocale(`CAMPAIGN_TYPE_${row.code}`), - }; - }); - return dropdownData; - }, - }, - }; - }, - customValidationCheck: (data) => { - //checking if both to and from date are present then they should be startDate<=endDate - const { startDate, endDate } = data; - const startDateEpoch = Digit.Utils.date.convertDateToEpoch(startDate); - const endDateEpoch = Digit.Utils.date.convertDateToEpoch(endDate); - - if (startDate && endDate && startDateEpoch > endDateEpoch) { - return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; - } - return false; - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - if (key === "CAMPAIGN_DATE") { - return `${Digit.DateUtils.ConvertEpochToDate(value)} - ${Digit.DateUtils.ConvertEpochToDate(row?.endDate)}`; - } - }, - }, - SearchMicroplan: { - preProcess: (data, additionalDetails) => { - const { name, status } = data?.state?.searchForm || {}; - - data.body.PlanConfigurationSearchCriteria = {}; - data.body.PlanConfigurationSearchCriteria.limit = data?.state?.tableForm?.limit; - // data.body.PlanConfigurationSearchCriteria.limit = 10 - data.body.PlanConfigurationSearchCriteria.offset = data?.state?.tableForm?.offset; - data.body.PlanConfigurationSearchCriteria.name = name; - data.body.PlanConfigurationSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); - data.body.PlanConfigurationSearchCriteria.userUuid = Digit.UserService.getUser().info.uuid; - // delete data.body.PlanConfigurationSearchCriteria.pagination - data.body.PlanConfigurationSearchCriteria.status = status?.status; - cleanObject(data.body.PlanConfigurationSearchCriteria); - return data; - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - if (key === "CAMPAIGN_DATE") { - return `${Digit.DateUtils.ConvertEpochToDate(value)} - ${Digit.DateUtils.ConvertEpochToDate(row?.CampaignDetails?.endDate)}`; - } - }, - }, -}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/example/src/index.js b/frontend/microplan-ui/web/micro-ui-internals/example/src/index.js deleted file mode 100644 index 32fd12b0d92..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/example/src/index.js +++ /dev/null @@ -1,73 +0,0 @@ -import React from "react"; -import ReactDOM from "react-dom"; - -import { initLibraries } from "@egovernments/digit-ui-libraries"; -import { DigitUI } from "@egovernments/digit-ui-module-core"; -import "@egovernments/digit-ui-css/example/index.css"; - -import { UICustomizations } from "./UICustomizations"; -import { initMicroplanningComponents } from "@egovernments/digit-ui-module-hcmmicroplanning"; - -var Digit = window.Digit || {}; - -const enabledModules = [ - "DSS", - "HRMS", - "Workbench", - "HCMWORKBENCH", - // "Engagement", "NDSS","QuickPayLinks", "Payment", - "Utilities", - "Microplanning", - //added to check fsm - // "FSM" -]; - -const initTokens = (stateCode) => { - const userType = window.sessionStorage.getItem("userType") || process.env.REACT_APP_USER_TYPE || "CITIZEN"; - const token = window.localStorage.getItem("token") || process.env[`REACT_APP_${userType}_TOKEN`]; - - const citizenInfo = window.localStorage.getItem("Citizen.user-info"); - - const citizenTenantId = window.localStorage.getItem("Citizen.tenant-id") || stateCode; - - const employeeInfo = window.localStorage.getItem("Employee.user-info"); - const employeeTenantId = window.localStorage.getItem("Employee.tenant-id"); - - const userTypeInfo = userType === "CITIZEN" || userType === "QACT" ? "citizen" : "employee"; - window.Digit.SessionStorage.set("user_type", userTypeInfo); - window.Digit.SessionStorage.set("userType", userTypeInfo); - - if (userType !== "CITIZEN") { - window.Digit.SessionStorage.set("User", { access_token: token, info: userType !== "CITIZEN" ? JSON.parse(employeeInfo) : citizenInfo }); - } else { - // if (!window.Digit.SessionStorage.get("User")?.extraRoleInfo) window.Digit.SessionStorage.set("User", { access_token: token, info: citizenInfo }); - } - - window.Digit.SessionStorage.set("Citizen.tenantId", citizenTenantId); - - if (employeeTenantId && employeeTenantId.length) window.Digit.SessionStorage.set("Employee.tenantId", employeeTenantId); -}; - -const initDigitUI = () => { - window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH") || "digit-ui"; - window.Digit.Customizations = { - commonUiConfig: UICustomizations, - }; - window?.Digit.ComponentRegistryService.setupRegistry({}); - - initMicroplanningComponents(); - - const moduleReducers = (initData) => initData; - - const stateCode = window?.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || "pb"; - initTokens(stateCode); - - ReactDOM.render( - , - document.getElementById("root") - ); -}; - -initLibraries().then(() => { - initDigitUI(); -}); diff --git a/frontend/microplan-ui/web/micro-ui-internals/example/src/setupProxy.js b/frontend/microplan-ui/web/micro-ui-internals/example/src/setupProxy.js deleted file mode 100644 index 5116edc0971..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/example/src/setupProxy.js +++ /dev/null @@ -1,100 +0,0 @@ -const { createProxyMiddleware } = require("http-proxy-middleware"); - -const createProxy = createProxyMiddleware({ - //target: process.env.REACT_APP_PROXY_API || "https://uat.digit.org", - // target: process.env.REACT_APP_PROXY_API || "https://qa.digit.org", - target: process.env.REACT_APP_PROXY_API || "https://works-dev.digit.org", - changeOrigin: true, - secure: false, -}); -const assetsProxy = createProxyMiddleware({ - target: process.env.REACT_APP_PROXY_ASSETS || "https://works-dev.digit.org", - changeOrigin: true, - secure: false, -}); -const mdmsProxy = createProxyMiddleware({ - target: process.env.REACT_APP_PROXY_ASSETS || "http://localhost:8080", - changeOrigin: true, - secure: false, -}); -module.exports = function (app) { - ["/mdms-v2/v2/_create"].forEach((location) => app.use(location, mdmsProxy)); - [ - "/access/v1/actions/mdms", - "/egov-mdms-service", - "/mdms-v2", - "/egov-idgen", - "/egov-location", - "/localization", - "/egov-workflow-v2", - "/pgr-services", - "/filestore", - "/egov-hrms", - "/user-otp", - "/user", - "/fsm", - "/billing-service", - "/collection-services", - "/pdf-service", - "/pg-service", - "/vehicle", - "/vendor", - "/property-services", - "/fsm-calculator/v1/billingSlab/_search", - "/pt-calculator-v2", - "/dashboard-analytics", - "/echallan-services", - "/egov-searcher/bill-genie/mcollectbills/_get", - "/egov-searcher/bill-genie/billswithaddranduser/_get", - "/egov-searcher/bill-genie/waterbills/_get", - "/egov-searcher/bill-genie/seweragebills/_get", - "/egov-pdf/download/UC/mcollect-challan", - "/egov-hrms/employees/_count", - "/tl-services/v1/_create", - "/tl-services/v1/_search", - "/egov-url-shortening/shortener", - "/inbox/v1/_search", - "/inbox/v2/_search", - "/tl-services", - "/tl-calculator", - "/org-services", - "/edcr", - "/bpa-services", - "/noc-services", - "/egov-user-event", - "/egov-document-uploader", - "/egov-pdf", - "/egov-survey-services", - "/ws-services", - "/sw-services", - "/ws-calculator", - "/sw-calculator/", - "/egov-searcher", - "/report", - "/inbox/v1/dss/_search", - "/loi-service", - "/project/v1/", - "/estimate-service", - "/loi-service", - "/works-inbox-service/v2/_search", - "/egov-pdf/download/WORKSESTIMATE/estimatepdf", - "/muster-roll", - "/individual", - "/mdms-v2", - "/hcm-moz-impl", - "/project", - "/project/staff/v1/_search", - "/project/v1/_search", - "/facility/v1/_search", - "/product/v1/_search", - "/product/variant/v1/_search", - "/hcm-bff/bulk/_transform", - "/hcm-bff/hcm/_processmicroplan", - "/health-hrms", - "/plan-service", - "/project-factory", - "/boundary-service" - ].forEach((location) => app.use(location, createProxy)); - ["/pb-egov-assets"].forEach((location) => app.use(location, assetsProxy)); - ["/mdms-v2/v2/_create"].forEach((location) => app.use(location, mdmsProxy)); -}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/package.json b/frontend/microplan-ui/web/micro-ui-internals/package.json deleted file mode 100644 index 2c382835952..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/package.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "egovernments", - "version": "1.0.0", - "main": "index.js", - "workspaces": [ - "example", - "packages/css", - "packages/modules/*" - ], - "author": "JaganKumar ", - "license": "MIT", - "private": true, - "engines": { - "node": ">=14" - }, - "scripts": { - "start": "SKIP_PREFLIGHT_CHECK=true run-s build start:dev", - "sprint": "SKIP_PREFLIGHT_CHECK=true run-s start:script", - "start:dev": "run-p dev:**", - "start:script": "./scripts/create.sh", - "dev:css": "cd packages/css && yarn start", - "publish:css": "cd packages/css && yarn && npm publish --tag workbench-1.0", - "dev:example": "cd example && yarn start", - "dev:hcm-microplanning": "cd packages/modules/hcm-microplanning && yarn start", - "build": "run-p build:**", - "build:hcm-microplanning": "cd packages/modules/hcm-microplanning && yarn build", - "deploy:jenkins": "./scripts/jenkins.sh", - "clean": "rm -rf node_modules" - }, - "resolutions": { - "**/@babel/runtime": "7.20.1", - "**/babel-preset-react-app": "10.0.0" - }, - "devDependencies": { - "husky": "7.0.4", - "lint-staged": "12.3.7", - "npm-run-all": "4.1.5", - "prettier": "2.1.2" - }, - "husky": {}, - "lint-staged": { - "*.{js,css,md}": "prettier --write" - }, - "dependencies": { - "lodash": "4.17.21", - "microbundle-crl": "0.13.11", - "@egovernments/digit-ui-react-components": "1.8.2-beta.1", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "react-router-dom": "5.3.0" - } -} diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/css/README.md b/frontend/microplan-ui/web/micro-ui-internals/packages/css/README.md deleted file mode 100644 index c2597b2240d..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/css/README.md +++ /dev/null @@ -1,57 +0,0 @@ - - -# digit-ui-css - -## Install - -```bash -npm install --save @egovernments/digit-ui-css -``` - -## Limitation - -```bash -This Package is more specific to DIGIT-UI's can be used across mission's -It is the base css for all Digit UI's -``` - -## Usage - -After adding the dependency make sure you have this dependency in - -```bash -frontend/micro-ui/web/package.json -``` - -```json -"@egovernments/digit-ui-css":"^1.5.0", -``` - -then navigate to App.js - -```bash -frontend/micro-ui/web/public/index.html -``` - -```jsx -/** add this import **/ - - - -``` -### Changelog - -```bash -1.0.0-microlan Base version - -``` -## Contributors - -[jagankumar-egov] [nipunarora-eGov] - -### Published from DIGIT Frontend -DIGIT Frontend Repo (https://github.com/egovernments/Digit-Frontend/tree/develop) - -## License - -MIT © [jagankumar-egov](https://github.com/jagankumar-egov) diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/css/gulpfile.js b/frontend/microplan-ui/web/micro-ui-internals/packages/css/gulpfile.js deleted file mode 100644 index 5d1a705494a..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/css/gulpfile.js +++ /dev/null @@ -1,71 +0,0 @@ -const fs = require("fs"); -const { name, version, author, cssConfig } = JSON.parse(fs.readFileSync("package.json")); - -const headerString = ` -@charset "UTF-8"; -/*! - * ${name} - ${version} - * - * Copyright (c) ${new Date().getFullYear()} ${author} - * - */ - `; -const { series, src, dest, watch, task } = require("gulp"); -const header = require("postcss-header"); - -const clean = require("gulp-clean"); -const postcss = require("gulp-postcss"); -const sass = require('gulp-sass'); - -const postcssPresetEnv = require("postcss-preset-env"); -const cleanCSS = require("gulp-clean-css"); -const rename = require("gulp-rename"); -const livereload = require("gulp-livereload"); - -let output = "./example"; -if (process.env.NODE_ENV === "production") { - output = "./dist"; -} - -function cleanStyles() { - return src(`${output}/*.css`, { read: false }).pipe(clean()); -} - -function styles() { - const plugins = [ - require("postcss-import"), - require("tailwindcss"), - postcssPresetEnv({ stage: 2, autoprefixer: { cascade: false }, features: { "custom-properties": true } }), - require("autoprefixer"), - require("cssnano"), - header({ header: headerString }), - ]; - return src("src/index.scss").pipe(postcss(plugins)).pipe(sass()).pipe(dest(output)); -} - -function minify() { - return src(`${output}/index.css`).pipe(cleanCSS()).pipe(rename(`index.min.css`)).pipe(dest(output)); -} - -function stylesLive() { - styles().pipe(livereload({ start: true })); -} - -function livereloadStyles() { - livereload.listen(); - watch("src/**/*.scss", series(stylesLive)); -} - -exports.styles = styles; -exports.default = series(styles); -exports.watch = livereloadStyles; -if (process.env.NODE_ENV === "production") { - exports.build = series(cleanStyles, styles, minify); -} else { - exports.build = series(styles, livereloadStyles); -} - -// gulp.task("watch:styles", function () { -// livereload.listen(); -// gulp.watch("**/*.scss", ["styles"]); -// }); diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/css/package.json b/frontend/microplan-ui/web/micro-ui-internals/packages/css/package.json deleted file mode 100644 index 00e571be8f6..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/css/package.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "name": "@egovernments/digit-ui-css", - "version": "1.0.42-microplan", - "license": "MIT", - "main": "dist/index.css", - "author": "Jagankumar ", - "engines": { - "node": ">=14" - }, - "cssConfig": { - "prefix": "" - }, - "scripts": { - "start": "gulp build", - "build:prod": "NODE_ENV=production gulp build", - "prepublish": "yarn build:prod", - "deploy": "gulp && cp -R svg example && cp -R img example && gh-pages -d example" - }, - "browserslist": [ - "> 3%", - "last 2 versions" - ], - "style": "./dist/index.css", - "dependencies": { - "node-sass": "4.14.1", - "normalize.css": "8.0.1", - "postcss-scss": "3.0.5", - "tailwindcss": "1.9.6" - }, - "devDependencies": { - "autoprefixer": "10.4.14", - "cssnano": "4.1.11", - "gh-pages": "3.2.3", - "gulp": "4.0.2", - "gulp-clean": "0.4.0", - "gulp-clean-css": "4.3.0", - "gulp-livereload": "4.0.2", - "gulp-postcss": "9.0.1", - "gulp-rename": "2.0.0", - "gulp-sass": "4.1.1", - "postcss": "8.4.26", - "postcss-cli": "8.3.1", - "postcss-header": "2.0.0", - "postcss-import": "12.0.1", - "postcss-prefixer": "2.1.3", - "postcss-preset-env": "6.7.1", - "postcss-scss": "3.0.5", - "sass": "^1.26.11" - }, - "files": [ - "dist/index.min.css", - "dist/index.css", - "svg/**/*.svg", - "img/**/*.png", - "src/**/*.scss", - "src/**/*.css" - ], - "keywords": [ - "digit", - "egov", - "dpg", - "digit-ui", - "css" - ] -} diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/css/postcss.config.js b/frontend/microplan-ui/web/micro-ui-internals/packages/css/postcss.config.js deleted file mode 100644 index 18485de221e..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/css/postcss.config.js +++ /dev/null @@ -1,55 +0,0 @@ -const postcssPresetEnv = require("postcss-preset-env"); - -module.exports = { - parser: require("postcss-scss"), - plugins: [ - require("postcss-import"), - require("postcss-nested").default, - require("tailwindcss"), - require("postcss-preset-env"), - require("autoprefixer"), - // require("cssnano"), - ], -}; - -// const fs = require('fs'); -// const { name, version, author, cssConfig } = JSON.parse(fs.readFileSync('package.json')); - -// const header = ` -// @charset "UTF-8"; -// /*! -// * ${name} - ${version} -// * -// * Copyright (c) ${new Date().getFullYear()} ${author.name} -// */ -// `; - -// module.exports = (ctx) => { -// const prefix = ctx.env === 'compat' ? '' : cssConfig.prefix; -// const devMessage = `🎉🎉🎉🎉 \n${name} ${ctx.env} build was compiled sucessfully! \n`; - - -// return { -// map: ctx.options.map, -// parser: ctx.options.parser, -// plugins: { -// 'postcss-import': { root: ctx.file.dirname }, -// 'postcss-prefixer': { -// prefix, -// ignore: [/\[class\*=.*\]/], -// }, -// 'postcss-preset-env': { -// autoprefixer: { -// cascade: false, -// }, -// features: { -// 'custom-properties': true, -// }, -// }, -// cssnano: ctx.env === 'production' || ctx.env === 'compat' ? {} : false, -// 'postcss-header': { -// header, -// }, -// }, -// }; -// }; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/css/src/components/coreOverride.scss b/frontend/microplan-ui/web/micro-ui-internals/packages/css/src/components/coreOverride.scss deleted file mode 100644 index 7d5d7126a8d..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/css/src/components/coreOverride.scss +++ /dev/null @@ -1,143 +0,0 @@ -.selector-button-border, -.digit-button-secondary { - h2, - .digit-button-label { - color: $primary-theme-color !important; - } - - background-color: white !important; -} - -.selector-button-primary { - background-color: $primary-theme-color !important; - box-shadow: inset 0 0 0 0 black !important; - - &:hover { - box-shadow: inset 0 -0.125rem 0 0 black !important; - } -} - -.jk-digit-primary-btn { - background-color: $primary-theme-color !important; - border-color: $primary-theme-color; - box-shadow: inset 0 0 0 0 black !important; - &:hover { - box-shadow: inset 0 -0.125rem 0 0 black !important; - } -} - -.jk-digit-secondary-btn { - h2 { - color: $primary-theme-color !important; - } -} - -.help-lable { - color: $primary-theme-color; -} - -.digit-header-content { - font-size: 2rem; -} - -.user-img-txt { - background-color: $primary-theme-color !important; -} - -.submit-bar { - background-color: $primary-theme-color !important; -} - -.bread-crumb--item a { - color: $primary-theme-color !important; -} - -.employeeCard, -.card-home .complaint-links-container .header { - .logo { - background-color: $primary-theme-color !important; - } - - .body { - .links-wrapper .link { - color: $primary-theme-color !important; - } - } -} - -.primary-label-btn { - color: $primary-theme-color !important; -} - -.language-button-container { - .customBtn-selected { - background-color: $primary-theme-color !important; - &:hover { - box-shadow: inset 0 -0.125rem 0 0 black; - } - } -} - -.digit-submit-bar { - box-shadow: inset 0 0 0 0 black !important; - &:hover { - box-shadow: inset 0 -0.125rem 0 0 black !important; - } -} - -.search-button-wrapper { - .link-label { - color: $primary-theme-color !important; - } -} - -.employee-card-input:hover, -employee-select-wrap--elipses:hover { - border-color: $primary-theme-color !important; -} - -.wbh-header, -.wbh-header-container { - margin: 0; -} - -.popup-module-action-bar .selector-button-border { - &:hover { - box-shadow: inset 0 -0.125rem 0 0 $primary-theme-color; - } -} -.search-button-wrapper button { - box-shadow: inset 0 0 0 0 black; - - &:hover { - box-shadow: inset 0 -0.125rem 0 0 black; - } -} - -.digit-home-moduleCardWrapper { - padding-left: 0; -} - -.digit-label-field-pair > div { - width: 100%; -} - -.jk-digit-secondary-btn { - box-shadow: inset 0 0 0 0 black; - - &:hover { - box-shadow: inset 0 -0.125rem 0 0 $primary-theme-color; - } -} - -.employee-select-wrap .select:hover { - border-color: $primary-theme-color !important; -} - -.digit-text-input-field .input-container:hover { - border-color: $primary-theme-color !important; -} - -.jk-digit-secondary-btn h2 { - font-weight: 550 !important; -} diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss b/frontend/microplan-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss deleted file mode 100644 index 8144c3f1563..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss +++ /dev/null @@ -1,2488 +0,0 @@ -$box-shadow-color: #00000029; -$border-color: rgba(214, 213, 212, 1); -$primary-theme-color: #c84c0e; -$border-color: rgba(214, 213, 212, 1); - -@mixin custom-scrollbar { - &::-webkit-scrollbar { - width: 0.625rem; - height: 0.625rem; - border: none; - } - - &::-webkit-scrollbar-track { - background: #ffffff; - border: none; - } - - &::-webkit-scrollbar-thumb { - background: rgba(177, 180, 182, 1); - border-radius: 0.625rem; - border: 0.125rem solid #f0f0f0; - } - - &::-webkit-scrollbar-thumb:hover { - background: rgba(177, 180, 182, 0.8); - } -} - -@mixin select-dropdown { - background-color: rgb(0, 0, 0, 0); - font-family: Roboto; - font-size: 1rem; - font-weight: 400; - text-align: left; -} - -.help-label { - color: $primary-theme-color; -} - -.guideline-actionbar-content { - display: flex; - flex-direction: row; - justify-content: end; - - .custom-button { - min-width: 12.5rem; - display: flex; - justify-content: center; - align-items: center; - - h2 { - width: fit-content !important; - } - - .icon { - margin: 0 0 0 1rem !important; - } - } - - .custom-button-left-icon { - .icon { - margin: 0 1rem 0 0 !important; - } - } -} - -.navigator-componet-not-found { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - padding: 2rem; - font-weight: 700; - font-size: 2rem; - color: rgb(0, 0, 0); -} - -.api-data-loader { - width: 100% !important; - height: 100% !important; - display: flex !important; - align-items: center !important; - justify-content: center !important; -} - -.modal-header { - padding-left: 1rem !important; - margin-bottom: 0 !important; - display: flex !important; - flex-wrap: wrap !important; - overflow: hidden !important; - - p { - padding: 0 !important; - margin: 0 !important; - } -} - -.modal-body { - overflow: hidden; - padding-left: 1rem; - padding-right: 1rem; - margin-bottom: 1rem; - margin-right: 1rem; - - p { - font-weight: 400; - font-size: 1rem; - } -} - -.non-editable-component { - pointer-events: none !important; -} - -.button-type-1 { - display: flex !important; - justify-content: center !important; - align-items: center !important; - padding: 0.625rem 0.5rem 0.625rem 0.5rem !important; - margin: 0 !important; - height: 2.5rem !important; - - p { - font-weight: 600 !important; - font-size: 1rem !important; - margin: 0 !important; - padding: 0 !important; - } -} - -.button-type-2 { - display: flex !important; - justify-content: center !important; - padding: 0.625rem 0.5rem 0.625rem 0.5rem !important; - margin: 0 !important; - align-items: center !important; - height: 2.5rem !important; - - .icon { - display: flex !important; - align-items: center !important; - margin: 0 !important; - padding: 0 !important; - } - - p { - font-weight: 600 !important; - font-size: 1rem !important; - margin: 0 !important; - padding: 0 !important; - } -} - -.microplan-close-button { - margin: 0.5rem 0.5rem 0 0; - align-self: flex-start; - border: none; - color: inherit; - cursor: pointer; - overflow: visible; - background-color: #00000000; -} - -.microplan-naming-conventions { - display: flex; - flex-direction: column; - .microplan-naming-convention-instruction-list-container { - margin-left: 0.3rem; - display: flex; - align-items: flex-start; - - .number { - min-width: 1.2rem !important; - } - } - .microplan-naming-convention-instruction-list { - font-family: Roboto; - font-size: 1rem; - font-weight: 400; - text-align: left; - padding: 0; - margin: 0; - line-height: 1.5rem; - } - .microplan-naming-conventions-heading { - font-family: Roboto; - font-size: 1.2rem; - font-weight: 500; - text-align: left; - padding: 0; - margin: 1rem 0 0 0; - } -} - -.upload-section { - font-family: Roboto; - - .upload-component-wrapper { - width: 100%; - /* - @media (min-width: 68.75rem) { - padding-right: 4rem; - } - */ - } - - .upload { - display: flex; - width: 100%; - justify-content: space-between; - margin-top: 1.25rem; - } - - .upload-section-option { - position: relative; - right: -1.68rem; - width: 12.7rem; - min-height: 32rem; - background-color: #ffffff; - border-top-left-radius: 0.5rem; - border-bottom-left-radius: 0.5rem; - box-shadow: 0 0.063rem 0.125rem 0 $box-shadow-color; - } - - .upload-section-options-active, - .upload-section-options-inactive { - min-height: 3.7rem; - display: flex; - align-items: center; - border-bottom: 0.063rem $border-color solid; - cursor: pointer; - - p { - margin-left: 0.5rem; - color: rgba(80, 90, 95, 1); - font-weight: 400; - font-size: 1rem; - } - - .icon { - display: flex; - flex-direction: row; - align-items: center; - justify-content: center !important; - overflow: visible; - padding: 0; - margin-left: 0.625rem; - width: 1.875rem; - height: 2.188rem; - } - .end { - position: absolute; - right: 0.5rem; - justify-self: end; - } - } - - .upload-section-options-active:first-child, - .upload-section-options-inactive:first-child { - border-top-left-radius: 0.5rem; - } - - .upload-section-options-active { - border-right: 0.3rem solid $primary-theme-color; - background-color: rgba(244, 119, 56, 0.12); - - p { - font-weight: 700; - } - } - - .upload-section-options-inactive { - border-right: none; - background-color: rgba(255, 255, 255, 1); - } - - .upload-component { - height: min-content; - border-radius: 0.25rem; - padding: 1.5rem; - background-color: rgba(255, 255, 255, 1); - margin: 0; - margin-right: 0.3rem; - padding-bottom: 0.625rem; - } - - .upload-component-active { - display: flex; - flex-direction: column; - margin-bottom: 0; - - .greyedout-name { - color: rgba(177, 180, 182, 1); - margin: 0 0.625rem; - font-size: 1.25rem; - padding-top: 0; - font-weight: 500; - } - - .h2-class { - margin: 0; - padding: 0; - width: 90% !important; - overflow: hidden; - font-size: 2.5rem; - font-weight: 700; - } - - p { - margin: 0.625rem 0; - padding-top: 0.625rem; - font-size: 1rem; - margin-top: 0.625rem; - font-weight: 400; - } - - .heading { - display: flex; - justify-content: space-between; - align-items: start; - - h2 { - width: 90% !important; - } - - .download-template-button { - display: flex !important; - padding-left: 0.625rem; - justify-content: center !important; - align-items: center !important; - min-width: 13.5rem; - height: 2.5rem; - border: 0.063rem $primary-theme-color solid; - background-color: #f1f1f100; - &:hover { - box-shadow: inset 0 -0.125rem 0 0 $primary-theme-color; - } - .icon { - display: flex; - align-items: center; - margin: 0; - padding: 0; - } - - p { - padding: 0; - margin: 0; - color: $primary-theme-color; - font-weight: 600; - font-size: 1rem; - } - } - } - } - - .upload-component-inactive { - display: none; - } - - .upload-option-container { - display: flex; - align-items: center; - justify-content: center; - padding: 1.25rem 0; - flex-wrap: wrap; - - .upload-option-container-selected { - border: 0.125rem $primary-theme-color solid; - color: $primary-theme-color; - } - } - - .upload-option { - border-radius: 0.25rem; - border: 0.0625rem rgba(214, 213, 212, 1) solid; - min-width: 12.5rem; - min-height: 8.75rem; - box-shadow: 0 0.0625rem rgba(0, 0, 0, 0.16); - padding: 0.625rem 0; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - justify-items: center; - margin: 0 1.25rem; - cursor: pointer; - - p { - margin-top: 0.625rem; - font-weight: 600; - color: rgba(80, 90, 95, 1); - } - - .label:hover { - color: $primary-theme-color; - } - - &:hover { - outline: 0.125rem $primary-theme-color solid; - } - - .upload-option-selected { - border: 0.125rem $primary-theme-color solid; - color: $primary-theme-color; - } - - .select-button { - justify-self: end; - border: 0.063rem solid $primary-theme-color; - background-color: rgba(255, 255, 255, 1); - width: 11rem; - height: 2.5rem; - justify-content: center; - color: $primary-theme-color; - font-size: 1rem; - font-weight: 600; - - &:hover { - box-shadow: inset 0 -0.125rem 0 0 $primary-theme-color; - } - } - - .selected-button { - display: flex; - flex-direction: row; - align-items: center !important; - justify-self: end; - justify-content: center; - border: 0.063rem solid $primary-theme-color; - background-color: $primary-theme-color; - width: 11rem; - height: 2.5rem; - padding: 0.6rem 0.5rem; - color: rgb(255, 255, 255); - font-size: 1rem; - font-weight: 600; - } - } - - .upload-file { - min-height: 10rem; - padding-top: 0.625; - border: 0.063rem $border-color; - margin: 1rem 0; - display: flex !important; - flex-direction: column; - align-items: center !important; - justify-content: center !important; - background-color: rgba(250, 250, 250, 255); - border: 0.063rem dotted rgba(214, 213, 212, 1); - - .browse-text-wrapper { - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - width: fit-content; - margin: 0; - padding: 0; - - .browse-text { - margin: 0; - padding: 0; - color: $primary-theme-color; - text-decoration: underline; - cursor: pointer; - } - } - - .flex { - display: flex; - } - } - - .uploaded-file { - border: 0.063rem solid $border-color; - min-height: 4.75rem; - background-color: rgb(250, 250, 250); - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - margin-top: 0.625rem; - margin-bottom: 0.625rem; - padding: 0 0.625rem; - flex-wrap: wrap !important; - - .uploaded-file-details { - display: flex !important; - flex-direction: row; - align-items: center !important; - flex-wrap: wrap; - padding: 1rem 0; - - p { - padding: 0; - margin: 0; - height: min-content; - font-weight: 700; - font-size: 1.5rem; - color: rgba(80, 90, 95, 1); - text-align: start; - } - } - - .uploaded-file-operations { - display: flex !important; - align-items: center; - justify-items: end; - flex-wrap: wrap; - - .button { - display: flex !important; - flex-direction: row; - align-items: center; - justify-content: center; - margin-left: 1rem; - min-width: 9rem; - height: 2.5rem; - border: 0.063rem $primary-theme-color solid; - background-color: white; - cursor: pointer; - &:hover { - box-shadow: inset 0 -0.125rem 0 0 $primary-theme-color; - } - } - - p { - padding: 0; - margin: 0; - margin-left: 0.5rem; - color: $primary-theme-color; - font-weight: 600; - font-size: 1rem; - } - - .delete-button { - background-color: rgb(255, 255, 255, 0); - border: none; - display: flex !important; - flex-direction: row; - align-items: center !important; - justify-content: center; - margin: 0 1rem; - cursor: pointer; - } - } - } - - .message { - margin-right: 0.6px; - } - - .download-template-button { - display: flex !important; - justify-content: center; - padding: 0; - margin: 0; - &:hover { - box-shadow: inset 0 -0.125rem 0 0 $primary-theme-color; - } - .icon { - display: flex; - align-items: center; - margin: 0; - padding: 0; - } - - p { - font-weight: 500; - font-size: 1rem; - margin: 0; - padding: 0; - } - } - - .file-upload-error-container { - display: flex; - flex-direction: column; - .link-wrapper { - padding-top: 1rem; - display: flex; - flex-direction: row; - margin: 0; - padding: 0; - - .link { - color: $primary-theme-color !important; - text-decoration: underline; - cursor: pointer; - } - } - p { - padding: 0; - margin: 0; - } - } - - .spatial-data-property-mapping { - width: calc(100%-2rem); - padding: 1rem; - max-height: 30rem; - padding-top: 0; - margin: 1rem; - border: 0.063rem rgba(0, 0, 0, 0.16) solid; - box-shadow: 0rem 0.063rem 0.125rem 0rem rgba(0, 0, 0, 0.16); - border-radius: 0.25rem; - background-color: rgba(250, 250, 250) !important; - display: block; - overflow: auto; - padding-bottom: 0; - position: relative; - - @include select-dropdown; - - table { - background-color: rgb(0, 0, 0, 0) !important; - width: 100%; - border-collapse: collapse; - - .select-dropdown { - background-color: rgb(0, 0, 0, 0); - font-family: Roboto; - font-size: 1rem; - font-weight: 400; - text-align: left; - } - - thead { - position: sticky !important; - z-index: 100; - top: 0; - background-color: rgba(250, 250, 250); - padding: 0; - } - - th { - width: 50%; - font-weight: 700; - font-size: 1rem; - padding: 1.5rem; - margin: 0; - text-align: left; - border-bottom: 0.063rem solid rgba(214, 213, 212, 1); - } - - td { - width: 50%; - font-weight: 400; - font-size: 1rem; - padding: 1.5rem; - margin: 0; - border-top: 0 !important; - border-bottom: 0.063rem solid rgba(214, 213, 212, 1); - - p { - max-width: 20.594rem; - font-weight: 700; - font-size: 1rem; - text-wrap: wrap; - overflow: hidden; - } - } - } - - .pagination { - position: sticky; - bottom: 0; - left: 0; - background-color: rgba(250, 250, 250, 255); - display: flex; - flex-direction: row; - align-items: center; - justify-content: end; - padding: 1rem 0; - padding-right: 2rem; - z-index: 10; - background-color: rgba(250, 250, 250); - } - - @include custom-scrollbar; - - &::-webkit-scrollbar-track { - background-color: rgb(0, 0, 0, 0); - } - } - - .popup-wrap { - background-color: rgba(0, 0, 0, 0.8); - } - - .preview-data { - margin: 0 2.5rem; - width: calc(100% - 5rem); - border-radius: 0.25rem; - - .operational-buttons { - display: flex; - justify-content: space-between; - margin-top: 1.5rem; - margin-bottom: 1.5rem; - } - - .excel-wrapper { - width: 100%; - padding: 1rem 0.5rem 0 0.5rem; - display: flex; - flex-direction: column; - gap: 0.5rem; - background-color: white !important; - border: 0.063rem rgba(0, 0, 0, 0.16) solid !important; - border-radius: 0.25rem; - - .error-user-directions { - margin: 0rem 0.5rem; - padding: 0; - color: $primary-theme-color; - } - - .sheet-wrapper { - height: 76vh; - overflow: auto; - background-color: white; - padding: 0.3rem; - - @include custom-scrollbar; - - h3 { - background-color: #f4f4f4; - padding: 0.625rem; - margin: 0; - } - - .excel-table { - width: 100%; - border: 0.063rem solid #ccc; - border-collapse: collapse; - - th, - td { - min-width: 7.578rem; - border: 0.063rem solid #ccc; - padding: 8px; - font-family: Arial, sans-serif; - font-size: 0.875rem; - height: 100%; - outline-offset: -0.07rem; - box-sizing: border-box; - position: relative; - - .edited-row-marker { - width: 0.313rem; - position: absolute; - top: -0.045rem; - left: -0.313rem; - padding: 0; - margin: 0; - height: calc(100% + 0.09rem); - border-top-left-radius: 0.125rem; - border-bottom-left-radius: 0.125rem; - background-color: $primary-theme-color !important; - } - } - - th { - background-color: #f4f4f4; - font-weight: bold; - text-align: left; - vertical-align: top; - } - } - } - - .excel-tab-list { - padding: 0.3rem; - display: flex; - margin-bottom: 0.625rem; - - .tab { - padding: 0.625rem; - margin-right: 0.313rem; - cursor: pointer; - outline: none !important; - background-color: #f1f1f1; - } - - .tab.active { - outline: none !important; - border: 0.25rem solid; - border-color: #000000 !important; - } - } - } - } - - .information-description { - p { - display: flex; - flex-direction: row; - color: rgba(80, 90, 95, 1); - font-family: Roboto; - font-size: 1rem; - font-weight: 400; - line-height: 1.172rem; - text-align: left; - } - - .link-wrapper { - padding-top: 1rem; - display: flex; - flex-direction: row; - margin: 0; - padding: 0; - - .link { - color: rgba(52, 152, 219, 1) !important; - text-decoration: underline; - cursor: pointer; - } - } - } - - .guidelines { - padding: 0.8rem 2rem 0 2rem; - - .sub-heading { - font-family: Roboto; - font-size: 1.5rem; - font-weight: 700; - line-height: 1.7rem; - text-align: left; - padding: 0; - margin: 0; - } - - .padtop { - margin-top: 1rem; - } - - .instruction-list { - font-family: Roboto; - font-size: 1rem; - font-weight: 400; - text-align: left; - padding: 0; - margin: 0; - line-height: 1.5rem; - - .link { - text-decoration: underline; - color: $primary-theme-color; - } - } - - .instruction-list-container { - margin-left: 0.3rem; - display: flex; - align-items: flex-start; - - .number { - min-width: 1.2rem !important; - } - } - - .flex { - display: flex; - } - } - - .upload-guidelines-header { - width: 100%; - font-size: 2.5rem; - padding-left: 2rem; - } -} - -.hypothesis-section { - font-family: Roboto; - display: flex; - flex-direction: column; - justify-content: start; - width: 100%; - background-color: rgb(255, 255, 255); - padding: 1.5rem; - margin-top: 1.3rem; - height: 33.5rem; - border-radius: 0.25rem; - box-shadow: 0 0.063rem 0.125rem 0 rgba(0, 0, 0, 0.16); - - input[type="number"]:focus, - input[type="number"]:hover { - border: 0.063rem solid $primary-theme-color; - outline: none; - } - - .heading { - padding: 0 0 0.5rem 0; - margin: 0; - font-family: Roboto Condensed; - font-size: 2.5rem; - font-weight: 700; - color: rgba(11, 12, 12, 1); - } - - .instruction { - margin: 0.8rem 0 1.2rem 0; - padding: 0; - font-size: 1rem; - font-weight: 400; - text-align: left; - } - - .user-input-section { - display: block; - overflow-y: scroll; - height: 21rem; - position: relative; - - @include custom-scrollbar; - - .example { - border: 0.063rem solid rgba(214, 213, 212, 1); - background-color: rgb(250, 250, 250); - padding: 1rem 1rem; - border-radius: 0.25rem; - max-width: 50rem; - overflow: hidden; - - @media (max-width: 104rem) { - max-width: 46.5rem; - } - - @media (max-width: 80rem) { - max-width: 46.55rem; - } - - .heading { - padding: 0.2rem 0; - margin: 0; - font-size: 1rem; - font-weight: 700; - } - - .example-body { - display: flex; - opacity: 0.6; - - p { - font-weight: 400; - } - } - - .key { - width: 22rem; - - @media (max-width: 48rem) { - width: 60%; - } - } - - .value { - margin-left: 9%; - - @media (max-width: 104rem) { - margin-left: 7%; - } - - .heading { - display: flex; - text-wrap: wrap; - } - - input { - width: 7.5rem; - } - - @media (min-width: 60rem) { - width: fit-content; - } - - @media (max-width: 48rem) { - margin-left: 1rem; - } - } - } - - .heading { - padding: 0.1rem 0; - margin: 0; - font-family: Roboto; - font-size: 1rem; - font-weight: 400; - text-align: left; - } - - .interactable-section { - padding-top: 1.5rem; - width: 41.5rem; - display: flex; - flex-wrap: wrap; - position: relative; - - @media (max-width: 48rem) { - width: 95%; - } - - .heading { - padding: 0; - font-weight: 700; - } - - .select-and-input-wrapper { - margin-top: 1.5rem !important; - } - - .select-and-input-wrapper:first-child { - margin-top: 0.8rem !important; - } - } - - .key { - width: 22.75rem; - position: relative; - - @media (max-width: 48rem) { - width: 60%; - } - - .select-dropdown { - @include select-dropdown; - } - } - - .value { - margin-left: 10%; - width: 7.5rem; - - @media (max-width: 48rem) { - margin-left: 1rem; - } - } - - .select-and-input-wrapper { - margin-top: 1rem; - width: 100%; - display: flex; - align-items: center; - position: relative; - } - - .select-and-input-wrapper-first { - margin-top: 0; - width: 100%; - display: flex; - align-items: center; - position: relative; - } - - .headerbar { - padding: 0; - width: 100%; - display: flex; - align-items: center; - margin: 0; - position: sticky; - top: 0; - background-color: rgb(255, 255, 255); - z-index: 100; - padding-bottom: 0.8rem; - } - - .invisible { - visibility: hidden; - pointer-events: none; - padding: 0; - margin: 0; - } - - .input { - appearance: none; - -webkit-appearance: none; - -moz-appearance: none; - width: 100%; - border: 0.063rem solid rgb(255, 255, 255); - background-color: rgb(255, 255, 255, 0); - padding: 0.5rem; - font-weight: 400; - line-height: 1.1rem; - font-size: 1rem; - } - } - - .delete-button { - max-width: 12.5rem; - margin: 0 0 0 1rem; - display: flex; - align-items: center; - justify-content: center; - background: rgba(255, 255, 255, 1); - - p { - margin: 0; - padding: 0 0 0 0.5rem; - font-size: 1rem; - font-weight: 600; - color: $primary-theme-color; - text-align: left; - } - } - - .add-button-help { - margin-top: 1.5rem; - max-width: 15.5rem; - } - - .add-button { - max-width: 12.5rem; - height: 2.5rem; - display: flex; - align-items: center; - justify-content: center !important; - background: rgba(255, 255, 255, 1); - border: 0.063rem solid $primary-theme-color; - - h2 { - color: $primary-theme-color; - padding: 0 0 0 0.6rem; - margin: 0; - font-size: 1.188rem; - width: fit-content !important; - font-weight: 600; - text-align: center; - } - } -} - -.rule-engine-section { - display: flex; - flex-direction: column; - margin-top: 1.3rem; - - .rule-engine-body { - font-family: Roboto; - display: flex; - flex-direction: column; - justify-content: start; - width: 100%; - background-color: rgb(255, 255, 255); - padding: 1.5rem; - height: 33.5rem; - box-shadow: 0 0.063rem 0.125rem 0 rgba(0, 0, 0, 0.16); - border-radius: 0.25rem; - - .heading { - padding: 0 0 0.5rem 0; - margin: 0; - font-family: Roboto Condensed; - font-size: 2.5rem; - font-weight: 700; - color: rgba(11, 12, 12, 1); - } - - .instruction { - margin: 0.8rem 0 1.2rem 0; - padding: 0; - font-size: 1rem; - font-weight: 400; - text-align: left; - } - - .user-input-section { - display: block; - overflow-y: scroll; - padding-bottom: 1rem; - height: 21rem; - - @include custom-scrollbar; - .example-wrapper { - display: flex; - align-items: center; - width: 100%; - .example { - border: 0.063rem solid rgba(214, 213, 212, 1); - background-color: rgb(250, 250, 250); - padding: 1rem 0.7rem; - overflow: hidden; - - .heading { - padding: 0.2rem 0; - margin: 0; - font-size: 1rem; - font-weight: 700; - line-height: 18.75px; - } - - .example-body { - display: flex; - /*flex-wrap: wrap;*/ - opacity: 0.6; - - p { - font-weight: 400; - } - } - .value { - width: 22.05rem; - } - - /* - .value-input-key { - width: 22rem; - overflow: hidden; - - @media (max-width: 48rem) { - width: 60%; - } - } - - .select-dropdown { - @include select-dropdown; - } - - .operator { - margin-left: 10%; - overflow: hidden; - width: 10rem; - margin: 0 1rem; - - @media (max-width: 48rem) { - margin-left: 1rem; - } - }*/ - } - .delete-button { - margin: 0 0 0 0.244rem; - } - } - - .heading { - padding: 0.1rem 0; - margin: 0; - font-family: Roboto; - font-size: 1rem; - font-weight: 400; - text-align: left; - } - - .interactable-section { - padding-top: 1.5rem; - display: flex; - flex-wrap: wrap; - - @media (max-width: 48rem) { - width: 95%; - } - - .heading { - padding: 0; - font-weight: 700; - } - } - - .value-input-key { - width: 22.75rem; - position: relative; - - @media (max-width: 48rem) { - width: 60%; - } - } - - .operator { - margin-left: 10%; - position: relative; - width: 11rem; - margin: 0 1rem; - - @media (max-width: 48rem) { - margin-left: 1rem; - } - } - - .select-dropdown { - @include select-dropdown; - } - - .equal-to-icon { - margin: 0 3%; - font-family: Roboto Condensed; - font-size: 2.5rem; - font-weight: 700; - } - - .select-and-input-wrapper { - margin-top: 1rem; - width: 100%; - display: flex; - align-items: center; - } - - .select-and-input-wrapper-first { - margin-top: 0rem; - width: 100%; - display: flex; - align-items: center; - } - - .user-input-wrapper { - width: 100%; - } - } - - .headerbar { - padding: 0; - width: 100%; - display: flex; - align-items: center; - margin: 0; - position: sticky; - top: 0; - background-color: rgb(255, 255, 255); - z-index: 100; - } - - .invisible { - visibility: hidden; - pointer-events: none; - } - - .delete-button { - max-width: 12.5rem; - margin: 0 0 0 1rem; - display: flex; - align-items: center; - justify-content: center; - background: rgba(255, 255, 255, 1); - - p { - text-align: center; - margin: 0; - padding: 0 0 0 0.5rem; - font-size: 1rem; - font-weight: 600; - color: $primary-theme-color; - text-align: left; - } - } - - .add-button-help { - margin-top: 1.5rem; - max-width: 15.5rem; - } - - .add-button { - max-width: 12.5rem; - height: 2.5rem; - display: flex; - align-items: center; - justify-content: center !important; - background: rgba(255, 255, 255, 1); - border: 0.063rem solid $primary-theme-color; - - h2 { - color: $primary-theme-color; - padding: 0 0 0 0.6rem; - margin: 0; - font-size: 1.188rem; - width: fit-content !important; - font-weight: 600; - text-align: center; - } - } - } -} - -.create-microplan { - .custom-action-bar, - .custom-action-bar-no-first-button { - height: 4rem; - display: flex !important; - justify-content: space-between; - align-items: center !important; - - .custom-button { - min-width: 12.5rem; - display: flex; - justify-content: center; - align-items: center; - - h2 { - font-weight: 600; - width: fit-content !important; - } - - .icon { - margin: 0 0 0 1rem !important; - } - } - - .custom-button-left-icon { - margin-left: 5.3rem; - padding-left: 0.7rem !important; - border-color: $primary-theme-color; - &:hover { - box-shadow: inset 0 -0.125rem 0 0 $primary-theme-color; - } - .icon { - margin: 0 1rem 0 0 !important; - } - } - - .custom-button-right-icon { - box-shadow: inset 0 0 0 0 black; - padding-left: 0.39rem !important; - padding-right: 0.355rem !important; - - &:hover { - box-shadow: inset 0 -0.125rem 0 0 black; - } - } - } - - .custom-action-bar-no-first-button { - justify-content: end; - } -} - -.mapping-section { - width: 100%; - display: flex; - flex-direction: column; - - .heading { - width: 100%; - margin: 1.5rem 0 1.5rem 0; - padding: 0 0 0 1rem; - font-family: Roboto Condensed; - font-size: 2.5rem; - font-weight: 700; - } - - .mapping-body-container { - display: flex; - border: 0; - box-shadow: none; - margin: 1rem; - - .filter-container { - padding: 1.5rem; - box-shadow: 0px 0.063rem 0.125rem 0px rgba(0, 0, 0, 0.16); - background: rgba(255, 255, 255, 1); - max-width: 17.5rem; - min-height: 34rem; - margin-right: 1rem; - - p { - font-family: Roboto; - font-size: 1rem; - font-weight: 400; - padding: 0; - margin: 0; - overflow: hidden; - text-wrap: wrap; - } - - .filter-heading { - font-family: Roboto; - font-size: 1.5rem; - font-weight: 700; - padding: 0; - margin: 0; - overflow: hidden; - text-wrap: wrap; - } - - .instructions { - margin: 1.5rem 0; - } - - .dropdown { - padding: 0.5rem 0 0 0; - width: 100%; - } - - .filter-controllers { - display: flex !important; - justify-content: space-between; - padding: 1rem 0 0 0; - - .button-primary, - .button-secondary { - font-family: Roboto; - font-size: 1.188rem; - font-weight: 600; - max-width: 6.75rem; - min-height: 2.5rem; - padding: 0; - display: flex; - align-items: center; - justify-content: center; - } - } - } - - .map-container { - width: 100%; - min-height: 34rem; - background: rgba(255, 255, 255, 1); - box-shadow: 0px 0.063rem 0.125rem 0px rgba(0, 0, 0, 0.16); - display: flex; - flex-direction: row; - position: relative; - margin: 0; - padding: 1rem 0 0 0; - - #map, - .map { - height: 100%; - z-index: 20; - border-radius: 0.25rem; - } - - .height-control { - max-height: 10rem !important; - } - - .filter-by-boundary { - position: absolute; - top: 1rem; - left: 0rem; - padding: 1rem; - z-index: 550; - height: 100%; - max-height: 32rem; - background-color: rbg(0, 0, 0, 1); - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - overflow: visible; - - .button-primary { - padding-left: 0; - padding-right: 0; - - div { - align-items: center; - justify-content: center !important; - width: 13.938rem; - - h2 { - width: fit-content; - } - } - } - - .display-none { - display: none !important; - } - - .boundary-selection { - display: block; - min-width: 16.5rem; - margin: 0.5rem 0 0 0 !important; - /*padding: 1rem 0.7rem 1rem 1rem;*/ - padding: 1rem 0rem 1rem 0rem; - background: rgba(255, 255, 255, 1) !important; - box-shadow: 0 0.063rem 0.25rem 0 rgba(0, 0, 0, 0.16); - position: relative; - overflow: visible; - - .digit-multiselectdropdown-label { - p { - color: rgba(177, 180, 182, 1); - } - } - - .header-section { - display: flex !important; - align-items: center; - gap: 0.5rem; - padding: 0; - margin-right: 1rem; - margin-left: 1rem; - } - - .hierarchy-selection-container { - position: relative; - overflow-x: hidden; - overflow-y: auto; - max-height: 24rem; - display: flex; - flex-direction: column; - margin: 0; - padding-left: 1rem; - padding-right: 1rem; - - @include custom-scrollbar; - - .hierarchy-selection-element { - position: relative; - padding-top: 1rem; - } - } - .scrollable { - padding-right: 0.2rem; - margin-right: 0.2rem; - } - } - } - - .bottom-left-map-subcomponents { - position: absolute; - bottom: 1rem; - left: 1rem; - z-index: 500; - - .custom-scale { - width: 7.5rem; - margin-left: 0.5rem; - text-align: center; - border-bottom: 0.063rem solid #ccc; - padding: 0 0; - color: #ffffff; - font-family: Roboto; - font-size: 0.75rem; - font-weight: 400; - position: relative; - - .border-spikes { - position: absolute; - bottom: 0; - left: 0; - width: 100%; - height: 20%; - border-left: 0.063rem solid #ccc; - border-right: 0.063rem solid #ccc; - } - } - } - - .zoom-container { - width: fit-content; - - .zoom-control { - display: flex !important; - flex-direction: column; - align-items: center; - margin-bottom: 1.3rem; - } - - .zoom-button { - border: 0.125rem solid rgba(214, 213, 212, 1); - border-radius: 0.063rem; - width: 2rem; - height: 2rem; - text-align: center; - color: $primary-theme-color; - background-color: rgb(255, 255, 255); - cursor: pointer; - font-family: Roboto; - font-size: 1.125rem; - font-weight: 700; - box-shadow: 0 0.063rem 0.125rem 0 rgba(0, 0, 0, 0.16); - } - } - - .north-arrow { - margin-left: 0.5rem; - } - - .bottom-right-map-subcomponents { - position: absolute; - bottom: 2rem; - right: 1rem; - z-index: 500; - display: flex !important; - flex-direction: column; - align-items: end; - gap: 1rem; - - @media (max-width: 62.188rem) { - bottom: 3rem; - } - - .filter-index { - background-color: rgba(255, 255, 255, 1); - border: 0.063rem solid rgba(214, 213, 212, 1); - border-radius: 0.25rem; - padding: 0.7rem; - padding-top: 0.3rem; - width: 8.5rem; - max-height: 8.5rem; - overflow-y: auto; - - @include custom-scrollbar; - - .filter-row { - display: flex !important; - flex-direction: row; - align-items: center; - width: 6.813rem; - min-height: 1.5rem; - padding-top: 0.4rem; - - p { - margin: 0 0 0 0.4rem; - padding: 0; - font-family: Roboto; - font-size: 0.75rem; - font-weight: 400; - text-align: left; - text-wrap: wrap; - } - } - } - - .choropleth-index { - width: 20.292rem; - /*height: 4.438rem;*/ - - @media (max-width: 20.292rem) { - width: 50%; - } - - border-radius: 0.25rem; - background-color: rgba(250, 250, 250, 1); - padding: 0.8rem; - - p { - font-family: Roboto; - font-size: 1rem; - font-weight: 700; - text-align: left; - padding: unset; - margin: unset; - } - - .label { - width: 100%; - padding-top: 0.3rem; - text-align: center; - } - - .gradient-wrapper { - width: 100%; - display: flex !important; - justify-content: center; - align-items: center; - - p { - padding: 0 0.5rem; - } - - .gradient { - width: 80%; - height: 0.875rem; - } - } - } - } - - .top-right-map-subcomponents { - position: absolute; - top: 1.5rem; - right: 1.5rem; - z-index: 550; - flex-direction: column; - align-items: flex-end !important; - } - - .filter-section, - .choropleth-section { - width: 14.438rem; - display: flex !important; - flex-direction: column; - margin-top: 1.5rem !important; - .icon-rest { - display: flex !important; - align-items: center; - width: fit-content; - align-self: flex-end; - justify-content: flex-end; - cursor: pointer; - - p { - margin: 0; - padding: 0; - font-family: Roboto; - font-size: 1rem; - font-weight: 400; - color: rgba(255, 255, 255, 1); - } - - .icon { - margin-left: 0.3rem; - height: 1.667rem; - } - } - .filter-section-option-wrapper, - .choropleth-section-option-wrapper { - position: absolute; - margin-top: 2rem; - max-height: 12.19rem; - width: 14.438rem; - - .custom-box-wrapper { - display: block; - max-height: 9.752rem; - overflow-x: auto; - background-color: rgba(255, 255, 255, 1); - - @include custom-scrollbar; - - .custom-box { - padding: 0.7rem; - border-bottom: 0.063rem solid rgba(214, 213, 212, 1); - - .mainClassName { - margin-bottom: 0; - display: flex; - align-items: center; - } - - .inputWrapperClassName { - margin: 0; - padding: 0; - } - - .labelClassName { - margin: 0; - margin-right: auto; - } - - input:checked ~ .inputIconClassname { - border-color: $primary-theme-color; - } - - .inputIconClassname { - margin: 0; - } - - .inputClassName { - margin: 0; - } - } - } - } - } - .choropleth-section-option-wrapper { - .button-primary { - background-color: rgba(250, 250, 250, 1) !important; - } - } - .choropleth-section-option-wrapper .custom-box-wrapper { - .radio-option-container { - padding: 0.7rem; - margin: 0; - width: 100%; - border-bottom: 0.063rem solid rgba(214, 213, 212, 1); - } - .custom-box { - padding: 0 !important; - margin: 0; - border-bottom: none; - } - } - .base-map-selector { - display: flex !important; - flex-direction: column; - align-items: flex-end !important; - position: relative; - border-radius: 0.25rem; - - .icon-first { - display: flex !important; - align-items: center; - margin-top: 0; - cursor: pointer; - box-shadow: none; - - p { - margin: 0; - padding: 0; - font-family: Roboto; - font-size: 1rem; - font-weight: 400; - color: rgba(255, 255, 255, 1); - } - - .icon { - margin-left: 0.3rem; - height: 1.667rem; - } - } - - .base-map-area-wrapper { - position: absolute; - top: 2rem; - max-width: 27.5rem; - max-height: 9rem; - display: block; - overflow-x: auto; - - @include custom-scrollbar; - } - - .base-map-area { - background-color: rgba(255, 255, 255, 1); - display: flex !important; - width: fit-content; - white-space: nowrap; - - .base-map-entity { - display: flex !important; - flex-direction: column; - align-items: center; - justify-content: center; - width: 5.927rem !important; - margin: 0.5rem; - - .base-map-img { - width: 5.927rem; - height: 5.839rem; - border: 0.063rem solid rgb(0, 0, 0, 0.1); - } - - p { - position: relative; - margin-left: auto; - margin-right: auto; - font-family: Roboto; - font-size: 0.75rem; - font-weight: 400; - line-height: 0.875rem; - color: black; - padding: 0; - margin: 0.4rem 0 0 0; - } - } - - .selected { - background-color: rgba(255, 255, 255, 1); - - .base-map-img { - border: 0.125rem solid $primary-theme-color !important; - } - - p { - color: $primary-theme-color !important; - } - } - } - } - } - } -} - -.microplan-preview-section { - width: 100%; - display: flex; - flex-direction: column; - - .top-section { - margin: 1.5rem 0 0 0; - - .campaign-name { - font-family: Roboto; - font-size: 20px; - font-style: italic; - font-weight: 500; - line-height: 23.44px; - text-align: left; - color: rgba(80, 90, 95, 1); - margin: 0; - padding: 0; - } - - .heading { - width: 100%; - margin: 0.5rem 0 1rem 0; - display: flex; - justify-content: space-between; - align-items: center; - font-family: Roboto Condensed; - font-size: 2.5rem; - font-weight: 700; - text-align: left; - line-height: 2.5rem; - padding: 0; - margin: 0; - } - - .user-name { - font-family: Roboto; - font-size: 1rem; - font-weight: 400; - line-height: 1.5rem; - text-align: left; - color: rgba(80, 90, 95, 1); - padding: 0; - margin: 0; - } - } - - .aggregates { - width: 100%; - background-color: rgb(255, 255, 255, 1); - display: flex; - align-items: center; - padding: 2.3rem; - justify-content: space-between; - - .aggregate-value { - font-family: Roboto; - font-size: 1.75rem; - font-weight: 700; - line-height: 2.051rem; - text-align: center; - color: rgba(11, 12, 12, 1); - padding: 0; - margin: 0; - } - - .aggregate-label { - font-family: Roboto; - font-size: 1rem; - font-weight: 400; - line-height: 1.5rem; - text-align: center; - color: rgba(80, 90, 95, 1); - padding: 0; - margin: 0 0 0 0; - } - } - - .boundary-selection { - display: flex; - flex-direction: row; - flex-wrap: wrap; - width: 100%; - align-items: center; - justify-content: flex-start; - padding-top: 2rem; - - .digit-multiselectdropdown-master { - background-color: rgb(255, 255, 255, 0) !important; - } - - .digit-multiselectdropdown-label { - p { - color: rgba(177, 180, 182, 1); - } - } - - .hierarchy-selection-element { - position: relative; - - .header { - font-family: Roboto; - font-size: 1rem; - font-weight: 400; - padding: 0 0 0.3rem 0; - margin: 0; - } - width: 19.75rem; - padding-right: 0.7rem; - } - } - - .microplan-preview-body { - width: 100%; - display: flex; - margin-top: 1.2rem; - - .hypothesis-container { - padding: 1.5rem 0 1.5rem 0; - box-shadow: 0px 0.063rem 0.125rem 0px rgba(0, 0, 0, 0.16); - background: rgba(255, 255, 255, 1); - max-width: 17.5rem; - max-height: 34rem; - margin-right: 1rem; - - p { - font-family: Roboto; - font-size: 1rem; - font-weight: 400; - padding: 0; - margin: 0; - overflow: hidden; - height: fit-content; - text-wrap: wrap; - } - - .hypothesis-heading { - font-family: Roboto; - font-size: 1.5rem; - font-weight: 700; - padding: 0; - overflow: hidden; - text-wrap: wrap; - margin: 0 1.5rem 0 1.5rem; - } - - .instructions { - margin: 1.5rem; - } - - .hypothesis-list-entity { - margin: 0 0 1.5rem 0; - } - - .input { - padding: 0.3rem 0 0 0; - width: 100%; - } - - .hypothesis-list-wrapper { - align-self: flex-end; - } - - .hypothesis-list { - overflow-y: auto; - max-height: 17rem; - @include custom-scrollbar; - padding-right: 0.4rem; - padding-left: 1.5rem; - padding-right: 1.5rem; - h3 { - background-color: #f4f4f4; - padding: 0.625rem; - margin: 0; - } - } - .scrollable { - padding-right: 0.8rem; - margin-right: 0.2rem; - } - - .hypothesis-controllers { - display: flex !important; - justify-content: space-between; - padding: 1rem 0 0 0; - width: 100%; - - .button-primary { - font-family: Roboto; - font-size: 1.188rem; - font-weight: 600; - width: 100%; - min-height: 2.5rem; - padding: 0; - display: flex; - align-items: center; - justify-content: center; - margin: 0.5rem 1.5rem 0 1.5rem; - } - } - } - - .preview-container { - flex-grow: 1; - background: rgba(255, 255, 255, 1); - box-shadow: 0px 0.063rem 0.125rem 0px rgba(0, 0, 0, 0.16); - position: relative; - width: 100%; - overflow: auto; - border-radius: 0.25rem; - - width: 100%; - overflow: auto; - border-radius: 0.25rem; - - .excel-wrapper { - width: 100%; - display: flex; - flex-direction: column; - background-color: white !important; - border: 0.063rem rgba(0, 0, 0, 0.16) solid !important; - border-radius: 0.25rem; - padding: 0.8rem 0.5rem 0.5rem 0.8rem; - padding: 0.8rem 0.5rem 0.8rem 0.8rem; - - .sheet-wrapper { - overflow: auto; - height: 33rem; - background-color: white; - padding: 0.3rem; - - @include custom-scrollbar; - - h3 { - background-color: #f4f4f4; - padding: 0.625rem; - margin: 0; - } - - .excel-table { - width: 100%; - border: 0.063rem solid #ccc; - border-collapse: collapse; - position: relative; - - tr:hover { - width: 100%; - outline: 0.1rem solid $primary-theme-color; - - td { - border-top: 0.063rem solid rgba(244, 119, 56, 0); - border-bottom: 0.063rem solid rgba(244, 119, 56, 0); - } - } - - .selected-row { - width: 100%; - height: 100%; - background-color: rgb(244, 119, 56, 0.12) !important; - } - - th, - td { - min-width: 7.578rem; - border-left: 0.063rem solid rgba(214, 213, 212, 1); - border-top: 0.063rem solid rgba(214, 213, 212, 1); - border-bottom: 0; - border-right: 0; - padding: 0.5rem; - font-family: Arial, sans-serif; - font-size: 0.875rem; - cursor: pointer; - position: relative; - - .edited-row-marker { - width: 0.313rem; - position: absolute; - top: -0.045rem; - left: -0.313rem; - padding: 0; - margin: 0; - height: calc(100% + 0.09rem); - border-top-left-radius: 0.125rem; - border-bottom-left-radius: 0.125rem; - background-color: $primary-theme-color; - } - } - - th { - background-color: #f4f4f4; - font-weight: bold; - text-align: left; - vertical-align: top; - } - } - } - - .edit-resource-data { - padding: 0 0.7rem 0 1rem; - width: 100%; - max-height: 25.5rem; - overflow: auto; - - @include custom-scrollbar; - - .edit-resource-data-table { - width: 100% !important; - background: rgb(255, 255, 255); - - thead { - position: sticky !important; - z-index: 100; - top: 0; - background-color: rgba(250, 250, 250); - padding: 0; - } - - th, - td { - p { - display: flex !important; - align-items: center; - min-width: 7.578rem; - height: 2.5rem; - padding-left: 0.5rem; - padding-right: 0.5rem; - font-family: Roboto; - margin: 0; - font-size: 1rem; - font-weight: 400; - text-align: left; - border: 0.063rem solid rgba(80, 90, 95, 1); - color: rgba(80, 90, 95, 1); - text-wrap: wrap; - } - - background: rgb(255, 255, 255); - } - th { - padding: 0 0 0.4rem 0 !important; - } - - td { - padding: 0.8rem 1.9rem 0.4rem 0; - } - - .old-value { - p { - background-color: rgba(238, 238, 238, 1); - } - - width: 35%; - } - - .new-value { - width: 35%; - } - - .column-names { - p { - font-weight: 700; - border: 0; - padding-left: 0; - color: rgba(11, 12, 12, 1); - } - - width: 25%; - } - - th { - border: 0; - padding: 0; - font-family: Roboto; - font-size: 1.5rem; - font-weight: 700; - line-height: 1.758rem; - text-align: left; - color: rgba(11, 12, 12, 1); - } - } - } - } - - .no-data-available-container { - width: 100%; - height: 100%; - display: flex !important; - align-items: center; - justify-content: center; - } - } - } - - .digit-action-cancel { - color: $primary-theme-color; - } - - .apply-changes-hypothesis { - padding: 1rem; - padding-top: 0; - - .instructions { - p { - font-weight: 400; - font-size: 1rem; - padding: 0; - margin: 0; - } - } - - .table-header { - font-family: Roboto; - font-size: 1rem; - font-weight: 700; - color: rgba(11, 12, 12, 1); - } - - .table-container { - max-height: 15rem; - overflow-y: auto; - @include custom-scrollbar; - - .custom-table { - width: 100%; - border-collapse: collapse; - - th { - font-family: Roboto; - font-size: 1rem; - font-weight: 700; - } - - th, - td { - overflow-wrap: normal; - text-wrap: wrap; - padding: 1rem 1.2rem; - text-align: left; - border: 0.063rem solid rgba(214, 213, 212, 1) !important; - } - - .even-row { - background-color: rgba(238, 238, 238, 1); - } - - .odd-row { - background-color: white; - } - } - } - } -} - -.microplan-success-screen { - padding: 1.5rem; - background-color: rgba(255, 255, 255, 1); -} - -.button-container { - width: 100%; - display: flex; - align-items: center; - justify-content: end; -} - -.custom-action-bar-success-screen { - padding: 1.5rem 1.5rem 1.5rem 5.3rem; - display: flex !important; - justify-content: flex-end !important; - align-items: center; - height: 4rem; - - .custom-button { - min-width: 12.5rem; - display: flex; - justify-content: center; - align-items: center; - - h2 { - font-weight: 600; - width: fit-content !important; - } - - .icon { - margin: 0 0 0 1rem !important; - } - } - - .custom-button-left-icon { - margin-right: 1.2rem; - - .icon { - margin: 0 1rem 0 0 !important; - } - } -} - -.popup-wrap-focus { - button:focus { - outline: 0.125rem solid #000000 !important; - border-color: rgba(255, 255, 255, 0) !important; - outline-offset: -0.125rem !important; - } -} -.popup-wrap-rest-unfocus { -} -.popup-wrap-rest-unfocus-active { - button:focus { - outline: none !important; - outline-offset: -0.125rem !important; - } -} - -.guide-line-heading { - font-family: Roboto Condensed; - font-size: 2.5rem; - font-weight: 700; - text-align: left; -} - -.map-pop-up { - @include custom-scrollbar(); - background-color: white; - margin: 1rem 0; - width: 28rem; - max-height: 23rem; - overflow: auto; -} diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/css/src/index.scss b/frontend/microplan-ui/web/micro-ui-internals/packages/css/src/index.scss deleted file mode 100644 index 3b3e8ff0f38..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/css/src/index.scss +++ /dev/null @@ -1,13 +0,0 @@ -/*@import 'normalize.css';*/ - -/*@import url("https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@400;500;700&family=Roboto:wght@400;500;700&display=swap");*/ - -@import "tailwindcss/base"; - -@import "tailwindcss/components"; - -@import "tailwindcss/utilities"; - -@import "./components/microplanning.scss"; -@import "./components/coreOverride.scss"; -@import "./pages/employee/index.scss"; \ No newline at end of file diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss b/frontend/microplan-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/css/tailwind.config.js b/frontend/microplan-ui/web/micro-ui-internals/packages/css/tailwind.config.js deleted file mode 100644 index 673ba2cfaba..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/css/tailwind.config.js +++ /dev/null @@ -1,231 +0,0 @@ -module.exports = { - future: { - removeDeprecatedGapUtilities: true, - purgeLayersByDefault: true, - }, - purge: { enabled: true, content: ["./example/index.html"] }, - theme: { - screens: { - dt: "780px", - sm: { max: "425px" }, - }, - colors: { - primary: { - light: "#F18F5E", - main: "#F47738", - dark: "#C8602B", - }, - secondary: "#22394D", - text: { - primary: "#0B0C0C", - secondary: "#505A5F", - }, - link: { - normal: "#1D70B8", - hover: "#003078", - }, - border: "#D6D5D4", - inputBorder: "#464646", - "input-border": "#464646", - focus: "#F47738", - error: "#D4351C", - success: "#00703C", - black: "#000000", - grey: { - dark: "#9E9E9E", - mid: "#EEEEEE", - light: "#FAFAFA", - bg: "#E3E3E3", - }, - white: "#FFFFFF", - }, - fontFamily: { - sans: ["Roboto", "sans-serif"], - rc: ['"Roboto Condensed"', "sans-serif"], - }, - fontSize: { - "heading-xl-dt": ["48px", "56px"], - "heading-xl": ["32px", "40px"], - "heading-l-dt": ["36px", "40px"], - "heading-l": ["24px", "32px"], - "heading-m-dt": ["24px", "32px"], - "heading-m": ["18px", "28px"], - "heading-s": ["16px", "24px"], - "caption-xl-dt": ["27px", "32px"], - "caption-xl": ["18px", "26px"], - "caption-l-dt": ["24px", "28px"], - "caption-l": ["18px", "21px"], - "caption-m-dt": ["19px", "23px"], - "caption-m": ["16px", "19px"], - "form-field": ["16px", "20px"], - "body-l-dt": ["19px", "28px"], - "body-l": ["16px", "24px"], - "body-s-dt": ["16px", "24px"], - "body-s": ["14px", "16px"], - legend: ["19px", "23px"], - link: ["16px", "24px"], - "text-btn": ["16px", "24px"], - }, - fontWeight: { - regular: 400, - medium: 500, - bold: 700, - }, - padding: { - sm: "8px", - md: "16px", - lg: "24px", - xl: "36px", - }, - margin: { - xs: "4px", - sm: "8px", - md: "16px", - lg: "24px", - xl: "64px", - }, - borderWidth: { - default: "1px", - 0: "0", - 2: "1px", - 4: "4px", - 10: "10px", - }, - boxShadow: { - card: "0 1px 2px 0 rgba(0, 0, 0, 0.16)", - radiobtn: "0 0 0 5px #F47738", - }, - inset: { - 0: 0, - 6: "6px", - 10: "10px", - }, - extend: {}, - digitv2: { - lightTheme: { - primary: "#F47738", - "text-color-primary": "#0B0C0C", - "text-color-secondary": "#505A5F", - "text-color-disabled": "#B1B4B6", - background: "#EEEEEE", - paper: "#FFFFFF", - "paper-secondary": "#FAFAFA", - divider: "#D6D5D4", - "header-sidenav": "#0B4B66", - "input-border": "#505A5F", - "primary-bg": "#FEEFE7", - }, - alert: { - error: "#D4351C", - "error-bg": "#EFC7C1", - success: "#00703C", - "success-bg": "#BAD6C9", - info: "#3498DB", - "info-bg": "#C7E0F1", - }, - chart: { - "chart-1": "#048BD0", - "chart-1-gradient": "#048BD0", - "chart-2": "#FBC02D", - "chart-2-gradient": "#FBC02D", - "chart-3": "#8E29BF", - "chart-4": "#EA8A3B", - "chart-5": "#0BABDE", - }, - fontSize: { - "heading-xl": { - mobile: "2rem", - tablet: "2.25rem", - desktop: "2.5rem", - }, - "heading-l": { - mobile: "1.5rem", - tablet: "1.75rem", - desktop: "2rem", - }, - "heading-m": { - mobile: "1.25rem", - tablet: "1.375rem", - desktop: "1.5rem", - }, - "heading-s": { - mobile: "1rem", - tablet: "1rem", - desktop: "1rem", - }, - "heading-xs": { - mobile: "0.75rem", - }, - "caption-l": { - mobile: "1.5rem", - tablet: "1.75rem", - desktop: "1.75rem", - }, - "caption-m": { - mobile: "1.25rem", - tablet: "1.5rem", - desktop: "1.5rem", - }, - "caption-s": { - mobile: "1rem", - tablet: "1.25rem", - desktop: "1.25rem", - }, - "body-l": { - mobile: "1rem", - tablet: "1.25rem", - desktop: "1.25rem", - }, - "body-s": { - mobile: "0.875rem", - tablet: "1rem", - desktop: "1rem", - }, - "body-xs": { - mobile: "0.75rem", - tablet: "0.875rem", - desktop: "0.875rem", - }, - label: { - mobile: "1rem", - tablet: "1rem", - desktop: "1rem", - }, - link: { - mobile: "1rem", - tablet: "1rem", - desktop: "1rem", - }, - }, - fontFamily: { - sans: ["Roboto"], - rc: ['"Roboto Condensed"'], - }, - fontStyle: { - normal: "normal", - italic: "italic", - }, - textDecorationLine: { - underline: "underline", - }, - fontWeight: { - regular: 400, - medium: 500, - bold: 700, - }, - lineHeight: { - "line-height-body-l": { mobile: "1.5rem", tablet: "1.75rem", desktop: "1.75rem" }, - "line-height-body-s": { mobile: "1.0938rem", tablet: "1.5rem", desktop: "1.5rem" }, - "line-height-body-xs": { mobile: "1.125rem", tablet: "1.5rem", desktop: "1.5rem" }, - normal: "normal", - }, - screens: { - mobile: "400px", - tablet: "768px", - desktop: "1024px", - }, - }, - }, - variants: {}, - plugins: [], -}; \ No newline at end of file diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js deleted file mode 100644 index 78c8585e23a..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js +++ /dev/null @@ -1,1693 +0,0 @@ -// Importing necessary modules -import { - Card, - CardLabel, - CustomDropdown, - Dropdown, - Header, - MultiSelectDropdown, - Toast, - TreeSelect, - Button, - CheckBox, - RadioButtons, -} from "@egovernments/digit-ui-components"; -import L, { map } from "leaflet"; -import "leaflet/dist/leaflet.css"; -import React, { memo, useCallback, useEffect, useMemo, useRef, useState, Fragment } from "react"; -import { useTranslation } from "react-i18next"; -import ZoomControl from "./ZoomControl"; -import CustomScaleControl from "./CustomScaleControl"; -import * as DigitSvgs from "@egovernments/digit-ui-svg-components"; -import { CardSectionHeader, InfoIconOutline, LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; -import { processHierarchyAndData, findParent, fetchDropdownValues, findChildren, calculateAggregateForTree } from "../utils/processHierarchyAndData"; -import { EXCEL, GEOJSON, SHAPEFILE, MapChoroplethGradientColors, PRIMARY_THEME_COLOR } from "../configs/constants"; -import { tourSteps } from "../configs/tourSteps"; -import { useMyContext } from "../utils/context"; -import { ClearAllIcon, CloseButton, ModalHeading } from "./CommonComponents"; -import { PopulationSvg } from "../icons/Svg"; -import chroma from "chroma-js"; -import * as MicroplanIconCollection from "../icons/Svg"; - -const IconCollection = { ...MicroplanIconCollection, ...DigitSvgs }; - -const page = "mapping"; - -function checkTruthyKeys(obj) { - for (let key in obj) { - if (Object.hasOwn(obj, key)) { - if (obj[key] && !(Array.isArray(obj[key]) && obj[key].length === 0)) { - return true; - } - } - } - return false; -} - -// Mapping component definition -const Mapping = ({ - campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, - microplanData, - setMicroplanData, - checkDataCompletion, - setCheckDataCompletion, - currentPage, - pages, - setToast, - ...props -}) => { - //fetch campaign data - const { id = "" } = Digit.Hooks.useQueryParams(); - const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( - { - CampaignDetails: { - tenantId: Digit.ULBService.getCurrentTenantId(), - ids: [id], - }, - }, - { - enabled: !!id, - } - ); - - // request body for boundary hierarchy api - var reqCriteria = { - url: `/boundary-service/boundary-hierarchy-definition/_search`, - params: {}, - body: { - BoundaryTypeHierarchySearchCriteria: { - tenantId: Digit.ULBService.getStateId(), - // hierarchyType: "Microplan", - hierarchyType: campaignData?.hierarchyType, - }, - }, - config: { - enabled: !!campaignData?.hierarchyType, - select: (data) => { - return ( - data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map((item) => ({ - ...item, - parentBoundaryType: item?.parentBoundaryType - ? `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.parentBoundaryType)}` - : null, - boundaryType: `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}`, - })) || {} - ); - }, - }, - }; - const { isLoading: ishierarchyLoading, data: hierarchy } = Digit.Hooks.useCustomAPIHook(reqCriteria); - // request body for boundary hierarchy api - var reqCriteria = { - url: `/boundary-service/boundary/_search`, - params: { codes: Digit.ULBService.getCurrentTenantId(), tenantId: Digit.ULBService.getCurrentTenantId() }, - body: {}, - config: { - select: (data) => { - return data?.Boundary || {}; - }, - }, - }; - const { isLoading: isBoundaryLoading, data: Boundary } = Digit.Hooks.useCustomAPIHook(reqCriteria); - - // Setting up state variables - const [editable, setEditable] = useState(true); - const { t } = useTranslation(); - var [map, setMap] = useState(null); - var [_mapNode, set__mapNode] = useState("map"); - const [layers, setLayer] = useState([]); - const [validationSchemas, setValidationSchemas] = useState([]); - const [filterDataOrigin, setFilterDataOrigin] = useState({}); - const [dataAvailability, setDataAvailability] = useState("true"); - // const [toast, setToast] = useState(); - const [baseMaps, setBaseMaps] = useState({}); - const [selectedBaseMap, setSelectedBaseMap] = useState({}); - const [selectedBaseMapName, setSelectedBaseMapName] = useState(""); - const [showBaseMapSelector, setShowBaseMapSelector] = useState(false); - const [boundaryData, setBoundaryData] = useState({}); // State for boundary data - const [filterData, setFilterData] = useState({}); // State for facility data - const [boundarySelections, setBoundarySelections] = useState({}); - const [isboundarySelectionSelected, setIsboundarySelectionSelected] = useState(false); - const { state, dispatch } = useMyContext(); - const [filterPropertyNames, setFilterPropertyNames] = useState(); - const [filterProperties, setFilterProperties] = useState(); - const [showFilterOptions, setShowFilterOptions] = useState(false); - const [filterSelections, setFilterSelections] = useState([]); - const [choroplethProperties, setChoroplethProperties] = useState([]); - const [showChoroplethOptions, setShowChoroplethOptions] = useState(false); - const [choroplethProperty, setChoroplethProperty] = useState(); - const [dataCompleteness, setDataCompleteness] = useState(); - const basemapRef = useRef(); - const filterBoundaryRef = useRef(); - const showChoroplethOptionRef = useRef(); - const showFilterOptionRef = useRef(); - const [loader, setLoader] = useState(false); - - // Set TourSteps - useEffect(() => { - const tourData = tourSteps(t)?.[page] || {}; - if (state?.tourStateData?.name === page) return; - dispatch({ - type: "SETINITDATA", - state: { tourStateData: tourData }, - }); - }, []); - - // Effect to initialize map when data is fetched - useEffect(() => { - if (!state || !Boundary) return; - let UIConfiguration = state?.UIConfiguration; - if (UIConfiguration) { - const filterDataOriginList = UIConfiguration.find((item) => item.name === "mapping"); - setFilterDataOrigin(filterDataOriginList); - } - const BaseMapLayers = state?.BaseMapLayers; - let schemas = state?.Schemas; - if (schemas) setValidationSchemas(schemas); - if (!BaseMapLayers || (BaseMapLayers && BaseMapLayers.length === 0)) return; - let baseMaps = {}; - let defaultBaseMap = undefined; - BaseMapLayers.forEach((item) => { - if (item.url) { - const layer = L.tileLayer(item.url, { - minZoom: item?.minZoom, - maxZoom: item?.maxZoom, - attribution: item?.attribution, - }); - baseMaps[item?.name] = { - metadata: item, - layer, - }; - if (!defaultBaseMap) - defaultBaseMap = { - name: item?.name, - layer, - }; - } - }); - setSelectedBaseMapName(defaultBaseMap?.name); - setBaseMaps(baseMaps); - if (!map) { - init(_mapNode, defaultBaseMap, Boundary); - } - }, [Boundary]); - - useEffect(() => { - if (map && filterDataOrigin && Object.keys(filterDataOrigin).length !== 0) { - setLoader("LOADING"); - // Check if all the data is present or not, if it is then extract it in a format that can be used for mapping and other mapping related operations - extractGeoData( - campaignType, - microplanData, - filterDataOrigin, - validationSchemas, - setToast, - setDataAvailability, - hierarchy, - setBoundaryData, - setFilterData, - setFilterProperties, - setFilterSelections, - setFilterPropertyNames, - state, - setChoroplethProperties, - setDataCompleteness, - t - ); - setLoader(false); - } - }, [filterDataOrigin, hierarchy]); - - // Function to initialize map - const init = (id, defaultBaseMap, Boundary) => { - if (map !== null) return; - - // let bounds = findBounds(Boundary); - - let mapConfig = { - center: [0, 0], - zoomControl: false, - zoom: 3, - scrollwheel: true, - minZoom: 3, - }; - - let map_i = L.map(id, mapConfig); - var verticalBounds = L.latLngBounds(L.latLng(-90, -170), L.latLng(85, 190)); - map_i.on("drag", () => { - map_i.panInsideBounds(verticalBounds, { animate: true }); - }); - map_i.on("zoom", () => { - map_i.panInsideBounds(verticalBounds, { animate: true }); - }); - const defaultBaseLayer = defaultBaseMap?.layer.addTo(map_i); - // if (bounds) map_i.fitBounds(bounds); - setSelectedBaseMap(defaultBaseLayer); - setMap(map_i); - }; - - const handleBaseMapToggle = (newBaseMap) => { - if (map) { - const currentBaseLayer = selectedBaseMap; - if (currentBaseLayer) { - currentBaseLayer.remove(); - } - const newBaseLayer = baseMaps[newBaseMap].layer.addTo(map); - // Add the new base layer to the bottom of the layer stack - newBaseLayer.addTo(map); - - // Update the baseLayer state - setSelectedBaseMap(newBaseLayer); - setSelectedBaseMapName(newBaseMap); - } - }; - - // showing selected boundary data - useEffect(() => { - if (!boundarySelections && !choroplethProperty && !filterSelections) return; - setLoader("LOADING"); - try { - removeAllLayers(map, layers); - const { filteredSelection, childrenList } = filterBoundarySelection(boundaryData, boundarySelections); - let newLayer = []; - let addOn = { - fillColor: "rgba(255, 107, 43, 0)", - weight: 3.5, - opacity: 1, - color: "rgba(176, 176, 176, 1)", - fillOpacity: 0, - fill: "rgb(4,136,219,1)", - child: !childrenList || childrenList.length === 0, // so that this layer also has mounse in and mouse out events - }; - let geojsonsBase = prepareGeojson(boundaryData, "ALL", addOn); - if (geojsonsBase) { - let baseLayer = addGeojsonToMap(map, geojsonsBase, t); - if (baseLayer) newLayer.push(baseLayer); - let bounds = findBounds(geojsonsBase); - if (bounds) map.fitBounds(bounds); - } - - addOn = { - fillColor: "rgba(255, 107, 43, 1)", - weight: 2.5, - opacity: 1, - color: "rgba(255, 255, 255, 1)", - fillOpacity: 0.22, - fill: "rgb(4,136,219)", - }; - - let geojsonLayer; - if (choroplethProperty) { - if (dataCompleteness === "partial" || dataCompleteness === "false" || dataCompleteness === undefined) { - setToast({ - state: "warning", - message: t("DISPLAYING_DATA_ONLY_FOR_UPLOADED_BOUNDARIES"), - }); - } - - let choroplethGeojson = prepareGeojson(boundaryData, "ALL", { ...addOn, child: true, fillColor: "rgb(0,0,0,0)" }) || []; - if (choroplethGeojson && choroplethGeojson.length !== 0) - choroplethGeojson = addChoroplethProperties(choroplethGeojson, choroplethProperty, filteredSelection); - geojsonLayer = addGeojsonToMap(map, choroplethGeojson, t); - if (geojsonLayer) { - newLayer.push(geojsonLayer); - } - } - geojsonLayer = null; - const geojsons = prepareGeojson(boundaryData, filteredSelection, addOn); - if (geojsons && geojsons.length > 0) { - geojsonLayer = addGeojsonToMap(map, geojsons, t); - newLayer.push(geojsonLayer); - let bounds = findBounds(geojsons); - if (bounds) map.fitBounds(bounds); - } - - const childrenGeojson = prepareGeojson(boundaryData, childrenList, { ...addOn, opacity: 0, fillOpacity: 0, child: true }); - let childrenGeojsonLayer = addGeojsonToMap(map, childrenGeojson, t); - if (childrenGeojsonLayer) newLayer.push(childrenGeojsonLayer); - - //filters - const filterGeojsons = prepareGeojson(filterData, filteredSelection && filteredSelection.length !== 0 ? filteredSelection : "ALL", addOn); - const filterGeojsonWithProperties = addFilterProperties(filterGeojsons, filterSelections, filterPropertyNames, state?.MapFilters); - let filterGeojsonLayer = addGeojsonToMap(map, filterGeojsonWithProperties, t); - if (filterGeojsonLayer) newLayer.push(filterGeojsonLayer); - - setLayer(newLayer); - } catch (error) { - console.error("Error while adding geojson to map: ", error.message); - } - setLoader(false); - }, [boundarySelections, choroplethProperty, filterSelections]); - - const handleOutsideClickAndSubmitSimultaneously = useCallback(() => { - if (isboundarySelectionSelected) setIsboundarySelectionSelected(false); - if (showBaseMapSelector) setShowBaseMapSelector(false); - if (showFilterOptions) setShowFilterOptions(false); - if (showChoroplethOptions) setShowChoroplethOptions(false); - }, [ - isboundarySelectionSelected, - showBaseMapSelector, - showFilterOptions, - showChoroplethOptions, - setIsboundarySelectionSelected, - setShowBaseMapSelector, - setShowFilterOptions, - setShowChoroplethOptions, - ]); - Digit?.Hooks.useClickOutside(filterBoundaryRef, handleOutsideClickAndSubmitSimultaneously, isboundarySelectionSelected, { capture: true }); - Digit?.Hooks.useClickOutside(basemapRef, handleOutsideClickAndSubmitSimultaneously, showBaseMapSelector, { capture: true }); - Digit?.Hooks.useClickOutside(showFilterOptionRef, handleOutsideClickAndSubmitSimultaneously, showFilterOptions, { capture: true }); - Digit?.Hooks.useClickOutside(showChoroplethOptionRef, handleOutsideClickAndSubmitSimultaneously, showChoroplethOptions, { capture: true }); - - // function to stop mouse event propogation from custom comopents to leaflet map - const handleMouseDownAndScroll = (event) => { - event?.stopPropagation(); - disableMapInteractions(map); - }; - - const handleMouseUpAndScroll = (event) => { - enableMapInteractions(map); - }; - useEffect(() => { - if (isboundarySelectionSelected || showBaseMapSelector || showFilterOptions || showChoroplethOptions) handleMouseDownAndScroll(); - else handleMouseUpAndScroll(); - }, [isboundarySelectionSelected, showBaseMapSelector, showFilterOptions, showChoroplethOptions, choroplethProperty, filterPropertyNames]); - - // Rendering component - return ( -
-
{t("MAPPING")}
- - - {/* Container for map */} - -
-
-
- -
- {filterProperties && Object.keys(filterProperties).length !== 0 && ( - - )} - -
- -
- -
- {DigitSvgs.NorthArrow && } -
- -
- -
- {filterSelections && filterSelections.length > 0 && ( - - )} - {choroplethProperty && } -
-
-
-
- {loader && } -
- ); -}; - -const MapFilterIndex = ({ filterSelections, MapFilters, t }) => { - return ( -
- {filterSelections && filterSelections.length > 0 ? ( - <> - {filterSelections.map((item) => ( - //
- - //

{t(item)}

- //
- ))} - - ) : ( - "" - )} -
- ); -}; - -// Function to create the gradient from the colors array for choropleth index -const MapChoroplethIndex = ({ t, choroplethProperty }) => { - const createGradientString = (colors) => { - return colors.map((color) => `${color.color} ${color.percent}%`).join(", "); - }; - - const gradientString = createGradientString(MapChoroplethGradientColors); - const gradientStyle = { - background: `linear-gradient(to right, ${gradientString})`, - }; - - return ( -
-
-

0%

-
-

100%

-
-

{t(choroplethProperty)}

-
- ); -}; - -const FilterItemBuilder = ({ item, MapFilters, t }) => { - let temp = MapFilters?.find((e) => e?.name == item)?.icon?.index; - let DynamicIcon = IconCollection?.[temp]; - // let icon; - // if (typeof DynamicIcon === "function") icon = DynamicIcon({}); - return DynamicIcon && typeof DynamicIcon === "function" ? ( -
- -

{t(item)}

-
- ) : ( - //
- "" - ); -}; - -const ChoroplethSelection = memo( - ({ - choroplethProperties, - showChoroplethOptions, - showChoroplethOptionRef, - setShowChoroplethOptions, - choroplethProperty, - setChoroplethProperty, - t, - }) => { - const handleChange = useCallback( - (value) => { - setChoroplethProperty(value?.code); - }, - [choroplethProperties] - ); - - return ( -
-
setShowChoroplethOptions((previous) => !previous)} - onKeyUp={() => setShowChoroplethOptions((previous) => !previous)} - tabIndex={0} - > -

{t("VISUALIZATIONS")}

-
- {DigitSvgs.FilterAlt && } -
-
- {showChoroplethOptions && ( -
-
- ({ name: item, id: item, code: item }))} - optionsKey="name" - onSelect={handleChange} - selectedOption={choroplethProperty} - /> -
-
- )} -
- ); - } -); - -const FilterSection = memo( - ({ filterProperties, showFilterOptionRef, showFilterOptions, setShowFilterOptions, filterSelections, setFilterSelections, t }) => { - const handleChange = useCallback( - (e, item) => { - let tempFilterSelections = [...filterSelections]; // Clone the array to avoid mutating state directly - if (filterSelections.includes(item)) { - tempFilterSelections = tempFilterSelections.filter((element) => element !== item); - } else { - tempFilterSelections.push(item); - } - setFilterSelections(tempFilterSelections); - }, - [filterSelections] - ); - - return ( -
-
setShowFilterOptions((previous) => !previous)} - onKeyUp={() => setShowFilterOptions((previous) => !previous)} - tabIndex={0} - > -

{t("FILTERS")}

-
- {DigitSvgs.FilterAlt && } -
-
- {showFilterOptions && ( -
-
- {filterProperties.map((item) => ( -
- handleChange(e, item)} - label={t(item)} - checked={!!filterSelections.includes(item)} - mainClassName="mainClassName" - labelClassName="labelClassName" - inputWrapperClassName="inputWrapperClassName" - inputClassName="inputClassName" - inputIconClassname="inputIconClassname" - iconFill={PRIMARY_THEME_COLOR} - onLabelClick={(e) => handleChange(e, item)} - /> -
- ))} -
-
- )} -
- ); - } -); - -const BoundarySelection = memo( - ({ - boundarySelections, - setBoundarySelections, - boundaryData, - hierarchy, - filterBoundaryRef, - isboundarySelectionSelected, - setIsboundarySelectionSelected, - t, - }) => { - const [processedHierarchy, setProcessedHierarchy] = useState([]); - const [isLoading, setIsLoading] = useState(false); - const [showConfirmationModal, setShowConformationModal] = useState(false); - const itemRefs = useRef([]); - const [expandedIndex, setExpandedIndex] = useState(null); - const scrollContainerRef = useRef(null); - const [changedBoundaryType, setChangedBoundaryType] = useState(""); - const [isScrollable, setIsScrollable] = useState(false); - - useEffect(() => { - // Scroll to the expanded item's child element after the state has updated and the DOM has re-rendered - if (expandedIndex !== null && itemRefs.current[expandedIndex]) { - // Use a timeout to ensure the DOM has updated - setTimeout(() => { - const childElement = itemRefs.current[expandedIndex].children[0]; // Assuming child content is the second child - // if (childElement) { - // childElement.scrollIntoView({ behavior: 'smooth' }); - // } - if (childElement) { - const scrollContainer = scrollContainerRef.current; - const childElementBound = childElement.getBoundingClientRect(); - const containerRect = scrollContainer.getBoundingClientRect(); - - // Calculate the offset from the top of the container - const offset = childElementBound.top - containerRect.top; - - // Scroll the container - scrollContainer.scrollTo({ - top: scrollContainer.scrollTop + offset - 10, - behavior: "smooth", - }); - } - }, 0); - } - }, [expandedIndex]); - - const toggleExpand = (index) => { - setExpandedIndex(index === expandedIndex ? null : index); - }; - - // Filtering out dropdown values - useEffect(() => { - if (!boundaryData || !hierarchy) return; - let processedHierarchyTemp = fetchDropdownValues( - boundaryData, - processedHierarchy.length !== 0 ? processedHierarchy : hierarchy, - boundarySelections, - changedBoundaryType - ); - setProcessedHierarchy(processedHierarchyTemp); - setIsLoading(false); - }, [boundaryData, hierarchy, boundarySelections]); - - const handleClearAll = () => { - setShowConformationModal(true); - }; - - const handleSubmitConfModal = () => { - setBoundarySelections({}); - setShowConformationModal(false); - }; - - const handleCancelConfModal = () => { - setShowConformationModal(false); - }; - - const checkScrollbar = () => { - if (scrollContainerRef.current) { - setIsScrollable(scrollContainerRef.current.scrollHeight > scrollContainerRef.current.clientHeight); - } - }; - - useEffect(() => { - // Initial check - checkScrollbar(); - - // Check on resize - window.addEventListener("resize", checkScrollbar); - - // Cleanup event listeners on component unmount - return () => { - window.removeEventListener("resize", checkScrollbar); - }; - }, []); - - useEffect(() => { - const content = scrollContainerRef.current; - content.addEventListener("scroll", checkScrollbar); - - return () => { - content.removeEventListener("scroll", checkScrollbar); - }; - }, [scrollContainerRef]); - - return ( -
- {isLoading && } -
- ); - } -); - -const BaseMapSwitcher = ({ baseMaps, showBaseMapSelector, setShowBaseMapSelector, handleBaseMapToggle, selectedBaseMapName, basemapRef, t }) => { - if (!baseMaps) return null; - return ( -
-
setShowBaseMapSelector((previous) => !previous)} - onKeyUp={() => setShowBaseMapSelector((previous) => !previous)} - tabIndex={0} - > -

{t("LAYERS")}

-
{DigitSvgs.Layers && }
-
-
- {showBaseMapSelector && ( -
- {Object.entries(baseMaps).map(([name, baseMap], index) => { - return ( -
- {name} handleBaseMapToggle(name)} - /> -

{t(name)}

-
- ); - })} -
- )} -
-
- ); -}; - -const generatePreviewUrl = (baseMapUrl, center = [0, 0], zoom = 5) => { - const lon = Math.floor(((center[1] + 180) / 360) * Math.pow(0, zoom)); - const lat = Math.floor( - ((1 - Math.log(Math.tan((center[0] * Math.PI) / 180) + 1 / Math.cos((center[0] * Math.PI) / 180)) / Math.PI) / 2) * Math.pow(2, zoom) - ); - if (baseMapUrl) { - return baseMapUrl.replace("{z}", zoom).replace("{x}", lat).replace("{y}", lon); - } - // Return a default preview URL or handle this case as needed - return "default-preview-url.jpg"; // todo -}; - -// get schema for validation -const getSchema = (campaignType, type, section, schemas) => { - return schemas.find((schema) => { - if (!schema.campaignType) { - return schema.type === type && schema.section === section; - } - return schema.campaignType === campaignType && schema.type === type && schema.section === section; - }); -}; - -const calculateAggregateForTreeMicroplanWrapper = (entity) => { - if (!entity || typeof entity !== "object") return {}; - let newObject = {}; - for (let [key, value] of Object.entries(entity)) { - if (!value?.["hierarchicalData"]) continue; - let aggregatedTree = calculateAggregateForTree(value?.["hierarchicalData"]); - newObject[key] = { ...value, hierarchicalData: aggregatedTree }; - } - return newObject; -}; - -const extractGeoData = ( - campaignType, - microplanData, - filterDataOrigin, - validationSchemas, - setToast, - setDataAvailability, - hierarchy, - setBoundaryData, - setFilterData, - setFilterProperties, - setFilterSelections, - setFilterPropertyNames, - state, - setChoroplethProperties, - setDataCompleteness, - t -) => { - if (!hierarchy) return; - - let setBoundary = {}; - let setFilter = {}; - let virtualizationPropertiesCollector = new Set(); - let filterPropertiesCollector = new Set(); - let filterPropertieNameCollector = new Set(); - let resources = state?.Resources?.find((item) => item.campaignType === campaignType)?.data; - let hypothesisAssumptionsList = microplanData?.hypothesis; - let formulaConfiguration = microplanData?.ruleEngine; - // Check if microplanData and its upload property exist - let dataAvailabilityCheck; // Initialize data availability check - if (microplanData?.upload) { - let files = _.cloneDeep(microplanData?.upload); - dataAvailabilityCheck = "initialStage"; // Initialize data availability check - // Loop through each file in the microplan upload - for (let fileData of files) { - if (!fileData.active) continue; // if file is inactive skip it - - // Check if the file is not part of boundary or layer data origins - if (!filterDataOrigin?.boundriesDataOrigin?.includes(fileData?.section) && !filterDataOrigin?.layerDataOrigin?.includes(fileData?.section)) { - dataAvailabilityCheck = "false"; // Set data availability to false if file not found in data origins - } - - // If data availability is not false, proceed with further checks - if (dataAvailabilityCheck !== false) { - if (fileData?.error) { - dataAvailabilityCheck = - dataAvailabilityCheck === "partial" - ? "partial" - : dataAvailabilityCheck === "false" || dataAvailabilityCheck === "initialStage" - ? "false" - : "partial"; - continue; - } - if (!fileData?.fileType || !fileData?.section) continue; // Skip files with errors or missing properties - - // Get validation schema for the file - let schema = getSchema(campaignType, fileData?.fileType, fileData?.section, validationSchemas); - const properties = Object.entries(schema?.schema?.Properties || {}); - const latLngColumns = []; - let filterProperty = []; - - for (const [key, value] of properties) { - if (value?.isLocationDataColumns) { - latLngColumns.push(t(key)); - } - if ( - filterDataOrigin?.layerDataOrigin && - filterDataOrigin?.layerDataOrigin.includes(fileData?.section) && - value?.isFilterPropertyOfMapSection - ) { - filterProperty.push(key); - } - if (value?.isVisualizationPropertyOfMapSection && filterDataOrigin?.boundriesDataOrigin?.includes(fileData?.section)) { - virtualizationPropertiesCollector.add(key); - } - } - - filterProperty.forEach((property) => filterPropertieNameCollector.add(property)); - - // Check if file contains latitude and longitude columns - if (fileData?.data && Object.keys(fileData?.data).length > 0) { - if (dataAvailabilityCheck == "initialStage") dataAvailabilityCheck = "true"; - // Check file type and update data availability accordingly - switch (fileData?.fileType) { - case EXCEL: { - let columnList = Object.values(fileData?.data)?.[0]?.[0]; - let check = true; - if (latLngColumns) { - for (let colName of latLngColumns) { - check = check && columnList.includes(t(colName)); // Check if columns exist in the file - } - } - dataAvailabilityCheck = check - ? dataAvailabilityCheck === "partial" - ? "partial" - : dataAvailabilityCheck === "false" - ? "partial" - : "true" - : dataAvailabilityCheck === "partial" - ? "partial" - : dataAvailabilityCheck === "false" - ? "false" - : "partial"; // Update data availability based on column check - let dataWithResources = Object.values(fileData?.data); - if (resources && formulaConfiguration && hypothesisAssumptionsList && schema?.showResourcesInMappingSection) { - dataWithResources = dataWithResources?.map((item) => { - return Digit.Utils.microplan.addResourcesToFilteredDataToShow( - item, - resources, - hypothesisAssumptionsList, - formulaConfiguration, - microplanData?.microplanPreview?.userEditedResources ? microplanData?.microplanPreview?.userEditedResources : [], - t - ); - }); - } - - let hasLocationData = false; - // has lat lon a points - const convertedData = dataWithResources?.map((item) => - item?.map((row, rowIndex) => { - if (rowIndex === 0) { - if (row.indexOf("features") === -1) { - row.push("feature"); - } - return row; - } - const latIndex = item?.[0].findIndex((cell) => cell === "lat"); - const lonIndex = item?.[0].findIndex((cell) => cell === "long"); - let properties = {}; - row.map((e, index) => { - properties[item?.[0]?.[index]] = e; - }); - if (latIndex !== -1 && lonIndex !== -1) { - if (!hasLocationData) hasLocationData = true; - const lat = row[latIndex]; - const lon = row[lonIndex]; - const feature = { - type: "Feature", - properties: properties, - geometry: { - type: "Point", - coordinates: [lon, lat], - }, - }; - row.push(feature); - } else { - row.push(null); - } - return row; - }) - ); - - if (hasLocationData) { - if (Object.values(fileData?.data).length > 0 && filterProperty) { - filterProperty?.forEach((item) => { - Object.values(fileData?.data).forEach((data) => { - let filterPropertyIndex = data?.[0].indexOf(item); - if (filterPropertyIndex && filterPropertyIndex !== -1) - data.slice(1).forEach((e) => { - return filterPropertiesCollector.add(e[filterPropertyIndex]); - }); - }); - }); - } - } - // extract dada - var { hierarchyLists, hierarchicalData } = processHierarchyAndData(hierarchy, convertedData); - if (filterDataOrigin?.boundriesDataOrigin?.includes(fileData?.section)) - setBoundary = { ...setBoundary, [fileData.section]: { hierarchyLists, hierarchicalData } }; - else if (filterDataOrigin?.layerDataOrigin?.includes(fileData?.section)) - setFilter = { ...setFilter, [fileData.section]: { hierarchyLists, hierarchicalData } }; - break; - } - case GEOJSON: - case SHAPEFILE: { - dataAvailabilityCheck = dataAvailabilityCheck === "partial" ? "partial" : dataAvailabilityCheck === "false" ? "partial" : "true"; // Update data availability for GeoJSON or Shapefile - // Extract keys from the first feature's properties - var keys = Object.keys(fileData?.data.features[0].properties); - keys.push("feature"); - - // Extract corresponding values for each feature - const values = fileData?.data?.features.map((feature) => { - // list with features added to it - const temp = keys.map((key) => { - if (feature.properties[key] === "") { - return null; - } - if (key === "feature") return feature; - return feature.properties[key]; - }); - return temp; - }); - - if (fileData?.data?.features && filterProperty) { - filterProperty?.forEach((item) => { - if (Object.values(fileData?.data).length > 0) { - fileData?.data?.features.forEach((e) => { - if (e?.properties?.[item]) filterPropertiesCollector.add(e?.properties?.[item]); - }); - } - }); - } - - // Group keys and values into the desired format - // Adding resource data - let dataWithResources = [keys, ...values]; - if (resources && formulaConfiguration && hypothesisAssumptionsList) { - dataWithResources = Digit.Utils.microplan.addResourcesToFilteredDataToShow( - dataWithResources, - resources, - hypothesisAssumptionsList, - formulaConfiguration, - microplanData?.microplanPreview?.userEditedResources ? microplanData?.microplanPreview?.userEditedResources : [], - t - ); - let indexOfFeatureInDataWithResources = dataWithResources?.[0]?.indexOf("feature"); - keys.push(...resources); - dataWithResources = dataWithResources.map((item, index) => { - if (index === 0) return item; - let newProperties = {}; - for (const e of keys) { - if (e === "feature") continue; - let index = dataWithResources?.[0]?.indexOf(e); - newProperties[e] = item[index]; - } - let newRow = _.cloneDeep(item); - newRow[indexOfFeatureInDataWithResources] = { ...item[indexOfFeatureInDataWithResources], properties: newProperties }; - return newRow; - }); - } - - // extract dada - var { hierarchyLists, hierarchicalData } = processHierarchyAndData(hierarchy, [dataWithResources]); - if (filterDataOrigin?.boundriesDataOrigin?.includes(fileData?.section)) - setBoundary = { ...setBoundary, [fileData.section]: { hierarchyLists, hierarchicalData } }; - else if (filterDataOrigin?.layerDataOrigin?.includes(fileData?.section)) - setFilter = { ...setFilter, [fileData.section]: { hierarchyLists, hierarchicalData } }; - } - } - } - } - } - - // Set overall data availability - setDataAvailability(dataAvailabilityCheck); - - // Combine boundary and layer data origins - const combineList = [...filterDataOrigin?.boundriesDataOrigin, ...filterDataOrigin?.layerDataOrigin]; - - // Section wise check - if (dataAvailabilityCheck == "true") { - let sectionWiseCheck = true; - combineList.forEach((item) => { - sectionWiseCheck = Object.keys(files).includes(item) && sectionWiseCheck; - }); - if (!sectionWiseCheck) dataAvailabilityCheck = "partial"; // Update data availability if section-wise check fails - } - - // Update data availability based on conditions - if (dataAvailabilityCheck == "initialStage" && (combineList.length === 0 || Object.keys(files).length === 0)) dataAvailabilityCheck = "false"; - switch (dataAvailabilityCheck) { - case "false": - case undefined: - // Set warning toast message for no data to show - setToast({ - state: "warning", - message: t("MAPPING_NO_DATA_TO_SHOW"), - }); - break; - case "partial": - // Set warning toast message for partial data to show - setToast({ - state: "warning", - message: t("MAPPING_PARTIAL_DATA_TO_SHOW"), - }); - break; - } - } else { - setToast({ - state: "error", - message: t("MAPPING_NO_DATA_TO_SHOW"), - }); - } - setDataCompleteness(dataAvailabilityCheck); - setBoundary = calculateAggregateForTreeMicroplanWrapper(setBoundary); - setFilter = calculateAggregateForTreeMicroplanWrapper(setFilter); - setBoundaryData((previous) => ({ ...previous, ...setBoundary })); - setFilterData((previous) => ({ ...previous, ...setFilter })); - setFilterProperties([...filterPropertiesCollector]); - setFilterSelections([...filterPropertiesCollector]); - setFilterPropertyNames([...filterPropertieNameCollector]); - let tempVirtualizationPropertiesCollectorArray = [...virtualizationPropertiesCollector]; - if (tempVirtualizationPropertiesCollectorArray.length !== 0) - setChoroplethProperties([...tempVirtualizationPropertiesCollectorArray, ...(resources ? resources : [])]); -}; - -//prepare geojson to show on the map -const prepareGeojson = (boundaryData, selection, style = {}) => { - if (!boundaryData || Object.keys(boundaryData).length === 0) return []; - let geojsonRawFeatures = []; - if (selection == "ALL") { - for (let data of Object.values(boundaryData)) { - const templist = fetchFeatures(data?.hierarchicalData, selection, [], style); - if (templist?.length !== 0) geojsonRawFeatures = [...geojsonRawFeatures, ...templist]; - } - } else if (Array.isArray(selection)) { - for (let data of Object.values(boundaryData)) { - const templist = fetchFeatures(data?.hierarchicalData, selection, [], style); - if (templist?.length !== 0) geojsonRawFeatures = [...geojsonRawFeatures, ...templist]; - } - } - - return geojsonRawFeatures.filter(Boolean); -}; -const fetchFeatures = (data, parameter = "ALL", outputList = [], addOn = {}) => { - let tempStorage = []; - if (parameter === "ALL") { - // outputList(Object.values(data).flatMap(item=>item?.data?.feature)) - for (let [entityKey, entityValue] of Object.entries(data)) { - if (entityValue?.data?.feature) { - let feature = entityValue.data.feature; - feature.properties["name"] = entityKey; - feature.properties["addOn"] = addOn; - if (entityValue?.children) tempStorage = [...tempStorage, feature, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; - else tempStorage = [...tempStorage, feature]; - } else { - tempStorage = [...tempStorage, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; - } - } - return tempStorage; - } else if (Array.isArray(parameter)) { - for (let [entityKey, entityValue] of Object.entries(data)) { - if (parameter.includes(entityKey) && entityValue && entityValue.data && entityValue.data.feature) { - let feature = entityValue.data.feature; - feature.properties["name"] = entityKey; - feature.properties["addOn"] = addOn; - if (entityValue?.children) tempStorage = [...tempStorage, feature, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; - else tempStorage = [...tempStorage, feature]; - } - if (entityValue?.children) tempStorage = [...tempStorage, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; - } - return tempStorage; - } -}; - -const addChoroplethProperties = (geojson, choroplethProperty, filteredSelection) => { - // Calculate min and max values of the property - const values = geojson.map((feature) => feature.properties[choroplethProperty]).filter((item) => !!item || item === 0) || []; - if (!values || values.length === 0) return []; - const convertedValues = values.map((item) => (!isNaN(item) ? item : 0)); - const minValue = Math.min(...convertedValues); - const maxValue = Math.max(...convertedValues); - - // Create a new geojson object - const newGeojson = geojson.map((feature) => { - const newFeature = { ...feature, properties: { ...feature.properties, addOn: { ...feature.properties.addOn } } }; - let color; - - if (choroplethProperty) { - color = interpolateColor(newFeature.properties[choroplethProperty], minValue, maxValue, MapChoroplethGradientColors); - } - - newFeature.properties.addOn.fillColor = color; - newFeature.properties.addOn.color = "rgba(0, 0, 0, 1)"; - if (!filteredSelection || filteredSelection.length === 0 || filteredSelection.includes(newFeature.properties.name)) { - newFeature.properties.addOn.fillOpacity = 1; - } else { - newFeature.properties.addOn.fillOpacity = 0.4; - newFeature.properties.addOn.opacity = 0.7; - } - - return newFeature; - }); - return newGeojson; -}; - -/** - * filterGeojsons : json - * filterSelection : array - * MapFilters : - */ -const addFilterProperties = (filterGeojsons, filterSelections, filterPropertyNames, iconMapping) => { - try { - if (!filterGeojsons || !iconMapping || !filterSelections) return []; - let newFilterGeojson = []; - filterGeojsons.forEach((item) => { - if (filterPropertyNames && filterPropertyNames.length !== 0 && item.properties) { - let icon; - filterPropertyNames.forEach((name) => { - if (item.properties[name]) { - let temp = item.properties[name]; - if (!filterSelections.includes(temp)) return; - temp = iconMapping?.find((e) => e?.name == temp)?.icon?.marker; - let DynamicIcon = IconCollection?.[temp]; - if (typeof DynamicIcon === "function") { - icon = L.divIcon({ - className: "custom-svg-icon", - html: DynamicIcon({}), - iconAnchor: [25, 50], - }); - newFilterGeojson.push({ ...item, properties: { ...item?.properties, addOn: { ...item?.properties?.addOn, icon: icon } } }); - } else { - icon = DefaultMapMarker({}); - newFilterGeojson.push({ ...item, properties: { ...item?.properties, addOn: { ...item?.properties?.addOn, icon: icon } } }); - } - } - }); - } - return item; - }); - return newFilterGeojson; - } catch (error) { - console.error(error.message); - } -}; - -/** - * map: map - * geojson: geojson - * t: translator - */ - -const addGeojsonToMap = (map, geojson, t) => { - try { - if (!map || !geojson) return false; - const geojsonLayer = L.geoJSON(geojson, { - style: function (feature) { - if (Object.keys(feature.properties.addOn).length !== 0) { - return feature.properties.addOn; - } else { - return { - weight: 2, - opacity: 1, - color: "rgba(176, 176, 176, 1)", - fillColor: "rgb(0,0,0,0)", - // fillColor: choroplethProperty ? color : "rgb(0,0,0,0)", - fillOpacity: 0, - // fillOpacity: choroplethProperty ? (feature?.properties?.style?.fillOpacity ? feature.properties.style.fillOpacity : 0.7) : 0, - }; - } - }, - pointToLayer: function (feature, latlng) { - if (feature.properties.addOn.icon) { - let icon = feature.properties.addOn.icon; - if (icon) { - return L.marker(latlng, { - icon: icon, - }); - } - } - return L.marker(latlng, { - icon: MapMarker(feature.properties.addOn), - }); - }, - onEachFeature: function (feature, layer) { - let popupContent; - popupContent = "
"; - popupContent += ""; - popupContent += - "
" + - feature.properties["name"] + - "
"; - for (let prop in feature.properties) { - if (prop !== "name" && prop !== "addOn" && prop !== "feature") { - let data = !!feature.properties[prop] ? feature.properties[prop] : t("NO_DATA"); - popupContent += - ""; - } - } - popupContent += "
" + - t(prop) + - "" + - data + - "
"; - layer.bindPopup(popupContent, { - minWidth: "28rem", - padding: "0", - }); - // Adjust map here when pop up closes - layer.on("popupclose", function () { - map.fitBounds(geojsonLayer.getBounds()); - }); - layer.on({ - mouseover: function (e) { - const layer = e.target; - if (layer.feature.properties.addOn && !layer.feature.properties.addOn.child) { - return; - } - if (layer.setStyle) - layer.setStyle({ - weight: 2.7, - opacity: 1, - color: "rgba(255, 255, 255, 1)", - }); - // layer.openPopup(); - }, - mouseout: function (e) { - const layer = e.target; - if (layer.feature.properties.addOn && !layer.feature.properties.addOn.child) { - return; - } - if (layer.setStyle) { - if (layer.feature.properties.addOn && Object.keys(layer.feature.properties.addOn).length !== 0) - layer.setStyle({ - ...layer.feature.properties.addOn, - }); - else - layer.setStyle({ - weight: 2, - color: "rgba(176, 176, 176, 1)", - }); - } - // layer.closePopup(); - }, - }); - }, - }); - geojsonLayer.addTo(map); - return geojsonLayer; - } catch (error) { - console.error(error.message); - } -}; - -function interpolateColor(value, minValue, maxValue, colors) { - // Handle case where min and max values are the same - if (minValue === maxValue) { - // Return a default color or handle the case as needed - return colors[0].color; - } - - // Normalize the value to a percentage between 0 and 100 - const percent = !isNaN(value) ? ((value - minValue) / (maxValue - minValue)) * 100 : 0; - // Find the two colors to interpolate between - let lowerColor, upperColor; - for (let i = 0; i < colors.length - 1; i++) { - if (!isNaN(percent) && percent >= colors[i].percent && percent <= colors[i + 1].percent) { - lowerColor = colors[i]; - upperColor = colors[i + 1]; - break; - } - } - // Interpolate between the two colors - const t = (percent - lowerColor.percent) / (upperColor.percent - lowerColor.percent); - return chroma.mix(lowerColor.color, upperColor.color, t, "lab").hex(); -} - -// Find bounds for multiple geojson together -const findBounds = (data, buffer = 0.1) => { - if (!Array.isArray(data) || data.length === 0) { - return null; - } - - // Initialize variables to store bounds - var minLat = Number.MAX_VALUE; - var maxLat = -Number.MAX_VALUE; - var minLng = Number.MAX_VALUE; - var maxLng = -Number.MAX_VALUE; - - // Iterate through the data to find bounds - data.forEach(function (feature) { - if (!feature || !feature.geometry || !feature.geometry.type || !feature.geometry.coordinates) { - return null; - } - - var coords = feature.geometry.coordinates; - var geometryType = feature.geometry.type; - - switch (geometryType) { - case "Point": - var coord = coords; - var lat = coord[1]; - var lng = coord[0]; - minLat = Math.min(minLat, lat); - maxLat = Math.max(maxLat, lat); - minLng = Math.min(minLng, lng); - maxLng = Math.max(maxLng, lng); - break; - case "MultiPoint": - coords.forEach(function (coord) { - var lat = coord[1]; - var lng = coord[0]; - minLat = Math.min(minLat, lat); - maxLat = Math.max(maxLat, lat); - minLng = Math.min(minLng, lng); - maxLng = Math.max(maxLng, lng); - }); - break; - case "LineString": - case "MultiLineString": - case "Polygon": - case "MultiPolygon": - coords.forEach(function (polygons) { - if ((geometryType === "Polygon" || geometryType === "MultiPolygon") && Array.isArray(polygons[0][0])) { - polygons.forEach(function (coordinates) { - coordinates.forEach(function (coord) { - if (!Array.isArray(coord) || coord.length !== 2 || typeof coord[0] !== "number" || typeof coord[1] !== "number") { - return null; - } - - var lat = coord[1]; - var lng = coord[0]; - minLat = Math.min(minLat, lat); - maxLat = Math.max(maxLat, lat); - minLng = Math.min(minLng, lng); - maxLng = Math.max(maxLng, lng); - }); - }); - } else { - polygons.forEach(function (coord) { - if (!Array.isArray(coord) || coord.length !== 2 || typeof coord[0] !== "number" || typeof coord[1] !== "number") { - return null; - } - - var lat = coord[1]; - var lng = coord[0]; - minLat = Math.min(minLat, lat); - maxLat = Math.max(maxLat, lat); - minLng = Math.min(minLng, lng); - maxLng = Math.max(maxLng, lng); - }); - } - }); - break; - default: - return null; - } - }); - - // Check if valid bounds found - if (minLat === Number.MAX_VALUE || maxLat === -Number.MAX_VALUE || minLng === Number.MAX_VALUE || maxLng === -Number.MAX_VALUE) { - return null; - } - // Apply buffer to bounds - minLat -= buffer; - maxLat += buffer; - minLng -= buffer; - maxLng += buffer; - - // Set bounds for the Leaflet map - var bounds = [ - [minLat, minLng], - [maxLat, maxLng], - ]; - - return bounds; -}; - -const filterBoundarySelection = (boundaryData, boundarySelections) => { - if (Object.keys(boundaryData).length === 0 || Object.keys(boundarySelections).length === 0) return []; - let selectionList = []; - Object.values(boundarySelections).forEach((item) => (selectionList = [...selectionList, ...item.map((e) => e.name)])); - let childrenList = []; - const set1 = new Set(selectionList); - selectionList = selectionList.filter((item) => { - const children = findChildren([item], Object.values(boundaryData)?.[0]?.hierarchicalData); - if (children) { - let childrenKeyList = getAllKeys(children); - childrenList = [...childrenList, ...childrenKeyList]; - const nonePresent = childrenKeyList.every((item) => !set1.has(item)); - const allPresent = childrenKeyList.every((item) => set1.has(item)); - return nonePresent ? true : allPresent ? true : false; - } else { - return true; - } - }); - return { filteredSelection: selectionList, childrenList }; -}; - -// Recursive function to extract all keys -const getAllKeys = (obj, keys = []) => { - for (let [key, value] of Object.entries(obj)) { - keys.push(key); - if (value.children) { - getAllKeys(value.children, keys); - } - } - return keys; -}; - -// Remove all layers from the map -const removeAllLayers = (map, layer) => { - if (!map) return; - layer.forEach((layer) => { - map.removeLayer(layer); - }); -}; -// Map-Marker -const MapMarker = (style = {}) => { - return L.divIcon({ - className: "custom-svg-icon", - html: PopulationSvg(style), - iconAnchor: [25, 50], - }); -}; -const DefaultMapMarker = (style = {}) => { - return L.divIcon({ - className: "custom-svg-icon", - html: IconCollection.DefaultMapMarkerSvg(style), - iconAnchor: [25, 50], - }); -}; - -const disableMapInteractions = (map) => { - if (!map) return; - map.dragging.disable(); - map.scrollWheelZoom.disable(); - map.touchZoom.disable(); - map.doubleClickZoom.disable(); - map.boxZoom.disable(); - map.keyboard.disable(); -}; - -const enableMapInteractions = (map) => { - if (!map) return; - map.dragging.enable(); - map.scrollWheelZoom.enable(); - map.touchZoom.enable(); - map.doubleClickZoom.enable(); - map.boxZoom.enable(); - map.keyboard.enable(); -}; - -// Exporting Mapping component -export default Mapping; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js deleted file mode 100644 index 644a1fa3a95..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js +++ /dev/null @@ -1,1292 +0,0 @@ -import { CardLabel, Header, Loader, MultiSelectDropdown, TextInput, Toast } from "@egovernments/digit-ui-components"; -import React, { memo, useCallback, useEffect, useMemo, useState, Fragment, useRef } from "react"; -import { useTranslation } from "react-i18next"; -import { processHierarchyAndData, findParent, fetchDropdownValues } from "../utils/processHierarchyAndData"; -import { CloseButton, ModalHeading } from "./CommonComponents"; -import { EXCEL, GEOJSON, PRIMARY_THEME_COLOR, SHAPEFILE, commonColumn } from "../configs/constants"; -import { Button, LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; -import { tourSteps } from "../configs/tourSteps"; -import { useMyContext } from "../utils/context"; -import { timeLineOptions } from "../configs/timeLineOptions.json"; -import { useNumberFormatter } from "../hooks/useNumberFormatter"; - -const page = "microplanPreview"; - -const MicroplanPreview = ({ - campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, - microplanData, - setMicroplanData, - checkDataCompletion, - setCheckDataCompletion, - currentPage, - pages, - navigationEvent, - setToast, - ...props -}) => { - const { mutate: UpdateMutate } = Digit.Hooks.microplan.useUpdatePlanConfig(); - const userInfo = Digit.SessionStorage.get("User")?.info; - const { id: campaignId = "" } = Digit.Hooks.useQueryParams(); - const { t } = useTranslation(); - const [hypothesisAssumptionsList, setHypothesisAssumptionsList] = useState([]); - const [data, setData] = useState([]); - const [dataToShow, setDataToShow] = useState([]); - const [joinByColumns, setJoinByColumns] = useState([]); - const [validationSchemas, setValidationSchemas] = useState([]); - const [resources, setResources] = useState([]); - const [formulaConfiguration, setFormulaConfiguration] = useState([]); - const [boundarySelections, setBoundarySelections] = useState({}); // state for hierarchy from the data available from uploaded data - const [boundaryData, setBoundaryData] = useState({}); // State for boundary data - // const [toast, setToast] = useState(); - const [modal, setModal] = useState("none"); - const [operatorsObject, setOperatorsObject] = useState([]); - - const [loaderActivation, setLoaderActivation] = useState(false); - - const [userEditedResources, setUserEditedResources] = useState({}); // state to maintain a record of the resources that the user has edited ( boundaryCode : {resource : value}) - const [microplanPreviewAggregates, setMicroplaPreviewAggregates] = useState(); - const { state, dispatch } = useMyContext(); - const [updateHypothesis, setUpdateHypothesis] = useState(false); - //fetch campaign data - const { id = "" } = Digit.Hooks.useQueryParams(); - const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( - { - CampaignDetails: { - tenantId: Digit.ULBService.getCurrentTenantId(), - ids: [id], - }, - }, - { - enabled: !!id, - } - ); - - // request body for boundary hierarchy api - const reqCriteria = { - url: `/boundary-service/boundary-hierarchy-definition/_search`, - params: {}, - body: { - BoundaryTypeHierarchySearchCriteria: { - tenantId: Digit.ULBService.getStateId(), - hierarchyType: campaignData?.hierarchyType, - }, - }, - config: { - enabled: !!campaignData?.hierarchyType, - select: (data) => { - return ( - data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map((item) => ({ - ...item, - parentBoundaryType: item?.parentBoundaryType - ? `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.parentBoundaryType)}` - : null, - boundaryType: `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}`, - })) || {} - ); - }, - }, - }; - const { isLoading: ishierarchyLoading, data: hierarchyRawData } = Digit.Hooks.useCustomAPIHook(reqCriteria); - const hierarchy = useMemo(() => { - return hierarchyRawData?.map((item) => item?.boundaryType); - }, [hierarchyRawData]); - // Set TourSteps - useEffect(() => { - const tourData = tourSteps(t)?.[page] || {}; - if (state?.tourStateData?.name === page) return; - dispatch({ - type: "SETINITDATA", - state: { tourStateData: tourData }, - }); - }, []); - - // UseEffect to extract data on first render - useEffect(() => { - if (microplanData && (microplanData?.ruleEngine || microplanData?.hypothesis)) { - const hypothesisAssumptions = microplanData?.hypothesis || []; - const formulaConfiguration = microplanData?.ruleEngine?.filter((item) => Object.values(item).every((key) => key !== "")) || []; - if (hypothesisAssumptions.length !== 0 && hypothesisAssumptionsList.length === 0) { - setHypothesisAssumptionsList(hypothesisAssumptions); - } - if (formulaConfiguration.length !== 0) { - setFormulaConfiguration(formulaConfiguration); - } - } - if (microplanData?.microplanPreview?.userEditedResources) { - setUserEditedResources(microplanData?.microplanPreview?.userEditedResources); - } - }, []); - - // Fetch and assign MDMS data - useEffect(() => { - if (!state) return; - let UIConfiguration = state?.UIConfiguration; - let schemas = state?.Schemas; - let resourcelist = state?.Resources; - let microplanPreviewAggregatesList = state?.MicroplanPreviewAggregates; - microplanPreviewAggregatesList = microplanPreviewAggregatesList.find((item) => item.campaignType === campaignType)?.data; - if (schemas) setValidationSchemas(schemas); - resourcelist = resourcelist.find((item) => item.campaignType === campaignType)?.data; - if (resourcelist) setResources(resourcelist); - if (UIConfiguration) { - const joinWithColumns = UIConfiguration.find((item) => item.name === "microplanPreview")?.joinWithColumns; - setJoinByColumns(joinWithColumns); - } - let temp; - if (UIConfiguration) temp = UIConfiguration.find((item) => item.name === "ruleConfigure"); - if (temp?.ruleConfigureOperators) { - setOperatorsObject(temp.ruleConfigureOperators); - } - if (microplanPreviewAggregatesList) setMicroplaPreviewAggregates(microplanPreviewAggregatesList); - }, []); - - // UseEffect for checking completeness of data before moveing to next section - useEffect(() => { - if (!dataToShow || checkDataCompletion !== "true" || !setCheckDataCompletion) return; - let check = filterObjects(hypothesisAssumptionsList, microplanData?.hypothesis); - if (check.length === 0) { - if (navigationEvent?.name === "next") return setModal("confirm-microplan-generation"); - return createMicroplan(false); - } - setModal("confirm-apply-changed-hypothesis"); - }, [checkDataCompletion]); - - // check if data has changed or not - const updateData = useCallback( - (doPerform) => { - // Update the microplan data with selected hierarchy and resources - // This function also handles setting the completion check based on the action to be performed - if (!setMicroplanData) return; - try { - let tempData = filterMicroplanDataToShowWithHierarchySelection(data, {}, hierarchy); - // Adding resources to the data we need to show - tempData = Digit.Utils.microplan.addResourcesToFilteredDataToShow( - tempData, - resources, - hypothesisAssumptionsList, - formulaConfiguration, - userEditedResources, - t - ); - setMicroplanData((previous) => ({ - ...previous, - microplanPreview: { - previewData: tempData, - userEditedResources, - }, - })); - if (doPerform) { - return setCheckDataCompletion("perform-action"); - } - setCheckDataCompletion("false"); - } catch (error) { - console.error("Failed to update data:", error); - } - }, - [ - resources, - boundarySelections, - hierarchy, - hypothesisAssumptionsList, - formulaConfiguration, - userEditedResources, - setMicroplanData, - setCheckDataCompletion, - ] - ); - - const cancelUpdateData = useCallback(() => { - setUpdateHypothesis(false); - setModal("confirm-microplan-generation"); - }, [setCheckDataCompletion, setModal]); - - useEffect(() => { - if (boundarySelections && Object.values(boundarySelections).every((item) => item.length === 0) && hierarchy) { - let tempBoundarySelection = {}; - for (const item of hierarchy) { - tempBoundarySelection[item] = []; - } - setBoundarySelections(tempBoundarySelection); - } - }, [hierarchy]); - - // UseEffect to add a event listener for keyboard - useEffect(() => { - window.addEventListener("keydown", handleKeyPress); - - return () => window.removeEventListener("keydown", handleKeyPress); - }, [modal]); - - const handleKeyPress = (event) => { - // if (modal !== "upload-guidelines") return; - if (["x", "Escape"].includes(event.key)) { - // Perform the desired action when "x" or "esc" is pressed - setCheckDataCompletion("false"); - setModal("none"); - } - }; - - const cancleNavigation = () => { - if (navigationEvent?.name !== "next") setCheckDataCompletion("false"); - setModal("none"); - }; - - const createMicroplan = useCallback( - (doCreation) => { - if (!hypothesisAssumptionsList || !setMicroplanData) return; - const updateDataWrapper = () => { - if (doCreation || navigationEvent?.name !== "next") { - return updateData(true); - } - updateData(false); - }; - const setCheckDataCompletionWrapper = (value) => { - if (!doCreation) { - return setCheckDataCompletion("false"); - } - setCheckDataCompletion(value); - }; - const microData = updateHypothesis ? updateMicroplanData(hypothesisAssumptionsList) : microplanData; - setLoaderActivation(true); - updateHyothesisAPICall( - microData, - setMicroplanData, - operatorsObject, - microData?.microplanDetails?.name, - campaignId, - UpdateMutate, - setToast, - updateDataWrapper, - setLoaderActivation, - doCreation && navigationEvent?.name === "next" ? "GENERATED" : "DRAFT", - cancleNavigation, - state, - campaignType, - navigationEvent, - setCheckDataCompletionWrapper, - t - ); - - setModal("none"); - }, - [ - hypothesisAssumptionsList, - setMicroplanData, - operatorsObject, - campaignId, - UpdateMutate, - setToast, - updateData, - setLoaderActivation, - navigationEvent, - t, - ] - ); - - const updateMicroplanData = useCallback( - (hypothesisAssumptionsList) => { - let microData = {}; - setMicroplanData((previous) => { - microData = { ...previous, hypothesis: hypothesisAssumptionsList }; - return microData; - }); - return microData; - }, - [setMicroplanData] - ); - - // Set microplan preview data - useEffect(() => { - if (data?.length !== 0 || !hierarchyRawData || !hierarchy || validationSchemas?.length === 0) return; - - let combinedData = fetchMicroplanPreviewData(campaignType, microplanData, validationSchemas, hierarchy); - // process and form hierarchy - if (combinedData && hierarchy) { - var { hierarchyLists, hierarchicalData } = processHierarchyAndData(hierarchyRawData, [combinedData]); - setBoundaryData({ Microplan: { hierarchyLists, hierarchicalData } }); - } - if (combinedData) { - setData(combinedData); - setDataToShow(combinedData); - } - }, [hierarchy, hierarchyRawData, microplanData]); - - useEffect(() => { - if (!boundarySelections && !resources) return; - let tempData = filterMicroplanDataToShowWithHierarchySelection(data, boundarySelections, hierarchy); - // Adding resources to the data we need to show - tempData = Digit.Utils.microplan.addResourcesToFilteredDataToShow( - tempData, - resources, - hypothesisAssumptionsList, - formulaConfiguration, - userEditedResources, - t - ); - setDataToShow(tempData); - setMicroplanData((previous) => ({ ...previous, microplanPreview: { ...previous.microplanPreview, previewData: tempData, userEditedResources } })); - }, [boundarySelections, resources, hypothesisAssumptionsList, userEditedResources]); - - if (isCampaignLoading || ishierarchyLoading) { - return ( -
- -
- ); - } - - return ( - <> -
-
-

{t(campaignData?.campaignName)}

-
{t(microplanData?.microplanDetails?.name)}
-

{t("MICROPLAN_PREVIEW_CREATE_BY", { username: userInfo?.name })}

-
-
-
- -
-
- -
-
-

{t("MICROPLAN_PREVIEW_HYPOTHESIS_HEADING")}

-

{t("MICROPLAN_PREVIEW_HYPOTHESIS_INSTRUCTIONS")}

- -
-
- {dataToShow?.length != 0 ? ( - - ) : ( -
{t("NO_DATA_AVAILABLE")}
- )} -
-
- {modal === "confirm-apply-changed-hypothesis" && ( - } - actionCancelLabel={t("YES")} - actionCancelOnSubmit={() => { - setUpdateHypothesis(true); - setModal("confirm-microplan-generation"); - }} - actionSaveLabel={t("NO")} - actionSaveOnSubmit={cancelUpdateData} - formId="modal-action" - > - - - )} - {modal === "confirm-microplan-generation" && ( - } - actionCancelLabel={t("YES")} - actionCancelOnSubmit={() => createMicroplan(true)} - actionSaveLabel={t("NO")} - actionSaveOnSubmit={() => createMicroplan(false)} - formId="modal-action" - > -
-

{t("INSTRUCTIONS_MICROPLAN_GENERATION_CONFIRMATION")}

-
-
- )} -
- {loaderActivation && } - - ); -}; - -const HypothesisValues = memo(({ boundarySelections, hypothesisAssumptionsList, setHypothesisAssumptionsList, setToast, setModal, t }) => { - const [tempHypothesisList, setTempHypothesisList] = useState(hypothesisAssumptionsList || []); - const { valueChangeHandler } = useHypothesis(tempHypothesisList, hypothesisAssumptionsList); - const contentRef = useRef(null); - const [isScrollable, setIsScrollable] = useState(false); - - const applyNewHypothesis = () => { - if (tempHypothesisList.some((item) => item.active && parseFloat(item.value) === 0)) { - setToast({ state: "error", message: t("ERROR_HYPOTHESIS_VALUE_SHOULD_NOT_BE_ZERO") }); - return; - } - if (Object.keys(boundarySelections).length !== 0 && Object.values(boundarySelections)?.every((item) => item?.length !== 0)) - return setToast({ state: "error", message: t("HYPOTHESIS_CAN_BE_ONLY_APPLIED_ON_ADMIN_LEVEL_ZORO") }); - setHypothesisAssumptionsList(tempHypothesisList); - }; - const checkScrollbar = () => { - if (contentRef.current) { - setIsScrollable(contentRef.current.scrollHeight > contentRef.current.clientHeight); - } - }; - - useEffect(() => { - // Initial check - checkScrollbar(); - - // Check on resize - window.addEventListener("resize", checkScrollbar); - - // Cleanup event listeners on component unmount - return () => { - window.removeEventListener("resize", checkScrollbar); - }; - }, []); - - useEffect(() => { - const content = contentRef.current; - content.addEventListener("scroll", checkScrollbar); - - return () => { - content.removeEventListener("scroll", checkScrollbar); - }; - }, [contentRef]); - - return ( -
-
- {tempHypothesisList - .filter((item) => item?.active) - ?.filter((item) => item.key !== "") - .map((item, index) => ( -
-

{t(item?.key)}

-
- {/* Dropdown for boundaries */} - - valueChangeHandler({ item, newValue: value?.target?.value }, setTempHypothesisList, boundarySelections, setToast, t) - } - disable={false} - /> -
-
- ))} -
-
-
-
- ); -}); - -const BoundarySelection = memo(({ boundarySelections, setBoundarySelections, boundaryData, hierarchy, t }) => { - const [processedHierarchy, setProcessedHierarchy] = useState([]); - const [isLoading, setIsLoading] = useState(false); - const [changedBoundaryType, setChangedBoundaryType] = useState(""); - - // Filtering out dropdown values - useEffect(() => { - if (!boundaryData || !hierarchy) return; - - let processedHierarchyTemp = fetchDropdownValues( - boundaryData, - processedHierarchy.length !== 0 ? processedHierarchy : hierarchy, - boundarySelections, - changedBoundaryType - ); - setProcessedHierarchy(processedHierarchyTemp); - setIsLoading(false); - }, [boundaryData, hierarchy, boundarySelections]); - - return ( -
- {isLoading && } - {processedHierarchy?.map((item, index) => ( -
- {t(item?.boundaryType)} - {item?.parentBoundaryType === null ? ( - 5 ? { height: "13.75rem" } : {}} - type={"multiselectdropdown"} - t={t} - options={item?.dropDownOptions || []} - optionsKey="name" - addSelectAllCheck={true} - onSelect={(e) => { - setChangedBoundaryType(item?.boundaryType); - Digit.Utils.microplan.handleSelection( - e, - item?.boundaryType, - boundarySelections, - hierarchy, - setBoundarySelections, - boundaryData, - setIsLoading - ); - }} - /> - ) : ( - 5 ? { height: "13.75rem" } : {}} - type={"multiselectdropdown"} - t={t} - options={Digit.Utils.microplan.processDropdownForNestedMultiSelect(item?.dropDownOptions) || []} - optionsKey="name" - addSelectAllCheck={true} - onSelect={(e) => { - setChangedBoundaryType(item?.boundaryType); - Digit.Utils.microplan.handleSelection( - e, - item?.boundaryType, - boundarySelections, - hierarchy, - setBoundarySelections, - boundaryData, - setIsLoading - ); - }} - variant="nestedmultiselect" - /> - )} -
- ))} -
- ); -}); - -const DataPreview = memo( - ({ previewData, isCampaignLoading, ishierarchyLoading, resources, userEditedResources, setUserEditedResources, modal, setModal, data, t }) => { - if (!previewData) return; - const [tempResourceChanges, setTempResourceChanges] = useState(userEditedResources); - const [selectedRow, setSelectedRow] = useState(); - const conmmonColumnIndex = useMemo(() => { - return previewData?.[0]?.indexOf(commonColumn); - }, [previewData]); - if (isCampaignLoading || ishierarchyLoading) { - return ( -
- -
- ); - } - - const rowClick = useCallback((rowIndex) => { - setSelectedRow(rowIndex); - setModal("change-preview-data"); - }, []); - - const finaliseRowDataChange = () => { - setUserEditedResources(tempResourceChanges); - setModal("none"); - setSelectedRow(undefined); - }; - - const modalCloseHandler = () => { - setModal("none"); - setSelectedRow(undefined); - }; - - return ( -
-
- - - - {previewData[0].map((header, columnIndex) => ( - - ))} - - - - {previewData.slice(1).map((rowData, rowIndex) => { - const rowDataList = Object.values(previewData[0]).map((header, cellIndex) => ( - - )); - return ( - { - rowClick(rowIndex + 1); - }} - // style={{...(userEditedResources?.[rowData?.[conmmonColumnIndex]] && Object.keys(userEditedResources?.[rowData?.[conmmonColumnIndex]]).length !==0 - // ? { borderL: "1px solid rgba(244, 119, 56, 0.12)" } - // : {}),}} - > - {rowDataList} - - ); - })} - -
- {t(header)} -
- {cellIndex === 0 && - userEditedResources?.[rowData?.[conmmonColumnIndex]] && - Object.keys(userEditedResources?.[rowData?.[conmmonColumnIndex]]).length !== 0 &&
} - - {rowData[cellIndex] || rowData[cellIndex] === 0 ? rowData[cellIndex] : t("NO_DATA")} -
-
- {modal === "change-preview-data" && ( -
- } - headerBarEnd={} - actionCancelLabel={t("CANCLE")} - actionCancelOnSubmit={modalCloseHandler} - actionSaveLabel={t("SAVE_CHANGES")} - actionSaveOnSubmit={finaliseRowDataChange} - formId="modal-action" - > - - -
- )} -
- ); - } -); - -// get schema for validation -const getRequiredColumnsFromSchema = (campaignType, microplanData, schemas) => { - if (!schemas || !microplanData || !microplanData?.upload || !campaignType) return []; - let sortData = []; - if (microplanData?.upload) { - for (const value of microplanData.upload) { - if (value.active && value?.error === null) { - sortData.push({ section: value.section, fileType: value?.fileType }); - } - } - } - const filteredSchemas = - schemas?.filter((schema) => { - if (schema.campaignType) { - return schema.campaignType === campaignType && sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); - } - return sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); - }) || []; - - let finalData = []; - let tempdata; - // tempdata = filteredSchemas - // ?.map((item) => - // Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => { - // if (value?.isLocationDataColumns) { - // acc.push(key); - // } - // return acc; - // }, []) - // ) - // .flatMap((item) => item) - // .filter((item) => !!item); - // finalData = [...finalData, ...tempdata]; - tempdata = filteredSchemas - ?.map((item) => - Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.isRuleConfigureInputs && value?.toShowInMicroplanPreview) { - acc.push(key); - } - return acc; - }, []) - ) - .flat() - .filter((item) => !!item); - finalData = [...finalData, ...tempdata]; - - tempdata = filteredSchemas - ?.map((item) => - Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.toShowInMicroplanPreview) acc.push(key); - return acc; - }, []) - ) - .flat() - .filter((item) => !!item); - finalData = [...finalData, ...tempdata]; - return [...new Set(finalData)]; -}; - -/** - * Combines two datasets based on a common column, duplicating rows from data1 for each matching row in data2. - * The final dataset's columns and their order are determined by listOfColumnsNeededInFinalData. - * If data2 is not provided, rows from data1 are included with null values for missing columns. - */ -const innerJoinLists = (data1, data2, commonColumnName, listOfColumnsNeededInFinalData) => { - // Error handling: Check if data1 array is provided - if (!Array.isArray(data1)) { - throw new Error("The first data input must be an array."); - } - - // Error handling: Check if common column name is provided - if (typeof commonColumnName !== "string") { - throw new Error("Common column name must be a string."); - } - - // Error handling: Check if listOfColumnsNeededInFinalData is provided and is an array - if (!Array.isArray(listOfColumnsNeededInFinalData)) { - throw new Error("listOfColumnsNeededInFinalData must be an array."); - } - - // Find the index of the common column in the first dataset - const commonColumnIndex1 = data1[0].indexOf(commonColumnName); - - // Error handling: Check if common column exists in the first dataset - if (commonColumnIndex1 === -1) { - throw new Error(`Common column "${commonColumnName}" not found in the first dataset.`); - } - - let commonColumnIndex2 = -1; - const data2Map = new Map(); - if (data2) { - // Find the index of the common column in the second dataset - commonColumnIndex2 = data2[0].indexOf(commonColumnName); - - // Error handling: Check if common column exists in the second dataset - if (commonColumnIndex2 === -1) { - throw new Error(`Common column "${commonColumnName}" not found in the second dataset.`); - } - - // Create a map for the second dataset for quick lookup by the common column value - for (let i = 1; i < data2.length; i++) { - const row = data2[i]; - const commonValue = row[commonColumnIndex2]; - if (!data2Map.has(commonValue)) { - data2Map.set(commonValue, []); - } - data2Map.get(commonValue).push(row); - } - } - - // Determine the headers for the final combined dataset based on listOfColumnsNeededInFinalData - const combinedHeaders = listOfColumnsNeededInFinalData.filter((header) => data1[0].includes(header) || (data2 && data2[0].includes(header))); - - // Combine rows - const combinedData = [combinedHeaders]; - const addedCommonValues = new Set(); - for (let i = 1; i < data1.length; i++) { - const row1 = data1[i]; - const commonValue = row1[commonColumnIndex1]; - const rows2 = data2 ? data2Map.get(commonValue) || [[null]] : [[null]]; // Handle missing common values with a placeholder array of null - - // Check if rows2 is the placeholder array - const isPlaceholderArray = rows2.length === 1 && rows2[0].every((value) => value === null); - - // Create combined rows for each row in data2 - if (isPlaceholderArray) { - // If no corresponding row found in data2, use row from data1 with null values for missing columns - const combinedRow = combinedHeaders.map((header) => { - const index1 = data1[0].indexOf(header); - return index1 !== -1 ? row1[index1] : null; - }); - combinedData.push(combinedRow); - } else { - // If corresponding rows found in data2, combine each row from data2 with row from data1 - rows2.forEach((row2) => { - const combinedRow = combinedHeaders.map((header) => { - const index1 = data1[0].indexOf(header); - const index2 = data2 ? data2[0].indexOf(header) : -1; - return index1 !== -1 ? row1[index1] : index2 !== -1 ? row2[index2] : null; - }); - combinedData.push(combinedRow); - }); - } - addedCommonValues.add(commonValue); - } - // Add rows from data2 that do not have a matching row in data1 - if (data2) { - for (let i = 1; i < data2.length; i++) { - const row2 = data2[i]; - const commonValue = row2[commonColumnIndex2]; - if (!addedCommonValues.has(commonValue)) { - const combinedRow = combinedHeaders.map((header) => { - // const index1 = data1[0].indexOf(header); - const index2 = data2[0].indexOf(header); - return index2 !== -1 ? row2[index2] : null; - }); - combinedData.push(combinedRow); - } - } - } - - return combinedData; -}; - -// function to filter the microplan data with respect to the hierarchy selected by the user -const filterMicroplanDataToShowWithHierarchySelection = (data, selections, hierarchy, hierarchyIndex = 0) => { - if (!selections || selections?.length === 0) return data; - if (hierarchyIndex >= hierarchy?.length) return data; - const filteredHirarchyLevelList = selections?.[hierarchy?.[hierarchyIndex]]?.map((item) => item?.name); - if (!filteredHirarchyLevelList || filteredHirarchyLevelList?.length === 0) return data; - const columnDataIndexForHierarchyLevel = data?.[0]?.indexOf(hierarchy?.[hierarchyIndex]); - if (columnDataIndexForHierarchyLevel === -1) return data; - const levelFilteredData = data.filter((item, index) => { - if (index === 0) return true; - if (item?.[columnDataIndexForHierarchyLevel] && filteredHirarchyLevelList.includes(item?.[columnDataIndexForHierarchyLevel])) return true; - return false; - }); - return filterMicroplanDataToShowWithHierarchySelection(levelFilteredData, selections, hierarchy, hierarchyIndex + 1); -}; - -const AppplyChangedHypothesisConfirmation = ({ newhypothesisList, hypothesisList, t }) => { - const data = filterObjects(newhypothesisList, hypothesisList); - return ( -
-
-

{t("INSTRUCTION_PROCEED_WITH_NEW_HYPOTHESIS")}

-
- - {t("MICROPLAN_PREVIEW_HYPOTHESIS")} - -
- - - - - - - - - - {data?.map((row, index) => ( - - - - - - ))} - -
{t("KEYS")}{t("OLD_VALUE")}{t("NEW_VALUE")}
{t(row?.key)}{t(row?.oldValue)}{t(row?.value)}
-
-
- ); -}; - -function filterObjects(arr1, arr2) { - if (!arr1 || !arr2) return []; - // Create a new array to store the filtered objects - let filteredArray = []; - - // Iterate through the first array - arr1.forEach((obj1) => { - // Find the corresponding object in the second array - let obj2 = _.cloneDeep(arr2.find((item) => item.key === obj1.key)); - - // If the object with the same key is found in the second array and their values are the same - if (obj2 && obj1.value !== obj2.value) { - // Push the object to the filtered array - obj1.oldValue = obj2.value; - filteredArray.push(obj1); - } - }); - - return filteredArray; -} - -const useHypothesis = (tempHypothesisList, hypothesisAssumptionsList) => { - // Handles the change in hypothesis value - const valueChangeHandler = (e, setTempHypothesisList, boundarySelections, setToast, t) => { - // Checks it the boundary filters at at root level ( given constraints ) - if (Object.keys(boundarySelections).length !== 0 && Object.values(boundarySelections)?.every((item) => item?.length !== 0)) - return setToast({ state: "error", message: t("HYPOTHESIS_CAN_BE_ONLY_APPLIED_ON_ADMIN_LEVEL_ZORO") }); - - // validating user input - if (e?.newValue.includes("+") || e?.newValue.includes("e")) return; - if ((e?.newValue < 0 || e.newValue > 10000000000) && e?.newValue !== "") return; - let value; - const decimalIndex = e.newValue.indexOf("."); - if (decimalIndex !== -1) { - const numDecimals = e.newValue.length - decimalIndex - 1; - if (numDecimals <= 2) { - value = e.newValue; - } else if (numDecimals > 2) { - value = e.newValue.substring(0, decimalIndex + 3); - } - } else value = parseFloat(e.newValue); - value = !isNaN(value) ? value : ""; - - // update the state with user input - let newhypothesisEntityIndex = hypothesisAssumptionsList.findIndex((item) => item?.id === e?.item?.id); - let unprocessedHypothesisList = _.cloneDeep(tempHypothesisList); - if (newhypothesisEntityIndex !== -1) unprocessedHypothesisList[newhypothesisEntityIndex].value = value; - setTempHypothesisList(unprocessedHypothesisList); - }; - - return { - valueChangeHandler, - }; -}; - -const updateHyothesisAPICall = async ( - microplanData, - setMicroplanData, - operatorsObject, - MicroplanName, - campaignId, - UpdateMutate, - setToast, - updateData, - setLoaderActivation, - status, - cancleNavigation, - state, - campaignType, - navigationEvent, - setCheckDataCompletion, - t -) => { - try { - let body = Digit.Utils.microplan.mapDataForApi(microplanData, operatorsObject, MicroplanName, campaignId, status); - body.PlanConfiguration["id"] = microplanData?.planConfigurationId; - body.PlanConfiguration["auditDetails"] = microplanData?.auditDetails; - if (!Digit.Utils.microplan.planConfigRequestBodyValidator(body, state, campaignType)) { - setLoaderActivation(false); - if (navigationEvent.name === "next") { - setToast({ - message: t("ERROR_DATA_NOT_SAVED"), - state: "error", - }); - setCheckDataCompletion("false"); - } else setCheckDataCompletion("perform-action"); - return; - } - await UpdateMutate(body, { - onSuccess: async (data) => { - updateData(); - setLoaderActivation(false); - setMicroplanData((previous) => ({ ...previous, microplanStatus: status })); - }, - onError: (error, variables) => { - setLoaderActivation(false); - setToast({ - message: t("ERROR_DATA_NOT_SAVED"), - state: "error", - }); - if (status === "GENERATED") cancleNavigation(); - else updateData(); - }, - }); - } catch (error) { - setLoaderActivation(false); - setToast({ - message: t("ERROR_DATA_NOT_SAVED"), - state: "error", - }); - } -}; - -// get schema for validation -const getSchema = (campaignType, type, section, schemas) => { - return schemas.find((schema) => - schema.campaignType - ? schema.campaignType === campaignType && schema.type === type && schema.section === section - : schema.type === type && schema.section === section - ); -}; - -const fetchMicroplanPreviewData = (campaignType, microplanData, validationSchemas, hierarchy) => { - try { - //Decide columns to take and their sequence - const getfilteredSchemaColumnsList = () => { - let filteredSchemaColumns = getRequiredColumnsFromSchema(campaignType, microplanData, validationSchemas) || []; - if (hierarchy) filteredSchemaColumns = [...hierarchy, commonColumn, ...filteredSchemaColumns.filter((e) => e !== commonColumn)]; - return filteredSchemaColumns; - }; - let filteredSchemaColumns = getfilteredSchemaColumnsList(); - const fetchedData = fetchMicroplanData(microplanData, campaignType, validationSchemas); - // Perform inner joins using reduce - const dataAfterJoins = fetchedData.reduce((accumulator, currentData, index) => { - if (index === 0) { - return innerJoinLists(currentData, null, commonColumn, filteredSchemaColumns); - } else { - return innerJoinLists(accumulator, currentData, commonColumn, filteredSchemaColumns); - } - }, null); - return dataAfterJoins; - } catch (error) { - console.error("Error in fetch microplan data: ", error.message); - } -}; - -const fetchMicroplanData = (microplanData, campaignType, validationSchemas) => { - if (!microplanData) return []; - - let combinesDataList = []; - // Check if microplanData and its upload property exist - if (microplanData?.upload) { - let files = microplanData?.upload; - // Loop through each file in the microplan upload - for (let fileData of files) { - const schema = getSchema(campaignType, fileData.fileType, fileData.templateIdentifier, validationSchemas); - - // Check if the file is not part of boundary or layer data origins - if (!fileData.active || !fileData.fileType || !fileData?.section) continue; // Skip files with errors or missing properties - - // Check if file contains latitude and longitude columns - if (fileData?.data) { - // Check file type and update data availability accordingly - switch (fileData?.fileType) { - case EXCEL: { - // extract dada - const mergedData = schema?.template?.hierarchyLevelWiseSheets - ? Object.values(fileData?.data).flatMap((data) => data) - : Object.values(fileData?.data)?.[0]; - - let commonColumnIndex = mergedData?.[0]?.indexOf(commonColumn); - - let uniqueEntries; - if (commonColumnIndex !== undefined) - uniqueEntries = schema?.template?.hierarchyLevelWiseSheets - ? Array.from(new Map(mergedData.map((entry) => [entry[commonColumnIndex], entry])).values()) - : mergedData; - if (uniqueEntries) combinesDataList.push(uniqueEntries); - break; - } - case GEOJSON: - case SHAPEFILE: { - // Extract keys from the first feature's properties - var keys = Object.keys(fileData?.data.features[0].properties); - - // Extract corresponding values for each feature - const values = fileData?.data?.features.map((feature) => { - // list with features added to it - const temp = keys.map((key) => { - // if (feature.properties[key] === "") { - // return null; - // } - return feature.properties[key]; - }); - return temp; - }); - - let data = [keys, ...values]; - combinesDataList.push(data); - } - } - } - } - } - return combinesDataList; -}; - -const EditResourceData = ({ previewData, selectedRow, resources, tempResourceChanges, setTempResourceChanges, data, t }) => { - const conmmonColumnData = useMemo(() => { - const index = previewData?.[0]?.indexOf(commonColumn); - if (index == -1) return; - return previewData?.[selectedRow]?.[index]; - }, [previewData]); - - const valueChangeHandler = (item, value) => { - if (!conmmonColumnData) return; - if (isNaN(value) || (!isFinite(value) && value !== "")) return; - let changedDataAgainstBoundaryCode = tempResourceChanges?.[conmmonColumnData] || {}; - changedDataAgainstBoundaryCode[item] = value == "" ? undefined : parseFloat(value); - setTempResourceChanges((previous) => ({ ...previous, [conmmonColumnData]: changedDataAgainstBoundaryCode })); - }; - - return ( -
- - - - - - - - - - {data[0].map((item) => { - let index = data?.[0]?.indexOf(item); - if (index === -1) return; - const currentData = data?.[selectedRow]?.[index]; - return ( - - - - - - ); - })} - {resources.map((item) => { - let index = previewData?.[0]?.indexOf(item); - if (index === -1) return; - const currentData = previewData?.[selectedRow]?.[index]; - - return ( - - - - - - ); - })} - -
{t("COLUMNS")}{t("OLD_VALUE")}{t("NEW_VALUE")}
-

{t(item)}

-
-

{currentData || t("NO_DATA")}

-
- -
-

{t(item)}

-
-

{currentData || t("NO_DATA")}

-
- valueChangeHandler(item, value.target.value)} - /> -
-
- ); -}; - -const Aggregates = memo(({ microplanPreviewAggregates, dataToShow, NumberFormatMappingForTranslation, t }) => { - const { formatNumber } = useNumberFormatter(NumberFormatMappingForTranslation?.reduce((acc, obj) => Object.assign(acc, obj), {})); - - if (!microplanPreviewAggregates) return null; - return ( -
- {microplanPreviewAggregates.map((item, index) => { - const aggregate = calculateAggregateValue(item, dataToShow); - return ( -
-

{isNaN(parseInt(aggregate)) ? 0 : formatNumber(parseInt(aggregate))}

-

{typeof item === "object" && item.name ? t(item.name) : t(item)}

-
- ); - })} -
- ); -}); - -const calculateAggregateValue = (aggregateName, dataToShow) => { - if (!aggregateName || !dataToShow || dataToShow.length === 0) return; - let aggregateNameList = aggregateName; - if (typeof aggregateName !== "object") aggregateNameList = { name: aggregateName, entities: [aggregateName] }; - let aggregateData = 0; - if (aggregateNameList) - for (const item of aggregateNameList.entities) { - const columnIndex = dataToShow?.[0].indexOf(item); - dataToShow.slice(1).forEach((e) => { - if (e?.[columnIndex]) aggregateData = aggregateData + Number(e[columnIndex]); - }); - } - return aggregateData; -}; - -export default MicroplanPreview; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js deleted file mode 100644 index 316eef6113c..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js +++ /dev/null @@ -1,2166 +0,0 @@ -import React, { useState, useEffect, useMemo, Fragment, useCallback } from "react"; -import { useTranslation } from "react-i18next"; -import { LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; -import * as Icons from "@egovernments/digit-ui-svg-components"; -import { FileUploader } from "react-drag-drop-files"; -import { convertJsonToXlsx } from "../utils/jsonToExcelBlob"; -import { parseXlsxToJsonMultipleSheets } from "../utils/exceltojson"; -import { ModalWrapper } from "./Modal"; -import { checkForErrorInUploadedFileExcel } from "../utils/excelValidations"; -import { geojsonPropetiesValidation, geojsonValidations } from "../utils/geojsonValidations"; -import JSZip from "jszip"; -import { SpatialDataPropertyMapping } from "./resourceMapping"; -import shp from "shpjs"; -import { JsonPreviewInExcelForm } from "./JsonPreviewInExcelForm"; -import { ButtonType1, ButtonType2, CloseButton, ModalHeading } from "./CommonComponents"; -import { InfoButton, InfoCard, Loader, Toast } from "@egovernments/digit-ui-components"; -import { - ACCEPT_HEADERS, - BOUNDARY_DATA_SHEET, - EXCEL, - FACILITY_DATA_SHEET, - FILE_STORE, - GEOJSON, - LOCALITY, - PRIMARY_THEME_COLOR, - SCHEMA_PROPERTIES_PREFIX, - SHAPEFILE, - SHEET_COLUMN_WIDTH, - SHEET_PASSWORD, - commonColumn, -} from "../configs/constants"; -import { tourSteps } from "../configs/tourSteps"; -import { useMyContext } from "../utils/context"; -import { v4 as uuidv4 } from "uuid"; -import { addBoundaryData, createTemplate, fetchBoundaryData, filterBoundaries } from "../utils/createTemplate"; -import XLSX from "xlsx"; -import ExcelJS from "exceljs"; -import { - freezeSheetValues, - freezeWorkbookValues, - hideUniqueIdentifierColumn, - performUnfreezeCells, - unfreezeColumnsByHeader, - updateFontNameToRoboto, -} from "../utils/excelUtils"; -const page = "upload"; - -const Upload = ({ - MicroplanName = "default", - campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, - microplanData, - setMicroplanData, - checkDataCompletion, - setCheckDataCompletion, - currentPage, - pages, - navigationEvent, - setToast, -}) => { - const { t } = useTranslation(); - - // States - const [editable, setEditable] = useState(true); - const [sections, setSections] = useState([]); - const [selectedSection, setSelectedSection] = useState(null); - const [modal, setModalState] = useState("none"); - const [selectedFileType, setSelectedFileType] = useState(null); - const [dataPresent, setDataPresent] = useState(false); - const [dataUpload, setDataUpload] = useState(false); - const [loader, setLoader] = useState(false); - const [fileData, setFileData] = useState(); - // const [toast, setToast] = useState(); - const [uploadedFileError, setUploadedFileError] = useState(); - const [fileDataList, setFileDataList] = useState([]); - const [validationSchemas, setValidationSchemas] = useState([]); - const [template, setTemplate] = useState([]); - const [resourceMapping, setResourceMapping] = useState([]); - const [previewUploadedData, setPreviewUploadedData] = useState(); - const { state, dispatch } = useMyContext(); - - //fetch campaign data - const { id = "" } = Digit.Hooks.useQueryParams(); - const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( - { - CampaignDetails: { - tenantId: Digit.ULBService.getCurrentTenantId(), - ids: [id], - }, - }, - { - enabled: !!id, - } - ); - - // request body for boundary hierarchy api - const reqCriteria = { - url: `/boundary-service/boundary-hierarchy-definition/_search`, - params: {}, - body: { - BoundaryTypeHierarchySearchCriteria: { - tenantId: Digit.ULBService.getCurrentTenantId(), - hierarchyType: campaignData?.hierarchyType, - // hierarchyType: "Microplan", - }, - }, - config: { - enabled: !!campaignData?.hierarchyType, - select: (data) => { - return ( - data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map( - (item) => `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}` - ) || {} - ); - }, - }, - }; - const { isLoading: ishierarchyLoading, data: hierarchy } = Digit.Hooks.useCustomAPIHook(reqCriteria); - // Set TourSteps - useEffect(() => { - const tourData = tourSteps(t)?.[page] || {}; - if (state?.tourStateData?.name === page) return; - dispatch({ - type: "SETINITDATA", - state: { tourStateData: tourData }, - }); - }, [t]); - - const setModal = (modalString) => { - const elements = document.querySelectorAll(".popup-wrap-rest-unfocus"); - elements.forEach((element) => { - element.classList.toggle("popup-wrap-rest-unfocus-active"); - }); - setModalState(modalString); - }; - - // UseEffect for checking completeness of data before moveing to next section - useEffect(() => { - if (!fileDataList || checkDataCompletion !== "true" || !setCheckDataCompletion) return; - // uncomment to activate data change save check - // if (!microplanData?.upload || !_.isEqual(fileDataList, microplanData.upload)) setModal("data-change-check"); - // else - updateData(true); - }, [checkDataCompletion]); - - // UseEffect to store current data - useEffect(() => { - if (!fileDataList || !setMicroplanData) return; - setMicroplanData((previous) => ({ ...previous, upload: fileDataList })); - }, [fileDataList]); - - // check if data has changed or not - const updateData = useCallback( - (check) => { - if (!fileDataList || !setMicroplanData) return; - - // if user has selected a file type and wants to go back to file type selection he/she can click back buttom - const currentSectionIndex = sections.findIndex((item) => item.id === selectedSection.id); - if (!dataPresent) { - if (navigationEvent?.name !== "step") { - if (navigationEvent?.name === "next") { - if (currentSectionIndex < sections.length - 1) { - setSelectedSection(sections[currentSectionIndex + 1]); - setCheckDataCompletion("false"); - return; - } - } else if (navigationEvent?.name === "previousStep") { - if (dataUpload) { - setDataUpload(false); - setSelectedFileType(null); - setCheckDataCompletion("false"); - return; - } - if (currentSectionIndex > 0) { - setSelectedSection(sections[currentSectionIndex - 1]); - setCheckDataCompletion("false"); - return; - } - } - } - } else { - if (navigationEvent?.name === "next") { - if (currentSectionIndex < sections.length - 1) { - setSelectedSection(sections[currentSectionIndex + 1]); - setCheckDataCompletion("false"); - return; - } - } else if (navigationEvent?.name === "previousStep") { - if (currentSectionIndex > 0) { - setSelectedSection(sections[currentSectionIndex - 1]); - setCheckDataCompletion("false"); - return; - } - } - } - - if (check) { - setMicroplanData((previous) => ({ ...previous, upload: fileDataList })); - const valueList = fileDataList ? fileDataList : []; - const sectionCheckList = sections?.filter((item) => item.required); - - if ( - valueList.length !== 0 && - sectionCheckList.every((item) => { - let filteredList = fileDataList?.filter((e) => e.active && e.templateIdentifier === item.id); - if (filteredList?.length === 0) return false; - return filteredList?.every((element) => element?.error === null) && fileDataList && !fileDataList.some((e) => e?.active && e?.error); - }) - ) - setCheckDataCompletion("valid"); - else setCheckDataCompletion("invalid"); - } else { - const valueList = microplanData?.Upload ? Object.values(microplanData?.Upload) : []; - if ( - valueList.length !== 0 && - sectionCheckList.every((item) => - fileDataList?.filter((e) => e.templateIdentifier === item.id)?.every((element) => element.active && element?.error === null) - ) - ) - setCheckDataCompletion("valid"); - else setCheckDataCompletion("invalid"); - } - }, - [fileDataList, setMicroplanData, microplanData, setCheckDataCompletion, dataPresent, dataUpload, navigationEvent] - ); - - // UseEffect to extract data on first render - useEffect(() => { - if (microplanData?.upload) { - setFileDataList(microplanData.upload); - } - - if (pages) { - const previouspage = pages[currentPage?.id - 1]; - if (previouspage?.checkForCompleteness && !microplanData?.status?.[previouspage?.name]) setEditable(false); - else setEditable(true); - } - }, []); - - // UseEffect to add a event listener for keyboard - useEffect(() => { - window.addEventListener("keydown", handleKeyPress); - - return () => window.removeEventListener("keydown", handleKeyPress); - }, [modal, previewUploadedData]); - - const handleKeyPress = (event) => { - // if (modal !== "upload-guidelines") return; - if (["x", "Escape"].includes(event.key)) { - // Perform the desired action when "x" or "esc" is pressed - if (modal === "upload-guidelines") { - setModal("none"); - } - if (previewUploadedData) setPreviewUploadedData(undefined); - } - }; - - // Effect to update sections and selected section when data changes - useEffect(() => { - if (state) { - let uploadSections = state?.UploadConfiguration; - let schemas = state?.Schemas; - let UIConfiguration = state?.UIConfiguration; - if (schemas) setValidationSchemas(schemas); - if (uploadSections) { - setSelectedSection(uploadSections.length > 0 ? uploadSections[0] : null); - setSections(uploadSections); - } - } - }, []); - - // Memoized section options to prevent unnecessary re-renders - const sectionOptions = useMemo(() => { - if (!sections) return []; - return sections.map((item) => ( - e.active && e.templateIdentifier === item.id && !e.error)?.length !== 0} - /> - )); - }, [sections, selectedSection, fileDataList]); - - const showDownloadTemplate = () => { - if (selectedSection?.UploadFileTypes) { - const schema = getSchema(campaignType, selectedFileType?.id, selectedSection.id, validationSchemas); - if (schema?.template?.showTemplateDownload) return true; - } - return false; - }; - - // Handler for when a file type is selected for uplaod - const selectFileTypeHandler = (e) => { - if (selectedSection?.UploadFileTypes) { - const schema = getSchema(campaignType, e.target.name, selectedSection.id, validationSchemas); - setSelectedFileType(selectedSection.UploadFileTypes.find((item) => item.id === e.target.name)); - if (schema?.template?.showTemplateDownload) setModal("upload-modal"); - else UploadFileClickHandler(false); - return; - } - setToast({ - state: "error", - message: t("ERROR_UNKNOWN"), - }); - setLoader(false); - return; - }; - - // Memoized section components to prevent unnecessary re-renders - const sectionComponents = useMemo(() => { - if (!sections) return; - return sections.map((item) => ( - - )); - }, [sections, selectedSection, selectedFileType]); - - // Close model click handler - const closeModal = () => { - setResourceMapping([]); - setModal("none"); - }; - - // handler for show file upload screen - const UploadFileClickHandler = (download = false) => { - if (download) { - downloadTemplateHandler(); - } - setModal("none"); - setDataUpload(true); - }; - - const downloadTemplateHandler = () => { - const downloadParams = { - campaignType, - type: selectedFileType.id, - section: selectedSection.id, - setToast, - campaignData, - hierarchyType: campaignData?.hierarchyType, - Schemas: validationSchemas, - HierarchyConfigurations: state?.HierarchyConfigurations, - setLoader, - hierarchy, - t, - }; - downloadTemplate(downloadParams); - }; - // Effect for updating current session data in case of section change - useEffect(() => { - if (selectedSection) { - let file = fileDataList?.find((item) => item.active && item.templateIdentifier === selectedSection.id); - if (file?.resourceMapping) { - setSelectedFileType(selectedSection.UploadFileTypes.find((item) => item?.id === file?.fileType)); - setUploadedFileError(file?.error); - setFileData(file); - setDataPresent(true); - } else { - resetSectionState(); - } - } else { - resetSectionState(); - } - }, [selectedSection]); - - const resetSectionState = () => { - setUploadedFileError(null); - setSelectedFileType(null); - setDataPresent(false); - setResourceMapping([]); - setDataUpload(false); - }; - - // Function for handling upload file event - const UploadFileToFileStorage = async (file) => { - if (!file) return; - try { - // setting loader - setLoader("FILE_UPLOADING"); - let check; - let fileDataToStore; - let errorMsg; - let errorLocationObject; // object containing the location and type of error - let response; - let callMapping = false; - // Checking if the file follows name convention rules - if (!validateNamingConvention(file, selectedFileType["namingConvention"], setToast, t)) { - setLoader(false); - return; - } - - let schemaData; - if (selectedFileType.id !== SHAPEFILE) { - // Check if validation schema is present or not - schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); - if (!schemaData) { - setToast({ - state: "error", - message: t("ERROR_VALIDATION_SCHEMA_ABSENT"), - }); - setLoader(false); - return; - } - } - let resourceMappingData = []; - - // Handling different filetypes - switch (selectedFileType.id) { - case EXCEL: - // let response = handleExcelFile(file,schemaData); - try { - response = await handleExcelFile(file, schemaData, hierarchy, selectedFileType, {}, setUploadedFileError, t, campaignData); - check = response.check; - errorMsg = response.errorMsg; - errorLocationObject = response.errors; - fileDataToStore = response.fileDataToStore; - resourceMappingData = response?.tempResourceMappingData; - if (check === true) { - if (response?.toast) setToast(response.toast); - else setToast({ state: "success", message: t("FILE_UPLOADED_SUCCESSFULLY") }); - } else if (response.toast) { - setToast(response.toast); - } else { - setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); - } - if (response.interruptUpload) { - setLoader(false); - return; - } - } catch (error) { - console.error("Excel parsing error", error.message); - setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); - handleValidationErrorResponse(t("ERROR_UPLOADED_FILE")); - return; - } - break; - case GEOJSON: - try { - response = await handleGeojsonFile(file, schemaData, setUploadedFileError, t); - file = new File([file], file.name, { type: "application/geo+json" }); - if (response.check === false && response.stopUpload) { - setLoader(false); - setToast(response.toast); - return; - } - check = response.check; - errorMsg = response.error; - fileDataToStore = response.fileDataToStore; - callMapping = true; - } catch (error) { - // console.error("Geojson parsing error", error.message); - setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); - handleValidationErrorResponse(t("ERROR_UPLOADED_FILE")); - return; - } - break; - case SHAPEFILE: - try { - response = await handleShapefiles(file, schemaData, setUploadedFileError, selectedFileType, setToast, t); - file = new File([file], file.name, { type: "application/octet-stream" }); - check = response.check; - errorMsg = response.error; - fileDataToStore = response.fileDataToStore; - callMapping = true; - } catch (error) { - console.error("Shapefile parsing error", error.message); - setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); - handleValidationErrorResponse(t("ERROR_UPLOADED_FILE")); - return; - } - break; - default: - setToast({ - state: "error", - message: t("ERROR_UNKNOWN_FILETYPE"), - }); - setLoader(false); - return; - } - let filestoreId; - if (!errorMsg && !callMapping) { - try { - const filestoreResponse = await Digit.UploadServices.Filestorage(FILE_STORE, file, Digit.ULBService.getCurrentTenantId()); - if (filestoreResponse?.data?.files?.length > 0) { - filestoreId = filestoreResponse?.data?.files[0]?.fileStoreId; - } else { - errorMsg = t("ERROR_UPLOADING_FILE"); - setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); - setFileData((previous) => ({ ...previous, error: errorMsg })); - setUploadedFileError(errorMsg); - } - } catch (errorData) { - console.error(errorData.message); - errorMsg = t("ERROR_UPLOADING_FILE"); - setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); - setUploadedFileError(errorMsg); - handleValidationErrorResponse(t("ERROR_UPLOADING_FILE")); - } - } - - if (selectedFileType.id === EXCEL) { - resourceMappingData = resourceMappingData.map((item) => ({ ...item, filestoreId })); - } - let uuid = uuidv4(); - // creating a fileObject to save all the data collectively - let fileObject = { - id: uuid, - templateIdentifier: `${selectedSection.id}`, - fileName: file.name, - section: selectedSection.id, - fileType: selectedFileType.id, - data: fileDataToStore, - file, - error: errorMsg ? errorMsg : null, - filestoreId, - resourceMapping: resourceMappingData, - active: true, - errorLocationObject, // contains location and type of error - }; - setFileDataList((prevFileDataList) => { - let temp = _.cloneDeep(prevFileDataList); - if (!temp) return temp; - let index = prevFileDataList?.findIndex((item) => item.active && item.templateIdentifier === selectedSection.id); - if (index !== -1) - temp[index] = { ...temp[index], resourceMapping: temp[index]?.resourceMapping.map((e) => ({ active: false, ...e })), active: false }; - temp.push(fileObject); - return temp; - }); - setFileData(fileObject); - if (errorMsg === undefined && callMapping) { - setModal("spatial-data-property-mapping"); - } - setDataPresent(true); - setLoader(false); - } catch (error) { - console.error(error.message); - console.error("File Upload error", error?.message); - setUploadedFileError("ERROR_UPLOADING_FILE"); - setLoader(false); - } - }; - - // Reupload the selected file - const reuplaodFile = () => { - setResourceMapping([]); - setFileData(undefined); - setDataPresent(false); - setUploadedFileError(null); - setDataUpload(false); - setSelectedFileType(null); - closeModal(); - }; - - // Function for creating blob out of data - const dataToBlob = async () => { - try { - let blob; - const schema = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); - switch (fileData.fileType) { - case EXCEL: - if (fileData?.errorLocationObject?.length !== 0) - blob = await prepareExcelFileBlobWithErrors(fileData.data, fileData.errorLocationObject, schema, hierarchy, t); - else blob = fileData.file; - break; - case SHAPEFILE: - case GEOJSON: - if (fileData?.data) { - const result = Digit.Utils.microplan.convertGeojsonToExcelSingleSheet(fileData?.data?.features, fileData?.section); - if (fileData?.errorLocationObject?.length !== 0) - blob = await prepareExcelFileBlobWithErrors(result, fileData.errorLocationObject, schema, hierarchy, t); - } - break; - } - return blob; - } catch (error) { - console.error("Error generating blob:", error); - return; - } - }; - - // Download the selected file - const downloadFile = async () => { - setLoader("LOADING"); - try { - let blob = await dataToBlob(); - if (blob) { - // Crating a url object for the blob - const url = URL.createObjectURL(blob); - const link = document.createElement("a"); - link.href = url; - - // Forming a name for downloaded file - let fileNameParts = fileData.fileName.split("."); - fileNameParts.pop(); - fileNameParts.push("xlsx"); - fileNameParts.join("."); - - //Downloading the file - link.download = fileNameParts.join("."); - link.click(); - URL.revokeObjectURL(url); - } else { - let downloadUrl = await Digit.UploadServices.Filefetch([fileData.filestoreId], Digit.ULBService.getCurrentTenantId()); - const link = document.createElement("a"); - link.href = downloadUrl; - // Forming a name for downloaded file - let fileNameParts = fileData.fileName.split("."); - fileNameParts.pop(); - fileNameParts.push("xlsx"); - fileNameParts.join("."); - link.download = fileNameParts; // Replace with the desired file name and extension - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - } - } catch (error) { - console.error(error.message); - setToast({ - state: "error", - message: t("ERROR_UNKNOWN_ERROR"), - }); - } - setLoader(false); - }; - - // delete the selected file - const deleteFile = () => { - setResourceMapping([]); - setFileDataList((previous) => { - let temp = _.cloneDeep(previous); - if (!temp) return temp; - let index = temp?.findIndex((item) => { - return item.id === fileData.id; - }); - if (index !== -1) - temp[index] = { ...temp[index], resourceMapping: temp[index]?.resourceMapping.map((e) => ({ active: false, ...e })), active: false }; - return temp; - }); - setFileData(undefined); - setDataPresent(false); - setUploadedFileError(null); - setDataUpload(false); - setSelectedFileType(null); - closeModal(); - }; - - // Function for handling the validations for geojson and shapefiles after mapping of properties - const validationForMappingAndDataSaving = async () => { - try { - setLoader("LOADING"); - const schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); - let error; - if (!checkForSchemaData(schemaData)) return; - const { data, valid, errors } = computeMappedDataAndItsValidations(schemaData); - error = errors; - if (!valid) return; - let filestoreId; - if (!error) { - filestoreId = await saveFileToFileStore(); - } - let resourceMappingData; - if (filestoreId) { - resourceMappingData = resourceMapping.map((item) => { - return { ...item, filestoreId }; - }); - } - setResourceMapping([]); - - let boundaryDataAgainstBoundaryCode = (await boundaryDataGeneration(schemaData, campaignData, t)) || {}; - const mappedToList = resourceMappingData.map((item) => item.mappedTo); - if (hierarchy.every((item) => !mappedToList.includes(t(item)))) { - data.features.forEach((feature) => { - const boundaryCode = feature.properties.boundaryCode; - let additionalDetails = {}; - for (let i = 0; i < hierarchy.length; i++) { - if (boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] || boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] === "") { - additionalDetails[hierarchy[i]] = boundaryDataAgainstBoundaryCode[boundaryCode][i]; - } else { - additionalDetails[hierarchy[i]] = ""; - } - } - feature.properties = { ...additionalDetails, ...feature.properties }; - }); - } - - let fileObject = _.cloneDeep(fileData); - fileObject = { ...fileData, data, resourceMapping: resourceMappingData, error: error ? error : null, filestoreId }; - setFileData(fileObject); - setFileDataList((prevFileDataList) => { - let temp = _.cloneDeep(prevFileDataList); - if (!temp) return temp; - let index = prevFileDataList?.findIndex((item) => item.id === fileData.id); - if (index !== -1) temp[index] = fileObject; - // temp.push(fileObject); - return temp; - }); - - setToast({ state: "success", message: t("FILE_UPLOADED_SUCCESSFULLY") }); - setLoader(false); - } catch (error) { - console.error(error.message); - setUploadedFileError(t("ERROR_UPLOADING_FILE")); - setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); - setLoader(false); - handleValidationErrorResponse("ERROR_UPLOADING_FILE"); - } - }; - const saveFileToFileStore = async () => { - try { - const filestoreResponse = await Digit.UploadServices.Filestorage(FILE_STORE, fileData.file, Digit.ULBService.getCurrentTenantId()); - if (filestoreResponse?.data?.files?.length > 0) { - return filestoreResponse?.data?.files[0]?.fileStoreId; - } - error = t("ERROR_UPLOADING_FILE"); - setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); - setResourceMapping([]); - setUploadedFileError(error); - } catch (errorData) { - console.error("Error while uploading file to filestore: ", errorData?.message); - let error = t("ERROR_UPLOADING_FILE"); - handleValidationErrorResponse(error); - setResourceMapping([]); - return; - } - }; - const computeMappedDataAndItsValidations = (schemaData) => { - const data = computeGeojsonWithMappedProperties(); - const response = geojsonPropetiesValidation(data, schemaData.schema, fileData?.section, t); - if (!response.valid) { - handleValidationErrorResponse(response.message, response.errors); - return { data: data, errors: response.errors, valid: response.valid }; - } - return { data: data, valid: response.valid }; - }; - - const handleValidationErrorResponse = (error, errorLocationObject = {}) => { - const fileObject = fileData; - if (fileObject) { - fileObject.error = [error]; - if (errorLocationObject) fileObject.errorLocationObject = errorLocationObject; - setFileData((previous) => ({ ...previous, error, errorLocationObject })); - setFileDataList((prevFileDataList) => { - let temp = _.cloneDeep(prevFileDataList); - if (!temp) return temp; - let index = prevFileDataList?.findIndex((item) => item.id === fileData.id); - temp[index] = fileObject; - return temp; - }); - setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); - if (error) setUploadedFileError(error); - } - setLoader(false); - }; - - const checkForSchemaData = (schemaData) => { - if (resourceMapping?.length === 0) { - setToast({ state: "warning", message: t("WARNING_INCOMPLETE_MAPPING") }); - setLoader(false); - return false; - } - - if (!schemaData || !schemaData.schema || !schemaData.schema["Properties"]) { - setToast({ state: "error", message: t("ERROR_VALIDATION_SCHEMA_ABSENT") }); - setLoader(false); - return; - } - - let columns = []; - if (schemaData?.doHierarchyCheckInUploadedData) { - columns.push(...hierarchy); - } - columns.push( - ...Object.entries(schemaData?.schema?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.isRequired) { - acc.push(key); - } - return acc; - }, []) - ); - - const resourceMappingLength = resourceMapping.filter((e) => !!e?.mappedFrom && columns.includes(e?.mappedTo)).length; - if (resourceMappingLength !== columns?.length) { - setToast({ state: "warning", message: t("WARNING_INCOMPLETE_MAPPING") }); - setLoader(false); - return false; - } - setModal("none"); - return true; - }; - - const computeGeojsonWithMappedProperties = () => { - const schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); - let schemaKeys; - if (schemaData?.schema?.["Properties"]) schemaKeys = hierarchy.concat(Object.keys(schemaData.schema["Properties"])); - // Sorting the resourceMapping list inorder to maintain the column sequence - const sortedSecondList = Digit.Utils.microplan.sortSecondListBasedOnFirstListOrder(schemaKeys, resourceMapping); - // Creating a object with input data with MDMS keys - const newFeatures = fileData.data["features"].map((item) => { - let newProperties = {}; - - sortedSecondList.forEach((e) => { - newProperties[e["mappedTo"]] = item["properties"][e["mappedFrom"]]; - }); - item["properties"] = newProperties; - return item; - }); - let data = fileData.data; - data["features"] = newFeatures; - return data; - }; - - // Handler for checing file extension and showing errors in case it is wrong - const onTypeErrorWhileFileUpload = () => { - switch (selectedFileType.id) { - case EXCEL: - setToast({ state: "error", message: t("ERROR_EXCEL_EXTENSION") }); - break; - case GEOJSON: - setToast({ state: "error", message: t("ERROR_GEOJSON_EXTENSION") }); - break; - case SHAPEFILE: - setToast({ state: "error", message: t("ERROR_SHAPE_FILE_EXTENSION") }); - break; - } - }; - - // Cancle mapping and uplaod in case of geojson and shapefiles - const cancelUpload = () => { - setFileDataList((previous) => { - let temp = previous?.filter((item) => item.id !== fileData?.id); - return temp; - }); - setFileData(undefined); - setDataPresent(false); - setUploadedFileError(null); - setDataUpload(false); - setSelectedFileType(null); - closeModal(); - }; - - const openDataPreview = () => { - let data; - switch (fileData.fileType) { - case EXCEL: - data = fileData.data; - break; - case SHAPEFILE: - case GEOJSON: - if (!fileData || !fileData.data) { - setToast({ - state: "error", - message: t("ERROR_DATA_NOT_PRESENT"), - }); - return; - } - data = Digit.Utils.microplan.convertGeojsonToExcelSingleSheet(fileData?.data?.features, fileData?.section); - break; - } - if (!data || Object.keys(data).length === 0) { - setToast({ - state: "error", - message: t("ERROR_DATA_NOT_PRESENT"), - }); - return; - } - setPreviewUploadedData(data); - }; - - if (isCampaignLoading || ishierarchyLoading) { - return ( -
- -
- ); - } - - return ( - <> -
-
-
- {!dataPresent ? ( - dataUpload ? ( -
- e.id === selectedSection.id)[0]} - selectedSection={selectedSection} - selectedFileType={selectedFileType} - UploadFileToFileStorage={UploadFileToFileStorage} - onTypeError={onTypeErrorWhileFileUpload} - downloadTemplateHandler={downloadTemplateHandler} - showDownloadTemplate={showDownloadTemplate} - /> -
- ) : ( -
{sectionComponents}
- ) - ) : ( -
- {selectedSection != null && fileData !== null && ( - { - setModal("reupload-conformation"); - }} - DownloadFile={downloadFile} - DeleteFile={() => { - setModal("delete-conformation"); - }} - error={uploadedFileError} - openDataPreview={openDataPreview} - downloadTemplateHandler={downloadTemplateHandler} - showDownloadTemplate={showDownloadTemplate} - /> - )} -
- )} - {!dataPresent && dataUpload && ( - { - setModal("upload-guidelines"); - }} - t={t} - /> - )} -
- -
{sectionOptions}
-
- -
- {modal === "upload-modal" && ( - { - closeModal(); - setSelectedFileType(null); - }} - LeftButtonHandler={() => UploadFileClickHandler(false)} - RightButtonHandler={() => UploadFileClickHandler(true)} - sections={sections} - popupModuleActionBarStyles={{ - flex: 1, - justifyContent: "space-between", - padding: "1rem", - gap: "1rem", - }} - footerLeftButtonBody={} - footerRightButtonBody={} - header={ - - } - bodyText={t("INSTRUCTIONS_DOWNLOAD_TEMPLATE_FOR_" + selectedSection.code + "_" + selectedFileType.code)} - /> - )} - {modal === "delete-conformation" && ( - } - actionCancelLabel={t("YES")} - actionCancelOnSubmit={deleteFile} - actionSaveLabel={t("NO")} - actionSaveOnSubmit={closeModal} - > -
-

{t("INSTRUCTIONS_DELETE_FILE_CONFIRMATION")}

-
-
- )} - {modal === "reupload-conformation" && ( - } - actionCancelLabel={t("YES")} - actionCancelOnSubmit={reuplaodFile} - actionSaveLabel={t("NO")} - actionSaveOnSubmit={closeModal} - > -
-

{t("INSTRUCTIONS_REUPLOAD_FILE_CONFIRMATION")}

-
-
- )} - {modal === "spatial-data-property-mapping" && ( - } - actionSaveOnSubmit={validationForMappingAndDataSaving} - actionSaveLabel={t("COMPLETE_MAPPING")} - headerBarEnd={} - > -
-

{t("INSTRUCTION_SPATIAL_DATA_PROPERTY_MAPPING")}

-
- -
- )} - {modal === "upload-guidelines" && ( - - } - headerBarEnd={} - > - - - )} - {loader && } - - {previewUploadedData && ( -
- setPreviewUploadedData(undefined)} - onDownload={downloadFile} - /> -
- )} -
-
- - ); -}; - -//find guideline -const findGuideLine = (campaignType, type, section, guidelineArray) => { - if (!guidelineArray) return guidelineArray; - return guidelineArray.find( - (guideline) => - guideline.fileType === type && guideline.templateIdentifier === section && (!guideline.campaignType || guideline.campaignType === campaignType) - )?.guidelines; -}; - -// Component for rendering individual section option -const UploadSection = ({ item, selected, setSelectedSection, uploadDone }) => { - const { t } = useTranslation(); - // Handle click on section option - const handleClick = () => { - setSelectedSection(item); - }; - - return ( -
-
- -
-

{t(item.code)}

- {uploadDone && ( -
- -
- )} -
- ); -}; - -const UploadInstructions = ({ setModal, t }) => { - return ( - - {t("REFER")} -
- {t("INFORMATION_DESCRIPTION_LINK")} -
-
, - ]} - /> - ); -}; - -// Component for rendering individual upload option -const UploadComponents = ({ item, selected, uploadOptions, selectedFileType, selectFileTypeHandler }) => { - const { t } = useTranslation(); - const title = item.code; - - // Component for rendering individual upload option container - const UploadOptionContainer = ({ item, selectedFileType, selectFileTypeHandler }) => { - const [isHovered, setIsHovered] = useState(false); - - const handleMouseEnter = () => { - setIsHovered(true); - }; - - const handleMouseLeave = () => { - setIsHovered(false); - }; - - return ( -
- -

{t(item.code)}

- -
- ); - }; - - return ( -
-
-
-

{t(`HEADING_UPLOAD_DATA_${title}`)}

-
- -

{t(`INSTRUCTIONS_DATA_UPLOAD_OPTIONS_${title}`)}

-
-
- {uploadOptions && - uploadOptions.map((item) => ( - - ))} -
-
- ); -}; - -// Component for uploading file -const FileUploadComponent = ({ - selectedSection, - selectedFileType, - UploadFileToFileStorage, - section, - onTypeError, - downloadTemplateHandler, - showDownloadTemplate, -}) => { - if (!selectedSection || !selectedFileType) return
; - const { t } = useTranslation(); - let types; - section["UploadFileTypes"].forEach((item) => { - if (item.id === selectedFileType.id) types = item.fileExtension; - }); - return ( -
-
-
-

{t(`HEADING_FILE_UPLOAD_${selectedSection.code}_${selectedFileType.code}`)}

- {showDownloadTemplate() && ( - - )} -
-

{t(`INSTRUCTIONS_FILE_UPLOAD_FROM_TEMPLATE_${selectedSection.code}`)}

- -
- -
- {t(`INSTRUCTIONS_UPLOAD_${selectedFileType.code}`)} 
{t("INSTRUCTIONS_UPLOAD_BROWSE_FILES")}
-
-
-
-
-
- ); -}; - -// Component to display uploaded file -const UploadedFile = ({ - selectedSection, - selectedFileType, - file, - ReuplaodFile, - DownloadFile, - DeleteFile, - error, - openDataPreview, - downloadTemplateHandler, - showDownloadTemplate, -}) => { - const { t } = useTranslation(); - const [errorList, setErrorList] = useState([]); - useEffect(() => { - let tempErrorList = []; - if (file?.errorLocationObject) { - for (const [sheetName, values] of Object.entries(file?.errorLocationObject)) { - for (const [row, columns] of Object.entries(values)) { - for (const [column, errors] of Object.entries(columns)) { - for (const error of errors) { - let convertedError; - if (typeof error === "object") { - let { error: actualError, ...otherProperties } = error; - convertedError = t(actualError, otherProperties?.values); - } else { - convertedError = t(error); - } - tempErrorList.push( - t("ERROR_UPLOAD_DATA_LOCATION_AND_MESSAGE", { - rowNumber: row, - columnName: t(column), - error: convertedError, - sheetName: sheetName, - }) - ); - } - } - } - } - } - if (tempErrorList.length !== 0) { - setErrorList(tempErrorList); - } - }, [file]); - return ( -
-
-
-

{t(`HEADING_FILE_UPLOAD_${selectedSection.code}_${selectedFileType.code}`)}

- {showDownloadTemplate() && ( - - )} -
-

{t(`INSTRUCTIONS_FILE_UPLOAD_FROM_TEMPLATE_${selectedSection.code}`)}

- -
-
-
- -
-

{file.fileName}

-
-
- - - -
-
-
- {error && Array.isArray(error) && ( - , -
- {error?.map((item) => { - if (item !== "ERROR_REFER_UPLOAD_PREVIEW_TO_SEE_THE_ERRORS") { - return

{t(item)}

; - } - return null; - })} - {errorList.length !== 0 && errorList.map((item) =>

{item}

)} -
, - ]} - /> - )} -
- ); -}; - -// Function for checking the uploaded file for nameing conventions -const validateNamingConvention = (file, namingConvention, setToast, t) => { - try { - let processedConvention = namingConvention.replace("$", ".[^.]*$"); - const regx = new RegExp(processedConvention); - - if (regx && !regx.test(file.name)) { - setToast({ - state: "error", - message: t("ERROR_NAMING_CONVENSION"), - }); - return false; - } - return true; - } catch (error) { - console.error(error.message); - setToast({ - state: "error", - message: t("ERROR_UNKNOWN"), - }); - } -}; - -// Function for reading ancd checking geojson data -const readGeojson = async (file, t) => { - return new Promise((resolve, reject) => { - if (!file) return resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } }); - - const reader = new FileReader(); - reader.onload = (e) => { - try { - const geoJSONData = JSON.parse(e.target.result); - const trimmedGeoJSONData = trimJSON(geoJSONData); - resolve({ valid: true, geojsonData: trimmedGeoJSONData }); - } catch (error) { - resolve({ valid: false, toast: { state: "error", message: t("ERROR_INCORRECT_FORMAT") } }); - } - }; - reader.onerror = (error) => { - resolve({ valid: false, toast: { state: "error", message: t("ERROR_CORRUPTED_FILE") } }); - }; - - reader.readAsText(file); - }); -}; - -// Function to recursively trim leading and trailing spaces from string values in a JSON object -const trimJSON = (jsonObject) => { - if (typeof jsonObject !== "object") { - return jsonObject; // If not an object, return as is - } - - if (Array.isArray(jsonObject)) { - return jsonObject.map((item) => trimJSON(item)); // If it's an array, recursively trim each item - } - - const trimmedObject = {}; - for (const key in jsonObject) { - if (Object.hasOwn(jsonObject, key)) { - const value = jsonObject[key]; - // Trim string values, recursively trim objects - trimmedObject[key.trim()] = typeof value === "string" ? value.trim() : typeof value === "object" ? trimJSON(value) : value; - } - } - return trimmedObject; -}; -// Function for reading and validating shape file data -const readAndValidateShapeFiles = async (file, t, namingConvention) => { - return new Promise(async (resolve, reject) => { - if (!file) { - resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } }); - } - const fileRegex = new RegExp(namingConvention.replace("$", ".*$")); - // File Size Check - const fileSizeInBytes = file.size; - const maxSizeInBytes = 2 * 1024 * 1024 * 1024; // 2 GB - - // Check if file size is within limit - if (fileSizeInBytes > maxSizeInBytes) - resolve({ valid: false, message: t("ERROR_FILE_SIZE"), toast: { state: "error", message: t("ERROR_FILE_SIZE") } }); - - try { - const zip = await JSZip.loadAsync(file); - const isEPSG4326 = await checkProjection(zip); - if (!isEPSG4326) { - resolve({ valid: false, message: t("ERROR_WRONG_PRJ"), toast: { state: "error", message: t("ERROR_WRONG_PRJ") } }); - } - const files = Object.keys(zip.files); - const allFilesMatchRegex = files.every((fl) => { - return fileRegex.test(fl); - }); - let regx = new RegExp(namingConvention.replace("$", "\\.shp$")); - const shpFile = zip.file(regx)[0]; - regx = new RegExp(namingConvention.replace("$", "\\.shx$")); - const shxFile = zip.file(regx)[0]; - regx = new RegExp(namingConvention.replace("$", "\\.dbf$")); - const dbfFile = zip.file(regx)[0]; - - let geojson; - if (shpFile && dbfFile) { - const shpArrayBuffer = await shpFile.async("arraybuffer"); - const dbfArrayBuffer = await dbfFile.async("arraybuffer"); - - geojson = shp.combine([shp.parseShp(shpArrayBuffer), shp.parseDbf(dbfArrayBuffer)]); - } - if (shpFile && dbfFile && shxFile && allFilesMatchRegex) resolve({ valid: true, data: geojson }); - else if (!allFilesMatchRegex) - resolve({ - valid: false, - message: [t("ERROR_CONTENT_NAMING_CONVENSION")], - toast: { state: "error", data: geojson, message: t("ERROR_CONTENT_NAMING_CONVENSION") }, - }); - else if (!shpFile) - resolve({ valid: false, message: [t("ERROR_SHP_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_SHP_MISSING") } }); - else if (!dbfFile) - resolve({ valid: false, message: [t("ERROR_DBF_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_DBF_MISSING") } }); - else if (!shxFile) - resolve({ valid: false, message: [t("ERROR_SHX_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_SHX_MISSING") } }); - } catch (error) { - resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } }); - } - }); -}; - -// Function for projections check in case of shapefile data -const checkProjection = async (zip) => { - const prjFile = zip.file(/.prj$/i)[0]; - if (!prjFile) { - return "absent"; - } - - const prjText = await prjFile.async("text"); - - if (prjText.includes("GEOGCS") && prjText.includes("WGS_1984") && prjText.includes("DATUM") && prjText.includes("D_WGS_1984")) { - return "EPSG:4326"; - } - return false; -}; - -// Function to handle the template download -const downloadTemplate = async ({ - campaignType, - type, - section, - setToast, - campaignData, - hierarchyType, - Schemas, - HierarchyConfigurations, - setLoader, - hierarchy, - t, -}) => { - try { - setLoader("LOADING"); - // Find the template based on the provided parameters - const schema = getSchema(campaignType, type, section, Schemas); - const hierarchyLevelName = HierarchyConfigurations?.find((item) => item.name === "devideBoundaryDataBy")?.value; - let template = await createTemplate({ - hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets, - hierarchyLevelName, - addFacilityData: schema?.template?.includeFacilityData, - schema, - boundaries: campaignData?.boundaries, - tenantId: Digit.ULBService.getCurrentTenantId(), - hierarchyType, - t, - }); - const translatedTemplate = translateTemplate(template, t); - - // Create a new workbook - const workbook = new ExcelJS.Workbook(); - - formatTemplate(translatedTemplate, workbook); - - // Color headers - colorHeaders( - workbook, - [...hierarchy.map((item) => t(item)), t(commonColumn)], - schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [], - [] - ); - // protextData - await protectData({ - workbook, - hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets, - addFacilityData: schema?.template?.includeFacilityData, - schema, - t, - }); - - // Write the workbook to a buffer - workbook.xlsx.writeBuffer({ compression: true }).then((buffer) => { - // Create a Blob from the buffer - const blob = new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); - // Create a URL for the Blob - const url = URL.createObjectURL(blob); - // Create a link element and simulate click to trigger download - const link = document.createElement("a"); - link.href = url; - link.download = t(section) + ".xlsx"; - link.click(); - // Revoke the URL to release the Blob - URL.revokeObjectURL(url); - setLoader(false); - }); - } catch (error) { - setLoader(false); - console.error(error?.message); - setToast({ state: "error", message: t("ERROR_DOWNLOADING_TEMPLATE") }); - } -}; - -const protectData = async ({ workbook, hierarchyLevelWiseSheets = true, addFacilityData = false, schema, t }) => { - if (hierarchyLevelWiseSheets) { - if (addFacilityData) { - await freezeSheetValues(workbook, t(BOUNDARY_DATA_SHEET)); - await performUnfreezeCells(workbook, t(FACILITY_DATA_SHEET)); - if (schema?.template?.propertiesToHide && Array.isArray(schema.template.propertiesToHide)) { - let tempPropertiesToHide = schema?.template?.propertiesToHide.map((item) => t(generateLocalisationKeyForSchemaProperties(item))); - await hideUniqueIdentifierColumn(workbook, t(FACILITY_DATA_SHEET), tempPropertiesToHide); - } - if (schema?.template?.facilitySchemaApiMapping) { - } else { - } - } else { - await freezeWorkbookValues(workbook); - await unfreezeColumnsByHeader( - workbook, - schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [] - ); - } - } else { - // total boundary Data in one sheet - if (addFacilityData) { - await freezeSheetValues(workbook, t(BOUNDARY_DATA_SHEET)); - await performUnfreezeCells(workbook, t(FACILITY_DATA_SHEET)); - if (schema?.template?.propertiesToHide && Array.isArray(schema.template.propertiesToHide)) { - let tempPropertiesToHide = schema?.template?.propertiesToHide.map((item) => t(generateLocalisationKeyForSchemaProperties(item))); - await hideUniqueIdentifierColumn(workbook, t(FACILITY_DATA_SHEET), tempPropertiesToHide); - } - - if (schema?.template?.facilitySchemaApiMapping) { - } else { - } - } else { - await freezeWorkbookValues(workbook); - await unfreezeColumnsByHeader( - workbook, - schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [] - ); - } - } -}; - -const colorHeaders = async (workbook, headerList1, headerList2, headerList3) => { - try { - // Iterate through each sheet - workbook.eachSheet((sheet, sheetId) => { - // Get the first row - const firstRow = sheet.getRow(1); - - // Iterate through each cell in the first row - firstRow.eachCell((cell, colNumber) => { - const cellValue = cell.value.toString(); - - // Check conditions and set colors - if (headerList1?.includes(cellValue)) { - cell.fill = { - type: "pattern", - pattern: "solid", - fgColor: { argb: "ff9248" }, - }; - } else if (headerList2?.includes(cellValue)) { - cell.fill = { - type: "pattern", - pattern: "solid", - fgColor: { argb: "93C47D" }, - }; - } else if (headerList3?.includes(cellValue)) { - cell.fill = { - type: "pattern", - pattern: "solid", - fgColor: { argb: "CCCC00" }, - }; - } - }); - }); - } catch (error) { - console.error("Error coloring headers:", error); - } -}; - -const formatTemplate = (template, workbook) => { - template.forEach(({ sheetName, data }) => { - // Create a new worksheet with properties - const worksheet = workbook.addWorksheet(sheetName, { - // properties: { - // outlineLevelCol: 1, - // defaultRowHeight: 15, - // }, - }); - data?.forEach((row, index) => { - const worksheetRow = worksheet.addRow(row); - - // Apply fill color to each cell in the first row and make cells bold - if (index === 0) { - worksheetRow.eachCell((cell, colNumber) => { - // // Set cell fill color - // cell.fill = { - // type: "pattern", - // pattern: "solid", - // fgColor: { - // argb: headerToColorwithColor1.includes(cell.value) ? "ff9248" : headerToColorwithColor2.includes(cell.value) ? "93C47D" : undefined, - // }, - // }; - - // Set font to bold - cell.font = { bold: true }; - - // Enable text wrapping - cell.alignment = { wrapText: true }; - - // Update column width based on the length of the cell's text - const currentWidth = worksheet.getColumn(colNumber).width || SHEET_COLUMN_WIDTH; // Default width or current width - const newWidth = Math.max(currentWidth, cell.value.toString().length + 2); // Add padding - worksheet.getColumn(colNumber).width = newWidth; - }); - } - }); - updateFontNameToRoboto(worksheet); - }); -}; - -const translateTemplate = (template, t) => { - // Initialize an array to hold the transformed result - const transformedResult = []; - - // Iterate over each sheet in the divided data - for (const sheet of template) { - const sheetData = sheet.data; - - // Find the index of the boundaryCode column in the header row - const boundaryCodeIndex = sheetData[0].indexOf(commonColumn); - - const sheetName = t(sheet.sheetName); - const transformedSheet = { - sheetName: sheetName.length > 31 ? sheetName.slice(0, 31) : sheetName, - data: [], - }; - - // Iterate over each row in the sheet data - for (const [rowIndex, row] of sheetData.entries()) { - // Transform each entity in the row using the transformFunction - const transformedRow = row.map((entity, index) => { - // Skip transformation for the boundaryCode column - if ((index === boundaryCodeIndex && rowIndex !== 0) || typeof entity === "number") { - return entity; - } - return t(entity); - }); - transformedSheet.data.push(transformedRow); - } - - // Add the transformed sheet to the transformed result - transformedResult.push(transformedSheet); - } - - return transformedResult; -}; - -// get schema for validation -const getSchema = (campaignType, type, section, schemas) => { - return schemas.find((schema) => { - if (!schema.campaignType) { - return schema.type === type && schema.section === section; - } - return schema.campaignType === campaignType && schema.type === type && schema.section === section; - }); -}; - -// Uplaod GuideLines -const UploadGuideLines = ({ uploadGuideLines, t }) => { - const formMsgFromObject = (item) => { - if (!item?.hasLink) { - return t(item?.name); - } - return ( - <> - {t(item?.name)} {t(item?.linkName)}{" "} - - ); - }; - return ( -
- {uploadGuideLines?.map((item, index) => ( -
-

- {t(index + 1)}. -

-
- {formMsgFromObject(item)} -
-
- ))} -
- ); -}; - -const CustomIcon = (props) => { - if (!props.Icon) return null; - return ; -}; - -const generateLocalisationKeyForSchemaProperties = (code) => { - if (!code) return code; - return SCHEMA_PROPERTIES_PREFIX + "_" + code; -}; -// Performs resource mapping and data filtering for Excel files based on provided schema data, hierarchy, and file data. -const resourceMappingAndDataFilteringForExcelFiles = (schemaData, hierarchy, selectedFileType, fileDataToStore, t) => { - let resourceMappingData = []; - let newFileData = {}; - let toAddInResourceMapping; - if (selectedFileType.id === EXCEL && fileDataToStore) { - // Extract all unique column names from fileDataToStore and then doing thir resource mapping - const columnForMapping = new Set(Object.values(fileDataToStore).flatMap((value) => value?.[0] || [])); - if (schemaData?.schema?.["Properties"]) { - const schemaKeys = Object.keys(schemaData.schema["Properties"]) - .map((item) => generateLocalisationKeyForSchemaProperties(item)) - .concat([...hierarchy, commonColumn]); - schemaKeys.forEach((item) => { - if (columnForMapping.has(t(item))) { - resourceMappingData.push({ - mappedFrom: t(item), - mappedTo: item, - }); - } - }); - } - - // Filtering the columns with respect to the resource mapping and removing the columns that are not needed - Object.entries(fileDataToStore).forEach(([key, value]) => { - let data = []; - let headers = []; - let toRemove = []; - if (value && value.length > 0) { - value[0].forEach((item, index) => { - const mappedTo = resourceMappingData.find((e) => e.mappedFrom === item)?.mappedTo; - if (!mappedTo) { - toRemove.push(index); - return; - } - headers.push(revertLocalisationKey(mappedTo)); - return; - }); - for (let i = 1; i < value?.length; i++) { - let temp = []; - for (let j = 0; j < value[i].length; j++) { - if (!toRemove.includes(j)) { - temp.push(value[i][j]); - } - } - data.push(temp); - } - } - newFileData[key] = [headers, ...data]; - }); - } - return { tempResourceMappingData: resourceMappingData, tempFileDataToStore: newFileData }; -}; -const revertLocalisationKey = (localisedCode) => { - if (!localisedCode || !localisedCode.startsWith(SCHEMA_PROPERTIES_PREFIX + "_")) { - return localisedCode; - } - return localisedCode.substring(SCHEMA_PROPERTIES_PREFIX.length + 1); -}; -const prepareExcelFileBlobWithErrors = async (data, errors, schema, hierarchy, t) => { - let tempData = { ...data }; - // Process each dataset within the data object - const processedData = {}; - let headerList1 = []; - let headerList2 = [t("MICROPLAN_ERROR_COLUMN")]; - const schemaCols = schema?.schema?.Properties ? Object.keys(schema.schema.Properties) : []; - for (const key in tempData) { - if (Object.hasOwn(tempData, key)) { - const dataset = [...tempData[key]]; - - // Add the 'error' column to the header - dataset[0] = dataset[0].map((item) => { - if (item !== commonColumn && schemaCols.includes(item)) { - return t(generateLocalisationKeyForSchemaProperties(item)); - } - return t(item); - }); - headerList1.push(...dataset[0]); - // Process each data row - if (errors) { - dataset[0].push(t("MICROPLAN_ERROR_COLUMN")); - let headerCount = 0; - for (let i = 1; i < dataset.length; i++) { - const row = dataset[i]; - if (i === 1 && row) { - headerCount = row.length; - } - - if (headerCount > row.length) { - row.push(...Array(headerCount - row.length).fill("")); - } - - // Check if there are errors for the given commonColumnData - const errorInfo = errors?.[key]?.[i - 1]; - if (errorInfo) { - let rowDataAddOn = Object.entries(errorInfo) - .map(([key, value]) => { - return t(key) + ": " + value.map((item) => t(item)).join(", "); - }) - .join("\n"); - row.push(rowDataAddOn); - } else { - row.push(""); - } - } - } - processedData[key] = dataset; - } - } - const errorColumn = "MICROPLAN_ERROR_COLUMN"; - const style = { - font: { color: { argb: "B91900" } }, - border: { - top: { style: "thin", color: { argb: "B91900" } }, - left: { style: "thin", color: { argb: "B91900" } }, - bottom: { style: "thin", color: { argb: "B91900" } }, - right: { style: "thin", color: { argb: "B91900" } }, - }, - }; - const workbook = await convertToWorkBook(processedData, { errorColumn, style }); - colorHeaders( - workbook, - [...hierarchy.map((item) => t(item)), t(commonColumn)], - schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [], - [] - ); - - // protextData - await protectData({ - workbook, - hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets, - addFacilityData: schema?.template?.includeFacilityData, - schema, - t, - }); - return await workbook.xlsx.writeBuffer({ compression: true }).then((buffer) => { - // Create a Blob from the buffer - return new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); - }); - // return xlsxBlob; -}; -const convertToWorkBook = async (jsonData, columnWithStyle) => { - const workbook = new ExcelJS.Workbook(); - - // Iterate over each sheet in jsonData - for (const [sheetName, data] of Object.entries(jsonData)) { - // Create a new worksheet - const worksheet = workbook.addWorksheet(sheetName); - - // Convert data to worksheet - for (const row of data) { - const newRow = worksheet.addRow(row); - // Apply red font color to the errorColumn if it exists - let errorColumnIndex = data[0].indexOf(columnWithStyle?.errorColumn); - if (columnWithStyle?.errorColumn && errorColumnIndex !== -1) { - const columnIndex = errorColumnIndex + 1; - if (columnIndex > 0) { - const newCell = newRow.getCell(columnIndex); - if (columnWithStyle.style && newCell) for (const key in columnWithStyle.style) newCell[key] = columnWithStyle.style[key]; - } - } - } - - // Make the first row bold - if (worksheet.getRow(1)) { - worksheet.getRow(1).font = { bold: true }; - } - - // Set column widths - const columnCount = data?.[0]?.length || 0; - const wscols = Array(columnCount).fill({ width: 30 }); - wscols.forEach((col, colIndex) => { - worksheet.getColumn(colIndex + 1).width = col.width; - }); - } - return workbook; -}; -const boundaryDataGeneration = async (schemaData, campaignData, t) => { - let boundaryDataAgainstBoundaryCode = {}; - if (schemaData && !schemaData.doHierarchyCheckInUploadedData) { - try { - const rootBoundary = campaignData?.boundaries?.filter((boundary) => boundary.isRoot); // Retrieve session storage data once and store it in a variable - const sessionData = Digit.SessionStorage.get("microplanHelperData") || {}; - let boundaryData = sessionData.filteredBoundaries; - let filteredBoundaries; - if (!boundaryData) { - // Only fetch boundary data if not present in session storage - boundaryData = await fetchBoundaryData(Digit.ULBService.getCurrentTenantId(), campaignData?.hierarchyType, rootBoundary?.[0]?.code); - filteredBoundaries = filterBoundaries(boundaryData, campaignData?.boundaries); - - // Update the session storage with the new filtered boundaries - Digit.SessionStorage.set("microplanHelperData", { - ...sessionData, - filteredBoundaries: filteredBoundaries, - }); - } else { - filteredBoundaries = boundaryData; - } - const xlsxData = addBoundaryData([], filteredBoundaries, campaignData?.hierarchyType)?.[0]?.data; - xlsxData.forEach((item, i) => { - if (i === 0) return; - let boundaryCodeIndex = xlsxData?.[0]?.indexOf(commonColumn); - if (boundaryCodeIndex >= item.length) { - // If boundaryCodeIndex is out of bounds, return the item as is - boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item.slice().map(t); - } else { - // Otherwise, remove the element at boundaryCodeIndex - boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item - .slice(0, boundaryCodeIndex) - .concat(item.slice(boundaryCodeIndex + 1)) - .map(t); - } - }); - return boundaryDataAgainstBoundaryCode; - } catch (error) { - console.error(error?.message); - } - } -}; - -export const handleExcelFile = async ( - file, - schemaData, - hierarchy, - selectedFileType, - boundaryDataAgainstBoundaryCode, - setUploadedFileError, - t, - campaignData -) => { - try { - // Converting the file to preserve the sequence of columns so that it can be stored - let fileDataToStore = await parseXlsxToJsonMultipleSheets(file, { header: 0 }); - if (fileDataToStore[t(BOUNDARY_DATA_SHEET)]) delete fileDataToStore[t(BOUNDARY_DATA_SHEET)]; - let { tempResourceMappingData, tempFileDataToStore } = resourceMappingAndDataFilteringForExcelFiles( - schemaData, - hierarchy, - selectedFileType, - fileDataToStore, - t - ); - fileDataToStore = await convertJsonToXlsx(tempFileDataToStore); - // Converting the input file to json format - let result = await parseXlsxToJsonMultipleSheets(fileDataToStore, { header: 1 }); - if (result?.error) { - return { - check: false, - interruptUpload: true, - error: result.error, - fileDataToStore: {}, - toast: { state: "error", message: t("ERROR_CORRUPTED_FILE") }, - }; - } - let extraColumns = [commonColumn]; - // checking if the hierarchy and common column is present the uploaded data - extraColumns = [...hierarchy, commonColumn]; - let data = Object.values(tempFileDataToStore); - let errorMsg; - let errors; // object containing the location and type of error - let toast; - let hierarchyDataPresent = true; - let latLngColumns = - Object.entries(schemaData?.schema?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.isLocationDataColumns) { - acc.push(key); - } - return acc; - }, []) || []; - data.forEach((item) => { - const keys = item[0]; - if (keys?.length !== 0) { - if (!extraColumns?.every((e) => keys.includes(e))) { - if (schemaData && !schemaData.doHierarchyCheckInUploadedData) { - hierarchyDataPresent = false; - } else { - errorMsg = { - check: false, - interruptUpload: true, - error: t("ERROR_BOUNDARY_DATA_COLUMNS_ABSENT"), - fileDataToStore: {}, - toast: { state: "error", message: t("ERROR_BOUNDARY_DATA_COLUMNS_ABSENT") }, - }; - } - } - if (!latLngColumns?.every((e) => keys.includes(e))) { - toast = { state: "warning", message: t("ERROR_UPLOAD_EXCEL_LOCATION_DATA_MISSING") }; - } - } - }); - if (errorMsg && !errorMsg?.check) return errorMsg; - // Running Validations for uploaded file - let response = await checkForErrorInUploadedFileExcel(result, schemaData.schema, t); - if (!response.valid) setUploadedFileError(response.message); - errorMsg = response.message; - errors = response.errors; - const missingProperties = response.missingProperties; - let check = response.valid; - try { - if (schemaData && !schemaData.doHierarchyCheckInUploadedData && !hierarchyDataPresent && boundaryDataAgainstBoundaryCode) { - let tempBoundaryDataAgainstBoundaryCode = (await boundaryDataGeneration(schemaData, campaignData, t)) || {}; - for (const sheet in tempFileDataToStore) { - const commonColumnIndex = tempFileDataToStore[sheet]?.[0]?.indexOf(commonColumn); - if (commonColumnIndex !== -1) - tempFileDataToStore[sheet] = tempFileDataToStore[sheet].map((item, index) => [ - ...(tempBoundaryDataAgainstBoundaryCode[item[commonColumnIndex]] - ? tempBoundaryDataAgainstBoundaryCode[item[commonColumnIndex]] - : index !== 0 - ? new Array(hierarchy.length).fill("") - : []), - ...item, - ]); - - tempFileDataToStore[sheet][0] = [...hierarchy, ...tempFileDataToStore[sheet][0]]; - } - } - } catch (error) { - console.error("Error in boundary adding operaiton: ", error); - } - tempFileDataToStore = addMissingPropertiesToFileData(tempFileDataToStore, missingProperties); - return { check, errors, errorMsg, fileDataToStore: tempFileDataToStore, tempResourceMappingData, toast }; - } catch (error) { - console.error("Error in handling Excel file:", error.message); - } -}; -const addMissingPropertiesToFileData = (data, missingProperties) => { - if (!data || !missingProperties) return data; - let tempData = {}; - Object.entries(data).forEach(([key, value], index) => { - const filteredMissingProperties = [...missingProperties]?.reduce((acc, item) => { - if (!value?.[0]?.includes(item)) { - acc.push(item); - } - return acc; - }, []); - const newTempHeaders = value?.[0].length !== 0 ? [...value[0], ...filteredMissingProperties] : [...filteredMissingProperties]; - console.error(newTempHeaders); - tempData[key] = [newTempHeaders, ...value.slice(1)]; - }); - return tempData; -}; - -const handleGeojsonFile = async (file, schemaData, setUploadedFileError, t) => { - // Reading and checking geojson data - const data = await readGeojson(file, t); - if (!data.valid) { - return { check: false, stopUpload: true, toast: data.toast }; - } - - // Running geojson validaiton on uploaded file - let response = geojsonValidations(data.geojsonData, schemaData.schema, t); - if (!response.valid) setUploadedFileError(response.message); - let check = response.valid; - let error = response.message; - let fileDataToStore = data.geojsonData; - return { check, error, fileDataToStore }; -}; - -const handleShapefiles = async (file, schemaData, setUploadedFileError, selectedFileType, setToast, t) => { - // Reading and validating the uploaded geojson file - let response = await readAndValidateShapeFiles(file, t, selectedFileType["namingConvention"]); - if (!response.valid) { - setUploadedFileError(response.message); - setToast(response.toast); - } - let check = response.valid; - let error = response.message; - let fileDataToStore = response.data; - return { check, error, fileDataToStore }; -}; - -export default Upload; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/logout.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/logout.js deleted file mode 100644 index 38415d5a63a..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/logout.js +++ /dev/null @@ -1,48 +0,0 @@ -var Digit = window.Digit || {}; - -/* Recreated a new hook in same name*/ -export const logoutV1 = async () => { - let user = Digit.UserService.getUser(); - if (!user || !user.info || !user.access_token) return false; - const { type } = user.info; - const access_token = user?.access_token; - const tenantId = type === "CITIZEN" ? Digit.ULBService.getStateId() : Digit.ULBService.getCurrentTenantId(); - const myHeaders = new Headers(); - myHeaders.append("accept", "application/json, text/plain, */*"); - myHeaders.append("content-type", "application/json;charset=UTF-8"); - const raw = { - RequestInfo: { - apiId: "Rainmaker", - ver: ".01", - ts: "", - action: "_logout", - did: "1", - key: "", - msgId: "20170310130900|en_IN", - authToken: access_token, - }, - access_token: access_token, - }; - - var requestOptions = { - method: "POST", - headers: myHeaders, - body: JSON.stringify(raw), - redirect: "follow", - }; - const userType = Digit.UserService.getType(); - try { - await fetch(`${window.location.origin}/user/v1/_logout?tenantId=${tenantId}`, requestOptions) - .then((response) => response.json()) - .catch((error) => console.log("error", error)); - } catch (e) { - } finally { - window.localStorage.clear(); - window.sessionStorage.clear(); - if (userType === "citizen") { - window.location.replace("/digit-ui/citizen"); - } else { - window.location.replace("/digit-ui/employee/user/language-selection"); - } - } -}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js deleted file mode 100644 index 176743cdfdb..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js +++ /dev/null @@ -1,182 +0,0 @@ -import Ajv from "ajv"; -const ajv = new Ajv({ allErrors: true }); -ajv.addKeyword("isRequired"); -ajv.addKeyword("isLocationDataColumns"); -ajv.addKeyword("isRuleConfigureInputs"); -ajv.addKeyword("isFilterPropertyOfMapSection"); -ajv.addKeyword("isVisualizationPropertyOfMapSection"); -ajv.addKeyword("toShowInMicroplanPreview"); - -// Function responsible for excel data validation with respect to the template/schema provided -export const excelValidations = (data, schemaData, t) => { - const translate = () => { - const required = Object.entries(schemaData?.Properties || {}) - .reduce((acc, [key, value]) => { - if (value?.isRequired) { - acc.push(key); - } - return acc; - }, []) - .map((item) => item); - return { required, properties: schemaData.Properties }; - }; - const { required, properties } = translate(); - const schema = { - type: "object", - patternProperties: { - ".*": { - type: "array", - items: { - type: "object", - properties: properties, - required: required, - additionalProperties: true, - }, - }, - }, - minProperties: 1, - additionalProperties: false, - }; - const validateExcel = ajv.compile(schema); - const valid = validateExcel(data); - let locationDataColumns = Object.entries(schemaData?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.isLocationDataColumns) { - acc.push(key); - } - return acc; - }, []); - if (!valid) { - let errors = {}; - let hasDataErrors = "false"; // true, false, missing_properties, unknown - let missingColumnsList = new Set(); - let errorMessages = {}; - for (let i = 0; i < validateExcel.errors.length; i++) { - let tempErrorStore = ""; - let instancePathTypeGlobal; // = validateExcel.errors[i].instancePath.split("/"); - switch (validateExcel.errors[i].keyword) { - case "additionalProperties": { - tempErrorStore = "ERROR_ADDITIONAL_PROPERTIES"; - hasDataErrors = "true"; - break; - } - case "type": - { - const instancePathType = validateExcel.errors[i].instancePath.split("/"); - const neededType = validateExcel.errors[i].params?.type; - instancePathTypeGlobal = instancePathType; - tempErrorStore = locationDataColumns.includes(instancePathType[instancePathType.length - 1]) - ? "ERROR_INCORRECT_LOCATION_COORDINATES" - : neededType === "number" - ? "ERROR_MUST_BE_A_NUMBER" - : "ERROR_MUST_BE_A_STRING"; - hasDataErrors = "true"; - } - break; - case "required": { - const missing = validateExcel.errors[i].params.missingProperty; - const instancePathType = validateExcel.errors[i].instancePath.split("/"); - instancePathTypeGlobal = [...instancePathType, missing]; - tempErrorStore = "ERROR_MANDATORY_FIELDS_CANT_BE_EMPTY"; - missingColumnsList.add(missing); - // hasDataErrors = "missing_properties"; - hasDataErrors = "true"; - break; - } - case "maximum": - case "minimum": { - const instancePathMinMax = validateExcel.errors[i].instancePath.split("/"); - instancePathTypeGlobal = instancePathMinMax; - tempErrorStore = locationDataColumns.includes(instancePathMinMax[instancePathTypeGlobal.length - 1]) - ? "ERROR_INCORRECT_LOCATION_COORDINATES" - : "ERROR_DATA_EXCEEDS_LIMIT_CONSTRAINTS"; - hasDataErrors = "true"; - break; - } - case "pattern": { - tempErrorStore = "ERROR_VALUE_NOT_ALLOWED"; - hasDataErrors = "true"; - break; - } - case "minProperties": { - hasDataErrors = "minProperties"; - break; - } - case "enum": { - const instancePathType = validateExcel.errors[i].instancePath.split("/"); - instancePathTypeGlobal = instancePathType; - tempErrorStore = { - error: "ERROR_UPLOAD_DATA_ENUM", - values: { allowedValues: validateExcel.errors[i]?.params?.allowedValues?.map((item) => t(item)).join(", ") }, - }; - hasDataErrors = "true"; - break; - } - default: { - hasDataErrors = "unknown"; - } - } - if (tempErrorStore && instancePathTypeGlobal) - errors[instancePathTypeGlobal[1]] = { - ...(errors[instancePathTypeGlobal[1]] ? errors[instancePathTypeGlobal[1]] : {}), - [instancePathTypeGlobal[2]]: { - ...(errors?.[instancePathTypeGlobal[1]]?.[instancePathTypeGlobal[2]] - ? errors?.[instancePathTypeGlobal[1]]?.[instancePathTypeGlobal[2]] - : {}), - [instancePathTypeGlobal[3]]: [ - ...new Set( - ...(errors?.[instancePathTypeGlobal[1]]?.[instancePathTypeGlobal[2]]?.[instancePathTypeGlobal[3]] - ? errors?.[instancePathTypeGlobal[1]]?.[instancePathTypeGlobal[2]]?.[instancePathTypeGlobal[3]] - : []) - ), - tempErrorStore, - ], - }, - }; - - switch (hasDataErrors) { - case "true": - errorMessages = { dataError: "ERROR_REFER_UPLOAD_PREVIEW_TO_SEE_THE_ERRORS" }; - break; - case "minProperties": - errorMessages = { minProperties: "ERROR_UPLOADED_DATA_IS_EMPTY" }; - break; - case "unknown": - errorMessages = { unkown: "ERROR_UNKNOWN" }; - break; - case "false": - break; - } - } - - ajv.removeSchema(); - - return { - valid: !hasDataErrors, - message: errorMessages ? [...new Set(Object.values(errorMessages))] : [], - errors, - validationError: validateExcel.errors, - missingColumnsList, - }; - } - ajv.removeSchema(); - return { valid }; -}; - -export const checkForErrorInUploadedFileExcel = async (fileInJson, schemaData, t) => { - try { - const valid = excelValidations(fileInJson, schemaData, t); - if (valid.valid) { - return { valid: true }; - } else { - return { - valid: false, - message: valid.message, - errors: valid.errors, - missingProperties: valid.missingColumnsList, - }; - } - } catch (error) { - console.error("Error in excel validations: ", error?.message); - return { valid: false, message: ["ERROR_PARSING_FILE"] }; - } -}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js deleted file mode 100644 index 130043f2d45..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js +++ /dev/null @@ -1,97 +0,0 @@ -import ExcelJS from "exceljs"; - -// input is a xlsx blob -// options {header} -// header: true -> have seperate header so data will be in key: value pair -export const parseXlsxToJsonMultipleSheets = async (file, options = {}) => { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - - reader.onload = async (event) => { - try { - const arrayBuffer = event.target.result; - const workbook = new ExcelJS.Workbook(); - await workbook.xlsx.load(arrayBuffer); - - const jsonData = {}; - workbook.eachSheet((worksheet, sheetId) => { - const jsonSheetData = []; - let headers = []; - - worksheet.eachRow({ includeEmpty: true }, (row, rowNumber) => { - const rowData = row.values.slice(1); // Remove the first element (it's always undefined due to ExcelJS indexing from 1) - for (let i = 0; i < rowData.length; i++) { - if (typeof rowData[i] === "string") { - rowData[i] = rowData[i].trim(); - } - } - - if (options.header && rowNumber === 1) { - headers = rowData; - } else if (options.header && headers.length > 0) { - const rowObject = {}; - headers.forEach((header, index) => { - rowObject[header] = rowData[index]; - }); - jsonSheetData.push(rowObject); - } else { - jsonSheetData.push(rowData); - } - }); - - if (jsonSheetData.length !== 0 && jsonSheetData?.[0].length !== 0) jsonData[worksheet.name] = jsonSheetData; - }); - resolve(jsonData); - } catch (error) { - console.error(error); - resolve({ error: true }); - } - }; - - reader.onerror = (error) => { - console.error(error); - resolve({ error: true, details: error }); - }; - - reader.readAsArrayBuffer(file); - }); -}; - -// export const parseXlsxToJsonMultipleSheetsForSessionUtil = (file, options, fileData) => { -// return new Promise((resolve, reject) => { -// const reader = new FileReader(); - -// reader.onload = function (event) { -// try { -// const arrayBuffer = event.target.result; -// const workbook = XLSX.read(arrayBuffer, { type: "arraybuffer" }); -// const jsonData = {}; - -// workbook.SheetNames.forEach((sheetName) => { -// const worksheet = workbook.Sheets[sheetName]; -// // const options = { header: 1 }; -// const jsonSheetData = XLSX.utils.sheet_to_json(worksheet, options); -// for (let i = 0; i < jsonSheetData.length; i++) { -// for (let j = 0; j < jsonSheetData[i].length; j++) { -// const cell = jsonSheetData[i][j]; -// if (typeof cell === "string") { -// jsonSheetData[i][j] = cell.trim(); -// } -// } -// } -// if (jsonSheetData.length !== 0 && jsonSheetData?.[0].length !== 0) jsonData[sheetName] = jsonSheetData; -// }); - -// resolve({ jsonData, file: fileData }); -// } catch (error) { -// resolve({ error: true }); -// } -// }; - -// reader.onerror = function (error) { -// resolve({ error: true, details: error }); -// }; - -// reader.readAsArrayBuffer(file); -// }); -// }; diff --git a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js b/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js deleted file mode 100644 index 2e1796f781a..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js +++ /dev/null @@ -1,44 +0,0 @@ -import ExcelJS from "exceljs"; - -export const convertJsonToXlsx = async (jsonData, columnWithStyle) => { - // Create a new workbook - const workbook = new ExcelJS.Workbook(); - - // Iterate over each sheet in jsonData - for (const [sheetName, data] of Object.entries(jsonData)) { - // Create a new worksheet - const worksheet = workbook.addWorksheet(sheetName); - - // Convert data to worksheet - for (const row of data) { - const newRow = worksheet.addRow(row); - // Apply red font color to the errorColumn if it exists - let errorColumnIndex = data[0].indexOf(columnWithStyle?.errorColumn); - if (columnWithStyle?.errorColumn && errorColumnIndex !== -1) { - const columnIndex = errorColumnIndex + 1; - if (columnIndex > 0) { - const newCell = newRow.getCell(columnIndex); - if (columnWithStyle.style && newCell) for (const key in columnWithStyle.style) newCell[key] = columnWithStyle.style[key]; - } - } - } - - // Make the first row bold - if (worksheet.getRow(1)) { - worksheet.getRow(1).font = { bold: true }; - } - - // Set column widths - const columnCount = data?.[0]?.length || 0; - const wscols = Array(columnCount).fill({ width: 30 }); - wscols.forEach((col, colIndex) => { - worksheet.getColumn(colIndex + 1).width = col.width; - }); - } - - // Write the workbook to a buffer - return await workbook.xlsx.writeBuffer({ compression: true }).then((buffer) => { - // Create a Blob from the buffer - return new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); - }); -}; diff --git a/frontend/microplan-ui/web/micro-ui-internals/publish-develop.sh b/frontend/microplan-ui/web/micro-ui-internals/publish-develop.sh deleted file mode 100644 index cd9a49b0b4f..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/publish-develop.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -BASEDIR="$(cd "$(dirname "$0")" && pwd)" - -msg() { - echo -e "\n\n\033[32;32m$1\033[0m" -} - - -# msg "Pre-building all packages" -# yarn build -# sleep 5 - -msg "Building and publishing css" -cd "$BASEDIR/packages/css" && rm -rf dist && yarn && npm publish --tag microplan-1.0 - - -# msg "Building and publishing libraries" -# cd "$BASEDIR/packages/modules/hcm-microplanning" && rm -rf dist && yarn&& npm publish --tag microplan-1.0 - diff --git a/frontend/microplan-ui/web/micro-ui-internals/publish.sh b/frontend/microplan-ui/web/micro-ui-internals/publish.sh deleted file mode 100644 index cd9a49b0b4f..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/publish.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -BASEDIR="$(cd "$(dirname "$0")" && pwd)" - -msg() { - echo -e "\n\n\033[32;32m$1\033[0m" -} - - -# msg "Pre-building all packages" -# yarn build -# sleep 5 - -msg "Building and publishing css" -cd "$BASEDIR/packages/css" && rm -rf dist && yarn && npm publish --tag microplan-1.0 - - -# msg "Building and publishing libraries" -# cd "$BASEDIR/packages/modules/hcm-microplanning" && rm -rf dist && yarn&& npm publish --tag microplan-1.0 - diff --git a/frontend/microplan-ui/web/micro-ui-internals/scripts/create.sh b/frontend/microplan-ui/web/micro-ui-internals/scripts/create.sh deleted file mode 100644 index 9de72331774..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/scripts/create.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -./scripts/run.sh core utilities diff --git a/frontend/microplan-ui/web/micro-ui-internals/scripts/deploy.sh b/frontend/microplan-ui/web/micro-ui-internals/scripts/deploy.sh deleted file mode 100644 index 5b0c7b831ed..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/scripts/deploy.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -curl -v -X POST https://builds.digit.org/job/builds/job/digit-ui/buildWithParameters \ - --user saurabh-egov:114cbf3df675835931688b2d3f0014a1f7 \ - --data-urlencode json='{"parameter": [{"name":"BRANCH", "value":"origin/'$1'"}]}' - -# curl https://builds.digit.org/job/builds/job/digit-ui/lastBuild/api/json | grep --color result\":null - diff --git a/frontend/microplan-ui/web/micro-ui-internals/scripts/jenkins.sh b/frontend/microplan-ui/web/micro-ui-internals/scripts/jenkins.sh deleted file mode 100644 index a1711fec55b..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/scripts/jenkins.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -./scripts/deploy.sh dev \ No newline at end of file diff --git a/frontend/microplan-ui/web/micro-ui-internals/scripts/run.sh b/frontend/microplan-ui/web/micro-ui-internals/scripts/run.sh deleted file mode 100644 index f00c59f13b8..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/scripts/run.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -MODULES=( "components" "core" "libraries" "example" ) - -RUNARGS=() -BUILDARGS=() - -for var in "$@" -do - BUILDARGS=( ${BUILDARGS[@]} build:"$var" ) - RUNARGS=( ${RUNARGS[@]} dev:"$var" ) -done - -a=0 -while [ "$a" -lt 3 ] -do - BUILD[$a]=build:${MODULES[$a]} - a=` expr $a + 1 ` -done - -echo "BUILDING MODULES:-" ${BUILD[*]} ${BUILDARGS[*]} -yarn run-p ${BUILD[*]} ${BUILDARGS[*]} - -b=0 -while [ "$b" -lt 4 ] -do - RUN[$b]=dev:${MODULES[$b]} - b=` expr $b + 1 ` -done - -echo "SERVING MODULES:-" ${RUN[*]} ${RUNARGS[*]} -yarn run-p ${RUN[*]} ${RUNARGS[*]} \ No newline at end of file diff --git a/frontend/microplan-ui/web/micro-ui-internals/test.js b/frontend/microplan-ui/web/micro-ui-internals/test.js deleted file mode 100644 index 60c958d0bac..00000000000 --- a/frontend/microplan-ui/web/micro-ui-internals/test.js +++ /dev/null @@ -1,31 +0,0 @@ -const middleWare_1 = (data, _break, _next) => { - data.a = "a"; - _next(data); -}; - - -const middleWare_2 = (data, _break, _next) => { - data.b = "b"; - // _break(); - _next(data); -}; - -const middleWare_3 = (data, _break, _next) => { - data.c = "c"; - _next(data); -}; - -let middleWares = [middleWare_1, middleWare_2, middleWare_3]; - -const callMiddlewares = () => { - let applyBreak = false; - let itr = -1; - let _break = () => (applyBreak = true); - let _next = (data) => { - if (!applyBreak && ++itr < middleWares.length) middleWares[itr](data, _break, _next); - else return; - }; - _next({}); -}; - -callMiddlewares(); diff --git a/frontend/microplan-ui/web/package.json b/frontend/microplan-ui/web/package.json deleted file mode 100644 index f47fcd5fb80..00000000000 --- a/frontend/microplan-ui/web/package.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "name": "micro-ui", - "version": "1.0.0", - "author": "Jagankumar ", - "license": "MIT", - "private": true, - "engines": { - "node": ">=14" - }, - "workspaces": [ - "micro-ui-internals/packages/libraries", - "micro-ui-internals/packages/react-components", - "micro-ui-internals/packages/modules/*" - ], - "homepage": "/digit-ui", - "dependencies": { - "@egovernments/digit-ui-libraries": "1.8.2-beta.1", - "@egovernments/digit-ui-module-workbench": "1.0.2-beta.1", - "@egovernments/digit-ui-module-core": "1.8.2-beta.1", - "@egovernments/digit-ui-module-hrms": "1.8.0-beta.2", - "@egovernments/digit-ui-react-components": "1.8.2-beta.1", - "@egovernments/digit-ui-module-dss": "1.8.0-beta", - "@egovernments/digit-ui-module-common": "1.8.0-beta", - "@egovernments/digit-ui-module-utilities": "1.0.1-beta.23", - "@egovernments/digit-ui-module-engagement": "1.5.20", - "babel-loader": "8.1.0", - "clean-webpack-plugin": "4.0.0", - "react": "17.0.2", - "react-dom": "17.0.2", - "jsonpath": "^1.1.1", - "react-router-dom": "5.3.0", - "react-scripts": "4.0.1", - "web-vitals": "1.1.2", - "terser-brunch": "^4.1.0", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "css-loader": "5.2.6", - "style-loader": "2.0.0", - "webpack-cli": "4.10.0" - }, - "devDependencies": { - "@babel/plugin-proposal-private-property-in-object": "7.21.0", - "http-proxy-middleware": "1.3.1", - "lodash": "4.17.21", - "file-loader": "^6.2.0", - "microbundle-crl": "0.13.11", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "react-router-dom": "5.3.0", - "husky": "7.0.4", - "lint-staged": "12.3.7", - "npm-run-all": "4.1.5", - "prettier": "2.1.2" - }, - "scripts": { - "start": "react-scripts start", - "build": "GENERATE_SOURCEMAP=false SKIP_PREFLIGHT_CHECK=true react-scripts build", - "build:prepare": "./build.sh", - "build:libraries": "cd micro-ui-internals && yarn build", - "build:prod": "webpack --mode production", - "build:webpack": "yarn build:libraries &&cd .. && ls && cd ./web && ls && yarn build:prod", - "clean": "rm -rf node_modules" - }, - "eslintConfig": { - "extends": [ - "react-app" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} \ No newline at end of file diff --git a/frontend/microplan-ui/web/public/index.html b/frontend/microplan-ui/web/public/index.html deleted file mode 100644 index 11a58320150..00000000000 --- a/frontend/microplan-ui/web/public/index.html +++ /dev/null @@ -1,47 +0,0 @@ - - - - - - - - - - - - DIGIT - - - - - - -
- - - diff --git a/frontend/microplan-ui/web/public/robots.txt b/frontend/microplan-ui/web/public/robots.txt deleted file mode 100644 index e9e57dc4d41..00000000000 --- a/frontend/microplan-ui/web/public/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# https://www.robotstxt.org/robotstxt.html -User-agent: * -Disallow: diff --git a/frontend/microplan-ui/web/src/App.js b/frontend/microplan-ui/web/src/App.js deleted file mode 100644 index 4a60913eee0..00000000000 --- a/frontend/microplan-ui/web/src/App.js +++ /dev/null @@ -1,53 +0,0 @@ -import React from "react"; -import { initLibraries } from "@egovernments/digit-ui-libraries"; -import { DigitUI } from "@egovernments/digit-ui-module-core"; -import { UICustomizations } from "./Customisations/UICustomizations"; -import { initMicroplanningComponents } from "@egovernments/digit-ui-module-hcmmicroplanning"; - -window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); - -const enabledModules = [ - "Microplanning" -]; - -const moduleReducers = (initData) => ({ - initData, -}); - -const initDigitUI = () => { - window.Digit.ComponentRegistryService.setupRegistry({ - - }); - - - initMicroplanningComponents(); - - window.Digit.Customizations = { - PGR: {}, - commonUiConfig: UICustomizations, - }; -}; - -initLibraries().then(() => { - initDigitUI(); -}); - -function App() { - window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); - const stateCode = - window.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || - process.env.REACT_APP_STATE_LEVEL_TENANT_ID; - if (!stateCode) { - return

stateCode is not defined

; - } - return ( - - ); -} - -export default App; diff --git a/frontend/microplan-ui/web/src/ComponentRegistry.js b/frontend/microplan-ui/web/src/ComponentRegistry.js deleted file mode 100644 index 9bafce3dc89..00000000000 --- a/frontend/microplan-ui/web/src/ComponentRegistry.js +++ /dev/null @@ -1,11 +0,0 @@ -class Registry { - constructor(registry = {}) { - this._registry = registry; - } - - getComponent(id) { - return this._registry[id]; - } -} - -export default Registry; diff --git a/frontend/microplan-ui/web/src/Customisations/UICustomizations.js b/frontend/microplan-ui/web/src/Customisations/UICustomizations.js deleted file mode 100644 index 6d17ab0d51b..00000000000 --- a/frontend/microplan-ui/web/src/Customisations/UICustomizations.js +++ /dev/null @@ -1,428 +0,0 @@ -import { Link } from "react-router-dom"; -import _ from "lodash"; - -//create functions here based on module name set in mdms(eg->SearchProjectConfig) -//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName] -// these functions will act as middlewares -var Digit = window.Digit || {}; - - - -const businessServiceMap = { - - "muster roll": "MR" -}; - -const inboxModuleNameMap = { - "muster-roll-approval": "muster-roll-service", -}; - -export const UICustomizations = { - businessServiceMap, - updatePayload: (applicationDetails, data, action, businessService) => { - - if (businessService === businessServiceMap.estimate) { - const workflow = { - comment: data.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - estimate: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap.contract) { - const workflow = { - comment: data?.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - contract: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap?.["muster roll"]) { - const workflow = { - comment: data?.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - musterRoll: applicationDetails, - workflow, - }; - } - if(businessService === businessServiceMap?.["works.purchase"]){ - const workflow = { - comment: data.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - const additionalFieldsToSet = { - projectId:applicationDetails.additionalDetails.projectId, - invoiceDate:applicationDetails.billDate, - invoiceNumber:applicationDetails.referenceId.split('_')?.[1], - contractNumber:applicationDetails.referenceId.split('_')?.[0], - documents:applicationDetails.additionalDetails.documents - } - return { - bill: {...applicationDetails,...additionalFieldsToSet}, - workflow, - }; - } - }, - enableModalSubmit:(businessService,action,setModalSubmit,data)=>{ - if(businessService === businessServiceMap?.["muster roll"] && action.action==="APPROVE"){ - setModalSubmit(data?.acceptTerms) - } - }, - enableHrmsSearch: (businessService, action) => { - if (businessService === businessServiceMap.estimate) { - return action.action.includes("TECHNICALSANCTION") || action.action.includes("VERIFYANDFORWARD"); - } - if (businessService === businessServiceMap.contract) { - return action.action.includes("VERIFY_AND_FORWARD"); - } - if (businessService === businessServiceMap?.["muster roll"]) { - return action.action.includes("VERIFY"); - } - if(businessService === businessServiceMap?.["works.purchase"]){ - return action.action.includes("VERIFY_AND_FORWARD") - } - return false; - }, - getBusinessService: (moduleCode) => { - if (moduleCode?.includes("estimate")) { - return businessServiceMap?.estimate; - } else if (moduleCode?.includes("contract")) { - return businessServiceMap?.contract; - } else if (moduleCode?.includes("muster roll")) { - return businessServiceMap?.["muster roll"]; - } - else if (moduleCode?.includes("works.purchase")) { - return businessServiceMap?.["works.purchase"]; - } - else if (moduleCode?.includes("works.wages")) { - return businessServiceMap?.["works.wages"]; - } - else if (moduleCode?.includes("works.supervision")) { - return businessServiceMap?.["works.supervision"]; - } - else { - return businessServiceMap; - } - }, - getInboxModuleName: (moduleCode) => { - if (moduleCode?.includes("estimate")) { - return inboxModuleNameMap?.estimate; - } else if (moduleCode?.includes("contract")) { - return inboxModuleNameMap?.contracts; - } else if (moduleCode?.includes("attendence")) { - return inboxModuleNameMap?.attendencemgmt; - } else { - return inboxModuleNameMap; - } - }, - - AttendanceInboxConfig: { - preProcess: (data) => { - - //set tenantId - data.body.inbox.tenantId = Digit.ULBService.getCurrentTenantId(); - data.body.inbox.processSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); - - const musterRollNumber = data?.body?.inbox?.moduleSearchCriteria?.musterRollNumber?.trim(); - if(musterRollNumber) data.body.inbox.moduleSearchCriteria.musterRollNumber = musterRollNumber - - const attendanceRegisterName = data?.body?.inbox?.moduleSearchCriteria?.attendanceRegisterName?.trim(); - if(attendanceRegisterName) data.body.inbox.moduleSearchCriteria.attendanceRegisterName = attendanceRegisterName - - // deleting them for now(assignee-> need clarity from pintu,ward-> static for now,not implemented BE side) - const assignee = _.clone(data.body.inbox.moduleSearchCriteria.assignee); - delete data.body.inbox.moduleSearchCriteria.assignee; - if (assignee?.code === "ASSIGNED_TO_ME") { - data.body.inbox.moduleSearchCriteria.assignee = Digit.UserService.getUser().info.uuid; - } - - //cloning locality and workflow states to format them - // let locality = _.clone(data.body.inbox.moduleSearchCriteria.locality ? data.body.inbox.moduleSearchCriteria.locality : []); - - let selectedOrg = _.clone(data.body.inbox.moduleSearchCriteria.orgId ? data.body.inbox.moduleSearchCriteria.orgId : null); - delete data.body.inbox.moduleSearchCriteria.orgId; - if(selectedOrg) { - data.body.inbox.moduleSearchCriteria.orgId = selectedOrg?.[0]?.applicationNumber; - } - - // let selectedWard = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : null); - // delete data.body.inbox.moduleSearchCriteria.ward; - // if(selectedWard) { - // data.body.inbox.moduleSearchCriteria.ward = selectedWard?.[0]?.code; - // } - - let states = _.clone(data.body.inbox.moduleSearchCriteria.state ? data.body.inbox.moduleSearchCriteria.state : []); - let ward = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : []); - // delete data.body.inbox.moduleSearchCriteria.locality; - delete data.body.inbox.moduleSearchCriteria.state; - delete data.body.inbox.moduleSearchCriteria.ward; - - // locality = locality?.map((row) => row?.code); - states = Object.keys(states)?.filter((key) => states[key]); - ward = ward?.map((row) => row?.code); - - - // //adding formatted data to these keys - // if (locality.length > 0) data.body.inbox.moduleSearchCriteria.locality = locality; - if (states.length > 0) data.body.inbox.moduleSearchCriteria.status = states; - if (ward.length > 0) data.body.inbox.moduleSearchCriteria.ward = ward; - const projectType = _.clone(data.body.inbox.moduleSearchCriteria.projectType ? data.body.inbox.moduleSearchCriteria.projectType : {}); - if (projectType?.code) data.body.inbox.moduleSearchCriteria.projectType = projectType.code; - - //adding tenantId to moduleSearchCriteria - data.body.inbox.moduleSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); - - //setting limit and offset becoz somehow they are not getting set in muster inbox - data.body.inbox .limit = data.state.tableForm.limit - data.body.inbox.offset = data.state.tableForm.offset - delete data.state - return data; - }, - postProcess: (responseArray, uiConfig) => { - const statusOptions = responseArray?.statusMap - ?.filter((item) => item.applicationstatus) - ?.map((item) => ({ code: item.applicationstatus, i18nKey: `COMMON_MASTERS_${item.applicationstatus}` })); - if (uiConfig?.type === "filter") { - let fieldConfig = uiConfig?.fields?.filter((item) => item.type === "dropdown" && item.populators.name === "musterRollStatus"); - if (fieldConfig.length) { - fieldConfig[0].populators.options = statusOptions; - } - } - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - if (key === "ATM_MUSTER_ROLL_ID") { - return ( - - - {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} - - - ); - } - if (key === "ATM_ATTENDANCE_WEEK") { - const week = `${Digit.DateUtils.ConvertTimestampToDate(value?.startDate, "dd/MM/yyyy")}-${Digit.DateUtils.ConvertTimestampToDate( - value?.endDate, - "dd/MM/yyyy" - )}`; - return
{week}
; - } - if (key === "ATM_NO_OF_INDIVIDUALS") { - return
{value?.length}
; - } - if(key === "ATM_AMOUNT_IN_RS"){ - return {value ? Digit.Utils.dss.formatterWithoutRound(value, "number") : t("ES_COMMON_NA")}; - } - if (key === "ATM_SLA") { - return parseInt(value) > 0 ? ( - {t(value) || ""} - ) : ( - {t(value) || ""} - ); - } - if (key === "COMMON_WORKFLOW_STATES") { - return {t(`WF_MUSTOR_${value}`)} - } - //added this in case we change the key and not updated here , it'll throw that nothing was returned from cell error if that case is not handled here. To prevent that error putting this default - return {t(`CASE_NOT_HANDLED`)} - }, - MobileDetailsOnClick: (row, tenantId) => { - let link; - Object.keys(row).map((key) => { - if (key === "ATM_MUSTER_ROLL_ID") - link = `/${window.contextPath}/employee/attendencemgmt/view-attendance?tenantId=${tenantId}&musterRollNumber=${row[key]}`; - }); - return link; - }, - populateReqCriteria: () => { - const tenantId = Digit.ULBService.getCurrentTenantId(); - return { - url: "/org-services/organisation/v1/_search", - params: { limit: 50, offset: 0 }, - body: { - SearchCriteria: { - tenantId: tenantId, - functions : { - type : "CBO" - } - }, - }, - config: { - enabled: true, - select: (data) => { - return data?.organisations; - }, - }, - }; - }, - }, - SearchWageSeekerConfig: { - customValidationCheck: (data) => { - //checking both to and from date are present - const { createdFrom, createdTo } = data; - if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === "")) - return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; - - return false; - }, - preProcess: (data) => { - data.params = { ...data.params, tenantId: Digit.ULBService.getCurrentTenantId() }; - - let requestBody = { ...data.body.Individual }; - const pathConfig = { - name: "name.givenName", - }; - const dateConfig = { - createdFrom: "daystart", - createdTo: "dayend", - }; - const selectConfig = { - wardCode: "wardCode[0].code", - socialCategory: "socialCategory.code", - }; - const textConfig = ["name", "individualId"] - let Individual = Object.keys(requestBody) - .map((key) => { - if (selectConfig[key]) { - requestBody[key] = _.get(requestBody, selectConfig[key], null); - } else if (typeof requestBody[key] == "object") { - requestBody[key] = requestBody[key]?.code; - } else if (textConfig?.includes(key)) { - requestBody[key] = requestBody[key]?.trim() - } - return key; - }) - .filter((key) => requestBody[key]) - .reduce((acc, curr) => { - if (pathConfig[curr]) { - _.set(acc, pathConfig[curr], requestBody[curr]); - } else if (dateConfig[curr] && dateConfig[curr]?.includes("day")) { - _.set(acc, curr, Digit.Utils.date.convertDateToEpoch(requestBody[curr], dateConfig[curr])); - } else { - _.set(acc, curr, requestBody[curr]); - } - return acc; - }, {}); - - data.body.Individual = { ...Individual }; - return data; - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - //here we can add multiple conditions - //like if a cell is link then we return link - //first we can identify which column it belongs to then we can return relevant result - switch (key) { - case "MASTERS_WAGESEEKER_ID": - return ( - - - {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} - - - ); - - case "MASTERS_SOCIAL_CATEGORY": - return value ? {String(t(`MASTERS_${value}`))} : t("ES_COMMON_NA"); - - case "CORE_COMMON_PROFILE_CITY": - return value ? {String(t(Digit.Utils.locale.getCityLocale(value)))} : t("ES_COMMON_NA"); - - case "MASTERS_WARD": - return value ? ( - {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} - ) : ( - t("ES_COMMON_NA") - ); - - case "MASTERS_LOCALITY": - return value ? ( - {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} - ) : ( - t("ES_COMMON_NA") - ); - default: - return t("ES_COMMON_NA"); - } - }, - MobileDetailsOnClick: (row, tenantId) => { - let link; - Object.keys(row).map((key) => { - if (key === "MASTERS_WAGESEEKER_ID") - link = `/${window.contextPath}/employee/masters/view-wageseeker?tenantId=${tenantId}&wageseekerId=${row[key]}`; - }); - return link; - }, - additionalValidations: (type, data, keys) => { - if (type === "date") { - return data[keys.start] && data[keys.end] ? () => new Date(data[keys.start]).getTime() <= new Date(data[keys.end]).getTime() : true; - } - } - }, -}; diff --git a/frontend/microplan-ui/web/src/Customisations/index.js b/frontend/microplan-ui/web/src/Customisations/index.js deleted file mode 100644 index 60fcbe8ac77..00000000000 --- a/frontend/microplan-ui/web/src/Customisations/index.js +++ /dev/null @@ -1,9 +0,0 @@ -var Digit = window.Digit || {}; - -const customisedComponent = {}; - -export const initCustomisationComponents = () => { - Object.entries(customisedComponent).forEach(([key, value]) => { - Digit.ComponentRegistryService.setComponent(key, value); - }); -}; diff --git a/frontend/microplan-ui/web/src/index.css b/frontend/microplan-ui/web/src/index.css deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/frontend/microplan-ui/web/src/index.js b/frontend/microplan-ui/web/src/index.js deleted file mode 100644 index 492c14421c8..00000000000 --- a/frontend/microplan-ui/web/src/index.js +++ /dev/null @@ -1,68 +0,0 @@ -import React from "react"; -import ReactDOM from "react-dom"; -import { initLibraries } from "@egovernments/digit-ui-libraries"; -import "./index.css"; -import App from "./App"; -import { initMicroplanningComponents } from "@egovernments/digit-ui-module-hcmmicroplanning"; -import { UICustomizations } from "./Customisations/UICustomizations"; - -initLibraries(); -initMicroplanningComponents(); - -window.Digit.Customizations = { PGR: {}, commonUiConfig: UICustomizations }; - -const user = window.Digit.SessionStorage.get("User"); - -if (!user || !user.access_token || !user.info) { - // login detection - - const parseValue = (value) => { - try { - return JSON.parse(value); - } catch (e) { - return value; - } - }; - - const getFromStorage = (key) => { - const value = window.localStorage.getItem(key); - return value && value !== "undefined" ? parseValue(value) : null; - }; - - const token = getFromStorage("token"); - - const citizenToken = getFromStorage("Citizen.token"); - const citizenInfo = getFromStorage("Citizen.user-info"); - const citizenTenantId = getFromStorage("Citizen.tenant-id"); - - const employeeToken = getFromStorage("Employee.token"); - const employeeInfo = getFromStorage("Employee.user-info"); - const employeeTenantId = getFromStorage("Employee.tenant-id"); - const userType = token === citizenToken ? "citizen" : "employee"; - - window.Digit.SessionStorage.set("user_type", userType); - window.Digit.SessionStorage.set("userType", userType); - - const getUserDetails = (access_token, info) => ({ - token: access_token, - access_token, - info, - }); - - const userDetails = - userType === "citizen" - ? getUserDetails(citizenToken, citizenInfo) - : getUserDetails(employeeToken, employeeInfo); - - window.Digit.SessionStorage.set("User", userDetails); - window.Digit.SessionStorage.set("Citizen.tenantId", citizenTenantId); - window.Digit.SessionStorage.set("Employee.tenantId", employeeTenantId); - // end -} - -ReactDOM.render( - - - , - document.getElementById("root") -); diff --git a/frontend/microplan-ui/web/src/setupProxy.js b/frontend/microplan-ui/web/src/setupProxy.js deleted file mode 100644 index 1b8eda94a19..00000000000 --- a/frontend/microplan-ui/web/src/setupProxy.js +++ /dev/null @@ -1,30 +0,0 @@ -const { createProxyMiddleware } = require("http-proxy-middleware"); -const createProxy = createProxyMiddleware({ - target: process.env.REACT_APP_PROXY_URL, - changeOrigin: true, -}); -module.exports = function (app) { - [ - "/egov-mdms-service", - "/egov-location", - "/localization", - "/egov-workflow-v2", - "/pgr-services", - "/filestore", - "/egov-hrms", - "/user-otp", - "/user", - "/fsm", - "/billing-service", - "/collection-services", - "/pdf-service", - "/pg-service", - "/vehicle", - "/vendor", - "/property-services", - "/fsm-calculator/v1/billingSlab/_search", - "/muster-roll" - ].forEach((location) => - app.use(location, createProxy) - ); -}; diff --git a/frontend/microplan-ui/web/webpack.config.js b/frontend/microplan-ui/web/webpack.config.js deleted file mode 100644 index b15cf021f19..00000000000 --- a/frontend/microplan-ui/web/webpack.config.js +++ /dev/null @@ -1,51 +0,0 @@ -const path = require("path"); -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const { CleanWebpackPlugin } = require("clean-webpack-plugin"); -// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; - -module.exports = { - // mode: 'development', - entry: "./src/index.js", - devtool: "none", - module: { - rules: [ - { - test: /\.(js)$/, - use: ["babel-loader"], - }, - { - test: /\.css$/i, - use: ["style-loader", "css-loader"], - }, - { - test: /\.(png|jpe?g|gif)$/i, - use: [ - { - loader: 'file-loader', - }, - ], - }, - ], - }, - output: { - filename: "[name].bundle.js", - path: path.resolve(__dirname, "build"), - publicPath: "/digit-ui/", - }, - optimization: { - splitChunks: { - chunks: 'all', - minSize:20000, - maxSize:50000, - enforceSizeThreshold:50000, - minChunks:1, - maxAsyncRequests:30, - maxInitialRequests:30 - }, - }, - plugins: [ - new CleanWebpackPlugin(), - // new BundleAnalyzerPlugin(), - new HtmlWebpackPlugin({ inject: true, template: "public/index.html" }), - ], -}; \ No newline at end of file From c720e8dbcda1cccb0d602252c2acd2032b529cf1 Mon Sep 17 00:00:00 2001 From: Priyanka-eGov <74049060+Priyanka-eGov@users.noreply.github.com> Date: Thu, 27 Jun 2024 12:26:53 +0530 Subject: [PATCH 265/283] Adding resource-estimation-service folder for master merge (#784) * Adding resource-estimation-service folder for master merge * change names to camel case. * Code review comment * code review comments * removed lines that are not required * removed space * updated files. * change and code review comment * code review * code review * code comment * code review * removed finally --------- Co-authored-by: devdatta-egov Co-authored-by: Nilesh Shinolikar <163095321+devdatta-egov@users.noreply.github.com> --- build/build-config.yml | 4 +- .../resource-estimation-service/CHANGELOG.md | 8 + .../resource-estimation-service/LOCALSETUP.md | 39 + .../resource-estimation-service/README.md | 61 ++ .../resource-estimation-service/pom.xml | 169 +++++ .../main/java/org/egov/processor/Main.java | 20 + .../egov/processor/config/Configuration.java | 74 ++ .../processor/config/MainConfiguration.java | 38 + .../processor/config/ServiceConstants.java | 68 ++ .../egov/processor/kafka/PlanConsumer.java | 44 ++ .../org/egov/processor/kafka/Producer.java | 18 + .../repository/ServiceRequestRepository.java | 70 ++ .../egov/processor/service/ExcelParser.java | 687 ++++++++++++++++++ .../egov/processor/service/FileParser.java | 13 + .../egov/processor/service/GeoJsonParser.java | 78 ++ .../service/ResourceEstimationService.java | 112 +++ .../processor/service/ShapeFileParser.java | 146 ++++ .../org/egov/processor/util/BoundaryUtil.java | 53 ++ .../egov/processor/util/CalculationUtil.java | 139 ++++ .../util/CampaignIntegrationUtil.java | 287 ++++++++ .../egov/processor/util/FilestoreUtil.java | 214 ++++++ .../org/egov/processor/util/MdmsUtil.java | 145 ++++ .../org/egov/processor/util/ParsingUtil.java | 249 +++++++ .../processor/util/PlanConfigurationUtil.java | 57 ++ .../org/egov/processor/util/PlanUtil.java | 132 ++++ .../web/controllers/FileController.java | 54 ++ .../egov/processor/web/models/Activity.java | 48 ++ .../egov/processor/web/models/Assumption.java | 45 ++ .../egov/processor/web/models/Condition.java | 40 + .../org/egov/processor/web/models/File.java | 83 +++ .../processor/web/models/MetricDetail.java | 34 + .../egov/processor/web/models/Operation.java | 92 +++ .../org/egov/processor/web/models/Plan.java | 63 ++ .../web/models/PlanConfiguration.java | 89 +++ .../web/models/PlanConfigurationRequest.java | 30 + .../web/models/PlanConfigurationResponse.java | 40 + .../PlanConfigurationSearchCriteria.java | 39 + .../PlanConfigurationSearchRequest.java | 30 + .../processor/web/models/PlanRequest.java | 30 + .../egov/processor/web/models/Resource.java | 39 + .../processor/web/models/ResourceMapping.java | 47 ++ .../org/egov/processor/web/models/Target.java | 37 + .../boundary/BoundarySearchResponse.java | 45 ++ .../web/models/boundary/EnrichedBoundary.java | 46 ++ .../models/boundary/HierarchyRelation.java | 37 + .../campaignManager/AdditionalDetails.java | 32 + .../web/models/campaignManager/Boundary.java | 41 ++ .../web/models/campaignManager/Campaign.java | 92 +++ .../campaignManager/CampaignCondition.java | 21 + .../campaignManager/CampaignDetails.java | 32 + .../campaignManager/CampaignRequest.java | 27 + .../campaignManager/CampaignResources.java | 41 ++ .../campaignManager/CampaignResponse.java | 31 + .../CampaignSearchRequest.java | 28 + .../campaignManager/CycleConfigureDate.java | 29 + .../web/models/campaignManager/CycleData.java | 18 + .../models/campaignManager/DeliveryRule.java | 38 + .../web/models/campaignManager/Product.java | 31 + .../src/main/resources/application.properties | 80 ++ .../src/main/resources/db/Dockerfile | 9 + .../src/main/resources/db/migrate.sh | 3 + 61 files changed, 4443 insertions(+), 3 deletions(-) create mode 100644 health-services/resource-estimation-service/CHANGELOG.md create mode 100644 health-services/resource-estimation-service/LOCALSETUP.md create mode 100644 health-services/resource-estimation-service/README.md create mode 100644 health-services/resource-estimation-service/pom.xml create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/Main.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/config/Configuration.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/config/MainConfiguration.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/PlanConsumer.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/Producer.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/repository/ServiceRequestRepository.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/service/FileParser.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/service/GeoJsonParser.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ResourceEstimationService.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ShapeFileParser.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/util/BoundaryUtil.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CalculationUtil.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/util/FilestoreUtil.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/util/MdmsUtil.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/util/ParsingUtil.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanUtil.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/controllers/FileController.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Activity.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Assumption.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Condition.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/File.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/MetricDetail.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Operation.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Plan.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfiguration.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationRequest.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationResponse.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchCriteria.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchRequest.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanRequest.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Resource.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/ResourceMapping.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Target.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/BoundarySearchResponse.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/EnrichedBoundary.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/HierarchyRelation.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/AdditionalDetails.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Boundary.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Campaign.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignCondition.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignDetails.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignRequest.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResources.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResponse.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignSearchRequest.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleConfigureDate.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleData.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/DeliveryRule.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Product.java create mode 100644 health-services/resource-estimation-service/src/main/resources/application.properties create mode 100644 health-services/resource-estimation-service/src/main/resources/db/Dockerfile create mode 100644 health-services/resource-estimation-service/src/main/resources/db/migrate.sh diff --git a/build/build-config.yml b/build/build-config.yml index 2a8fb6940dd..dec24965782 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -254,9 +254,7 @@ config: build: - work-dir: "health-services/resource-estimation-service" image-name: "resource-estimation-service" - dockerfile: "build/17/maven/Dockerfile" - - work-dir: "health-services/resource-estimation-service/src/main/resources/db" - image-name: "resource-estimation-service-db" + dockerfile: "build/17/maven/Dockerfile" - name: "builds/health-campaign-services/analytics/auth-proxy" build: - work-dir: "analytics/auth-proxy" diff --git a/health-services/resource-estimation-service/CHANGELOG.md b/health-services/resource-estimation-service/CHANGELOG.md new file mode 100644 index 00000000000..e5ce4491284 --- /dev/null +++ b/health-services/resource-estimation-service/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog +## 1.0.0 - 2024-06-24 +#### Base Resource Estimation Service + 1. Resource Estimation Service manages file processing: validating data, calculating for files, updating plans, and integrating with campaigns. + 2. File Processing: In file processing, it processes files present in plan configuration by calculating resources. + 3. Updating Plan: It creates plans based on rows and updates those by putting them on topics that are consumed by the plan service. + 4. Integrate with Campaign Manager: After processing calculations, it also integrates resources and boundary with the Campaign Manager. + 5. Boundary and Data Validation: Validates boundaries and excel data during calculations. \ No newline at end of file diff --git a/health-services/resource-estimation-service/LOCALSETUP.md b/health-services/resource-estimation-service/LOCALSETUP.md new file mode 100644 index 00000000000..88506beb5eb --- /dev/null +++ b/health-services/resource-estimation-service/LOCALSETUP.md @@ -0,0 +1,39 @@ +# Local Setup + +To set up the Resource Estimation Service in your local system, clone the [Health Campaign Services repository](https://github.com/egovernments/health-campaign-services.git). + +## Dependencies + +- [x] Postgres DB +- [ ] Redis +- [ ] Elasticsearch +- [x] Kafka + - [x] Consumer + - [x] Producer + + +## Running Locally + +### Local setup +1. To set up the Resource Estimation Service in your local system, clone the [Health Campaign Services repository](https://github.com/egovernments/health-campaign-services.git). +2. Install GIT. + [For Windows](https://git-scm.com/download/win). + [For Linux](https://www.digitalocean.com/community/tutorials/how-to-install-git-on-ubuntu-18-04-quickstart). +2. Install JDK version 17 or above. + [For windows](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html). + [For Linux](https://javahelps.com/install-oracle-jdk-17-on-linux). +3. Install maven locally and configure environment variables. +4. Install Kafka (version 3.2.0 which is the latest version) - To install and run Kafka locally, follow the following links - + [Kafka for windows](https://dzone.com/articles/running-apache-kafka-on-windows-os) or [Kafka for Linux](https://tecadmin.net/install-apache-kafka-ubuntu/) +5. Install Postman - To install Postman, follow the following links - + [Postman for windows](https://www.postman.com/downloads/) +6. Install Kubectl - Kubectl is the tool that we use to interact with services deployed on our sandbox environment - + [kubectl for windows](https://core.digit.org/guides/operations-guide/working-with-kubernetes/installation-of-kubectl) + [kubectl for Linux](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/) +7. Install aws-iam-authenticator - [if the DIGIT development environment is in AWS](https://docs.aws.amazon.com/eks/latest/userguide/install-aws-iam-authenticator.html) +8. Install PostgreSQL v14 locally. +4. Also update DB config values as per your local system config. +5. Update all dependency service host either on any unified-env or port-forward. +6. Run spring boot main class + +> Note: After running the above steps, if you encounter a Kafka error, ensure that both Kafka and Zookeeper services are actively running. For connection errors with other microservices, verify the correctness of the URL in the external mapping of the data configuration or consider port-forwarding the problematic service for direct access. \ No newline at end of file diff --git a/health-services/resource-estimation-service/README.md b/health-services/resource-estimation-service/README.md new file mode 100644 index 00000000000..1d3816cce38 --- /dev/null +++ b/health-services/resource-estimation-service/README.md @@ -0,0 +1,61 @@ +# Resource Estimation Service Documentation + +## Overview + +The resource estimation service processes various file formats to estimate resources, generate microplans, upload result sheets, and update the HCM Admin Console. It integrates with other services like Mdms, Filestore, Project Factory, and Plan Service to ensure accurate resource estimation and campaign planning. + +## Key Features + +- **Parsing and Estimating Resources**: Processes file formats (Excel, Shapefiles, GeoJSON) to estimate necessary resources for micro planning by applying assumptions and formulas. +- **Validation**: Validates file data for proper data types and updates plan configuration status based on exceptions. +- **Generating Microplans**: Triggers the creation of microplans based on estimated resources and input data, detailing resource distribution for campaigns. +- **Uploading Results**: Uploads updated result sheets to a filestore, ensuring secure storage and accessibility. +- **Integrating with HCM Admin Console**: Updates the HCM Admin Console with estimated resources for effective campaign planning and execution. + +## Service Dependencies + +- **Mdms service** +- **Filestore service** +- **Project Factory service** +- **Plan service** + +## API Specification + +- Not Applicable (NA) + +## Sequence Diagram + +- To be provided (Placeholder) + +## Producer Details + +### Topics + +| Topic | Description | +|--------------------------------|-------------------------------------------------------------------------| +| resource-microplan-create-topic | Pushes to Plan Service for microplan creation after resource estimation. | +| resource-plan-config-update-topic | Updates a plan configuration with INVALID_DATA status in case of processing exceptions. | + +### Topics + +| Topic | Description | +|---------------------------|------------------------------------------------------------------------| +| plan-config-update-topic | Triggers resource estimation, microplan creation, and campaign manager integration. | + +## Configuration and Deployment + +- **Persister Config**: NA +- **Helm Chart**: Deployment details available [here](https://github.com/egovernments/DIGIT-DevOps/tree/unified-env/deploy-as-code/helm/charts/health-services/resource-estimation-service). + +## Environment Variables + +- Configure environment variables such as `db-host`, `db-name`, `db-url`, `domain`, and other DIGIT core platform services configurations before deployment. + +## MDMS Configuration + +- Configure MDMS data for Plan Service as per the documentation [here](https://github.com/egovernments/egov-mdms-data/tree/UNIFIED-QA/data/mz/health/hcm-microplanning). + +## Reference Documents + +- **MDMS Technical Document**: [Mdms service](https://core.digit.org/platform/core-services/mdms-master-data-management-service) + diff --git a/health-services/resource-estimation-service/pom.xml b/health-services/resource-estimation-service/pom.xml new file mode 100644 index 00000000000..c73dd06629d --- /dev/null +++ b/health-services/resource-estimation-service/pom.xml @@ -0,0 +1,169 @@ + + 4.0.0 + org.egov + resource-estimation-service + jar + file-processor-utility + 1.0.0 + + 17 + 32-SNAPSHOT + 17 + 17 + + + 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.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 + + + org.geotools + gt-shapefile + ${geotools.version} + + + org.geotools + gt-geojson + ${geotools.version} + + + org.apache.poi + poi + 5.2.5 + + + org.apache.poi + poi-ooxml + 5.2.5 + + + org.springframework + spring-test + 5.3.10 + + + + + 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 + + + jakarta.annotation + jakarta.annotation-api + + + com.fasterxml.jackson.core + jackson-databind + + + org.springframework + spring-web + + + + + + 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/ + + + apache.snapshots + Apache Development Snapshot Repository + https://repository.apache.org/snapshots/ + + + osgeo-snapshot + OSGeo Snapshot Repository + https://repo.osgeo.org/repository/snapshot/ + + true + + + false + + + + diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/Main.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/Main.java new file mode 100644 index 00000000000..bee96b9f016 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/Main.java @@ -0,0 +1,20 @@ +package org.egov.processor; + + +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 = { "org.egov.processor", "org.egov.processor.web.controllers" , "org.egov.processor.config"}) +public class Main { + + + public static void main(String[] args) throws Exception { + SpringApplication.run(Main.class, args); + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/Configuration.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/Configuration.java new file mode 100644 index 00000000000..089320e0b06 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/Configuration.java @@ -0,0 +1,74 @@ +package org.egov.processor.config; + +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 lombok.AllArgsConstructor; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Component +@Data +@Import({ TracerConfiguration.class }) +@NoArgsConstructor +@AllArgsConstructor +@Setter +@Getter +public class Configuration { + + // MDMS + @Value("${egov.mdms.host}") + private String mdmsHost; + + @Value("${egov.mdms.search.endpoint}") + private String mdmsEndPoint; + + @Value("${egov.plan.config.host}") + private String planConfigHost; + + @Value("${egov.plan.config.endpoint}") + private String planConfigEndPoint; + + // Filestore + + @Value("${egov.filestore.service.host}") + private String fileStoreHost; + + @Value("${egov.filestore.endpoint}") + private String fileStoreEndpoint; + + @Value("${egov.filestore.upload.endpoint}") + private String fileStoreUploadEndpoint; + + @Value("${egov.plan.create.endpoint}") + private String planCreateEndPoint; + + @Value("${egov.project.factory.search.endpoint}") + private String campaignIntegrationSearchEndPoint; + + @Value("${egov.project.factory.update.endpoint}") + private String campaignIntegrationUpdateEndPoint; + + @Value("${egov.project.factory.host}") + private String projectFactoryHostEndPoint; + + @Value("${resource.microplan.create.topic}") + private String resourceMicroplanCreateTopic; + + @Value("${integrate.with.admin.console}") + private boolean isIntegrateWithAdminConsole; + + @Value("${resource.update.plan.config.consumer.topic}") + private String resourceUpdatePlanConfigConsumerTopic; + + @Value("${egov.boundary.service.host}") + private String egovBoundaryServiceHost; + + @Value("${egov.boundary.relationship.search.endpoint}") + private String egovBoundaryRelationshipSearchEndpoint; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/MainConfiguration.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/MainConfiguration.java new file mode 100644 index 00000000000..dbead6fe299 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/MainConfiguration.java @@ -0,0 +1,38 @@ +package org.egov.processor.config; + +import jakarta.annotation.PostConstruct; +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.converter.json.MappingJackson2HttpMessageConverter; +import java.util.TimeZone; +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/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java new file mode 100644 index 00000000000..23ffe8a02ba --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java @@ -0,0 +1,68 @@ +package org.egov.processor.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 ERROR_WHILE_FETCHING_FROM_MDMS = "Exception occurred while fetching category lists from mdms: "; + + public static final String TENANTID_REPLACER = "{tenantId}"; + + public static final String TENANTID = "tenantId"; + + public static final String FILESTORE_ID_REPLACER = "{fileStoreId}"; + + public static final String FILES = "files"; + + public static final String FILESTORE_ID = "fileStoreId"; + + public static final String MODULE = "module"; + + public static final String MICROPLANNING_MODULE = "microplan"; + + public static final String PROPERTIES = "properties"; + + public static final String NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_CODE = "NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT"; + public static final String NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_MESSAGE = "Invalid or incorrect TenantId. No mdms data found for provided Tenant."; + + public static final String ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE = "Exception occurred while fetching plan configuration from plan service "; + + public static final String NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM_CODE = "NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM"; + public static final String NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM_MESSAGE = "Not able to fetch byte stream from a multipart file"; + + public static final String BOUNDARY_CODE = "boundaryCode"; + public static final String ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE_FOR_LOCALITY = "Exception occurred while fetching plan configuration from plan service for Locality "; + + public static final String ERROR_WHILE_SEARCHING_CAMPAIGN = "Exception occurred while searching/updating campaign."; + public static final String FILE_NAME = "output.xls"; + public static final String FILE_TYPE = "boundaryWithTarget"; + public static final String FILE_TEMPLATE_IDENTIFIER = "Population"; + public static final String INPUT_IS_NOT_VALID = "File does not contain valid input for row "; + + public static final String MDMS_SCHEMA_TYPE = "type"; + public static final String MDMS_SCHEMA_SECTION = "section"; + public static final String MDMS_PLAN_MODULE_NAME = "hcm-microplanning"; + public static final String MDMS_MASTER_SCHEMAS = "Schemas"; + public static final String MDMS_CAMPAIGN_TYPE = "campaignType"; + + public static final String ERROR_WHILE_UPDATING_PLAN_CONFIG = "Exception occurred while updating plan configuration."; + + public static final String VALIDATE_STRING_REGX = "^[a-zA-Z0-9 .,()_\\-`~!@#\\$%^&*\\+=\\\\|{}\\[\\]:;\"'<>,.?/]*$"; + public static final String VALIDATE_NUMBER_REGX = "^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$"; + public static final String VALIDATE_BOOLEAN_REGX = "^(?i)(true|false)$"; + + public static final String FILE_TEMPLATE = "Facilities"; + public static final String HIERARCHYTYPE_REPLACER = "{hierarchyType}"; + public static final String FILE_EXTENSION = "excel"; + + public static final String SCIENTIFIC_NOTATION_INDICATOR = "E"; + public static final String ATTRIBUTE_IS_REQUIRED ="isRequired"; + public static final int DEFAULT_SCALE=2; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/PlanConsumer.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/PlanConsumer.java new file mode 100644 index 00000000000..2aa31907413 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/PlanConsumer.java @@ -0,0 +1,44 @@ +package org.egov.processor.kafka; + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.Collections; +import java.util.Map; +import lombok.extern.slf4j.Slf4j; +import org.egov.processor.service.ResourceEstimationService; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.tracer.model.CustomException; +import org.springframework.http.HttpStatus; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class PlanConsumer { + + private ObjectMapper objectMapper; + + private ResourceEstimationService resourceEstimationService; + + public PlanConsumer(ObjectMapper objectMapper, ResourceEstimationService resourceEstimationService) { + this.objectMapper = objectMapper; + this.resourceEstimationService = resourceEstimationService; + } + + @KafkaListener(topics = { "${plan.config.consumer.kafka.save.topic}", "${plan.config.consumer.kafka.update.topic}" }) + public void listen(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + PlanConfigurationRequest planConfigurationRequest = objectMapper.convertValue(consumerRecord, PlanConfigurationRequest.class); + if (planConfigurationRequest.getPlanConfiguration().getStatus().equals(PlanConfiguration.StatusEnum.GENERATED)) { + resourceEstimationService.estimateResources(planConfigurationRequest); + log.info("Successfully estimated resources for plan."); + } + } catch (Exception exception) { + log.error("Error processing record from topic "+topic+" with exception :"+exception); + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + exception.toString()); + } + } +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/Producer.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/Producer.java new file mode 100644 index 00000000000..4a8c949fc08 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/Producer.java @@ -0,0 +1,18 @@ +package org.egov.processor.kafka; + +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/health-services/resource-estimation-service/src/main/java/org/egov/processor/repository/ServiceRequestRepository.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/repository/ServiceRequestRepository.java new file mode 100644 index 00000000000..9c19a935415 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/repository/ServiceRequestRepository.java @@ -0,0 +1,70 @@ +package org.egov.processor.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.http.HttpEntity; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Repository; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import java.util.Map; + +import static org.egov.processor.config.ServiceConstants.EXTERNAL_SERVICE_EXCEPTION; +import static org.egov.processor.config.ServiceConstants.SEARCHER_SERVICE_EXCEPTION; + +@Repository +@Slf4j +public class ServiceRequestRepository { + + private ObjectMapper mapper; + + private RestTemplate restTemplate; + + + @Autowired + 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(SEARCHER_SERVICE_EXCEPTION, "Error occurred while fetching data: {}", e.getMessage()); + throw new ServiceCallException(e.getResponseBodyAsString()); + }catch(Exception e) { + log.error(SEARCHER_SERVICE_EXCEPTION, "Error occurred while fetching data: {}", e.getMessage()); + throw new ServiceCallException(e.getMessage()); + } + + return response; + } + + public Object fetchResultWithGET(StringBuilder uri) { + Object response = null; + try { + response = restTemplate.getForObject(uri.toString(), byte[].class); + } catch (HttpClientErrorException e) { + log.error(SEARCHER_SERVICE_EXCEPTION, "Error occurred while fetching data: {}", e.getMessage()); + throw new ServiceCallException(e.getResponseBodyAsString()); + } catch (Exception e) { + log.error(SEARCHER_SERVICE_EXCEPTION, "Error occurred while fetching data: {}", e.getMessage()); + throw new ServiceCallException(e.getMessage()); + } + return response; + } + + public ResponseEntity sendHttpRequest(String url, HttpEntity> requestEntity) { + return restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class); + } +} \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java new file mode 100644 index 00000000000..c718136755a --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java @@ -0,0 +1,687 @@ +package org.egov.processor.service; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.DataFormatter; +import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.egov.processor.config.Configuration; +import org.egov.processor.config.ServiceConstants; +import org.egov.processor.util.BoundaryUtil; +import org.egov.processor.util.CalculationUtil; +import org.egov.processor.util.CampaignIntegrationUtil; +import org.egov.processor.util.FilestoreUtil; +import org.egov.processor.util.MdmsUtil; +import org.egov.processor.util.ParsingUtil; +import org.egov.processor.util.PlanUtil; +import org.egov.processor.web.models.Operation; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfiguration.StatusEnum; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.processor.web.models.ResourceMapping; +import org.egov.processor.web.models.boundary.BoundarySearchResponse; +import org.egov.processor.web.models.boundary.EnrichedBoundary; +import org.egov.processor.web.models.campaignManager.Boundary; +import org.egov.processor.web.models.campaignManager.CampaignResources; +import org.egov.processor.web.models.campaignManager.CampaignResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class ExcelParser implements FileParser { + + private ObjectMapper objectMapper; + + private ParsingUtil parsingUtil; + + private FilestoreUtil filestoreUtil; + + private CalculationUtil calculationUtil; + + private PlanUtil planUtil; + + private CampaignIntegrationUtil campaignIntegrationUtil; + + private Configuration config; + + private MdmsUtil mdmsUtil; + + private BoundaryUtil boundaryUtil; + + public ExcelParser(ObjectMapper objectMapper, ParsingUtil parsingUtil, FilestoreUtil filestoreUtil, + CalculationUtil calculationUtil, PlanUtil planUtil, CampaignIntegrationUtil campaignIntegrationUtil, + Configuration config, MdmsUtil mdmsUtil, BoundaryUtil boundaryUtil) { + this.objectMapper = objectMapper; + this.parsingUtil = parsingUtil; + this.filestoreUtil = filestoreUtil; + this.calculationUtil = calculationUtil; + this.planUtil = planUtil; + this.campaignIntegrationUtil = campaignIntegrationUtil; + this.config = config; + this.mdmsUtil = mdmsUtil; + this.boundaryUtil = boundaryUtil; + } + + /** + * Parses file data, extracts information from the file, and processes it. + * + * @param planConfigurationRequest The plan configuration request containing + * necessary information for parsing the file. + * @param fileStoreId The ID of the file in the file store. + * @param campaignResponse The response object to be updated with parsed + * data. + * @return The parsed and processed data. + */ + @Override + public Object parseFileData(PlanConfigurationRequest planConfigurationRequest, String fileStoreId, + Object campaignResponse) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + byte[] byteArray = filestoreUtil.getFile(planConfig.getTenantId(), fileStoreId); + File file = parsingUtil.convertByteArrayToFile(byteArray, ServiceConstants.FILE_EXTENSION); + if (file == null || !file.exists()) { + log.error("File not found: {} in tenant: {}", fileStoreId, planConfig.getTenantId()); + throw new CustomException("FileNotFound", + "The file with ID " + fileStoreId + " was not found in the tenant " + planConfig.getTenantId()); + } + return processExcelFile(planConfigurationRequest, file, fileStoreId, campaignResponse); + } + + /** + * Processes an Excel file, extracts data, and updates campaign details and + * resources. + * + * @param planConfigurationRequest The plan configuration request containing + * necessary information for processing the + * file. + * @param file The Excel file to be processed. + * @param fileStoreId The ID of the file in the file store. + * @param campaignResponse The response object to be updated with + * processed data. + * @return The ID of the uploaded file. + */ + private String processExcelFile(PlanConfigurationRequest planConfigurationRequest, File file, String fileStoreId, + Object campaignResponse) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + try (Workbook workbook = new XSSFWorkbook(file)) { + List campaignBoundaryList = new ArrayList<>(); + List campaignResourcesList = new ArrayList<>(); + DataFormatter dataFormatter = new DataFormatter(); + processSheets(planConfigurationRequest, fileStoreId, campaignResponse, planConfig, workbook, + campaignBoundaryList, campaignResourcesList, dataFormatter); + String uploadedFileStoreId = uploadFileAndIntegrateCampaign(planConfigurationRequest, campaignResponse, + planConfig, workbook, campaignBoundaryList, campaignResourcesList); + return uploadedFileStoreId; + } catch (FileNotFoundException e) { + log.error("File not found: {}", e.getMessage()); + throw new CustomException("FileNotFound", "The specified file was not found."); + } catch (InvalidFormatException e) { + log.error("Invalid format: {}", e.getMessage()); + throw new CustomException("InvalidFormat", "The file format is not supported."); + } catch (IOException e) { + log.error("Error processing Excel file: {}", e); + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + "Error processing Excel file"); + } + } + + /** + * Uploads a converted file and integrates campaign details if configured to do so. + * + * @param planConfigurationRequest The request containing configuration details including tenant ID. + * @param campaignResponse The response object containing campaign details. + * @param planConfig The configuration details specific to the plan. + * @param workbook The workbook containing data to be uploaded and integrated. + * @param campaignBoundaryList List of boundary objects related to the campaign. + * @param campaignResourcesList List of campaign resources to be integrated. + * @return The ID of the uploaded file in the file store. + */ + private String uploadFileAndIntegrateCampaign(PlanConfigurationRequest planConfigurationRequest, + Object campaignResponse, PlanConfiguration planConfig, Workbook workbook, + List campaignBoundaryList, List campaignResourcesList) { + File fileToUpload = null; + try { + fileToUpload = convertWorkbookToXls(workbook); + String uploadedFileStoreId = uploadConvertedFile(fileToUpload, planConfig.getTenantId()); + + if (config.isIntegrateWithAdminConsole()) { + campaignIntegrationUtil.updateCampaignResources(uploadedFileStoreId, campaignResourcesList, + fileToUpload.getName()); + + campaignIntegrationUtil.updateCampaignDetails(planConfigurationRequest, campaignResponse, + campaignBoundaryList, campaignResourcesList); + } + return uploadedFileStoreId; + } finally { + try { + if (fileToUpload != null && !fileToUpload.delete()) { + log.warn("Failed to delete temporary file: " + fileToUpload.getPath()); + } + }catch(SecurityException e) { + log.error("Security exception when attempting to delete file: " + e.getMessage()); + } + } + } + + /** + * Processes each sheet in the workbook for plan configuration data. + * Validates column names, processes rows, and integrates campaign details. + * + * @param planConfigurationRequest The request containing configuration details including tenant ID. + * @param fileStoreId The ID of the uploaded file in the file store. + * @param campaignResponse The response object containing campaign details. + * @param planConfig The configuration details specific to the plan. + * @param workbook The workbook containing sheets to be processed. + * @param campaignBoundaryList List of boundary objects related to the campaign. + * @param campaignResourcesList List of campaign resources to be integrated. + * @param dataFormatter The data formatter for formatting cell values. + */ + private void processSheets(PlanConfigurationRequest planConfigurationRequest, String fileStoreId, + Object campaignResponse, PlanConfiguration planConfig, Workbook workbook, + List campaignBoundaryList, List campaignResourcesList, + DataFormatter dataFormatter) { + workbook.forEach(sheet -> { + Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(sheet); + List columnNamesList = mapOfColumnNameAndIndex.keySet().stream().toList(); + parsingUtil.validateColumnNames(columnNamesList, planConfig, fileStoreId); + processRows(planConfigurationRequest, sheet, dataFormatter, fileStoreId, campaignResponse, + campaignBoundaryList, campaignResourcesList); + }); + } + + /** + * Processes rows of data in an Excel sheet, performs calculations, updates + * campaign boundaries, and creates plans. + * + * @param planConfigurationRequest The plan configuration request containing + * necessary information for processing the + * rows. + * @param sheet The Excel sheet containing the data to be + * processed. + * @param dataFormatter The data formatter for formatting cell + * values. + * @param fileStoreId The ID of the file in the file store. + * @param campaignResponse The response object to be updated with + * processed data. + * @param campaignBoundaryList The list of campaign boundaries to be + * updated. + * @param campaignResourcesList The list of campaign resources to be updated. + * @throws IOException If an I/O error occurs. + */ + private void processRows(PlanConfigurationRequest planConfigurationRequest, Sheet sheet, + DataFormatter dataFormatter, String fileStoreId, Object campaignResponse, + List campaignBoundaryList, List campaignResourcesList) { + CampaignResponse campaign = parseCampaignResponse(campaignResponse); + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + Map attributeNameVsDataTypeMap = prepareAttributeVsIndexMap(planConfigurationRequest, + fileStoreId, campaign, planConfig); + List boundaryCodeList = getBoundaryCodeList(planConfigurationRequest, campaign, planConfig); + Row firstRow = null; + performRowLevelCalculations(planConfigurationRequest, sheet, dataFormatter, fileStoreId, campaignBoundaryList, + planConfig, attributeNameVsDataTypeMap, boundaryCodeList, firstRow); + } + + /** + * Retrieves a list of boundary codes based on the given plan configuration, campaign details, and request information. + * + * @param planConfigurationRequest The request containing configuration details including tenant ID. + * @param campaign The campaign response object containing campaign details. + * @param planConfig The configuration details specific to the plan. + * @return A list of boundary codes corresponding to the specified hierarchy type and tenant ID. + */ + private List getBoundaryCodeList(PlanConfigurationRequest planConfigurationRequest, + CampaignResponse campaign, PlanConfiguration planConfig) { + BoundarySearchResponse boundarySearchResponse = boundaryUtil.search(planConfig.getTenantId(), + campaign.getCampaign().get(0).getHierarchyType(), planConfigurationRequest); + List boundaryList = new ArrayList<>(); + List boundaryCodeList = getAllBoundaryPresentforHierarchyType( + boundarySearchResponse.getTenantBoundary().get(0).getBoundary(), boundaryList); + return boundaryCodeList; + } + + /** + * Prepares a mapping of attribute names to their corresponding indices or data types based on configuration and MDMS data. + * + * @param planConfigurationRequest The request containing configuration details including tenant ID. + * @param fileStoreId The ID of the uploaded file in the file store. + * @param campaign The campaign response object containing campaign details. + * @param planConfig The configuration details specific to the plan. + * @return A map of attribute names to their corresponding indices or data types. + */ + private Map prepareAttributeVsIndexMap(PlanConfigurationRequest planConfigurationRequest, + String fileStoreId, CampaignResponse campaign, PlanConfiguration planConfig) { + Object mdmsData = mdmsUtil.fetchMdmsData(planConfigurationRequest.getRequestInfo(), + planConfigurationRequest.getPlanConfiguration().getTenantId()); + org.egov.processor.web.models.File file = planConfig.getFiles().stream() + .filter(f -> f.getFilestoreId().equalsIgnoreCase(fileStoreId)).findFirst().get(); + Map attributeNameVsDataTypeMap = mdmsUtil.filterMasterData(mdmsData.toString(), file.getInputFileType(), + file.getTemplateIdentifier(), campaign.getCampaign().get(0).getProjectType()); + return attributeNameVsDataTypeMap; + } + + + /** + * Parses an object representing campaign response into a CampaignResponse object. + * + * @param campaignResponse The object representing campaign response to be parsed. + * @return CampaignResponse object parsed from the campaignResponse. + */ + private CampaignResponse parseCampaignResponse(Object campaignResponse) { + CampaignResponse campaign = null; + campaign = objectMapper.convertValue(campaignResponse, CampaignResponse.class); + return campaign; + } + + /** + * Performs row-level calculations and processing on each row in the sheet. + * Validates rows, maps resource values, converts assumptions, creates feature nodes, + * calculates operations results, updates campaign boundaries, and creates plan entities. + * + * @param planConfigurationRequest The request containing configuration details including tenant ID. + * @param sheet The sheet from which rows are processed. + * @param dataFormatter The data formatter for formatting cell values. + * @param fileStoreId The ID of the uploaded file in the file store. + * @param campaignBoundaryList List of boundary objects related to the campaign. + * @param planConfig The configuration details specific to the plan. + * @param attributeNameVsDataTypeMap Mapping of attribute names to their data types. + * @param boundaryCodeList List of boundary codes. + * @param firstRow The first row of the sheet. + */ + private void performRowLevelCalculations(PlanConfigurationRequest planConfigurationRequest, Sheet sheet, + DataFormatter dataFormatter, String fileStoreId, List campaignBoundaryList, + PlanConfiguration planConfig, Map attributeNameVsDataTypeMap, List boundaryCodeList, + Row firstRow) { + for (Row row : sheet) { + if (row.getRowNum() == 0) { + firstRow = row; + continue; + } + + Map resultMap = new HashMap<>(); + Map mappedValues = planConfig.getResourceMapping().stream() + .filter(f -> f.getFilestoreId().equals(fileStoreId)) + .collect(Collectors.toMap(ResourceMapping::getMappedTo, ResourceMapping::getMappedFrom)); + Map assumptionValueMap = calculationUtil + .convertAssumptionsToMap(planConfig.getAssumptions()); + Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(sheet); + + Integer indexOfBoundaryCode = campaignIntegrationUtil.getIndexOfBoundaryCode(0, + campaignIntegrationUtil.sortColumnByIndex(mapOfColumnNameAndIndex), mappedValues); + validateRows(indexOfBoundaryCode, row, firstRow, attributeNameVsDataTypeMap, mappedValues, mapOfColumnNameAndIndex, + planConfigurationRequest, boundaryCodeList); + JsonNode feature = createFeatureNodeFromRow(row, dataFormatter, mapOfColumnNameAndIndex); + performCalculationsOnOperations(sheet, planConfig, row, resultMap, mappedValues, + assumptionValueMap, feature); + if (config.isIntegrateWithAdminConsole()) + campaignIntegrationUtil.updateCampaignBoundary(planConfig, feature, assumptionValueMap, mappedValues, + mapOfColumnNameAndIndex, campaignBoundaryList, resultMap); + planUtil.create(planConfigurationRequest, feature, resultMap, mappedValues); + // TODO: remove after testing + printRow(sheet, row); + } + } + + /** + * Performs calculations on operations for a specific row in the sheet. + * Calculates results based on plan configuration operations, updates result map, and sets cell values. + * + * @param sheet The sheet where calculations are performed. + * @param planConfig The configuration details for the plan. + * @param row The row in the sheet where calculations are applied. + * @param resultMap The map to store calculation results. + * @param mappedValues Mapping of values needed for calculations. + * @param assumptionValueMap Map of assumption values used in calculations. + * @param feature JSON node containing additional features or data for calculations. + */ + private void performCalculationsOnOperations(Sheet sheet, PlanConfiguration planConfig, Row row, + Map resultMap, Map mappedValues, + Map assumptionValueMap, JsonNode feature) { + int columnIndex = row.getLastCellNum(); // Get the index of the last cell in the row + + for (Operation operation : planConfig.getOperations()) { + BigDecimal result = calculationUtil.calculateResult(operation, feature, mappedValues, + assumptionValueMap, resultMap); + String output = operation.getOutput(); + resultMap.put(output, result); + + Cell cell = row.createCell(columnIndex++); + cell.setCellValue(result.doubleValue()); + + if (row.getRowNum() == 1) { + Cell headerCell = sheet.getRow(0).createCell(row.getLastCellNum() - 1); + headerCell.setCellValue(output); + } + } + + } + + /** + * Uploads the converted XLS file to the file store. + * + * @param convertedFile The converted XLS file to upload. + * @param tenantId The tenant ID for the file upload. + * @return The file store ID of the uploaded file, or null if an error occurred. + */ + private String uploadConvertedFile(File convertedFile, String tenantId) { + if (convertedFile != null) { + return filestoreUtil.uploadFile(convertedFile, tenantId); + } + return null; + } + + /** + * Creates a temporary file with the specified prefix and suffix. + * + * @param prefix The prefix for the temporary file. + * @param suffix The suffix for the temporary file. + * @return The created temporary file. + * @throws IOException If an IO error occurs while creating the file. + */ + private File createTempFile(String prefix, String suffix) throws IOException { + return File.createTempFile(prefix, suffix); + } + + /** + * Converts the provided workbook to XLS format. + * + * @param workbook The workbook to convert. + * @return The converted XLS file, or null if an error occurred. + */ + private File convertWorkbookToXls(Workbook workbook) { + try { + // Create a temporary file for the output XLS file + File outputFile = File.createTempFile("output", ".xls"); + + // Write the XLS file + try (FileOutputStream fos = new FileOutputStream(outputFile)) { + workbook.write(fos); + log.info("XLS file saved successfully."); + return outputFile; + } catch (IOException e) { + log.info("Error saving XLS file: " + e); + return null; + } + } catch (IOException e) { + log.info("Error converting workbook to XLS: " + e); + return null; + } + } + + /** + * Creates a JSON feature node from a row in the Excel sheet. + * + * @param row The row in the Excel sheet. + * @param dataFormatter The data formatter for formatting cell values. + * @param columnIndexMap The mapping of column names to column indices. + * @return The JSON feature node representing the row. + */ + private JsonNode createFeatureNodeFromRow(Row row, DataFormatter dataFormatter, + Map columnIndexMap) { + ObjectNode featureNode = objectMapper.createObjectNode(); + ObjectNode propertiesNode = featureNode.putObject("properties"); + + // Iterate over each entry in the columnIndexMap + for (Map.Entry entry : columnIndexMap.entrySet()) { + String columnName = entry.getKey(); + Integer columnIndex = entry.getValue(); + + // Get the cell value from the row based on the columnIndex + Cell cell = row.getCell(columnIndex); + String cellValue = dataFormatter.formatCellValue(cell); + + // Add the columnName and cellValue to the propertiesNode + propertiesNode.put(columnName, cellValue); + } +// System.out.println("Feature Node ---- > " + featureNode); + return featureNode; + } + + public void printRow(Sheet sheet, Row row) { + System.out.print("Row -> "); + for (Cell cell : row) { + int columnIndex = cell.getColumnIndex(); + // String columnName = sheet.getRow(0).getCell(columnIndex).toString(); + // System.out.print("Column " + columnName + " - "); + switch (cell.getCellType()) { + case STRING: + System.out.print(cell.getStringCellValue() + "\t"); + break; + case NUMERIC: + if (DateUtil.isCellDateFormatted(cell)) { + System.out.print(cell.getDateCellValue() + "\t"); + } else { + System.out.print(cell.getNumericCellValue() + "\t"); + } + break; + case BOOLEAN: + System.out.print(cell.getBooleanCellValue() + "\t"); + break; + case FORMULA: + System.out.print(cell.getCellFormula() + "\t"); + break; + case BLANK: + System.out.print("\t"); + break; + default: + System.out.print("\t"); + break; + } + } + System.out.println(); // Move to the next line after printing the row + } + + /** + * Validates the data in a row. + * + * @param indexOfBoundaryCode The index of the "BCode" column in the row. + * @param row The row containing the data to be validated. + * @param columnHeaderRow The row containing the column headers. + * @param attributeNameVsDataTypeMap Map containing data types from external + * source (MDMS). + * @param mappedValues Map containing mapped values. + * @param mapOfColumnNameAndIndex Map containing column names and their + * corresponding indices. + * @param planConfigurationRequest Object representing the plan configuration + * request. + * @throws CustomException if the input data is not valid or if a custom + * exception occurs. + */ + public void validateRows(Integer indexOfBoundaryCode, Row row, Row columnHeaderRow, Map attributeNameVsDataTypeMap, + Map mappedValues, Map mapOfColumnNameAndIndex, + PlanConfigurationRequest planConfigurationRequest, List boundaryCodeList) { + + try { + validateTillBoundaryCode(indexOfBoundaryCode, row, columnHeaderRow); + validateAttributes(attributeNameVsDataTypeMap, mappedValues, mapOfColumnNameAndIndex, row, columnHeaderRow, indexOfBoundaryCode, + boundaryCodeList); + } catch (JsonProcessingException e) { + log.info(ServiceConstants.INPUT_IS_NOT_VALID + (row.getRowNum() + 1)); + planConfigurationRequest.getPlanConfiguration().setStatus(StatusEnum.INVALID_DATA); + planUtil.update(planConfigurationRequest); + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + ServiceConstants.INPUT_IS_NOT_VALID + row.getRowNum()); + } catch (CustomException customException) { + log.info(customException.toString()); + planConfigurationRequest.getPlanConfiguration().setStatus(StatusEnum.INVALID_DATA); + planUtil.update(planConfigurationRequest); + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + customException.getMessage()); + } + } + + /** + * Validates the data in columns from "BCode" column. + * + * @param attributeNameVsDataTypeMap Map containing data types from an external + * source (MDMS). + * @param mappedValues Map containing mapped values. + * @param mapOfColumnNameAndIndex Map containing column names and their + * corresponding indices. + * @param row The row containing the data to be validated. + * @param columnHeaderRow The row containing the column headers. + * @param indexOfBoundaryCode The index of the "BCode" column in the row. + * @throws JsonMappingException if there's an issue mapping JSON. + * @throws JsonProcessingException if there's an issue processing JSON. + */ + private void validateAttributes(Map attributeNameVsDataTypeMap, Map mappedValues, + Map mapOfColumnNameAndIndex, Row row, Row columnHeaderRow, Integer indexOfBoundaryCode, + List boundaryCodeList) throws JsonMappingException, JsonProcessingException { + for (int j = indexOfBoundaryCode; j < mapOfColumnNameAndIndex.size(); j++) { + Cell cell = row.getCell(j); + Cell columnName = columnHeaderRow.getCell(j); + String name = findByValue(mappedValues, columnName.getStringCellValue()); + if (attributeNameVsDataTypeMap.containsKey(name)) { + Map mapOfAttributes = (Map) attributeNameVsDataTypeMap.get(name); + boolean isRequired = (mapOfAttributes.containsKey(ServiceConstants.ATTRIBUTE_IS_REQUIRED) + ? (boolean) mapOfAttributes.get(ServiceConstants.ATTRIBUTE_IS_REQUIRED) + : false); + if (cell != null) { + switch (cell.getCellType()) { + case STRING: + String cellValue = cell.getStringCellValue(); + if (j == indexOfBoundaryCode && !boundaryCodeList.contains(cellValue)) { + log.info("Boundary Code " + cellValue + " is not present in boundary search. Code for row " + + (row.getRowNum() + 1) + " and cell/column " + columnName); + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + "Boundary Code " + cellValue + " is not present in boundary search. Code for row " + + (row.getRowNum() + 1) + " and cell/column " + columnName); + } + // "^[a-zA-Z0-9 .,()-]+$" + if (cellValue != null && !cellValue.isEmpty() + && cellValue.matches(ServiceConstants.VALIDATE_STRING_REGX)) { + continue; + } else { + log.info(ServiceConstants.INPUT_IS_NOT_VALID + (row.getRowNum() + 1) + " and cell/column " + + columnName); + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + ServiceConstants.INPUT_IS_NOT_VALID + row.getRowNum() + " and cell " + columnName); + } + case NUMERIC: + String numricValue = Double.toString(cell.getNumericCellValue()); + // "^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$" + if (numricValue != null && !numricValue.isEmpty() + && numricValue.matches(ServiceConstants.VALIDATE_NUMBER_REGX)) { + continue; + } else { + log.info(ServiceConstants.INPUT_IS_NOT_VALID + (row.getRowNum() + 1) + " and cell/column " + + columnName); + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + ServiceConstants.INPUT_IS_NOT_VALID + row.getRowNum() + " and cell " + columnName); + } + case BOOLEAN: + Boolean booleanvalue = cell.getBooleanCellValue(); + // "^(?i)(true|false)$" + if (booleanvalue != null && !booleanvalue.toString().isEmpty() + && booleanvalue.toString().matches(ServiceConstants.VALIDATE_BOOLEAN_REGX)) { + continue; + } else { + log.info(ServiceConstants.INPUT_IS_NOT_VALID + (row.getRowNum() + 1) + " and cell/column " + + columnName); + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + ServiceConstants.INPUT_IS_NOT_VALID + row.getRowNum() + " and cell " + columnName); + } + case BLANK: + if (!isRequired) { + continue; + }else { + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + ServiceConstants.INPUT_IS_NOT_VALID + (row.getRowNum() + 1) + " and cell " + + columnName); + } + default: + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + ServiceConstants.INPUT_IS_NOT_VALID + (row.getRowNum() + 1) + " and cell " + + columnName); + } + }else { + if(isRequired) { + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + ServiceConstants.INPUT_IS_NOT_VALID + (row.getRowNum() + 1) + " and cell " + + columnName); + } + } + } + } + } + + /** + * Validates the data in columns up to the specified index of the "BCode" + * column. + * + * @param indexOfBoundaryCode The index of the "BCode" column in the row. + * @param row The row containing the data to be validated. + * @param columnHeaderRow The row containing the column headers. + */ + private void validateTillBoundaryCode(Integer indexOfBoundaryCode, Row row, Row columnHeaderRow) { + for (int j = 0; j <= indexOfBoundaryCode - 1; j++) { + Cell cell = row.getCell(j); + if (cell != null && !cell.getCellType().name().equals("BLANK")) { + String cellValue = cell.getStringCellValue(); + if (!cellValue.isBlank()) { + if (cellValue != null && !cellValue.isEmpty() + && cellValue.matches(ServiceConstants.VALIDATE_STRING_REGX)) { + continue; + } else { + log.info(ServiceConstants.INPUT_IS_NOT_VALID + (row.getRowNum() + 1) + + " and cell/column number " + (j + 1)); + throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), + ServiceConstants.INPUT_IS_NOT_VALID + row.getRowNum() + " and cell " + + columnHeaderRow.getCell(j)); + } + } + } + } + } + + /** + * Finds the key associated with a given value in a map. + * + * @param map The map to search. + * @param value The value to search for. + * @return The key associated with the specified value, or {@code null} if not + * found. + */ + public String findByValue(Map map, String value) { + for (Map.Entry entry : map.entrySet()) { + if (entry.getValue().equals(value)) { + return entry.getKey(); + } + } + return null; + } + + public List getAllBoundaryPresentforHierarchyType(List boundaries, + List boundaryList) { + for (EnrichedBoundary boundary : boundaries) { + boundaryList.add(boundary.getCode()); + // Recursively check children if they exist + if (boundary.getChildren() != null && !boundary.getChildren().isEmpty()) { + getAllBoundaryPresentforHierarchyType(boundary.getChildren(), boundaryList); + } + } + return boundaryList; + } +} \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/FileParser.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/FileParser.java new file mode 100644 index 00000000000..b62f2a3d058 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/FileParser.java @@ -0,0 +1,13 @@ +package org.egov.processor.service; + + +import java.math.BigDecimal; +import org.egov.processor.web.models.Plan; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationRequest; + +public interface FileParser { + + Object parseFileData(PlanConfigurationRequest planConfigurationRequest , String fileStoreId, Object campaignResponse); + + } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/GeoJsonParser.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/GeoJsonParser.java new file mode 100644 index 00000000000..cdc70900a3e --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/GeoJsonParser.java @@ -0,0 +1,78 @@ +package org.egov.processor.service; + + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.io.File; +import java.math.BigDecimal; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.egov.processor.util.CalculationUtil; +import org.egov.processor.util.FilestoreUtil; +import org.egov.processor.util.ParsingUtil; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.processor.web.models.ResourceMapping; + +import org.springframework.stereotype.Service; + + +@Service +@Slf4j +public class GeoJsonParser implements FileParser { + + private ObjectMapper objectMapper; + + private ParsingUtil parsingUtil; + + private FilestoreUtil filestoreUtil; + + private CalculationUtil calculationUtil; + + public GeoJsonParser(ObjectMapper objectMapper, ParsingUtil parsingUtil, FilestoreUtil filestoreUtil, CalculationUtil calculationUtil) { + this.objectMapper = objectMapper; + this.parsingUtil = parsingUtil; + this.filestoreUtil = filestoreUtil; + this.calculationUtil = calculationUtil; + } + + /** + * Parses the file data based on the provided plan configuration and file store ID. + * Converts the byte array data to a GeoJSON string, then to a JSON node. + * Calculates resources based on the operations defined in the plan configuration. + * Writes the updated JSON node to a file and uploads it to the file store. + * + * @param planConfigurationRequest The plan configuration containing mapping and operation details. + * @param fileStoreId The file store ID of the GeoJSON file to be parsed. + * @return The file store ID of the uploaded updated file, or null if an error occurred. + */ + @Override + public Object parseFileData(PlanConfigurationRequest planConfigurationRequest, String fileStoreId, Object campaignResponse) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + String geoJSON = parsingUtil.convertByteArrayToString(planConfig, fileStoreId); + + JsonNode jsonNode = parsingUtil.parseJson(geoJSON, objectMapper); + + List columnNamesList = parsingUtil.fetchAttributeNamesFromJson(jsonNode); + parsingUtil.validateColumnNames(columnNamesList, planConfig, fileStoreId); + + Map resultMap = new HashMap<>(); + Map mappedValues = planConfig.getResourceMapping().stream() + .filter(f-> f.getFilestoreId().equals(fileStoreId)) + .collect(Collectors.toMap(ResourceMapping::getMappedTo, ResourceMapping::getMappedFrom)); + Map assumptionValueMap = calculationUtil.convertAssumptionsToMap(planConfig.getAssumptions()); + + calculationUtil.calculateResources(jsonNode, planConfigurationRequest, resultMap, mappedValues, assumptionValueMap); + + File outputFile = parsingUtil.writeToFile(jsonNode, objectMapper); + + return filestoreUtil.uploadFile(outputFile, planConfig.getTenantId()); + + } + +} \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ResourceEstimationService.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ResourceEstimationService.java new file mode 100644 index 00000000000..c1b1ab07b7a --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ResourceEstimationService.java @@ -0,0 +1,112 @@ +package org.egov.processor.service; + + +import java.util.HashMap; +import java.util.Map; + +import org.egov.processor.config.Configuration; +import org.egov.processor.config.ServiceConstants; +import org.egov.processor.repository.ServiceRequestRepository; +import org.egov.processor.util.CampaignIntegrationUtil; +import org.egov.processor.web.models.File; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.processor.web.models.campaignManager.CampaignSearchRequest; +import org.springframework.stereotype.Service; + +import lombok.extern.slf4j.Slf4j; + +@Service +@Slf4j +public class ResourceEstimationService { + + private final FileParser excelParser; + private final FileParser geoJsonParser; + private final FileParser shapeFileParser; + private CampaignIntegrationUtil campaignIntegrationUtil; + private ServiceRequestRepository serviceRequestRepository; + private Configuration config; + + public ResourceEstimationService(FileParser excelParser, FileParser geoJsonParser, FileParser shapeFileParser,CampaignIntegrationUtil campaignIntegrationUtil + ,ServiceRequestRepository serviceRequestRepository, + Configuration config) { + this.excelParser = excelParser; + this.geoJsonParser = geoJsonParser; + this.shapeFileParser = shapeFileParser; + this.campaignIntegrationUtil= campaignIntegrationUtil; + this.serviceRequestRepository=serviceRequestRepository; + this.config=config; + } + + /** + * Estimates resources required for the plan configuration by parsing files and fetching campaign search results. + * + * @param planConfigurationRequest The plan configuration request containing necessary information for estimating resources. + */ + public void estimateResources(PlanConfigurationRequest planConfigurationRequest) { + PlanConfiguration planConfiguration = planConfigurationRequest.getPlanConfiguration(); + + Map parserMap = getInputFileTypeMap(); + Object campaignSearchResponse = performCampaignSearch(planConfigurationRequest); + processFiles(planConfigurationRequest, planConfiguration, parserMap, campaignSearchResponse); + } + + /** + * Performs a campaign search based on the provided plan configuration request. + * This method builds a campaign search request using the integration utility, + * fetches the search result from the service request repository, and returns it. + * + * @param planConfigurationRequest The request object containing configuration details for the campaign search. + * @return The response object containing the result of the campaign search. + */ + private Object performCampaignSearch(PlanConfigurationRequest planConfigurationRequest) { + CampaignSearchRequest campaignRequest = campaignIntegrationUtil.buildCampaignRequestForSearch(planConfigurationRequest); + Object campaignSearchResponse = serviceRequestRepository.fetchResult(new StringBuilder(config.getProjectFactoryHostEndPoint()+config.getCampaignIntegrationSearchEndPoint()), + campaignRequest); + return campaignSearchResponse; + } + + /** + * Processes files in the plan configuration by parsing active files and skipping inactive ones. + * Uses the provided parser map to parse supported file types. If a file type is not supported, + * throws an IllegalArgumentException. Skips files with a specific template identifier defined + * in ServiceConstants. + * + * @param planConfigurationRequest The request object containing configuration details. + * @param planConfiguration The plan configuration object containing files to process. + * @param parserMap A map of supported file types to their respective parsers. + * @param campaignSearchResponse The response object from a campaign search operation. + */ + private void processFiles(PlanConfigurationRequest planConfigurationRequest, PlanConfiguration planConfiguration, + Map parserMap, Object campaignSearchResponse) { + for (File file : planConfiguration.getFiles()) { + if (!file.getActive()) { + continue; + } + File.InputFileTypeEnum fileType = file.getInputFileType(); + FileParser parser = parserMap.computeIfAbsent(fileType, ft -> { + throw new IllegalArgumentException("Unsupported file type: " + ft); + }); + if (!ServiceConstants.FILE_TEMPLATE.equalsIgnoreCase(file.getTemplateIdentifier())) { + parser.parseFileData(planConfigurationRequest, file.getFilestoreId(), campaignSearchResponse); + } + } + + } + + /** + * Retrieves a map of input file types to their respective parsers. + * + * @return A map containing input file types as keys and their corresponding parsers as values. + */ + public Map getInputFileTypeMap() + { + Map parserMap = new HashMap<>(); + parserMap.put(File.InputFileTypeEnum.EXCEL, excelParser); + parserMap.put(File.InputFileTypeEnum.SHAPEFILE, shapeFileParser); + parserMap.put(File.InputFileTypeEnum.GEOJSON, geoJsonParser); + + return parserMap; + } +} + diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ShapeFileParser.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ShapeFileParser.java new file mode 100644 index 00000000000..92260690fa6 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ShapeFileParser.java @@ -0,0 +1,146 @@ +package org.egov.processor.service; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.processor.util.CalculationUtil; +import org.egov.processor.util.FilestoreUtil; +import org.egov.processor.util.ParsingUtil; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.processor.web.models.ResourceMapping; +import org.egov.tracer.model.CustomException; +import org.geotools.api.data.DataStore; +import org.geotools.api.data.DataStoreFinder; +import org.geotools.api.data.SimpleFeatureSource; +import org.geotools.geojson.feature.FeatureJSON; +import org.springframework.stereotype.Service; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Service +public class ShapeFileParser implements FileParser { + + private ParsingUtil parsingUtil; + + private FilestoreUtil filestoreUtil; + + private CalculationUtil calculationUtil; + + private ObjectMapper objectMapper; + + public ShapeFileParser(ParsingUtil parsingUtil, FilestoreUtil filestoreUtil, CalculationUtil calculationUtil, ObjectMapper objectMapper) { + this.parsingUtil = parsingUtil; + this.filestoreUtil = filestoreUtil; + this.calculationUtil = calculationUtil; + this.objectMapper = objectMapper; + } + + /** + * Parses the file data based on the provided plan configuration and file store ID. + * Converts a Shapefile to GeoJSON format, calculates resources based on the operations + * defined in the plan configuration, and uploads the updated GeoJSON file to the file store. + * + * @param planConfigurationRequest The plan configuration containing mapping and operation details. + * @param fileStoreId The file store ID of the Shapefile to be converted and parsed. + * @return The file store ID of the uploaded updated file, or null if an error occurred. + */ + @Override + public Object parseFileData(PlanConfigurationRequest planConfigurationRequest, String fileStoreId, Object campaignResponse) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + File geojsonFile = convertShapefileToGeoJson(planConfig, fileStoreId); + String geoJSONString = parsingUtil.convertFileToJsonString(geojsonFile); + JsonNode jsonNode = parsingUtil.parseJson(geoJSONString, objectMapper); + + List columnNamesList = parsingUtil.fetchAttributeNamesFromJson(jsonNode); + parsingUtil.validateColumnNames(columnNamesList, planConfig, fileStoreId); + + Map resultMap = new HashMap<>(); + Map mappedValues = planConfig.getResourceMapping().stream() + .filter(f-> f.getFilestoreId().equals(fileStoreId)) + .collect(Collectors.toMap(ResourceMapping::getMappedTo, ResourceMapping::getMappedFrom)); + Map assumptionValueMap = calculationUtil.convertAssumptionsToMap(planConfig.getAssumptions()); + + calculationUtil.calculateResources(jsonNode, planConfigurationRequest, resultMap, mappedValues, assumptionValueMap); + + File updatedGeojsonFile = parsingUtil.writeToFile(jsonNode, objectMapper); + + return filestoreUtil.uploadFile(updatedGeojsonFile, planConfig.getTenantId()); + } + + /** + * Converts a Shapefile to GeoJSON format and writes it to a GeoJSON file. + * + * @param planConfig The plan configuration containing mapping details. + * @param fileStoreId The file store ID of the Shapefile to be converted. + * @return The GeoJSON file containing the converted data. + */ + public File convertShapefileToGeoJson(PlanConfiguration planConfig, String fileStoreId) { + File shapefile = null; + try { + shapefile = parsingUtil.extractShapeFilesFromZip(planConfig, fileStoreId, "shapefile"); + } catch (IOException exception) { + log.error(exception.getMessage()); + } + + File geojsonFile = new File("geojsonfile.geojson"); + + SimpleFeatureSource featureSource = null; + DataStore dataStore; + try { + dataStore = getDataStore(shapefile); + String typeName = dataStore.getTypeNames()[0]; + featureSource = dataStore.getFeatureSource(typeName); + + writeFeaturesToGeoJson(featureSource, geojsonFile); + } catch (IOException e) { + throw new CustomException("ERROR_IN_SHAPE_FILE_PARSER_WHILE_CONVERTING_SHAPE_FILE_TO_GEOJSON_IN_METHOD_CONVERTSHAPEFILETOGEOJSON",e.getMessage()); + } + + return geojsonFile; + } + + /** + * Retrieves a DataStore object for a given Shapefile. + * + * @param shapefile The Shapefile to retrieve the DataStore for. + * @return The DataStore object for the Shapefile. + * @throws IOException If an I/O error occurs. + */ + private DataStore getDataStore(File shapefile) { + Map params = new HashMap<>(); + try { + params.put("url", shapefile.toURI().toURL()); + return DataStoreFinder.getDataStore(params); + } catch (IOException e) { + throw new CustomException("Exception accours while getting data store",e.getMessage()); + } + + } + + /** + * Writes features from a SimpleFeatureSource to a GeoJSON file. + * + * @param featureSource The SimpleFeatureSource containing the features to write. + * @param geojsonFile The GeoJSON file to write the features to. + * @throws IOException If an I/O error occurs. + */ + private void writeFeaturesToGeoJson(SimpleFeatureSource featureSource, File geojsonFile) { + try (FileOutputStream geojsonStream = new FileOutputStream(geojsonFile)) { + new FeatureJSON().writeFeatureCollection(featureSource.getFeatures(), geojsonStream); + } catch (IOException e) { + throw new CustomException("Failed to write feature to GeoJson",e.getMessage()); + } + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/BoundaryUtil.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/BoundaryUtil.java new file mode 100644 index 00000000000..b898dbe5110 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/BoundaryUtil.java @@ -0,0 +1,53 @@ +package org.egov.processor.util; + +import static org.egov.processor.config.ServiceConstants.HIERARCHYTYPE_REPLACER; +import static org.egov.processor.config.ServiceConstants.TENANTID_REPLACER; + +import org.egov.processor.config.Configuration; +import org.egov.processor.repository.ServiceRequestRepository; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.processor.web.models.boundary.BoundarySearchResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class BoundaryUtil { + + private Configuration config; + + private ServiceRequestRepository serviceRequestRepository; + + private ObjectMapper mapper; + + public BoundaryUtil(Configuration config, ServiceRequestRepository serviceRequestRepository, ObjectMapper mapper) { + this.config = config; + this.serviceRequestRepository = serviceRequestRepository; + this.mapper = mapper; + } + + public BoundarySearchResponse search(String tenantId, String hierarchyType,PlanConfigurationRequest planConfigurationRequest) { + String boundaryRelationShipSearchLink = getBoundaryRelationShipSearchLink(tenantId, hierarchyType); + Object response; + BoundarySearchResponse searchResponse = null; + try { + response = serviceRequestRepository.fetchResult(new StringBuilder(boundaryRelationShipSearchLink),planConfigurationRequest.getRequestInfo()); + return searchResponse = mapper.convertValue(response, BoundarySearchResponse.class); + + } catch (Exception ex) { + log.error("Boundary relationship response error!!", ex); + throw new CustomException("BOUNDARY_SEARCH_EXCEPTION", "Exception occurs while searhing boundary or parsing search response of boundary relationship for tenantId: "+tenantId); + } + } + + private String getBoundaryRelationShipSearchLink(String tenantId, String hierarchyType) { + String fileStoreServiceLink = config.getEgovBoundaryServiceHost() + config.getEgovBoundaryRelationshipSearchEndpoint(); + fileStoreServiceLink = fileStoreServiceLink.replace(TENANTID_REPLACER, tenantId); + fileStoreServiceLink = fileStoreServiceLink.replace(HIERARCHYTYPE_REPLACER, hierarchyType); + return fileStoreServiceLink; + } +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CalculationUtil.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CalculationUtil.java new file mode 100644 index 00000000000..d6b53891a8b --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CalculationUtil.java @@ -0,0 +1,139 @@ +package org.egov.processor.util; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.processor.config.ServiceConstants; +import org.egov.processor.web.models.Assumption; +import org.egov.processor.web.models.Operation; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; + +import static org.egov.processor.config.ServiceConstants.PROPERTIES; + +@Component +public class CalculationUtil { + + private PlanUtil planUtil; + + + + public CalculationUtil(PlanUtil planUtil) { + this.planUtil = planUtil; + } + + /** + * Calculates the output value based on the input value, operator, and assumption value. + * + * @param input The input value. + * @param operator The operator enum. + * @param assumptionValue The assumption value. + * @return The calculated output. + */ + public BigDecimal calculateOutputValue(BigDecimal input, Operation.OperatorEnum operator, BigDecimal assumptionValue) { + return switch (operator) { + case PLUS -> input.add(assumptionValue); + case MINUS -> input.subtract(assumptionValue); + case SLASH -> input.divide(assumptionValue,ServiceConstants.DEFAULT_SCALE,RoundingMode.DOWN).setScale(ServiceConstants.DEFAULT_SCALE); + case STAR -> input.multiply(assumptionValue); + case PERCENT -> input.remainder(assumptionValue); + case _U -> input.pow(assumptionValue.intValue()); + default -> throw new CustomException("UNSUPPORTED_OPERATOR", "Unsupported operator: " + operator); + }; + } + + /** + * Converts a list of assumptions into a map with assumption keys as keys and assumption values as values. + * + * @param assumptions The list of assumptions to convert. + * @return The map of assumptions. + */ + public Map convertAssumptionsToMap(List assumptions) { + return assumptions.stream().collect(Collectors.toMap(Assumption::getKey, Assumption::getValue)); + } + + /** + * Calculates resources based on the provided JSON node, list of operations, and assumption values. + * + * @param jsonNode The JSON node containing the data. + * @param resultMap The map to store the results. + * @param mappedValues The mapped values for inputs. + * @param assumptionValueMap The assumption values map. + */ + public void calculateResources(JsonNode jsonNode, PlanConfigurationRequest planConfigurationRequest, Map resultMap, + Map mappedValues, Map assumptionValueMap) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + for (JsonNode feature : jsonNode.get("features")) { + for (Operation operation : planConfig.getOperations()) { + BigDecimal result = calculateResult(operation, feature, mappedValues, assumptionValueMap, resultMap); + String output = operation.getOutput(); + resultMap.put(output, result); + ((ObjectNode) feature.get("properties")).put(output, result); + } + planUtil.create(planConfigurationRequest,feature,resultMap,mappedValues); + + } + } + + /** + * Retrieves the input value from the JSON node based on the input and input mapping. + * + * @param resultMap The map containing previous results. + * @param feature The JSON node feature. + * @param input The input key. + * @param columnName The input from mapping. + * @return The input value. + */ + public BigDecimal getInputValueFromJsonFeature(Map resultMap, JsonNode feature, String input, String columnName) { + if (resultMap.containsKey(input)) { + return resultMap.get(input); + } else { + if (feature.get(PROPERTIES).get(columnName) != null) { + try { + String cellValue = String.valueOf(feature.get(PROPERTIES).get(columnName)); + BigDecimal value; + // Handle scientific notation + if (cellValue.contains(ServiceConstants.SCIENTIFIC_NOTATION_INDICATOR)) { + value = new BigDecimal(cellValue); + } else { + String cleanedValue = cellValue.replaceAll("[^\\d.\\-E]", ""); + value = new BigDecimal(cleanedValue); + } + return value; + } catch (NumberFormatException | NullPointerException e) { + return BigDecimal.ZERO; + } + } else { + throw new CustomException("INPUT_VALUE_NOT_FOUND", "Input value not found: " + input); + } + } + } + + /** + * Calculates a result based on the provided operation and inputs. + * + * @param operation The operation object containing details like input, operator, and assumption value. + * @param feature The JSON node representing additional features or parameters for calculation. + * @param mappedValues A map containing mappings for input keys to their corresponding values. + * @param assumptionValueMap A map containing assumption values referenced by keys. + * @param resultMap A map to store and update the calculated results. + * @return The calculated result as a BigDecimal. + */ + public BigDecimal calculateResult(Operation operation, JsonNode feature, Map mappedValues, Map assumptionValueMap, Map resultMap) + { + String input = operation.getInput(); + String inputFromMapping = mappedValues.get(input); + BigDecimal inputValue = getInputValueFromJsonFeature(resultMap, feature, operation.getInput(), inputFromMapping); + BigDecimal assumptionValue = assumptionValueMap.get(operation.getAssumptionValue()); + return calculateOutputValue(inputValue, operation.getOperator(), assumptionValue); + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java new file mode 100644 index 00000000000..d14b3512aef --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/CampaignIntegrationUtil.java @@ -0,0 +1,287 @@ +package org.egov.processor.util; + +import static org.egov.processor.config.ServiceConstants.PROPERTIES; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; + +import org.apache.commons.lang.StringUtils; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.ss.usermodel.DataFormatter; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.egov.processor.config.Configuration; +import org.egov.processor.config.ServiceConstants; +import org.egov.processor.repository.ServiceRequestRepository; +import org.egov.processor.service.ExcelParser; +import org.egov.processor.web.models.File; +import org.egov.processor.web.models.Operation; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.processor.web.models.ResourceMapping; +import org.egov.processor.web.models.campaignManager.Boundary; +import org.egov.processor.web.models.campaignManager.CampaignDetails; +import org.egov.processor.web.models.campaignManager.CampaignRequest; +import org.egov.processor.web.models.campaignManager.CampaignResources; +import org.egov.processor.web.models.campaignManager.CampaignResponse; +import org.egov.processor.web.models.campaignManager.CampaignSearchRequest; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class CampaignIntegrationUtil { + + private ServiceRequestRepository serviceRequestRepository; + private Configuration config; + private ObjectMapper mapper; + + public CampaignIntegrationUtil(ServiceRequestRepository serviceRequestRepository, Configuration config, + ObjectMapper mapper, FilestoreUtil filestoreUtil, ParsingUtil parsingUtil) { + + this.serviceRequestRepository = serviceRequestRepository; + this.config = config; + this.mapper = mapper; + } + + /** + * Updates campaign details based on the provided plan configuration request and response data. + * This method integrates the campaign details obtained from the response into the provided plan configuration request. + * It also updates the campaign boundaries and resources accordingly. + * + * @param planConfigurationRequest The plan configuration request containing the execution plan details. + * @param response The response object containing campaign details. + * @param campaignBoundaryList The list of campaign boundaries. + * @param campaignResourcesList The list of campaign resources. + */ + public void updateCampaignDetails(PlanConfigurationRequest planConfigurationRequest,Object response,List campaignBoundaryList,List campaignResourcesList) { + CampaignResponse campaignResponse = null; + try { + campaignResponse = mapper.convertValue(response, CampaignResponse.class); + campaignResponse.getCampaign().get(0).setResources(campaignResourcesList); + Boundary[] array = campaignBoundaryList.toArray(new Boundary[0]); + campaignResponse.getCampaign().get(0).setBoundaries(campaignBoundaryList.toArray(new Boundary[0])); + serviceRequestRepository.fetchResult( + new StringBuilder(config.getProjectFactoryHostEndPoint() + config.getCampaignIntegrationUpdateEndPoint()), + buildCampaignRequestForUpdate(planConfigurationRequest, campaignResponse)); + log.info("Campaign Integration successful."); + } catch (Exception e) { + log.error(ServiceConstants.ERROR_WHILE_SEARCHING_CAMPAIGN + + planConfigurationRequest.getPlanConfiguration().getExecutionPlanId(), e); + throw new CustomException("Failed to update campaign details in CampaignIntegration class within method updateCampaignDetails.", e.toString()); + } + } + + /** + * Updates the campaign resources in the given campaign response based on the files specified in the plan configuration request. + * + * @param campaignResponse The campaign response object to be updated with resources. + * @param planConfigurationRequest The plan configuration request containing file information. + * @param fileStoreId The file store ID. + */ + public void updateResources(CampaignResponse campaignResponse, PlanConfigurationRequest planConfigurationRequest, + String fileStoreId) { + List campaignResourcesList = new ArrayList<>(); + List files = planConfigurationRequest.getPlanConfiguration().getFiles(); + for (File file : files) { + CampaignResources campaignResource = new CampaignResources(); + campaignResource.setFilename(ServiceConstants.FILE_NAME); + campaignResource.setFilestoreId(fileStoreId); + campaignResource.setType(ServiceConstants.FILE_TYPE); + campaignResourcesList.add(campaignResource); + } + campaignResponse.getCampaign().get(0).setResources(campaignResourcesList); + } + + /** + * Builds a campaign request object for updating campaign details based on the provided plan configuration request and campaign response. + * + * @param planConfigurationRequest The plan configuration request containing necessary information for updating the campaign. + * @param campaignResponse The campaign response containing the updated campaign details. + * @return The campaign request object built for updating campaign details. + */ + private CampaignRequest buildCampaignRequestForUpdate(PlanConfigurationRequest planConfigurationRequest, + CampaignResponse campaignResponse) { + return CampaignRequest.builder().requestInfo(planConfigurationRequest.getRequestInfo()) + .campaignDetails(campaignResponse.getCampaign().get(0)).build(); + + } + + /** + * Updates campaign boundary based on the provided plan configuration, feature, assumption values, mapped values, column index map, boundary list, and result map. + * + * @param planConfig The plan configuration containing relevant details. + * @param feature The JSON node representing the feature. + * @param assumptionValueMap The map containing assumption values. + * @param mappedValues The map containing mapped values. + * @param mapOfColumnNameAndIndex The map containing column names and their indices. + * @param boundaryList The list of campaign boundaries to update. + * @param resultMap The map containing result values. + * @throws IOException If an I/O error occurs. + */ + public void updateCampaignBoundary(PlanConfiguration planConfig, JsonNode feature, + Map assumptionValueMap, Map mappedValues, + Map mapOfColumnNameAndIndex, List boundaryList, + Map resultMap) { + Integer indexOfType = null; + boolean validToAdd = false; + Integer indexValue = 0; + Boundary boundary = new Boundary(); + List> sortedColumnList = sortColumnByIndex(mapOfColumnNameAndIndex); + indexValue = getIndexOfBoundaryCode(indexValue, sortedColumnList, mappedValues); + prepareBoundary(indexOfType, indexValue, sortedColumnList, feature, boundary, mappedValues); + if (isValidToAdd(boundaryList, resultMap, validToAdd, boundary)) + boundaryList.add(boundary); + } + + /** + * Retrieves the index value of the boundary code from the sorted column list based on the mapped values. + * + * @param indexValue The initial index value. + * @param sortedColumnList The sorted list of column names and indices. + * @param mappedValues The map containing mapped values. + * @return The index value of the boundary code. + */ + public Integer getIndexOfBoundaryCode(Integer indexValue, List> sortedColumnList,Map mappedValues) { + for (Map.Entry entry : sortedColumnList) { + if (entry.getKey().equals(mappedValues.get(ServiceConstants.BOUNDARY_CODE))) { + indexValue = entry.getValue(); + } + } + return indexValue; + } + + /** + * Prepares a campaign boundary based on the provided index values, sorted column list, feature, and mapped values. + * + * @param indexOfType The index of the boundary type. + * @param indexValue The index value. + * @param sortedColumnList The sorted list of column names and indices. + * @param feature The JSON node representing the feature. + * @param boundary The boundary object to be prepared. + * @param mappedValues The map containing mapped values. + * @return The index of the boundary type after preparation. + */ + private Integer prepareBoundary(Integer indexOfType, Integer indexValue, + List> sortedColumnList, JsonNode feature, Boundary boundary,Map mappedValues) { + String codeValue = getBoundaryCodeValue(ServiceConstants.BOUNDARY_CODE, feature, mappedValues); + boundary.setCode(codeValue); + for (int j = 0; j < indexValue; j++) { + Map.Entry entry = sortedColumnList.get(j); + String value = String.valueOf(feature.get(PROPERTIES).get(entry.getKey())); + if (StringUtils.isNotBlank(value) && value.length() > 2) { + boundary.setType(entry.getKey()); + indexOfType = entry.getValue(); + } + } + if (indexOfType == 0) { + boundary.setRoot(true); + boundary.setIncludeAllChildren(true); + } + return indexOfType; + } + + /** + * Checks if the provided boundary is valid to add to the boundary list based on the result map. + * + * @param boundaryList The list of existing boundaries. + * @param resultMap The map containing result values. + * @param validToAdd The flag indicating whether the boundary is valid to add. + * @param boundary The boundary to be checked for validity. + * @return True if the boundary is valid to add, false otherwise. + */ + private boolean isValidToAdd(List boundaryList, Map resultMap, boolean validToAdd, + Boundary boundary) { + for (Entry entry : resultMap.entrySet()) { + if (entry.getValue().compareTo(new BigDecimal(0)) > 0) { + validToAdd = true; + } else { + validToAdd = false; + break; + } + } + return validToAdd; + } + + /** + * Sorts the column names and indices based on the provided map of column names and indices. + * + * @param mapOfColumnNameAndIndex The map containing column names and their corresponding indices. + * @return The sorted list of column names and indices. + */ + public List> sortColumnByIndex(Map mapOfColumnNameAndIndex) { + List> sortedColumnList = new ArrayList<>(mapOfColumnNameAndIndex.entrySet()); + Collections.sort(sortedColumnList, new Comparator>() { + @Override + public int compare(Map.Entry o1, Map.Entry o2) { + return o1.getValue().compareTo(o2.getValue()); + } + }); + return sortedColumnList; + } + + /** + * Retrieves the value of the boundary code from the feature JSON node based on the mapped values. + * + * @param input The input key. + * @param feature The JSON node representing the feature. + * @param mappedValues The map containing mapped values. + * @return The value of the boundary code. + * @throws CustomException If the input value is not found in the feature JSON node. + */ + private String getBoundaryCodeValue(String input, JsonNode feature, Map mappedValues) { + if (feature.get(PROPERTIES).get(mappedValues.get(input)) != null) { + String value = String.valueOf(feature.get(PROPERTIES).get(mappedValues.get(input))); + return ((value != null && value.length() > 2) ? value.substring(1, value.length() - 1) : value); + } else { + throw new CustomException("INPUT_VALUE_NOT_FOUND", "Input value not found: " + input); + } + } + + /** + * Updates campaign resources with the provided file store ID. + * + * @param fileStoreId The file store ID. + * @param campaignResourcesList The list of campaign resources to update. + */ + public void updateCampaignResources(String fileStoreId,List campaignResourcesList,String fileName) { + CampaignResources campaignResource = new CampaignResources(); + campaignResource.setFilename(fileName); + campaignResource.setFilestoreId(fileStoreId); + campaignResource.setType(ServiceConstants.FILE_TYPE); + campaignResourcesList.add(campaignResource); + + } + + /** + * Builds a campaign search request based on the provided plan configuration request. + * + * @param planConfigurationRequest The plan configuration request containing necessary information for building the search request. + * @return The campaign search request object built for searching campaigns. + */ + public CampaignSearchRequest buildCampaignRequestForSearch(PlanConfigurationRequest planConfigurationRequest) { + + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + List id = new ArrayList(); + id.add(planConfig.getExecutionPlanId()); + return CampaignSearchRequest.builder().requestInfo(planConfigurationRequest.getRequestInfo()) + .campaignDetails(CampaignDetails.builder().ids(id).tenantId(planConfig.getTenantId()).build()).build(); + + } +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/FilestoreUtil.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/FilestoreUtil.java new file mode 100644 index 00000000000..37cae634df2 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/FilestoreUtil.java @@ -0,0 +1,214 @@ +package org.egov.processor.util; + +import static org.egov.processor.config.ServiceConstants.FILES; +import static org.egov.processor.config.ServiceConstants.FILESTORE_ID; +import static org.egov.processor.config.ServiceConstants.FILESTORE_ID_REPLACER; +import static org.egov.processor.config.ServiceConstants.MICROPLANNING_MODULE; +import static org.egov.processor.config.ServiceConstants.MODULE; +import static org.egov.processor.config.ServiceConstants.NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM_CODE; +import static org.egov.processor.config.ServiceConstants.NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM_MESSAGE; +import static org.egov.processor.config.ServiceConstants.TENANTID; +import static org.egov.processor.config.ServiceConstants.TENANTID_REPLACER; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Arrays; +import java.util.List; + +import org.egov.processor.config.Configuration; +import org.egov.processor.repository.ServiceRequestRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.mock.web.MockMultipartFile; +import org.springframework.stereotype.Component; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.multipart.MultipartFile; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class FilestoreUtil { + + private Configuration config; + + private ServiceRequestRepository serviceRequestRepository; + + + public FilestoreUtil(Configuration config, ServiceRequestRepository serviceRequestRepository) { + this.config = config; + this.serviceRequestRepository = serviceRequestRepository; + } + + /** + * Retrieves a file from the file store service based on the tenant ID and file store ID. + * + * @param tenantId The ID of the tenant. + * @param fileStoreId The ID of the file in the file store. + * @return The file content as a byte array. + */ + public byte[] getFile(String tenantId, String fileStoreId) { + String fileStoreServiceLink = getFileStoreServiceLink(tenantId, fileStoreId); + byte[] responseInByteArray; + Object response; + try { + response = serviceRequestRepository.fetchResultWithGET(new StringBuilder(fileStoreServiceLink)); + responseInByteArray = (byte[]) response; + } catch (Exception ex) { + log.error("File store id response error!!", ex); + throw new CustomException("FILESTORE_EXCEPTION", "File Store response can not parsed!!!"); + } + return responseInByteArray; + } + + + /** + * Uploads a file to the file store service. + * + * @param file The file to upload. + * @param tenantId The ID of the tenant. + * @return The file store ID of the uploaded file. + */ + public String uploadFile(File file, String tenantId) { + byte[] fileContent = readFileContent(file); + MultipartFile multipartFile = createMultipartFile(file, fileContent); + String url = config.getFileStoreHost() + config.getFileStoreUploadEndpoint(); + HttpHeaders headers = createHttpHeaders(multipartFile.getName()); + MultiValueMap body = createHttpBody(multipartFile, tenantId); + HttpEntity> requestEntity = new HttpEntity<>(body, headers); + ResponseEntity responseEntity = serviceRequestRepository.sendHttpRequest(url, requestEntity); + return fetchFilestoreIdFromResponse(responseEntity); + } + + /** + * Generates the file store service link by combining the file store host and endpoint, + * and replacing placeholders for tenant ID and file store ID. + * + * @param tenantId The ID of the tenant. + * @param fileStoreId The ID of the file store. + * @return The generated file store service link. + */ + private String getFileStoreServiceLink(String tenantId, String fileStoreId) { + String fileStoreServiceLink = config.getFileStoreHost() + config.getFileStoreEndpoint(); + fileStoreServiceLink = fileStoreServiceLink.replace(TENANTID_REPLACER, tenantId); + fileStoreServiceLink = fileStoreServiceLink.replace(FILESTORE_ID_REPLACER, fileStoreId); + return fileStoreServiceLink; + } + + + /** + * Reads the content of a file as a byte array. + * + * @param file The file to read. + * @return The file content as a byte array. + */ + private byte[] readFileContent(File file) { + try { + return Files.readAllBytes(file.toPath()); + } catch (IOException e) { + throw new CustomException("IOException",e.getMessage()); + } + } + + /** + * Creates a multipart file from a file and its content. + * + * @param file The file to create a multipart file from. + * @param fileContent The content of the file as a byte array. + * @return The created multipart file. + */ + private MultipartFile createMultipartFile(File file, byte[] fileContent) { + List excelExtensions = Arrays.asList("xls", "xlsx"); + String fileExtension = getFileExtension(file); + MultipartFile multipartFile = null; + if (excelExtensions.contains(fileExtension)) { + multipartFile = new MockMultipartFile(file.getName(), file.getName(), "application/xls", fileContent); + } + else + multipartFile = new MockMultipartFile(file.getName(), file.getName(), "application/geo+json", fileContent); + + return multipartFile; + } + + /** + * Creates HTTP headers for the multipart file upload. + * + * @param filename The name of the file. + * @return The HTTP headers. + */ + private HttpHeaders createHttpHeaders(String filename) { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); + headers.add(HttpHeaders.CONTENT_DISPOSITION, String.format("form-data; name=\"file\"; filename=\"%s\"", filename)); + headers.set("Accept", "application/json, text/plain, */*"); + return headers; + } + + /** + * Creates the HTTP body for the multipart file upload. + * + * @param multipartFile The multipart file to upload. + * @param tenantId The ID of the tenant. + * @return The HTTP body. + */ + private MultiValueMap createHttpBody(MultipartFile multipartFile, String tenantId) { + MultiValueMap body = new LinkedMultiValueMap<>(); + try { + body.add("file", new HttpEntity<>(multipartFile.getBytes(), createHttpHeaders(multipartFile.getName()))); + } catch (IOException e) { + throw new CustomException(NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM_CODE, NOT_ABLE_TO_CONVERT_MULTIPARTFILE_TO_BYTESTREAM_MESSAGE); + } + body.add(TENANTID, tenantId); + body.add(MODULE, MICROPLANNING_MODULE); + return body; + } + + /** + * Extracts the file store ID from the response entity of the file store service. + * + * @param responseEntity The response entity from the file store service. + * @return The file store ID of the uploaded file. + */ + public String fetchFilestoreIdFromResponse(ResponseEntity responseEntity) { + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode rootNode; + try { + rootNode = objectMapper.readTree(responseEntity.getBody()); + } catch (JsonProcessingException e) { + log.error(e.getMessage()); + throw new CustomException("FILESTORE_EXCEPTION", "File Store response can not parsed!!!"); + } + + String fileStoreId = rootNode.get(FILES).get(0).get(FILESTORE_ID).asText(); + System.out.println("FileStoreId: " + fileStoreId); + return fileStoreId; + } + + /** + * Retrieves the file extension from a file name. + * + * @param file The file to get the extension from. + * @return The file extension. + */ + public String getFileExtension(File file) { + String fileName = file.getName(); + String extension = ""; + + int lastIndexOfDot = fileName.lastIndexOf('.'); + if (lastIndexOfDot >= 0) { + extension = fileName.substring(lastIndexOfDot + 1); + } + + return extension; + } + +} \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/MdmsUtil.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/MdmsUtil.java new file mode 100644 index 00000000000..c46529c06e0 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/MdmsUtil.java @@ -0,0 +1,145 @@ +package org.egov.processor.util; + +import static org.egov.processor.config.ServiceConstants.ERROR_WHILE_FETCHING_FROM_MDMS; +import static org.egov.processor.config.ServiceConstants.NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_CODE; +import static org.egov.processor.config.ServiceConstants.NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_MESSAGE; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.egov.common.contract.request.RequestInfo; +import org.egov.mdms.model.MasterDetail; +import org.egov.mdms.model.MdmsCriteria; +import org.egov.mdms.model.MdmsCriteriaReq; +import org.egov.mdms.model.MdmsResponse; +import org.egov.mdms.model.ModuleDetail; +import org.egov.processor.config.Configuration; +import org.egov.processor.config.ServiceConstants; +import org.egov.processor.web.models.File; +import org.egov.tracer.model.CustomException; +import org.flywaydb.core.internal.util.JsonUtils; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; +import org.springframework.web.client.RestTemplate; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +public class MdmsUtil { + + private RestTemplate restTemplate; + + private ObjectMapper mapper; + + private Configuration configs; + + public MdmsUtil(RestTemplate restTemplate, ObjectMapper mapper, Configuration configs) { + this.restTemplate = restTemplate; + this.mapper = mapper; + this.configs = configs; + } + + /** + * Fetches MDMS (Municipal Data Management System) data using the provided + * request information and tenant ID. + * + * @param requestInfo The request information. + * @param tenantId The ID of the tenant for which MDMS data is to be fetched. + * @return The MDMS response data. + * @throws CustomException if there's an error while fetching MDMS data or if no + * data is found for the given tenant. + */ + public Object fetchMdmsData(RequestInfo requestInfo, String tenantId) { + StringBuilder uri = new StringBuilder(); + uri.append(configs.getMdmsHost()).append(configs.getMdmsEndPoint()); + MdmsCriteriaReq mdmsCriteriaReq = getMdmsRequest(requestInfo, tenantId); + Object response = new HashMap<>(); + MdmsResponse mdmsResponse = new MdmsResponse(); + try { + response = restTemplate.postForObject(uri.toString(), mdmsCriteriaReq, Map.class); + mdmsResponse = mapper.convertValue(response, MdmsResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_MDMS, e); + } + + Object result = mdmsResponse.getMdmsRes(); + if (result == null || ObjectUtils.isEmpty(result)) { + log.error(NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_MESSAGE + " - " + tenantId); + throw new CustomException(NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_CODE, + NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_MESSAGE); + } + return result; + } + + /** + * Constructs an MDMS request object based on the provided request information and tenant ID. + * + * @param requestInfo The request information. + * @param tenantId The ID of the tenant for which MDMS data is to be fetched. + * @return The MDMS criteria request object. + */ + public MdmsCriteriaReq getMdmsRequest(RequestInfo requestInfo, String tenantId) { + + ModuleDetail moduleDetail = getPlanModuleDetail(); + List moduleDetails = new LinkedList<>(); + moduleDetails.add(moduleDetail); + MdmsCriteria mdmsCriteria = MdmsCriteria.builder().moduleDetails(moduleDetails).tenantId(tenantId).build(); + return MdmsCriteriaReq.builder().mdmsCriteria(mdmsCriteria).requestInfo(requestInfo).build(); + } + + /** + * Retrieves the module details for the plan module. + * + * @return ModuleDetail object containing master details for the plan module. + */ + private ModuleDetail getPlanModuleDetail() { + List assumptionMasterDetails = new ArrayList<>(); + MasterDetail schemaDetails = MasterDetail.builder().name(ServiceConstants.MDMS_MASTER_SCHEMAS).build(); + assumptionMasterDetails.add(schemaDetails); + + return ModuleDetail.builder().masterDetails(assumptionMasterDetails) + .moduleName(ServiceConstants.MDMS_PLAN_MODULE_NAME).build(); + } + + /** + * Filters master data based on the provided parameters. + * + * @param masterDataJson The JSON string representing the master data. + * @param fileType The type of input file. + * @param templateIdentifier The template identifier. + * @param campaignType The campaign type. + * @return A map containing filtered properties from the master data. + * @throws JsonMappingException if there's an issue mapping JSON. + * @throws JsonProcessingException if there's an issue processing JSON. + */ + public Map filterMasterData(String masterDataJson, File.InputFileTypeEnum fileType, + String templateIdentifier, String campaignType) { + Map properties = new HashMap<>(); + Map masterData = JsonUtils.parseJson(masterDataJson, Map.class); + Map planModule = (Map) masterData.get(ServiceConstants.MDMS_PLAN_MODULE_NAME); + List> schemas = (List>) planModule + .get(ServiceConstants.MDMS_MASTER_SCHEMAS); + log.info("masterDataJson ==>" + schemas); + for (Map schema : schemas) { + String type = (String) schema.get(ServiceConstants.MDMS_SCHEMA_TYPE); + String campaign = (String) schema.get(ServiceConstants.MDMS_CAMPAIGN_TYPE); + // String fileT = InputFileTypeEnum.valueOf(type); + if (schema.get(ServiceConstants.MDMS_SCHEMA_SECTION).equals(ServiceConstants.FILE_TEMPLATE_IDENTIFIER) + && campaign.equals(campaignType) && type.equals(fileType.toString())) { + Map schemaProperties = (Map) schema.get("schema"); + properties = (Map) schemaProperties.get("Properties"); + } + } + + return properties; + } + +} \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/ParsingUtil.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/ParsingUtil.java new file mode 100644 index 00000000000..b1902b49afb --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/ParsingUtil.java @@ -0,0 +1,249 @@ +package org.egov.processor.util; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +import org.apache.commons.io.FileUtils; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.DataFormatter; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.ResourceMapping; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Component +public class ParsingUtil { + + private PlanConfigurationUtil planConfigurationUtil; + + private FilestoreUtil filestoreUtil; + + private CalculationUtil calculationUtil; + + public ParsingUtil(PlanConfigurationUtil planConfigurationUtil, FilestoreUtil filestoreUtil, CalculationUtil calculationUtil) { + this.planConfigurationUtil = planConfigurationUtil; + this.filestoreUtil = filestoreUtil; + this.calculationUtil = calculationUtil; + } + + public List fetchAttributeNamesFromJson(JsonNode jsonNode) + { + if(jsonNode.get("features") == null) + throw new CustomException("No Features found in geojson", " "); + List columnNames = new ArrayList<>(); + JsonNode propertiesNode = jsonNode.get("features").get(0).get("properties"); + Iterator fieldNames = propertiesNode.fieldNames(); + while (fieldNames.hasNext()) { + String columnName = fieldNames.next(); + columnNames.add(columnName); + } + return columnNames; + } + public void validateColumnNames(List columnNamesList, PlanConfiguration planConfig, String fileStoreId ) { + Set mappedFromSet = planConfig.getResourceMapping().stream() + .filter(mapping -> Objects.equals(mapping.getFilestoreId(), fileStoreId)) + .map(ResourceMapping::getMappedFrom) + .collect(Collectors.toSet()); + + for (String attributeName : mappedFromSet) { + if (attributeName.equalsIgnoreCase("the_geom")) + continue; + if (!columnNamesList.contains(attributeName)) { + log.error("Attribute mapping is invalid."); + log.info("Plan configuration doesn't contain a mapping for attribute -> " + attributeName); + throw new CustomException("Attribute mapping is invalid.", "Plan configuration doesn't contain a mapping for attribute -> " + attributeName); + } + } + + log.info("Attribute mapping is valid."); + } + + /** + * Extracts attribute names and their corresponding indices from the first row of an Excel sheet. + * + * @param sheet The Excel sheet from which to extract attribute names and indices. + * @return A sorted map containing attribute names as keys and their corresponding indices as values. + */ + public Map getAttributeNameIndexFromExcel(Sheet sheet) { + Map columnIndexMap = new HashMap<>(); + Map sortedMap = new LinkedHashMap<>(); + DataFormatter dataFormatter = new DataFormatter(); + // Assuming the first row contains column headers + Row headerRow = sheet.getRow(0); + for (int i = 0; i < headerRow.getLastCellNum(); i++) { + Cell cell = headerRow.getCell(i); + String columnHeader = dataFormatter.formatCellValue(cell); + columnIndexMap.put(columnHeader, i); + } + List> sortedColumnList = new ArrayList<>(columnIndexMap.entrySet()); + Collections.sort(sortedColumnList, (o1, o2) -> (o1.getValue()).compareTo(o2.getValue())); + for (Map.Entry entry : sortedColumnList) { + sortedMap.put(entry.getKey(), entry.getValue()); + } + return sortedMap; + } + + /** + * Converts a byte array to a File object. + * + * @param byteArray The byte array to convert. + * @param fileName The name of the file to create. + * @return The File object representing the byte array. + */ + public File convertByteArrayToFile(byte[] byteArray, String fileName) { + try { + File file = new File(fileName); + ByteArrayInputStream bis = new ByteArrayInputStream(byteArray); + FileUtils.copyInputStreamToFile(bis, file); + bis.close(); + return file; + } catch (IOException e) { + log.error("CANNOT_CONVERT_BYTE_ARRAY_TO_FILE", "Cannot convert byte array from response to File object"); + } + return null; + } + + /** + * Retrieves a file from a byte array. + * + * @param planConfig The plan configuration containing tenant and file information. + * @param fileStoreId The ID of the file store. + * @return The File object representing the byte array. + */ + public File getFileFromByteArray(PlanConfiguration planConfig, String fileStoreId) { + byte[] byteArray = filestoreUtil.getFile(planConfig.getTenantId(), fileStoreId); + return convertByteArrayToFile(byteArray, "geojson"); + } + + /** + * Converts a byte array to a String. + * + * @param planConfig The plan configuration containing tenant and file information. + * @param fileStoreId The ID of the file store. + * @return The String representation of the byte array. + */ + public String convertByteArrayToString(PlanConfiguration planConfig, String fileStoreId) { + byte[] byteArray = filestoreUtil.getFile(planConfig.getTenantId(), fileStoreId); + return new String(byteArray, StandardCharsets.UTF_8); + } + + /** + * Converts a File object containing JSON data to a String. + * + * @param geojsonFile The File object containing JSON data. + * @return The String representation of the JSON data. + */ + public String convertFileToJsonString(File geojsonFile) { + String geoJSONString = null; + try { + geoJSONString = new String(Files.readAllBytes(geojsonFile.toPath())); + } catch (IOException e) { + throw new CustomException(e.getMessage(), ""); + } + + return geoJSONString; + } + + /** + * Writes a JsonNode to a file. + * + * @param jsonNode The JsonNode to write. + * @param objectMapper The ObjectMapper used for writing the JsonNode. + * @return The File object representing the written JSON data. + */ + public File writeToFile(JsonNode jsonNode, ObjectMapper objectMapper) { + String outputFileName = "processed.geojson"; + File outputFile; + try { + String processedGeoJSON = objectMapper.writeValueAsString(jsonNode); + Object jsonObject = objectMapper.readValue(processedGeoJSON, Object.class); + outputFile = new File(outputFileName); + objectMapper.writeValue(outputFile, jsonObject); + return outputFile; + } catch (IOException e) { + throw new CustomException("NOT_ABLE_TO_WRITE_TO_FILE", "Not able to write processed geojson to file"); + } + } + + /** + * Parses a JSON string into a JsonNode. + * + * @param geoJSON The JSON string to parse. + * @param objectMapper The ObjectMapper used for parsing the JSON string. + * @return The parsed JsonNode. + */ + public JsonNode parseJson(String geoJSON, ObjectMapper objectMapper) { + try { + return objectMapper.readTree(geoJSON); + } catch (Exception e) { + log.error(e.getMessage()); + throw new CustomException("JSON_PARSE_ERROR", "Error parsing JSON: " + e.getMessage()); + } + } + + /** + * Extracts shapefiles from a zip file and returns the .shp file. + * + * @param planConfig The plan configuration containing tenant and file information. + * @param fileStoreId The ID of the file store. + * @param fileName The name of the file to extract. + * @return The extracted .shp File object. + * @throws IOException If an I/O error occurs while extracting the shapefiles. + */ + public File extractShapeFilesFromZip(PlanConfiguration planConfig, String fileStoreId, String fileName) throws IOException { + File shpFile = null; + byte[] zipFileBytes = filestoreUtil.getFile(planConfig.getTenantId(), fileStoreId); + + try (ByteArrayInputStream bais = new ByteArrayInputStream(zipFileBytes); ZipInputStream zis = new ZipInputStream(bais)) { + ZipEntry entry; + while ((entry = zis.getNextEntry()) != null) { + if (entry.getName().endsWith(".dbf")) { + String fileBaseName = entry.getName().substring(0, entry.getName().length() - 4); // Remove the .shp extension + + File tempDir = new File(System.getProperty("java.io.tmpdir") + File.separator + fileBaseName); + if (!tempDir.exists()) { + tempDir.mkdirs(); + } + + String shpFilePath = tempDir.getAbsolutePath() + File.separator + entry.getName(); + FileOutputStream fos = new FileOutputStream(shpFilePath); + byte[] buffer = new byte[4096]; + int bytesRead; + while ((bytesRead = zis.read(buffer)) != -1) { + fos.write(buffer, 0, bytesRead); + } + fos.close(); + + shpFile = new File(shpFilePath); + break; // Assuming there is only one .shp file in the zip + } + } + } + return shpFile; + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java new file mode 100644 index 00000000000..26a11dcf976 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanConfigurationUtil.java @@ -0,0 +1,57 @@ +package org.egov.processor.util; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import lombok.extern.slf4j.Slf4j; + +import org.egov.processor.config.Configuration; +import org.egov.processor.repository.ServiceRequestRepository; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationResponse; +import org.egov.processor.web.models.PlanConfigurationSearchRequest; +import org.springframework.stereotype.Component; + +import static org.egov.processor.config.ServiceConstants.ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE; + +@Component +@Slf4j +public class PlanConfigurationUtil { + + private ServiceRequestRepository serviceRequestRepository; + + private Configuration config; + + private ObjectMapper mapper; + + public PlanConfigurationUtil(ServiceRequestRepository serviceRequestRepository, Configuration config, ObjectMapper mapper) { + this.serviceRequestRepository = serviceRequestRepository; + this.config = config; + this.mapper = mapper; + } + + public List search(PlanConfigurationSearchRequest planConfigurationSearchRequest) + { + List planConfigurationList = new ArrayList<>(); + PlanConfigurationResponse planConfigurationResponse = null; + Object response = new HashMap<>(); + + StringBuilder uri = new StringBuilder(); + uri.append(config.getPlanConfigHost()).append(config.getPlanConfigEndPoint()); + + try { + response = serviceRequestRepository.fetchResult(uri, planConfigurationSearchRequest); + planConfigurationResponse = mapper.convertValue(response, PlanConfigurationResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE, e); + } + + + if(planConfigurationResponse != null) + return planConfigurationResponse.getPlanConfiguration(); + else + return planConfigurationList; + } +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanUtil.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanUtil.java new file mode 100644 index 00000000000..d44aaa2a59f --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/PlanUtil.java @@ -0,0 +1,132 @@ +package org.egov.processor.util; + +import static org.egov.processor.config.ServiceConstants.ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE_FOR_LOCALITY; +import static org.egov.processor.config.ServiceConstants.PROPERTIES; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.egov.processor.config.Configuration; +import org.egov.processor.config.ServiceConstants; +import org.egov.processor.repository.ServiceRequestRepository; +import org.egov.processor.kafka.Producer; +import org.egov.processor.web.models.Activity; +import org.egov.processor.web.models.Plan; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.processor.web.models.PlanConfigurationResponse; +import org.egov.processor.web.models.PlanRequest; +import org.egov.processor.web.models.Resource; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class PlanUtil { + private ServiceRequestRepository serviceRequestRepository; + + private Configuration config; + + private Producer producer; + + public PlanUtil(ServiceRequestRepository serviceRequestRepository, Configuration config, Producer producer) { + this.serviceRequestRepository = serviceRequestRepository; + this.config = config; + this.producer = producer; + } + + /** + * Creates a plan configuration request, builds a plan request from it, and pushes it to the messaging system for further processing. + * + * @param planConfigurationRequest The plan configuration request. + * @param feature The feature JSON node. + * @param resultMap The result map. + * @param mappedValues The mapped values. + */ + public void create(PlanConfigurationRequest planConfigurationRequest, JsonNode feature, + Map resultMap, Map mappedValues) { + PlanRequest planRequest = buildPlanRequest(planConfigurationRequest, feature, resultMap, mappedValues); + try { + producer.push(config.getResourceMicroplanCreateTopic(), planRequest); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_PLAN_SERVICE_FOR_LOCALITY + planRequest.getPlan().getLocality(), e); + } + } + + /** + * Builds a PlanRequest object using the provided plan configuration request, feature JSON node, + * result map, mapped values, and assumption value map. + * + * @param planConfigurationRequest The plan configuration request. + * @param feature The feature JSON node. + * @param resultMap The result map. + * @param mappedValues The mapped values. + * @return The constructed PlanRequest object. + */ + private PlanRequest buildPlanRequest(PlanConfigurationRequest planConfigurationRequest, JsonNode feature, + Map resultMap, Map mappedValues) { + + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); + return PlanRequest.builder() + .requestInfo(planConfigurationRequest.getRequestInfo()) + .plan(Plan.builder() + .tenantId(planConfig.getTenantId()) + .executionPlanId(planConfig.getExecutionPlanId()) + .locality(getBoundaryCodeValue(ServiceConstants.BOUNDARY_CODE, + feature, mappedValues)) + .resources(resultMap.entrySet().stream().map(result -> { + Resource res = new Resource(); + res.setResourceType(result.getKey()); + res.setEstimatedNumber(result.getValue()); + return res; + }).collect(Collectors.toList())) + .activities(new ArrayList()) + .targets(new ArrayList()) + .build()) + .build(); + + } + + /** + * Retrieves the boundary code value from the feature JSON node using the mapped value for the given input. + * + * @param input The input value. + * @param feature The feature JSON node. + * @param mappedValues The mapped values. + * @return The boundary code value. + * @throws CustomException if the input value is not found in the feature JSON node. + */ + private String getBoundaryCodeValue(String input, JsonNode feature, Map mappedValues) { + if (feature.get(PROPERTIES).get(mappedValues.get(input)) != null) { + String value = String.valueOf(feature.get(PROPERTIES).get(mappedValues.get(input))); + return ((value!=null && value.length()>2)?value.substring(1, value.length()-1):value); + } + else { + throw new CustomException("INPUT_VALUE_NOT_FOUND", "Input value not found: " + input); + } + } + + /** + * Updates the plan configuration request by pushing it to the messaging system for further processing. + * + * @param planConfigurationRequest The plan configuration request to be updated. + */ + public void update(PlanConfigurationRequest planConfigurationRequest) { + + try { + producer.push(config.getResourceUpdatePlanConfigConsumerTopic(), planConfigurationRequest); + log.info("Plan Config updated because of Invalid data."); + } catch (Exception e) { + log.error(ServiceConstants.ERROR_WHILE_UPDATING_PLAN_CONFIG); + } + } +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/controllers/FileController.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/controllers/FileController.java new file mode 100644 index 00000000000..fac9d74d4d1 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/controllers/FileController.java @@ -0,0 +1,54 @@ +package org.egov.processor.web.controllers; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import java.util.List; +import org.egov.common.contract.request.RequestInfo; +import org.egov.processor.service.ExcelParser; +import org.egov.processor.util.ParsingUtil; +import org.egov.processor.util.PlanConfigurationUtil; +import org.egov.processor.web.models.PlanConfiguration; +import org.egov.processor.web.models.PlanConfigurationSearchCriteria; +import org.egov.processor.web.models.PlanConfigurationSearchRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.stereotype.Controller; + + +@Controller +public class FileController { + + private ObjectMapper objectMapper; + + private ParsingUtil parsingUtil; + + private ExcelParser parser; + + private PlanConfigurationUtil planConfigurationUtil; + + @Autowired + public FileController(ObjectMapper objectMapper, ParsingUtil parsingUtil, ExcelParser parser, PlanConfigurationUtil planConfigurationUtil) { + this.objectMapper = objectMapper; + this.parsingUtil = parsingUtil; + this.parser = parser; + this.planConfigurationUtil = planConfigurationUtil; + } + + @RequestMapping(value = "/config/_test", method = RequestMethod.POST) + public ResponseEntity test() { + + PlanConfigurationSearchCriteria planConfigurationSearchCriteria = PlanConfigurationSearchCriteria.builder() + .tenantId("mz").id("b1a23c4e-a402-4047-9388-e8ae2bf7c1a3").build(); + +// id("533db2ad-cfa7-42ce-b9dc-c2877c7405ca") + PlanConfigurationSearchRequest planConfigurationSearchRequest = PlanConfigurationSearchRequest.builder().planConfigurationSearchCriteria(planConfigurationSearchCriteria).requestInfo(new RequestInfo()).build(); + List planConfigurationls = planConfigurationUtil.search(planConfigurationSearchRequest); + +// parser.parseFileData(planConfigurationls.get(0)); + return ResponseEntity.status(HttpStatus.OK).body("Okay"); + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Activity.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Activity.java new file mode 100644 index 00000000000..fa9e1193e90 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Activity.java @@ -0,0 +1,48 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * Activity + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Activity { + @JsonProperty("id") + private String id = null; + + @JsonProperty("code") + @NotNull + @Size(min = 2, max = 128) + private String code = null; + + @JsonProperty("description") + @Size(max = 2048) + private String description = null; + + @JsonProperty("plannedStartDate") + private Long plannedStartDate = null; + + @JsonProperty("plannedEndDate") + private Long plannedEndDate = null; + + @JsonProperty("dependencies") + private List dependencies = null; + + @JsonProperty("conditions") + @Valid + private List conditions = null; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Assumption.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Assumption.java new file mode 100644 index 00000000000..b8ed98d54e8 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Assumption.java @@ -0,0 +1,45 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; + +/** + * Assumption + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Assumption { + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("key") + @NotNull + @Size(min = 1, max = 256) + private String key = null; + + @JsonProperty("value") + @NotNull + @Valid + @DecimalMin(value = "0.01", inclusive = true, message = "Assumption value must be greater than 0") + @DecimalMax(value = "999.99", inclusive = true, message = "Assumption value must be less than 1000") + @Digits(integer = 3, fraction = 2, message = "Assumption value must have up to 3 digits and up to 2 decimal points") + private BigDecimal value = null; + + @JsonProperty("active") + @NotNull + private Boolean active = true; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Condition.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Condition.java new file mode 100644 index 00000000000..51d3511c068 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Condition.java @@ -0,0 +1,40 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * Condition + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Condition { + + @JsonProperty + private String id = null; + + @JsonProperty("entity") + @NotNull + @Size(min = 2, max = 64) + private String entity = null; + + @JsonProperty("entityProperty") + @NotNull + @Size(min = 2, max = 64) + private String entityProperty = null; + + @JsonProperty("expression") + @NotNull + @Size(min = 3, max = 2048) + private String expression = null; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/File.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/File.java new file mode 100644 index 00000000000..fe6b6c1abab --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/File.java @@ -0,0 +1,83 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * File + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class File { + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("filestoreId") + @NotNull + @Size(min = 1, max = 128) + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Filestore Id must contain alphanumeric characters and may include some special characters") + private String filestoreId = null; + + @JsonProperty("inputFileType") + @NotNull + private InputFileTypeEnum inputFileType = null; + + @JsonProperty("templateIdentifier") + @NotNull + @Size(min = 2, max = 128) + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Name must contain alphanumeric characters and may include some special characters") + private String templateIdentifier = null; + + @JsonProperty("active") + @NotNull + private Boolean active = true; + + /** + * The original file type of the Input + */ + public enum InputFileTypeEnum { + EXCEL("Excel"), + + SHAPEFILE("Shapefile"), + + GEOJSON("GeoJSON"); + + private String value; + + InputFileTypeEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static InputFileTypeEnum fromValue(String text) { + for (InputFileTypeEnum b : InputFileTypeEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/MetricDetail.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/MetricDetail.java new file mode 100644 index 00000000000..32a5c0b4ccc --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/MetricDetail.java @@ -0,0 +1,34 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.math.BigDecimal; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class MetricDetail { + + @JsonProperty("value") + @NotNull + private BigDecimal metricValue = null; + + @JsonProperty("comparator") + @NotNull + @Size(min = 1, max = 64) + private String metricComparator = null; + + @JsonProperty("unit") + @NotNull + @Size(min = 1, max = 128) + private String metricUnit = null; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Operation.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Operation.java new file mode 100644 index 00000000000..25b5b189fa0 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Operation.java @@ -0,0 +1,92 @@ +package org.egov.processor.web.models; + + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * Operation + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Operation { + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("input") + @NotNull + @Size(min = 1, max = 256) + private String input = null; + + @JsonProperty("operator") + @NotNull + private OperatorEnum operator = null; + + @JsonProperty("assumptionValue") + @NotNull + @Size(min = 2, max = 256) + private String assumptionValue = null; + + @JsonProperty("output") + @NotNull + @Size(min = 1, max = 64) + private String output = null; + + @JsonProperty("active") + @NotNull + private Boolean active = true; + + /** + * The operator used in the operation + */ + public enum OperatorEnum { + PLUS("+"), + + MINUS("-"), + + SLASH("/"), + + STAR("*"), + + PERCENT("%"), + + _U("**"); + + private String value; + + OperatorEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static OperatorEnum fromValue(String text) { + for (OperatorEnum b : OperatorEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Plan.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Plan.java new file mode 100644 index 00000000000..a9d4f3139b5 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Plan.java @@ -0,0 +1,63 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; + +/** + * Plan + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Plan { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("locality") + @Size(min = 1, max = 64) + private String locality = null; + + @JsonProperty("executionPlanId") + @Size(max = 64) + private String executionPlanId = null; + + @JsonProperty("planConfigurationId") + @Size(max = 64) + private String planConfigurationId = null; + + @JsonProperty("additionalDetails") + private Object additionalDetails = null; + + @JsonProperty("activities") + @Valid + private List activities = null; + + @JsonProperty("resources") + @Valid + private List resources = null; + + @JsonProperty("targets") + @Valid + private List targets = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfiguration.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfiguration.java new file mode 100644 index 00000000000..e02d7e49b70 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfiguration.java @@ -0,0 +1,89 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotEmpty; +import java.util.ArrayList; +import java.util.List; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import jakarta.validation.constraints.Pattern; +import org.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; +import lombok.Data; +import lombok.Builder; + +/** + * PlanConfiguration + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanConfiguration { + @JsonProperty("id") + @Valid + @Size(min = 2, max = 64) + private String id = null; + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("name") + @NotNull + @Size(min = 2, max = 128) + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Name must not contain only special characters") + private String name = null; + + @JsonProperty("executionPlanId") + @NotNull + @Size(min = 2, max = 64) + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Execution Plan Id must not contain only special characters") + private String executionPlanId = null; + + @JsonProperty("status") + @NotNull + private StatusEnum status = null; + + @JsonProperty("files") + @NotNull + @NotEmpty + @Valid + private List files = new ArrayList<>(); + + @JsonProperty("assumptions") + @NotNull + @NotEmpty + @Valid + private List assumptions = new ArrayList<>(); + + @JsonProperty("operations") + @NotNull + @NotEmpty + @Valid + private List operations = new ArrayList<>(); + + @JsonProperty("resourceMapping") + @NotNull + @NotEmpty + @Valid + private List resourceMapping = new ArrayList<>(); + + @JsonProperty("auditDetails") + private @Valid AuditDetails auditDetails; + + /** + * The status used in the Plan Configuration + */ + public enum StatusEnum { + DRAFT , + GENERATED, + INVALID_DATA + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationRequest.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationRequest.java new file mode 100644 index 00000000000..555db5d17e1 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationRequest.java @@ -0,0 +1,30 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * PlanConfigurationRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanConfigurationRequest { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("PlanConfiguration") + @Valid + private PlanConfiguration planConfiguration = null; + + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationResponse.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationResponse.java new file mode 100644 index 00000000000..c3892dbc869 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationResponse.java @@ -0,0 +1,40 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import java.util.ArrayList; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +/** + * PlanConfigurationResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanConfigurationResponse { + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("PlanConfiguration") + @Valid + private List planConfiguration = null; + + + public PlanConfigurationResponse addPlanConfigurationResponseItem(PlanConfiguration planConfigurationResponseItem) { + if (this.planConfiguration == null) { + this.planConfiguration = new ArrayList<>(); + } + this.planConfiguration.add(planConfigurationResponseItem); + return this; + } + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchCriteria.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchCriteria.java new file mode 100644 index 00000000000..b03c281067b --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchCriteria.java @@ -0,0 +1,39 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * PlanConfigurationSearchCriteria + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanConfigurationSearchCriteria { + @JsonProperty("tenantId") + @Size(min = 1, max = 100) + private String tenantId = null; + + @JsonProperty("id") + private String id = null; + + @JsonProperty("name") + private String name = null; + + @JsonProperty("executionPlanId") + private String executionPlanId = null; + + @JsonProperty("offset") + private Integer offset; + + @JsonProperty("limit") + private Integer limit; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchRequest.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchRequest.java new file mode 100644 index 00000000000..6b421259d15 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanConfigurationSearchRequest.java @@ -0,0 +1,30 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * PlanConfigurationSearchRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanConfigurationSearchRequest { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("PlanConfigurationSearchCriteria") + @Valid + private PlanConfigurationSearchCriteria planConfigurationSearchCriteria = null; + + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanRequest.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanRequest.java new file mode 100644 index 00000000000..a462e0605c0 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/PlanRequest.java @@ -0,0 +1,30 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * PlanCreateRequest + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class PlanRequest { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("Plan") + @Valid + private Plan plan = null; + + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Resource.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Resource.java new file mode 100644 index 00000000000..5fea454bd5d --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Resource.java @@ -0,0 +1,39 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import java.math.BigDecimal; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * Resource + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Resource { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("resourceType") + @NotNull + @Size(min = 2, max = 256) + private String resourceType = null; + + @JsonProperty("estimatedNumber") + @NotNull + private BigDecimal estimatedNumber = null; + + @JsonProperty("activityCode") + @Size(min = 2, max = 128) + private String activityCode = null; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/ResourceMapping.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/ResourceMapping.java new file mode 100644 index 00000000000..c53868d1033 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/ResourceMapping.java @@ -0,0 +1,47 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * ResourceMapping + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ResourceMapping { + @JsonProperty("id") + @Valid + private String id = null; + + @JsonProperty("filestoreId") + @NotNull + @Size(min = 1, max = 128) + @Pattern(regexp = "^(?!\\p{Punct}+$).*$", message = "Filestore Id must not contain only special characters") + private String filestoreId = null; + + @JsonProperty("mappedFrom") + @NotNull + @Size(min = 2, max = 256) + private String mappedFrom = null; + + @JsonProperty("mappedTo") + @NotNull + @Size(min = 2, max = 256) + private String mappedTo = null; + + @JsonProperty("active") + @NotNull + private Boolean active = true; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Target.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Target.java new file mode 100644 index 00000000000..8d7298939f6 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Target.java @@ -0,0 +1,37 @@ +package org.egov.processor.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + +/** + * Target + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Target { + + @JsonProperty("id") + @Valid + private String id = null; + + @JsonProperty("metric") + private String metric = null; + + @JsonProperty("metricDetail") + @Valid + private MetricDetail metricDetail = null; + + @JsonProperty("activityCode") + @Size(min = 2, max = 128) + private String activityCode = null; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/BoundarySearchResponse.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/BoundarySearchResponse.java new file mode 100644 index 00000000000..d72d5bbc608 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/BoundarySearchResponse.java @@ -0,0 +1,45 @@ +package org.egov.processor.web.models.boundary; + +import java.util.ArrayList; +import java.util.List; + +import javax.validation.Valid; + +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * BoundarySearchResponse + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class BoundarySearchResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("TenantBoundary") + @Valid + private List tenantBoundary = null; + + + public BoundarySearchResponse addTenantBoundaryItem(HierarchyRelation tenantBoundaryItem) { + if (this.tenantBoundary == null) { + this.tenantBoundary = new ArrayList<>(); + } + this.tenantBoundary.add(tenantBoundaryItem); + return this; + } + +} \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/EnrichedBoundary.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/EnrichedBoundary.java new file mode 100644 index 00000000000..e0240d1e6d4 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/EnrichedBoundary.java @@ -0,0 +1,46 @@ +package org.egov.processor.web.models.boundary; + +import java.util.ArrayList; +import java.util.List; + +import javax.validation.Valid; +import javax.validation.constraints.NotNull; + +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * EnrichedBoundary + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class EnrichedBoundary { + + @JsonProperty("id") + private String id; + + @JsonProperty("code") + @NotNull + private String code; + + @JsonProperty("boundaryType") + private String boundaryType; + + @JsonProperty("children") + @Valid + private List children = null; + + @JsonIgnore + private String parent = null; + +} \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/HierarchyRelation.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/HierarchyRelation.java new file mode 100644 index 00000000000..f8de3cc5816 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/boundary/HierarchyRelation.java @@ -0,0 +1,37 @@ +package org.egov.processor.web.models.boundary; + +import java.util.List; + +import javax.validation.Valid; + +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * HierarchyRelation + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class HierarchyRelation { + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("hierarchyType") + private String hierarchyType = null; + + @JsonProperty("boundary") + @Valid + private List boundary = null; + + +} \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/AdditionalDetails.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/AdditionalDetails.java new file mode 100644 index 00000000000..ecaa5b6b7f1 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/AdditionalDetails.java @@ -0,0 +1,32 @@ +package org.egov.processor.web.models.campaignManager; + +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AdditionalDetails { + + @JsonProperty("key") + @Valid + private int key; + + @JsonProperty("cycleData") + @Valid + private CycleData cycleData; + + @JsonProperty("beneficiaryType") + @Valid + private String beneficiaryType; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Boundary.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Boundary.java new file mode 100644 index 00000000000..89e93500795 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Boundary.java @@ -0,0 +1,41 @@ +package org.egov.processor.web.models.campaignManager; + +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Boundary { + + @JsonProperty("code") + @NotNull + @Size(min = 1, max = 64) + private String code; + + @JsonProperty("type") + @NotNull + @Size(min = 1, max = 128) + private String type; + + @JsonProperty("isRoot") + private boolean isRoot; + + @JsonProperty("parent") + @Valid + private String parent; + + @JsonProperty("includeAllChildren") + private boolean includeAllChildren; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Campaign.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Campaign.java new file mode 100644 index 00000000000..352b29b693b --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Campaign.java @@ -0,0 +1,92 @@ +package org.egov.processor.web.models.campaignManager; + +import java.util.List; + +import org.egov.common.contract.models.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Campaign { + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("id") + private String id; + + @JsonProperty("status") + @Valid + private String status; + + @JsonProperty("action") + @Size(min = 1, max = 64) + private String action; + + @JsonProperty("campaignNumber") + @Valid + private String campaignNumber; + + @JsonProperty("campaignName") + @Size(min = 2, max = 250) + private String campaignName; + + @JsonProperty("projectType") + @Size(min = 1, max = 128) + private String projectType; + + @JsonProperty("hierarchyType") + @Size(min = 1, max = 128) + private String hierarchyType; + + @JsonProperty("boundaryCode") + @Valid + private String boundaryCode; + + @JsonProperty("projectId") + @Valid + private String projectId; + + @JsonProperty("startDate") + private long startDate; + + @JsonProperty("endDate") + private long endDate; + + @JsonProperty("additionalDetails") + @Valid + private AdditionalDetails additionalDetails; + + @JsonProperty("resources") + @Valid + private List resources; + + @JsonProperty("boundaries") + @Valid + private Boundary[] boundaries = new Boundary[0]; + + @JsonProperty("deliveryRules") + @Valid + private DeliveryRule[] deliveryRules= new DeliveryRule[0]; + + @JsonProperty("auditDetails") + @Valid + private AuditDetails auditDetails; + + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignCondition.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignCondition.java new file mode 100644 index 00000000000..deec238e5c6 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignCondition.java @@ -0,0 +1,21 @@ +package org.egov.processor.web.models.campaignManager; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; + +public class CampaignCondition { + + + @JsonProperty("value") + @Valid + private Object value; // Change Object to the appropriate type + + @JsonProperty("operator") + @Valid + private Object operator; // Change Object to the appropriate type + + @JsonProperty("attribute") + @Valid + private String attribute; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignDetails.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignDetails.java new file mode 100644 index 00000000000..021c80db5a4 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignDetails.java @@ -0,0 +1,32 @@ +package org.egov.processor.web.models.campaignManager; + +import java.util.List; + +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CampaignDetails { + + @JsonProperty("tenantId") + @NotNull + @Size(min = 2, max = 64) + private String tenantId = null; + + @JsonProperty("ids") + @Valid + private List ids = null; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignRequest.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignRequest.java new file mode 100644 index 00000000000..182533fbcab --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignRequest.java @@ -0,0 +1,27 @@ +package org.egov.processor.web.models.campaignManager; + +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CampaignRequest { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("CampaignDetails") + @Valid + private Campaign campaignDetails = null; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResources.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResources.java new file mode 100644 index 00000000000..b330f7bb92b --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResources.java @@ -0,0 +1,41 @@ +package org.egov.processor.web.models.campaignManager; + +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CampaignResources { + @JsonProperty("filestoreId") + @NotNull + @Size(min = 1, max = 128) + private String filestoreId = null; + + @JsonProperty("type") + @NotNull + @Size(min = 1, max = 128) + private String type = null; + + @JsonProperty("filename") + @NotNull + @Size(min = 1, max = 128) + private String filename = null; + + @JsonProperty("createResourceId") + @Valid + private String createResourceId=null; + + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResponse.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResponse.java new file mode 100644 index 00000000000..6617aeb592d --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignResponse.java @@ -0,0 +1,31 @@ +package org.egov.processor.web.models.campaignManager; + +import java.util.List; + +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CampaignResponse { + + @JsonProperty("ResponseInfo") + @Valid + private ResponseInfo responseInfo = null; + + @JsonProperty("CampaignDetails") + @Valid + private List campaign = null; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignSearchRequest.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignSearchRequest.java new file mode 100644 index 00000000000..2bfd78dab88 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CampaignSearchRequest.java @@ -0,0 +1,28 @@ +package org.egov.processor.web.models.campaignManager; + +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class CampaignSearchRequest { + @JsonProperty("RequestInfo") + @Valid + private RequestInfo requestInfo = null; + + @JsonProperty("CampaignDetails") + @Valid + private CampaignDetails campaignDetails = null; + +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleConfigureDate.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleConfigureDate.java new file mode 100644 index 00000000000..9afd1a3c845 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleConfigureDate.java @@ -0,0 +1,29 @@ +package org.egov.processor.web.models.campaignManager; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; + +/** + * The cycle duration in days. + * This specifies the duration of the cycle for deliveries. + */ +public class CycleConfigureDate { + + /** + * The cycle duration in days. + * This specifies the duration of the cycle for deliveries. + */ + @JsonProperty("cycle") + @Valid + private int cycle; + + + /** + * The number of deliveries within the cycle. + * This indicates how many deliveries occur during each cycle period. + */ + @JsonProperty("deliveries") + @Valid + private int deliveries; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleData.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleData.java new file mode 100644 index 00000000000..ce7ae8ce080 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/CycleData.java @@ -0,0 +1,18 @@ +package org.egov.processor.web.models.campaignManager; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; + +public class CycleData { + + @JsonProperty("cycleData") + @Valid + private List cycleData; // Change Object to the appropriate type + + @JsonProperty("cycleConfigureDate") + @Valid + private CycleConfigureDate cycleConfigureDate; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/DeliveryRule.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/DeliveryRule.java new file mode 100644 index 00000000000..44b8a3aaf0c --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/DeliveryRule.java @@ -0,0 +1,38 @@ +package org.egov.processor.web.models.campaignManager; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; + +public class DeliveryRule { + + @JsonProperty("products") + @Valid + private List products; // Change Object to the appropriate type + + @JsonProperty("conditions") + @Valid + private List conditions; + + @JsonProperty("cycleNumber") + @Valid + private int cycleNumber; + + @JsonProperty("deliveryNumber") + @Valid + private int deliveryNumber; + + @JsonProperty("deliveryRuleNumber") + @Valid + private int deliveryRuleNumber; + + @JsonProperty("endDate") + @Valid + private long endDate; + + @JsonProperty("startDate") + @Valid + private long startDate; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Product.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Product.java new file mode 100644 index 00000000000..204ab279c2a --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/campaignManager/Product.java @@ -0,0 +1,31 @@ +package org.egov.processor.web.models.campaignManager; + +import org.springframework.validation.annotation.Validated; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import jakarta.validation.Valid; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Product { + + @JsonProperty("name") + @Valid + private String name; + + @JsonProperty("count") + @Valid + private int count; + + @JsonProperty("value") + @Valid + private String value; +} diff --git a/health-services/resource-estimation-service/src/main/resources/application.properties b/health-services/resource-estimation-service/src/main/resources/application.properties new file mode 100644 index 00000000000..6c45aefda80 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/resources/application.properties @@ -0,0 +1,80 @@ +server.contextPath=/resource-estimation-service +server.servlet.context-path=/resource-estimation-service +server.port=8083 +app.timezone=UTC + +#MANAGEMENT ENDPOINT CONFIGURATION +management.endpoints.web.base-path=/ + + +#DATABASE CONFIGURATION +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/plandb +spring.datasource.username=postgres +spring.datasource.password=postgres + +#FLYWAY CONFIGURATION +spring.flyway.url=jdbc:postgresql://localhost:5432/plandb +spring.flyway.user=postgres +spring.flyway.password=postgres +spring.flyway.table=public +spring.flyway.baseline-on-migrate=true +spring.flyway.outOfOrder=true +spring.flyway.locations=classpath:/db/migration/main +spring.flyway.enabled=false + +# 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=plan-service +spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer +spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer +spring.kafka.listener.missing-topics-fatal=false +spring.kafka.consumer.properties.spring.json.use.type.headers=false + +# 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 + +#mdms urls +egov.mdms.host=https://unified-dev.digit.org +egov.mdms.search.endpoint=/egov-mdms-service/v1/_search + +#plan config +egov.plan.config.host=https://unified-dev.digit.org +#egov.plan.config.host=http://localhost:8080 +egov.plan.config.endpoint=/plan-service/config/_search + +#file store +#egov.filestore.host=https://unified-dev.digit.org +egov.filestore.service.host=http://localhost:8084 + +egov.filestore.endpoint=/filestore/v1/files/id?tenantId={tenantId}&fileStoreId={fileStoreId} +egov.filestore.upload.endpoint=/filestore/v1/files + +plan.config.consumer.kafka.save.topic=plan-config-create-topic +plan.config.consumer.kafka.update.topic=plan-config-update-topic + +#Plan Create +egov.plan.create.endpoint=/plan-service/plan/_create + +#Campaign Manager +egov.project.factory.search.endpoint=/project-factory/v1/project-type/search +egov.project.factory.update.endpoint=/project-factory/v1/project-type/update +egov.project.factory.host=https://unified-dev.digit.org +#egov.project.factory.host=http://localhost:8090 +resource.microplan.create.topic=resource-microplan-create-topic +resource.update.plan.config.consumer.topic=resource-plan-config-update-topic +integrate.with.admin.console=true + +egov.boundary.service.host=https://unified-dev.digit.org +#egov.boundary.service.host=http://localhost:8091 +egov.boundary.relationship.search.endpoint=/boundary-service/boundary-relationships/_search?includeChildren=true&tenantId={tenantId}&hierarchyType={hierarchyType} \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/resources/db/Dockerfile b/health-services/resource-estimation-service/src/main/resources/db/Dockerfile new file mode 100644 index 00000000000..60fc07ce69f --- /dev/null +++ b/health-services/resource-estimation-service/src/main/resources/db/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"] \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/resources/db/migrate.sh b/health-services/resource-estimation-service/src/main/resources/db/migrate.sh new file mode 100644 index 00000000000..43960b25cdb --- /dev/null +++ b/health-services/resource-estimation-service/src/main/resources/db/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 From 9374c37904ef6ba4720e4e1de2b4ea3d9bd45fa2 Mon Sep 17 00:00:00 2001 From: Nilesh Shinolikar <163095321+devdatta-egov@users.noreply.github.com> Date: Thu, 27 Jun 2024 12:31:10 +0530 Subject: [PATCH 266/283] commit changelog,localsetup,readme (#797) * commit changelog,localsetup,readme * Code review comment * Order by caluse in search * checking empty in differnt way --- health-services/plan-service/CHANGELOG.md | 10 +++ health-services/plan-service/LOCALSETUP.md | 40 ++++++++++++ health-services/plan-service/README.md | 65 ++++++++++++------- .../querybuilder/PlanConfigQueryBuilder.java | 2 +- .../java/digit/service/PlanValidator.java | 2 +- 5 files changed, 92 insertions(+), 27 deletions(-) create mode 100644 health-services/plan-service/CHANGELOG.md create mode 100644 health-services/plan-service/LOCALSETUP.md diff --git a/health-services/plan-service/CHANGELOG.md b/health-services/plan-service/CHANGELOG.md new file mode 100644 index 00000000000..650d79eae57 --- /dev/null +++ b/health-services/plan-service/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog +All notable changes to this module will be documented in this file. + +## 1.0.0 - 2024-06-24 +#### Plan Service + 1. Plan Service manages: validation of plans, plan search, plan create, plan update. + 2. Validation of plan: Plan service validates plan request before it takes action on it like update or create. + 3. Plan Create: Plan service creates a plan after successful validation is done. It sends create request on topic to create plan. + 4. Plan Update : Plan service creates a plan after successful validation is done. It sends update request on topic to resource estimation service to further process. + 5. Plan Search: This enables to search plan based on provided search string. \ No newline at end of file diff --git a/health-services/plan-service/LOCALSETUP.md b/health-services/plan-service/LOCALSETUP.md new file mode 100644 index 00000000000..b1a80932b83 --- /dev/null +++ b/health-services/plan-service/LOCALSETUP.md @@ -0,0 +1,40 @@ +# Local Setup + +To set up the Plan Service in your local system, clone the [Health Campaign Services repository](https://github.com/egovernments/health-campaign-services.git). + +## Dependencies + +- [x] Postgres DB +- [ ] Redis +- [ ] Elasticsearch +- [x] Kafka + - [x] Consumer + - [x] Producer + + +## Running Locally + +### Local setup +1. To set up the Plan Service in your local system, clone the [Health Campaign Services repository](https://github.com/egovernments/health-campaign-services.git). +2. Install GIT. + [For Windows](https://git-scm.com/download/win). + [For Linux](https://www.digitalocean.com/community/tutorials/how-to-install-git-on-ubuntu-18-04-quickstart). +2. Install JDK version 17 or above. + [For windows](https://www.oracle.com/java/technologies/javase/jdk17-archive-downloads.html). + [For Linux](https://javahelps.com/install-oracle-jdk-17-on-linux). +3. Install maven locally and configure environment variables. +4. Install Kafka (version 3.2.0 which is the latest version) - To install and run Kafka locally, follow the following links - + [Kafka for windows](https://dzone.com/articles/running-apache-kafka-on-windows-os) or [Kafka for Linux](https://tecadmin.net/install-apache-kafka-ubuntu/) +5. Install Postman - To install Postman, follow the following links - + [Postman for windows](https://www.postman.com/downloads/) +6. Install Kubectl - Kubectl is the tool that we use to interact with services deployed on our sandbox environment - + [kubectl for windows](https://core.digit.org/guides/operations-guide/working-with-kubernetes/installation-of-kubectl) + [kubectl for Linux](https://kubernetes.io/docs/tasks/tools/install-kubectl-linux/) +7. Install aws-iam-authenticator - [if the DIGIT development environment is in AWS](https://docs.aws.amazon.com/eks/latest/userguide/install-aws-iam-authenticator.html) +8. Install PostgreSQL v14 locally. +9. Also update DB config values as per your local system config. +10. Update the host settings for all dependency services, either on any unified environment or by port-forwarding. +11. Run spring boot main class + +> Note: After running the above, if a Kafka error occurs, ensure that Kafka and Zookeeper are running in the background. If a connection error with another microservice occurs, ensure that the URL mentioned in the external mapping of the data config is correct, or you can port-forward that particular service. +\ No newline at end of file \ No newline at end of file diff --git a/health-services/plan-service/README.md b/health-services/plan-service/README.md index 7bdb464adb1..0b940dd90f7 100644 --- a/health-services/plan-service/README.md +++ b/health-services/plan-service/README.md @@ -1,43 +1,58 @@ -# Plan Service +# Plan Service Documentation -Plan service is a Health Microplanning Service that facilitates creation of micro plan configurations and micro plans. This functionality is exposed via REST API. +## Overview -### DB UML Diagram +The PlanService is a tool designed for managing plan configurations and microplans. It supports various functionalities such as creating, updating, validating, and processing plan configurations, microplans, and related elements. This service can operate independently for micro planning or integrate with DIGIT HCM for campaign execution and monitoring. -DB UML Diagram +## Key Features -### Service Dependencies -- MDMS Service +- **Data Upload for Microplanning**: Upload essential data in formats including .xlsx (Excel), Shapefiles, and GeoJSON. +- **Assumptions Configuration**: Configure assumptions crucial for estimation processes. +- **Formula Configuration**: Set up formulae to calculate estimated resources (e.g., human resources, commodities, budgets). +- **Visualization**: Visualize microplans on a map layer using GIS technologies. +- **Output Generation**: Generate, save, and print microplans. -### Swagger API Contract -[Link](https://editor.swagger.io/?url=https://raw.githubusercontent.com/egovernments/DIGIT-Specs/grouped-service-contracts/Domain%20Services/Plan%20Service/plan-1.0.0.yaml) to the swagger API contract yaml and editor link +## Service Dependencies -### Service Details +- **Mdms-service**: Dependency for managing Master Data Management System. -#### API Details -BasePath `/plan-service` +## API Documentation -Plan config APIs - contains create, update and search end point +- **Swagger Link**: [Plan Service Swagger](https://editor.swagger.io/?url=https://raw.githubusercontent.com/egovernments/DIGIT-Specs/grouped-service-contracts/Domain%20Services/Plan%20Service/plan-1.0.0.yaml) -* POST `/plan-service/config/_create` - Create Project, This API is used to create/add a new Project. +## Database and Persistence -* POST `/plan-service/config/_update` - Update Project, This API is used to update the details of an existing Project. +- **DB Diagrams**: Detailed diagrams for Microplan and Plan Configuration are available. -* POST `/plan-service/config/_search` - Search Project, This API is used to search details of an existing Project. +## Configuration and Deployment +- **Persister Config**: Configuration for persistence can be found in [plan-service-persister.yml](https://github.com/egovernments/configs/blob/UNIFIED-QA/health/egov-persister/plan-service-persister.yml). +- **Helm Chart**: Deployment details available in the [Helm chart](https://github.com/egovernments/DIGIT-DevOps/tree/unified-env/deploy-as-code/helm/charts/health-services/plan-service). -* POST `/plan-service/_create` - Create Project Beneficiary, This API is used to create/add a new beneficiary for Project. +## Role and Access Control -* POST `/plan-service/_update` - Update Project Beneficiary, This API is used to update beneficiary registration for Project. +- **Access Control Role**: Configure the role `MICROPLAN_ADMIN` in the ‘ACCESSCONTROL-ROLES’ module. +- **Role-Action Mapping**: Map actions to role codes in the ‘ACCESSCONTROL-ROLEACTIONS’ module as per the provided mappings. -* POST `/plan-service/_search` - Search Project Beneficiary, This API is used to search beneficiary registration for Project. +### Role-Action Mappings (Dev Environment) -### Kafka Consumers -NA +- `/plan-service/plan/_create`: `MICROPLAN_ADMIN` +- `/plan-service/plan/_search`: `MICROPLAN_ADMIN` +- `/plan-service/plan/_update`: `MICROPLAN_ADMIN` +- `/plan-service/config/_create`: `MICROPLAN_ADMIN` +- `/plan-service/config/_search`: `MICROPLAN_ADMIN` +- `/plan-service/config/_update`: `MICROPLAN_ADMIN` -### Kafka Producers -- plan-config-create-topic -- plan-config-update-topic +## Environment Variables -- save-plan -- update-plan +- Configure environment variables such as `db-host`, `db-name`, `db-url`, `domain`, and other DIGIT core platform services configurations before deployment. Example configurations can be found in the [unified-qa.yaml](https://github.com/egovernments/DIGIT-DevOps/blob/unified-env/deploy-as-code/helm/environments/unified-qa.yaml). + +## MDMS Configuration + +- Configure MDMS data for Plan Service including UOM config, Metric config, Assumptions config, Input rules, Output rules, Campaign Based Schema, Microplan status, Map layers, Map filters, Preview Aggregates, and UI configs. Reference data can be found [here](https://github.com/egovernments/egov-mdms-data/tree/UNIFIED-QA/data/mz/health/hcm-microplanning). + +## Reference Documents + +- **MDMS Technical Document**: [Mdms service](https://core.digit.org/platform/core-services/mdms-master-data-management-service) +- **Persister Technical Document**: [Persister service](https://core.digit.org/platform/core-services/persister-service) +- **API Contract**: [API Contract](https://github.com/egovernments/SANITATION/blob/develop/API-CONTRACTS/pqm/PQM_API_ANOMALY_Contract.yaml) diff --git a/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanConfigQueryBuilder.java b/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanConfigQueryBuilder.java index 74c3e04ff62..6dc4449b55f 100644 --- a/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanConfigQueryBuilder.java +++ b/health-services/plan-service/src/main/java/digit/repository/querybuilder/PlanConfigQueryBuilder.java @@ -51,7 +51,7 @@ private String buildPlanConfigQuery(List ids, List preparedStmtL addActiveWhereClause(builder, preparedStmtList); - return builder.toString(); + return QueryUtil.addOrderByClause(builder.toString(), PLAN_CONFIG_SEARCH_QUERY_ORDER_BY_CLAUSE); } /** diff --git a/health-services/plan-service/src/main/java/digit/service/PlanValidator.java b/health-services/plan-service/src/main/java/digit/service/PlanValidator.java index c04e18f708b..b52c3450c6d 100644 --- a/health-services/plan-service/src/main/java/digit/service/PlanValidator.java +++ b/health-services/plan-service/src/main/java/digit/service/PlanValidator.java @@ -172,7 +172,7 @@ private void validateActivities(PlanRequest request) { */ private void validatePlanConfigurationExistence(PlanRequest request) { // If plan id provided is invalid, throw an exception - if(!request.getPlan().getPlanConfigurationId().isEmpty() && CollectionUtils.isEmpty(planConfigurationRepository.search(PlanConfigurationSearchCriteria.builder() + if(!ObjectUtils.isEmpty(request.getPlan().getPlanConfigurationId()) && CollectionUtils.isEmpty(planConfigurationRepository.search(PlanConfigurationSearchCriteria.builder() .id(request.getPlan().getPlanConfigurationId()) .tenantId(request.getPlan().getTenantId()) .build()))) { From 90dd4d2f3fd6695fb156da716862a600c6ea2c55 Mon Sep 17 00:00:00 2001 From: Nilesh Shinolikar <163095321+devdatta-egov@users.noreply.github.com> Date: Thu, 27 Jun 2024 18:18:52 +0530 Subject: [PATCH 267/283] Resource service read me from master (#801) * Read me changes from master branch * change properties file * Code review comment --- .../egov/processor/config/Configuration.java | 6 ++ .../processor/config/ServiceConstants.java | 4 + .../egov/processor/service/ExcelParser.java | 49 +++++++++-- .../org/egov/processor/util/LocaleUtil.java | 80 +++++++++++++++++ .../org/egov/processor/util/MdmsUtil.java | 88 ++++++++++++++++++- .../org/egov/processor/web/models/Locale.java | 32 +++++++ .../processor/web/models/LocaleResponse.java | 24 +++++ .../src/main/resources/application.properties | 5 +- 8 files changed, 278 insertions(+), 10 deletions(-) create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/util/LocaleUtil.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Locale.java create mode 100644 health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/LocaleResponse.java diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/Configuration.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/Configuration.java index 089320e0b06..12ce0667abd 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/Configuration.java +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/Configuration.java @@ -70,5 +70,11 @@ public class Configuration { @Value("${egov.boundary.relationship.search.endpoint}") private String egovBoundaryRelationshipSearchEndpoint; + + @Value("${egov.locale.service.host}") + private String egovLocaleServiceHost; + + @Value("${egov.locale.search.endpoint}") + private String egovLocaleSearchEndpoint; } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java index 23ffe8a02ba..1b9ae7efc8b 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java @@ -64,5 +64,9 @@ public class ServiceConstants { public static final String SCIENTIFIC_NOTATION_INDICATOR = "E"; public static final String ATTRIBUTE_IS_REQUIRED ="isRequired"; public static final int DEFAULT_SCALE=2; + + public static final String MDMS_LOCALE_SEARCH_MODULE ="rainmaker-microplanning,rainmaker-boundary-undefined,rainmaker-hcm-admin-schemas"; + public static final String ERROR_WHILE_SEARCHING_LOCALE = "Exception occurred while searching locale. "; + public static final String MDMS_MASTER_COMMON_CONSTANTS = "CommonConstants"; } diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java index c718136755a..8cadbadcf3a 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java @@ -25,9 +25,12 @@ import org.egov.processor.util.CalculationUtil; import org.egov.processor.util.CampaignIntegrationUtil; import org.egov.processor.util.FilestoreUtil; +import org.egov.processor.util.LocaleUtil; import org.egov.processor.util.MdmsUtil; import org.egov.processor.util.ParsingUtil; import org.egov.processor.util.PlanUtil; +import org.egov.processor.web.models.Locale; +import org.egov.processor.web.models.LocaleResponse; import org.egov.processor.web.models.Operation; import org.egov.processor.web.models.PlanConfiguration; import org.egov.processor.web.models.PlanConfiguration.StatusEnum; @@ -71,10 +74,12 @@ public class ExcelParser implements FileParser { private MdmsUtil mdmsUtil; private BoundaryUtil boundaryUtil; + + private LocaleUtil localeUtil; public ExcelParser(ObjectMapper objectMapper, ParsingUtil parsingUtil, FilestoreUtil filestoreUtil, CalculationUtil calculationUtil, PlanUtil planUtil, CampaignIntegrationUtil campaignIntegrationUtil, - Configuration config, MdmsUtil mdmsUtil, BoundaryUtil boundaryUtil) { + Configuration config, MdmsUtil mdmsUtil, BoundaryUtil boundaryUtil,LocaleUtil localeUtil) { this.objectMapper = objectMapper; this.parsingUtil = parsingUtil; this.filestoreUtil = filestoreUtil; @@ -84,6 +89,7 @@ public ExcelParser(ObjectMapper objectMapper, ParsingUtil parsingUtil, Filestore this.config = config; this.mdmsUtil = mdmsUtil; this.boundaryUtil = boundaryUtil; + this.localeUtil = localeUtil; } /** @@ -200,15 +206,17 @@ private String uploadFileAndIntegrateCampaign(PlanConfigurationRequest planConfi * @param dataFormatter The data formatter for formatting cell values. */ private void processSheets(PlanConfigurationRequest planConfigurationRequest, String fileStoreId, - Object campaignResponse, PlanConfiguration planConfig, Workbook workbook, + Object campaignResponse, PlanConfiguration planConfig, Workbook excelWorkbook, List campaignBoundaryList, List campaignResourcesList, DataFormatter dataFormatter) { - workbook.forEach(sheet -> { - Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(sheet); - List columnNamesList = mapOfColumnNameAndIndex.keySet().stream().toList(); - parsingUtil.validateColumnNames(columnNamesList, planConfig, fileStoreId); - processRows(planConfigurationRequest, sheet, dataFormatter, fileStoreId, campaignResponse, - campaignBoundaryList, campaignResourcesList); + excelWorkbook.forEach(excelWorkbookSheet -> { + if (isSheetAlloedToProcess(planConfigurationRequest, excelWorkbookSheet.getSheetName())) { + Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(excelWorkbookSheet); + List columnNamesList = mapOfColumnNameAndIndex.keySet().stream().toList(); + parsingUtil.validateColumnNames(columnNamesList, planConfig, fileStoreId); + processRows(planConfigurationRequest, excelWorkbookSheet, dataFormatter, fileStoreId, campaignResponse, + campaignBoundaryList, campaignResourcesList); + } }); } @@ -684,4 +692,29 @@ public List getAllBoundaryPresentforHierarchyType(List } return boundaryList; } + + /** + * Checks if a sheet is allowed to be processed based on MDMS constants and locale-specific configuration. + * + * @param planConfigurationRequest The request containing configuration details including request info and tenant ID. + * @param sheetName The name of the sheet to be processed. + * @return true if the sheet is allowed to be processed, false otherwise. + * @throws JsonMappingException If there's an issue mapping JSON response to Java objects. + * @throws JsonProcessingException If there's an issue processing JSON during conversion. + */ + private boolean isSheetAlloedToProcess(PlanConfigurationRequest planConfigurationRequest, String sheetName) { + Map mdmsDataConstants = mdmsUtil.fetchMdmsDataForCommonConstants( + planConfigurationRequest.getRequestInfo(), + planConfigurationRequest.getPlanConfiguration().getTenantId()); + LocaleResponse localeResponse = localeUtil.searchLocale(planConfigurationRequest); + String value = (String) mdmsDataConstants.get("readMeSheetName"); + for (Locale locale : localeResponse.getMessages()) { + if ((locale.getCode().equalsIgnoreCase(value))) { + if (sheetName.equals(locale.getMessage())) + return false; + } + } + return true; + + } } \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/LocaleUtil.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/LocaleUtil.java new file mode 100644 index 00000000000..1ecb725308f --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/LocaleUtil.java @@ -0,0 +1,80 @@ +package org.egov.processor.util; + +import java.util.List; + +import org.egov.processor.config.Configuration; +import org.egov.processor.config.ServiceConstants; +import org.egov.processor.repository.ServiceRequestRepository; +import org.egov.processor.web.models.LocaleResponse; +import org.egov.processor.web.models.PlanConfigurationRequest; +import org.egov.processor.web.models.boundary.BoundarySearchResponse; +import org.egov.processor.web.models.campaignManager.Boundary; +import org.egov.processor.web.models.campaignManager.CampaignResources; +import org.egov.processor.web.models.campaignManager.CampaignResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.stereotype.Component; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.extern.slf4j.Slf4j; + +/** + * Utility class for handling operations related to locale data retrieval and processing. + * This class encapsulates methods to search for locale information based on plan configuration requests. + * It utilizes a service request repository to interact with external services and ObjectMapper for JSON conversion. + */ +@Component +@Slf4j +public class LocaleUtil { + + private ServiceRequestRepository serviceRequestRepository; + private Configuration config; + private ObjectMapper mapper; + + /** + * Constructs a LocaleUtil instance with necessary dependencies. + * + * @param serviceRequestRepository The repository for making service requests. + * @param config Configuration settings for the application. + * @param mapper ObjectMapper for JSON serialization/deserialization. + */ + public LocaleUtil(ServiceRequestRepository serviceRequestRepository, Configuration config, ObjectMapper mapper) { + + this.serviceRequestRepository = serviceRequestRepository; + this.config = config; + this.mapper = mapper; + } + + /** + * Searches for locale information based on the provided plan configuration request. + * Retrieves locale-specific data using service request repository and converts the response + * into a LocaleResponse object. + * + * @param planConfigurationRequest The request containing configuration details including request info. + * @return LocaleResponse containing locale-specific information. + * @throws CustomException If an error occurs during the locale search process. + */ + public LocaleResponse searchLocale(PlanConfigurationRequest planConfigurationRequest) { + Object response; + String localeToUse = planConfigurationRequest.getRequestInfo().getMsgId().split("\\|")[1]; + String tenantId = planConfigurationRequest.getRequestInfo().getUserInfo().getTenantId(); + LocaleResponse localeResponse = null; + try { + + String url = config.getEgovLocaleSearchEndpoint() + .replace("{module}", ServiceConstants.MDMS_LOCALE_SEARCH_MODULE) + .replace("{locale}", localeToUse) + .replace("{tenantId}", tenantId); + response = serviceRequestRepository.fetchResult(new StringBuilder(config.getEgovLocaleServiceHost() + url), + planConfigurationRequest.getRequestInfo()); + localeResponse = mapper.convertValue(response, LocaleResponse.class); + log.info("Locale Search successful."); + return localeResponse; + } catch (Exception e) { + log.error(ServiceConstants.ERROR_WHILE_SEARCHING_LOCALE + localeToUse + " and tenantId" + tenantId, e); + throw new CustomException( + ServiceConstants.ERROR_WHILE_SEARCHING_LOCALE + localeToUse + " and tenantId" + tenantId, + e.toString()); + } + } +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/MdmsUtil.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/MdmsUtil.java index c46529c06e0..229dbf57f45 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/MdmsUtil.java +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/util/MdmsUtil.java @@ -74,7 +74,7 @@ public Object fetchMdmsData(RequestInfo requestInfo, String tenantId) { if (result == null || ObjectUtils.isEmpty(result)) { log.error(NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_MESSAGE + " - " + tenantId); throw new CustomException(NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_CODE, - NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_MESSAGE); + "no data found for the given tenantid "+tenantId + " for master name "+ServiceConstants.MDMS_MASTER_SCHEMAS); } return result; } @@ -141,5 +141,91 @@ public Map filterMasterData(String masterDataJson, File.InputFil return properties; } + + /** + * Parses the provided JSON string containing master data, extracts common constants, + * and returns them as a map of name-value pairs. + * + * @param masterDataJson JSON string representing master data + * @return Map containing common constants where keys are constant names and values are constant values + */ + public Map filterMasterDataForLocale(String masterDataJson) { + Map properties = new HashMap<>(); + Map masterData = JsonUtils.parseJson(masterDataJson, Map.class); + Map planModule = (Map) masterData.get(ServiceConstants.MDMS_PLAN_MODULE_NAME); + List> commonConstantsMap = (List>) planModule + .get(ServiceConstants.MDMS_MASTER_COMMON_CONSTANTS); + log.info("masterDataJson ==>" + commonConstantsMap); + for (Map commonConstantMap : commonConstantsMap) { + properties.put((String) commonConstantMap.get("name"), (String) commonConstantMap.get("value")); + + } + + return properties; + } + + /** + * Fetches MDMS (Master Data Management System) data for common constants based on the provided request info and tenant ID. + * Constructs an MDMS request, sends a POST request to the configured MDMS endpoint, and processes the response. + * + * @param requestInfo The request information containing context like user details and timestamp. + * @param tenantId The ID of the tenant for which MDMS data is requested. + * @return A filtered map of MDMS data for common constants, specific to the locale. + * @throws CustomException If no MDMS data is found for the given tenant ID. + * @throws JsonMappingException If there's an issue mapping JSON response to Java objects. + * @throws JsonProcessingException If there's an issue processing JSON during conversion. + */ + public Map fetchMdmsDataForCommonConstants(RequestInfo requestInfo, String tenantId) { + StringBuilder uri = new StringBuilder(); + uri.append(configs.getMdmsHost()).append(configs.getMdmsEndPoint()); + MdmsCriteriaReq mdmsCriteriaReq = getMdmsRequestForCommonConstants(requestInfo, tenantId); + Object response = new HashMap<>(); + MdmsResponse mdmsResponse = new MdmsResponse(); + try { + response = restTemplate.postForObject(uri.toString(), mdmsCriteriaReq, Map.class); + mdmsResponse = mapper.convertValue(response, MdmsResponse.class); + } catch (Exception e) { + log.error(ERROR_WHILE_FETCHING_FROM_MDMS, e); + } + + Object result = mdmsResponse.getMdmsRes(); + if (result == null || ObjectUtils.isEmpty(result)) { + log.error(NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_MESSAGE + " - " + tenantId); + throw new CustomException(NO_MDMS_DATA_FOUND_FOR_GIVEN_TENANT_CODE, + "no data found for the given tenantid "+tenantId + " for master name "+ServiceConstants.MDMS_MASTER_COMMON_CONSTANTS); + } + return filterMasterDataForLocale(result.toString()); + } + + /** + * Constructs an MDMS (Master Data Management System) request object for fetching common constants. + * + * @param requestInfo The request information containing context like user details and timestamp. + * @param tenantId The ID of the tenant for which MDMS data is requested. + * @return MdmsCriteriaReq object encapsulating the MDMS criteria for fetching common constants. + */ + public MdmsCriteriaReq getMdmsRequestForCommonConstants(RequestInfo requestInfo, String tenantId) { + + ModuleDetail moduleDetail = getPlanModulesCommonConstants(); + List moduleDetails = new LinkedList<>(); + moduleDetails.add(moduleDetail); + MdmsCriteria mdmsCriteria = MdmsCriteria.builder().moduleDetails(moduleDetails).tenantId(tenantId).build(); + return MdmsCriteriaReq.builder().mdmsCriteria(mdmsCriteria).requestInfo(requestInfo).build(); + } + + + /** + * Constructs a ModuleDetail object for fetching common constants from MDMS. + * + * @return ModuleDetail object representing the module configuration for common constants. + */ + private ModuleDetail getPlanModulesCommonConstants() { + List assumptionMasterDetails = new ArrayList<>(); + MasterDetail schemaDetails = MasterDetail.builder().name(ServiceConstants.MDMS_MASTER_COMMON_CONSTANTS).build(); + assumptionMasterDetails.add(schemaDetails); + + return ModuleDetail.builder().masterDetails(assumptionMasterDetails) + .moduleName(ServiceConstants.MDMS_PLAN_MODULE_NAME).build(); + } } \ No newline at end of file diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Locale.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Locale.java new file mode 100644 index 00000000000..9de6904d989 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/Locale.java @@ -0,0 +1,32 @@ +package org.egov.processor.web.models; + +import org.springframework.validation.annotation.Validated; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Represents a locale-specific message. + * This class is annotated for validation and includes Lombok annotations for generating getters, setters, constructors, and builder. + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Locale { + + // Field representing the code of the locale message + private String code; + + // Field representing the actual message in the locale + private String message; + + // Field representing the module to which the message belongs + private String module; + + // Field representing the locale identifier (e.g., "en_US") + private String locale; +} diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/LocaleResponse.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/LocaleResponse.java new file mode 100644 index 00000000000..18a9e3f3a25 --- /dev/null +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/web/models/LocaleResponse.java @@ -0,0 +1,24 @@ +package org.egov.processor.web.models; + +import java.util.List; + +import org.springframework.validation.annotation.Validated; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Represents a response containing locale-specific messages. + * This class is annotated for validation and includes Lombok annotations for generating getters, setters, constructors, and builder. + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class LocaleResponse { + // Field representing a list of Locale messages + private List messages;; +} diff --git a/health-services/resource-estimation-service/src/main/resources/application.properties b/health-services/resource-estimation-service/src/main/resources/application.properties index 6c45aefda80..7cdfe225f6d 100644 --- a/health-services/resource-estimation-service/src/main/resources/application.properties +++ b/health-services/resource-estimation-service/src/main/resources/application.properties @@ -77,4 +77,7 @@ integrate.with.admin.console=true egov.boundary.service.host=https://unified-dev.digit.org #egov.boundary.service.host=http://localhost:8091 -egov.boundary.relationship.search.endpoint=/boundary-service/boundary-relationships/_search?includeChildren=true&tenantId={tenantId}&hierarchyType={hierarchyType} \ No newline at end of file +egov.boundary.relationship.search.endpoint=/boundary-service/boundary-relationships/_search?includeChildren=true&tenantId={tenantId}&hierarchyType={hierarchyType} + +egov.locale.service.host=https://unified-qa.digit.org +egov.locale.search.endpoint=/localization/messages/v1/_search?module={module}&locale={locale}&tenantId={tenantId} \ No newline at end of file From 8b6bfaabaef8ff65afee5642d525829639d56b94 Mon Sep 17 00:00:00 2001 From: nitish-egov <137176807+nitish-egov@users.noreply.github.com> Date: Tue, 2 Jul 2024 16:14:54 +0530 Subject: [PATCH 268/283] fixed target upload flow in french locale as it was causing error with underscores being present in boundary codes (#809) * fixed target upload flow in french locale * added comments for changes in each line of codes --- .../project-factory/src/server/api/campaignApis.ts | 3 ++- .../project-factory/src/server/utils/genericUtils.ts | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/health-services/project-factory/src/server/api/campaignApis.ts b/health-services/project-factory/src/server/api/campaignApis.ts index e9d2cd8f158..f0a5a231965 100644 --- a/health-services/project-factory/src/server/api/campaignApis.ts +++ b/health-services/project-factory/src/server/api/campaignApis.ts @@ -519,7 +519,8 @@ async function processValidate(request: any, localizationMap?: { [key: string]: const dataFromSheet = await getDataFromSheet(request, request?.body?.ResourceDetails?.fileStoreId, request?.body?.ResourceDetails?.tenantId, createAndSearchConfig, null, localizationMap) if (type == 'boundaryWithTarget') { logger.info("target sheet format validation started"); - immediateValidationForTargetSheet(dataFromSheet, localizationMap); + // added await to ensure validations complete before proceeding, preventing premature errors. + await immediateValidationForTargetSheet(dataFromSheet, localizationMap); logger.info("target sheet format validation completed and starts with data validation"); validateTargetSheetData(dataFromSheet, request, createAndSearchConfig?.boundaryValidation, localizationMap); } diff --git a/health-services/project-factory/src/server/utils/genericUtils.ts b/health-services/project-factory/src/server/utils/genericUtils.ts index 480d5fc8134..fa3c194b8ca 100644 --- a/health-services/project-factory/src/server/utils/genericUtils.ts +++ b/health-services/project-factory/src/server/utils/genericUtils.ts @@ -966,10 +966,10 @@ function getDifferentDistrictTabs(boundaryData: any, differentTabsBasedOnLevel: const rowData = Object.values(data); const districtValue = data[differentTabsBasedOnLevel]; const districtIndex = districtValue !== '' ? rowData.indexOf(districtValue) : -1; - + // replaced '_' with '#' to avoid errors caused by underscores in boundary codes. if (districtIndex != -1) { const districtLevelRow = rowData.slice(0, districtIndex + 1); - const districtKey = districtLevelRow.join('_'); + const districtKey = districtLevelRow.join('#'); if (!uniqueDistrictsForMainSheet.includes(districtKey)) { uniqueDistrictsForMainSheet.push(districtKey); @@ -977,7 +977,7 @@ function getDifferentDistrictTabs(boundaryData: any, differentTabsBasedOnLevel: } } for (const uniqueData of uniqueDistrictsForMainSheet) { - differentDistrictTabs.push(uniqueData.slice(uniqueData.lastIndexOf('_') + 1)); + differentDistrictTabs.push(uniqueData.slice(uniqueData.lastIndexOf('#') + 1)); } return differentDistrictTabs; } From 0d98691359dd159659d18b8272d8be04749a186b Mon Sep 17 00:00:00 2001 From: Priyanka-eGov <74049060+Priyanka-eGov@users.noreply.github.com> Date: Wed, 3 Jul 2024 10:16:48 +0530 Subject: [PATCH 269/283] Resource estimation service - regex fix (#803) * Resource estimation service - regex fix * Resource estimation service - empty row check --- .../processor/config/ServiceConstants.java | 2 +- .../egov/processor/service/ExcelParser.java | 77 +++++++++++-------- 2 files changed, 47 insertions(+), 32 deletions(-) diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java index 1b9ae7efc8b..797c9a894c3 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/config/ServiceConstants.java @@ -53,7 +53,7 @@ public class ServiceConstants { public static final String ERROR_WHILE_UPDATING_PLAN_CONFIG = "Exception occurred while updating plan configuration."; - public static final String VALIDATE_STRING_REGX = "^[a-zA-Z0-9 .,()_\\-`~!@#\\$%^&*\\+=\\\\|{}\\[\\]:;\"'<>,.?/]*$"; + public static final String VALIDATE_STRING_REGX = "^(?!\\d+$).+$"; public static final String VALIDATE_NUMBER_REGX = "^[-+]?[0-9]*\\.?[0-9]+([eE][-+]?[0-9]+)?$"; public static final String VALIDATE_BOOLEAN_REGX = "^(?i)(true|false)$"; diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java index 8cadbadcf3a..ee005cd81c8 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/service/ExcelParser.java @@ -12,12 +12,7 @@ import java.util.stream.Collectors; import org.apache.poi.openxml4j.exceptions.InvalidFormatException; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.DataFormatter; -import org.apache.poi.ss.usermodel.DateUtil; -import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.egov.processor.config.Configuration; import org.egov.processor.config.ServiceConstants; @@ -200,7 +195,7 @@ private String uploadFileAndIntegrateCampaign(PlanConfigurationRequest planConfi * @param fileStoreId The ID of the uploaded file in the file store. * @param campaignResponse The response object containing campaign details. * @param planConfig The configuration details specific to the plan. - * @param workbook The workbook containing sheets to be processed. + * @param excelWorkbook The workbook containing sheets to be processed. * @param campaignBoundaryList List of boundary objects related to the campaign. * @param campaignResourcesList List of campaign resources to be integrated. * @param dataFormatter The data formatter for formatting cell values. @@ -209,13 +204,19 @@ private void processSheets(PlanConfigurationRequest planConfigurationRequest, St Object campaignResponse, PlanConfiguration planConfig, Workbook excelWorkbook, List campaignBoundaryList, List campaignResourcesList, DataFormatter dataFormatter) { + LocaleResponse localeResponse = localeUtil.searchLocale(planConfigurationRequest); + CampaignResponse campaign = parseCampaignResponse(campaignResponse); + Map attributeNameVsDataTypeMap = prepareAttributeVsIndexMap(planConfigurationRequest, + fileStoreId, campaign, planConfig); + List boundaryCodeList = getBoundaryCodeList(planConfigurationRequest, campaign, planConfig); + excelWorkbook.forEach(excelWorkbookSheet -> { - if (isSheetAlloedToProcess(planConfigurationRequest, excelWorkbookSheet.getSheetName())) { + if (isSheetAlloedToProcess(planConfigurationRequest, excelWorkbookSheet.getSheetName(),localeResponse)) { Map mapOfColumnNameAndIndex = parsingUtil.getAttributeNameIndexFromExcel(excelWorkbookSheet); List columnNamesList = mapOfColumnNameAndIndex.keySet().stream().toList(); parsingUtil.validateColumnNames(columnNamesList, planConfig, fileStoreId); - processRows(planConfigurationRequest, excelWorkbookSheet, dataFormatter, fileStoreId, campaignResponse, - campaignBoundaryList, campaignResourcesList); + processRows(planConfigurationRequest, excelWorkbookSheet, dataFormatter, fileStoreId, + campaignBoundaryList, attributeNameVsDataTypeMap, boundaryCodeList); } }); } @@ -232,24 +233,16 @@ private void processSheets(PlanConfigurationRequest planConfigurationRequest, St * @param dataFormatter The data formatter for formatting cell * values. * @param fileStoreId The ID of the file in the file store. - * @param campaignResponse The response object to be updated with - * processed data. * @param campaignBoundaryList The list of campaign boundaries to be * updated. - * @param campaignResourcesList The list of campaign resources to be updated. + * @param attributeNameVsDataTypeMap Mapping of attribute names to their data types. + * @param boundaryCodeList List of boundary codes. * @throws IOException If an I/O error occurs. */ - private void processRows(PlanConfigurationRequest planConfigurationRequest, Sheet sheet, - DataFormatter dataFormatter, String fileStoreId, Object campaignResponse, - List campaignBoundaryList, List campaignResourcesList) { - CampaignResponse campaign = parseCampaignResponse(campaignResponse); - PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); - Map attributeNameVsDataTypeMap = prepareAttributeVsIndexMap(planConfigurationRequest, - fileStoreId, campaign, planConfig); - List boundaryCodeList = getBoundaryCodeList(planConfigurationRequest, campaign, planConfig); + private void processRows(PlanConfigurationRequest planConfigurationRequest, Sheet sheet, DataFormatter dataFormatter, String fileStoreId, List campaignBoundaryList, Map attributeNameVsDataTypeMap, List boundaryCodeList) { + PlanConfiguration planConfig = planConfigurationRequest.getPlanConfiguration(); Row firstRow = null; - performRowLevelCalculations(planConfigurationRequest, sheet, dataFormatter, fileStoreId, campaignBoundaryList, - planConfig, attributeNameVsDataTypeMap, boundaryCodeList, firstRow); + performRowLevelCalculations(planConfigurationRequest, sheet, dataFormatter, fileStoreId, campaignBoundaryList, planConfig, attributeNameVsDataTypeMap, boundaryCodeList, firstRow); } /** @@ -323,6 +316,9 @@ private void performRowLevelCalculations(PlanConfigurationRequest planConfigurat PlanConfiguration planConfig, Map attributeNameVsDataTypeMap, List boundaryCodeList, Row firstRow) { for (Row row : sheet) { + if(isRowEmpty(row)) + continue; + if (row.getRowNum() == 0) { firstRow = row; continue; @@ -339,7 +335,7 @@ private void performRowLevelCalculations(PlanConfigurationRequest planConfigurat Integer indexOfBoundaryCode = campaignIntegrationUtil.getIndexOfBoundaryCode(0, campaignIntegrationUtil.sortColumnByIndex(mapOfColumnNameAndIndex), mappedValues); validateRows(indexOfBoundaryCode, row, firstRow, attributeNameVsDataTypeMap, mappedValues, mapOfColumnNameAndIndex, - planConfigurationRequest, boundaryCodeList); + planConfigurationRequest, boundaryCodeList, sheet); JsonNode feature = createFeatureNodeFromRow(row, dataFormatter, mapOfColumnNameAndIndex); performCalculationsOnOperations(sheet, planConfig, row, resultMap, mappedValues, assumptionValueMap, feature); @@ -352,6 +348,26 @@ private void performRowLevelCalculations(PlanConfigurationRequest planConfigurat } } + /** + * Checks if a given row is empty. + * + * A row is considered empty if it is null or if all of its cells are empty or of type BLANK. + * + * @param row the Row to check + * @return true if the row is empty, false otherwise + */ + public static boolean isRowEmpty(Row row) { + if (row == null) { + return true; + } + for (Cell cell : row) { + if (cell != null && cell.getCellType() != CellType.BLANK) { + return false; + } + } + return true; + } + /** * Performs calculations on operations for a specific row in the sheet. * Calculates results based on plan configuration operations, updates result map, and sets cell values. @@ -519,24 +535,24 @@ public void printRow(Sheet sheet, Row row) { */ public void validateRows(Integer indexOfBoundaryCode, Row row, Row columnHeaderRow, Map attributeNameVsDataTypeMap, Map mappedValues, Map mapOfColumnNameAndIndex, - PlanConfigurationRequest planConfigurationRequest, List boundaryCodeList) { + PlanConfigurationRequest planConfigurationRequest, List boundaryCodeList, Sheet sheet) { try { validateTillBoundaryCode(indexOfBoundaryCode, row, columnHeaderRow); validateAttributes(attributeNameVsDataTypeMap, mappedValues, mapOfColumnNameAndIndex, row, columnHeaderRow, indexOfBoundaryCode, boundaryCodeList); } catch (JsonProcessingException e) { - log.info(ServiceConstants.INPUT_IS_NOT_VALID + (row.getRowNum() + 1)); + log.info(ServiceConstants.INPUT_IS_NOT_VALID + (row.getRowNum() + 1) + " at sheet - " + sheet); planConfigurationRequest.getPlanConfiguration().setStatus(StatusEnum.INVALID_DATA); planUtil.update(planConfigurationRequest); throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), - ServiceConstants.INPUT_IS_NOT_VALID + row.getRowNum()); + ServiceConstants.INPUT_IS_NOT_VALID + row.getRowNum() + " at sheet - " + sheet); } catch (CustomException customException) { - log.info(customException.toString()); + log.info(customException.toString()+ "at sheet - " + sheet.getSheetName()); planConfigurationRequest.getPlanConfiguration().setStatus(StatusEnum.INVALID_DATA); planUtil.update(planConfigurationRequest); throw new CustomException(Integer.toString(HttpStatus.INTERNAL_SERVER_ERROR.value()), - customException.getMessage()); + customException.getMessage()+ "at sheet - " + sheet.getSheetName()); } } @@ -702,11 +718,10 @@ public List getAllBoundaryPresentforHierarchyType(List * @throws JsonMappingException If there's an issue mapping JSON response to Java objects. * @throws JsonProcessingException If there's an issue processing JSON during conversion. */ - private boolean isSheetAlloedToProcess(PlanConfigurationRequest planConfigurationRequest, String sheetName) { + private boolean isSheetAlloedToProcess(PlanConfigurationRequest planConfigurationRequest, String sheetName,LocaleResponse localeResponse) { Map mdmsDataConstants = mdmsUtil.fetchMdmsDataForCommonConstants( planConfigurationRequest.getRequestInfo(), planConfigurationRequest.getPlanConfiguration().getTenantId()); - LocaleResponse localeResponse = localeUtil.searchLocale(planConfigurationRequest); String value = (String) mdmsDataConstants.get("readMeSheetName"); for (Locale locale : localeResponse.getMessages()) { if ((locale.getCode().equalsIgnoreCase(value))) { From eda20286b9ff55d83daca3b9c4495292a978f5de Mon Sep 17 00:00:00 2001 From: nitish-egov <137176807+nitish-egov@users.noreply.github.com> Date: Wed, 3 Jul 2024 16:27:54 +0530 Subject: [PATCH 270/283] updated generate different tab logic if there is no different tab then it will show previous filestore id (#811) * updated generate different tab logic * added comments --- .../project-factory/src/server/utils/campaignUtils.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/health-services/project-factory/src/server/utils/campaignUtils.ts b/health-services/project-factory/src/server/utils/campaignUtils.ts index 76f00140eda..f2b4e1f37ca 100644 --- a/health-services/project-factory/src/server/utils/campaignUtils.ts +++ b/health-services/project-factory/src/server/utils/campaignUtils.ts @@ -1775,7 +1775,8 @@ async function getFinalValidHeadersForTargetSheetAsPerCampaignType(request: any, } async function getDifferentTabGeneratedBasedOnConfig(request: any, boundaryDataGeneratedBeforeDifferentTabSeparation: any, localizationMap?: any) { - var boundaryDataGeneratedAfterDifferentTabSeparation: any; + // assigning fileStoreId of a single district tab if criteria for multiple tabs are not met + var boundaryDataGeneratedAfterDifferentTabSeparation: any = boundaryDataGeneratedBeforeDifferentTabSeparation; const boundaryData = await getBoundaryDataAfterGeneration(boundaryDataGeneratedBeforeDifferentTabSeparation, request, localizationMap); const differentTabsBasedOnLevel = getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap); logger.info(`Boundaries are seperated based on hierarchy type ${differentTabsBasedOnLevel}`) From 0a99f06f1409cbea26a0e78584a7d0b08bbc7c2a Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Mon, 8 Jul 2024 23:42:11 +0530 Subject: [PATCH 271/283] Master flyway imageupdate - after impel pull (#808) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter * Project beneficiary tag cherrypick (#539) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * referral management project beneficiary validation fix * deleted persister and indexer file from project module resource folder --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * HH member clientrefid (#551) * adding clientRefId, Models version change, migration file * adding clientRefId for HouseholdMemberSearch as List * updated migration * adding Notnull for clientrefId --------- Co-authored-by: Vishal * Downsync smc referral module (#556) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Project beneficiary tag cherrypick (#549) * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * referral management project beneficiary validation fix --------- Co-authored-by: kanishq-egov Co-authored-by: Vishal * dummy api with same pagination response * dummy api with same pagination response * dummy api with same pagination response * downsync data test * data integrated till beneficiary * Update CHANGELOG.md * Delete health-services/project/src/main/resources/project-persistor.yml * skip on empty result added * skip on empty result added * beneficary searhc based on individual clientref id added * sideeffetc, ref, task fetch added * tasks earch fix * referral search fix --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * Dev downsync fix smc (#561) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: kanishq-egov * Dev master conflict fix (#562) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#563) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Dev master conflict fix (#565) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#566) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Added fix for testcases for householdmember (#570) Co-authored-by: kanishq-egov * updated the version, and added the changelog (#571) * updated the version, and added the changelog * updated ReferralManagement CHANGELOG * Update CHANGELOG.md --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * HLM-4062: removed pagination from fields excluding household api call * HLM-4062: missed in implementation (#574) * HLM-4062: missed in implementation * HLM-4062: default max is set to 1000 for not null limit value and 0 for offset value * project beneficiary tag update failed fix HLM-4444 * HLM-4444: added code review comments * sownsync bug fix for limit --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> * HLM-4444: project beneficiary update fix (#575) * Update CHANGELOG.md * updated changelog with dates (#577) * updated stock module changelog (#578) * HLM-4481: Added changes for task resource quantity validation and data type to double, db migration script added * HLM-4481: updated rowmapper for taskresource * HLM-4481: updated TaskTestBuilder.java * HLM-4481: added user create and update properties in application.properties * HLM-4481: fixed the regex required * Hlm 4501 smc referral flow (#602) * HLM-4501: Added changes for HFReferral flow * updated comments for common models * updated comments for common models removed ini file This reverts commit c1e226f961042f1162bb9ece8d2e1c01b62d220c. * HLM-4501: updated topics and hfreferal constants * HLM-4501: updated HFReferralService.java * HLM-4501: Added changes in project id validator * HLM-4501: updated HFReferralService.java * HLM-4501: fixed hfreferral changes * HLM-4501: added project facility id validator for hf_referral * HLM-4501: missing link for validator added * HLM-4501: updated HfrProjectFacilityIdValidator for NPE * HLM-4501 : updated hf referral symtoms character length to 256 * HLM-4501: updated additionalFields field value size from 2 to 1 * Implementation of row version validator for referral and side effect Implemented the row version validator for side effect under validator/sideeffect and similarly for referral under validator. The implemented validators were added to their respective service classes. * Revert "Implementation of row version validator for referral and side effect" This reverts commit 7a1a291110e4b5079fd177612c76df2d27681a6d. * hlm-4989 Implementation of row version validtor for side effect and referral * hlm-4989 Ordered and cleaned up imports * hlm-4989 Added code review comments for the Side effect and Referral Version Validator * hlm-4988 Regex pattern added for bednet quantities to be positive whole numbers * hlm-4988 Added config for health-project to build-config file * hlm-4988 Newly added regex pattern for bednet quantities commented-out * hlm-4988 mesage for Task resource quantity added in application.properties * hlm-4988 message added for invalid quantity error * Hlm 3372 enhance inventory flow backend fixes (#623) * HLM-3372: added changes required to fix quantity, Sender Receiver enum * HLM-3372: Sender and Receiver id validator * HLM-3372: updated all reference for SenderType and Receiver Type enum * HLM-3372: stock model updated, removed size annotations from referenceidtype enum field * HLM-3372: Min validation added for integer type of quantity * HLM-3372: test cases updated * HLM-5004 Added max value and decimal condition for quantity in stock, added component and order annotation for SSenderIdReceiverIdEqualsValidator * HLM-5004 Custom JsonDeserializer validator IntegerValidator added in health-services-models * hlm-5004 added custom exception and a custom exception handler to handle the integer validator exception * hlm-5004 optimized imports and added code comments * hlm-5004 CustomIntegerSerializer added and unnecessary validators removed * hlm-5004 Registered the CustomIntegerDeserializer with objectMapper for Integer class * hlm-5004 Removed line of code that was removing all the invalid entities from the list in SSenderIdReceiverIdEqualsValidator * hlm-5004 changes in test configurations and optimized imports * hlm-5004 added row version validator for stock delete * hlm-5004 dateOfEntry field was handled in StockRowMapper to return null if no value is present and description was added to stock contact for transactionReason * updated pom.xml for health campaign models * Revert "updated pom.xml for health campaign models" This reverts commit 035c78720c610916000c8de76fa87e7904774b59. --------- Co-authored-by: syed-egov * Hlm 4501 smc referral flow code comments (#636) * Dev to master : beneficiary tag bug fix, downsync pagination fix (#576) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter * Project beneficiary tag cherrypick (#539) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * referral management project beneficiary validation fix * deleted persister and indexer file from project module resource folder --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * HH member clientrefid (#551) * adding clientRefId, Models version change, migration file * adding clientRefId for HouseholdMemberSearch as List * updated migration * adding Notnull for clientrefId --------- Co-authored-by: Vishal * Downsync smc referral module (#556) * added downsync dummy api * added downsync dummy api with res * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Dev (#537) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * Hlm 4062 count api (#547) (#548) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Project beneficiary tag cherrypick (#549) * Added project beneficiary tag field * renamed project beneficiary tag to voucher tag * rebased project-persister.yml from configs * updated pom.xml: update common model version to 1.0.10 * updated db script, added unique constraint to tag column * updated referral-management.yml * updated db script * project beneficiary voucher tag uniqueness validator and search support * updated PbVoucherTagUniqueValidator.java * Added and updated for unique field voucher tag create and update scenario * project beneficiary bug fix * removed unused import * project beneficiary : voucherTag renamed to tag * referral management project beneficiary validation fix --------- Co-authored-by: kanishq-egov Co-authored-by: Vishal * dummy api with same pagination response * dummy api with same pagination response * dummy api with same pagination response * downsync data test * data integrated till beneficiary * Update CHANGELOG.md * Delete health-services/project/src/main/resources/project-persistor.yml * skip on empty result added * skip on empty result added * beneficary searhc based on individual clientref id added * sideeffetc, ref, task fetch added * tasks earch fix * referral search fix --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * Dev downsync fix smc (#561) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: kanishq-egov * Dev master conflict fix (#562) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#563) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Dev master conflict fix (#565) * HLM-3069: updated build.config.yml * HLM-3069: updated build-config.yml renamed adrm to referralmanagement * HLM-3372: increased stock version from 1.1.0 to 1.1.1-beta and project version from 1.1.0 to 1.1.1-beta * referralmanagement version 1.0.0-beta, added changelog, localsetup * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * Update CHANGELOG.md * HLM-3069: null project beneficiary validation error fix * HLM-3069: added comments and splitted validation condition * Dev to master (#550) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-4062: added count api changes for household * HLM-4062: Updated findbyid references * HLM-4062: Updated pom.xml of household * Hlm 3376 reviewcomments (#524) * HLM-3376: review comments commit * HLM-3069: side effect code comments, code refactor * HLM-3376: code review comments and code refactoring * updated the common-models version to 1.0.10, and updated in dependent service * HLM-3376 : Added additional field in side effect, referral. * HLM-3376: missing column fix * HLM-3372: constants type changed * HLM-3376: removed not used validators * code refactor and code comments * hlm-3376: added test cases * hlm-3376: referralmanagement context in test cases * hlm-3376: changed parameters for find by id * HLM-3372: typo fix * hlm-3376: persister changes, removed invalid parameters * hlm-3372: added changes as per code review, removed unused properties * hlm-3376: recipient validator for faciliy not working fix * HLM-3376: throwing exception on invalid recipient type * HLM-3376: added comments as per review comments * HLM-3376 : added changes as per code review comments, each column's name included in query * HLM-3376: query column names * Hlm 4062 count api (#547) * hlm-4062: updated household * HLM-4062: added count api support using cte for household * HLM-4062: updated HouseholdRepository.java * updated householdrowmapper.java * HLM-4062:code refactor, removed useCTE parameter --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> --------- Co-authored-by: kanishq-egov Co-authored-by: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> * Dev downsync fix smc (#566) * household model reverse * Update CHANGELOG.md * Added changes for includeDeleted for downsync * not null added --------- Co-authored-by: kanishq-egov * Added fix for testcases for householdmember (#570) Co-authored-by: kanishq-egov * updated the version, and added the changelog (#571) * updated the version, and added the changelog * updated ReferralManagement CHANGELOG * Update CHANGELOG.md --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * HLM-4062: removed pagination from fields excluding household api call * HLM-4062: missed in implementation (#574) * HLM-4062: missed in implementation * HLM-4062: default max is set to 1000 for not null limit value and 0 for offset value * project beneficiary tag update failed fix HLM-4444 * HLM-4444: added code review comments * sownsync bug fix for limit --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> * HLM-4444: project beneficiary update fix (#575) * Update CHANGELOG.md * updated changelog with dates (#577) * updated stock module changelog (#578) --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: bhanu prakash <109132521+bhanuprakash-egov@users.noreply.github.com> Co-authored-by: Naveen J <83631045+naveen-egov@users.noreply.github.com> Co-authored-by: talele08 * Referral and Side effect sequence diagram * HLM-4501: Added changes for HFReferral flow * updated comments for common models * updated comments for common models removed ini file This reverts commit c1e226f961042f1162bb9ece8d2e1c01b62d220c. * HLM-4501: updated topics and hfreferal constants * HLM-4501: updated HFReferralService.java * HLM-4501: Added changes in project id validator * HLM-4501: updated HFReferralService.java * HLM-4501: fixed hfreferral changes * HLM-4501: added project facility id validator for hf_referral * HLM-4501: missing link for validator added * HLM-4501: updated HfrProjectFacilityIdValidator for NPE * HLM-4501 : updated hf referral symtoms character length to 256 * HLM-4501: updated additionalFields field value size from 2 to 1 * HLM-4501: added code comments for all hf referral related classes * HLM-4501: hf-referral sequence diagram --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: bhanu prakash <109132521+bhanuprakash-egov@users.noreply.github.com> Co-authored-by: Naveen J <83631045+naveen-egov@users.noreply.github.com> Co-authored-by: talele08 * HLM-4496, HLM-4207 attendance module (#616) * HLM-4496: Added attendance module in HCM * HLM-4496: updated attendance directory, removed target folder and imi file * buil config added for hlm-4496 in feature branch * HLM-4207: offline enablement in attendance log * HLM-4207: added db migration script * HLM-4207: updated db migration script * HLM-4207: updated incorrect statements * HLM-4207: bulk api support, without redis cache * HLM-4207: updated Attendancelog consumer for bulk api * HLM-4207: consumer fix * HLM-4207: cache support added for attendance log create and update * HLM-4207: added health-individual endpoint * HLM-4207: added radis host * HLM-4207: updated qualified for objectmapper in attendance module * HLM-4496,HLM-4207: updated application.properties for redis config * HLM-4207: updated kafka listener topics * HLM-4207: changed kafka config * HLM-4894 adding hrms related flag to Individual object, adding another ApiOperation * HLM-4894 adding hrms related flag to Individual object, adding another ApiOperation * HLM-4207, HLM-4986, HLM-4987 : bug fix * HLM-4894 adding changes related to linking of HRMS Employee with Individual * HLM-4894 adding changes related to linking of HRMS Employee with Individual * HLM-4207: added clientreferenceid search, null check for document id * HLM-4894 reverting changes related to linking of HRMS Employee with Individual * HLM-4894 reverting changes related to linking of HRMS Employee with Individual from libraries, common-models * HLM-4207: code re-format * HLM-4894 adding changes for managing attendees while enrollment * HLM-4207: updated attendance search, register id or clientreference id are mandatory * hlm-5009 staffId in ProjectStaffSearch changed to list from string * HLM-4894 updating build config * HLM-4207: clientReferenceIds is changed to clientReferenceId for Attendance Log search criteria * HLM-4207: removed staff validation for search without register id * HLM-4894 adding changes for project staff validation * HLM-4894 adding @Qualifier annotation for object mapper * HLM-4894 fixing hrms url * HLM-4771: added changes for updating the registers on project date update * HLM-4771: project update changes * HLM-4771: updated the project start date update validation, can not update start date if it is already started * HLM-4771: updated attendance register consumer and service with comments * HLM-4771: updated the tenant id * HLM-4894 updating environment variables. * HLM-4894 updating code changes * HLM-4894 adding code changes * HLM-4894 adding code changes * HLM-4894 adding code changes * HLM-4771: updated the project validators, validation for start and end date of project * HLM-4894 adding useruuid as search param in individual search * HLM-4894 adding useruuid as search param in individual search * HLM-4894 adding useruuid as search param in individual search * HLM-4894 adding changes for registry creation when supervisor enrolls * HLM-4496, HLM-4894: first staff enrollment on attendance register creation is optional * HLM-4894 adding changes attendee enrollment * HLM-4894 adding changes for making staffId as list of staffId in ProjectStaffSearch * HLM-4894 adding changes for making staffId as list of staffId in ProjectStaffSearch * HLM-4894 adding changes for making staffId as list of staffId in ProjectStaffSearch * HLM-4894 removing staff-bulk-create-topic * HLM-4894 removing staff-bulk-create-topic * HLM-4894 removing staff-bulk-create-topic * HLM-4894 removing staff-bulk-create-topic * HLM-4894 changing health-attendance consumer group-id * HLM-4894 adding changes for projectstaff consumer * HLM-4894 adding changes for projectstaff consumer * HLM-4894 adding changes for projectstaff consumer * HLM-4894 adding changes for projectstaff consumer * HLM-4894 adding changes for projectstaff consumer * HLM-5045: added changes, project start date and end date difference should at least be 1 day. * HLM-4894 adding comments * HLM-4894 adding additional Details during attendance register creation * HLM-4894 adding additional Details during attendance register creation * hlm-4496 : bug fix on adding staff on updation of register * HLM-4894 increasing limit to 1000 * Added changelog for individual, health-services-models, project, stock * HLM-4496 : remove attendance module as it is moved to DIGIT-Works repository. * HLM-5076: added changes related to project module * updated individual user uuid search field for hlm-4496, hlm-4207 * changed common models build to 1.0.19-SNAPSHOT --------- Co-authored-by: Priyanka-eGov Co-authored-by: syed-egov Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * Hlm 4496 individual UUID search (#656) * HLM-4496: updated changedlog for individual, health-services-models, project, referralmanagement * HLM-4496: Added size annotations on individual search userUuid field * hlm-4496: Revert of application.properties changes * updated pom.xml version for individual, project, referralmanagement, stock (#657) * Health hrms (#660) * updated pom.xml version for individual, project, referralmanagement, stock * Added health-hrms * Hlm health hrms changes (#650) * HLM-4496: Added attendance module in HCM * HLM-4496: updated attendance directory, removed target folder and imi file * buil config added for hlm-4496 in feature branch * HLM-4207: offline enablement in attendance log * HLM-4207: added db migration script * HLM-4207: updated db migration script * HLM-4207: updated incorrect statements * HLM-4207: bulk api support, without redis cache * HLM-4207: updated Attendancelog consumer for bulk api * HLM-4207: consumer fix * HLM-4207: cache support added for attendance log create and update * HLM-4207: added health-individual endpoint * HLM-4207: added radis host * HLM-4207: updated qualified for objectmapper in attendance module * HLM-4496,HLM-4207: updated application.properties for redis config * HLM-4207: updated kafka listener topics * HLM-4207: changed kafka config * HLM-4207, HLM-4986, HLM-4987 : bug fix * HLM-4207: added clientreferenceid search, null check for document id * HLM-4894 moving hrms code from DIGIT-Dev branc health-moz-dev * HLM-4894 moving hrms code from DIGIT-Dev branc health-moz-dev * HLM-4894 updating build config for health-hrms * HLM-4894 adding clientreferenceID while creating individuals * HLM-4894 adding clientreferenceID while creating individuals * HLM-4894 adding clientreferenceID while creating individuals * HLM-4894 adding clientAuditDetails while creating individuals * Adding mdmsLegacyHost * Adding mdmsLegacyHost --------- Co-authored-by: kanishq-egov Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * Revert "Hlm health hrms changes (#650)" (#663) This reverts commit db786acf5fd949084ad544aa6f9f31e5d9a37f6e. * index creation migrations (#668) * hlm-5051 added method to validate task resource quantity based on product variant id which will be used to fetch the regex and error message from mdms * hlm-5051 changed the versionn for health-services-models * hlm-5051 added mdms task module config * hlm-5051 changed the module name for mdms data for task validation * hlm-5051 removed the regex patterns and error messages from appliction.properties and al removed the properties from cofigurations * flyway base image updated * reverted product changes and removed duplicate attendance code (#768) * flyway version update * updated psql version for core services and facility * flyway update * HLM throwing custom exception when boundary service call throw an error (#775) * HLM-6196: Search failing, updated GenericQueryBuilder.java, added changes to get all … (#769) * HLM Health-HRMS bug fix, user was set to null in hrms update as the t… (#761) * HLM Health-HRMS bug fix, user was set to null in hrms update as the tenantid was not provided during internal search * HLM updated hrms user type * updated type from individual create * Addressed code review comments * Added code comments and fixme todo as per code review comments * HLM updated flyway migration docker version * Revert "HLM updated flyway migration docker version" This reverts commit 1f1167ea0fc5ee5ed259f85cbdf9777e31eb868f. * Updated code comments on EmployeeService update method * Update EmployeeService.java * Updated code comments on EmployeeService, added changes for NPE handling --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * HLM-6196: updated GenericQueryBuilder.java, added changes to get all the fields except Object class * hlm-6196: update common library reference for dev testing" * HLM-6196: updated health-service-common version to 1.0.17-SNAPSHOT and added default for included deleted * HLM-6196: updated genericrepository * HLM-6196: fixed testcases * HLM-6196: fixed individual search query error * taskresource additional fields column added * HLM-6196: updated health services models TaskResource, added AdditionalField * HLM-6196: hfreferral, referral, sideeffect - edge case fix * HLM-6196: removed todo from urlparams --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * Hlm 6196 hrms employee search by names fix (#785) * HLM-6196: updated @component in validators for client reference id validation * HLM-6196: fixed testcases for stock and individual * HLM-6196: added missing migration file * HLM-6196: updated IndividualSearch model, added exclude annotation on individual name * HLM-6196: rectifying egov-hrms individual search object commit * HLM-6196: updated health services common for model exclude field fix * Revert "HLM-6196: updated @component in validators for client reference id validation" This reverts commit 6e915a0c58c07d3495bf736069c30003ac0ba65e. * Revert "HLM-6196: fixed testcases for stock and individual" This reverts commit ce90104fbe75fd01bf6e812e8cbe4b91569c1f2f. * HLM-6196: added comments as per code review * Update IndividualSearch.java --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * HLM-6196: updated @component in validators for client reference id va… (#781) * HLM-6196: updated @component in validators for client reference id validation * HLM-6196: fixed testcases for stock and individual * HLM-6196: added missing migration file * HLM-6196: updated IndividualSearch model, added exclude annotation on individual name * HLM-6196: rectifying egov-hrms individual search object commit * HLM-6196: updated health services common for model exclude field fix * Revert "HLM-6196: updated @component in validators for client reference id validation" This reverts commit 6e915a0c58c07d3495bf736069c30003ac0ba65e. * Revert "HLM-6196: fixed testcases for stock and individual" This reverts commit ce90104fbe75fd01bf6e812e8cbe4b91569c1f2f. * Revert "Revert "HLM-6196: updated @component in validators for client reference id validation"" This reverts commit 2218ad3b3916587f2b0e6ac67d06ded5152ce366. * Revert "Revert "HLM-6196: fixed testcases for stock and individual"" This reverts commit 083c516b18c02096ab1cfeb70e32b68c2c1c6c0d. * HLM-6196: replaced RuntimeException with CustomException * HLM-6196: updated to get only message from exception * HLM-6196: updated individual search as it was with exclude annotation * Update core-services/egov-hrms/src/main/java/org/egov/hrms/web/validator/EmployeeValidator.java Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * updated changelog for HCM v1.4 release * updated changelog for HCM v1.4 release * Update health-services/product/CHANGELOG.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * HLM added error stack strace whenever custom exception is thrown while validation duplicate entry * HLM-6303: fixed search for zero search object parameters case (#799) * merging master to master-flyway-imageupdate (#800) * HLM Health-HRMS bug fix, user was set to null in hrms update as the t… (#761) * HLM Health-HRMS bug fix, user was set to null in hrms update as the tenantid was not provided during internal search * HLM updated hrms user type * updated type from individual create * Addressed code review comments * Added code comments and fixme todo as per code review comments * HLM updated flyway migration docker version * Revert "HLM updated flyway migration docker version" This reverts commit 1f1167ea0fc5ee5ed259f85cbdf9777e31eb868f. * Updated code comments on EmployeeService update method * Update EmployeeService.java * Updated code comments on EmployeeService, added changes for NPE handling --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * HLM-6185: Added null check for the project task resources list (#767) * HLM-6185: Added null check for the project task resources list * HLM-6185: updated transformer logic for project task with beneficiary task and status population * microplan-ui (#782) * microplan-ui * adding HLM-6172 changes * hiding unique identifier column * Update build-config.yml * Update Dockerfile * Update Dockerfile * Update Dockerfile * Update Dockerfile * Update Dockerfile * Update Dockerfile * adding digti frontend pr 934 changes * Update build-config.yml * removing pl tl and template files * removed unnecessary code * Delete frontend/microplan-ui/Jenkinsfile * updating operation to match api changes * updating operation to match api changes * Update README.md * Update README.md * microplan-ui adding uploadguidelines and removing unnecessary files --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: SriPadma8997-egov <112681948+SriPadma8997-egov@users.noreply.github.com> * Admin console Improved performance, sheets freezed, implemented caching, delivery type integarted (#790) * Update campaignValidators.ts (#655) * fixes-> cyclenumber issue, hover issue, dropdown height issue, * css * fixes-> cyclenumber issue, hover issue, dropdown height issue, (#656) * fixes-> cyclenumber issue, hover issue, dropdown height issue, * css --------- Co-authored-by: nabeelmd-eGov * Update campaignUtils.ts * fixed HLM-5970 * Feat : added boundary validation at data level * fixes * local add * Added boundary validation * Refactor * fixed HLM-5935 and HLM-5749 * Refactor * Feat : updated table * change campaignid in payload * Feat : added campaignId * Update campaignApis.ts * Update campaignValidators.ts * refactored * Refactor * assigned campaignId * Refactor * updated createRequest Schema * Feat : invalid Status Persist * status fix * version-fix * Update CODEOWNERS * core version updated and css fix for language dropdown * refactor (#676) * Uat signoff (#678) * change in filter recursive * lowest level * added validation related to target sheet headers * HLM-5916 * download button fixes in summary (#682) Co-authored-by: nabeelmd-eGov * Hlm 5927 (#687) * change in filter recursive * lowest level * added validation for boundary codes to be invalid other than that selected from UI in target upload * Added Delivery and cycle config for LLIN and SMC both (#688) * no of cycle and deivery drafted changes * fixes * add localisation code for boundaries * fixes * fixes * Value localise in summary screen, api error change * fixes * genarate api call fix * font size change for summary * login css change * HLM-5718: SMC delivery config enhancement * config update * added config for in between * fix config for llin * added mdms integration --------- Co-authored-by: nabeelmd-eGov * Fixed HLM-5988_warning message (#689) Co-authored-by: nabeelmd-eGov <94039229+nabeelmd-eGov@users.noreply.github.com> * download filename fixes (#693) * download button fixes in summary * download filename with custom name changes added --------- Co-authored-by: nabeelmd-eGov * download filename fixes (#694) * download button fixes in summary * download filename with custom name changes added * config fix for llin --------- Co-authored-by: nabeelmd-eGov * successful toast message is fixed (#695) * successful toast message is fixed * Update UploadData.js * HLM-5991: Alert Pop UP CR (#696) Co-authored-by: nabeelmd-eGov * HLM-5718 changes (#703) Co-authored-by: nabeelmd-eGov * Localization cache (#706) * change in filter recursive * lowest level * refactored localization cache logic * Update README.md (#707) * Update README.md * Update README.md * Update utilities/project-factory/README.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update README.md --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * HLM-5985_made lowest level changes (#708) * HLM-5985_made lowest level changes * resolved codeRabbit comments * Create LOCALSETUP.md (#709) * Create LOCALSETUP.md * Refactored config * Update LOCALSETUP.md * Update utilities/project-factory/LOCALSETUP.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/LOCALSETUP.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/LOCALSETUP.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/LOCALSETUP.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update LOCALSETUP.md --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * updated the localisation module config * Refactor config (#713) * Refactor config * Update utilities/project-factory/src/server/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update postman_collection.json (#714) * Update postman_collection.json * Update postman_collection.json * Delete utilities/project-factory/project_factory_swagger.yml (#715) * Feat : removed campaignId validation for boundary upload (#718) * updated the delay for boundary relationship * added logger for request TODO TEST will be reverted * Revert "added logger for request TODO TEST" This reverts commit d5c2bf570400ada8183eebfec71f0a3449143117. * Schema validation (#719) * Feat : removed campaignId validation for boundary upload * Feat : added schema validation * Fixed mdms host * updated the logger messages * updated the loggers * delivery new changes, toast fix, error fix (#716) * delivery new changes, toast fix, error fix * new fixes * fixes * change text component to field component * added hierarchy * fix * fix * fix * fix * passing hierarchy from props --------- Co-authored-by: nabeelmd-eGov * Schema validation2 (#721) * Feat : removed campaignId validation for boundary upload * Feat : added schema validation * Fixed mdms host * Feat : added boundary validation * Feat : optimized product search * Fix : project mapping fixed (#722) * Fixed project search (#723) * smc fixes (#724) Co-authored-by: nabeelmd-eGov * Feat : added boundary confirmation (#727) * Fix: fixed processing boundary * Refactor * fixed HLM-6109 (#729) * gate fixes validation, ui ux (#731) Co-authored-by: nabeelmd-eGov * integrated panelcard component (#732) * integrated panelcard component * Update micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/Response.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update genericUtils.ts (#733) * updated the folder structure * Create CHANGELOG.md (#717) * updated the versions * Update .gitignore * Update request.ts (#735) * fixed generate api issue (#734) Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Create CHANGELOG.md * gate fixes (#736) * gate fixes validation, ui ux * gate fix --------- Co-authored-by: nabeelmd-eGov * added loader in the selecting boundaries (#737) * Update createAndSearch.ts (#738) * fix (#739) * fix * fix --------- Co-authored-by: nabeelmd-eGov * Patch 3 (#740) * change in filter recursive * lowest level * trimmed underscore and empty spaces * boundary fix (#742) Co-authored-by: nabeelmd-eGov * Update genericUtils.ts (#746) * fixed the delivery products issue * Fixed delivery conditions issue * Update campaignApis.ts (#747) * fixed warning toast (#748) * fixed warning toast * Update UploadData.js * fix (#749) * fix * fx * fix --------- Co-authored-by: nabeelmd-eGov * core -update (#751) Co-authored-by: nabeelmd-eGov * fixed stepper issue (#752) * fixed stepper issue * Update index.html * Feat : added user validation via individual (#753) * fixes (#754) Co-authored-by: nabeelmd-eGov * code fix nabeel (#756) * fixes * fix --------- Co-authored-by: nabeelmd-eGov * Updated few loggers (#759) * updated few loggers flow * Update utilities/project-factory/src/server/api/campaignApis.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/utils/campaignMappingUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/utils/campaignUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/api/campaignApis.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/utils/campaignMappingUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/utils/genericUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Updated the user Password generation logic #761 * Update Listener.ts (#730) * Update Listener.ts * added try catch logic in producer * Feat : added parallel batch execution (#767) * Feat : added parallel batch execution * Refactor * Update utilities/project-factory/src/server/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fixed the stepper (#765) * changes config (#769) * Project type config and added loggers for process of campaign (#772) * Feat : added themes in generate template (#773) * fixed the ajv package version for build issue * Feat : removed xlsx (#776) * HLM-6177: PARALLEL SEARCH IMPLEMENT, DELIVERY TYPE IMPLEMENT (#778) Co-authored-by: nabeelmd-eGov * css update (#780) Co-authored-by: nabeelmd-eGov * HLM-6179 and HLM-6180 (#777) * HLM-6179 and HLM-6180 * campaign name changes --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Feat : fixed target generation (#781) * fixed tenantId issue (#784) * fix: resolved AJV-related Jenkins build issue reference #783 #786 (#787) * module ui fix * updated all the package version for build fixes * fixed kafka-error at target generation (#789) * updated core version (#791) * updated core version * updated css also * Update campaignValidators.ts (#794) * Updated the excel generation logic and files * added changes for configurable column in target sheet (#779) * change in filter recursive * lowest level * made target headers genearte through mdms schema * changed config index.ts * changed config index.ts * changes for now * added configurable column logic from schema HLM-6169 * updated validate of target columns through schema * added masterForColumnSchema in index.ts * formatted dataManageService * refactored lock TargetFields func * removed console.log * User creation performance improved (#800) * Feat : Improved user creation performance * Change status color * Update utilities/project-factory/src/server/utils/campaignUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update genericUtils.ts (#801) * Hlm 6170 (#802) * change in filter recursive * lowest level * HLM -6170 added logic for only village level data in target sheet and some refactoring * updated css (#804) * fixed button issue (#805) * HLM 6177: Error card implementation in summary screen (#806) * HLM-6177: PARALLEL SEARCH IMPLEMENT, DELIVERY TYPE IMPLEMENT * Added Error Cards in summary screen and redirection --------- Co-authored-by: nabeelmd-eGov * added error button styles (#807) Co-authored-by: nabeelmd-eGov * updated popUp css (#808) * HLM 6178: Implementing New Pop up screen in boundaries (#809) * added error button styles * Implementing New Pop up screen in boundaries --------- Co-authored-by: nabeelmd-eGov * Facility changes (#812) * Feat : changed facility Template * Feat : locked target templates * fixed colour issue (#813) * Updated the project type conversion logic for the "deliveryType" dont1 and n config * Unique field added (#814) * Feat : changed facility Template * Feat : locked target templates * Feat : added unique check logic * Target schema update (#815) * change in filter recursive * lowest level * updated shcema of target columns to be configurable * removed empty spaces from config index.ts * Active mapping (#817) * Feat : changed facility Template * Feat : locked target templates * Feat : added unique check logic * Feat : added mapping via active field * changes in the schema validation (#816) * Updated the workbench and css module version * Feat : added active inactive boundary check (#818) * Update campaignValidators.ts (#819) * added active inactive validation (#820) * changed api call time (#826) * Feat : added target sum mapping (#825) * added campaign type as filter (#827) * Update genericApis.ts (#828) * Update excelUtils.ts (#829) * UI issue fixes, icon fix in summary error (#831) Co-authored-by: nabeelmd-eGov * Target columns (#830) * change in filter recursive * lowest level * commit * Feat : target flow fixed for LLIN-mz * uat to dev --------- Co-authored-by: admin1 * Feat : freezed target columns (#833) * Target mr dn (#834) * change in filter recursive * lowest level * Feat : skipped validation temporarily * changes in the target validation (#835) * fixed error info (#837) * Added roboto font (#840) * Feat : added roboto font * Fixed config * target validation based on diff campaign types (#843) * change in filter recursive * lowest level * updated validation of target based on campaign type * fixed validation issue (#844) * Updated the workbench package version * fixed validation logic (#846) * fixed validation logic * Update micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Error messages improved (#848) * Feat : imporved error messages and initilised utils for tracking process * Fix ; unused variables fixed * Feat : improved error messages * Fix : download error fix (#850) * Update campaignUtils.ts (#851) * Update campaignUtils.ts * Update utilities/project-factory/src/server/utils/campaignUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update campaignValidators.ts (#853) * HLM 6210: Toast, error focus fix and project type reset delivery data fix (#854) * HLM-6210: campaign type change reset delivery data fix, summary error focus fix * summary error focus fix --------- Co-authored-by: nabeelmd-eGov * HLM-6225_added time out according to data (#855) * Update campaignValidators.ts (#859) * HLM 6210 (#858) * HLM-6210: campaign type change reset delivery data fix, summary error focus fix * summary error focus fix * parallel search fixes --------- Co-authored-by: nabeelmd-eGov * Remove validation (#852) * change in filter recursive * lowest level * removed unnecessary validation for target * spacing refactor * Update campaignValidators.ts (#863) * Header validation (#861) * change in filter recursive * lowest level * removed unnecessary validation for target * changed the logic of header validation * space refactor * Update campaignUtils.ts (#864) * fixed ui error (#865) * Read me (#867) * change in filter recursive * lowest level * removed unnecessary validation for target * changed the logic of header validation * fixed portugese language error * space refactoring * Update Dockerfile * Update Dockerfile * Update migrate.sh * Update Dockerfile * Update campaignValidators.ts (#868) * HLM 6210:campaign type change reset fix (#869) * HLM-6210: campaign type change reset delivery data fix, summary error focus fix * summary error focus fix * parallel search fixes * campaign type change reset fix --------- Co-authored-by: nabeelmd-eGov * Update excelUtils.ts for sheetHeaders wraping (#870) * Update package.json * updated error messages (#871) * feat : added jaeger-client tracing (#872) * updated the table config * Update campaignApis.ts (#875) * removed the schema and updated the db name * fixing generate API call, file auto delete, date error (#877) Co-authored-by: nabeelmd-eGov * Trim resource (#878) * Feat : trimmed resource persist message * Refactor * Removed reject error in produce message * fixed min time, draft logic (#879) * Update index.ts (#880) * added min ui error and facility usage (#883) * added min ui error and facility usage * changes * Update campaignUtils.ts (#884) * HLM 6007 (#885) * fixing generate API call, file auto delete, date error * generate api fix --------- Co-authored-by: nabeelmd-eGov * Update Dockerfile * Feat : docker config update (#886) * Update Dockerfile (#887) * Create buildWorkbenchUI.yml * Update README.md (#917) * Update buildWorkbenchUI.yml * Update README.md * Updated the DB Schema issue of Project-factory * fixed hierarchy order (#919) * User flag hcm (#920) * Feat : docker config update * Feat : added user create flag * Refactored * Update campaignUtils.ts * Update campaignMappingUtils.ts (#922) * Ashish egov patch 2 (#921) * Update index.ts * Update campaignApis.ts * Fixed the project type conversion and product duplicate issue * Update campaignApis.ts (#924) * Update campaignMappingUtils.ts (#925) * Update campaignMappingUtils.ts * Refactored * Update publishProjectFactory.yml * Update buildWorkbenchUI.yml * Update campaignMappingUtils.ts (#926) * Update request.ts (#928) * Update request.ts * Feat : updated httprequest * Feat : warning response added * Refactor * added start and enddate in cycles * Update campaignApis.ts (#930) * Update request.ts (#932) * fixed generate issue (#933) * Fixed project-type resources duplication * updated target error messages (#936) * fixed stepper from draft (#937) * Update Listener.ts * delivery type disable fix, product sku name change (#939) Co-authored-by: nabeelmd-eGov * fixed error message issue (#941) * Redis integration (#940) * Feat : added redis * Feat : added redis retry * updated migration * fixed * updated migration * Delete .vscode/launch.json * Delete .vscode/settings.json --------- Co-authored-by: ashish-egov <137176738+ashish-egov@users.noreply.github.com> Co-authored-by: nabeelmd-eGov Co-authored-by: nabeelmd-eGov <94039229+nabeelmd-eGov@users.noreply.github.com> Co-authored-by: Bhavya-egov Co-authored-by: ashish-egov Co-authored-by: nitish-egov <137176807+nitish-egov@users.noreply.github.com> Co-authored-by: Bhavya-egov <137176879+Bhavya-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Swathi-eGov <137176788+Swathi-eGov@users.noreply.github.com> Co-authored-by: admin1 * Master flyway imageupdate (#794) * flyway base image updated * reverted product changes and removed duplicate attendance code (#768) * flyway version update * updated psql version for core services and facility * flyway update * HLM throwing custom exception when boundary service call throw an error (#775) * HLM-6196: Search failing, updated GenericQueryBuilder.java, added changes to get all … (#769) * HLM Health-HRMS bug fix, user was set to null in hrms update as the t… (#761) * HLM Health-HRMS bug fix, user was set to null in hrms update as the tenantid was not provided during internal search * HLM updated hrms user type * updated type from individual create * Addressed code review comments * Added code comments and fixme todo as per code review comments * HLM updated flyway migration docker version * Revert "HLM updated flyway migration docker version" This reverts commit 1f1167ea0fc5ee5ed259f85cbdf9777e31eb868f. * Updated code comments on EmployeeService update method * Update EmployeeService.java * Updated code comments on EmployeeService, added changes for NPE handling --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * HLM-6196: updated GenericQueryBuilder.java, added changes to get all the fields except Object class * hlm-6196: update common library reference for dev testing" * HLM-6196: updated health-service-common version to 1.0.17-SNAPSHOT and added default for included deleted * HLM-6196: updated genericrepository * HLM-6196: fixed testcases * HLM-6196: fixed individual search query error * taskresource additional fields column added * HLM-6196: updated health services models TaskResource, added AdditionalField * HLM-6196: hfreferral, referral, sideeffect - edge case fix * HLM-6196: removed todo from urlparams --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal * Hlm 6196 hrms employee search by names fix (#785) * HLM-6196: updated @component in validators for client reference id validation * HLM-6196: fixed testcases for stock and individual * HLM-6196: added missing migration file * HLM-6196: updated IndividualSearch model, added exclude annotation on individual name * HLM-6196: rectifying egov-hrms individual search object commit * HLM-6196: updated health services common for model exclude field fix * Revert "HLM-6196: updated @component in validators for client reference id validation" This reverts commit 6e915a0c58c07d3495bf736069c30003ac0ba65e. * Revert "HLM-6196: fixed testcases for stock and individual" This reverts commit ce90104fbe75fd01bf6e812e8cbe4b91569c1f2f. * HLM-6196: added comments as per code review * Update IndividualSearch.java --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> * HLM-6196: updated @component in validators for client reference id va… (#781) * HLM-6196: updated @component in validators for client reference id validation * HLM-6196: fixed testcases for stock and individual * HLM-6196: added missing migration file * HLM-6196: updated IndividualSearch model, added exclude annotation on individual name * HLM-6196: rectifying egov-hrms individual search object commit * HLM-6196: updated health services common for model exclude field fix * Revert "HLM-6196: updated @component in validators for client reference id validation" This reverts commit 6e915a0c58c07d3495bf736069c30003ac0ba65e. * Revert "HLM-6196: fixed testcases for stock and individual" This reverts commit ce90104fbe75fd01bf6e812e8cbe4b91569c1f2f. * Revert "Revert "HLM-6196: updated @component in validators for client reference id validation"" This reverts commit 2218ad3b3916587f2b0e6ac67d06ded5152ce366. * Revert "Revert "HLM-6196: fixed testcases for stock and individual"" This reverts commit 083c516b18c02096ab1cfeb70e32b68c2c1c6c0d. * HLM-6196: replaced RuntimeException with CustomException * HLM-6196: updated to get only message from exception * HLM-6196: updated individual search as it was with exclude annotation * Update core-services/egov-hrms/src/main/java/org/egov/hrms/web/validator/EmployeeValidator.java Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * updated changelog for HCM v1.4 release * updated changelog for HCM v1.4 release * Update health-services/product/CHANGELOG.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * HLM added error stack strace whenever custom exception is thrown while validation duplicate entry --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Adding plan-service folder for master merge (#783) * Adding plan-service folder for master merge * code review comment. --------- Co-authored-by: devdatta-egov * Microplan UI (#793) * microplan-ui * adding HLM-6172 changes * hiding unique identifier column * Update build-config.yml * Update Dockerfile * Update Dockerfile * Update Dockerfile * Update Dockerfile * Update Dockerfile * Update Dockerfile * adding digti frontend pr 934 changes * Update build-config.yml * removing pl tl and template files * removed unnecessary code * Delete frontend/microplan-ui/Jenkinsfile * updating operation to match api changes * updating operation to match api changes * Update README.md * Update README.md * microplan-ui adding uploadguidelines and removing unnecessary files * adding microplan to micro-ui * adding microplan folder in microui/web * Update setupProxy.js * review changes * adding review changes * review changes * Update Mapping.js * Update Upload.js * Update geojsonValidations.js * Update CreateMicroplan.js * Update MicroplanPreview.js * Update MicroplanPreview.js * Update CreateMicroplan.js * adding review comments, updage campaign service, removed hardcoded tenent and removed logout util * removing microplan-ui folder * Update index.js * adding review changes, reducing functional complexcity * updaing microplan css pkg version * Update jsonToExcelBlob.js * Update MicroplanCreatedScreen.js * Update UICustomizations.js * Update uploadUtils.js * Update build-config.yml --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: SriPadma8997-egov <112681948+SriPadma8997-egov@users.noreply.github.com> --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: siddhant-nawale-egov <162107530+siddhant-nawale-egov@users.noreply.github.com> Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: SriPadma8997-egov <112681948+SriPadma8997-egov@users.noreply.github.com> Co-authored-by: ashish-egov <137176738+ashish-egov@users.noreply.github.com> Co-authored-by: nabeelmd-eGov Co-authored-by: nabeelmd-eGov <94039229+nabeelmd-eGov@users.noreply.github.com> Co-authored-by: Bhavya-egov Co-authored-by: ashish-egov Co-authored-by: nitish-egov <137176807+nitish-egov@users.noreply.github.com> Co-authored-by: Bhavya-egov <137176879+Bhavya-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Swathi-eGov <137176788+Swathi-eGov@users.noreply.github.com> Co-authored-by: admin1 Co-authored-by: Vishal Co-authored-by: Priyanka-eGov <74049060+Priyanka-eGov@users.noreply.github.com> Co-authored-by: devdatta-egov * removing location accuracy maximum * Added changes from commit 6ea1b424cb0ac161707a2721e308100ae5f8837f * Added changes from commit f16f84e0be73f2ae2f918302671ffe7c844261a3 * HLM-6289: updated changes from impel for stock and referral minus downsync * [hlm-4053] client ref id unique key error changes and search fix * HLM-6289: updated the code for search in cache fix * [hlm-4053] search fix for facility, household. Fixed individual identifier clientrefId enrichment * beneficiary sick and absent in task validation * HLM-6289: Reset transformer to match base branch master * HLM-6289: Reset transformer to match base branch master 2 * HLM-6289: Reset dashboard-analytics and pgr-services to match base branch master * HLM-6289: findInCache fix for individual repository, project beneficiary repository, referral managment service repositories * HLM-6289: updated individual repository * updated Field.java, removed javax references * HLM-4989: refactor - remove unused imports * Revert "HLM-6185: Added null check for the project task resources list (#767)" This reverts commit 3d000ed57c9caa7e8b46eb224bc998203a44b1b9. * Update ProjectTaksIndexV1 model as the quantity field type is changed to double * HLM-6289: added RmRowVersionValidator in Referral Service * Removed plan service README changes picked from merge commits --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Vishal Co-authored-by: bhanu prakash <109132521+bhanuprakash-egov@users.noreply.github.com> Co-authored-by: Naveen J <83631045+naveen-egov@users.noreply.github.com> Co-authored-by: talele08 Co-authored-by: syed Co-authored-by: Priyanka-eGov Co-authored-by: Priyanka-eGov <74049060+Priyanka-eGov@users.noreply.github.com> Co-authored-by: vishal-egov <121248108+vishal-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: siddhant-nawale-egov <162107530+siddhant-nawale-egov@users.noreply.github.com> Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: SriPadma8997-egov <112681948+SriPadma8997-egov@users.noreply.github.com> Co-authored-by: ashish-egov <137176738+ashish-egov@users.noreply.github.com> Co-authored-by: nabeelmd-eGov Co-authored-by: nabeelmd-eGov <94039229+nabeelmd-eGov@users.noreply.github.com> Co-authored-by: Bhavya-egov Co-authored-by: ashish-egov Co-authored-by: nitish-egov <137176807+nitish-egov@users.noreply.github.com> Co-authored-by: Bhavya-egov <137176879+Bhavya-egov@users.noreply.github.com> Co-authored-by: Swathi-eGov <137176788+Swathi-eGov@users.noreply.github.com> Co-authored-by: admin1 Co-authored-by: devdatta-egov Co-authored-by: bhanuprakash-egov Co-authored-by: SivajiGanesh Nangireddy --- .../validators/ServiceRequestValidator.java | 6 + .../web/models/AttributeValue.java | 1 - .../facility/consumer/FacilityConsumer.java | 7 +- .../repository/FacilityRepository.java | 16 +- .../facility/service/FacilityService.java | 7 +- .../household/consumer/HouseholdConsumer.java | 7 +- .../consumer/HouseholdMemberConsumer.java | 7 +- .../repository/HouseholdRepository.java | 25 +- .../service/HouseholdMemberService.java | 10 +- .../household/service/HouseholdService.java | 9 +- .../household/service/IndividualService.java | 3 +- .../repository/IndividualRepository.java | 50 ++-- .../individual/service/EnrichmentService.java | 18 +- .../service/IndividualEncryptionService.java | 3 +- .../individual/service/IndividualService.java | 11 +- .../data/repository/GenericRepository.java | 11 +- .../egov/common/models/facility/Address.java | 1 - .../egov/common/models/facility/Field.java | 1 + .../egov/common/models/household/Address.java | 1 - .../common/models/individual/Address.java | 1 - .../egov/common/models/product/Address.java | 1 - .../egov/common/models/project/Address.java | 1 - .../common/models/project/TaskQuantity.java | 45 ++++ .../common/models/project/TaskResource.java | 2 +- .../org/egov/common/models/stock/Address.java | 1 - .../main/java/org/egov/project/Constants.java | 2 + .../project/config/ProjectConfiguration.java | 3 + .../consumer/ProjectBeneficiaryConsumer.java | 7 +- .../consumer/ProjectFacilityConsumer.java | 7 +- .../consumer/ProjectResourceConsumer.java | 7 +- .../consumer/ProjectStaffConsumer.java | 7 +- .../project/consumer/ProjectTaskConsumer.java | 7 +- .../ProjectBeneficiaryRepository.java | 9 +- .../repository/ProjectTaskRepository.java | 16 +- .../rowmapper/TaskResourceRowMapper.java | 2 +- .../service/ProjectBeneficiaryService.java | 7 +- .../service/ProjectFacilityService.java | 7 +- .../service/ProjectResourceService.java | 7 +- .../project/service/ProjectStaffService.java | 7 +- .../project/service/ProjectTaskService.java | 13 +- .../service/enrichment/ProjectEnrichment.java | 3 +- .../org/egov/project/util/BoundaryUtil.java | 3 +- .../java/org/egov/project/util/MDMSUtils.java | 3 +- .../egov/project/util/ProjectConstants.java | 8 +- .../beneficiary/BeneficiaryValidator.java | 3 +- .../facility/PfFacilityIdValidator.java | 3 +- .../validator/staff/PsUserIdValidator.java | 3 +- .../task/PtIsResouceEmptyValidator.java | 33 ++- .../task/PtResourceQuantityValidator.java | 234 ++++++++++++++++++ .../src/main/resources/application.properties | 1 + .../egov/project/helper/TaskTestBuilder.java | 4 +- .../consumer/ReferralManagementConsumer.java | 6 +- .../consumer/SideEffectConsumer.java | 6 +- .../repository/HFReferralRepository.java | 9 +- .../repository/ReferralRepository.java | 9 +- .../repository/SideEffectRepository.java | 9 +- .../service/FacilityService.java | 3 +- .../service/ReferralManagementService.java | 14 +- .../service/SideEffectService.java | 35 +-- .../RmProjectBeneficiaryIdValidator.java | 16 +- .../validator/RmRowVersionValidator.java | 83 +++++++ .../validator/RmSideEffectIdValidator.java | 14 +- .../sideeffect/SeRowVersionValidator.java | 86 +++++++ .../sideeffect/SeUniqueEntityValidator.java | 14 +- .../BeneficiaryDownsyncController.java | 16 +- .../org/egov/processor/kafka/Producer.java | 2 + .../egov/stock/consumer/StockConsumer.java | 15 +- .../consumer/StockReconciliationConsumer.java | 15 +- .../repository/rowmapper/StockRowMapper.java | 6 +- .../egov/stock/service/FacilityService.java | 38 ++- .../service/StockReconciliationService.java | 63 ++--- .../org/egov/stock/service/StockService.java | 55 ++-- .../org/egov/stock/util/ValidatorUtil.java | 26 +- ...va => SStockTransferPartiesValidator.java} | 4 +- .../models/downstream/ProjectTaskIndexV1.java | 4 +- .../transformer/service/ProjectService.java | 30 --- .../ProjectTaskTransformationService.java | 99 +++----- 77 files changed, 920 insertions(+), 408 deletions(-) create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskQuantity.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmRowVersionValidator.java create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeRowVersionValidator.java rename health-services/stock/src/main/java/org/egov/stock/validator/stock/{StocktransferPartiesValidator.java => SStockTransferPartiesValidator.java} (88%) 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 fc692f42310..66595568bc1 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 @@ -104,6 +104,9 @@ private void validateAttributeValuesAgainstServiceDefinition(ServiceDefinition s // Validate if value being passed is consistent in terms of data type provided as part of service definition service.getAttributes().forEach(attributeValue -> { + if (attributeValue.getValue() == null && !setOfRequiredAttributes.contains(attributeValue.getAttributeCode())) { + return; + } if(attributeCodeVsDataType.get(attributeValue.getAttributeCode()).equals(AttributeDefinition.DataTypeEnum.NUMBER)){ if(!(attributeValue.getValue() instanceof Number)){ throw new CustomException(SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_CODE, SERVICE_REQUEST_ATTRIBUTE_INVALID_NUMBER_VALUE_MSG); @@ -135,6 +138,9 @@ private void validateAttributeValuesAgainstServiceDefinition(ServiceDefinition s // Validate if value provided against attribute definition of single value list and multi value list is the same as the list of values provided during creation service.getAttributes().forEach(attributeValue -> { + if (attributeValue.getValue() == null && !setOfRequiredAttributes.contains(attributeValue.getAttributeCode())) { + return; + } if(attributeCodeVsValues.containsKey(attributeValue.getAttributeCode())){ if(attributeCodeVsDataType.get(attributeValue.getAttributeCode()).equals(AttributeDefinition.DataTypeEnum.SINGLEVALUELIST)){ if(!attributeCodeVsValues.get(attributeValue.getAttributeCode()).contains(attributeValue.getValue())){ 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 8b498387d86..8aeff4e39f3 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 @@ -35,7 +35,6 @@ public class AttributeValue { private String attributeCode = null; @JsonProperty("value") - @NotNull private Object value = null; @JsonProperty("auditDetails") diff --git a/health-services/facility/src/main/java/org/egov/facility/consumer/FacilityConsumer.java b/health-services/facility/src/main/java/org/egov/facility/consumer/FacilityConsumer.java index e05edce134c..424dc8eb71f 100644 --- a/health-services/facility/src/main/java/org/egov/facility/consumer/FacilityConsumer.java +++ b/health-services/facility/src/main/java/org/egov/facility/consumer/FacilityConsumer.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.facility.Facility; import org.egov.common.models.facility.FacilityBulkRequest; import org.egov.facility.service.FacilityService; @@ -33,7 +34,7 @@ public List bulkCreate(Map consumerRecord, FacilityBulkRequest request = objectMapper.convertValue(consumerRecord, FacilityBulkRequest.class); return service.create(request, true); } catch (Exception exception) { - log.error("error in facility consumer bulk create", exception); + log.error("error in facility consumer bulk create: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -45,7 +46,7 @@ public List bulkUpdate(Map consumerRecord, FacilityBulkRequest request = objectMapper.convertValue(consumerRecord, FacilityBulkRequest.class); return service.update(request, true); } catch (Exception exception) { - log.error("error in facility consumer bulk update", exception); + log.error("error in facility consumer bulk update: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -57,7 +58,7 @@ public List bulkDelete(Map consumerRecord, FacilityBulkRequest request = objectMapper.convertValue(consumerRecord, FacilityBulkRequest.class); return service.delete(request, true); } catch (Exception exception) { - log.error("error in facility consumer bulk delete", exception); + log.error("error in facility consumer bulk delete: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } diff --git a/health-services/facility/src/main/java/org/egov/facility/repository/FacilityRepository.java b/health-services/facility/src/main/java/org/egov/facility/repository/FacilityRepository.java index 9c67b1e6be2..482ac988b98 100644 --- a/health-services/facility/src/main/java/org/egov/facility/repository/FacilityRepository.java +++ b/health-services/facility/src/main/java/org/egov/facility/repository/FacilityRepository.java @@ -13,6 +13,7 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; import java.lang.reflect.Method; @@ -35,9 +36,12 @@ public FacilityRepository(Producer producer, NamedParameterJdbcTemplate namedPar } public List findById(List ids, String columnName, Boolean includeDeleted) { - List objFound = findInCache(ids).stream() - .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) - .collect(Collectors.toList()); + List objFound = findInCache(ids); + if (!includeDeleted) { + objFound = objFound.stream() + .filter(entity -> entity.getIsDeleted().equals(false)) + .collect(Collectors.toList()); + } if (!objFound.isEmpty()) { Method idMethod = getIdMethod(objFound, columnName); ids.removeAll(objFound.stream() @@ -67,7 +71,11 @@ public List find(FacilitySearch searchObject, Integer limit, Integer o query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); query = query.replace("id IN (:id)", "f.id IN (:id)"); - query = query + " and f.tenantId=:tenantId "; + if(CollectionUtils.isEmpty(whereFields)) { + query = query + " where f.tenantId=:tenantId "; + } else { + query = query + " and f.tenantId=:tenantId "; + } if (Boolean.FALSE.equals(includeDeleted)) { query = query + "and isDeleted=:isDeleted "; } diff --git a/health-services/facility/src/main/java/org/egov/facility/service/FacilityService.java b/health-services/facility/src/main/java/org/egov/facility/service/FacilityService.java index 04cf66e5760..769aae4b725 100644 --- a/health-services/facility/src/main/java/org/egov/facility/service/FacilityService.java +++ b/health-services/facility/src/main/java/org/egov/facility/service/FacilityService.java @@ -1,6 +1,7 @@ package org.egov.facility.service; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.facility.Facility; @@ -101,7 +102,7 @@ public List create(FacilityBulkRequest request, boolean isBulk) { facilityRepository.save(validEntities, configuration.getCreateFacilityTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); + log.error("error occurred: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_FACILITIES); } @@ -132,7 +133,7 @@ public List update(FacilityBulkRequest request, boolean isBulk) { facilityRepository.save(validEntities, configuration.getUpdateFacilityTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); + log.error("error occurred: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_FACILITIES); } @@ -163,7 +164,7 @@ public List delete(FacilityBulkRequest request, boolean isBulk) { facilityRepository.save(validEntities, configuration.getDeleteFacilityTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); + log.error("error occurred: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_FACILITIES); } diff --git a/health-services/household/src/main/java/org/egov/household/consumer/HouseholdConsumer.java b/health-services/household/src/main/java/org/egov/household/consumer/HouseholdConsumer.java index 7bc27e9bbd2..dcaf3d491ab 100644 --- a/health-services/household/src/main/java/org/egov/household/consumer/HouseholdConsumer.java +++ b/health-services/household/src/main/java/org/egov/household/consumer/HouseholdConsumer.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.household.Household; import org.egov.common.models.household.HouseholdBulkRequest; import org.egov.household.service.HouseholdService; @@ -38,7 +39,7 @@ public List bulkCreate(Map consumerRecord, HouseholdBulkRequest request = objectMapper.convertValue(consumerRecord, HouseholdBulkRequest.class); return householdService.create(request, true); } catch (Exception exception) { - log.error("error in household consumer bulk create", exception); + log.error("error in household consumer bulk create: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -50,7 +51,7 @@ public List bulkUpdate(Map consumerRecord, HouseholdBulkRequest request = objectMapper.convertValue(consumerRecord, HouseholdBulkRequest.class); return householdService.update(request, true); } catch (Exception exception) { - log.error("error in household consumer bulk update", exception); + log.error("error in household consumer bulk update: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -62,7 +63,7 @@ public List bulkDelete(Map consumerRecord, HouseholdBulkRequest request = objectMapper.convertValue(consumerRecord, HouseholdBulkRequest.class); return householdService.delete(request, true); } catch (Exception exception) { - log.error("error in household consumer bulk delete", exception); + log.error("error in household consumer bulk delete: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } diff --git a/health-services/household/src/main/java/org/egov/household/consumer/HouseholdMemberConsumer.java b/health-services/household/src/main/java/org/egov/household/consumer/HouseholdMemberConsumer.java index 11bc1709232..35acb74b53f 100644 --- a/health-services/household/src/main/java/org/egov/household/consumer/HouseholdMemberConsumer.java +++ b/health-services/household/src/main/java/org/egov/household/consumer/HouseholdMemberConsumer.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.household.HouseholdMember; import org.egov.common.models.household.HouseholdMemberBulkRequest; import org.egov.household.service.HouseholdMemberService; @@ -38,7 +39,7 @@ public List bulkCreate(Map consumerRecord, HouseholdMemberBulkRequest request = objectMapper.convertValue(consumerRecord, HouseholdMemberBulkRequest.class); return householdMemberService.create(request, true); } catch (Exception exception) { - log.error("error in household member consumer bulk create", exception); + log.error("error in household member consumer bulk create: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -50,7 +51,7 @@ public List bulkUpdate(Map consumerRecord, HouseholdMemberBulkRequest request = objectMapper.convertValue(consumerRecord, HouseholdMemberBulkRequest.class); return householdMemberService.update(request, true); } catch (Exception exception) { - log.error("error in household member consumer bulk update", exception); + log.error("error in household member consumer bulk update: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -62,7 +63,7 @@ public List bulkDelete(Map consumerRecord, HouseholdMemberBulkRequest request = objectMapper.convertValue(consumerRecord, HouseholdMemberBulkRequest.class); return householdMemberService.delete(request, true); } catch (Exception exception) { - log.error("error in household member consumer bulk delete", exception); + log.error("error in household member consumer bulk delete: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } diff --git a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java index 35ed43a136b..55a0cee69e1 100644 --- a/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java +++ b/health-services/household/src/main/java/org/egov/household/repository/HouseholdRepository.java @@ -15,6 +15,7 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; import java.lang.reflect.Method; @@ -43,9 +44,12 @@ protected HouseholdRepository(Producer producer, } public SearchResponse findById(List ids, String columnName, Boolean includeDeleted) { - List objFound = findInCache(ids).stream() - .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) - .collect(Collectors.toList()); + List objFound = findInCache(ids); + if (!includeDeleted) { + objFound = objFound.stream() + .filter(entity -> entity.getIsDeleted().equals(false)) + .collect(Collectors.toList()); + } if (!objFound.isEmpty()) { Method idMethod = getIdMethod(objFound, columnName); ids.removeAll(objFound.stream() @@ -79,7 +83,12 @@ public SearchResponse find(HouseholdSearch searchObject, Integer limi query = query.replace("id IN (:id)", "h.id IN (:id)"); query = query.replace("clientReferenceId IN (:clientReferenceId)", "h.clientReferenceId IN (:clientReferenceId)"); - query = query + " and h.tenantId=:tenantId "; + if(CollectionUtils.isEmpty(whereFields)) { + query = query + " where h.tenantId=:tenantId "; + } else { + query = query + " and h.tenantId=:tenantId "; + } + if (Boolean.FALSE.equals(includeDeleted)) { query = query + "and isDeleted=:isDeleted "; } @@ -120,7 +129,13 @@ public SearchResponse findByRadius(HouseholdSearch searchObject, Inte query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); query = query.replace("id IN (:id)", "h.id IN (:id)"); query = query.replace("clientReferenceId IN (:clientReferenceId)", "h.clientReferenceId IN (:clientReferenceId)"); - query = query + " and h.tenantId=:tenantId "; + + if(CollectionUtils.isEmpty(whereFields)) { + query = query + " where h.tenantId=:tenantId "; + } else { + query = query + " and h.tenantId=:tenantId "; + } + if (Boolean.FALSE.equals(includeDeleted)) { query = query + "and isDeleted=:isDeleted "; } diff --git a/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberService.java b/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberService.java index 2f350d2be76..9d64577f1f9 100644 --- a/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberService.java +++ b/health-services/household/src/main/java/org/egov/household/service/HouseholdMemberService.java @@ -7,6 +7,8 @@ import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.ds.Tuple; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.ErrorDetails; @@ -126,7 +128,7 @@ public List create(HouseholdMemberBulkRequest householdMemberBu log.info("household members data saved successfully"); } } catch (Exception exception) { - log.error("error occurred while creating household members: ", exception); + log.error("error occurred while creating household members: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(householdMemberBulkRequest, errorDetailsMap, validHouseholdMembers, exception, SET_HOUSEHOLD_MEMBERS); } @@ -161,7 +163,7 @@ public SearchResponse search(HouseholdMemberSearch householdMem return householdMemberRepository.find(householdMemberSearch, limit, offset, tenantId, lastChangedSince, includeDeleted); } catch (Exception e) { - log.error("error in building query for household member search", e); + log.error("error in building query for household member search: {}", ExceptionUtils.getStackTrace(e)); throw new CustomException("ERROR_IN_QUERY", e.getMessage()); } } @@ -192,7 +194,7 @@ public List update(HouseholdMemberBulkRequest householdMemberBu log.info("household member data updated successfully"); } } catch (Exception exception) { - log.error("error occurred", exception); + log.error("error occurred: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(householdMemberBulkRequest, errorDetailsMap, validHouseholdMembers, exception, SET_HOUSEHOLD_MEMBERS); } @@ -224,7 +226,7 @@ public List delete(HouseholdMemberBulkRequest householdMemberBu log.info("deleted Household Members: {}", validHouseholdMembers); } } catch (Exception exception) { - log.error("error occurred while deleting household members", exception); + log.error("error occurred while deleting household members: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(householdMemberBulkRequest, errorDetailsMap, validHouseholdMembers, exception, SET_HOUSEHOLD_MEMBERS); } diff --git a/health-services/household/src/main/java/org/egov/household/service/HouseholdService.java b/health-services/household/src/main/java/org/egov/household/service/HouseholdService.java index 2fb2804f178..c6f701b6eb0 100644 --- a/health-services/household/src/main/java/org/egov/household/service/HouseholdService.java +++ b/health-services/household/src/main/java/org/egov/household/service/HouseholdService.java @@ -1,6 +1,7 @@ package org.egov.household.service; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; @@ -111,7 +112,7 @@ public List create(HouseholdBulkRequest request, boolean isBulk) { log.info("successfully created {} households", validEntities.size()); } } catch (Exception exception) { - log.error("error occurred while creating households", exception); + log.error("error occurred while creating households: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_HOUSEHOLDS); } @@ -147,7 +148,7 @@ public SearchResponse search(HouseholdSearch householdSearch, Integer log.info("households found for search, size: {}", searchResponse.getResponse().size()); return searchResponse; } catch (QueryBuilderException e) { - log.error("error occurred while searching households", e); + log.error("error occurred while searching households: {}", ExceptionUtils.getStackTrace(e)); throw new CustomException("ERROR_IN_QUERY", e.getMessage()); } } @@ -173,7 +174,7 @@ public List update(HouseholdBulkRequest request, boolean isBulk) { log.info("successfully updated households"); } } catch (Exception exception) { - log.error("error occurred while updating households: " + exception.getMessage()); + log.error("error occurred while updating households: {}" , ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_HOUSEHOLDS); } @@ -207,7 +208,7 @@ public List delete(HouseholdBulkRequest request, boolean isBulk) { log.info("Households saved to delete topic"); } } catch (Exception exception) { - log.error("error occurred while deleting households: ", exception); + log.error("error occurred while deleting households: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_HOUSEHOLDS); } diff --git a/health-services/household/src/main/java/org/egov/household/service/IndividualService.java b/health-services/household/src/main/java/org/egov/household/service/IndividualService.java index 5701e87c5a1..369dfb9b1fd 100644 --- a/health-services/household/src/main/java/org/egov/household/service/IndividualService.java +++ b/health-services/household/src/main/java/org/egov/household/service/IndividualService.java @@ -1,6 +1,7 @@ package org.egov.household.service; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; @@ -82,7 +83,7 @@ private IndividualBulkResponse getIndividualResponse(String tenantId, Individual individualSearchRequest, IndividualBulkResponse.class); } catch (Exception e) { - log.error("error while fetching individuals list: {}", e.getMessage()); + log.error("error while fetching individuals list: {}", ExceptionUtils.getStackTrace(e)); throw new CustomException(INTERNAL_SERVER_ERROR, "Error while fetching individuals list"); } } diff --git a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java index 11a942b5050..e08aeef5d17 100644 --- a/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java +++ b/health-services/individual/src/main/java/org/egov/individual/repository/IndividualRepository.java @@ -1,6 +1,17 @@ package org.egov.individual.repository; +import java.lang.reflect.Method; +import java.math.BigDecimal; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.data.query.builder.GenericQueryBuilder; import org.egov.common.data.query.builder.QueryFieldChecker; import org.egov.common.data.query.builder.SelectQueryBuilder; @@ -23,16 +34,6 @@ import org.springframework.stereotype.Repository; import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; -import org.springframework.util.StringUtils; - -import java.lang.reflect.Method; -import java.math.BigDecimal; -import java.time.Instant; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.stream.Collectors; import static org.egov.common.utils.CommonUtils.constructTotalCountCTEAndReturnResult; import static org.egov.common.utils.CommonUtils.getIdMethod; @@ -54,18 +55,25 @@ protected IndividualRepository(@Qualifier("individualProducer") Producer produc } public SearchResponse findById(List ids, String idColumn, Boolean includeDeleted) { - List objFound; - objFound = findInCache(ids).stream() - .filter(individual -> individual.getIsDeleted().equals(includeDeleted)) - .collect(Collectors.toList()); - if (!objFound.isEmpty()) { - Method idMethod = getIdMethod(objFound, idColumn); - ids.removeAll(objFound.stream() - .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) - .collect(Collectors.toList())); - if (ids.isEmpty()) { - return SearchResponse.builder().totalCount(Long.valueOf(objFound.size())).response(objFound).build(); + List objFound = new ArrayList<>(); + try { + objFound = findInCache(ids); + if (!includeDeleted) { + objFound = objFound.stream() + .filter(entity -> entity.getIsDeleted().equals(false)) + .collect(Collectors.toList()); + } + if (!objFound.isEmpty()) { + Method idMethod = getIdMethod(objFound, idColumn); + ids.removeAll(objFound.stream() + .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) + .collect(Collectors.toList())); + if (ids.isEmpty()) { + return SearchResponse.builder().totalCount(Long.valueOf(objFound.size())).response(objFound).build(); + } } + }catch (Exception e){ + log.info("Error occurred while reading from cache", ExceptionUtils.getStackTrace(e)); } String individualQuery = String.format(getQuery("SELECT * FROM individual WHERE %s IN (:ids)", diff --git a/health-services/individual/src/main/java/org/egov/individual/service/EnrichmentService.java b/health-services/individual/src/main/java/org/egov/individual/service/EnrichmentService.java index 188a5fe3af9..7ea9daff08e 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/EnrichmentService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/EnrichmentService.java @@ -1,5 +1,14 @@ package org.egov.individual.service; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.function.Predicate; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + import digit.models.coremodels.AuditDetails; import lombok.extern.slf4j.Slf4j; import org.egov.common.contract.request.RequestInfo; @@ -14,14 +23,6 @@ import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; -import java.util.stream.IntStream; - import static org.egov.common.utils.CommonUtils.collectFromList; import static org.egov.common.utils.CommonUtils.enrichForCreate; import static org.egov.common.utils.CommonUtils.enrichForDelete; @@ -229,6 +230,7 @@ private static Individual enrichWithSystemGeneratedIdentifier(Individual individ log.info("enriching individual with system generated identifier"); List identifiers = new ArrayList<>(); identifiers.add(Identifier.builder() + .clientReferenceId(UUID.randomUUID().toString()) .identifierType(SYSTEM_GENERATED) .identifierId(individual.getId()) .build()); diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualEncryptionService.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualEncryptionService.java index a80ff5de93a..ee7fe12030b 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualEncryptionService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualEncryptionService.java @@ -2,6 +2,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.models.Error; import org.egov.common.models.ErrorDetails; @@ -111,7 +112,7 @@ private void validateAadhaarUniqueness (List individuals, Individual individualsList = individualRepository.find(individualSearch,null, null,tenantId,null,false).getResponse(); } catch (Exception exception) { - log.error("database error occurred", exception); + log.error("database error occurred", ExceptionUtils.getStackTrace(exception)); throw new CustomException("DATABASE_ERROR", exception.getMessage()); } if (!CollectionUtils.isEmpty(individualsList)) { diff --git a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java index 4ce82e4246e..c700e51d4e8 100644 --- a/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java +++ b/health-services/individual/src/main/java/org/egov/individual/service/IndividualService.java @@ -13,6 +13,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.ds.Tuple; import org.egov.common.models.Error; @@ -153,7 +154,7 @@ public List create(IndividualBulkRequest request, boolean isBulk) { properties.getSaveIndividualTopic()); } } catch (CustomException exception) { - log.error("error occurred", exception); + log.error("error occurred", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validIndividuals, exception, SET_INDIVIDUALS); } @@ -266,7 +267,7 @@ public List update(IndividualBulkRequest request, boolean isBulk) { properties.getUpdateIndividualTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); + log.error("error occurred", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validIndividuals, exception, SET_INDIVIDUALS); } @@ -338,7 +339,7 @@ public SearchResponse search(IndividualSearch individualSearch, .filter(havingBoundaryCode(individualSearch.getBoundaryCode(), individualSearch.getWardCode())) .collect(Collectors.toList()); } catch (Exception exception) { - log.error("database error occurred", exception); + log.error("database error occurred", ExceptionUtils.getStackTrace(exception)); throw new CustomException("DATABASE_ERROR", exception.getMessage()); } //decrypt @@ -388,7 +389,7 @@ public List delete(IndividualBulkRequest request, boolean isBulk) { properties.getDeleteIndividualTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); + log.error("error occurred", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validIndividuals, exception, SET_INDIVIDUALS); } @@ -435,7 +436,7 @@ private void integrateWithUserService(IndividualBulkRequest request, encryptedIndividualList.size()); } } catch (Exception exception) { - log.error("error occurred while creating user", exception); + log.error("error occurred while creating user", ExceptionUtils.getStackTrace(exception)); } } } diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java index 3ab5536b9d1..872d11c9d2a 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java @@ -1,6 +1,7 @@ package org.egov.common.data.repository; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.data.query.builder.SelectQueryBuilder; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.producer.Producer; @@ -126,9 +127,11 @@ public List findById(List ids, Boolean includeDeleted, String columnN if (!objFound.isEmpty()) { Method idMethod = getIdMethod(objFound, columnName); Method isDeleted = getMethod("getIsDeleted", getObjClass(objFound)); - objFound = objFound.stream() - .filter(entity -> Objects.equals(ReflectionUtils.invokeMethod(isDeleted, entity), includeDeleted)) - .collect(Collectors.toList()); + if (!includeDeleted) { + objFound = objFound.stream() + .filter(entity -> Objects.equals(ReflectionUtils.invokeMethod(isDeleted, entity), false)) + .collect(Collectors.toList()); + } ids.removeAll(objFound.stream() .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) .collect(Collectors.toList())); @@ -201,7 +204,7 @@ protected void cacheByKey(List objects, String fieldName) { redisTemplate.expire(tableName, Long.parseLong(timeToLive), TimeUnit.SECONDS); } } catch (Exception exception) { - log.warn("Error while saving to cache: {}", exception.getMessage()); + log.warn("Error while saving to cache: {}", ExceptionUtils.getStackTrace(exception)); } } diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Address.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Address.java index 3f6469257f9..6bce525fa97 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Address.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Address.java @@ -55,7 +55,6 @@ public class Address { @JsonProperty("locationAccuracy") @DecimalMin("0") - @DecimalMax("10000") private Double locationAccuracy = null; @JsonProperty("type") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Field.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Field.java index 6fea19acbe4..95260a87d83 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Field.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/facility/Field.java @@ -1,5 +1,6 @@ package org.egov.common.models.facility; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.validation.constraints.NotNull; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Address.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Address.java index d6578c2808a..fe0c85041cb 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Address.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/household/Address.java @@ -57,7 +57,6 @@ public class Address { @JsonProperty("locationAccuracy") @DecimalMin("0") - @DecimalMax("10000") private Double locationAccuracy = null; @JsonProperty("type") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Address.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Address.java index 4367ad3057d..a6a6a067449 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Address.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/individual/Address.java @@ -77,7 +77,6 @@ public class Address { @DecimalMin("0") - @DecimalMax("10000") private Double locationAccuracy = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Address.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Address.java index dfefe72564d..33e05c90d14 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Address.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/product/Address.java @@ -68,7 +68,6 @@ public class Address { @DecimalMin("0") - @DecimalMax("10000") private Double locationAccuracy = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Address.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Address.java index 332c652ac33..a928b1cadbf 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Address.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Address.java @@ -57,7 +57,6 @@ public class Address { @JsonProperty("locationAccuracy") @DecimalMin("0") - @DecimalMax("10000") private Double locationAccuracy = null; @JsonProperty("type") diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskQuantity.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskQuantity.java new file mode 100644 index 00000000000..6fa7d16610b --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskQuantity.java @@ -0,0 +1,45 @@ +package org.egov.common.models.project; + + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.validation.annotation.Validated; + + +/** + * @author syed-egov + * POJO to capture the metadata of Task + */ +@Validated +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class TaskQuantity { + + @JsonProperty("id") + private List id = null; + + @JsonProperty("regex") + private String regex = null; + + @JsonProperty("errorMessage") + private String errorMessage = null; + + public TaskQuantity addProductVariantId(String id) { + if (this.id == null) { + this.id = new ArrayList<>(); + } + this.id.add(id); + return this; + } + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java index 3ea472c9683..8c798d1ef34 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskResource.java @@ -48,7 +48,7 @@ public class TaskResource { @JsonProperty("quantity") @NotNull - private Long quantity = null; + private Double quantity = null; @JsonProperty("isDelivered") @NotNull diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Address.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Address.java index 3a08cad9abc..dacc7c3c5b7 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Address.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/stock/Address.java @@ -52,7 +52,6 @@ public class Address { @JsonProperty("locationAccuracy") @DecimalMin("0") - @DecimalMax("10000") private Double locationAccuracy = null; @JsonProperty("type") diff --git a/health-services/project/src/main/java/org/egov/project/Constants.java b/health-services/project/src/main/java/org/egov/project/Constants.java index 42b730bbd11..91e1f824ae8 100644 --- a/health-services/project/src/main/java/org/egov/project/Constants.java +++ b/health-services/project/src/main/java/org/egov/project/Constants.java @@ -54,4 +54,6 @@ public interface Constants { String PROJECT_ID = "projectId"; + String TASK_QUANTITY = "taskQuantity"; + } diff --git a/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java b/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java index 34308dd587f..32c76154f2b 100644 --- a/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java +++ b/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java @@ -177,6 +177,9 @@ public class ProjectConfiguration { @Value("${project.mdms.module}") private String mdmsModule; + @Value("${task.mdms.module}") + private String taskMdmsModule; + @Value("${egov.location.hierarchy.type}") private String locationHierarchyType; diff --git a/health-services/project/src/main/java/org/egov/project/consumer/ProjectBeneficiaryConsumer.java b/health-services/project/src/main/java/org/egov/project/consumer/ProjectBeneficiaryConsumer.java index 2cc3309aedc..fcf11150c4e 100644 --- a/health-services/project/src/main/java/org/egov/project/consumer/ProjectBeneficiaryConsumer.java +++ b/health-services/project/src/main/java/org/egov/project/consumer/ProjectBeneficiaryConsumer.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.project.BeneficiaryBulkRequest; import org.egov.common.models.project.ProjectBeneficiary; import org.egov.project.service.ProjectBeneficiaryService; @@ -38,7 +39,7 @@ public List bulkCreate(Map consumerRecord, BeneficiaryBulkRequest request = objectMapper.convertValue(consumerRecord, BeneficiaryBulkRequest.class); return projectBeneficiaryService.create(request, true); } catch (Exception exception) { - log.error("error in project beneficiary consumer bulk create", exception); + log.error("error in project beneficiary consumer bulk create", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -50,7 +51,7 @@ public List bulkUpdate(Map consumerRecord, BeneficiaryBulkRequest request = objectMapper.convertValue(consumerRecord, BeneficiaryBulkRequest.class); return projectBeneficiaryService.update(request, true); } catch (Exception exception) { - log.error("error in project beneficiary consumer bulk update", exception); + log.error("error in project beneficiary consumer bulk update", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -62,7 +63,7 @@ public List bulkDelete(Map consumerRecord, BeneficiaryBulkRequest request = objectMapper.convertValue(consumerRecord, BeneficiaryBulkRequest.class); return projectBeneficiaryService.delete(request, true); } catch (Exception exception) { - log.error("error in project beneficiary consumer bulk delete", exception); + log.error("error in project beneficiary consumer bulk delete", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } diff --git a/health-services/project/src/main/java/org/egov/project/consumer/ProjectFacilityConsumer.java b/health-services/project/src/main/java/org/egov/project/consumer/ProjectFacilityConsumer.java index 2525e68bfbe..25049dda375 100644 --- a/health-services/project/src/main/java/org/egov/project/consumer/ProjectFacilityConsumer.java +++ b/health-services/project/src/main/java/org/egov/project/consumer/ProjectFacilityConsumer.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.project.ProjectFacility; import org.egov.common.models.project.ProjectFacilityBulkRequest; import org.egov.project.service.ProjectFacilityService; @@ -34,7 +35,7 @@ public List bulkCreate(Map consumerRecord, ProjectFacilityBulkRequest request = objectMapper.convertValue(consumerRecord, ProjectFacilityBulkRequest.class); return service.create(request, true); } catch (Exception exception) { - log.error("error in project facility consumer bulk create", exception); + log.error("error in project facility consumer bulk create", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -46,7 +47,7 @@ public List bulkUpdate(Map consumerRecord, ProjectFacilityBulkRequest request = objectMapper.convertValue(consumerRecord, ProjectFacilityBulkRequest.class); return service.update(request, true); } catch (Exception exception) { - log.error("error in project facility consumer bulk update", exception); + log.error("error in project facility consumer bulk update", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -58,7 +59,7 @@ public List bulkDelete(Map consumerRecord, ProjectFacilityBulkRequest request = objectMapper.convertValue(consumerRecord, ProjectFacilityBulkRequest.class); return service.delete(request, true); } catch (Exception exception) { - log.error("error in project facility consumer bulk delete", exception); + log.error("error in project facility consumer bulk delete", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } diff --git a/health-services/project/src/main/java/org/egov/project/consumer/ProjectResourceConsumer.java b/health-services/project/src/main/java/org/egov/project/consumer/ProjectResourceConsumer.java index d3ffa6100d6..d3801b3bec9 100644 --- a/health-services/project/src/main/java/org/egov/project/consumer/ProjectResourceConsumer.java +++ b/health-services/project/src/main/java/org/egov/project/consumer/ProjectResourceConsumer.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.project.ProjectResource; import org.egov.common.models.project.ProjectResourceBulkRequest; import org.egov.project.service.ProjectResourceService; @@ -35,7 +36,7 @@ public List bulkCreate(Map consumerRecord, ProjectResourceBulkRequest request = objectMapper.convertValue(consumerRecord, ProjectResourceBulkRequest.class); return service.create(request, true); } catch (Exception exception) { - log.error("error in project resource consumer bulk create", exception); + log.error("error in project resource consumer bulk create", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -47,7 +48,7 @@ public List bulkUpdate(Map consumerRecord, ProjectResourceBulkRequest request = objectMapper.convertValue(consumerRecord, ProjectResourceBulkRequest.class); return service.update(request, true); } catch (Exception exception) { - log.error("error in project resource consumer bulk update", exception); + log.error("error in project resource consumer bulk update", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -59,7 +60,7 @@ public List bulkDelete(Map consumerRecord, ProjectResourceBulkRequest request = objectMapper.convertValue(consumerRecord, ProjectResourceBulkRequest.class); return service.delete(request, true); } catch (Exception exception) { - log.error("error in project resource consumer bulk delete", exception); + log.error("error in project resource consumer bulk delete", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } diff --git a/health-services/project/src/main/java/org/egov/project/consumer/ProjectStaffConsumer.java b/health-services/project/src/main/java/org/egov/project/consumer/ProjectStaffConsumer.java index 168e8665cf1..21e50fbba89 100644 --- a/health-services/project/src/main/java/org/egov/project/consumer/ProjectStaffConsumer.java +++ b/health-services/project/src/main/java/org/egov/project/consumer/ProjectStaffConsumer.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.project.ProjectStaff; import org.egov.common.models.project.ProjectStaffBulkRequest; import org.egov.project.service.ProjectStaffService; @@ -34,7 +35,7 @@ public List bulkCreate(Map consumerRecord, ProjectStaffBulkRequest request = objectMapper.convertValue(consumerRecord, ProjectStaffBulkRequest.class); return service.create(request, true); } catch (Exception exception) { - log.error("error in project staff consumer bulk create", exception); + log.error("error in project staff consumer bulk create", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -46,7 +47,7 @@ public List bulkUpdate(Map consumerRecord, ProjectStaffBulkRequest request = objectMapper.convertValue(consumerRecord, ProjectStaffBulkRequest.class); return service.update(request, true); } catch (Exception exception) { - log.error("error in project staff consumer bulk update", exception); + log.error("error in project staff consumer bulk update", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -58,7 +59,7 @@ public List bulkDelete(Map consumerRecord, ProjectStaffBulkRequest request = objectMapper.convertValue(consumerRecord, ProjectStaffBulkRequest.class); return service.delete(request, true); } catch (Exception exception) { - log.error("error in project staff consumer bulk delete", exception); + log.error("error in project staff consumer bulk delete", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } diff --git a/health-services/project/src/main/java/org/egov/project/consumer/ProjectTaskConsumer.java b/health-services/project/src/main/java/org/egov/project/consumer/ProjectTaskConsumer.java index 21d56dd266b..aa2c9155cdb 100644 --- a/health-services/project/src/main/java/org/egov/project/consumer/ProjectTaskConsumer.java +++ b/health-services/project/src/main/java/org/egov/project/consumer/ProjectTaskConsumer.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskBulkRequest; import org.egov.project.service.ProjectTaskService; @@ -38,7 +39,7 @@ public List bulkCreate(Map consumerRecord, TaskBulkRequest request = objectMapper.convertValue(consumerRecord, TaskBulkRequest.class); return projectTaskService.create(request, true); } catch (Exception exception) { - log.error("error in project task consumer bulk create", exception); + log.error("error in project task consumer bulk create", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -50,7 +51,7 @@ public List bulkUpdate(Map consumerRecord, TaskBulkRequest request = objectMapper.convertValue(consumerRecord, TaskBulkRequest.class); return projectTaskService.update(request, true); } catch (Exception exception) { - log.error("error in project task consumer bulk update", exception); + log.error("error in project task consumer bulk update", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -62,7 +63,7 @@ public List bulkDelete(Map consumerRecord, TaskBulkRequest request = objectMapper.convertValue(consumerRecord, TaskBulkRequest.class); return projectTaskService.delete(request, true); } catch (Exception exception) { - log.error("error in project task consumer bulk delete", exception); + log.error("error in project task consumer bulk delete", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } diff --git a/health-services/project/src/main/java/org/egov/project/repository/ProjectBeneficiaryRepository.java b/health-services/project/src/main/java/org/egov/project/repository/ProjectBeneficiaryRepository.java index 3b879371d52..56d23bca00a 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/ProjectBeneficiaryRepository.java +++ b/health-services/project/src/main/java/org/egov/project/repository/ProjectBeneficiaryRepository.java @@ -89,9 +89,12 @@ public SearchResponse find(ProjectBeneficiarySearch househol } public SearchResponse findById(List ids, String columnName, Boolean includeDeleted) { - List objFound = findInCache(ids).stream() - .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) - .collect(Collectors.toList()); + List objFound = findInCache(ids); + if (!includeDeleted) { + objFound = objFound.stream() + .filter(entity -> entity.getIsDeleted().equals(false)) + .collect(Collectors.toList()); + } if (!objFound.isEmpty()) { Method idMethod = getIdMethod(objFound, columnName); ids.removeAll(objFound.stream() diff --git a/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java b/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java index d748602b7a4..3f5895633d3 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java +++ b/health-services/project/src/main/java/org/egov/project/repository/ProjectTaskRepository.java @@ -26,6 +26,7 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; import static org.egov.common.utils.CommonUtils.getIdList; @@ -55,7 +56,11 @@ public SearchResponse find(TaskSearch searchObject, Integer limit, Integer query = query.replace("id IN (:id)", "pt.id IN (:id)"); query = query.replace("clientReferenceId IN (:clientReferenceId)", "pt.clientReferenceId IN (:clientReferenceId)"); - query = query + " and pt.tenantId=:tenantId "; + if(CollectionUtils.isEmpty(whereFields)) { + query = query + " where pt.tenantId=:tenantId "; + } else { + query = query + " and pt.tenantId=:tenantId "; + } if (Boolean.FALSE.equals(includeDeleted)) { query = query + "and isDeleted=:isDeleted "; } @@ -105,9 +110,12 @@ private void fetchAndSetTaskResource(List taskList) { } public SearchResponse findById(List ids, String columnName, Boolean includeDeleted) { - List objFound = findInCache(ids).stream() - .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) - .collect(Collectors.toList()); + List objFound = findInCache(ids); + if (!includeDeleted) { + objFound = objFound.stream() + .filter(entity -> entity.getIsDeleted().equals(false)) + .collect(Collectors.toList()); + } if (!objFound.isEmpty()) { Method idMethod = getIdMethod(objFound, columnName); ids.removeAll(objFound.stream() diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TaskResourceRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TaskResourceRowMapper.java index bfb130d350b..87cab062d9c 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TaskResourceRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/TaskResourceRowMapper.java @@ -25,7 +25,7 @@ public TaskResource mapRow(ResultSet resultSet, int i) throws SQLException { .tenantId(resultSet.getString("tenantId")) .taskId(resultSet.getString("taskId")) .productVariantId(resultSet.getString("productVariantId")) - .quantity(resultSet.getLong("quantity")) + .quantity(resultSet.getDouble("quantity")) .isDelivered(resultSet.getBoolean("isDelivered")) .deliveryComment(resultSet.getString("reasonIfNotDelivered")) .clientReferenceId(resultSet.getString("clientReferenceId")) diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectBeneficiaryService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectBeneficiaryService.java index 21e60b12be7..73d70127632 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectBeneficiaryService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectBeneficiaryService.java @@ -7,6 +7,7 @@ import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.core.SearchResponse; @@ -127,7 +128,7 @@ public List create(BeneficiaryBulkRequest beneficiaryRequest log.info("successfully created project beneficiaries"); } } catch (Exception exception) { - log.error("error occurred while creating project beneficiaries: {}", exception.getMessage()); + log.error("error occurred while creating project beneficiaries: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(beneficiaryRequest, errorDetailsMap, validProjectBeneficiaries, exception, SET_PROJECT_BENEFICIARIES); } @@ -160,7 +161,7 @@ public List update(BeneficiaryBulkRequest beneficiaryRequest log.info("successfully updated bulk project beneficiaries"); } } catch (Exception exception) { - log.error("error occurred while updating project beneficiaries", exception); + log.error("error occurred while updating project beneficiaries", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(beneficiaryRequest, errorDetailsMap, validProjectBeneficiaries, exception, SET_PROJECT_BENEFICIARIES); } @@ -223,7 +224,7 @@ public List delete(BeneficiaryBulkRequest beneficiaryRequest log.info("successfully deleted entities"); } } catch (Exception exception) { - log.error("error occurred while deleting entities: {}", exception); + log.error("error occurred while deleting entities: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(beneficiaryRequest, errorDetailsMap, validProjectBeneficiaries, exception, SET_PROJECT_BENEFICIARIES); } diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectFacilityService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectFacilityService.java index a7baaecf912..f7628318789 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectFacilityService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectFacilityService.java @@ -1,6 +1,7 @@ package org.egov.project.service; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.project.ProjectFacility; @@ -121,7 +122,7 @@ public List create(ProjectFacilityBulkRequest request, boolean log.info("successfully created project facility"); } } catch (Exception exception) { - log.error("error occurred while creating project facility: {}", exception.getMessage()); + log.error("error occurred while creating project facility: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_PROJECT_FACILITIES); } @@ -155,7 +156,7 @@ public List update(ProjectFacilityBulkRequest request, boolean log.info("successfully updated bulk project facility"); } } catch (Exception exception) { - log.error("error occurred while updating project facility", exception); + log.error("error occurred while updating project facility", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_PROJECT_FACILITIES); } @@ -187,7 +188,7 @@ public List delete(ProjectFacilityBulkRequest request, boolean log.info("successfully deleted entities"); } } catch (Exception exception) { - log.error("error occurred while deleting entities: {}", exception); + log.error("error occurred while deleting entities: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_PROJECT_FACILITIES); } diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectResourceService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectResourceService.java index c99dc41448f..660efbd4814 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectResourceService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectResourceService.java @@ -1,6 +1,7 @@ package org.egov.project.service; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; @@ -105,7 +106,7 @@ public List create(ProjectResourceBulkRequest request, boolean log.info("successfully created project resource"); } } catch (Exception exception) { - log.error("error occurred while creating project resource: {}", exception.getMessage()); + log.error("error occurred while creating project resource: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_PROJECT_RESOURCE); } @@ -138,7 +139,7 @@ public List update(ProjectResourceBulkRequest request, boolean log.info("successfully created project resource"); } } catch (Exception exception) { - log.error("error occurred while creating project resource: {}", exception.getMessage()); + log.error("error occurred while creating project resource: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_PROJECT_RESOURCE); } @@ -171,7 +172,7 @@ public List delete(ProjectResourceBulkRequest request, boolean log.info("successfully deleted project resource"); } } catch (Exception exception) { - log.error("error occurred while deleting project resource: {}", exception.getMessage()); + log.error("error occurred while deleting project resource: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_PROJECT_RESOURCE); } diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java index 82733608c54..c600537a74e 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectStaffService.java @@ -1,6 +1,7 @@ package org.egov.project.service; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.project.ProjectStaff; @@ -131,7 +132,7 @@ public List create(ProjectStaffBulkRequest request, boolean isBulk log.info("successfully created project staff"); } } catch (Exception exception) { - log.error("error occurred while creating project staff: {}", exception.getMessage()); + log.error("error occurred while creating project staff: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_STAFF); } @@ -165,7 +166,7 @@ public List update(ProjectStaffBulkRequest request, boolean isBulk log.info("successfully updated bulk project staff"); } } catch (Exception exception) { - log.error("error occurred while updating project staff", exception); + log.error("error occurred while updating project staff", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_STAFF); } @@ -197,7 +198,7 @@ public List delete(ProjectStaffBulkRequest request, boolean isBulk log.info("successfully deleted entities"); } } catch (Exception exception) { - log.error("error occurred while deleting entities: {}", exception); + log.error("error occurred while deleting entities: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_STAFF); } diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java index ff59ee82446..12c8ea87062 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java @@ -7,6 +7,7 @@ import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.ds.Tuple; import org.egov.common.http.client.ServiceRequestClient; @@ -33,6 +34,8 @@ import org.egov.project.validator.task.PtProductVariantIdValidator; import org.egov.project.validator.task.PtProjectBeneficiaryIdValidator; import org.egov.project.validator.task.PtProjectIdValidator; +import org.egov.project.validator.task.PtIsResouceEmptyValidator; +import org.egov.project.validator.task.PtResourceQuantityValidator; import org.egov.project.validator.task.PtRowVersionValidator; import org.egov.project.validator.task.PtUniqueEntityValidator; import org.egov.project.validator.task.PtUniqueSubEntityValidator; @@ -74,12 +77,14 @@ public class ProjectTaskService { validator.getClass().equals(PtProjectIdValidator.class) || validator.getClass().equals(PtExistentEntityValidator.class) || validator.getClass().equals(PtIsResouceEmptyValidator.class) + || validator.getClass().equals(PtResourceQuantityValidator.class) || validator.getClass().equals(PtProjectBeneficiaryIdValidator.class) || validator.getClass().equals(PtProductVariantIdValidator.class); private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(PtProjectIdValidator.class) || validator.getClass().equals(PtIsResouceEmptyValidator.class) + || validator.getClass().equals(PtResourceQuantityValidator.class) || validator.getClass().equals(PtProjectBeneficiaryIdValidator.class) || validator.getClass().equals(PtProductVariantIdValidator.class) || validator.getClass().equals(PtNullIdValidator.class) @@ -134,7 +139,7 @@ public List create(TaskBulkRequest request, boolean isBulk) { log.info("successfully created project tasks"); } } catch (Exception exception) { - log.error("error occurred while creating project tasks: {}", exception.getMessage()); + log.error("error occurred while creating project tasks: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validTasks, exception, SET_TASKS); } @@ -166,7 +171,7 @@ public List update(TaskBulkRequest request, boolean isBulk) { log.info("successfully updated bulk project tasks"); } } catch (Exception exception) { - log.error("error occurred while updating project tasks", exception); + log.error("error occurred while updating project tasks", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validTasks, exception, SET_TASKS); } @@ -196,7 +201,7 @@ public List delete(TaskBulkRequest request, boolean isBulk) { projectTaskRepository.save(validTasks, projectConfiguration.getDeleteProjectTaskTopic()); } } catch (Exception exception) { - log.error("error occurred while deleting entities: {}", exception); + log.error("error occurred while deleting entities: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(request, errorDetailsMap, validTasks, exception, SET_TASKS); } @@ -245,7 +250,7 @@ public SearchResponse search(TaskSearch taskSearch, Integer limit, Integer return projectTaskRepository.find(taskSearch, limit, offset, tenantId, lastChangedSince, includeDeleted); } catch (QueryBuilderException e) { - log.error("error in building query", e); + log.error("error in building query", ExceptionUtils.getStackTrace(e)); throw new CustomException("ERROR_IN_QUERY", e.getMessage()); } } diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java index 182473417e0..6bea9a663b5 100644 --- a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java @@ -3,6 +3,7 @@ import digit.models.coremodels.AuditDetails; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.models.project.Document; import org.egov.common.models.project.Project; @@ -301,7 +302,7 @@ private List getIdList(RequestInfo requestInfo, String tenantId, String try { return idGenService.getIdList(requestInfo, tenantId, idKey, idformat, count); } catch (Exception exception) { - log.error("error while calling id gen service", exception); + log.error("error while calling id gen service", ExceptionUtils.getStackTrace(exception)); throw new CustomException("IDGEN_ERROR", String.format("error while calling id gen service for %s", idformat)); } diff --git a/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java b/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java index 2894a5aa5d6..74a4e2df8fa 100644 --- a/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java +++ b/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java @@ -6,6 +6,7 @@ import lombok.extern.slf4j.Slf4j; import net.minidev.json.JSONObject; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.tracer.model.CustomException; @@ -64,7 +65,7 @@ public void validateBoundaryDetails(Map> locations, String response = Optional.ofNullable(serviceRequestRepository.fetchResult(uri, RequestInfoWrapper.builder().requestInfo(requestInfo).build(), LinkedHashMap.class)); } catch (Exception e) { - log.error("error while calling boundary service", e); + log.error("error while calling boundary service", ExceptionUtils.getStackTrace(e)); throw new CustomException("BOUNDARY_ERROR", "error while calling boundary service"); } diff --git a/health-services/project/src/main/java/org/egov/project/util/MDMSUtils.java b/health-services/project/src/main/java/org/egov/project/util/MDMSUtils.java index 27300bff902..4de61e5ab79 100644 --- a/health-services/project/src/main/java/org/egov/project/util/MDMSUtils.java +++ b/health-services/project/src/main/java/org/egov/project/util/MDMSUtils.java @@ -10,6 +10,7 @@ import digit.models.coremodels.mdms.MdmsCriteriaReq; import digit.models.coremodels.mdms.ModuleDetail; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.project.Project; @@ -49,7 +50,7 @@ public Object mDMSCall(ProjectRequest request, String tenantId) { try { result = serviceRequestRepository.fetchResult(getMdmsSearchUrl(), mdmsCriteriaReq, LinkedHashMap.class); } catch (Exception e) { - log.error("error while calling mdms", e); + log.error("error while calling mdms", ExceptionUtils.getStackTrace(e)); throw new CustomException("MDMS_ERROR", "error while calling mdms"); } return result; diff --git a/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java b/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java index b314eb59fbf..8bebbfda738 100644 --- a/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java +++ b/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java @@ -22,9 +22,15 @@ public class ProjectConstants { public static final String TASK_NOT_ALLOWED_BENEFICIARY_REFUSED_RESOURCE_EMPTY_ERROR_MESSAGE = "Task not allowed as resources can not be provided when " + TaskStatus.BENEFICIARY_REFUSED; public static final String TASK_NOT_ALLOWED_RESOURCE_CANNOT_EMPTY_ERROR_MESSAGE = "Task not allowed as resources can not be empty when "; public static final String NUMBER_OF_SESSIONS = "numberOfSessions"; + public static final String OR = " OR "; + public enum TaskStatus { - BENEFICIARY_REFUSED("BENEFICIARY_REFUSED"); + BENEFICIARY_REFUSED("BENEFICIARY_REFUSED"), + BENEFICIARY_REFERRED("BENEFICIARY_REFERRED"), + BENEFICIARY_INELIGIBLE("BENEFICIARY_INELIGIBLE"), + BENEFICIARY_SICK("BENEFICIARY_SICK"), + BENEFICIARY_ABSENT("BENEFICIARY_ABSENT"); private String value; TaskStatus(String value) { diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/BeneficiaryValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/BeneficiaryValidator.java index 756f7875883..19c8454d63a 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/BeneficiaryValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/BeneficiaryValidator.java @@ -8,6 +8,7 @@ import digit.models.coremodels.mdms.MdmsCriteriaReq; import digit.models.coremodels.mdms.ModuleDetail; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; @@ -188,7 +189,7 @@ private void searchHouseholdBeneficiary( } } } catch (Exception e) { - log.error("error while fetching households list", e); + log.error("error while fetching households list", ExceptionUtils.getStackTrace(e)); beneficiaryList.forEach(b -> { Error error = getErrorForEntityWithNetworkError(); populateErrorDetails(b, error, errorDetailsMap); diff --git a/health-services/project/src/main/java/org/egov/project/validator/facility/PfFacilityIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/facility/PfFacilityIdValidator.java index 0733300cf59..bec1a7ffa89 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/facility/PfFacilityIdValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/facility/PfFacilityIdValidator.java @@ -1,6 +1,7 @@ package org.egov.project.validator.facility; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; @@ -98,7 +99,7 @@ private List validateFacilityIds(List entityIds, FacilityBulkResponse.class); return response.getFacilities().stream().map(Facility::getId).collect(Collectors.toList()); } catch (Exception e) { - log.error("error while fetching facility list", e); + log.error("error while fetching facility list", ExceptionUtils.getStackTrace(e)); projectFacilities.forEach(b -> { Error error = getErrorForEntityWithNetworkError(); populateErrorDetails(b, error, errorDetailsMap); diff --git a/health-services/project/src/main/java/org/egov/project/validator/staff/PsUserIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/staff/PsUserIdValidator.java index 4326859c0be..7491e024ec3 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/staff/PsUserIdValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/staff/PsUserIdValidator.java @@ -2,6 +2,7 @@ import digit.models.coremodels.UserSearchRequest; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.User; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; @@ -101,7 +102,7 @@ public Map> validate(ProjectStaffBulkRequest request) } } } catch (Exception exception) { - log.error("error while validating users", exception); + log.error("error while validating users", ExceptionUtils.getStackTrace(exception)); entities.stream().filter(notHavingErrors()).forEach(b -> { Error error = getErrorForEntityWithNetworkError(); populateErrorDetails(b, error, errorDetailsMap); diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java index f5d5cd42a77..4487d0ae5e4 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java @@ -36,17 +36,42 @@ public Map> validate(TaskBulkRequest request) { List entities = request.getTasks(); if(!entities.isEmpty()) { entities.forEach(task -> { - if(CollectionUtils.isEmpty(task.getResources()) && !ProjectConstants.TaskStatus.BENEFICIARY_REFUSED.toString().equals(task.getStatus())) { + if(CollectionUtils.isEmpty(task.getResources()) && + !(ProjectConstants.TaskStatus.BENEFICIARY_REFUSED.toString().equals(task.getStatus()) + || ProjectConstants.TaskStatus.BENEFICIARY_INELIGIBLE.toString().equals(task.getStatus()) + || ProjectConstants.TaskStatus.BENEFICIARY_REFERRED.toString().equals(task.getStatus()) + || ProjectConstants.TaskStatus.BENEFICIARY_SICK.toString().equals(task.getStatus()) + || ProjectConstants.TaskStatus.BENEFICIARY_ABSENT.toString().equals(task.getStatus()))) { /** * If the task resource is empty or null and task status is not BENEFICIARY_REFUSED it is invalid */ Error error = Error.builder() - .errorMessage(ProjectConstants.TASK_NOT_ALLOWED_RESOURCE_CANNOT_EMPTY_ERROR_MESSAGE + ProjectConstants.TaskStatus.BENEFICIARY_REFUSED) + .errorMessage(ProjectConstants.TASK_NOT_ALLOWED_RESOURCE_CANNOT_EMPTY_ERROR_MESSAGE + + ProjectConstants.TaskStatus.BENEFICIARY_REFUSED + + ProjectConstants.OR + ProjectConstants.TaskStatus.BENEFICIARY_INELIGIBLE + + ProjectConstants.OR + ProjectConstants.TaskStatus.BENEFICIARY_REFERRED + + ProjectConstants.OR + ProjectConstants.TaskStatus.BENEFICIARY_SICK + + ProjectConstants.OR + ProjectConstants.TaskStatus.BENEFICIARY_ABSENT) .errorCode(TASK_NOT_ALLOWED) .type(Error.ErrorType.NON_RECOVERABLE) - .exception(new CustomException(TASK_NOT_ALLOWED, ProjectConstants.TASK_NOT_ALLOWED_RESOURCE_CANNOT_EMPTY_ERROR_MESSAGE + ProjectConstants.TaskStatus.BENEFICIARY_REFUSED)).build(); + .exception(new CustomException(TASK_NOT_ALLOWED, + ProjectConstants.TASK_NOT_ALLOWED_RESOURCE_CANNOT_EMPTY_ERROR_MESSAGE + + ProjectConstants.TaskStatus.BENEFICIARY_REFUSED + + ProjectConstants.OR + + ProjectConstants.TaskStatus.BENEFICIARY_INELIGIBLE + + ProjectConstants.OR + + ProjectConstants.TaskStatus.BENEFICIARY_REFERRED + + ProjectConstants.OR + + ProjectConstants.TaskStatus.BENEFICIARY_SICK + + ProjectConstants.OR + + ProjectConstants.TaskStatus.BENEFICIARY_ABSENT)).build(); populateErrorDetails(task, error, errorDetailsMap); - } else if (!CollectionUtils.isEmpty(task.getResources()) && ProjectConstants.TaskStatus.BENEFICIARY_REFUSED.toString().equals(task.getStatus())) { + } else if (!CollectionUtils.isEmpty(task.getResources()) && + (ProjectConstants.TaskStatus.BENEFICIARY_REFUSED.toString().equals(task.getStatus()) + || ProjectConstants.TaskStatus.BENEFICIARY_INELIGIBLE.toString().equals(task.getStatus()) + || ProjectConstants.TaskStatus.BENEFICIARY_REFERRED.toString().equals(task.getStatus()) + || ProjectConstants.TaskStatus.BENEFICIARY_SICK.toString().equals(task.getStatus()) + || ProjectConstants.TaskStatus.BENEFICIARY_ABSENT.toString().equals(task.getStatus()))) { /** * If the task resource is not empty and task status is BENEFICIARY_REFUSED */ diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java new file mode 100644 index 00000000000..94b2aaea221 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java @@ -0,0 +1,234 @@ +package org.egov.project.validator.task; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.mdms.MasterDetail; +import digit.models.coremodels.mdms.MdmsCriteria; +import digit.models.coremodels.mdms.MdmsCriteriaReq; +import digit.models.coremodels.mdms.ModuleDetail; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.models.Error; +import org.egov.common.models.project.Task; +import org.egov.common.models.project.TaskBulkRequest; +import org.egov.common.models.project.TaskQuantity; +import org.egov.common.models.project.TaskResource; +import org.egov.common.service.MdmsService; +import org.egov.common.utils.CommonUtils; +import org.egov.common.validator.Validator; +import org.egov.project.config.ProjectConfiguration; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.project.Constants.INTERNAL_SERVER_ERROR; +import static org.egov.project.Constants.MDMS_RESPONSE; +import static org.egov.project.Constants.TASK_QUANTITY; +import static org.egov.project.util.ProjectConstants.TASK_NOT_ALLOWED; + +/** + * The PtResourceQuantityValidator class is responsible for validating the resource quantity of tasks in a bulk request. + * It checks whether the quantity adheres to the specified pattern defined in the project configuration. + * + * @author kanishq-egov + */ +@Component +@Order(value = 3) +@Slf4j +public class PtResourceQuantityValidator implements Validator { + private final ProjectConfiguration projectConfiguration; + + private final MdmsService mdmsService; + + /** + * Constructor for PtResourceQuantityValidator. + * + * @param projectConfiguration The configuration containing settings for the project module. + */ + public PtResourceQuantityValidator(ProjectConfiguration projectConfiguration, MdmsService mdmsService) { + this.projectConfiguration = projectConfiguration; + this.mdmsService = mdmsService; + } + + /** + * Validates the resource quantity of tasks in a bulk request. + * + * @param request The TaskBulkRequest containing a list of tasks. + * @return A map containing tasks with associated error details. + */ + @Override + public Map> validate(TaskBulkRequest request) { + // Map to store error details for each task + Map> errorDetailsMap = new HashMap<>(); + + // Extract the list of tasks from the request + List entities = request.getTasks(); + + // Check if the list is not empty + if(!entities.isEmpty()) { + entities.forEach(task -> { + List errors = new ArrayList<>(); + // Extract the list of task resources + List taskResources = task.getResources(); + for(TaskResource taskResource : taskResources){ + Error error = validateResourceQuantity(taskResource, request.getRequestInfo()); + if(error != null){ + errors.add(error); + } + } + if (!errors.isEmpty()){ + errorDetailsMap.put(task,errors); + } + }); + } + return errorDetailsMap; + } + + /** + * Validates the resource quantity for a single task resource. + * + * @param taskResource The task resource to be validated. + * @param requestInfo The request information. + * @return An Error object if validation fails, else null. + */ + private Error validateResourceQuantity(TaskResource taskResource, RequestInfo requestInfo){ + String productVariantId = taskResource.getProductVariantId(); + String regex = getRegex(productVariantId, taskResource.getTenantId(), requestInfo); + String errorMessage = getErrorMessage(productVariantId, taskResource.getTenantId(), requestInfo); + if(regex == null){ + log.error("Failed to fetch regex for product variant id: {}",productVariantId); + return Error.builder() + .errorMessage("Failed to fetch Regex") + .errorCode(TASK_NOT_ALLOWED) + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException(TASK_NOT_ALLOWED, "Failed to Fetch Regex Pattern")) + .build(); + } + if(!CommonUtils.isValidPattern(Double.toString(taskResource.getQuantity()),regex)){ + String productVariantIdErrorMessage = (errorMessage+ " for product variant id: "+ productVariantId); + return Error.builder() + .errorMessage(productVariantIdErrorMessage) + .errorCode(TASK_NOT_ALLOWED) + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException(TASK_NOT_ALLOWED,errorMessage)) + .build(); + } + return null; + } + + /** + * Retrieves the regex pattern from MDMS for the given product variant ID. + * + * @param productVariantId The ID of the product variant. + * @param tenantId The tenant ID. + * @param requestInfo The request information. + * @return The regex pattern if found, otherwise null. + */ + private String getRegex(String productVariantId,String tenantId, RequestInfo requestInfo){ + List mdmsData = mdmsCall(tenantId, requestInfo); + for(TaskQuantity data : mdmsData){ + if (data.getId().contains(productVariantId)){ + return data.getRegex(); + }else{ + log.error("Failed to fetch regex for product variant ID: {}", productVariantId); + } + } + return null; + } + + /** + * Retrieves the error message from MDMS for the given product variant ID. + * + * @param productVariantId The ID of the product variant. + * @param tenantId The tenant ID. + * @param requestInfo The request information. + * @return The error message if found, otherwise null. + */ + private String getErrorMessage(String productVariantId,String tenantId, RequestInfo requestInfo){ + List mdmsData = mdmsCall(tenantId, requestInfo); + for(TaskQuantity data : mdmsData){ + if (data.getId().contains(productVariantId)){ + return data.getErrorMessage(); + }else{ + log.error("Failed to fetch error message for product variant ID: {}", productVariantId); + } + } + return null; + } + + /** + * Makes a call to MDMS to fetch task quantity data. + * + * @param tenantId The tenant ID. + * @param requestInfo The request information. + * @return A list of TaskQuantity objects. + */ + private List mdmsCall(String tenantId, RequestInfo requestInfo){ + JsonNode response = fetchMdmsResponse(requestInfo,tenantId, TASK_QUANTITY, projectConfiguration.getTaskMdmsModule()); + return convertToTaskQuantityList(response); + } + + /** + * Converts JSON response to a list of TaskQuantity objects. + * + * @param jsonNode The JSON node containing task quantity data. + * @return A list of TaskQuantity objects. + */ + private List convertToTaskQuantityList(JsonNode jsonNode) { + JsonNode taskTypesNode = jsonNode.get(projectConfiguration.getTaskMdmsModule()).withArray(TASK_QUANTITY); + return new ObjectMapper().convertValue(taskTypesNode, new TypeReference>() { + }); + } + + /** + * Makes a call to MDMS service to fetch MDMS configuration data. + * + * @param requestInfo The request information. + * @param tenantId The tenant ID. + * @param name The name of the MDMS configuration. + * @param moduleName The name of the MDMS module. + * @return The MDMS response JSON node. + */ + private JsonNode fetchMdmsResponse(RequestInfo requestInfo, String tenantId, String name, String moduleName){ + MdmsCriteriaReq serviceRegistry = getMdmsRequest(requestInfo, tenantId, name, moduleName); + try{ + return mdmsService.fetchConfig(serviceRegistry, JsonNode.class).get(MDMS_RESPONSE); + } catch(Exception e){ + throw new CustomException(INTERNAL_SERVER_ERROR, "Error while fetching mdms config"); + } + } + + /** + * Prepares MDMS request object. + * + * @param requestInfo The request information. + * @param tenantId The tenant ID. + * @param masterName The name of the master. + * @param moduleName The name of the module. + * @return The MDMS criteria request object. + */ + private MdmsCriteriaReq getMdmsRequest(RequestInfo requestInfo, String tenantId, String masterName, String moduleName){ + MasterDetail masterDetail = new MasterDetail(); + masterDetail.setName(masterName); + List masterDetailsList = new ArrayList<>(); + masterDetailsList.add(masterDetail); + ModuleDetail moduleDetail = new ModuleDetail(); + moduleDetail.setMasterDetails(masterDetailsList); + moduleDetail.setModuleName(moduleName); + List moduleDetailList = new ArrayList<>(); + moduleDetailList.add(moduleDetail); + MdmsCriteria mdmsCriteria = new MdmsCriteria(); + mdmsCriteria.setTenantId(tenantId.split("\\.")[0]); + mdmsCriteria.setModuleDetails(moduleDetailList); + MdmsCriteriaReq mdmsCriteriaReq = new MdmsCriteriaReq(); + mdmsCriteriaReq.setMdmsCriteria(mdmsCriteria); + mdmsCriteriaReq.setRequestInfo(requestInfo); + return mdmsCriteriaReq; + } +} diff --git a/health-services/project/src/main/resources/application.properties b/health-services/project/src/main/resources/application.properties index caed5303565..f52ba8f6584 100644 --- a/health-services/project/src/main/resources/application.properties +++ b/health-services/project/src/main/resources/application.properties @@ -162,6 +162,7 @@ project.resource.consumer.bulk.update.topic=update-project-resource-bulk-topic project.resource.consumer.bulk.delete.topic=delete-project-resource-bulk-topic project.mdms.module=HCM-PROJECT-TYPES +task.mdms.module=HCM-TASK-QUANTITY-VALIDATION egov.location.hierarchy.type=ADMIN #---------Attendance-----------# diff --git a/health-services/project/src/test/java/org/egov/project/helper/TaskTestBuilder.java b/health-services/project/src/test/java/org/egov/project/helper/TaskTestBuilder.java index 8cec710de7b..ddda5a11de5 100644 --- a/health-services/project/src/test/java/org/egov/project/helper/TaskTestBuilder.java +++ b/health-services/project/src/test/java/org/egov/project/helper/TaskTestBuilder.java @@ -27,9 +27,9 @@ public TaskTestBuilder withTask() { .plannedStartDate(100L).plannedEndDate(101L) .address(AddressTestBuilder.builder().withAddress().build()) .resources(Arrays.asList(TaskResource.builder().tenantId("default").isDelivered(false) - .quantity(100L).productVariantId("v101").build(), + .quantity(100.0).productVariantId("v101").build(), TaskResource.builder().tenantId("default").isDelivered(false) - .quantity(100L).productVariantId("v101").build())) + .quantity(100.0).productVariantId("v101").build())) .projectId("some-id").createdBy("some-id") .createdDate(100L).status("status") .isDeleted(false).projectBeneficiaryId("some-id") diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java index c62c099415a..4e810216f06 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/ReferralManagementConsumer.java @@ -38,7 +38,7 @@ public void bulkCreate(Map consumerRecord, referralManagementService.create(request, true); } catch (Exception exception) { log.error("Error in Referral consumer bulk create", exception); - log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + log.error("Exception trace: {}", ExceptionUtils.getStackTrace(exception)); throw new CustomException("HCM_REFERRAL_MANAGEMENT_REFERRAL_CREATE", exception.getMessage()); } } @@ -51,7 +51,7 @@ public void bulkUpdate(Map consumerRecord, referralManagementService.update(request, true); } catch (Exception exception) { log.error("Error in Referral consumer bulk update", exception); - log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + log.error("Exception trace: {}", ExceptionUtils.getStackTrace(exception)); throw new CustomException("HCM_REFERRAL_MANAGEMENT_REFERRAL_UPDATE", exception.getMessage()); } } @@ -64,7 +64,7 @@ public void bulkDelete(Map consumerRecord, referralManagementService.delete(request, true); } catch (Exception exception) { log.error("Error in Referral consumer bulk delete", exception); - log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + log.error("Exception trace: {}", ExceptionUtils.getStackTrace(exception)); throw new CustomException("HCM_REFERRAL_MANAGEMENT_REFERRAL_DELETE", exception.getMessage()); } } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/SideEffectConsumer.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/SideEffectConsumer.java index e06cb3a03be..10cfbddb1db 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/SideEffectConsumer.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/consumer/SideEffectConsumer.java @@ -38,7 +38,7 @@ public void bulkCreate(Map consumerRecord, sideEffectService.create(request, true); } catch (Exception exception) { log.error("Error in Side Effect consumer bulk create", exception); - log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + log.error("Exception trace: {}", ExceptionUtils.getStackTrace(exception)); throw new CustomException("HCM_REFERRAL_MANAGEMENT_SIDE_EFFECT_CREATE", exception.getMessage()); } } @@ -51,7 +51,7 @@ public void bulkUpdate(Map consumerRecord, sideEffectService.update(request, true); } catch (Exception exception) { log.error("Error in Side Effect consumer bulk update", exception); - log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + log.error("Exception trace: {}", ExceptionUtils.getStackTrace(exception)); throw new CustomException("HCM_REFERRAL_MANAGEMENT_SIDE_EFFECT_UPDATE", exception.getMessage()); } } @@ -64,7 +64,7 @@ public void bulkDelete(Map consumerRecord, sideEffectService.delete(request, true); } catch (Exception exception) { log.error("Error in Side Effect consumer bulk delete", exception); - log.error("Exception trace: ", ExceptionUtils.getStackTrace(exception)); + log.error("Exception trace: {}", ExceptionUtils.getStackTrace(exception)); throw new CustomException("HCM_REFERRAL_MANAGEMENT_SIDE_EFFECT_DELETE", exception.getMessage()); } } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java index 1e9c0f8cce0..d2d43634030 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/HFReferralRepository.java @@ -118,9 +118,12 @@ public List find(HFReferralSearch searchObject, Integer limit, Integ */ public List findById(List ids, Boolean includeDeleted, String columnName) { // Find objects in the cache based on the provided IDs. - List objFound = findInCache(ids).stream() - .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) - .collect(Collectors.toList()); + List objFound = findInCache(ids); + if (!includeDeleted) { + objFound = objFound.stream() + .filter(entity -> entity.getIsDeleted().equals(false)) + .collect(Collectors.toList()); + } // If objects are found in the cache, check if there are any IDs remaining to be retrieved. if (!objFound.isEmpty()) { diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java index b4ae1ada5eb..aa002b560e1 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/ReferralRepository.java @@ -79,9 +79,12 @@ public SearchResponse find(ReferralSearch searchObject, Integer limit, } public SearchResponse findById(List ids, String columnName, Boolean includeDeleted) { - List objFound = findInCache(ids).stream() - .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) - .collect(Collectors.toList()); + List objFound = findInCache(ids); + if (!includeDeleted) { + objFound = objFound.stream() + .filter(entity -> entity.getIsDeleted().equals(false)) + .collect(Collectors.toList()); + } if (!objFound.isEmpty()) { Method idMethod = getIdMethod(objFound, columnName); ids.removeAll(objFound.stream() diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java index 8c4c6564116..06301c2c211 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/repository/SideEffectRepository.java @@ -108,9 +108,12 @@ public SearchResponse find(SideEffectSearch searchObject, Integer li } public List findById(List ids, String columnName, Boolean includeDeleted) { - List objFound = findInCache(ids).stream() - .filter(entity -> entity.getIsDeleted().equals(includeDeleted)) - .collect(Collectors.toList()); + List objFound = findInCache(ids); + if (!includeDeleted) { + objFound = objFound.stream() + .filter(entity -> entity.getIsDeleted().equals(false)) + .collect(Collectors.toList()); + } if (!objFound.isEmpty()) { Method idMethod = getIdMethod(objFound, columnName); ids.removeAll(objFound.stream() diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/FacilityService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/FacilityService.java index c687029b90d..993dca6757d 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/FacilityService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/FacilityService.java @@ -1,6 +1,7 @@ package org.egov.referralmanagement.service; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; @@ -76,7 +77,7 @@ public List validateFacilityIds(List entityIds, // Extract and return valid facility IDs from the response. return response.getFacilities().stream().map(Facility::getId).collect(Collectors.toList()); } catch (Exception e) { - log.error("error while fetching facility list", e); + log.error("error while fetching facility list: {}", ExceptionUtils.getStackTrace(e)); // Handle errors by associating errors with the respective entities. entities.forEach( entity -> { diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java index 25c41986eea..b14512d7551 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java @@ -8,6 +8,7 @@ import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.core.SearchResponse; @@ -29,6 +30,7 @@ import org.egov.referralmanagement.validator.RmProjectBeneficiaryIdValidator; import org.egov.referralmanagement.validator.RmRecipientIdValidator; import org.egov.referralmanagement.validator.RmReferrerIdValidator; +import org.egov.referralmanagement.validator.RmRowVersionValidator; import org.egov.referralmanagement.validator.RmSideEffectIdValidator; import org.egov.referralmanagement.validator.RmUniqueEntityValidator; import org.egov.tracer.model.CustomException; @@ -64,7 +66,8 @@ public class ReferralManagementService { || validator.getClass().equals(RmExistentEntityValidator.class) || validator.getClass().equals(RmReferrerIdValidator.class) || validator.getClass().equals(RmRecipientIdValidator.class) - || validator.getClass().equals(RmSideEffectIdValidator.class); + || validator.getClass().equals(RmSideEffectIdValidator.class) + || validator.getClass().equals(RmRowVersionValidator.class); private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(RmProjectBeneficiaryIdValidator.class) @@ -74,7 +77,8 @@ public class ReferralManagementService { || validator.getClass().equals(RmNullIdValidator.class) || validator.getClass().equals(RmIsDeletedValidator.class) || validator.getClass().equals(RmUniqueEntityValidator.class) - || validator.getClass().equals(RmNonExistentEntityValidator.class); + || validator.getClass().equals(RmNonExistentEntityValidator.class) + || validator.getClass().equals(RmRowVersionValidator.class); private final Predicate> isApplicableForDelete = validator -> validator.getClass().equals(RmNullIdValidator.class) @@ -113,7 +117,7 @@ public List create(ReferralBulkRequest referralRequest, boolean isBulk log.info("successfully created referrals"); } } catch (Exception exception) { - log.error("error occurred while creating referrals: {}", exception.getMessage()); + log.error("error occurred while creating referrals: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, exception, Constants.SET_REFERRALS); } @@ -146,7 +150,7 @@ public List update(ReferralBulkRequest referralRequest, boolean isBulk log.info("successfully updated bulk referrals"); } } catch (Exception exception) { - log.error("error occurred while updating referrals", exception); + log.error("error occurred while updating referrals: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, exception, Constants.SET_REFERRALS); } @@ -207,7 +211,7 @@ public List delete(ReferralBulkRequest referralRequest, boolean isBulk log.info("successfully deleted entities"); } } catch (Exception exception) { - log.error("error occurred while deleting entities: {}", exception); + log.error("error occurred while deleting entities: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(referralRequest, errorDetailsMap, validReferrals, exception, Constants.SET_REFERRALS); } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java index e5cfd43e00d..c437e392fcf 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/SideEffectService.java @@ -1,21 +1,13 @@ package org.egov.referralmanagement.service; -import static org.egov.common.utils.CommonUtils.getIdFieldName; -import static org.egov.common.utils.CommonUtils.getIdMethod; -import static org.egov.common.utils.CommonUtils.handleErrors; -import static org.egov.common.utils.CommonUtils.havingTenantId; -import static org.egov.common.utils.CommonUtils.includeDeleted; -import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; -import static org.egov.common.utils.CommonUtils.lastChangedSince; -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; - import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.Predicate; import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.core.SearchResponse; @@ -35,13 +27,22 @@ import org.egov.referralmanagement.validator.sideeffect.SeNullIdValidator; import org.egov.referralmanagement.validator.sideeffect.SeProjectBeneficiaryIdValidator; import org.egov.referralmanagement.validator.sideeffect.SeProjectTaskIdValidator; +import org.egov.referralmanagement.validator.sideeffect.SeRowVersionValidator; import org.egov.referralmanagement.validator.sideeffect.SeUniqueEntityValidator; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; -import lombok.extern.slf4j.Slf4j; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; /** * @author kanishq-egov @@ -68,11 +69,13 @@ public class SideEffectService { || validator.getClass().equals(SeNullIdValidator.class) || validator.getClass().equals(SeIsDeletedValidator.class) || validator.getClass().equals(SeUniqueEntityValidator.class) - || validator.getClass().equals(SeNonExistentEntityValidator.class); + || validator.getClass().equals(SeNonExistentEntityValidator.class) + || validator.getClass().equals(SeRowVersionValidator.class); private final Predicate> isApplicableForDelete = validator -> validator.getClass().equals(SeNullIdValidator.class) - || validator.getClass().equals(SeNonExistentEntityValidator.class); + || validator.getClass().equals(SeNonExistentEntityValidator.class) + || validator.getClass().equals(SeRowVersionValidator.class); @Autowired public SideEffectService( @@ -123,7 +126,7 @@ public List create(SideEffectBulkRequest sideEffectRequest, boolean log.info("successfully created side effects"); } } catch (Exception exception) { - log.error("error occurred while creating side effects: {}", exception.getMessage()); + log.error("error occurred while creating side effects: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(sideEffectRequest, errorDetailsMap, validSideEffects, exception, Constants.SET_SIDE_EFFECTS); } @@ -168,7 +171,7 @@ public List update(SideEffectBulkRequest sideEffectRequest, boolean log.info("successfully updated bulk side effects"); } } catch (Exception exception) { - log.error("error occurred while updating side effects", exception); + log.error("error occurred while updating side effects: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(sideEffectRequest, errorDetailsMap, validSideEffects, exception, Constants.SET_SIDE_EFFECTS); } @@ -252,7 +255,7 @@ public List delete(SideEffectBulkRequest sideEffectRequest, boolean log.info("successfully deleted entities"); } } catch (Exception exception) { - log.error("error occurred while deleting entities: {}", exception); + log.error("error occurred while deleting entities: {}", ExceptionUtils.getStackTrace(exception)); populateErrorDetails(sideEffectRequest, errorDetailsMap, validSideEffects, exception, Constants.SET_SIDE_EFFECTS); } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectBeneficiaryIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectBeneficiaryIdValidator.java index b10789f596e..2029562e8eb 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectBeneficiaryIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmProjectBeneficiaryIdValidator.java @@ -1,7 +1,13 @@ package org.egov.referralmanagement.validator; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; -import org.egov.common.data.query.exception.QueryBuilderException; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; import org.egov.common.models.project.BeneficiaryBulkResponse; @@ -16,14 +22,6 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmRowVersionValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmRowVersionValidator.java new file mode 100644 index 00000000000..7c45f467c6d --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmRowVersionValidator.java @@ -0,0 +1,83 @@ +package org.egov.referralmanagement.validator; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.Referral; +import org.egov.common.models.referralmanagement.ReferralBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.repository.ReferralRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.getEntitiesWithMismatchedRowVersion; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForRowVersionMismatch; + +/* +* +* Validator for checking row version consistency of Referral entities in a bulk request. +* It retrieves existing Referral entities from the repository, compares row versions, +* and populates error details for entities with mismatched row versions. +* +* @author syed-egov +* */ + +@Component +@Order(value = 5) +@Slf4j +public class RmRowVersionValidator implements Validator { + + private ReferralRepository referralRepository; + + @Autowired + public RmRowVersionValidator(ReferralRepository referralRepository) { + this.referralRepository = referralRepository; + } + + /* + * + * @param referralBulkRequest The bulk request containing Referral entities to be validated. + * @return A map containing Referral entities with associated error details + * for entities with mismatched row versions. + */ + + @Override + public Map> validate(ReferralBulkRequest referralBulkRequest) { + log.info("validating row version"); + // Map to store Referral entities with associated error details + Map> errorDetailsMap = new HashMap<>(); + // Get the method used for obtaining entity IDs + Method idMethod = getIdMethod(referralBulkRequest.getReferrals()); + // Create a map of entity IDs to Referral entities for entities without errors + Map iMap = getIdToObjMap(referralBulkRequest.getReferrals() + .stream() + .filter(notHavingErrors()) + .collect(Collectors.toList()),idMethod); + // Check if the map of IDs to Referral entities is not empty + if(!iMap.isEmpty()){ + List referralIds = new ArrayList<>(iMap.keySet()); + // Retrieve existing Referral entities from the repository + List existingReferrals = referralRepository.findById(referralIds,false,getIdFieldName(idMethod)); + // Identify entities with mismatched row versions + List entitiesWithMismatchedVersion = getEntitiesWithMismatchedRowVersion(iMap,existingReferrals,idMethod); + // Populate error details for entities with mismatched row versions + entitiesWithMismatchedVersion.forEach(referral -> { + Error error = getErrorForRowVersionMismatch(); + populateErrorDetails(referral, error, errorDetailsMap); + }); + } + return errorDetailsMap; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmSideEffectIdValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmSideEffectIdValidator.java index c0fa26bf55c..cd3d8c57ac1 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmSideEffectIdValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmSideEffectIdValidator.java @@ -1,5 +1,12 @@ package org.egov.referralmanagement.validator; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; import org.egov.common.models.referralmanagement.Referral; @@ -13,13 +20,6 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeRowVersionValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeRowVersionValidator.java new file mode 100644 index 00000000000..bc31412b97b --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeRowVersionValidator.java @@ -0,0 +1,86 @@ +package org.egov.referralmanagement.validator.sideeffect; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.referralmanagement.sideeffect.SideEffect; +import org.egov.common.models.referralmanagement.sideeffect.SideEffectBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.referralmanagement.repository.SideEffectRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.getEntitiesWithMismatchedRowVersion; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForRowVersionMismatch; + +/* +* +* Validator for checking row version consistency of SideEffect entities in a bulk request. +* It retrieves existing SideEffect entities from the repository, compares row versions, +* and populates error details for entities with mismatched row versions. +* +* @author syed-egov +* */ + +@Component +@Order(value = 5) +@Slf4j +public class SeRowVersionValidator implements Validator { + + private SideEffectRepository sideEffectRepository; + + @Autowired + public SeRowVersionValidator(SideEffectRepository sideEffectRepository) { + this.sideEffectRepository = sideEffectRepository; + } + + /* + * + * @param sideEffectBulkRequest The bulk request containing SideEffect entities to be validated. + * @return A map containing SideEffect entities with associated error details + * for entities with mismatched row versions. + * + */ + + @Override + public Map> validate(SideEffectBulkRequest sideEffectBulkRequest) { + log.info("validating row version"); + // Map to store SideEffect entities with associated error details + Map> errorDetailsMap = new HashMap<>(); + // Get the method used for obtaining entity IDs + Method idMethod = getIdMethod(sideEffectBulkRequest.getSideEffects()); + // Create a map of entity IDs to SideEffect entities for entities without errors + Map iMap = getIdToObjMap(sideEffectBulkRequest + .getSideEffects() + .stream() + .filter(notHavingErrors()) + .collect(Collectors.toList()),idMethod); + // Check if the map of IDs to SideEffect entities is not empty + if(!iMap.isEmpty()){ + List sideEffectIds = new ArrayList<>(iMap.keySet()); + // Retrieve existing SideEffect entities from the repository + List existingSideEffects = sideEffectRepository + .findById(sideEffectIds,false,getIdFieldName(idMethod)); + // Identify entities with mismatched row versions + List entitiesWithMismatchedRowVersion = getEntitiesWithMismatchedRowVersion(iMap, existingSideEffects, idMethod); + // Populate error details for entities with mismatched row versions + entitiesWithMismatchedRowVersion.forEach(sideEffect -> { + Error error = getErrorForRowVersionMismatch(); + populateErrorDetails(sideEffect, error, errorDetailsMap); + }); + } + return errorDetailsMap; + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java index 43f99f7cef2..90d4ffd633a 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeUniqueEntityValidator.java @@ -1,5 +1,10 @@ package org.egov.referralmanagement.validator.sideeffect; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; import org.egov.common.models.referralmanagement.sideeffect.SideEffect; @@ -8,12 +13,9 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import static org.egov.common.utils.CommonUtils.*; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; @Component diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/BeneficiaryDownsyncController.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/BeneficiaryDownsyncController.java index bd6a1a2ad2d..d780ef1cce0 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/BeneficiaryDownsyncController.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/web/controllers/BeneficiaryDownsyncController.java @@ -1,13 +1,16 @@ package org.egov.referralmanagement.web.controllers; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.annotations.ApiParam; import jakarta.validation.Valid; - +import lombok.extern.slf4j.Slf4j; import org.egov.common.models.referralmanagement.beneficiarydownsync.Downsync; import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncRequest; import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncResponse; import org.egov.common.utils.ResponseInfoFactory; import org.egov.referralmanagement.service.DownsyncService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; @@ -16,8 +19,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; -import io.swagger.annotations.ApiParam; - +@Slf4j @Controller @RequestMapping("/beneficiary-downsync") @Validated @@ -25,14 +27,18 @@ public class BeneficiaryDownsyncController { private DownsyncService downsyncService; + private ObjectMapper mapper; + @Autowired - BeneficiaryDownsyncController (DownsyncService downsyncService){ + BeneficiaryDownsyncController (DownsyncService downsyncService, @Qualifier("objectMapper") ObjectMapper objectMapper){ this.downsyncService = downsyncService; + this.mapper = objectMapper; } @PostMapping(value = "/v1/_get") public ResponseEntity getBeneficaryData (@ApiParam(value = "Capture details of Side Effect", required = true) @Valid @RequestBody DownsyncRequest request) { - + log.info("UserUUID: {}", request.getRequestInfo().getUserInfo().getUuid()); + log.info("Downsync RequestBody: {}", mapper.valueToTree(request).toString()); Downsync.builder(). downsyncCriteria(request.getDownsyncCriteria()) .build(); diff --git a/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/Producer.java b/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/Producer.java index 4a8c949fc08..44eb1742816 100644 --- a/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/Producer.java +++ b/health-services/resource-estimation-service/src/main/java/org/egov/processor/kafka/Producer.java @@ -5,6 +5,8 @@ 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 { diff --git a/health-services/stock/src/main/java/org/egov/stock/consumer/StockConsumer.java b/health-services/stock/src/main/java/org/egov/stock/consumer/StockConsumer.java index bfa250d6097..e5b6dcf68eb 100644 --- a/health-services/stock/src/main/java/org/egov/stock/consumer/StockConsumer.java +++ b/health-services/stock/src/main/java/org/egov/stock/consumer/StockConsumer.java @@ -1,7 +1,12 @@ package org.egov.stock.consumer; +import java.util.Collections; +import java.util.List; +import java.util.Map; + import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.stock.Stock; import org.egov.common.models.stock.StockBulkRequest; import org.egov.stock.service.StockService; @@ -10,10 +15,6 @@ import org.springframework.messaging.handler.annotation.Header; import org.springframework.stereotype.Component; -import java.util.Collections; -import java.util.List; -import java.util.Map; - @Component @Slf4j public class StockConsumer { @@ -33,7 +34,7 @@ public List bulkCreate(Map consumerRecord, StockBulkRequest request = objectMapper.convertValue(consumerRecord, StockBulkRequest.class); return service.create(request, true); } catch (Exception exception) { - log.error("error in stock consumer bulk create", exception); + log.error("error in stock consumer bulk create: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -45,7 +46,7 @@ public List bulkUpdate(Map consumerRecord, StockBulkRequest request = objectMapper.convertValue(consumerRecord, StockBulkRequest.class); return service.update(request, true); } catch (Exception exception) { - log.error("error in stock consumer bulk update", exception); + log.error("error in stock consumer bulk update: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -57,7 +58,7 @@ public List bulkDelete(Map consumerRecord, StockBulkRequest request = objectMapper.convertValue(consumerRecord, StockBulkRequest.class); return service.delete(request, true); } catch (Exception exception) { - log.error("error in stock consumer bulk delete", exception); + log.error("error in stock consumer bulk delete: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } diff --git a/health-services/stock/src/main/java/org/egov/stock/consumer/StockReconciliationConsumer.java b/health-services/stock/src/main/java/org/egov/stock/consumer/StockReconciliationConsumer.java index 336197b2c15..7695c176f08 100644 --- a/health-services/stock/src/main/java/org/egov/stock/consumer/StockReconciliationConsumer.java +++ b/health-services/stock/src/main/java/org/egov/stock/consumer/StockReconciliationConsumer.java @@ -1,7 +1,12 @@ package org.egov.stock.consumer; +import java.util.Collections; +import java.util.List; +import java.util.Map; + import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.models.stock.StockReconciliation; import org.egov.common.models.stock.StockReconciliationBulkRequest; import org.egov.stock.service.StockReconciliationService; @@ -10,10 +15,6 @@ import org.springframework.messaging.handler.annotation.Header; import org.springframework.stereotype.Component; -import java.util.Collections; -import java.util.List; -import java.util.Map; - @Component @Slf4j public class StockReconciliationConsumer { @@ -33,7 +34,7 @@ public List bulkCreate(Map consumerRecord, StockReconciliationBulkRequest request = objectMapper.convertValue(consumerRecord, StockReconciliationBulkRequest.class); return service.create(request, true); } catch (Exception exception) { - log.error("error in stock reconciliation consumer bulk create", exception); + log.error("error in stock reconciliation consumer bulk create: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -45,7 +46,7 @@ public List bulkUpdate(Map consumerRecord, StockReconciliationBulkRequest request = objectMapper.convertValue(consumerRecord, StockReconciliationBulkRequest.class); return service.update(request, true); } catch (Exception exception) { - log.error("error in stock reconciliation consumer bulk update", exception); + log.error("error in stock reconciliation consumer bulk update: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } @@ -57,7 +58,7 @@ public List bulkDelete(Map consumerRecord, StockReconciliationBulkRequest request = objectMapper.convertValue(consumerRecord, StockReconciliationBulkRequest.class); return service.delete(request, true); } catch (Exception exception) { - log.error("error in stock reconciliation consumer bulk delete", exception); + log.error("error in stock reconciliation consumer bulk delete: {}", ExceptionUtils.getStackTrace(exception)); return Collections.emptyList(); } } diff --git a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java index d8d417b4fc0..e413a3052ac 100644 --- a/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java +++ b/health-services/stock/src/main/java/org/egov/stock/repository/rowmapper/StockRowMapper.java @@ -1,5 +1,8 @@ package org.egov.stock.repository.rowmapper; +import java.sql.ResultSet; +import java.sql.SQLException; + import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import digit.models.coremodels.AuditDetails; @@ -12,9 +15,6 @@ import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; -import java.sql.ResultSet; -import java.sql.SQLException; - @Component public class StockRowMapper implements RowMapper { diff --git a/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java b/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java index 5d93a0ecfdd..2951b21e031 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/FacilityService.java @@ -1,20 +1,13 @@ package org.egov.stock.service; -import static org.egov.common.utils.CommonUtils.getIdList; -import static org.egov.common.utils.CommonUtils.getMethod; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.common.utils.ValidatorUtils.getErrorForEntityWithNetworkError; -import static org.egov.stock.Constants.GET_FACILITY_ID; -import static org.egov.stock.Constants.GET_REFERENCE_ID; -import static org.egov.stock.Constants.WAREHOUSE; - import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.Error; @@ -32,7 +25,12 @@ import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; -import lombok.extern.slf4j.Slf4j; +import static org.egov.common.utils.CommonUtils.getIdList; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForEntityWithNetworkError; +import static org.egov.stock.Constants.GET_FACILITY_ID; +import static org.egov.stock.Constants.GET_REFERENCE_ID; @Service @Slf4j @@ -55,7 +53,7 @@ public List validateFacilityIds(List entityIds, if (CollectionUtils.isEmpty(entityIds)) return Collections.emptyList(); - + FacilitySearchRequest facilitySearchRequest = FacilitySearchRequest.builder() .facility(FacilitySearch.builder().id(entityIds).build()) .requestInfo(requestInfo) @@ -71,7 +69,7 @@ public List validateFacilityIds(List entityIds, FacilityBulkResponse.class); return response.getFacilities().stream().map(Facility::getId).collect(Collectors.toList()); } catch (Exception e) { - log.error("error while fetching facility list", e); + log.error("error while fetching facility list: {}", ExceptionUtils.getStackTrace(e)); entities.forEach( stockEntity -> { Error error = getErrorForEntityWithNetworkError(); populateErrorDetails(stockEntity, error, errorDetailsMap); @@ -84,15 +82,15 @@ public Map> validateProjectFacilityMappings(List ent String tenantId, Map> errorDetailsMap, RequestInfo requestInfo) { - - + + List projectIds = getIdList(entities, getMethod(GET_REFERENCE_ID, entities.get(0).getClass())); List facilityIds = null; - + if (entities.get(0) instanceof StockReconciliation) { facilityIds = getIdList(entities, getMethod(GET_FACILITY_ID, entities.get(0).getClass())); } else if (entities.get(0) instanceof Stock) { - + facilityIds = new ArrayList<>(); for (T entity : entities) { @@ -106,7 +104,7 @@ public Map> validateProjectFacilityMappings(List ent } } } - + Integer searchLimit = projectIds.size() * facilityIds.size(); ProjectFacilitySearchRequest projectFacilitySearchRequest = ProjectFacilitySearchRequest.builder() @@ -122,13 +120,13 @@ public Map> validateProjectFacilityMappings(List ent + "&offset=0&tenantId=" + tenantId), projectFacilitySearchRequest, ProjectFacilityBulkResponse.class); - + return response.getProjectFacilities().stream() .collect(Collectors.groupingBy(projectFacility -> projectFacility.getProjectId(), Collectors.mapping(projectFacility -> projectFacility.getFacilityId(), Collectors.toList()))); - + } catch (Exception e) { - log.error("error while fetching project facility list", e); + log.error("error while fetching project facility list: {}", ExceptionUtils.getStackTrace(e)); entities.forEach(b -> { Error error = getErrorForEntityWithNetworkError(); populateErrorDetails(b, error, errorDetailsMap); diff --git a/health-services/stock/src/main/java/org/egov/stock/service/StockReconciliationService.java b/health-services/stock/src/main/java/org/egov/stock/service/StockReconciliationService.java index 1765e34c015..6c6801a5922 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/StockReconciliationService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/StockReconciliationService.java @@ -1,11 +1,19 @@ package org.egov.stock.service; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.stock.StockReconciliation; import org.egov.common.models.stock.StockReconciliationBulkRequest; import org.egov.common.models.stock.StockReconciliationRequest; +import org.egov.common.models.stock.StockReconciliationSearchRequest; import org.egov.common.validator.Validator; import org.egov.stock.config.StockReconciliationConfiguration; import org.egov.stock.repository.StockReconciliationRepository; @@ -19,16 +27,9 @@ import org.egov.stock.validator.stockreconciliation.SrReferenceIdValidator; import org.egov.stock.validator.stockreconciliation.SrRowVersionValidator; import org.egov.stock.validator.stockreconciliation.SrUniqueEntityValidator; -import org.egov.common.models.stock.StockReconciliationSearchRequest; import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.getIdMethod; import static org.egov.common.utils.CommonUtils.handleErrors; @@ -99,21 +100,21 @@ public List create(StockReconciliationBulkRequest request, isBulk); Map errorDetailsMap = tuple.getY(); - List validTasks = tuple.getX(); + List validEntities = tuple.getX(); try { - if (!validTasks.isEmpty()) { - log.info("processing {} valid entities", validTasks.size()); - enrichmentService.create(validTasks, request); - stockRepository.save(validTasks, configuration.getCreateStockReconciliationTopic()); + if (!validEntities.isEmpty()) { + log.info("processing {} valid entities", validEntities.size()); + enrichmentService.create(validEntities, request); + stockRepository.save(validEntities, configuration.getCreateStockReconciliationTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); - populateErrorDetails(request, errorDetailsMap, validTasks, exception, SET_STOCK_RECONCILIATION); + log.error("error occurred: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_STOCK_RECONCILIATION); } handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); log.info("completed create method for stock reconciliation"); - return validTasks; + return validEntities; } public StockReconciliation update(StockReconciliationRequest request) { @@ -131,22 +132,22 @@ public List update(StockReconciliationBulkRequest request, isBulk); Map errorDetailsMap = tuple.getY(); - List validTasks = tuple.getX(); + List validEntities = tuple.getX(); try { - if (!validTasks.isEmpty()) { - log.info("processing {} valid entities", validTasks.size()); - enrichmentService.update(validTasks, request); - stockRepository.save(validTasks, configuration.getUpdateStockReconciliationTopic()); + if (!validEntities.isEmpty()) { + log.info("processing {} valid entities", validEntities.size()); + enrichmentService.update(validEntities, request); + stockRepository.save(validEntities, configuration.getUpdateStockReconciliationTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); - populateErrorDetails(request, errorDetailsMap, validTasks, exception, SET_STOCK_RECONCILIATION); + log.error("error occurred: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_STOCK_RECONCILIATION); } handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); log.info("completed update method for stock reconciliation"); - return validTasks; + return validEntities; } public StockReconciliation delete(StockReconciliationRequest request) { @@ -164,21 +165,21 @@ public List delete(StockReconciliationBulkRequest request, isBulk); Map errorDetailsMap = tuple.getY(); - List validTasks = tuple.getX(); + List validEntities = tuple.getX(); try { - if (!validTasks.isEmpty()) { - log.info("processing {} valid entities", validTasks.size()); - enrichmentService.delete(validTasks, request); - stockRepository.save(validTasks, configuration.getDeleteStockReconciliationTopic()); + if (!validEntities.isEmpty()) { + log.info("processing {} valid entities", validEntities.size()); + enrichmentService.delete(validEntities, request); + stockRepository.save(validEntities, configuration.getDeleteStockReconciliationTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); - populateErrorDetails(request, errorDetailsMap, validTasks, exception, SET_STOCK_RECONCILIATION); + log.error("error occurred: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_STOCK_RECONCILIATION); } handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); log.info("completed delete method for stock reconciliation"); - return validTasks; + return validEntities; } public List search(StockReconciliationSearchRequest request, diff --git a/health-services/stock/src/main/java/org/egov/stock/service/StockService.java b/health-services/stock/src/main/java/org/egov/stock/service/StockService.java index 97ac13ff46b..6a26da44ced 100644 --- a/health-services/stock/src/main/java/org/egov/stock/service/StockService.java +++ b/health-services/stock/src/main/java/org/egov/stock/service/StockService.java @@ -7,6 +7,7 @@ import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; import org.egov.common.ds.Tuple; import org.egov.common.models.ErrorDetails; import org.egov.common.models.stock.Stock; @@ -26,7 +27,7 @@ import org.egov.stock.validator.stock.SRowVersionValidator; import org.egov.stock.validator.stock.SSenderIdReceiverIdEqualsValidator; import org.egov.stock.validator.stock.SUniqueEntityValidator; -import org.egov.stock.validator.stock.StocktransferPartiesValidator; +import org.egov.stock.validator.stock.SStockTransferPartiesValidator; import org.springframework.stereotype.Service; import org.springframework.util.ReflectionUtils; @@ -60,7 +61,7 @@ public class StockService { validator -> validator.getClass().equals(SProductVariantIdValidator.class) || validator.getClass().equals(SExistentEntityValidator.class) || validator.getClass().equals(SSenderIdReceiverIdEqualsValidator.class) - || validator.getClass().equals(StocktransferPartiesValidator.class) + || validator.getClass().equals(SStockTransferPartiesValidator.class) || validator.getClass().equals(SReferenceIdValidator.class); private final Predicate> isApplicableForUpdate = @@ -72,7 +73,7 @@ public class StockService { || validator.getClass().equals(SUniqueEntityValidator.class) || validator.getClass().equals(SReferenceIdValidator.class) || validator.getClass().equals(SSenderIdReceiverIdEqualsValidator.class) - || validator.getClass().equals(StocktransferPartiesValidator.class); + || validator.getClass().equals(SStockTransferPartiesValidator.class); private final Predicate> isApplicableForDelete = validator -> validator.getClass().equals(SNonExistentValidator.class) @@ -99,21 +100,21 @@ public List create(StockBulkRequest request, boolean isBulk) { isApplicableForCreate, request, SET_STOCK, GET_STOCK, VALIDATION_ERROR, isBulk); Map errorDetailsMap = tuple.getY(); - List validTasks = tuple.getX(); + List validEntities = tuple.getX(); try { - if (!validTasks.isEmpty()) { - log.info("processing {} valid entities", validTasks.size()); - enrichmentService.create(validTasks, request); - stockRepository.save(validTasks, configuration.getCreateStockTopic()); + if (!validEntities.isEmpty()) { + log.info("processing {} valid entities", validEntities.size()); + enrichmentService.create(validEntities, request); + stockRepository.save(validEntities, configuration.getCreateStockTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); - populateErrorDetails(request, errorDetailsMap, validTasks, exception, SET_STOCK); + log.error("error occurred: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_STOCK); } handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); log.info("completed create method for stock"); - return validTasks; + return validEntities; } public Stock update(StockRequest request) { @@ -129,21 +130,21 @@ public List update(StockBulkRequest request, boolean isBulk) { isApplicableForUpdate, request, SET_STOCK, GET_STOCK, VALIDATION_ERROR, isBulk); Map errorDetailsMap = tuple.getY(); - List validTasks = tuple.getX(); + List validEntities = tuple.getX(); try { - if (!validTasks.isEmpty()) { - log.info("processing {} valid entities", validTasks.size()); - enrichmentService.update(validTasks, request); - stockRepository.save(validTasks, configuration.getUpdateStockTopic()); + if (!validEntities.isEmpty()) { + log.info("processing {} valid entities", validEntities.size()); + enrichmentService.update(validEntities, request); + stockRepository.save(validEntities, configuration.getUpdateStockTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); - populateErrorDetails(request, errorDetailsMap, validTasks, exception, SET_STOCK); + log.error("error occurred: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_STOCK); } handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); log.info("completed update method for stock"); - return validTasks; + return validEntities; } public Stock delete(StockRequest request) { @@ -159,21 +160,21 @@ public List delete(StockBulkRequest request, boolean isBulk) { isApplicableForDelete, request, SET_STOCK, GET_STOCK, VALIDATION_ERROR, isBulk); Map errorDetailsMap = tuple.getY(); - List validTasks = tuple.getX(); + List validEntities = tuple.getX(); try { - if (!validTasks.isEmpty()) { - log.info("processing {} valid entities", validTasks.size()); - enrichmentService.delete(validTasks, request); - stockRepository.save(validTasks, configuration.getDeleteStockTopic()); + if (!validEntities.isEmpty()) { + log.info("processing {} valid entities", validEntities.size()); + enrichmentService.delete(validEntities, request); + stockRepository.save(validEntities, configuration.getDeleteStockTopic()); } } catch (Exception exception) { - log.error("error occurred", exception); - populateErrorDetails(request, errorDetailsMap, validTasks, exception, SET_STOCK); + log.error("error occurred: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validEntities, exception, SET_STOCK); } handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); log.info("completed delete method for stock"); - return validTasks; + return validEntities; } public List search(StockSearchRequest stockSearchRequest, diff --git a/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java b/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java index b46431fe018..d71f92cda2d 100644 --- a/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java +++ b/health-services/stock/src/main/java/org/egov/stock/util/ValidatorUtil.java @@ -1,23 +1,12 @@ package org.egov.stock.util; -import static org.egov.common.utils.CommonUtils.getIdToObjMap; -import static org.egov.common.utils.CommonUtils.getMethod; -import static org.egov.common.utils.CommonUtils.getObjClass; -import static org.egov.common.utils.CommonUtils.getTenantId; -import static org.egov.common.utils.CommonUtils.notHavingErrors; -import static org.egov.common.utils.CommonUtils.populateErrorDetails; -import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentRelatedEntity; -import static org.egov.stock.Constants.GET_REQUEST_INFO; -import static org.egov.stock.Constants.NO_PROJECT_FACILITY_MAPPING_EXISTS; -import static org.egov.stock.Constants.STAFF; -import static org.egov.stock.Constants.WAREHOUSE; - import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import digit.models.coremodels.UserSearchRequest; import org.egov.common.contract.request.RequestInfo; import org.egov.common.ds.Tuple; import org.egov.common.models.Error; @@ -30,7 +19,15 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.ReflectionUtils; -import digit.models.coremodels.UserSearchRequest; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.getObjClass; +import static org.egov.common.utils.CommonUtils.getTenantId; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentRelatedEntity; +import static org.egov.stock.Constants.GET_REQUEST_INFO; +import static org.egov.stock.Constants.NO_PROJECT_FACILITY_MAPPING_EXISTS; public class ValidatorUtil { @@ -49,7 +46,8 @@ public static Map> validateFacilityIds(R request, Map entityIds = new ArrayList<>(eMap.keySet()); List existingFacilityIds = facilityService.validateFacilityIds(entityIds, validEntities, tenantId, errorDetailsMap, requestInfo); - List invalidEntities = validEntities.stream().filter(notHavingErrors()) + List invalidEntities = validEntities.stream() + .filter(notHavingErrors()) .filter(entity -> !existingFacilityIds .contains((String) ReflectionUtils.invokeMethod(idMethod, entity))) .collect(Collectors.toList()); diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/StocktransferPartiesValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SStockTransferPartiesValidator.java similarity index 88% rename from health-services/stock/src/main/java/org/egov/stock/validator/stock/StocktransferPartiesValidator.java rename to health-services/stock/src/main/java/org/egov/stock/validator/stock/SStockTransferPartiesValidator.java index 10ee33cf1f1..7be98ea1199 100644 --- a/health-services/stock/src/main/java/org/egov/stock/validator/stock/StocktransferPartiesValidator.java +++ b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SStockTransferPartiesValidator.java @@ -23,14 +23,14 @@ @Component @Order(value = 7) @Slf4j -public class StocktransferPartiesValidator implements Validator { +public class SStockTransferPartiesValidator implements Validator { private final FacilityService facilityService; private UserService userService; @Autowired - public StocktransferPartiesValidator(FacilityService facilityService, UserService userService) { + public SStockTransferPartiesValidator(FacilityService facilityService, UserService userService) { this.facilityService = facilityService; this.userService = userService; } diff --git a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ProjectTaskIndexV1.java b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ProjectTaskIndexV1.java index 5bcccb84f71..6e504ad3ec7 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ProjectTaskIndexV1.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/models/downstream/ProjectTaskIndexV1.java @@ -28,7 +28,7 @@ public class ProjectTaskIndexV1 { @JsonProperty("productVariant") private String productVariant; @JsonProperty("quantity") - private Long quantity; + private Double quantity; @JsonProperty("deliveredTo") private String deliveredTo; @JsonProperty("isDelivered") @@ -59,6 +59,4 @@ public class ProjectTaskIndexV1 { private Long lastModifiedTime; @JsonProperty("isDeleted") private boolean isDeleted; - @JsonProperty("status") - private String status; } diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectService.java index e6c997a2dd6..c0970a51a6d 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectService.java @@ -235,36 +235,6 @@ public List getProducts(String tenantId, String projectTypeId) { return convertToProjectTypeList(response); } - /** - * Retrieves the beneficiary type for a given project ID and tenant ID. - * - * @param projectId The ID of the project. - * @param tenantId The ID of the tenant. - * @return The beneficiary type as a String. If not found, returns an empty string. - */ - public String getBeneficiaryType(String projectId, String tenantId) { - // Fetch the project details using the provided project ID and tenant ID - Project project = getProject(projectId, tenantId); - - // Construct a JSONPath filter to locate the beneficiary type within the project details - String filter = "$[?(@.id == '" + project.getProjectTypeId() + "')].beneficiaryType"; - - // Create a RequestInfo object with user information for making the MDMS request - RequestInfo requestInfo = RequestInfo.builder() - .userInfo(User.builder().uuid("transformer-uuid").build()) - .build(); - - // Fetch the MDMS response based on the constructed filter - JsonNode response = fetchMdmsResponse(requestInfo, tenantId, PROJECT_TYPES, - transformerProperties.getMdmsModule(), filter); - - // Convert the MDMS response to a list of beneficiary types - List beneficiaryTypeList = convertToProjectTypeList(response); - - // Return the first beneficiary type if the list is not empty; otherwise, return an empty string - return !CollectionUtils.isEmpty(beneficiaryTypeList) ? beneficiaryTypeList.get(0) : ""; - } - private JsonNode fetchMdmsResponse(RequestInfo requestInfo, String tenantId, String name, String moduleName, String filter) { MdmsCriteriaReq serviceRegistry = getMdmsRequest(requestInfo, tenantId, name, moduleName, filter); diff --git a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java index f10ebb90e5e..286b416649f 100644 --- a/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java +++ b/health-services/transformer/src/main/java/org/egov/transformer/service/ProjectTaskTransformationService.java @@ -9,13 +9,10 @@ import org.egov.transformer.service.transformer.Transformer; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import org.springframework.util.CollectionUtils; -import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; -import java.util.UUID; import java.util.stream.Collectors; @Slf4j @@ -78,74 +75,34 @@ public List transform(Task task) { } log.info("boundary labels {}", boundaryLabelToNameMap.toString()); Map finalBoundaryLabelToNameMap = boundaryLabelToNameMap; - String beneficiaryType = projectService.getBeneficiaryType(task.getProjectId(), task.getTenantId()); - - List taskResourceIndex = null; - // Check if the task's resources list is not null and not empty - if(!CollectionUtils.isEmpty(task.getResources())) { - taskResourceIndex = task.getResources().stream().map(r -> - ProjectTaskIndexV1.builder() - .id(r.getId()) - .taskId(task.getId()) - .taskType("DELIVERY") - .projectId(task.getProjectId()) - .startDate(task.getActualStartDate()) - .endDate(task.getActualEndDate()) - .productVariant(r.getProductVariantId()) - .isDelivered(r.getIsDelivered()) - .quantity(r.getQuantity()) - .status(task.getStatus()) - .deliveredTo(beneficiaryType) - .deliveryComments(r.getDeliveryComment()) - .province(finalBoundaryLabelToNameMap != null ? finalBoundaryLabelToNameMap.get(properties.getProvince()) : null) - .district(finalBoundaryLabelToNameMap != null ? finalBoundaryLabelToNameMap.get(properties.getDistrict()) : null) - .administrativeProvince(finalBoundaryLabelToNameMap != null ? - finalBoundaryLabelToNameMap.get(properties.getAdministrativeProvince()) : null) - .locality(finalBoundaryLabelToNameMap != null ? finalBoundaryLabelToNameMap.get(properties.getLocality()) : null) - .village(finalBoundaryLabelToNameMap != null ? finalBoundaryLabelToNameMap.get(properties.getVillage()) : null) - .latitude(task.getAddress().getLatitude()) - .longitude(task.getAddress().getLongitude()) - .createdTime(task.getAuditDetails().getCreatedTime()) - .createdBy(task.getAuditDetails().getCreatedBy()) - .lastModifiedTime(task.getAuditDetails().getLastModifiedTime()) - .lastModifiedBy(task.getAuditDetails().getLastModifiedBy()) - .isDeleted(task.getIsDeleted()) - .build() - ).collect(Collectors.toList()); - } else { - taskResourceIndex = new ArrayList<>(); - taskResourceIndex.add( - ProjectTaskIndexV1.builder() - .id(UUID.randomUUID().toString()) - .taskId(task.getId()) - .taskType("DELIVERY") - .projectId(task.getProjectId()) - .startDate(task.getActualStartDate()) - .endDate(task.getActualEndDate()) - .productVariant(null) - .isDelivered(false) - .status(task.getStatus()) - .quantity(null) - .deliveredTo(beneficiaryType) - .deliveryComments(null) - .province(finalBoundaryLabelToNameMap != null ? finalBoundaryLabelToNameMap.get(properties.getProvince()) : null) - .district(finalBoundaryLabelToNameMap != null ? finalBoundaryLabelToNameMap.get(properties.getDistrict()) : null) - .administrativeProvince(finalBoundaryLabelToNameMap != null ? - finalBoundaryLabelToNameMap.get(properties.getAdministrativeProvince()) : null) - .locality(finalBoundaryLabelToNameMap != null ? finalBoundaryLabelToNameMap.get(properties.getLocality()) : null) - .village(finalBoundaryLabelToNameMap != null ? finalBoundaryLabelToNameMap.get(properties.getVillage()) : null) - .latitude(task.getAddress().getLatitude()) - .longitude(task.getAddress().getLongitude()) - .createdTime(task.getAuditDetails().getCreatedTime()) - .createdBy(task.getAuditDetails().getCreatedBy()) - .lastModifiedTime(task.getAuditDetails().getLastModifiedTime()) - .lastModifiedBy(task.getAuditDetails().getLastModifiedBy()) - .isDeleted(task.getIsDeleted()) - .build() - ); - } - - return taskResourceIndex; + return task.getResources().stream().map(r -> + ProjectTaskIndexV1.builder() + .id(r.getId()) + .taskId(task.getId()) + .taskType("DELIVERY") + .projectId(task.getProjectId()) + .startDate(task.getActualStartDate()) + .endDate(task.getActualEndDate()) + .productVariant(r.getProductVariantId()) + .isDelivered(r.getIsDelivered()) + .quantity(r.getQuantity()) + .deliveredTo("HOUSEHOLD") + .deliveryComments(r.getDeliveryComment()) + .province(finalBoundaryLabelToNameMap != null ? finalBoundaryLabelToNameMap.get(properties.getProvince()) : null) + .district(finalBoundaryLabelToNameMap != null ? finalBoundaryLabelToNameMap.get(properties.getDistrict()) : null) + .administrativeProvince(finalBoundaryLabelToNameMap != null ? + finalBoundaryLabelToNameMap.get(properties.getAdministrativeProvince()) : null) + .locality(finalBoundaryLabelToNameMap != null ? finalBoundaryLabelToNameMap.get(properties.getLocality()) : null) + .village(finalBoundaryLabelToNameMap != null ? finalBoundaryLabelToNameMap.get(properties.getVillage()) : null) + .latitude(task.getAddress().getLatitude()) + .longitude(task.getAddress().getLongitude()) + .createdTime(task.getAuditDetails().getCreatedTime()) + .createdBy(task.getAuditDetails().getCreatedBy()) + .lastModifiedTime(task.getAuditDetails().getLastModifiedTime()) + .lastModifiedBy(task.getAuditDetails().getLastModifiedBy()) + .isDeleted(task.getIsDeleted()) + .build() + ).collect(Collectors.toList()); } } } From 8208b6fc8fd39dfa4f6cde11e77f1aabb8606a3f Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Mon, 12 Aug 2024 17:00:37 +0530 Subject: [PATCH 272/283] hcm v1.5 : dev to master (#855) * Hlm 6385 irs changes (#841) * HLM-6385: added changes for IRS activity track and closed household concepts * HLM-6385: added changes for IRS activity track and closed household concepts, added db migration script, validations for closed household * HLM-6385: added changes for location tracking * HLM-6385: added changes for location points * HLM-6385: added clientReferenceId and tenantId in LocationPoint, updated Location_capture model * HLM-6385, HCMPRE-46: Updated changes as per design review * HLM-6385, HCMPRE-46: Added Location capture changes * HLM-6385, HCMPRE-46: Added UserAction changes * HLM-6385, HCMPRE-46: updated common models, replaced digit models with service-common * Revert "HLM-6385, HCMPRE-46: updated common models, replaced digit models with service-common" This reverts commit 6abdea41edc35ce8fe9efe298438c559a664136e. * HLM-6385, HCMPRE-46: updated table informations and columns for migration scripts * reverting BoundaryUtil change * reverting BoundaryUtil changes * HLM-6385, HCMPRE-46: updated validators and IRSConsumer * HLM-6385, HCMPRE-46: updated validators * HLM-6385, HCMPRE-46: updated project configuration * HLM-6385, HCMPRE-49: updated models to have isDeleted as it is required in common utils enrichment code * HLM-6385, HCMPRE-46: updated the projectid field, added notnull annotation * HLM-6385, HCMPRE-46: updated all the changes related to enrichment * HLM-6385, HCMPRE-46: made action field notnull * HLM-6385, HCMPRE-46: updated locationCapture and userAction with mandatory latitude, longitude, locationAccuracy fields * HLM-6385, HCMPRE-46: updated locationCapture and userAction with mandatory latitude, longitude, locationAccuracy fields, HCMPRE-116, HCMPRE-117 * HLM-6385, HCMPRE-46: updated locationCapture and userAction with mandatory latitude, longitude, locationAccuracy fields, HCMPRE-116, HCMPRE-117, added in services * HLM-6385, HCMPRE-46: removed outdated changes from Task.java * removed all user location models * Refactored from LocationCapture model to UserAction and packges from irs to useraction * HLM-6385 - lat/long irs name changes * HLM Downsync Incremental product changes pull from impel (#831) * HLM Downsync Incremental product changes pull from impel * HLM removed impel specific changes * renamed Project type filter code constant * HLM updated beneficiary based search * HLM updated downsync search, cycles is required only when it is smc based campaign * HCM - removed project task resource quantity validator * HLM updated downsync logic as per review comments * HCMPRE-216 : Added Administration failed status for validation when task resource is empty or when status is ADMINISTRATION_FAILED * HCMPRE-216: updated task status * HCMPRE-216: changed to ADMINISTRATION_FAILED * HLM-6385: updated with code review comments * HLM-6385: added changes as per review comments, and added correct logs wherever required. * HLM-6385: code review comments addressed. * HLM-6385: review comment added for error handling on LocationCaptureRepository * HLM-6385: another batch of coderabbitai code review comments addressed. * HLM-6385: added more logs in repository for useraction and location capture * HLM-6385: updated the code as per code review comments from @kavi-egov --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Holash Chand * Hcmpre 240 (#846) * HLM closed household status * HCMPRE-240: validate no resource task status scenario with configurable statuses * HCMPRE-240: fixed issues related to string trimming * HLM fixed rowversion referral bug, mis placement of rowversion validator * HCMPRE-240: code review changes * HCMPRE-242: updated for null resources and address check * HCMPRE-242: added for proper null check * HCMPRE-242: added checks for task resource where ever applicable * HCMPRE-242: updated taskstatus to enum from string * HCMPRE-242, HCMPRE-240: renamed task's status field to taskStatus field, as there is contradiction with EgovModel status field * HCMPRE-242: fixed dupcalite entity cache issue for existing entity validation during bulk create * HCMPRE-242: updated project test case for taskStatus field contraints changes : not null * HCMPRE-242: fix generic repository code * HCMPRE-242: added taskstatus migration script * HCMPRE-240: updated PtIsResourceEmptyValidator, for task status * HLM-242: added changes as per code review * Revert "HCMPRE-242: added taskstatus migration script", and removed status field from EgovModel, and rename TaskStatus to status This reverts commit 7caf0c43241154bdabc97bc20c876b86d984fdb6. * HCMPRE-240: FIXED all task status reference --------- Co-authored-by: sivajiganesh-dev * HLM rowmapper issue in household, referral fixed (#848) * HLM rowmapper issue in household, referral fixed * HCMPRE-255: updated the changes for household * reverted local changes commit by mistake * added logic for cascading project date updates (#834) * added logic for cascading project date updates * updated application.properties * refactored logic for using ProjectRequest pojo to send message to kafka instead of Ancestor and Descendant Projects pojo * added comments and enhanced search project logic * made public back to private * made more concise the method in project service separated create project map logic * separated concerns of update based on action whether null or updateProjectDates * updated action logic for just test purpose * updated version of health-service-models library * update logic * updated final logic for cascading update project dates based on flag in project request * reverted config * reverted config 2 * added multiple line comments * udpated error messages * HLM fixed issues in useraction existent entity validator (#850) * HLM fixed issues in useraction existent entity validator * updated after code review comments * updated version for hcm v1.5 release (#852) * updated version for hcm v1.5 release * HLM updated the code as per code review from code rabbit * HCMPRE-209: updated code review comments and code documentation --------- Co-authored-by: kavi_elrey <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: Holash Chand Co-authored-by: sivajiganesh-dev Co-authored-by: nitish-egov <137176807+nitish-egov@users.noreply.github.com> --- health-services/household/pom.xml | 2 +- .../java/org/egov/household/Constants.java | 2 +- .../validators/HmExistentEntityValidator.java | 47 ++- .../household/HExistentEntityValidator.java | 47 ++- health-services/individual/pom.xml | 2 +- .../validators/IExistentEntityValidator.java | 48 ++- health-services/libraries/docker-compose.yml | 67 ---- .../health-services-common/CHANGELOG.md | 3 + .../libraries/health-services-common/pom.xml | 2 +- .../data/repository/GenericRepository.java | 19 ++ .../health-services-models/CHANGELOG.md | 6 + .../libraries/health-services-models/pom.xml | 2 +- .../egov/common/models/core/EgovModel.java | 3 - .../common/models/project/ProjectRequest.java | 4 + .../org/egov/common/models/project/Task.java | 17 +- .../common/models/project/TaskStatus.java | 99 ++++++ .../common/models/project/UserActionEnum.java | 33 ++ .../models/project/useraction/UserAction.java | 109 ++++++ .../useraction/UserActionBulkRequest.java | 64 ++++ .../useraction/UserActionBulkResponse.java | 70 ++++ .../project/useraction/UserActionSearch.java | 55 +++ .../useraction/UserActionSearchRequest.java | 44 +++ health-services/project/CHANGELOG.md | 2 + health-services/project/pom.xml | 6 +- .../main/java/org/egov/project/Constants.java | 8 + .../project/config/ProjectConfiguration.java | 33 ++ .../project/consumer/UserActionConsumer.java | 103 ++++++ .../repository/LocationCaptureRepository.java | 135 ++++++++ .../repository/UserActionRepository.java | 139 ++++++++ .../rowmapper/LocationCaptureRowMapper.java | 91 +++++ .../rowmapper/ProjectTaskRowMapper.java | 3 +- .../rowmapper/UserActionRowMapper.java | 94 +++++ .../service/LocationCaptureService.java | 222 ++++++++++++ .../egov/project/service/ProjectService.java | 204 ++++++++++- .../project/service/ProjectTaskService.java | 8 +- .../project/service/UserActionService.java | 213 ++++++++++++ .../service/enrichment/ProjectEnrichment.java | 188 +++++++++- .../ProjectTaskEnrichmentService.java | 29 +- .../UserActionEnrichmentService.java | 67 ++++ .../org/egov/project/util/BoundaryUtil.java | 2 +- .../egov/project/util/ProjectConstants.java | 30 +- .../egov/project/util/ProjectServiceUtil.java | 62 ++++ .../PbExistentEntityValidator.java | 64 ++-- .../task/PtExistentEntityValidator.java | 67 ++-- .../task/PtIsResouceEmptyValidator.java | 57 ++-- .../task/PtNonExistentEntityValidator.java | 8 +- .../task/PtResourceQuantityValidator.java | 11 +- .../useraction/UaBoundaryValidator.java | 125 +++++++ .../useraction/UaExistentEntityValidator.java | 99 ++++++ .../UaNonExistentEntityValidator.java | 96 ++++++ .../useraction/UaNullIdValidator.java | 27 ++ .../useraction/UaProjectIdValidator.java | 96 ++++++ .../useraction/UaRowVersionValidator.java | 69 ++++ .../LocationCaptureController.java | 130 +++++++ .../web/controllers/UserActionController.java | 162 +++++++++ .../src/main/resources/application.properties | 13 + .../V20240711175300__user_location_ddl.sql | 23 ++ .../main/V20240711175500__user_action_ddl.sql | 28 ++ .../egov/project/helper/TaskTestBuilder.java | 8 +- .../referralmanagement/CHANGELOG.md | 4 + health-services/referralmanagement/pom.xml | 4 +- .../egov/referralmanagement/Constants.java | 6 + .../ReferralManagementConfiguration.java | 6 + .../service/DownsyncService.java | 323 +++++++++++------- .../service/MasterDataService.java | 129 +++++++ .../service/ReferralManagementService.java | 6 +- .../validator/RmExistentEntityValidator.java | 62 ++-- .../HfrExistentEntityValidator.java | 56 +-- .../sideeffect/SeExistentEntityValidator.java | 48 ++- health-services/stock/pom.xml | 2 +- .../stock/SExistentEntityValidator.java | 44 ++- .../SrExistentEntityValidator.java | 45 ++- 72 files changed, 3671 insertions(+), 531 deletions(-) delete mode 100644 health-services/libraries/docker-compose.yml create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskStatus.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserActionEnum.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserAction.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkRequest.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkResponse.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearch.java create mode 100644 health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearchRequest.java create mode 100644 health-services/project/src/main/java/org/egov/project/consumer/UserActionConsumer.java create mode 100644 health-services/project/src/main/java/org/egov/project/repository/LocationCaptureRepository.java create mode 100644 health-services/project/src/main/java/org/egov/project/repository/UserActionRepository.java create mode 100644 health-services/project/src/main/java/org/egov/project/repository/rowmapper/LocationCaptureRowMapper.java create mode 100644 health-services/project/src/main/java/org/egov/project/repository/rowmapper/UserActionRowMapper.java create mode 100644 health-services/project/src/main/java/org/egov/project/service/LocationCaptureService.java create mode 100644 health-services/project/src/main/java/org/egov/project/service/UserActionService.java create mode 100644 health-services/project/src/main/java/org/egov/project/service/enrichment/UserActionEnrichmentService.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/useraction/UaBoundaryValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/useraction/UaExistentEntityValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/useraction/UaNonExistentEntityValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/useraction/UaNullIdValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/useraction/UaProjectIdValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/validator/useraction/UaRowVersionValidator.java create mode 100644 health-services/project/src/main/java/org/egov/project/web/controllers/LocationCaptureController.java create mode 100644 health-services/project/src/main/java/org/egov/project/web/controllers/UserActionController.java create mode 100644 health-services/project/src/main/resources/db/migration/main/V20240711175300__user_location_ddl.sql create mode 100644 health-services/project/src/main/resources/db/migration/main/V20240711175500__user_action_ddl.sql create mode 100644 health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java diff --git a/health-services/household/pom.xml b/health-services/household/pom.xml index 1d59cc57c94..955934b5e1a 100644 --- a/health-services/household/pom.xml +++ b/health-services/household/pom.xml @@ -45,7 +45,7 @@ org.egov.common health-services-common - 1.0.17-SNAPSHOT + 1.0.18-SNAPSHOT org.egov.common diff --git a/health-services/household/src/main/java/org/egov/household/Constants.java b/health-services/household/src/main/java/org/egov/household/Constants.java index da512e39234..0ce22b8bb8d 100644 --- a/health-services/household/src/main/java/org/egov/household/Constants.java +++ b/health-services/household/src/main/java/org/egov/household/Constants.java @@ -23,7 +23,7 @@ public interface Constants { String INDIVIDUAL_ALREADY_MEMBER_OF_HOUSEHOLD = "INDIVIDUAL_ALREADY_MEMBER_OF_HOUSEHOLD"; - String INDIVIDUAL_ALREADY_MEMBER_OF_HOUSEHOLD_MESSAGE = "individual is already member od household"; + String INDIVIDUAL_ALREADY_MEMBER_OF_HOUSEHOLD_MESSAGE = "individual is already member of household"; String INDIVIDUAL_NOT_FOUND = "INDIVIDUAL_NOT_FOUND"; diff --git a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmExistentEntityValidator.java b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmExistentEntityValidator.java index 1e335cd753e..cc9eb6c12d7 100644 --- a/health-services/household/src/main/java/org/egov/household/household/member/validators/HmExistentEntityValidator.java +++ b/health-services/household/src/main/java/org/egov/household/household/member/validators/HmExistentEntityValidator.java @@ -15,8 +15,8 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; @@ -45,39 +45,52 @@ public HmExistentEntityValidator(HouseholdMemberRepository householdMemberReposi /** * Validates the existence of entities with the given client reference IDs. + * This method checks if any of the HouseholdMember entities in the request already exist in the database, + * based on their client reference IDs. If an entity is found to exist, an error is added to the error details map. * * @param request The bulk request containing HouseholdMember entities. - * @return A map containing HouseholdMember entities and their associated error details. + * @return A map containing HouseholdMember entities and their associated error details, if any. */ @Override public Map> validate(HouseholdMemberBulkRequest request) { - // Map to hold HouseholdMember entities and their error details + // Map to hold HouseholdMember entities and their associated error details Map> errorDetailsMap = new HashMap<>(); + // Get the list of HouseholdMember entities from the request List entities = request.getHouseholdMembers(); - // Extract client reference IDs from HouseholdMember entities without errors + + // Extract client reference IDs from HouseholdMember entities that do not have errors List clientReferenceIdList = entities.stream() - .filter(notHavingErrors()) - .map(HouseholdMember::getClientReferenceId) - .collect(Collectors.toList()); + .filter(notHavingErrors()) // Filter out entities that already have errors + .map(HouseholdMember::getClientReferenceId) // Map to client reference IDs + .collect(Collectors.toList()); // Collect the IDs into a list + // Create a search object for querying entities by client reference IDs HouseholdMemberSearch householdSearch = HouseholdMemberSearch.builder() - .clientReferenceId(clientReferenceIdList) + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search .build(); - // Check if the client reference ID list is not empty + + // Create a map of client reference ID to HouseholdMember entity for easy lookup + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + + // Check if the client reference ID list is not empty before querying the database if (!CollectionUtils.isEmpty(clientReferenceIdList)) { // Query the repository to find existing entities by client reference IDs - List existentEntities = householdMemberRepository.findById( - clientReferenceIdList, - getIdFieldName(householdSearch), - Boolean.FALSE).getResponse(); - // For each existing entity, populate error details for uniqueness - existentEntities.forEach(entity -> { + List existingClientReferenceIds = + householdMemberRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, populate error details for uniqueness + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation Error error = getErrorForUniqueEntity(); - populateErrorDetails(entity, error, errorDetailsMap); + // Populate error details for the HouseholdMember entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); }); } + + // Return the map containing HouseholdMember entities and their associated error details return errorDetailsMap; } - } diff --git a/health-services/household/src/main/java/org/egov/household/validators/household/HExistentEntityValidator.java b/health-services/household/src/main/java/org/egov/household/validators/household/HExistentEntityValidator.java index 57162432093..33253089919 100644 --- a/health-services/household/src/main/java/org/egov/household/validators/household/HExistentEntityValidator.java +++ b/health-services/household/src/main/java/org/egov/household/validators/household/HExistentEntityValidator.java @@ -15,8 +15,8 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; @@ -24,6 +24,7 @@ /** * Validator class for checking the existence of entities with the given client reference IDs. * This validator checks if the provided household entities already exist in the database based on their client reference IDs. + * * @author kanishq-egov */ @Component @@ -44,38 +45,52 @@ public HExistentEntityValidator(HouseholdRepository householdRepository) { /** * Validates the existence of entities with the given client reference IDs. + * This method checks if any of the household entities in the request already exist in the database, + * based on their client reference IDs. If an entity is found to exist, an error is added to the error details map. * * @param request The bulk request containing household entities. - * @return A map containing household entities and their associated error details. + * @return A map containing household entities and their associated error details, if any. */ @Override public Map> validate(HouseholdBulkRequest request) { - // Map to hold household entities and their error details + // Map to hold household entities and their associated error details Map> errorDetailsMap = new HashMap<>(); + // Get the list of household entities from the request List entities = request.getHouseholds(); - // Extract client reference IDs from household entities without errors + + // Extract client reference IDs from household entities that do not have errors List clientReferenceIdList = entities.stream() - .filter(notHavingErrors()) - .map(Household::getClientReferenceId) - .collect(Collectors.toList()); + .filter(notHavingErrors()) // Filter out entities that already have errors + .map(Household::getClientReferenceId) // Map to client reference IDs + .collect(Collectors.toList()); // Collect the IDs into a list + + // Create a map of client reference ID to Household entity for easy lookup + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + // Create a search object for querying entities by client reference IDs HouseholdSearch householdSearch = HouseholdSearch.builder() - .clientReferenceId(clientReferenceIdList) + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search .build(); - // Check if the client reference ID list is not empty + + // Check if the client reference ID list is not empty before querying the database if (!CollectionUtils.isEmpty(clientReferenceIdList)) { // Query the repository to find existing entities by client reference IDs - List existentEntities = householdRepository.findById( - clientReferenceIdList, - getIdFieldName(householdSearch), - Boolean.FALSE).getResponse(); - // For each existing entity, populate error details for uniqueness - existentEntities.forEach(entity -> { + List existingClientReferenceIds = + householdRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, populate error details for uniqueness + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation Error error = getErrorForUniqueEntity(); - populateErrorDetails(entity, error, errorDetailsMap); + // Populate error details for the household entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); }); } + + // Return the map containing household entities and their associated error details return errorDetailsMap; } diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index f739e08e736..ab7767c7206 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -53,7 +53,7 @@ org.egov.common health-services-common - 1.0.17-SNAPSHOT + 1.0.18-SNAPSHOT org.egov.common diff --git a/health-services/individual/src/main/java/org/egov/individual/validators/IExistentEntityValidator.java b/health-services/individual/src/main/java/org/egov/individual/validators/IExistentEntityValidator.java index a5f75eaa0b8..39bb06f6ed8 100644 --- a/health-services/individual/src/main/java/org/egov/individual/validators/IExistentEntityValidator.java +++ b/health-services/individual/src/main/java/org/egov/individual/validators/IExistentEntityValidator.java @@ -15,8 +15,8 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; @@ -24,6 +24,7 @@ /** * Validator class for checking the existence of entities with the given client reference IDs. * This validator checks if the provided individual entities already exist in the database based on their client reference IDs. + * * @author kanishq-egov */ @Component @@ -44,40 +45,53 @@ public IExistentEntityValidator(IndividualRepository individualRepository) { /** * Validates the existence of entities with the given client reference IDs. + * This method checks if any of the individual entities in the request already exist in the database, + * based on their client reference IDs. If an entity is found to exist, an error is added to the error details map. * * @param request The bulk request containing individual entities. - * @return A map containing individual entities and their associated error details. + * @return A map containing individual entities and their associated error details, if any. */ @Override public Map> validate(IndividualBulkRequest request) { - // Map to hold individual entities and their error details + // Map to hold individual entities and their associated error details Map> errorDetailsMap = new HashMap<>(); + // Get the list of individual entities from the request List entities = request.getIndividuals(); - // Extract client reference IDs from individual entities without errors + + // Extract client reference IDs from individual entities that do not have errors List clientReferenceIdList = entities.stream() - .filter(notHavingErrors()) - .map(Individual::getClientReferenceId) - .collect(Collectors.toList()); + .filter(notHavingErrors()) // Filter out entities that already have errors + .map(Individual::getClientReferenceId) // Map to client reference IDs + .collect(Collectors.toList()); // Collect the IDs into a list + + // Create a map of client reference ID to Individual entity for easy lookup + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + // Create a search object for querying entities by client reference IDs IndividualSearch individualSearch = IndividualSearch.builder() - .clientReferenceId(clientReferenceIdList) + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search .build(); - // Check if the client reference ID list is not empty + + // Check if the client reference ID list is not empty before querying the database if (!CollectionUtils.isEmpty(clientReferenceIdList)) { // Query the repository to find existing entities by client reference IDs - List existentEntities = individualRepository.findById( - clientReferenceIdList, - getIdFieldName(individualSearch), - Boolean.FALSE).getResponse(); - // For each existing entity, populate error details for uniqueness - existentEntities.forEach(entity -> { + List existingClientReferenceIds = + individualRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, populate error details for uniqueness + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation Error error = getErrorForUniqueEntity(); - populateErrorDetails(entity, error, errorDetailsMap); + // Populate error details for the individual entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); }); } + + // Return the map containing individual entities and their associated error details return errorDetailsMap; } } - diff --git a/health-services/libraries/docker-compose.yml b/health-services/libraries/docker-compose.yml deleted file mode 100644 index fea4de2e4ca..00000000000 --- a/health-services/libraries/docker-compose.yml +++ /dev/null @@ -1,67 +0,0 @@ -version: '2' -services: - zookeeper: - image: 'confluentinc/cp-zookeeper:latest' - container_name: zookeeper - environment: - ZOOKEEPER_CLIENT_PORT: 2181 - ZOOKEEPER_TICK_TIME: 2000 - ports: - - '2181:2181' - kafka: - image: 'confluentinc/cp-kafka:latest' - container_name: kafka - depends_on: - - zookeeper - ports: - - '9092:9092' - environment: - KAFKA_BROKER_ID: 1 - KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 - KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://127.0.0.1:9092 - KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT - KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT - KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 - schema-registry: - image: confluentinc/cp-schema-registry:4.1.1 - hostname: schema-registry - ports: - - "38081:38081" - depends_on: - - kafka - environment: - SCHEMA_REGISTRY_KAFKASTORE_CONNECTION_URL: zookeeper:2181 - SCHEMA_REGISTRY_HOST_NAME: schema-registry - SCHEMA_REGISTRY_LISTENERS: http://schema-registry:38081 - SCHEMA_REGISTRY_DEBUG: "true" - - kafka-rest: - image: confluentinc/cp-kafka-rest:4.1.1 - hostname: kafka-rest - ports: - - "38082:38082" - depends_on: - - schema-registry - environment: - KAFKA_REST_ZOOKEEPER_CONNECT: zookeeper:2181 - KAFKA_REST_SCHEMA_REGISTRY_URL: schema-registry:38081 - KAFKA_REST_HOST_NAME: kafka-rest - KAFKA_REST_LISTENERS: http://kafka-rest:38082 - postgres: - image: postgres:10-bullseye - environment: - - POSTGRES_USER=postgres - - POSTGRES_PASSWORD=postgres - ports: - - 5432:5432 - magic: - image: digitsy/kafka-magic - ports: - - "9999:80" - environment: - KMAGIC_ALLOW_TOPIC_DELETE: "true" - KMAGIC_ALLOW_SCHEMA_DELETE: "true" - redis: - image: redis:3.2 - ports: - - 6379:6379 diff --git a/health-services/libraries/health-services-common/CHANGELOG.md b/health-services/libraries/health-services-common/CHANGELOG.md index 14669d15d9f..fbb085523fc 100644 --- a/health-services/libraries/health-services-common/CHANGELOG.md +++ b/health-services/libraries/health-services-common/CHANGELOG.md @@ -1,5 +1,8 @@ All notable changes to this module will be documented in this file. +## 1.0.18 - 2024-08-09 +- Added validateClientReferenceIdsFromDB method to GenericRepository. + ## 1.0.16 - 2024-05-29 - Introduced multiple reusable functions to streamline and simplify the codebase. - Enhanced function modularity for better maintainability and readability. diff --git a/health-services/libraries/health-services-common/pom.xml b/health-services/libraries/health-services-common/pom.xml index a48b96a222d..8f5e0d4fae9 100644 --- a/health-services/libraries/health-services-common/pom.xml +++ b/health-services/libraries/health-services-common/pom.xml @@ -8,7 +8,7 @@ health-services-common jar health-services-common - 1.0.17-SNAPSHOT + 1.0.18-SNAPSHOT Shared classes among services diff --git a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java index 872d11c9d2a..537a82400cc 100644 --- a/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java +++ b/health-services/libraries/health-services-common/src/main/java/org/egov/common/data/repository/GenericRepository.java @@ -291,4 +291,23 @@ public List validateIds(List idsToValidate, String columnName){ return validIds.stream().map((obj) -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) .collect(Collectors.toList()); } + + public List validateClientReferenceIdsFromDB(List clientReferenceIds, Boolean isDeletedKeyPresent) { + List objFound = new ArrayList<>(); + + String query = null; + + if(isDeletedKeyPresent) { + query = String.format("SELECT clientReferenceId FROM %s WHERE clientReferenceId IN (:ids) AND isDeleted = false", tableName); + } else { + query = String.format("SELECT clientReferenceId FROM %s WHERE clientReferenceId IN (:ids) ", tableName); + } + + Map paramMap = new HashMap<>(); + paramMap.put("ids", clientReferenceIds); + + objFound.addAll(namedParameterJdbcTemplate.queryForList(query, paramMap, String.class)); + + return objFound; + } } diff --git a/health-services/libraries/health-services-models/CHANGELOG.md b/health-services/libraries/health-services-models/CHANGELOG.md index 531680fc20e..c7476cbe79b 100644 --- a/health-services/libraries/health-services-models/CHANGELOG.md +++ b/health-services/libraries/health-services-models/CHANGELOG.md @@ -1,5 +1,11 @@ All notable changes to this module will be documented in this file. +## 1.0.21 - 2024-08-07 +- Added UserActionEnum, UserAction Entities, TaskStatus enum +- Added isCascadingProjectDateUpdate in ProjectRequest model +- Removed status field from EgovModel + + ## 1.0.20 - 2024-05-29 - Added EgovModel, EgovSearchModel, EgovOfflineModel, EgovOfflineSearchModel - Updated Lombok to 1.18.22 for SuperBuilder annotation support. diff --git a/health-services/libraries/health-services-models/pom.xml b/health-services/libraries/health-services-models/pom.xml index ccbf98bc824..6ca95c3fe47 100644 --- a/health-services/libraries/health-services-models/pom.xml +++ b/health-services/libraries/health-services-models/pom.xml @@ -5,7 +5,7 @@ 4.0.0 org.egov.common health-services-models - 1.0.20-SNAPSHOT + 1.0.21-SNAPSHOT 17 ${java.version} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovModel.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovModel.java index d125458f9af..f68ea5cea75 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovModel.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/core/EgovModel.java @@ -30,9 +30,6 @@ public class EgovModel { @Size(min = 2, max = 1000) protected String tenantId; - @JsonProperty("status") - protected String status; - @JsonProperty("source") protected String source; //TODO what are the various sources and needs comments diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectRequest.java index fd09b6b635b..da4ae0343e4 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectRequest.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/ProjectRequest.java @@ -38,6 +38,10 @@ public class ProjectRequest { @Size(min=1) private List projects = new ArrayList<>(); + @JsonProperty("isCascadingProjectDateUpdate") + @Valid + private boolean isCascadingProjectDateUpdate = false; + @JsonProperty("apiOperation") @Valid private ApiOperation apiOperation = null; diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java index eddbeb82f0f..9f0160c34b5 100644 --- a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/Task.java @@ -1,9 +1,13 @@ package org.egov.common.models.project; -import com.fasterxml.jackson.annotation.JsonIgnore; +import java.util.ArrayList; +import java.util.List; + import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import digit.models.coremodels.AuditDetails; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -12,12 +16,6 @@ import org.egov.common.models.core.EgovOfflineModel; import org.springframework.validation.annotation.Validated; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Size; -import java.util.ArrayList; -import java.util.List; - /** * Task */ @@ -75,7 +73,8 @@ public class Task extends EgovOfflineModel { private Boolean isDeleted = Boolean.FALSE; @JsonProperty("status") - private String status = null; + @NotNull + TaskStatus status = null; public Task addResourcesItem(TaskResource resourcesItem) { this.resources.add(resourcesItem); diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskStatus.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskStatus.java new file mode 100644 index 00000000000..a17652a89c0 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/TaskStatus.java @@ -0,0 +1,99 @@ +package org.egov.common.models.project; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +/** + * Enum representing the various possible statuses for a task. + *

+ * Each status corresponds to a specific state of the task in the system. + * The status is stored as a string value and can be serialized/deserialized + * from JSON using Jackson annotations. + *

+ */ +public enum TaskStatus { + + /** + * Indicates that the task administration has failed. + * This status represents an error or issue encountered during + * the administrative process of the task. + */ + ADMINISTRATION_FAILED("ADMINISTRATION_FAILED"), + + /** + * Indicates that the task administration was successful. + * This status signifies that the task has been processed correctly + * without any issues. + */ + ADMINISTRATION_SUCCESS("ADMINISTRATION_SUCCESS"), + + /** + * Indicates that the beneficiary has refused the task. + * This status means that the individual or entity for whom the task + * was intended has declined to participate or accept it. + */ + BENEFICIARY_REFUSED("BENEFICIARY_REFUSED"), + + /** + * Indicates that the household associated with the task has been closed. + * This status implies that the household is no longer active or + * relevant to the task, possibly due to its closure or other reasons. + */ + CLOSED_HOUSEHOLD("CLOSED_HOUSEHOLD"), + + /** + * Indicates that the task has been delivered. + * This status shows that the task has been successfully completed + * and the deliverables have been provided. + */ + DELIVERED("DELIVERED"), + + /** + * Indicates that the task has not been administered. + * This status signifies that the task has not been processed or + * handled yet. + */ + NOT_ADMINISTERED("NOT_ADMINISTERED"); + + // The string value associated with the task status. + private String value; + + /** + * Constructor to initialize the TaskStatus with a specific string value. + * + * @param value The string value representing the task status. + */ + TaskStatus(String value) { + this.value = value; + } + + /** + * Returns the string representation of the TaskStatus. + * This method is used for serialization of the enum value to JSON. + * + * @return The string value of the task status. + */ + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + /** + * Creates a TaskStatus enum from a string value. + * This method is used for deserialization of the enum value from JSON. + * + * @param text The string value representing the task status. + * @return The TaskStatus enum corresponding to the provided value, + * or null if no match is found. + */ + @JsonCreator + public static TaskStatus fromValue(String text) { + for (TaskStatus status : TaskStatus.values()) { + if (String.valueOf(status.value).equals(text)) { + return status; + } + } + return null; // Return null if no matching status is found + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserActionEnum.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserActionEnum.java new file mode 100644 index 00000000000..1271584b583 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/UserActionEnum.java @@ -0,0 +1,33 @@ +package org.egov.common.models.project; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public enum UserActionEnum { + CLOSED_HOUSEHOLD("CLOSED_HOUSEHOLD"), + LOCATION_CAPTURE("LOCATION_CAPTURE"), + OTHER("OTHER"); + + private String value; + + UserActionEnum(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + + @JsonCreator + public static UserActionEnum fromValue(String text) { + for (UserActionEnum status : UserActionEnum.values()) { + if (String.valueOf(status.value).equals(text)) { + return status; + } + } + return null; + } + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserAction.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserAction.java new file mode 100644 index 00000000000..d58d98996d8 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserAction.java @@ -0,0 +1,109 @@ +package org.egov.common.models.project.useraction; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.constraints.DecimalMax; +import jakarta.validation.constraints.DecimalMin; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineModel; +import org.egov.common.models.project.UserActionEnum; +import org.springframework.validation.annotation.Validated; + +/** + * The UserAction class represents an action performed by the logged in user related to a project with + * or without in relation to a beneficiary + * It extends the EgovOfflineModel to inherit common properties. + */ +@Validated +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class UserAction extends EgovOfflineModel { + + /** + * The ID of the project associated with the user action. + * It must be between 2 and 64 characters long and cannot be null. + */ + @JsonProperty("projectId") + @Size(min = 2, max = 64, message = "Project ID must be between 2 and 64 characters") + @NotNull + private String projectId; + + /** + * The latitude coordinate of the user action's location. + * It must be between -90 and 90 degrees and cannot be null. + */ + @JsonProperty("latitude") + @DecimalMin("-90") + @DecimalMax("90") + @NotNull + private Double latitude; + + /** + * The longitude coordinate of the user action's location. + * It must be between -180 and 180 degrees and cannot be null. + */ + @JsonProperty("longitude") + @DecimalMin("-180") + @DecimalMax("180") + @NotNull + private Double longitude; + + /** + * The accuracy of the location measurement in meters. + * It must be a positive number and cannot be null. + */ + @JsonProperty("locationAccuracy") + @DecimalMin("0") + @NotNull + private Double locationAccuracy; + + /** + * The code of the boundary where the user action took place. + * It cannot be null. + */ + @JsonProperty("boundaryCode") + @NotNull + private String boundaryCode; + + /** + * The action performed by the user, represented as a UserActionEnum object. + * It cannot be null. + */ + @JsonProperty("action") + @NotNull + private UserActionEnum action; + + /** + * An optional tag if there is a beneficiary associated with the user action + * It must be between 2 and 64 characters long. + */ + @JsonProperty("beneficiaryTag") + @Size(min = 2, max = 64) + private String beneficiaryTag; + + /** + * An optional tag for the resource associated with the user action. + * It must be between 2 and 64 characters long. + */ + @JsonProperty("resourceTag") + @Size(min = 2, max = 64) + private String resourceTag; + + /** + * A flag indicating whether the user action has been deleted. + * The default value is false. + */ + @JsonProperty("isDeleted") + @Builder.Default + private Boolean isDeleted = false; + +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkRequest.java new file mode 100644 index 00000000000..b2bcb8b4f11 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkRequest.java @@ -0,0 +1,64 @@ +package org.egov.common.models.project.useraction; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestInfo; +import org.springframework.validation.annotation.Validated; + +/** + * The UserActionBulkRequest class is used for handling bulk requests of user actions. + * It contains a RequestInfo object and a list of UserAction objects. + */ +@Validated + + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class UserActionBulkRequest { + + /** + * The RequestInfo object containing metadata about the request. + * This field is mandatory and must be valid. + */ + @JsonProperty("RequestInfo") + @NotNull + @Valid + private RequestInfo requestInfo = null; + + /** + * A list of UserAction objects that are part of the bulk request. + * This field is mandatory, must contain at least one item, and must be valid. + * It is initialized to an empty list by default. + */ + @JsonProperty("UserActions") + @NotNull + @Valid + @Size(min = 1) + @Builder.Default + private List userActions = new ArrayList<>(); + + /** + * Adds a UserAction item to the list of user actions in the bulk request. + * This method is useful for incrementally building the list of user actions. + * + * @param userAction The UserAction object to be added to the list. + * @return The current instance of UserActionBulkRequest with the new UserAction added. + */ + public UserActionBulkRequest addTaskItem(UserAction userAction) { + this.userActions.add(userAction); + return this; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkResponse.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkResponse.java new file mode 100644 index 00000000000..f8698b676bd --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionBulkResponse.java @@ -0,0 +1,70 @@ +package org.egov.common.models.project.useraction; + +import java.util.ArrayList; +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseInfo; +import org.springframework.validation.annotation.Validated; + +/** + * The UserActionBulkResponse class is used for handling bulk responses of user actions. + * It contains a ResponseInfo object, a total count of user actions, and a list of UserAction objects. + */ +@Validated +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +@JsonIgnoreProperties(ignoreUnknown = true) +public class UserActionBulkResponse { + + /** + * The ResponseInfo object containing metadata about the response. + * This field is mandatory and must be valid. + */ + @JsonProperty("ResponseInfo") + @NotNull + @Valid + private ResponseInfo responseInfo = null; + + /** + * The total count of user actions in the response. + * It is initialized to 0 by default. + */ + @JsonProperty("TotalCount") + @Valid + @Builder.Default + private Long totalCount = 0L; + + /** + * A list of UserAction objects that are part of the bulk response. + * This field is mandatory and must be valid. + */ + @JsonProperty("UserActions") + @NotNull + @Valid + private List userActions = null; + + /** + * Adds a UserAction item to the list of user actions in the bulk response. + * This method is useful for incrementally building the list of user actions. + * + * @param userActionItem The UserAction object to be added to the list. + * @return The current instance of UserActionBulkResponse with the new UserAction added. + */ + public UserActionBulkResponse addUserAction(UserAction userActionItem) { + if (this.userActions == null) { + this.userActions = new ArrayList<>(); + } + this.userActions.add(userActionItem); + return this; + } +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearch.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearch.java new file mode 100644 index 00000000000..0e2051b6be6 --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearch.java @@ -0,0 +1,55 @@ +package org.egov.common.models.project.useraction; + +import java.util.List; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.egov.common.models.core.EgovOfflineSearchModel; +import org.springframework.validation.annotation.Validated; + +/** + * The UserActionSearch class is used for searching user actions based on various criteria. + * It extends the EgovOfflineSearchModel to inherit common search properties. + */ +@Validated +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class UserActionSearch extends EgovOfflineSearchModel { + + /** + * A userId to filter the user actions. + */ + @JsonProperty("createdBy") + private String createdBy; + + /** + * A project ID to filter the user actions. + */ + @JsonProperty("projectId") + private String projectId; + + /** + * A beneficiary tag to filter the user actions. + */ + @JsonProperty("beneficiaryTag") + private String beneficiaryTag; + + /** + * A resource tag to filter the user actions. + */ + @JsonProperty("resourceTag") + private String resourceTag; + + /** + * A boundary code to filter the user actions. + */ + @JsonProperty("boundaryCode") + private String boundaryCode; +} diff --git a/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearchRequest.java b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearchRequest.java new file mode 100644 index 00000000000..1bf43eb8ced --- /dev/null +++ b/health-services/libraries/health-services-models/src/main/java/org/egov/common/models/project/useraction/UserActionSearchRequest.java @@ -0,0 +1,44 @@ +package org.egov.common.models.project.useraction; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.experimental.SuperBuilder; +import org.springframework.validation.annotation.Validated; + +/** + * The UserActionSearchRequest class is used to encapsulate the request information + * for searching user actions. It includes the request metadata and the search criteria. + */ +@Validated +@Data +@NoArgsConstructor +@AllArgsConstructor +@SuperBuilder +@JsonIgnoreProperties(ignoreUnknown = true) +public class UserActionSearchRequest { + + /** + * The RequestInfo object contains metadata about the request, such as the + * API version, request timestamp, and user details. This field is mandatory + * and must be valid. + */ + @JsonProperty("RequestInfo") + @NotNull + @Valid + private org.egov.common.contract.request.RequestInfo requestInfo; + + /** + * The UserAction object contains the search criteria for filtering user actions. + * This includes various filters such as project IDs, beneficiary tags, resource tags, + * and boundary codes. This field is mandatory and must be valid. + */ + @JsonProperty("UserAction") + @NotNull + @Valid + private UserActionSearch userAction; +} \ No newline at end of file diff --git a/health-services/project/CHANGELOG.md b/health-services/project/CHANGELOG.md index 427aa3e5917..7865206457c 100644 --- a/health-services/project/CHANGELOG.md +++ b/health-services/project/CHANGELOG.md @@ -1,5 +1,7 @@ All notable changes to this module will be documented in this file. +## 1.1.5 - 2024-08-07 +- Added UserAction functionality with support for Location capture. ## 1.1.4 - 2024-05-29 - Integrated Core 2.9LTS diff --git a/health-services/project/pom.xml b/health-services/project/pom.xml index 54bd4fd9c91..fd0b688dcc3 100644 --- a/health-services/project/pom.xml +++ b/health-services/project/pom.xml @@ -5,7 +5,7 @@ project jar project - 1.1.4 + 1.1.5 17 ${java.version} @@ -45,12 +45,12 @@ org.egov.common health-services-common - 1.0.17-SNAPSHOT + 1.0.18-SNAPSHOT org.egov.common health-services-models - 1.0.20-SNAPSHOT + 1.0.21-SNAPSHOT compile diff --git a/health-services/project/src/main/java/org/egov/project/Constants.java b/health-services/project/src/main/java/org/egov/project/Constants.java index 91e1f824ae8..66333c64989 100644 --- a/health-services/project/src/main/java/org/egov/project/Constants.java +++ b/health-services/project/src/main/java/org/egov/project/Constants.java @@ -56,4 +56,12 @@ public interface Constants { String TASK_QUANTITY = "taskQuantity"; + String HOUSEHOLD_ID = "HouseholdId"; + + String SET_USER_ACTION = "setUserActions"; + + String GET_USER_ACTION = "getUserActions"; + + String PROJECT_USER_ACTION_ENRICHMENT_ERROR = "PROJECT_USER_ACTION_ENRICHMENT_ERROR"; + } diff --git a/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java b/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java index 32c76154f2b..26759e381e2 100644 --- a/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java +++ b/health-services/project/src/main/java/org/egov/project/config/ProjectConfiguration.java @@ -1,5 +1,7 @@ package org.egov.project.config; +import java.util.List; + import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -189,4 +191,35 @@ public class ProjectConfiguration { @Value("${project.staff.attendance.topic}") private String projectStaffAttendanceTopic; + @Value("${project.management.system.kafka.update.date.topic}") + private String updateProjectDateTopic; + + + // closed household task + @Value("${project.user.action.kafka.create.topic}") + private String createUserActionTopic; + + @Value("${project.user.action.consumer.bulk.create.topic}") + private String bulkCreateUserActionTopic; + + @Value("${project.user.action.kafka.update.topic}") + private String updateUserActionTopic; + + @Value("${project.user.action.consumer.bulk.update.topic}") + private String bulkUpdateUserActionTopic; + + @Value("${project.location.capture.consumer.bulk.create.topic}") + private String bulkCreateLocationCaptureTopic; + + @Value("${project.location.capture.kafka.create.topic}") + private String createLocationCaptureTopic; + + @Value("${egov.boundary.host}") + private String boundaryServiceHost; + + @Value("${egov.boundary.search.url}") + private String boundarySearchUrl; + + @Value("${project.task.no.resource.validation.status}") + private List noResourceStatuses; } diff --git a/health-services/project/src/main/java/org/egov/project/consumer/UserActionConsumer.java b/health-services/project/src/main/java/org/egov/project/consumer/UserActionConsumer.java new file mode 100644 index 00000000000..f01d2e00913 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/consumer/UserActionConsumer.java @@ -0,0 +1,103 @@ +package org.egov.project.consumer; + +import java.util.Map; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.project.service.LocationCaptureService; +import org.egov.project.service.UserActionService; +import org.egov.tracer.model.CustomException; +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; + +@Component +@Slf4j +public class UserActionConsumer { + + private final UserActionService userActionService; + private final LocationCaptureService locationCaptureService; + private final ObjectMapper objectMapper; + + @Autowired + public UserActionConsumer(UserActionService userActionService, LocationCaptureService locationCaptureService, ObjectMapper objectMapper) { + // Constructor injection for services and object mapper + this.userActionService = userActionService; + this.locationCaptureService = locationCaptureService; + this.objectMapper = objectMapper; + } + + /** + * Kafka listener for bulk creating user actions. + * + * @param consumerRecord The Kafka consumer record as a map. + * @param topic The topic from which the message was received. + * @return List of created UserAction objects. + */ + @KafkaListener(topics = "${project.user.action.consumer.bulk.create.topic}") + public void bulkCreateUserAction(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + // Convert consumer record to UserActionBulkRequest object + UserActionBulkRequest request = objectMapper.convertValue(consumerRecord, UserActionBulkRequest.class); + // Call the userActionService to handle the create operation + userActionService.create(request, true); + } catch (Exception exception) { + // Log any exception that occurs + log.error("Error processing bulk create for user actions from topic {}: {}", topic, ExceptionUtils.getStackTrace(exception)); + // throw custom exception + throw new CustomException("PROJECT_USER_ACTION_BULK_CREATE", exception.getMessage()); + } + } + + /** + * Kafka listener for bulk updating user actions. + * + * @param consumerRecord The Kafka consumer record as a map. + * @param topic The topic from which the message was received. + * @return List of updated UserAction objects. + */ + @KafkaListener(topics = "${project.user.action.consumer.bulk.update.topic}") + public void bulkUpdateUserAction(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + // Convert consumer record to UserActionBulkRequest object + UserActionBulkRequest request = objectMapper.convertValue(consumerRecord, UserActionBulkRequest.class); + // Call the userActionService to handle the update operation + userActionService.update(request, true); + } catch (Exception exception) { + // Log any exception that occurs + log.error("Error processing bulk update for user actions from topic {}: {}", topic, ExceptionUtils.getStackTrace(exception)); + // throw custom exception + throw new CustomException("PROJECT_USER_ACTION_BULK_UPDATE", exception.getMessage()); + } + } + + /** + * Kafka listener for bulk creating location captures. + * + * @param consumerRecord The Kafka consumer record as a map. + * @param topic The topic from which the message was received. + * @return List of created UserAction objects. + */ + @KafkaListener(topics = "${project.location.capture.consumer.bulk.create.topic}") + public void bulkCreateLocationCapture(Map consumerRecord, + @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + // Convert consumer record to UserActionBulkRequest object + UserActionBulkRequest request = objectMapper.convertValue(consumerRecord, UserActionBulkRequest.class); + // Call the locationCaptureService to handle the create operation + locationCaptureService.create(request, true); + } catch (Exception exception) { + // Log any exception that occurs + log.error("Error processing bulk create for location captures from topic {}: {}", topic, ExceptionUtils.getStackTrace(exception)); + // throw custom exception + throw new CustomException("PROJECT_USER_ACTION_LOCATION_CAPTURE_BULK_CREATE", exception.getMessage()); + } + } + +} diff --git a/health-services/project/src/main/java/org/egov/project/repository/LocationCaptureRepository.java b/health-services/project/src/main/java/org/egov/project/repository/LocationCaptureRepository.java new file mode 100644 index 00000000000..9127c0272b8 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/repository/LocationCaptureRepository.java @@ -0,0 +1,135 @@ +package org.egov.project.repository; + +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.builder.GenericQueryBuilder; +import org.egov.common.data.query.builder.QueryFieldChecker; +import org.egov.common.data.query.builder.SelectQueryBuilder; +import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionSearch; +import org.egov.common.producer.Producer; +import org.egov.common.utils.CommonUtils; +import org.egov.project.repository.rowmapper.LocationCaptureRowMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ReflectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdMethod; + +@Repository +@Slf4j +public class LocationCaptureRepository extends GenericRepository { + + private final String selectQuery = "SELECT id, clientreferenceid, tenantid, projectid, latitude, longitude, locationaccuracy, boundarycode, action, createdby, createdtime, lastmodifiedby, lastmodifiedtime, clientcreatedtime, clientlastmodifiedtime, clientcreatedby, clientlastmodifiedby, additionaldetails FROM user_location ul "; + + @Autowired + protected LocationCaptureRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, LocationCaptureRowMapper locationCaptureRowMapper) { + // Initialize the repository with producer, JDBC template, Redis template, query builder, and row mapper + super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, locationCaptureRowMapper, Optional.of("user_location")); + } + + /** + * Finds user locations based on search criteria and URL parameters. + * + * @param searchObject The search criteria for user locations. + * @param urlParams The URL parameters including pagination and filtering information. + * @return A SearchResponse containing the list of user locations and the total count. + */ + public SearchResponse find(UserActionSearch searchObject, URLParams urlParams) { + log.info("Executing find with searchObject: {} and urlParams: {}", searchObject, urlParams); + + String query = selectQuery + ""; + + Map paramsMap = new HashMap<>(); + List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); + query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); + query = query.replace("id IN (:id)", "ul.id IN (:id)"); + query = query.replace("clientReferenceId IN (:clientReferenceId)", "ul.clientReferenceId IN (:clientReferenceId)"); + + if (CollectionUtils.isEmpty(whereFields)) { + query = query + " WHERE ul.tenantId=:tenantId "; + } else { + query = query + " AND ul.tenantId=:tenantId "; + } + + if (urlParams.getLastChangedSince() != null) { + query = query + " AND ul.lastModifiedTime>=:lastModifiedTime "; + } + paramsMap.put("tenantId", urlParams.getTenantId()); + paramsMap.put("lastModifiedTime", urlParams.getLastChangedSince()); + + try { + log.debug("Executing query to fetch total count"); + Long totalCount = CommonUtils.constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + + query = query + " ORDER BY ul.id ASC LIMIT :limit OFFSET :offset"; + paramsMap.put("limit", urlParams.getLimit()); + paramsMap.put("offset", urlParams.getOffset()); + + log.debug("Executing query to fetch user locations: {}", query); + List locationCaptureList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + + log.info("Successfully fetched user locations: {}", locationCaptureList.size()); + return SearchResponse.builder().response(locationCaptureList).totalCount(totalCount).build(); + } catch (Exception e) { + log.error("Failed to execute query for finding user locations", e); + return SearchResponse.builder().response(Collections.emptyList()).totalCount(0L).build(); + } + } + + /** + * Finds user locations by their IDs, first checking the cache before querying the database. + * + * @param ids The list of IDs to search for. + * @param columnName The name of the column to search by. + * @return A SearchResponse containing the list of user locations found. + */ + public SearchResponse findById(List ids, String columnName) { + log.info("Executing findById with ids: {} and columnName: {}", ids, columnName); + + List objFound = findInCache(ids); + + if (!objFound.isEmpty()) { + Method idMethod = getIdMethod(objFound, columnName); + ids.removeAll(objFound.stream() + .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) + .collect(Collectors.toList())); + + if (ids.isEmpty()) { + log.info("All requested user locations found in cache"); + return SearchResponse.builder().response(objFound).build(); + } + } + + String query = String.format(selectQuery + " WHERE ul.%s IN (:ids)", columnName); + Map paramMap = new HashMap<>(); + paramMap.put("ids", ids); + + try { + log.debug("Executing query to fetch user locations by ID: {}", query); + List locationCaptureList = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + + objFound.addAll(locationCaptureList); + putInCache(objFound); + + log.info("Successfully fetched user locations by ID: {}", locationCaptureList.size()); + return SearchResponse.builder().response(objFound).build(); + } catch (Exception e) { + log.error("Failed to execute query for finding user locations by ID", e); + return SearchResponse.builder().response(Collections.emptyList()).totalCount(0L).build(); + } + } +} diff --git a/health-services/project/src/main/java/org/egov/project/repository/UserActionRepository.java b/health-services/project/src/main/java/org/egov/project/repository/UserActionRepository.java new file mode 100644 index 00000000000..a5e61318fe8 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/repository/UserActionRepository.java @@ -0,0 +1,139 @@ +package org.egov.project.repository; + +import java.lang.reflect.Method; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.data.query.builder.GenericQueryBuilder; +import org.egov.common.data.query.builder.QueryFieldChecker; +import org.egov.common.data.query.builder.SelectQueryBuilder; +import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.data.repository.GenericRepository; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionSearch; +import org.egov.common.producer.Producer; +import org.egov.common.utils.CommonUtils; +import org.egov.project.repository.rowmapper.UserActionRowMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ReflectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdMethod; + +@Repository +@Slf4j +public class UserActionRepository extends GenericRepository { + + private final String selectQuery = + "SELECT id, clientreferenceid, tenantid, projectid, latitude, longitude, locationaccuracy, boundarycode, action, beneficiarytag, resourcetag, status, additionaldetails, createdby, createdtime, lastmodifiedby, lastmodifiedtime, clientcreatedtime, clientlastmodifiedtime, clientcreatedby, clientlastmodifiedby, rowversion FROM user_action ua"; + @Autowired + protected UserActionRepository(Producer producer, NamedParameterJdbcTemplate namedParameterJdbcTemplate, + RedisTemplate redisTemplate, SelectQueryBuilder selectQueryBuilder, + UserActionRowMapper rowMapper) { + super(producer, namedParameterJdbcTemplate, redisTemplate, selectQueryBuilder, rowMapper, Optional.of("user_action")); + } + + /** + * Finds user actions based on search criteria and URL parameters. + * + * @param searchObject The search criteria for user actions. + * @param urlParams The URL parameters including pagination and filtering information. + * @return A SearchResponse containing the list of user actions and the total count. + * @throws QueryBuilderException If there is an error building the query. + */ + public SearchResponse find(UserActionSearch searchObject, URLParams urlParams) throws QueryBuilderException { + log.info("Executing find with searchObject: {} and urlParams: {}", searchObject, urlParams); + + String query = ""+selectQuery; + + Map paramsMap = new HashMap<>(); + List whereFields = GenericQueryBuilder.getFieldsWithCondition(searchObject, QueryFieldChecker.isNotNull, paramsMap); + query = GenericQueryBuilder.generateQuery(query, whereFields).toString(); + query = query.replace("id IN (:id)", "ua.id IN (:id)"); + query = query.replace("clientReferenceId IN (:clientReferenceId)", "ua.clientReferenceId IN (:clientReferenceId)"); + + if (CollectionUtils.isEmpty(whereFields)) { + query = query + " WHERE ua.tenantId=:tenantId "; + } else { + query = query + " AND ua.tenantId=:tenantId "; + } + + if (urlParams.getLastChangedSince() != null) { + query = query + " AND lastModifiedTime>=:lastModifiedTime "; + } + paramsMap.put("tenantId", urlParams.getTenantId()); + paramsMap.put("isDeleted", urlParams.getIncludeDeleted()); + paramsMap.put("lastModifiedTime", urlParams.getLastChangedSince()); + + try { + log.debug("Executing query to fetch total count"); + Long totalCount = CommonUtils.constructTotalCountCTEAndReturnResult(query, paramsMap, this.namedParameterJdbcTemplate); + + query = query + " ORDER BY ua.id ASC LIMIT :limit OFFSET :offset"; + paramsMap.put("limit", urlParams.getLimit()); + paramsMap.put("offset", urlParams.getOffset()); + + log.debug("Executing query to fetch user actions: {}", query); + List userActionList = this.namedParameterJdbcTemplate.query(query, paramsMap, this.rowMapper); + + log.info("Successfully fetched user actions: {}", userActionList.size()); + return SearchResponse.builder().response(userActionList).totalCount(totalCount).build(); + } catch (Exception e) { + log.error("Failed to execute query for finding user actions", e); + return SearchResponse.builder().response(Collections.emptyList()).totalCount(0L).build(); + } + } + + /** + * Finds user actions by their IDs, first checking the cache before querying the database. + * + * @param ids The list of IDs to search for. + * @param columnName The name of the column to search by. + * @return A SearchResponse containing the list of user actions found. + */ + public SearchResponse findById(List ids, String columnName) { + log.info("Executing findById with ids: {} and columnName: {}", ids, columnName); + + List objFound = findInCache(ids); + + if (!objFound.isEmpty()) { + Method idMethod = getIdMethod(objFound, columnName); + ids.removeAll(objFound.stream() + .map(obj -> (String) ReflectionUtils.invokeMethod(idMethod, obj)) + .collect(Collectors.toList())); + + if (ids.isEmpty()) { + log.info("All requested user actions found in cache"); + return SearchResponse.builder().response(objFound).build(); + } + } + + String query = String.format(selectQuery + " WHERE ua.%s IN (:ids) ", columnName); + Map paramMap = new HashMap<>(); + paramMap.put("ids", ids); + + try { + log.debug("Executing query to fetch user actions by ID: {}", query); + List userActionList = this.namedParameterJdbcTemplate.query(query, paramMap, this.rowMapper); + + objFound.addAll(userActionList); + putInCache(objFound); + + log.info("Successfully fetched user actions by ID: {}", userActionList.size()); + return SearchResponse.builder().response(objFound).build(); + } catch (Exception e) { + log.error("Failed to execute query for finding user actions by ID", e); + return SearchResponse.builder().response(Collections.emptyList()).totalCount(0L).build(); + } + } +} diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/LocationCaptureRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/LocationCaptureRowMapper.java new file mode 100644 index 00000000000..b9ea8babec8 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/LocationCaptureRowMapper.java @@ -0,0 +1,91 @@ +package org.egov.project.repository.rowmapper; + +import java.sql.ResultSet; +import java.sql.SQLException; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.core.AdditionalFields; +import org.egov.common.models.project.UserActionEnum; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; + +/** + * RowMapper implementation for mapping rows of a ResultSet to UserAction objects. + * This class is used to map the result of a SQL query to UserAction instances. + */ +@Component +@Slf4j +public class LocationCaptureRowMapper implements RowMapper { + + private final ObjectMapper objectMapper; + + /** + * Constructor for dependency injection of ObjectMapper. + * + * @param objectMapper The ObjectMapper used for converting JSON strings to objects. + */ + @Autowired + public LocationCaptureRowMapper(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + /** + * Map a single row of the ResultSet to a UserAction object. + * + * @param resultSet The ResultSet containing data from the database. + * @param rowNum The number of the current row. + * @return A UserAction object populated with data from the current row of the ResultSet. + * @throws SQLException If there is an issue accessing the ResultSet data. + */ + @Override + public UserAction mapRow(ResultSet resultSet, int rowNum) throws SQLException { + + // Creating AuditDetails object with information from the ResultSet + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + + // Creating client-specific AuditDetails object with information from the ResultSet + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .createdBy(resultSet.getString("clientCreatedBy")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) + .build(); + + UserAction locationCaptureUserAction; + try { + // Building the UserAction object with data from the ResultSet + locationCaptureUserAction = UserAction.builder() + .id(resultSet.getString("id")) + .tenantId(resultSet.getString("tenantId")) + .clientReferenceId(resultSet.getString("clientReferenceId")) + .projectId(resultSet.getString("projectId")) + .latitude(resultSet.getDouble("latitude")) + .longitude(resultSet.getDouble("longitude")) + .locationAccuracy(resultSet.getDouble("locationAccuracy")) + .boundaryCode(resultSet.getString("boundaryCode")) + .action(UserActionEnum.fromValue(resultSet.getString("action"))) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) + .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper + .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) + .build(); + } catch (JsonProcessingException e) { + // Throwing a RuntimeException if there's an error processing JSON + log.error("Error processing Additional detail JSON in Location capture UserAction ", e); + throw new CustomException("HCM_PROJECT_USER_ACTION_LOCATION_CAPTURE_ROW_MAPPER_INVALID_ERROR", "Error processing JSON: " + e.getMessage()); + } + + return locationCaptureUserAction; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java index caafec9a8e1..ccff648bd41 100644 --- a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/ProjectTaskRowMapper.java @@ -8,6 +8,7 @@ import org.egov.common.models.project.AddressType; import org.egov.common.models.core.Boundary; import org.egov.common.models.project.Task; +import org.egov.common.models.project.TaskStatus; import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Component; @@ -47,7 +48,7 @@ public Task mapRow(ResultSet resultSet, int i) throws SQLException { .plannedEndDate(resultSet.getLong("plannedEndDate")) .actualStartDate(resultSet.getLong("actualStartDate")) .actualEndDate(resultSet.getLong("actualEndDate")) - .status(resultSet.getString("status")) + .status(TaskStatus.fromValue(resultSet.getString("status"))) .auditDetails(auditDetails) .clientAuditDetails(clientAuditDetails) .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper diff --git a/health-services/project/src/main/java/org/egov/project/repository/rowmapper/UserActionRowMapper.java b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/UserActionRowMapper.java new file mode 100644 index 00000000000..8a63f0f3c99 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/repository/rowmapper/UserActionRowMapper.java @@ -0,0 +1,94 @@ +package org.egov.project.repository.rowmapper; + +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.core.AdditionalFields; +import org.egov.common.models.project.UserActionEnum; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Component; + +/** + * RowMapper implementation for mapping rows of a ResultSet to UserAction objects. + * This class is used to map the result of a SQL query to UserAction instances. + */ +@Component +@Slf4j +public class UserActionRowMapper implements RowMapper { + + private final ObjectMapper objectMapper; + + /** + * Constructor for dependency injection of ObjectMapper. + * + * @param objectMapper The ObjectMapper used for converting JSON strings to objects. + */ + @Autowired + public UserActionRowMapper(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + /** + * Map a single row of the ResultSet to a UserAction object. + * + * @param resultSet The ResultSet containing data from the database. + * @param rowNum The number of the current row. + * @return A UserAction object populated with data from the current row of the ResultSet. + * @throws SQLException If there is an issue accessing the ResultSet data or processing JSON. + */ + @Override + public UserAction mapRow(ResultSet resultSet, int rowNum) throws SQLException { + try { + // Creating AuditDetails object with information from the ResultSet + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(resultSet.getString("createdBy")) + .createdTime(resultSet.getLong("createdTime")) + .lastModifiedBy(resultSet.getString("lastModifiedBy")) + .lastModifiedTime(resultSet.getLong("lastModifiedTime")) + .build(); + + // Creating client-specific AuditDetails object with information from the ResultSet + AuditDetails clientAuditDetails = AuditDetails.builder() + .createdTime(resultSet.getLong("clientCreatedTime")) + .createdBy(resultSet.getString("clientCreatedBy")) + .lastModifiedTime(resultSet.getLong("clientLastModifiedTime")) + .lastModifiedBy(resultSet.getString("clientLastModifiedBy")) + .build(); + + // Building the UserAction object with data from the ResultSet + UserAction userAction = UserAction.builder() + .id(resultSet.getString("id")) + .tenantId(resultSet.getString("tenantId")) + .clientReferenceId(resultSet.getString("clientReferenceId")) + .projectId(resultSet.getString("projectId")) + .latitude(resultSet.getDouble("latitude")) + .longitude(resultSet.getDouble("longitude")) + .locationAccuracy(resultSet.getDouble("locationAccuracy")) + .boundaryCode(resultSet.getString("boundaryCode")) + .action(UserActionEnum.fromValue(resultSet.getString("action"))) + .beneficiaryTag(resultSet.getString("beneficiaryTag")) + .resourceTag(resultSet.getString("resourceTag")) + .rowVersion(resultSet.getInt("rowVersion")) + .auditDetails(auditDetails) + .clientAuditDetails(clientAuditDetails) + .additionalFields(resultSet.getString("additionalDetails") == null ? null : objectMapper + .readValue(resultSet.getString("additionalDetails"), AdditionalFields.class)) + .build(); + + return userAction; + } catch (JsonProcessingException e) { + String id = resultSet.getString("id"); + String errorMessage = "Error processing JSON for UserAction mapping. Row number: " + rowNum + ", id: " + (id != null ? id : "not available"); + log.error(errorMessage, e); + throw new CustomException("HCM_PROJECT_USER_ACTION_ROW_MAPPER_INVALID_ERROR", errorMessage + ", " + e.getMessage()); + } + } +} diff --git a/health-services/project/src/main/java/org/egov/project/service/LocationCaptureService.java b/health-services/project/src/main/java/org/egov/project/service/LocationCaptureService.java new file mode 100644 index 00000000000..5667184beb0 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/service/LocationCaptureService.java @@ -0,0 +1,222 @@ +package org.egov.project.service; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.common.ds.Tuple; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.models.project.useraction.UserActionSearch; +import org.egov.common.models.project.useraction.UserActionSearchRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.egov.common.validator.Validator; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.repository.LocationCaptureRepository; +import org.egov.project.service.enrichment.UserActionEnrichmentService; +import org.egov.project.validator.useraction.UaBoundaryValidator; +import org.egov.project.validator.useraction.UaExistentEntityValidator; +import org.egov.project.validator.useraction.UaProjectIdValidator; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.ReflectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.project.Constants.SET_USER_ACTION; +import static org.egov.project.Constants.VALIDATION_ERROR; + +/** + * Service class for handling location capture tasks related to user actions. + * Provides methods for creating, validating, searching, and caching location capture tasks. + */ +@Service +@Slf4j +public class LocationCaptureService { + + private final IdGenService idGenService; + private final LocationCaptureRepository locationCaptureRepository; + private final ServiceRequestClient serviceRequestClient; + private final ProjectConfiguration projectConfiguration; + private final UserActionEnrichmentService userActionEnrichmentService; + private final List> validators; + + /** + * Predicate to determine if a validator is applicable for creation. + * Filters validators based on specific classes. + */ + private final Predicate> isApplicableForCreate = validator -> + validator.getClass().equals(UaProjectIdValidator.class) + || validator.getClass().equals(UaExistentEntityValidator.class) + || validator.getClass().equals(UaBoundaryValidator.class); + + /** + * Constructor for injecting dependencies into the LocationCaptureService. + * + * @param idGenService The service for generating unique IDs. + * @param locationCaptureRepository Repository for location capture tasks. + * @param serviceRequestClient Client for making service requests. + * @param projectConfiguration Configuration properties related to the project. + * @param userActionEnrichmentService Service for enriching location capture user action tasks. + * @param validators List of validators for user actions. + */ + @Autowired + public LocationCaptureService( + IdGenService idGenService, + LocationCaptureRepository locationCaptureRepository, + ServiceRequestClient serviceRequestClient, + ProjectConfiguration projectConfiguration, + UserActionEnrichmentService userActionEnrichmentService, + List> validators + ) { + this.idGenService = idGenService; + this.locationCaptureRepository = locationCaptureRepository; + this.serviceRequestClient = serviceRequestClient; + this.projectConfiguration = projectConfiguration; + this.userActionEnrichmentService = userActionEnrichmentService; + this.validators = validators; + } + + /** + * Creates location capture tasks in bulk. + * Validates the request, enriches valid tasks, saves them, and handles errors. + * + * @param request The bulk request containing location capture tasks. + * @param isBulk Flag indicating if the request is a bulk operation. + * @return A list of valid location capture tasks. + */ + public List create(UserActionBulkRequest request, boolean isBulk) { + log.info("Received request to create bulk location capture tasks"); + + // Validate the request and separate valid tasks from error details. + Tuple, Map> tuple = validate(validators, isApplicableForCreate, request, isBulk); + Map errorDetailsMap = tuple.getY(); + List validLocationCaptures = tuple.getX(); + + try { + if (!validLocationCaptures.isEmpty()) { + log.info("Processing {} valid entities", validLocationCaptures.size()); + + // Enrich valid location capture tasks. + userActionEnrichmentService.create(validLocationCaptures, request); + + // Save valid location capture tasks and send them to the Kafka topic. + locationCaptureRepository.save(validLocationCaptures, projectConfiguration.getCreateLocationCaptureTopic()); + log.info("Successfully created location capture tasks"); + } + } catch (Exception exception) { + // Log and handle exceptions that occur during task creation. + log.error("Error occurred while creating location capture tasks: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validLocationCaptures, exception, SET_USER_ACTION); + } + + // Handle errors based on the validation results. + handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); + + return validLocationCaptures; + } + + /** + * Validates the user action bulk request using the provided validators. + * Filters out tasks with errors and returns the valid ones. + * + * @param validators List of validators to use for validation. + * @param applicableValidators Predicate to filter applicable validators. + * @param request The bulk request to validate. + * @param isBulk Flag indicating if the request is a bulk operation. + * @return A tuple containing valid location capture tasks and error details. + */ + private Tuple, Map> validate( + List> validators, + Predicate> applicableValidators, + UserActionBulkRequest request, boolean isBulk) { + + log.info("Validating request"); + + // Perform validation and collect error details. + Map errorDetailsMap = CommonUtils.validate( + validators, + applicableValidators, + request, + SET_USER_ACTION + ); + + // Throw an exception if there are validation errors and it's not a bulk operation. + if (!errorDetailsMap.isEmpty() && !isBulk) { + throw new CustomException(VALIDATION_ERROR, errorDetailsMap.values().toString()); + } + + // Filter out tasks with no errors. + List validLocationCaptures = request.getUserActions().stream() + .filter(notHavingErrors()) + .collect(Collectors.toList()); + + return new Tuple<>(validLocationCaptures, errorDetailsMap); + } + + /** + * Searches for location capture tasks based on the provided search request and URL parameters. + * Supports searching by ID or by other criteria. + * + * @param locationCaptureSearchRequest The search request containing criteria for searching. + * @param urlParams URL parameters for filtering the search results. + * @return A SearchResponse containing the search results and total count. + */ + public SearchResponse search(UserActionSearchRequest locationCaptureSearchRequest, URLParams urlParams) { + log.info("Received request to search project task"); + + UserActionSearch locationCaptureSearch = locationCaptureSearchRequest.getUserAction(); + String idFieldName = getIdFieldName(locationCaptureSearch); + + if (isSearchByIdOnly(locationCaptureSearch, idFieldName)) { + log.info("Searching location capture by id"); + List ids = (List) ReflectionUtils.invokeMethod( + getIdMethod(Collections.singletonList(locationCaptureSearch)), + locationCaptureSearch + ); + log.info("Fetching location capture tasks with ids: {}", ids); + + // Perform search by IDs and filter results based on last changed date and tenant ID. + SearchResponse searchResponse = locationCaptureRepository.findById(ids, idFieldName); + return SearchResponse.builder() + .response(searchResponse.getResponse().stream() + .filter(lastChangedSince(urlParams.getLastChangedSince())) + .filter(havingTenantId(urlParams.getTenantId())) + .collect(Collectors.toList()) + ) + .totalCount(searchResponse.getTotalCount()) + .build(); + } + + log.info("Searching project beneficiaries using criteria"); + // Perform search based on other criteria. + return locationCaptureRepository.find(locationCaptureSearch, urlParams); + } + + /** + * Puts location capture tasks into cache. + * + * @param locationCaptures The list of location capture tasks to cache. + */ + public void putInCache(List locationCaptures) { + log.info("Putting {} location tracking tasks in cache", locationCaptures.size()); + locationCaptureRepository.putInCache(locationCaptures); + log.info("Successfully put location tracking tasks in cache"); + } +} diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectService.java index f0dd5a2645b..56e2665792a 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectService.java @@ -1,6 +1,9 @@ package org.egov.project.service; +import com.fasterxml.jackson.databind.ObjectMapper; +import digit.models.coremodels.AuditDetails; import jakarta.validation.Valid; +import java.util.Map; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.egov.common.contract.request.RequestInfo; @@ -12,7 +15,9 @@ import org.egov.project.config.ProjectConfiguration; import org.egov.project.repository.ProjectRepository; import org.egov.project.service.enrichment.ProjectEnrichment; +import org.egov.project.util.ProjectServiceUtil; import org.egov.project.validator.project.ProjectValidator; +import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -24,6 +29,7 @@ @Slf4j public class ProjectService { + private final ProjectRepository projectRepository; private final ProjectValidator projectValidator; @@ -34,15 +40,21 @@ public class ProjectService { private final Producer producer; + private final ProjectServiceUtil projectServiceUtil; + + private final ObjectMapper objectMapper; + @Autowired public ProjectService( ProjectRepository projectRepository, - ProjectValidator projectValidator, ProjectEnrichment projectEnrichment, ProjectConfiguration projectConfiguration, Producer producer) { + ProjectValidator projectValidator, ProjectEnrichment projectEnrichment, ProjectConfiguration projectConfiguration, Producer producer,ProjectServiceUtil projectServiceUtil) { this.projectRepository = projectRepository; this.projectValidator = projectValidator; this.projectEnrichment = projectEnrichment; this.projectConfiguration = projectConfiguration; this.producer = producer; + this.projectServiceUtil = projectServiceUtil; + this.objectMapper = new ObjectMapper(); } public List validateProjectIds(List productIds) { @@ -100,22 +112,190 @@ public List searchProject(ProjectSearchRequest projectSearchRequest, @V return projectRepository.getProjects(projectSearchRequest.getProject(), urlParams); } - public ProjectRequest updateProject(ProjectRequest project) { - projectValidator.validateUpdateProjectRequest(project); + public ProjectRequest updateProject(ProjectRequest request) { + /* + * Validate the update project request + */ + projectValidator.validateUpdateProjectRequest(request); log.info("Update project request validated"); - //Search projects based on project ids - List projectsFromDB = searchProject(getSearchProjectRequest(project.getProjects(), project.getRequestInfo(), false), projectConfiguration.getMaxLimit(), projectConfiguration.getDefaultOffset(), project.getProjects().get(0).getTenantId(), null, false, false, false, null, null); + + /* + * Search for projects based on project IDs provided in the request + */ + List projectsFromDB = searchProject( + getSearchProjectRequest(request.getProjects(), request.getRequestInfo(), false), + projectConfiguration.getMaxLimit(), projectConfiguration.getDefaultOffset(), + request.getProjects().get(0).getTenantId(), null, false, false, false, null, null + ); log.info("Fetched projects for update request"); - //Validate Update project request against projects fetched form database - projectValidator.validateUpdateAgainstDB(project.getProjects(), projectsFromDB); - projectEnrichment.enrichProjectOnUpdate(project, projectsFromDB); - log.info("Enriched with project Number, Ids and AuditDetails"); - producer.push(projectConfiguration.getUpdateProjectTopic(), project); - log.info("Pushed to kafka"); - return project; + /* + * Validate the update project request against the projects fetched from the database + */ + projectValidator.validateUpdateAgainstDB(request.getProjects(), projectsFromDB); + + /* + * Process each project in the update request + */ + for (Project project : request.getProjects()) { + processProjectUpdate(request, project, projectsFromDB); + } + + return request; } + private void processProjectUpdate(ProjectRequest request, Project project, List projectsFromDB) { + /* + * Convert project ID to string for comparison + */ + String projectId = String.valueOf(project.getId()); + + /* + * Find the project from the database that matches the current project ID + */ + Project projectFromDB = findProjectById(projectId, projectsFromDB); + boolean isCascadingProjectDateUpdate = request.isCascadingProjectDateUpdate(); + + if (projectFromDB != null) { + /* + * Merge additional details of the project from the request and project from DB + */ + projectServiceUtil.mergeAdditionalDetails(project, projectFromDB); + + /* + * Handle cases where cascading project date update is true + */ + if (isCascadingProjectDateUpdate) { + handleUpdateProjectDates(request, project, projectFromDB); + } + /* + * Handle cases for normal update flow + */ + else { + handleNormalUpdate(request, project, projectFromDB); + } + } + } + + private Project findProjectById(String projectId, List projectsFromDB) { + /* + * Find and return the project with the matching ID from the list of projects fetched from the database + */ + return projectsFromDB.stream() + .filter(p -> projectId.equals(String.valueOf(p.getId()))) + .findFirst() + .orElse(null); + } + + + private void handleNormalUpdate(ProjectRequest request, Project project, Project projectFromDB) { + /* + * Ensure that start and end dates are not being updated when flag is false + */ + if (!project.getStartDate().equals(projectFromDB.getStartDate()) || + !project.getEndDate().equals(projectFromDB.getEndDate())) { + throw new CustomException("PROJECT_CASCADE_UPDATE_DATE_ERROR", + "Can't Update Date Range if Cascade Project Date Update false"); + } + + /* + * Enrich the project with values other than the start, end dates, and AdditionalDetails, + * and push the update to the message broker + */ + projectEnrichment.enrichProjectOnUpdate(request, project, projectFromDB); + producer.push(projectConfiguration.getUpdateProjectTopic(), request); + } + + private void handleUpdateProjectDates(ProjectRequest request, Project project, Project projectFromDB) { + /* + * Save original values of start date, end date, and additional details + */ + Long originalStartDate = projectFromDB.getStartDate(); + Long originalEndDate = projectFromDB.getEndDate(); + Object originalAdditionalDetails = projectFromDB.getAdditionalDetails(); + AuditDetails originalAuditDetails = projectFromDB.getAuditDetails(); + + + /* + * Update the project with new start date, end date, and additional details + */ + projectFromDB.setStartDate(project.getStartDate()); + projectFromDB.setEndDate(project.getEndDate()); + projectFromDB.setAdditionalDetails(project.getAdditionalDetails()); + projectFromDB.setAuditDetails(project.getAuditDetails()); + + /* + * Ensure that no other properties are being updated besides the start and end dates + */ + if (!objectMapper.valueToTree(projectFromDB).equals(objectMapper.valueToTree(project))) { + throw new CustomException( + "PROJECT_CASCADE_UPDATE_ERROR", + "Can only update Project dates and additional details if cascade Project date update true" + ); + } + + /* + * Restore original values of start date, end date, and additional details + */ + projectFromDB.setStartDate(originalStartDate); + projectFromDB.setEndDate(originalEndDate); + projectFromDB.setAdditionalDetails(originalAdditionalDetails); + projectFromDB.setAuditDetails(originalAuditDetails); + + /* + * Update lastModifiedTime and lastModifiedBy for the project + */ + projectEnrichment.enrichProjectRequestOnUpdate(project, projectFromDB, request.getRequestInfo()); + + /* + * Check and enrich cascading project dates and push the update to the message broker + */ + checkAndEnrichCascadingProjectDates(request, project); + producer.push(projectConfiguration.getUpdateProjectDateTopic(), request); + } + + + /** + * Checks and enriches cascading project dates. + * + * @param request The project request containing projects and request information. + */ + private void checkAndEnrichCascadingProjectDates(ProjectRequest request, Project project) { + /* + * Retrieve tenant ID from the first project in the request + */ + String tenantId = request.getProjects().get(0).getTenantId(); + String projectId = String.valueOf(project.getId()); + + /* + * Fetch projects from the database with ancestors and descendants + */ + List projectsFromDbWithAncestorsAndDescendants = searchProject( + getSearchProjectRequest(request.getProjects(), request.getRequestInfo(), false), + projectConfiguration.getMaxLimit(), + projectConfiguration.getDefaultOffset(), + tenantId, + null, + false, + true, + true, + null, + null + ); + + /* + * Create a map of projects from the database with ancestors and descendants + */ + Map projectFromDbWithAncestorsAndDescendantsMap = projectServiceUtil.createProjectMap(projectsFromDbWithAncestorsAndDescendants); + Project projectFromDbWithAncestorsAndDescendants = projectFromDbWithAncestorsAndDescendantsMap.get(projectId); + + /* + * Enrich project cascading dates based on the retrieved data + */ + projectEnrichment.enrichProjectCascadingDatesOnUpdate(project, projectFromDbWithAncestorsAndDescendants); + } + + /* Search for parent projects based on "parent" field and returns parent projects */ private List getParentProjects(ProjectRequest projectRequest) { List parentProjects = null; diff --git a/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java b/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java index 12c8ea87062..42989bf6d57 100644 --- a/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java +++ b/health-services/project/src/main/java/org/egov/project/service/ProjectTaskService.java @@ -34,8 +34,6 @@ import org.egov.project.validator.task.PtProductVariantIdValidator; import org.egov.project.validator.task.PtProjectBeneficiaryIdValidator; import org.egov.project.validator.task.PtProjectIdValidator; -import org.egov.project.validator.task.PtIsResouceEmptyValidator; -import org.egov.project.validator.task.PtResourceQuantityValidator; import org.egov.project.validator.task.PtRowVersionValidator; import org.egov.project.validator.task.PtUniqueEntityValidator; import org.egov.project.validator.task.PtUniqueSubEntityValidator; @@ -72,19 +70,19 @@ public class ProjectTaskService { private final ProjectConfiguration projectConfiguration; private final ProjectTaskEnrichmentService enrichmentService; - + // || validator.getClass().equals(PtResourceQuantityValidator.class) FIXME add this back once requirement confirmation is done private final Predicate> isApplicableForCreate = validator -> validator.getClass().equals(PtProjectIdValidator.class) || validator.getClass().equals(PtExistentEntityValidator.class) || validator.getClass().equals(PtIsResouceEmptyValidator.class) - || validator.getClass().equals(PtResourceQuantityValidator.class) + || validator.getClass().equals(PtProjectBeneficiaryIdValidator.class) || validator.getClass().equals(PtProductVariantIdValidator.class); + // || validator.getClass().equals(PtResourceQuantityValidator.class) FIXME add this back once requirement confirmation is done private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(PtProjectIdValidator.class) || validator.getClass().equals(PtIsResouceEmptyValidator.class) - || validator.getClass().equals(PtResourceQuantityValidator.class) || validator.getClass().equals(PtProjectBeneficiaryIdValidator.class) || validator.getClass().equals(PtProductVariantIdValidator.class) || validator.getClass().equals(PtNullIdValidator.class) diff --git a/health-services/project/src/main/java/org/egov/project/service/UserActionService.java b/health-services/project/src/main/java/org/egov/project/service/UserActionService.java new file mode 100644 index 00000000000..0e0f76dec0e --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/service/UserActionService.java @@ -0,0 +1,213 @@ +package org.egov.project.service; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.egov.common.data.query.exception.QueryBuilderException; +import org.egov.common.ds.Tuple; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.ErrorDetails; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.models.project.useraction.UserActionSearch; +import org.egov.common.models.project.useraction.UserActionSearchRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.egov.common.validator.Validator; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.repository.UserActionRepository; +import org.egov.project.service.enrichment.UserActionEnrichmentService; +import org.egov.project.validator.useraction.UaBoundaryValidator; +import org.egov.project.validator.useraction.UaExistentEntityValidator; +import org.egov.project.validator.useraction.UaNonExistentEntityValidator; +import org.egov.project.validator.useraction.UaNullIdValidator; +import org.egov.project.validator.useraction.UaProjectIdValidator; +import org.egov.project.validator.useraction.UaRowVersionValidator; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.ReflectionUtils; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.handleErrors; +import static org.egov.common.utils.CommonUtils.havingTenantId; +import static org.egov.common.utils.CommonUtils.includeDeleted; +import static org.egov.common.utils.CommonUtils.isSearchByIdOnly; +import static org.egov.common.utils.CommonUtils.lastChangedSince; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.project.Constants.SET_USER_ACTION; +import static org.egov.project.Constants.VALIDATION_ERROR; + +@Service +@Slf4j +public class UserActionService { + private final IdGenService idGenService; // Service for generating unique IDs + private final UserActionRepository userActionTaskRepository; // Repository for user actions + private final ServiceRequestClient serviceRequestClient; // Client for external service requests + private final ProjectConfiguration projectConfiguration; // Configuration properties for the project + private final UserActionEnrichmentService userActionEnrichmentService; // Service for enriching user actions + private final List> validators; // List of validators for user actions + + // Predicate to filter validators applicable for creation + private final Predicate> isApplicableForCreate = validator -> + validator.getClass().equals(UaProjectIdValidator.class) + || validator.getClass().equals(UaExistentEntityValidator.class) + || validator.getClass().equals(UaBoundaryValidator.class); + + // Predicate to filter validators applicable for updates + private final Predicate> isApplicableForUpdate = validator -> + validator.getClass().equals(UaProjectIdValidator.class) + || validator.getClass().equals(UaNullIdValidator.class) + || validator.getClass().equals(UaNonExistentEntityValidator.class) + || validator.getClass().equals(UaRowVersionValidator.class) + || validator.getClass().equals(UaBoundaryValidator.class); + + // Constructor for dependency injection + @Autowired + public UserActionService( + IdGenService idGenService, + UserActionRepository userActionTaskRepository, + ServiceRequestClient serviceRequestClient, + ProjectConfiguration projectConfiguration, + UserActionEnrichmentService userActionEnrichmentService, + List> validators + ) { + this.idGenService = idGenService; + this.userActionTaskRepository = userActionTaskRepository; + this.serviceRequestClient = serviceRequestClient; + this.projectConfiguration = projectConfiguration; + this.userActionEnrichmentService = userActionEnrichmentService; + this.validators = validators; + } + + // Method to handle the creation of user actions + public List create(UserActionBulkRequest request, boolean isBulk) { + log.info("Received request to create bulk closed household userActions"); + + // Validate the request and get valid user actions along with error details + Tuple, Map> tuple = validate(validators, isApplicableForCreate, request, isBulk); + Map errorDetailsMap = tuple.getY(); + List validUserActions = tuple.getX(); + + try { + // If there are valid user actions, enrich and save them + if (!validUserActions.isEmpty()) { + log.info("Processing {} valid entities", validUserActions.size()); + userActionEnrichmentService.create(validUserActions, request); + userActionTaskRepository.save(validUserActions, projectConfiguration.getCreateUserActionTopic()); + log.info("Successfully created closed household userActions"); + } + } catch (Exception exception) { + // Handle and log any exceptions that occur + log.error("Error occurred while creating closed household userActions: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validUserActions, exception, SET_USER_ACTION); + } + + // Handle any validation errors + handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); + + return validUserActions; + } + + // Method to handle the update of user actions + public List update(UserActionBulkRequest request, boolean isBulk) { + log.info("Received request to update bulk closed household userActions"); + + // Validate the request and get valid user actions along with error details + Tuple, Map> tuple = validate(validators, isApplicableForUpdate, request, isBulk); + Map errorDetailsMap = tuple.getY(); + List validUserActions = tuple.getX(); + + try { + // If there are valid user actions, enrich and update them + if (!validUserActions.isEmpty()) { + log.info("Processing {} valid entities", validUserActions.size()); + userActionEnrichmentService.update(validUserActions, request); + userActionTaskRepository.save(validUserActions, projectConfiguration.getUpdateUserActionTopic()); + log.info("Successfully updated bulk closed household userActions"); + } + } catch (Exception exception) { + // Handle and log any exceptions that occur + log.error("Error occurred while updating closed household userActions: {}", ExceptionUtils.getStackTrace(exception)); + populateErrorDetails(request, errorDetailsMap, validUserActions, exception, SET_USER_ACTION); + } + + // Handle any validation errors + handleErrors(errorDetailsMap, isBulk, VALIDATION_ERROR); + + return validUserActions; + } + + // Method to validate user action requests + private Tuple, Map> validate(List> validators, + Predicate> applicableValidators, + UserActionBulkRequest request, boolean isBulk) { + log.info("Validating request"); + + // Validate the request using the applicable validators + Map errorDetailsMap = CommonUtils.validate(validators, + applicableValidators, request, + SET_USER_ACTION); + + // Throw exception if there are validation errors and it's not a bulk request + if (!errorDetailsMap.isEmpty() && !isBulk) { + throw new CustomException(VALIDATION_ERROR, errorDetailsMap.values().toString()); + } + + // Filter and return valid user actions + List validUserActions = request.getUserActions().stream() + .filter(notHavingErrors()).collect(Collectors.toList()); + return new Tuple<>(validUserActions, errorDetailsMap); + } + + // Method to search for user actions based on the request and URL parameters + public SearchResponse search(UserActionSearchRequest request, URLParams urlParams) { + log.info("Received request to search project UserAction"); + + UserActionSearch userActionSearch = request.getUserAction(); + + // Determine the ID field name for search + String idFieldName = getIdFieldName(userActionSearch); + if (isSearchByIdOnly(userActionSearch, idFieldName)) { + log.info("Searching project UserAction by id"); + + // Retrieve IDs and search for user actions by ID + List ids = (List) ReflectionUtils.invokeMethod(getIdMethod(Collections + .singletonList(userActionSearch)), + userActionSearch); + log.info("Fetching closed household userActions with ids: {}", ids); + SearchResponse searchResponse = userActionTaskRepository.findById(ids, idFieldName); + return SearchResponse.builder().response(searchResponse.getResponse().stream() + .filter(lastChangedSince(urlParams.getLastChangedSince())) + .filter(havingTenantId(urlParams.getTenantId())) + .filter(includeDeleted(urlParams.getIncludeDeleted())) + .collect(Collectors.toList())).totalCount(searchResponse.getTotalCount()).build(); + } + + try { + // Search using the criteria specified in the request + log.info("Searching project user actions using criteria"); + return userActionTaskRepository.find(userActionSearch, urlParams); + } catch (QueryBuilderException e) { + // Handle and log query building exceptions + log.error("Error in building query: {}", ExceptionUtils.getStackTrace(e)); + throw new CustomException("ERROR_IN_QUERY", e.getMessage()); + } + } + + // Method to put user actions into cache + public void putInCache(List userActions) { + log.info("Putting {} closed household userActions in cache", userActions.size()); + userActionTaskRepository.putInCache(userActions); + log.info("Successfully put closed household userActions in cache"); + } +} diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java index 6bea9a663b5..2bd670f589f 100644 --- a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectEnrichment.java @@ -1,6 +1,12 @@ package org.egov.project.service.enrichment; +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.ObjectNode; import digit.models.coremodels.AuditDetails; +import java.util.Map; +import java.util.ArrayList; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.exception.ExceptionUtils; @@ -9,8 +15,10 @@ import org.egov.common.models.project.Project; import org.egov.common.models.project.ProjectRequest; import org.egov.common.models.project.Target; +import org.egov.common.producer.Producer; import org.egov.common.service.IdGenService; import org.egov.project.config.ProjectConfiguration; +import org.egov.project.service.ProjectService; import org.egov.project.util.ProjectServiceUtil; import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; @@ -30,6 +38,11 @@ public class ProjectEnrichment { @Autowired private ProjectServiceUtil projectServiceUtil; + @Autowired + private Producer producer; + @Autowired + private ProjectConfiguration projectConfiguration; + @Autowired private IdGenService idGenService; @@ -78,15 +91,8 @@ public void enrichProjectOnCreate(ProjectRequest request, List parentPr } /* Enrich Project on Update Request */ - public void enrichProjectOnUpdate(ProjectRequest request, List projectsFromDB) { + public void enrichProjectOnUpdate(ProjectRequest request, Project project , Project projectFromDB) { RequestInfo requestInfo = request.getRequestInfo(); - List projectsFromRequest = request.getProjects(); - - for (Project project : projectsFromRequest) { - String projectId = String.valueOf(project.getId()); - Project projectFromDB = projectsFromDB.stream().filter(p -> projectId.equals(String.valueOf(p.getId()))).findFirst().orElse(null); - - if (projectFromDB != null) { //Updating lastModifiedTime and lastModifiedBy for Project enrichProjectRequestOnUpdate(project, projectFromDB, requestInfo); log.info("Enriched project in update project request"); @@ -102,8 +108,6 @@ public void enrichProjectOnUpdate(ProjectRequest request, List projects //Add new document if id is empty or update lastModifiedTime and lastModifiedBy if id exists enrichProjectDocumentOnUpdate(project, projectFromDB, requestInfo); log.info("Enriched document in update project request"); - } - } } /* Enrich Project with id and audit details */ @@ -118,12 +122,174 @@ private void enrichProjectRequestOnCreate(Project projectRequest, RequestInfo re } /* Enrich Project update request with last modified by and last modified time */ - private void enrichProjectRequestOnUpdate(Project projectRequest, Project projectFromDB, RequestInfo requestInfo) { + public void enrichProjectRequestOnUpdate(Project projectRequest, Project projectFromDB, RequestInfo requestInfo) { projectRequest.setAuditDetails(projectFromDB.getAuditDetails()); AuditDetails auditDetails = projectServiceUtil.getAuditDetails(requestInfo.getUserInfo().getUuid(), projectFromDB.getAuditDetails(), false); projectRequest.setAuditDetails(auditDetails); log.info("Enriched project audit details for project " + projectRequest.getId()); } + public void enrichProjectCascadingDatesOnUpdate(Project project, Project projectFromDB) + { + // enrich project start and end dates along with ancestors and descendants + enrichProjectStartAndEndDateOfBothAncestorsAndDescendantsIfFoundAccordingly(project, + projectFromDB); + } + + private void enrichProjectStartAndEndDateOfBothAncestorsAndDescendantsIfFoundAccordingly( + Project projectRequest, Project projectFromDB) { + long startDate = projectRequest.getStartDate(); + long endDate = projectRequest.getEndDate(); + + /* + * Update both cycle dates and project start and end dates of descendants + */ + updateProjects(projectRequest, projectFromDB, startDate, endDate, true); + + /* + * Update both cycle dates and project start and end dates of ancestors in a way like start date = min(current, existing) + * and end date = max(current, existing) + */ + updateProjects(projectRequest, projectFromDB, startDate, endDate, false); + } + + + private void updateProjects(Project projectRequest, Project projectFromDB, long startDate, long endDate, boolean isDescendant) { + /* + * Get the list of projects from the database that are either descendants or ancestors + */ + List projectsFromDb = isDescendant ? projectFromDB.getDescendants() : projectFromDB.getAncestors(); + List modifiedProjectsFromDb = new ArrayList<>(); + + if (projectsFromDb != null) { + for (Project project : projectsFromDb) { + /* + * Update the project dates based on whether it is a descendant or ancestor + */ + updateProjectDates(project, startDate, endDate, isDescendant); + + /* + * Update the project cycles based on the request and whether it is a descendant or ancestor + */ + updateCycles(project, projectRequest, isDescendant); + + /* + * Add the modified project to the list + */ + modifiedProjectsFromDb.add(project); + } + + /* + * Push the modified projects to Kafka + */ + pushProjectsToKafka(modifiedProjectsFromDb); + } + } + + private void updateProjectDates(Project project, long startDate, long endDate, boolean isDescendant) { + if (isDescendant) { + /* + * For descendant projects, directly set the start and end dates + */ + project.setStartDate(startDate); + project.setEndDate(endDate); + } else { + /* + * For ancestor projects, set the start date to the minimum of the current and existing start dates, + * and set the end date to the maximum of the current and existing end dates + */ + project.setStartDate(Math.min(startDate, project.getStartDate())); + project.setEndDate(Math.max(endDate, project.getEndDate())); + } + } + + + private void updateCycles(Project descendantOrAncestor, Project projectRequest, boolean isDescendant) { + if (descendantOrAncestor.getAdditionalDetails() == null) { + return; + } + + ObjectMapper objectMapper = new ObjectMapper(); + + /* + * Extract additional details from descendant and request projects + */ + JsonNode descendantOrAncestorAdditionalDetails = objectMapper.valueToTree( + descendantOrAncestor.getAdditionalDetails()); + JsonNode descendantOrAncestorProjectTypeNode = descendantOrAncestorAdditionalDetails.get("projectType"); + + if (descendantOrAncestorProjectTypeNode != null) { + JsonNode descendantOrAncestorCyclesNode = descendantOrAncestorProjectTypeNode.get("cycles"); + + if (descendantOrAncestorCyclesNode != null && descendantOrAncestorCyclesNode.isArray()) { + /* + * Extract cycles from the request project + */ + JsonNode requestAdditionalDetails = objectMapper.valueToTree( + projectRequest.getAdditionalDetails()); + JsonNode requestProjectTypeNode = requestAdditionalDetails.get("projectType"); + + if (requestProjectTypeNode != null) { + JsonNode requestCyclesNode = requestProjectTypeNode.get("cycles"); + + if (requestCyclesNode != null && requestCyclesNode.isArray()) { + /* + * Iterate over descendant cycles and update as necessary + */ + for (JsonNode descendantOrAncestorCycleNode : descendantOrAncestorCyclesNode) { + String descendantOrAncestorCycleId = descendantOrAncestorCycleNode.get("id").asText(); + + for (JsonNode requestCycleNode : requestCyclesNode) { + String requestCycleId = requestCycleNode.get("id").asText(); + + if (descendantOrAncestorCycleId.equals(requestCycleId)) { + /* + * Update start and end dates of descendant cycle node + */ + long requestStartDate = requestCycleNode.get("startDate").asLong(); + long requestEndDate = requestCycleNode.get("endDate").asLong(); + long currentStartDate = descendantOrAncestorCycleNode.get("startDate").asLong(); + long currentEndDate = descendantOrAncestorCycleNode.get("endDate").asLong(); + if (isDescendant) { + ((ObjectNode) descendantOrAncestorCycleNode).put("startDate", requestStartDate); + ((ObjectNode) descendantOrAncestorCycleNode).put("endDate", requestEndDate); + } else { + ((ObjectNode) descendantOrAncestorCycleNode).put("startDate", + Math.min(requestStartDate, currentStartDate)); + ((ObjectNode) descendantOrAncestorCycleNode).put("endDate", + Math.max(requestEndDate, currentEndDate)); + } + break; // Once updated, exit the loop for this descendantCycleNode + } + } + } + + /* + * Convert updated additional details back to a map and set it on the descendant or ancestor project + */ + Map updatedAdditionalDetails = objectMapper.convertValue( + descendantOrAncestorAdditionalDetails, new TypeReference>() {}); + descendantOrAncestor.setAdditionalDetails(updatedAdditionalDetails); + } + } + } + } + } + + + private void pushProjectsToKafka(List projects) { + /* + * Create a ProjectRequest object with the list of projects + */ + ProjectRequest projectRequest = ProjectRequest.builder() + .projects(projects) + .build(); + + /* + * Push the ProjectRequest to the Kafka topic for updating projects + */ + producer.push(projectConfiguration.getUpdateProjectTopic(), projectRequest); + } + //Enrich Project with Parent Hierarchy. If parent Project hierarchy is not present then add parent locality at the beginning of project hierarchy, if present add Parent project's project hierarchy private void enrichProjectHierarchy(Project projectRequest, List parentProjects) { diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java index 9706c877ff2..db974db9be9 100644 --- a/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/ProjectTaskEnrichmentService.java @@ -1,5 +1,9 @@ package org.egov.project.service.enrichment; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import digit.models.coremodels.AuditDetails; import lombok.extern.slf4j.Slf4j; import org.egov.common.models.project.Address; @@ -11,10 +15,6 @@ import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - import static org.egov.common.utils.CommonUtils.enrichForCreate; import static org.egov.common.utils.CommonUtils.enrichForUpdate; import static org.egov.common.utils.CommonUtils.enrichId; @@ -67,20 +67,24 @@ public void delete(List validTasks, TaskBulkRequest request) throws Except for (Task task : validTasks) { if (task.getIsDeleted()) { log.info("enriching all task resources for delete"); - for (TaskResource resource : task.getResources()) { - resource.setIsDeleted(true); - updateAuditDetailsForResource(request, resource); + if(!CollectionUtils.isEmpty(task.getResources())) { + for (TaskResource resource : task.getResources()) { + resource.setIsDeleted(true); + updateAuditDetailsForResource(request, resource); + } } updateAuditDetailsForTask(request, task); task.setRowVersion(task.getRowVersion() + 1); } else { int previousRowVersion = task.getRowVersion(); log.info("enriching task resources for delete"); - task.getResources().stream().filter(TaskResource::getIsDeleted).forEach(resource -> { - updateAuditDetailsForResource(request, resource); - updateAuditDetailsForTask(request, task); - task.setRowVersion(previousRowVersion + 1); - }); + if(!CollectionUtils.isEmpty(task.getResources())) { + task.getResources().stream().filter(TaskResource::getIsDeleted).forEach(resource -> { + updateAuditDetailsForResource(request, resource); + updateAuditDetailsForTask(request, task); + task.setRowVersion(previousRowVersion + 1); + }); + } } } log.info("enrichment done"); @@ -103,6 +107,7 @@ private static void updateAuditDetailsForResource(TaskBulkRequest request, TaskR private static void enrichResourcesForUpdate(TaskBulkRequest request, List tasks) { log.info("enriching resources"); for (Task task : tasks) { + if(CollectionUtils.isEmpty(task.getResources())) continue; List resourcesToCreate = task.getResources().stream() .filter(r -> r.getId() == null).collect(Collectors.toList()); List resourcesToUpdate = task.getResources().stream() diff --git a/health-services/project/src/main/java/org/egov/project/service/enrichment/UserActionEnrichmentService.java b/health-services/project/src/main/java/org/egov/project/service/enrichment/UserActionEnrichmentService.java new file mode 100644 index 00000000000..afa331fc1cc --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/service/enrichment/UserActionEnrichmentService.java @@ -0,0 +1,67 @@ +package org.egov.project.service.enrichment; + +import java.util.List; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.service.IdGenService; +import org.egov.common.utils.CommonUtils; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.repository.UserActionRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import static org.egov.common.utils.CommonUtils.enrichForCreate; +import static org.egov.common.utils.CommonUtils.enrichForUpdate; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.project.Constants.PROJECT_USER_ACTION_ENRICHMENT_ERROR; + +@Service +@Slf4j +public class UserActionEnrichmentService { + private final IdGenService idGenService; + + private final ProjectConfiguration projectConfiguration; + + private final UserActionRepository userActionRepository; + + @Autowired + public UserActionEnrichmentService( + IdGenService idGenService, + ProjectConfiguration projectConfiguration, + UserActionRepository userActionRepository + ) { + this.idGenService = idGenService; + this.projectConfiguration = projectConfiguration; + this.userActionRepository = userActionRepository; + } + + public void create(List entities, UserActionBulkRequest request) { + log.info("starting the enrichment for create UserActions"); + log.info("generating IDs using UUID"); + try { + List idList = CommonUtils.uuidSupplier().apply(entities.size()); + log.info("enriching UserActions with generated IDs"); + enrichForCreate(entities, idList, request.getRequestInfo(),false); + log.info("enrichment done"); + } catch (Exception exception) { + log.error("Error during enrichment for create UserActions", exception); + throw new CustomException(PROJECT_USER_ACTION_ENRICHMENT_ERROR, "Error during enrichment for create UserActions" + exception); + } + } + + public void update(List entities, UserActionBulkRequest request) { + log.info("starting the enrichment for update UserActions"); + try { + Map userActionMap = getIdToObjMap(entities); + enrichForUpdate(userActionMap, entities, request); + log.info("enrichment done"); + } catch (Exception exception) { + log.error("Error during enrichment for update UserActions", exception); + throw new CustomException(PROJECT_USER_ACTION_ENRICHMENT_ERROR, "Error during enrichment for update UserActions" + exception); + } + } +} diff --git a/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java b/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java index 74a4e2df8fa..3a0a08d31ea 100644 --- a/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java +++ b/health-services/project/src/main/java/org/egov/project/util/BoundaryUtil.java @@ -92,4 +92,4 @@ public void validateBoundaryDetails(Map> locations, String } } -} +} \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java b/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java index 8bebbfda738..0252281f736 100644 --- a/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java +++ b/health-services/project/src/main/java/org/egov/project/util/ProjectConstants.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonValue; +import org.egov.common.models.project.TaskStatus; public class ProjectConstants { public static final String MASTER_TENANTS = "tenants"; @@ -25,33 +26,4 @@ public class ProjectConstants { public static final String OR = " OR "; - public enum TaskStatus { - BENEFICIARY_REFUSED("BENEFICIARY_REFUSED"), - BENEFICIARY_REFERRED("BENEFICIARY_REFERRED"), - BENEFICIARY_INELIGIBLE("BENEFICIARY_INELIGIBLE"), - BENEFICIARY_SICK("BENEFICIARY_SICK"), - BENEFICIARY_ABSENT("BENEFICIARY_ABSENT"); - private String value; - - TaskStatus(String value) { - this.value = value; - } - - @Override - @JsonValue - public String toString() { - return String.valueOf(value); - } - - @JsonCreator - public static TaskStatus fromValue(String text) { - for (TaskStatus status : TaskStatus.values()) { - if (String.valueOf(status.value).equals(text)) { - return status; - } - } - return null; - } - } - } \ No newline at end of file diff --git a/health-services/project/src/main/java/org/egov/project/util/ProjectServiceUtil.java b/health-services/project/src/main/java/org/egov/project/util/ProjectServiceUtil.java index 90b2c3cfe12..7d750e8d984 100644 --- a/health-services/project/src/main/java/org/egov/project/util/ProjectServiceUtil.java +++ b/health-services/project/src/main/java/org/egov/project/util/ProjectServiceUtil.java @@ -1,10 +1,23 @@ package org.egov.project.util; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; import digit.models.coremodels.AuditDetails; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import org.egov.common.models.project.Project; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import static java.util.Objects.isNull; @Component public class ProjectServiceUtil { + @Autowired + private ObjectMapper objectMapper; public AuditDetails getAuditDetails(String by, AuditDetails auditDetails, Boolean isCreate) { Long time = System.currentTimeMillis(); @@ -14,4 +27,53 @@ public AuditDetails getAuditDetails(String by, AuditDetails auditDetails, Boolea return AuditDetails.builder().createdBy(auditDetails.getCreatedBy()).lastModifiedBy(by) .createdTime(auditDetails.getCreatedTime()).lastModifiedTime(time).build(); } + + + /** + * Creates a map from a list of projects, using project IDs as keys. + * + * @param projects The list of projects to be converted into a map. + * @return A map with project IDs as keys and project objects as values. + */ + public Map createProjectMap(List projects) { + return projects.stream() + .collect(Collectors.toMap(p -> String.valueOf(p.getId()), Function.identity())); + } + + public void mergeAdditionalDetails( Project project , Project projectFromDb) { + project.setAdditionalDetails(jsonMerge( objectMapper.valueToTree(projectFromDb.getAdditionalDetails()), + objectMapper.valueToTree(project.getAdditionalDetails()))); + } + /** + * Method to merge additional details during update + * + * @param mainNode + * @param updateNode + * @return + */ + public JsonNode jsonMerge(JsonNode mainNode, JsonNode updateNode) { + + if (isNull(mainNode) || mainNode.isNull()) + return updateNode; + if (isNull(updateNode) || updateNode.isNull()) + return mainNode; + + Iterator fieldNames = updateNode.fieldNames(); + while (fieldNames.hasNext()) { + String fieldName = fieldNames.next(); + JsonNode jsonNode = mainNode.get(fieldName); + // if field exists and is an embedded object + if (jsonNode != null && jsonNode.isObject()) { + jsonMerge(jsonNode, updateNode.get(fieldName)); + } else { + if (mainNode instanceof ObjectNode) { + // Overwrite field + JsonNode value = updateNode.get(fieldName); + ((ObjectNode) mainNode).set(fieldName, value); + } + } + + } + return mainNode; + } } diff --git a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbExistentEntityValidator.java index 167969d09e3..97acdc3d867 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbExistentEntityValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/beneficiary/PbExistentEntityValidator.java @@ -15,16 +15,19 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; /** - * Validator class for checking the existence of entities with the given client reference IDs. + * Validator class for checking the existence of ProjectBeneficiary entities with the given client reference IDs. * This validator checks if the provided ProjectBeneficiary entities already exist in the database based on their client reference IDs. * + * The validation ensures that each ProjectBeneficiary entity in the bulk request has a unique client reference ID, + * and if an entity with the same client reference ID already exists, an error is recorded. + * * @author kanishq-egov */ @Component @@ -38,45 +41,62 @@ public class PbExistentEntityValidator implements Validator> validate(BeneficiaryBulkRequest request) { - // Map to hold ProjectBeneficiary entities and their error details + // Initialize a map to hold ProjectBeneficiary entities and their associated error details. Map> errorDetailsMap = new HashMap<>(); - // Get the list of ProjectBeneficiary entities from the request + + // Extract the list of ProjectBeneficiary entities from the request. List entities = request.getProjectBeneficiaries(); - // Extract client reference IDs from ProjectBeneficiary entities without errors + + // Extract the client reference IDs from ProjectBeneficiary entities that do not have existing errors. List clientReferenceIdList = entities.stream() - .filter(notHavingErrors()) - .map(ProjectBeneficiary::getClientReferenceId) - .collect(Collectors.toList()); - // Create a search object for querying entities by client reference IDs + .filter(notHavingErrors()) // Filter out entities that already have errors. + .map(ProjectBeneficiary::getClientReferenceId) // Map to extract client reference IDs. + .collect(Collectors.toList()); // Collect the IDs into a list. + + // Create a map of client reference ID to ProjectBeneficiary entity for quick lookup. + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty. + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map. + + // Create a search object to query entities by client reference IDs. ProjectBeneficiarySearch projectBeneficiarySearch = ProjectBeneficiarySearch.builder() - .clientReferenceId(clientReferenceIdList) + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search. .build(); - // Check if the client reference ID list is not empty + + // Check if the client reference ID list is not empty before querying the database. if (!CollectionUtils.isEmpty(clientReferenceIdList)) { - // Query the repository to find existing entities by client reference IDs - List existentEntities = projectBeneficiaryRepository.findById( - clientReferenceIdList, - getIdFieldName(projectBeneficiarySearch), - Boolean.FALSE).getResponse(); - // For each existing entity, populate error details for uniqueness - existentEntities.forEach(entity -> { + // Query the repository to find existing entities with the given client reference IDs. + List existingClientReferenceIds = + projectBeneficiaryRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, populate error details for the corresponding ProjectBeneficiary entity. + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation. Error error = getErrorForUniqueEntity(); - populateErrorDetails(entity, error, errorDetailsMap); + // Populate error details for the individual entity associated with the client reference ID. + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); }); } + + // Return the map containing ProjectBeneficiary entities and their associated error details. return errorDetailsMap; } diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtExistentEntityValidator.java index c3cb60b2b8c..ba4ebc24889 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtExistentEntityValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtExistentEntityValidator.java @@ -15,15 +15,18 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; /** - * Validator class for checking the existence of entities with the given client reference IDs. - * This validator checks if the provided Task entities already exist in the database based on their client reference IDs. + * Validator class for checking the existence of ProjectTask entities with the given client reference IDs. + * This validator ensures that the Task entities provided in the bulk request do not have duplicate client reference IDs in the database. + * + * The validation checks if each Task entity's client reference ID is unique across the database, + * and if a duplicate ID is found, it adds an error to the map with the entity. * * @author: kanishq-egov */ @@ -37,46 +40,62 @@ public class PtExistentEntityValidator implements Validator> validate(TaskBulkRequest request) { - // Map to hold Task entities and their error details + // Initialize a map to store Task entities and their associated error details. Map> errorDetailsMap = new HashMap<>(); - // Get the list of Task entities from the request + + // Extract the list of Task entities from the request. List entities = request.getTasks(); - // Extract client reference IDs from Task entities without errors + + // Extract client reference IDs from Task entities that do not have existing errors. List clientReferenceIdList = entities.stream() - .filter(notHavingErrors()) - .map(Task::getClientReferenceId) - .collect(Collectors.toList()); - // Create a search object for querying entities by client reference IDs + .filter(notHavingErrors()) // Filter out entities that already have errors. + .map(Task::getClientReferenceId) // Map to extract client reference IDs. + .collect(Collectors.toList()); // Collect the IDs into a list. + + // Create a map for quick lookup of Task entities by client reference ID. + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty. + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map. + + // Create a search object to query for existing entities based on client reference IDs. TaskSearch taskSearch = TaskSearch.builder() - .clientReferenceId(clientReferenceIdList) + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search. .build(); - // Check if the client reference ID list is not empty + + // Check if the client reference ID list is not empty before querying the database. if (!CollectionUtils.isEmpty(clientReferenceIdList)) { - // Query the repository to find existing entities by client reference IDs - List existentEntities = projectTaskRepository.findById( - clientReferenceIdList, - getIdFieldName(taskSearch), - Boolean.FALSE).getResponse(); - // For each existing entity, populate error details for uniqueness - existentEntities.forEach(entity -> { + // Query the repository to find existing entities with the given client reference IDs. + List existingClientReferenceIds = projectTaskRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, add an error to the map for the corresponding Task entity. + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation. Error error = getErrorForUniqueEntity(); - populateErrorDetails(entity, error, errorDetailsMap); + // Populate error details for the individual Task entity associated with the client reference ID. + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); }); } + + // Return the map containing Task entities and their associated error details. return errorDetailsMap; } } diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java index 4487d0ae5e4..03838764dce 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtIsResouceEmptyValidator.java @@ -1,20 +1,22 @@ package org.egov.project.validator.task; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + import lombok.extern.slf4j.Slf4j; import org.egov.common.models.Error; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskBulkRequest; import org.egov.common.validator.Validator; +import org.egov.project.config.ProjectConfiguration; import org.egov.project.util.ProjectConstants; import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.project.util.ProjectConstants.TASK_NOT_ALLOWED; @@ -26,6 +28,13 @@ @Slf4j public class PtIsResouceEmptyValidator implements Validator { + private final ProjectConfiguration projectConfiguration; + + @Autowired + public PtIsResouceEmptyValidator(ProjectConfiguration projectConfiguration) { + this.projectConfiguration = projectConfiguration; + } + /** * Returns all the invalid objects in the request based on the task resources. * @param request of TaskBulkRequest class @@ -36,42 +45,20 @@ public Map> validate(TaskBulkRequest request) { List entities = request.getTasks(); if(!entities.isEmpty()) { entities.forEach(task -> { - if(CollectionUtils.isEmpty(task.getResources()) && - !(ProjectConstants.TaskStatus.BENEFICIARY_REFUSED.toString().equals(task.getStatus()) - || ProjectConstants.TaskStatus.BENEFICIARY_INELIGIBLE.toString().equals(task.getStatus()) - || ProjectConstants.TaskStatus.BENEFICIARY_REFERRED.toString().equals(task.getStatus()) - || ProjectConstants.TaskStatus.BENEFICIARY_SICK.toString().equals(task.getStatus()) - || ProjectConstants.TaskStatus.BENEFICIARY_ABSENT.toString().equals(task.getStatus()))) { + if (CollectionUtils.isEmpty(task.getResources()) && + !projectConfiguration.getNoResourceStatuses().contains(task.getStatus().toString())) { /** * If the task resource is empty or null and task status is not BENEFICIARY_REFUSED it is invalid */ + String errorMessage = ProjectConstants.TASK_NOT_ALLOWED_RESOURCE_CANNOT_EMPTY_ERROR_MESSAGE + + String.join(ProjectConstants.OR, projectConfiguration.getNoResourceStatuses()); Error error = Error.builder() - .errorMessage(ProjectConstants.TASK_NOT_ALLOWED_RESOURCE_CANNOT_EMPTY_ERROR_MESSAGE + - ProjectConstants.TaskStatus.BENEFICIARY_REFUSED + - ProjectConstants.OR + ProjectConstants.TaskStatus.BENEFICIARY_INELIGIBLE + - ProjectConstants.OR + ProjectConstants.TaskStatus.BENEFICIARY_REFERRED + - ProjectConstants.OR + ProjectConstants.TaskStatus.BENEFICIARY_SICK + - ProjectConstants.OR + ProjectConstants.TaskStatus.BENEFICIARY_ABSENT) - .errorCode(TASK_NOT_ALLOWED) - .type(Error.ErrorType.NON_RECOVERABLE) - .exception(new CustomException(TASK_NOT_ALLOWED, - ProjectConstants.TASK_NOT_ALLOWED_RESOURCE_CANNOT_EMPTY_ERROR_MESSAGE + - ProjectConstants.TaskStatus.BENEFICIARY_REFUSED + - ProjectConstants.OR + - ProjectConstants.TaskStatus.BENEFICIARY_INELIGIBLE + - ProjectConstants.OR + - ProjectConstants.TaskStatus.BENEFICIARY_REFERRED + - ProjectConstants.OR + - ProjectConstants.TaskStatus.BENEFICIARY_SICK + - ProjectConstants.OR + - ProjectConstants.TaskStatus.BENEFICIARY_ABSENT)).build(); + .errorMessage(errorMessage) + .errorCode(TASK_NOT_ALLOWED) + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException(TASK_NOT_ALLOWED, errorMessage)).build(); populateErrorDetails(task, error, errorDetailsMap); - } else if (!CollectionUtils.isEmpty(task.getResources()) && - (ProjectConstants.TaskStatus.BENEFICIARY_REFUSED.toString().equals(task.getStatus()) - || ProjectConstants.TaskStatus.BENEFICIARY_INELIGIBLE.toString().equals(task.getStatus()) - || ProjectConstants.TaskStatus.BENEFICIARY_REFERRED.toString().equals(task.getStatus()) - || ProjectConstants.TaskStatus.BENEFICIARY_SICK.toString().equals(task.getStatus()) - || ProjectConstants.TaskStatus.BENEFICIARY_ABSENT.toString().equals(task.getStatus()))) { + } else if (!CollectionUtils.isEmpty(task.getResources()) && projectConfiguration.getNoResourceStatuses().contains(task.getStatus().toString())) { /** * If the task resource is not empty and task status is BENEFICIARY_REFUSED */ diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtNonExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtNonExistentEntityValidator.java index 52b577acdbe..5a1ceaa0b3b 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtNonExistentEntityValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtNonExistentEntityValidator.java @@ -88,10 +88,10 @@ public Map> validate(TaskBulkRequest request) { }); existingEntities.forEach(task -> { - validateSubEntity(errorDetailsMap, eMap, task, + if(task.getAddress() != null) validateSubEntity(errorDetailsMap, eMap, task, Collections.singletonList(task.getAddress()), GET_ADDRESS); - validateSubEntity(errorDetailsMap, eMap, task, + if(task.getResources() != null) validateSubEntity(errorDetailsMap, eMap, task, task.getResources(), GET_RESOURCES); }); } @@ -106,10 +106,10 @@ private void validateSubEntity(Map> errorDetailsMap, String getSubEntityMethodName) { Object objFromReq = ReflectionUtils.invokeMethod(getMethod(getSubEntityMethodName, Task.class), eMap.get(entity.getId())); - List subEntitiesInReq; + List subEntitiesInReq = null; if (objFromReq instanceof List) { subEntitiesInReq = (List) objFromReq; - } else { + } else if(objFromReq != null) { // if else condition here is added to prevent creating a list of null values, and if objFromReq is null then it will bypass line 116 till end of function. subEntitiesInReq = (List) Collections.singletonList(objFromReq); } diff --git a/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java index 94b2aaea221..e3be161fabb 100644 --- a/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java +++ b/health-services/project/src/main/java/org/egov/project/validator/task/PtResourceQuantityValidator.java @@ -26,6 +26,7 @@ import org.egov.tracer.model.CustomException; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; import static org.egov.project.Constants.INTERNAL_SERVER_ERROR; import static org.egov.project.Constants.MDMS_RESPONSE; @@ -76,10 +77,12 @@ public Map> validate(TaskBulkRequest request) { List errors = new ArrayList<>(); // Extract the list of task resources List taskResources = task.getResources(); - for(TaskResource taskResource : taskResources){ - Error error = validateResourceQuantity(taskResource, request.getRequestInfo()); - if(error != null){ - errors.add(error); + if(!CollectionUtils.isEmpty(taskResources)) { + for(TaskResource taskResource : taskResources){ + Error error = validateResourceQuantity(taskResource, request.getRequestInfo()); + if(error != null){ + errors.add(error); + } } } if (!errors.isEmpty()){ diff --git a/health-services/project/src/main/java/org/egov/project/validator/useraction/UaBoundaryValidator.java b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaBoundaryValidator.java new file mode 100644 index 00000000000..4f0394c1556 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaBoundaryValidator.java @@ -0,0 +1,125 @@ +package org.egov.project.validator.useraction; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.Error; +import org.egov.common.models.core.Boundary; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.web.models.boundary.BoundaryResponse; +import org.egov.tracer.model.CustomException; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import static org.egov.common.utils.CommonUtils.populateErrorDetails; + +/** + * Validator class for validating userAction boundaries. + */ +@Component +@Order(value = 4) +@Slf4j +public class UaBoundaryValidator implements Validator { + + private final ServiceRequestClient serviceRequestClient; + + private final ProjectConfiguration projectConfiguration; + + /** + * Constructor to initialize the HBoundaryValidator. + * + * @param serviceRequestClient Service request client for making HTTP requests + * @param projectConfiguration Configuration properties for the userAction module + */ + public UaBoundaryValidator(ServiceRequestClient serviceRequestClient, ProjectConfiguration projectConfiguration) { + this.serviceRequestClient = serviceRequestClient; + this.projectConfiguration = projectConfiguration; + } + + /** + * Validates the userActions' boundaries. + * + * @param request the bulk request containing userActions + * @return a map containing userActions with their corresponding list of errors + */ + @Override + public Map> validate(UserActionBulkRequest request) { + log.debug("Validating userActions boundaries."); + // Create a HashMap to store error details for each userAction + HashMap> errorDetailsMap = new HashMap<>(); + + // Filter userActions with non-null addresses + List entitiesWithValidBoundaries = request.getUserActions().parallelStream() + .filter(userAction -> Objects.nonNull(userAction.getBoundaryCode())) // Exclude null boundary codes + .collect(Collectors.toList()); + + Map> tenantIdUserActionMap = entitiesWithValidBoundaries.stream().collect(Collectors.groupingBy(UserAction::getTenantId)); + + tenantIdUserActionMap.forEach((tenantId, userActions) -> { + // Group userActions by locality code + Map> boundaryCodeUserActionsMap = userActions.stream() + .collect(Collectors.groupingBy( + userAction -> userAction.getBoundaryCode() // Group by boundary code + )); + + List boundaries = new ArrayList<>(boundaryCodeUserActionsMap.keySet()); + if(!CollectionUtils.isEmpty(boundaries)) { + try { + // Fetch boundary details from the service + log.debug("Fetching boundary details for tenantId: {}, boundaries: {}", tenantId, boundaries); + BoundaryResponse boundarySearchResponse = serviceRequestClient.fetchResult( + new StringBuilder(projectConfiguration.getBoundaryServiceHost() + + projectConfiguration.getBoundarySearchUrl() + +"?limit=" + boundaries.size() + + "&offset=0&tenantId=" + tenantId + + "&codes=" + String.join(",", boundaries)), + request.getRequestInfo(), + BoundaryResponse.class + ); + log.debug("Boundary details fetched successfully for tenantId: {}", tenantId); + + List invalidBoundaryCodes = new ArrayList<>(boundaries); + invalidBoundaryCodes.removeAll(boundarySearchResponse.getBoundary().stream() + .map(Boundary::getCode) + .collect(Collectors.toList()) + ); + + // Filter out userActions with invalid boundary codes + List userActionsWithInvalidBoundaries = boundaryCodeUserActionsMap.entrySet().stream() + .filter(entry -> invalidBoundaryCodes.contains(entry.getKey())) // filter invalid boundary codes + .flatMap(entry -> entry.getValue().stream()) // Flatten the list of userActions + .collect(Collectors.toList()); + + // Create an error object for userActions with invalid boundaries + Error error = Error.builder() + .errorMessage("Boundary code does not exist in db") + .errorCode("PROJECT_USER_ACTION_INVALID_BOUNDARY_ERROR") + .type(Error.ErrorType.NON_RECOVERABLE) + .exception(new CustomException("PROJECT_USER_ACTION_INVALID_BOUNDARY_ERROR", "Boundary code does not exist in db")) + .build(); + userActionsWithInvalidBoundaries.forEach(userAction -> { + // Populate error details for the userAction + populateErrorDetails(userAction, error, errorDetailsMap); + }); + + } catch (Exception e) { + log.error("Exception while searching boundaries for tenantId: {}", tenantId, e); + // Throw a custom exception if an error occurs during boundary search + throw new CustomException("BOUNDARY_SERVICE_SEARCH_ERROR","Error in while fetching boundaries from Boundary Service : " + e.getMessage()); + } + } + }); + + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/useraction/UaExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaExistentEntityValidator.java new file mode 100644 index 00000000000..e5f3ff7a026 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaExistentEntityValidator.java @@ -0,0 +1,99 @@ +package org.egov.project.validator.useraction; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.models.project.useraction.UserActionSearch; +import org.egov.common.validator.Validator; +import org.egov.project.repository.UserActionRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; + +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; + +/** + * Validator class for checking the existence of UserAction entities based on their client reference IDs. + * This validator ensures that the UserAction entities in the bulk request do not have duplicate client reference IDs in the database. + * + * The validation checks if each UserAction entity's client reference ID already exists in the database. + * If a duplicate ID is found, it adds an error to the map with the entity. + * + * @author: kanishq-egov + */ +@Component +@Order(value = 1) +@Slf4j +public class UaExistentEntityValidator implements Validator { + private UserActionRepository userActionRepository; + + /** + * Constructs a UaExistentEntityValidator with the specified UserActionRepository. + * + * @param userActionRepository the repository used to validate UserAction entities. + */ + @Autowired + public UaExistentEntityValidator(UserActionRepository userActionRepository) { + this.userActionRepository = userActionRepository; + } + + /** + * Validates the existence of UserAction entities in the UserActionBulkRequest. + * Checks if the provided UserAction entities already exist in the database based on their client reference IDs. + * + * @param request the bulk request containing UserAction entities. + * @return a map of UserAction entities and their associated error details. + */ + @Override + public Map> validate(UserActionBulkRequest request) { + // Map to hold UserAction entities and their error details. + log.info("Validating existence of entities in UserActionBulkRequest with {} entities", request.getUserActions().size()); + Map> errorDetailsMap = new HashMap<>(); + + // Get the list of UserAction entities from the request. + List entities = request.getUserActions(); + + // Extract client reference IDs from UserAction entities that do not have existing errors. + List clientReferenceIdList = entities.stream() + .filter(notHavingErrors()) // Filter out entities that already have errors. + .map(UserAction::getClientReferenceId) // Map to extract client reference IDs. + .collect(Collectors.toList()); // Collect the IDs into a list. + + // Create a map for quick lookup of UserAction entities by client reference ID. + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty. + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map. + + // Create a search object to query for existing UserAction entities based on client reference IDs. + UserActionSearch userActionSearch = UserActionSearch.builder() + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search. + .build(); + + // Check if the client reference ID list is not empty before querying the database. + if (!CollectionUtils.isEmpty(clientReferenceIdList)) { + // Query the repository to find existing UserAction entities with the given client reference IDs. + List existingClientReferenceIds = userActionRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.FALSE); + + // For each existing client reference ID, add an error to the map for the corresponding UserAction entity. + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation. + Error error = getErrorForUniqueEntity(); + // Populate error details for the individual UserAction entity associated with the client reference ID. + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); + }); + } + + // Return the map containing UserAction entities and their associated error details. + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/useraction/UaNonExistentEntityValidator.java b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaNonExistentEntityValidator.java new file mode 100644 index 00000000000..c2b2534c1b0 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaNonExistentEntityValidator.java @@ -0,0 +1,96 @@ +package org.egov.project.validator.useraction; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.models.project.useraction.UserActionSearch; +import org.egov.common.validator.Validator; +import org.egov.project.repository.UserActionRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.checkNonExistentEntities; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.getObjClass; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentEntity; +import static org.egov.project.Constants.GET_ID; + +@Component +@Order(value = 4) +@Slf4j +public class UaNonExistentEntityValidator implements Validator { + + private final UserActionRepository userActionRepository; + + @Autowired + public UaNonExistentEntityValidator(UserActionRepository userActionRepository) { + this.userActionRepository = userActionRepository; + } + + + @Override + public Map> validate(UserActionBulkRequest request) { + log.info("Validating existence of entities in UserActionBulkRequest with {} user actions", request.getUserActions().size()); + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getUserActions(); + Class objClass = getObjClass(entities); + Method idMethod = getMethod(GET_ID, objClass); + Map eMap = getIdToObjMap(entities + .stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + // Lists to store IDs and client reference IDs + List idList = new ArrayList<>(); + List clientReferenceIdList = new ArrayList<>(); + // Extract IDs and client reference IDs from Project UserAction entities + entities.forEach(entity -> { + idList.add(entity.getId()); + clientReferenceIdList.add(entity.getClientReferenceId()); + }); + if (!eMap.isEmpty()) { + UserActionSearch taskSearch = UserActionSearch.builder() + .clientReferenceId(clientReferenceIdList) + .id(idList) + .build(); + + URLParams urlParams = URLParams.builder() + .tenantId(entities.get(0).getTenantId()) + .limit(entities.size()) + .offset(0) + .includeDeleted(false) + .lastChangedSince(null) + .build(); + + List existingEntities; + try { + // Query the repository to find existing entities + existingEntities = userActionRepository.find(taskSearch, urlParams).getResponse(); + } catch (Exception e) { + // Handle query builder exception + log.error("Search failed for ProjectUserAction with error: {}", e.getMessage(), e); + throw new CustomException("PROJECT_USER_ACTION_SEARCH_FAILED", "Search failed for ProjectUserAction with clientReferenceId(s): " + + clientReferenceIdList + " and id(s): " + idList + ". Error: " + e.getMessage()); + } + List nonExistentEntities = checkNonExistentEntities(eMap, + existingEntities, idMethod); + nonExistentEntities.forEach(task -> { + Error error = getErrorForNonExistentEntity(); + populateErrorDetails(task, error, errorDetailsMap); + }); + } + + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/useraction/UaNullIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaNullIdValidator.java new file mode 100644 index 00000000000..52196f57f96 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaNullIdValidator.java @@ -0,0 +1,27 @@ +package org.egov.project.validator.useraction; + +import java.util.List; +import java.util.Map; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.validator.Validator; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.validateForNullId; +import static org.egov.project.Constants.GET_USER_ACTION; + +@Component +@Order(value = 1) +@Slf4j +public class UaNullIdValidator implements Validator { + + @Override + public Map> validate(UserActionBulkRequest request) { + log.info("validating for null id"); + return validateForNullId(request, GET_USER_ACTION); + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/useraction/UaProjectIdValidator.java b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaProjectIdValidator.java new file mode 100644 index 00000000000..b7c6ea63277 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaProjectIdValidator.java @@ -0,0 +1,96 @@ +package org.egov.project.validator.useraction; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.project.repository.ProjectRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.getMethod; +import static org.egov.common.utils.CommonUtils.getObjClass; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForNonExistentRelatedEntity; + +/** + * UaProjectIdValidator is responsible for validating the Project IDs in UserActionBulkRequest. + * It checks if the Project IDs present in the UserAction entities exist in the Project repository. + */ +@Component +@Order(value = 6) +@Slf4j +public class UaProjectIdValidator implements Validator { + + private ProjectRepository projectRepository; + + @Autowired + public UaProjectIdValidator(ProjectRepository projectRepository) { + this.projectRepository = projectRepository; + } + + /** + * Validates the Project IDs in the UserActionBulkRequest. + * It checks if the Project IDs present in the UserAction entities exist in the Project repository. + * + * @param request the UserActionBulkRequest containing UserAction entities to be validated. + * @return a map of UserAction entities to a list of Errors encountered during validation. + */ + @Override + public Map> validate(UserActionBulkRequest request) { + log.info("Starting validation of project IDs in UserActionBulkRequest with {} entities", request.getUserActions().size()); + + Map> errorDetailsMap = new HashMap<>(); + List entities = request.getUserActions(); + + // Retrieve the class of the UserAction entities + Class objClass = getObjClass(entities); + log.debug("Retrieved UserAction entity class: {}", objClass.getName()); + + // Retrieve the method to get ProjectId from UserAction entities + Method idMethod = getMethod("getProjectId", objClass); + log.debug("Retrieved getProjectId method from UserAction entity class"); + + // Create a map of Project IDs to UserAction entities + Map eMap = getIdToObjMap(entities.stream().filter(notHavingErrors()).collect(Collectors.toList()), idMethod); + log.info("Created map of Project IDs to UserAction entities with {} entries", eMap.size()); + + if (!eMap.isEmpty()) { + List entityIds = new ArrayList<>(eMap.keySet()); + log.debug("List of Project IDs to validate: {}", entityIds); + + // Validate the Project IDs by checking their existence in the Project repository + List existingProjectIds = projectRepository.validateIds(entityIds, getIdFieldName(idMethod)); + log.info("Retrieved list of existing Project IDs from Project repository: {}", existingProjectIds); + + // Identify invalid UserAction entities with non-existent Project IDs + List invalidEntities = entities.stream().filter(notHavingErrors()).filter(entity -> + !existingProjectIds.contains(entity.getProjectId())).collect(Collectors.toList()); + log.info("Identified {} invalid UserAction entities with non-existent Project IDs", invalidEntities.size()); + + // Populate error details for invalid UserAction entities + invalidEntities.forEach(userAction -> { + Error error = getErrorForNonExistentRelatedEntity(userAction.getProjectId()); + populateErrorDetails(userAction, error, errorDetailsMap); + log.debug("Populated error details for UserAction with invalid Project ID: {}", userAction.getProjectId()); + }); + } else { + log.info("No Project IDs to validate as the map of Project IDs to UserAction entities is empty"); + } + + log.info("Completed validation of project IDs in UserActionBulkRequest"); + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/validator/useraction/UaRowVersionValidator.java b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaRowVersionValidator.java new file mode 100644 index 00000000000..45c8381d120 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/validator/useraction/UaRowVersionValidator.java @@ -0,0 +1,69 @@ +package org.egov.project.validator.useraction; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.models.Error; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.validator.Validator; +import org.egov.project.repository.UserActionRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import static org.egov.common.utils.CommonUtils.getEntitiesWithMismatchedRowVersion; +import static org.egov.common.utils.CommonUtils.getIdFieldName; +import static org.egov.common.utils.CommonUtils.getIdMethod; +import static org.egov.common.utils.CommonUtils.getIdToObjMap; +import static org.egov.common.utils.CommonUtils.notHavingErrors; +import static org.egov.common.utils.CommonUtils.populateErrorDetails; +import static org.egov.common.utils.ValidatorUtils.getErrorForRowVersionMismatch; + +@Component +@Order(value = 5) +@Slf4j +public class UaRowVersionValidator implements Validator { + + private final UserActionRepository userActionRepository; + + @Autowired + public UaRowVersionValidator(UserActionRepository userActionRepository) { + this.userActionRepository = userActionRepository; + } + + + @Override + public Map> validate(UserActionBulkRequest request) { + log.info("validating row version"); + Map> errorDetailsMap = new HashMap<>(); + try { + + Method idMethod = getIdMethod(request.getUserActions()); + Map eMap = getIdToObjMap(request.getUserActions().stream() + .filter(notHavingErrors()) + .collect(Collectors.toList()), idMethod); + if (!eMap.isEmpty()) { + List entityIds = new ArrayList<>(eMap.keySet()); + List existingEntities = userActionRepository.findById(entityIds, + getIdFieldName(idMethod)).getResponse(); + List entitiesWithMismatchedRowVersion = + getEntitiesWithMismatchedRowVersion(eMap, existingEntities, idMethod); + entitiesWithMismatchedRowVersion.forEach(individual -> { + Error error = getErrorForRowVersionMismatch(); + populateErrorDetails(individual, error, errorDetailsMap); + }); + } + } catch (Exception e) { + log.error("Exception occurred during validation: {}", e.getMessage()); + throw new CustomException("PROJECT_USER_ACTION_PROJECT_ID_VALIDATION_ERROR", "Error occurred while validating project IDs"+e); + } + return errorDetailsMap; + } +} diff --git a/health-services/project/src/main/java/org/egov/project/web/controllers/LocationCaptureController.java b/health-services/project/src/main/java/org/egov/project/web/controllers/LocationCaptureController.java new file mode 100644 index 00000000000..2214594b313 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/web/controllers/LocationCaptureController.java @@ -0,0 +1,130 @@ +package org.egov.project.web.controllers; + +import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.models.project.useraction.UserActionBulkResponse; +import org.egov.common.models.project.useraction.UserActionSearchRequest; +import org.egov.common.producer.Producer; +import org.egov.common.utils.ResponseInfoFactory; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.service.LocationCaptureService; +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.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Controller for handling requests related to location capture tasks. + * Provides endpoints for creating and searching location capture tasks. + */ +@Controller +@RequestMapping("/user-location") +@Validated +@Slf4j +public class LocationCaptureController { + + private final HttpServletRequest httpServletRequest; + private final LocationCaptureService locationCaptureService; + private final Producer producer; + private final ProjectConfiguration projectConfiguration; + + /** + * Constructor for injecting dependencies into the LocationCaptureController. + * + * @param httpServletRequest The HttpServletRequest to capture request details. + * @param locationCaptureService The service for handling location capture logic. + * @param producer The producer for sending messages to Kafka topics. + * @param projectConfiguration Configuration properties related to the project. + */ + @Autowired + public LocationCaptureController( + HttpServletRequest httpServletRequest, + LocationCaptureService locationCaptureService, + Producer producer, + ProjectConfiguration projectConfiguration + ) { + this.httpServletRequest = httpServletRequest; + this.locationCaptureService = locationCaptureService; + this.producer = producer; + this.projectConfiguration = projectConfiguration; + } + + /** + * Endpoint for creating location capture tasks in bulk. + * Receives a UserActionBulkRequest object, processes it, and sends it to the appropriate Kafka topic. + * + * @param request The bulk request containing user actions to be created. + * @return A ResponseEntity containing the response info with HTTP status ACCEPTED. + */ + @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) + public ResponseEntity locationCaptureTaskV1BulkCreatePost( + @ApiParam(value = "Create Location Capture LocationCapture.", required = true) @Valid @RequestBody UserActionBulkRequest request) { + // Set the API ID in the request info using the current request URI. + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + + try { + // Send the request to the Kafka topic for bulk creation. + producer.push(projectConfiguration.getBulkCreateLocationCaptureTopic(), request); + } catch (Exception e) { + log.error("Error sending bulk create request for location captures to Kafka: {}", e.getMessage(), e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body( + ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), false) + ); + } + + // Create and return a ResponseInfo object with HTTP status ACCEPTED. + return ResponseEntity.status(HttpStatus.ACCEPTED).body( + ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), true) + ); + } + + /** + * Endpoint for searching location capture tasks based on given search criteria. + * Receives a UserActionSearchRequest object and returns the search results. + * + * @param urlParams URL parameters for the search. + * @param locationCaptureSearchRequest The request containing search criteria for location capture tasks. + * @return A ResponseEntity containing the search results with HTTP status OK. + * @throws Exception if there is an error during the search operation. + */ + @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) + public ResponseEntity locationCaptureTaskV2SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Search details of Location Capture.", required = true) @Valid @RequestBody UserActionSearchRequest locationCaptureSearchRequest + ) throws Exception { + + try { + // Perform the search using the locationCaptureService. + SearchResponse locationCaptureSearchResponse = locationCaptureService.search(locationCaptureSearchRequest, urlParams); + + // Build the response object with the search results and response info. + UserActionBulkResponse response = UserActionBulkResponse.builder() + .userActions(locationCaptureSearchResponse.getResponse()) + .totalCount(locationCaptureSearchResponse.getTotalCount()) + .responseInfo(ResponseInfoFactory.createResponseInfo(locationCaptureSearchRequest.getRequestInfo(), true)) + .build(); + + // Return the response with HTTP status OK. + return ResponseEntity.status(HttpStatus.OK).body(response); + } catch (Exception e) { + log.error("Error occurred during search operation for location captures: {}", e.getMessage(), e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body( + UserActionBulkResponse.builder() + .responseInfo(ResponseInfoFactory.createResponseInfo(locationCaptureSearchRequest.getRequestInfo(), false)) + .build() + ); + } + } +} diff --git a/health-services/project/src/main/java/org/egov/project/web/controllers/UserActionController.java b/health-services/project/src/main/java/org/egov/project/web/controllers/UserActionController.java new file mode 100644 index 00000000000..34a56ae9ca5 --- /dev/null +++ b/health-services/project/src/main/java/org/egov/project/web/controllers/UserActionController.java @@ -0,0 +1,162 @@ +package org.egov.project.web.controllers; + +import io.swagger.annotations.ApiParam; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.Valid; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.response.ResponseInfo; +import org.egov.common.models.core.SearchResponse; +import org.egov.common.models.core.URLParams; +import org.egov.common.models.project.useraction.UserAction; +import org.egov.common.models.project.useraction.UserActionBulkRequest; +import org.egov.common.models.project.useraction.UserActionBulkResponse; +import org.egov.common.models.project.useraction.UserActionSearchRequest; +import org.egov.common.producer.Producer; +import org.egov.common.utils.ResponseInfoFactory; +import org.egov.project.config.ProjectConfiguration; +import org.egov.project.service.UserActionService; +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.validation.annotation.Validated; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +/** + * Controller for handling user action-related requests. + * Provides endpoints for creating, updating, and searching user actions. + */ +@Controller +@RequestMapping("/user-action") +@Validated +@Slf4j +public class UserActionController { + + private final HttpServletRequest httpServletRequest; + private final UserActionService userActionService; + private final Producer producer; + private final ProjectConfiguration projectConfiguration; + + /** + * Constructor for injecting dependencies into the UserActionController. + * + * @param httpServletRequest The HttpServletRequest to capture request details. + * @param userActionService The service for handling user action logic. + * @param producer The producer for sending messages to Kafka topics. + * @param projectConfiguration Configuration properties related to the project. + */ + @Autowired + public UserActionController( + HttpServletRequest httpServletRequest, + UserActionService userActionService, + Producer producer, + ProjectConfiguration projectConfiguration + ) { + this.httpServletRequest = httpServletRequest; + this.userActionService = userActionService; + this.producer = producer; + this.projectConfiguration = projectConfiguration; + } + + /** + * Endpoint for creating user actions in bulk. + * Receives a UserActionBulkRequest object, processes it, and sends it to the appropriate Kafka topic. + * + * @param request The bulk request containing user actions to be created. + * @return A ResponseEntity containing the response info with HTTP status ACCEPTED. + */ + @RequestMapping(value = "/v1/_create", method = RequestMethod.POST) + public ResponseEntity userActionV1BulkCreatePost( + @ApiParam(value = "Capture linkage of Project and User Action UserAction.", required = true) @Valid @RequestBody UserActionBulkRequest request + ) { + // Set the API ID in the request info using the current request URI. + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + + try { + log.debug("Pushing user action bulk create request to Kafka topic: {}", projectConfiguration.getBulkCreateUserActionTopic()); + // Send the request to the Kafka topic for bulk creation. + producer.push(projectConfiguration.getBulkCreateUserActionTopic(), request); + log.info("Successfully pushed user action bulk create request to Kafka"); + } catch (Exception e) { + log.error("Failed to push user action bulk create request to Kafka", e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body( + ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), false) + ); + } + + // Create and return a ResponseInfo object with HTTP status ACCEPTED. + return ResponseEntity.status(HttpStatus.ACCEPTED).body( + ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), true) + ); + } + + /** + * Endpoint for searching user actions based on given search criteria. + * Receives a UserActionSearchRequest object and returns the search results. + * + * @param urlParams URL parameters for the search. + * @param request The request containing search criteria for user actions. + * @return A ResponseEntity containing the search results with HTTP status OK. + */ + @RequestMapping(value = "/v1/_search", method = RequestMethod.POST) + public ResponseEntity userActionV2SearchPost( + @Valid @ModelAttribute URLParams urlParams, + @ApiParam(value = "Capture details of Project User Action UserAction.", required = true) @Valid @RequestBody UserActionSearchRequest request + ) { + log.debug("Executing search with URLParams: {} and request: {}", urlParams, request); + + // Perform the search using the userActionService. + SearchResponse userActions; + try { + // Perform the search using the userActionService. + userActions = userActionService.search(request, urlParams); + log.info("Successfully searched for user actions: {}", userActions.getResponse().size()); + } catch (Exception e) { + log.error("Failed to search for user actions", e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null); + } + + // Build the response object with the search results and response info. + UserActionBulkResponse response = UserActionBulkResponse.builder() + .userActions(userActions.getResponse()) + .totalCount(userActions.getTotalCount()) + .responseInfo(ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), true)) + .build(); + + // Return the response with HTTP status OK. + return ResponseEntity.status(HttpStatus.OK).body(response); + } + + /** + * Endpoint for updating user actions in bulk. + * Receives a UserActionBulkRequest object, processes it, and sends it to the appropriate Kafka topic. + * + * @param request The bulk request containing user actions to be updated. + * @return A ResponseEntity containing the response info with HTTP status ACCEPTED. + */ + @RequestMapping(value = "/v1/_update", method = RequestMethod.POST) + public ResponseEntity userActionV1BulkUpdatePost( + @ApiParam(value = "Capture linkage of Project and User Action UserAction.", required = true) @Valid @RequestBody UserActionBulkRequest request + ) { + // Set the API ID in the request info using the current request URI. + request.getRequestInfo().setApiId(httpServletRequest.getRequestURI()); + + try { + // Send the request to the Kafka topic for bulk update. + producer.push(projectConfiguration.getBulkUpdateUserActionTopic(), request); + } catch (Exception e) { + log.error("Failed to push user action bulk update request to Kafka", e); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body( + ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), false) + ); + } + + // Create and return a ResponseInfo object with HTTP status ACCEPTED. + return ResponseEntity.status(HttpStatus.ACCEPTED).body( + ResponseInfoFactory.createResponseInfo(request.getRequestInfo(), true) + ); + } +} diff --git a/health-services/project/src/main/resources/application.properties b/health-services/project/src/main/resources/application.properties index f52ba8f6584..93f601466a9 100644 --- a/health-services/project/src/main/resources/application.properties +++ b/health-services/project/src/main/resources/application.properties @@ -144,6 +144,7 @@ project.search.max.limit=200 project.management.system.kafka.create.topic=save-project project.management.system.kafka.update.topic=update-project +project.management.system.kafka.update.date.topic=update-project-date # BOUNDARY SERVICE egov.boundary.host=http://localhost:8081 @@ -168,3 +169,15 @@ egov.location.hierarchy.type=ADMIN #---------Attendance-----------# project.staff.attendance.topic=project-staff-attendance-health-topic +#-------Closed Household Task-------# +project.user.action.kafka.create.topic=save-user-action-project-topic +project.user.action.kafka.update.topic=update-user-action-project-topic +project.user.action.consumer.bulk.create.topic=save-user-action-project-bulk-topic +project.user.action.consumer.bulk.update.topic=update-user-action-project-bulk-topic + +#-------Location Capture Task-------# +project.location.capture.kafka.create.topic=save-location-capture-project-topic +project.location.capture.consumer.bulk.create.topic=save-location-capture-project-bulk-topic + +#---------No resource statuses ------------# +project.task.no.resource.validation.status=ADMINISTRATION_FAILED, BENEFICIARY_REFUSED, CLOSED_HOUSEHOLD, NOT_ADMINISTERED \ No newline at end of file diff --git a/health-services/project/src/main/resources/db/migration/main/V20240711175300__user_location_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20240711175300__user_location_ddl.sql new file mode 100644 index 00000000000..fd9a0f8f611 --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20240711175300__user_location_ddl.sql @@ -0,0 +1,23 @@ +CREATE TABLE IF NOT EXISTS USER_LOCATION ( + id CHARACTER VARYING(64), + clientReferenceId CHARACTER VARYING(64), + tenantId CHARACTER VARYING(1000) NOT NULL, + projectId CHARACTER VARYING(64) NOT NULL, + latitude DOUBLE PRECISION NOT NULL, + longitude DOUBLE PRECISION NOT NULL, + locationAccuracy INTEGER NOT NULL, + boundaryCode CHARACTER VARYING(256) NOT NULL, + action CHARACTER VARYING(256), + createdBy CHARACTER VARYING(64) NOT NULL, + createdTime BIGINT NOT NULL, + lastModifiedBy CHARACTER VARYING(64) NOT NULL, + lastModifiedTime BIGINT NOT NULL, + clientCreatedTime BIGINT, + clientLastModifiedTime BIGINT, + clientCreatedBy CHARACTER VARYING(64), + clientLastModifiedBy CHARACTER VARYING(64), + additionalDetails jsonb, + CONSTRAINT pk_user_location PRIMARY KEY (id) +); + +CREATE INDEX IF NOT EXISTS idx_user_location_clientCreatedBy ON USER_LOCATION (clientCreatedBy); diff --git a/health-services/project/src/main/resources/db/migration/main/V20240711175500__user_action_ddl.sql b/health-services/project/src/main/resources/db/migration/main/V20240711175500__user_action_ddl.sql new file mode 100644 index 00000000000..411e86e86ef --- /dev/null +++ b/health-services/project/src/main/resources/db/migration/main/V20240711175500__user_action_ddl.sql @@ -0,0 +1,28 @@ +CREATE TABLE IF NOT EXISTS USER_ACTION ( +id character varying(64), +clientReferenceId character varying(64), +tenantId character varying(1000) not null, +projectId character varying(64) not null, +latitude double precision not null, +longitude double precision not null, +locationAccuracy INTEGER not null, +boundaryCode CHARACTER VARYING(256) not null, +action CHARACTER VARYING(256) not null, +beneficiaryTag CHARACTER VARYING(64), +resourceTag CHARACTER VARYING(64), +status character varying(1000), +additionalDetails jsonb, +createdBy character varying(64) not null, +createdTime bigint not null, +lastModifiedBy character varying(64) not null, +lastModifiedTime bigint not null, +clientCreatedTime bigint, +clientLastModifiedTime bigint, +clientCreatedBy character varying(64), +clientLastModifiedBy character varying(64), +rowVersion bigint, + CONSTRAINT pk_user_action_id PRIMARY KEY (id), + CONSTRAINT uk_user_action_clientReference_id UNIQUE (clientReferenceId) +); + +CREATE INDEX IF NOT EXISTS idx_user_action_projectId_clientCreatedBy ON USER_ACTION (projectId, clientCreatedBy); diff --git a/health-services/project/src/test/java/org/egov/project/helper/TaskTestBuilder.java b/health-services/project/src/test/java/org/egov/project/helper/TaskTestBuilder.java index ddda5a11de5..453e3be4d11 100644 --- a/health-services/project/src/test/java/org/egov/project/helper/TaskTestBuilder.java +++ b/health-services/project/src/test/java/org/egov/project/helper/TaskTestBuilder.java @@ -1,10 +1,11 @@ package org.egov.project.helper; +import java.util.Arrays; + import org.egov.common.helper.AuditDetailsTestBuilder; import org.egov.common.models.project.Task; import org.egov.common.models.project.TaskResource; - -import java.util.Arrays; +import org.egov.common.models.project.TaskStatus; public class TaskTestBuilder { @@ -31,7 +32,8 @@ public TaskTestBuilder withTask() { TaskResource.builder().tenantId("default").isDelivered(false) .quantity(100.0).productVariantId("v101").build())) .projectId("some-id").createdBy("some-id") - .createdDate(100L).status("status") + .createdDate(100L) + .status(TaskStatus.DELIVERED) .isDeleted(false).projectBeneficiaryId("some-id") .rowVersion(0) .hasErrors(Boolean.FALSE) diff --git a/health-services/referralmanagement/CHANGELOG.md b/health-services/referralmanagement/CHANGELOG.md index c605b868638..21e78657688 100644 --- a/health-services/referralmanagement/CHANGELOG.md +++ b/health-services/referralmanagement/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog All notable changes to this module will be documented in this file. +## 1.0.3 - 2024-08-09 +- Upgraded downsync logic. + + ## 1.0.2 - 2024-05-29 - Upgraded to Core 2.9LTS - Client reference ID validation added diff --git a/health-services/referralmanagement/pom.xml b/health-services/referralmanagement/pom.xml index 915072c78a1..b9d85ad8269 100644 --- a/health-services/referralmanagement/pom.xml +++ b/health-services/referralmanagement/pom.xml @@ -6,7 +6,7 @@ referralmanagement jar referralmanagement - 1.0.2 + 1.0.3 17 ${java.version} @@ -46,7 +46,7 @@ org.egov.common health-services-common - 1.0.17-SNAPSHOT + 1.0.18-SNAPSHOT org.egov.common diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java index f33a82c8bea..b24119eb8dd 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/Constants.java @@ -1,6 +1,7 @@ package org.egov.referralmanagement; public interface Constants { + String SET_SIDE_EFFECTS = "setSideEffects"; String GET_SIDE_EFFECTS = "getSideEffects"; String SET_REFERRALS = "setReferrals"; @@ -15,5 +16,10 @@ public interface Constants { String STAFF = "STAFF"; String FACILITY = "FACILITY"; + public static final String HCM_MASTER_PROJECTTYPE = "projectTypes"; + public static final String HCM_MDMS_PROJECT_MODULE_NAME = "HCM-PROJECT-TYPES"; + public static final String HCM_PROJECT_TYPE_FILTER_CODE = "$.[?(@.code=='%s')]"; + public static final String HCM_MDMS_PROJECTTYPE_RES_PATH = "$.MdmsRes." + HCM_MDMS_PROJECT_MODULE_NAME + "." + HCM_MASTER_PROJECTTYPE + ".*"; + String INVALID_RECIPIENT_TYPE = "Invalid Recipient Type"; } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java index 1113ac58efb..e69325f19c5 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/config/ReferralManagementConfiguration.java @@ -109,4 +109,10 @@ public class ReferralManagementConfiguration { @Value("${egov.search.individual.url}") private String individualSearchUrl; + @Value("${egov.mdms.host}") + private String mdmsHost; + + @Value("${egov.mdms.search.endpoint}") + private String mdmsSearchUrl; + } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java index f3ca4fa075d..7db34924dd4 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/DownsyncService.java @@ -3,11 +3,13 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; import org.egov.common.contract.request.RequestInfo; import org.egov.common.http.client.ServiceRequestClient; import org.egov.common.models.household.Household; @@ -46,6 +48,7 @@ import org.springframework.util.CollectionUtils; @Service +@Slf4j public class DownsyncService { private ServiceRequestClient restClient; @@ -58,28 +61,34 @@ public class DownsyncService { private ReferralManagementService referralService; + private MasterDataService masterDataService; + @Autowired - public DownsyncService(ServiceRequestClient serviceRequestClient, - ReferralManagementConfiguration referralManagementConfiguration, - NamedParameterJdbcTemplate jdbcTemplate, - SideEffectService sideEffectService, - ReferralManagementService referralService) { + public DownsyncService( ServiceRequestClient serviceRequestClient, + ReferralManagementConfiguration referralManagementConfiguration, + NamedParameterJdbcTemplate jdbcTemplate, + SideEffectService sideEffectService, + ReferralManagementService referralService, + MasterDataService masterDataService ) { this.restClient = serviceRequestClient; this.configs = referralManagementConfiguration; this.jdbcTemplate = jdbcTemplate; - this.sideEffectService = sideEffectService; - this.referralService = referralService; + this.sideEffectService=sideEffectService; + this.referralService=referralService; + this.masterDataService=masterDataService; } /** + * * @param downsyncRequest * @return Downsync */ public Downsync prepareDownsyncData(DownsyncRequest downsyncRequest) { Downsync downsync = new Downsync(); + DownsyncCriteria downsyncCriteria = downsyncRequest.getDownsyncCriteria(); List householdIds = null; Set individualIds = null; @@ -87,43 +96,60 @@ public Downsync prepareDownsyncData(DownsyncRequest downsyncRequest) { List beneficiaryClientRefIds = null; List taskClientRefIds = null; - downsync.setDownsyncCriteria(downsyncRequest.getDownsyncCriteria()); + + downsync.setDownsyncCriteria(downsyncCriteria); + boolean isSyncTimeAvailable = null != downsyncCriteria.getLastSyncedTime(); + + //Project project = getProjectType(downsyncRequest); + LinkedHashMap projectType = masterDataService.getProjectType(downsyncRequest); + /* search household */ householdIds = searchHouseholds(downsyncRequest, downsync); - if (!CollectionUtils.isEmpty(householdIds)) - /* search household member using household ids */ + /* search household member using household ids */ + if (isSyncTimeAvailable || !CollectionUtils.isEmpty(householdIds)) { individualIds = searchMembers(downsyncRequest, downsync, householdIds); + } - if (!CollectionUtils.isEmpty(individualIds)) { - - /* search individuals using individual ids */ + /* search individuals using individual ids */ + if (isSyncTimeAvailable || !CollectionUtils.isEmpty(individualIds) ) { individualClientRefIds = searchIndividuals(downsyncRequest, downsync, individualIds); } - if (!CollectionUtils.isEmpty(individualClientRefIds)) { - /* search beneficiary using individual ids */ - beneficiaryClientRefIds = searchBeneficiaries(downsyncRequest, downsync, individualClientRefIds); + /* search beneficiary using individual ids OR household ids */ + + String beneficiaryType = (String) projectType.get("beneficiaryType"); + + beneficiaryClientRefIds = individualClientRefIds; + + if("HOUSEHOLD".equalsIgnoreCase(beneficiaryType)) + beneficiaryClientRefIds = downsync.getHouseholds().stream().map(Household::getClientReferenceId).collect(Collectors.toList()); + + //fetch beneficiary in the db + if (isSyncTimeAvailable || !CollectionUtils.isEmpty(beneficiaryClientRefIds)) { + beneficiaryClientRefIds = searchBeneficiaries(downsyncRequest, downsync, beneficiaryClientRefIds); } - if (!CollectionUtils.isEmpty(beneficiaryClientRefIds)) { + /* search tasks using beneficiary uuids */ + if (isSyncTimeAvailable || !CollectionUtils.isEmpty(beneficiaryClientRefIds)) { - /* search tasks using beneficiary uuids */ - taskClientRefIds = searchTasks(downsyncRequest, downsync, beneficiaryClientRefIds); + taskClientRefIds = searchTasks(downsyncRequest, downsync, beneficiaryClientRefIds, projectType); /* ref search */ referralSearch(downsyncRequest, downsync, beneficiaryClientRefIds); } - if (!CollectionUtils.isEmpty(taskClientRefIds)) { + if (isSyncTimeAvailable || !CollectionUtils.isEmpty(taskClientRefIds)) { searchSideEffect(downsyncRequest, downsync, taskClientRefIds); } return downsync; } + /** + * * @param downsyncRequest * @param downsync * @return @@ -135,7 +161,7 @@ private List searchHouseholds(DownsyncRequest downsyncRequest, Downsync StringBuilder householdUrl = new StringBuilder(configs.getHouseholdHost()) .append(configs.getHouseholdSearchUrl()); - householdUrl = appendUrlParams(householdUrl, criteria, null, null); + householdUrl = appendUrlParams(householdUrl, criteria, null, null, true); HouseholdSearch householdSearch = HouseholdSearch.builder() .localityCode(criteria.getLocality()) @@ -151,13 +177,14 @@ private List searchHouseholds(DownsyncRequest downsyncRequest, Downsync downsync.setHouseholds(households); downsync.getDownsyncCriteria().setTotalCount(res.getTotalCount()); - if (CollectionUtils.isEmpty(households)) + if(CollectionUtils.isEmpty(households)) return Collections.emptyList(); return households.stream().map(Household::getId).collect(Collectors.toList()); } /** + * * @param downsyncRequest * @param downsync * @param individualIds @@ -171,12 +198,15 @@ private List searchIndividuals(DownsyncRequest downsyncRequest, Downsync StringBuilder url = new StringBuilder(configs.getIndividualHost()) .append(configs.getIndividualSearchUrl()); - url = appendUrlParams(url, criteria, 0, individualIds.size()); + + url = appendUrlParams(url, criteria, 0, individualIds.size(),true); IndividualSearch individualSearch = IndividualSearch.builder() - .id(new ArrayList<>(individualIds)) .build(); + if(!CollectionUtils.isEmpty(individualIds)) + individualSearch.setId(new ArrayList<>(individualIds)); + IndividualSearchRequest searchRequest = IndividualSearchRequest.builder() .individual(individualSearch) .requestInfo(requestInfo) @@ -189,6 +219,7 @@ private List searchIndividuals(DownsyncRequest downsyncRequest, Downsync } /** + * * @param downsyncRequest * @param householdIds * @return @@ -196,21 +227,17 @@ private List searchIndividuals(DownsyncRequest downsyncRequest, Downsync private Set searchMembers(DownsyncRequest downsyncRequest, Downsync downsync, List householdIds) { - StringBuilder memberUrl = new StringBuilder(configs.getHouseholdHost()) - .append(configs.getHouseholdMemberSearchUrl()); + Long lastChangedSince = downsyncRequest.getDownsyncCriteria().getLastSyncedTime(); - String memberIdsquery = "SELECT id from HOUSEHOLD_MEMBER where householdId IN (:householdIds)"; - - Map paramMap = new HashMap<>(); - paramMap.put("householdIds", householdIds); - appendUrlParams(memberUrl, downsyncRequest.getDownsyncCriteria(), 0, householdIds.size()); - - /* FIXME SHOULD BE REMOVED AND SEARCH SHOULD BE enhanced with list of household ids*/ - List memberids = jdbcTemplate.queryForList(memberIdsquery, paramMap, String.class); + List memberids = getPrimaryIds(householdIds, "householdId","HOUSEHOLD_MEMBER",lastChangedSince); if (CollectionUtils.isEmpty(memberids)) return Collections.emptySet(); + StringBuilder memberUrl = new StringBuilder(configs.getHouseholdHost()) + .append(configs.getHouseholdMemberSearchUrl()); + + appendUrlParams(memberUrl, downsyncRequest.getDownsyncCriteria(), 0, householdIds.size(), false); HouseholdMemberSearch memberSearch = HouseholdMemberSearch.builder() .id(memberids) @@ -228,92 +255,94 @@ private Set searchMembers(DownsyncRequest downsyncRequest, Downsync down } /** + * * @param downsyncRequest * @param downsync - * @param individualClientRefIds + * @param beneficiaryClientRefIds * @return clientreferenceid of beneficiary object */ private List searchBeneficiaries(DownsyncRequest downsyncRequest, Downsync downsync, - List individualClientRefIds) { + List beneficiaryClientRefIds) { DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + Long lastChangedSince =criteria.getLastSyncedTime(); + + List beneficiaryIds = getPrimaryIds( + beneficiaryClientRefIds, + "beneficiaryclientreferenceid", + "PROJECT_BENEFICIARY", + lastChangedSince + ); + + if(CollectionUtils.isEmpty(beneficiaryIds)) + return Collections.emptyList(); + + StringBuilder url = new StringBuilder(configs.getProjectHost()) + .append(configs.getProjectBeneficiarySearchUrl()); + + url = appendUrlParams(url, criteria, 0, beneficiaryClientRefIds.size(),false); + + ProjectBeneficiarySearch search = ProjectBeneficiarySearch.builder() + .id(beneficiaryIds) + .projectId(Collections.singletonList(downsyncRequest.getDownsyncCriteria().getProjectId())) + .build(); + + BeneficiarySearchRequest searchRequest = BeneficiarySearchRequest.builder() + .projectBeneficiary(search) + .requestInfo(requestInfo) + .build(); + + List beneficiaries = restClient.fetchResult(url, searchRequest, BeneficiaryBulkResponse.class).getProjectBeneficiaries(); + downsync.setProjectBeneficiaries(beneficiaries); + + return beneficiaries.stream().map(ProjectBeneficiary::getClientReferenceId).collect(Collectors.toList()); + } + - StringBuilder url = new StringBuilder(configs.getProjectHost()) - .append(configs.getProjectBeneficiarySearchUrl()); - url = appendUrlParams(url, criteria, 0, individualClientRefIds.size()); - - String beneficiaryIdQuery = "SELECT id from PROJECT_BENEFICIARY where beneficiaryclientreferenceid IN (:beneficiaryIds)"; - - Map paramMap = new HashMap<>(); - paramMap.put("beneficiaryIds", individualClientRefIds); - - /* FIXME SHOULD BE REMOVED AND SEARCH SHOULD BE enhanced with list of beneficiary ids*/ - List ids = jdbcTemplate.queryForList(beneficiaryIdQuery, paramMap, String.class); - - if(CollectionUtils.isEmpty(ids)) - return Collections.emptyList(); - - ProjectBeneficiarySearch search = ProjectBeneficiarySearch.builder() - .id(ids) - .projectId(Collections.singletonList(downsyncRequest.getDownsyncCriteria().getProjectId())) - .build(); - - BeneficiarySearchRequest searchRequest = BeneficiarySearchRequest.builder() - .projectBeneficiary(search) - .requestInfo(requestInfo) - .build(); - - List beneficiaries = restClient.fetchResult(url, searchRequest, BeneficiaryBulkResponse.class).getProjectBeneficiaries(); - downsync.setProjectBeneficiaries(beneficiaries); - - return beneficiaries.stream().map(ProjectBeneficiary::getClientReferenceId).collect(Collectors.toList()); - } /** + * * @param downsyncRequest * @param downsync * @param beneficiaryClientRefIds + * @param projectType * @return */ private List searchTasks(DownsyncRequest downsyncRequest, Downsync downsync, - List beneficiaryClientRefIds) { - - DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); - RequestInfo requestInfo = downsyncRequest.getRequestInfo(); - - StringBuilder url = new StringBuilder(configs.getProjectHost()) - .append(configs.getProjectTaskSearchUrl()); - - String taskIdQuery = "SELECT id from PROJECT_TASK where projectBeneficiaryClientReferenceId IN (:beneficiaryClientRefIds)"; - - Map paramMap = new HashMap<>(); - paramMap.put("beneficiaryClientRefIds", beneficiaryClientRefIds); - - /* FIXME SHOULD BE REMOVED AND TASK SEARCH SHOULD BE enhanced with list of client-ref-beneficiary ids*/ - List taskIds = jdbcTemplate.queryForList(taskIdQuery, paramMap, String.class); - url = appendUrlParams(url, criteria, 0, taskIds.size()); - - if(CollectionUtils.isEmpty(taskIds)) - return Collections.emptyList(); - - TaskSearch search = TaskSearch.builder() - .id(taskIds) - .projectId(Collections.singletonList(downsyncRequest.getDownsyncCriteria().getProjectId())) - .build(); - - TaskSearchRequest searchRequest = TaskSearchRequest.builder() - .task(search) - .requestInfo(requestInfo) - .build(); - - List tasks = restClient.fetchResult(url, searchRequest, TaskBulkResponse.class).getTasks(); - downsync.setTasks(tasks); - - return tasks.stream().map(Task::getClientReferenceId).collect(Collectors.toList()); - } + List beneficiaryClientRefIds, LinkedHashMap projectType) { + + DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + List taskIds = getPrimaryIds(beneficiaryClientRefIds, "projectBeneficiaryClientReferenceId", "PROJECT_TASK", + criteria.getLastSyncedTime()); + + if(CollectionUtils.isEmpty(taskIds)) + return Collections.emptyList(); + + StringBuilder url = new StringBuilder(configs.getProjectHost()) + .append(configs.getProjectTaskSearchUrl()); + + url = appendUrlParams(url, criteria, 0, taskIds.size(), false); + + TaskSearch search = TaskSearch.builder() + .id(taskIds) + .projectId(Collections.singletonList(downsyncRequest.getDownsyncCriteria().getProjectId())) + .build(); + + TaskSearchRequest searchRequest = TaskSearchRequest.builder() + .task(search) + .requestInfo(requestInfo) + .build(); + + List tasks = restClient.fetchResult(url, searchRequest, TaskBulkResponse.class).getTasks(); + downsync.setTasks(tasks); + + return tasks.stream().map(Task::getClientReferenceId).collect(Collectors.toList()); + } /** + * * @param downsyncRequest * @param downsync * @param taskClientRefIds @@ -324,33 +353,29 @@ private void searchSideEffect(DownsyncRequest downsyncRequest, Downsync downsync DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); RequestInfo requestInfo = downsyncRequest.getRequestInfo(); - // search side effect FIXME - tasks id array search not available - String sEIdQuery = "SELECT id from SIDE_EFFECT where taskClientReferenceId IN (:taskClientRefIds)"; - - Map paramMap = new HashMap<>(); - paramMap.put("taskClientRefIds", taskClientRefIds); - /* FIXME SHOULD BE REMOVED AND TASK SEARCH SHOULD BE enhanced with list of client-ref-beneficiary ids*/ - List SEIds = jdbcTemplate.queryForList(sEIdQuery, paramMap, String.class); + List SEIds = getPrimaryIds(taskClientRefIds, "taskClientReferenceId", "SIDE_EFFECT", criteria.getLastSyncedTime()); - if (CollectionUtils.isEmpty(SEIds)) + if(CollectionUtils.isEmpty(SEIds)) return; SideEffectSearch search = SideEffectSearch.builder() .id(SEIds) .build(); + SideEffectSearchRequest effectSearchRequest = SideEffectSearchRequest.builder() .sideEffect(search) .requestInfo(requestInfo) .build(); List effects = sideEffectService.search( - effectSearchRequest, - SEIds.size(), - 0, - criteria.getTenantId(), - criteria.getLastSyncedTime(), - criteria.getIncludeDeleted()).getResponse(); + effectSearchRequest, + SEIds.size(), + 0, + criteria.getTenantId(), + criteria.getLastSyncedTime(), + criteria.getIncludeDeleted() + ).getResponse(); downsync.setSideEffects(effects); } @@ -360,28 +385,72 @@ private void referralSearch(DownsyncRequest downsyncRequest, Downsync downsync, DownsyncCriteria criteria = downsyncRequest.getDownsyncCriteria(); RequestInfo requestInfo = downsyncRequest.getRequestInfo(); + Integer limit = beneficiaryClientRefIds.size(); ReferralSearch search = ReferralSearch.builder() - .projectBeneficiaryClientReferenceId(beneficiaryClientRefIds) .build(); + if(!CollectionUtils.isEmpty(beneficiaryClientRefIds)) { + search.setProjectBeneficiaryClientReferenceId(beneficiaryClientRefIds); + limit = null; + } + ReferralSearchRequest searchRequest = ReferralSearchRequest.builder() .referral(search) .requestInfo(requestInfo) .build(); List referrals = referralService.search( - searchRequest, - beneficiaryClientRefIds.size(), - 0, - criteria.getTenantId(), - criteria.getLastSyncedTime(), - criteria.getIncludeDeleted()).getResponse(); + searchRequest, + limit, + 0, + criteria.getTenantId(), + criteria.getLastSyncedTime(), + criteria.getIncludeDeleted() + ).getResponse(); downsync.setReferrals(referrals); } + /** + * common method to fetch Ids with list of relation Ids like id of member with householdIds + * @param idList + * @param idListFieldName + * @param tableName + * @param lastChangedSince + * @return + */ + private List getPrimaryIds(List idList, String idListFieldName, String tableName, Long lastChangedSince) { + + /** + * Adding lastShangedSince to id query to avoid load on API search for members + */ + boolean isAndRequired = false; + Map paramMap = new HashMap<>(); + StringBuilder memberIdsquery = new StringBuilder("SELECT id from %s WHERE "); + + + if (!CollectionUtils.isEmpty(idList)) { + + memberIdsquery.append("%s IN (:%s)"); + paramMap.put(idListFieldName, idList); + isAndRequired = true; + } + + if (null != lastChangedSince) { + if(isAndRequired) + memberIdsquery.append(" AND "); + memberIdsquery.append(" lastModifiedTime >= (:lastChangedSince)"); + paramMap.put("lastChangedSince", lastChangedSince); + } + + String finalQuery = String.format(memberIdsquery.toString(), tableName, idListFieldName, idListFieldName); + /* FIXME SHOULD BE REMOVED AND SEARCH SHOULD BE enhanced with list of household ids*/ + List memberids = jdbcTemplate.queryForList(finalQuery, paramMap, String.class); + return memberids; + } + /** * append url params * @@ -389,9 +458,10 @@ private void referralSearch(DownsyncRequest downsyncRequest, Downsync downsync, * @param criteria * @param offset * @param limit + * @param sendPrevSyncTime * @return */ - private StringBuilder appendUrlParams(StringBuilder url, DownsyncCriteria criteria, Integer offset, Integer limit) { + private StringBuilder appendUrlParams(StringBuilder url, DownsyncCriteria criteria, Integer offset, Integer limit, boolean sendPrevSyncTime) { url.append("?tenantId=") .append(criteria.getTenantId()) @@ -399,18 +469,21 @@ private StringBuilder appendUrlParams(StringBuilder url, DownsyncCriteria criter .append(criteria.getIncludeDeleted()) .append("&limit="); - if (null != limit) + if (null != limit && limit != 0) url.append(limit); else url.append(criteria.getLimit()); url.append("&offset="); - if (null != offset) + if(null != offset) url.append(offset); else url.append(criteria.getOffset()); + if(sendPrevSyncTime && null != criteria.getLastSyncedTime()) + url.append("&lastChangedSince=").append(criteria.getLastSyncedTime()); + return url; } } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java new file mode 100644 index 00000000000..3c09df3edde --- /dev/null +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/MasterDataService.java @@ -0,0 +1,129 @@ +package org.egov.referralmanagement.service; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +import com.jayway.jsonpath.JsonPath; +import digit.models.coremodels.mdms.MasterDetail; +import digit.models.coremodels.mdms.MdmsCriteria; +import digit.models.coremodels.mdms.MdmsCriteriaReq; +import digit.models.coremodels.mdms.ModuleDetail; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestInfo; +import org.egov.common.http.client.ServiceRequestClient; +import org.egov.common.models.project.Project; +import org.egov.common.models.project.ProjectRequest; +import org.egov.common.models.project.ProjectResponse; +import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncCriteria; +import org.egov.common.models.referralmanagement.beneficiarydownsync.DownsyncRequest; +import org.egov.referralmanagement.config.ReferralManagementConfiguration; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import static org.egov.referralmanagement.Constants.HCM_MASTER_PROJECTTYPE; +import static org.egov.referralmanagement.Constants.HCM_MDMS_PROJECTTYPE_RES_PATH; +import static org.egov.referralmanagement.Constants.HCM_MDMS_PROJECT_MODULE_NAME; +import static org.egov.referralmanagement.Constants.HCM_PROJECT_TYPE_FILTER_CODE; + +@Slf4j +@Service +public class MasterDataService { + + private ServiceRequestClient restClient; + + private ReferralManagementConfiguration configs; + + @Autowired + public MasterDataService(ServiceRequestClient serviceRequestClient, + ReferralManagementConfiguration referralManagementConfiguration) { + + this.restClient = serviceRequestClient; + this.configs = referralManagementConfiguration; + + } + + + @SuppressWarnings("unchecked") + public LinkedHashMap getProjectType(DownsyncRequest downsyncRequest) { + + DownsyncCriteria downsyncCriteria = downsyncRequest.getDownsyncCriteria(); + RequestInfo info = downsyncRequest.getRequestInfo(); + String projectId = downsyncCriteria.getProjectId(); + + + Project project = getProject(downsyncCriteria, info, projectId); + + String projectCode = project.getProjectType(); // FIXME + + /* + * TODO FIXME code should get upgraded when next version of project is created with execution plan (project type master) in the additional details + */ + StringBuilder mdmsUrl = new StringBuilder(configs.getMdmsHost()) + .append(configs.getMdmsSearchUrl()); + + /* + * Assumption is that the project code is always unique + */ + MasterDetail masterDetail = MasterDetail.builder() + .name(HCM_MASTER_PROJECTTYPE) + .filter(String.format(HCM_PROJECT_TYPE_FILTER_CODE, projectCode)) // projectCode FIXME + .build(); + + ModuleDetail moduleDetail = ModuleDetail.builder() + .masterDetails(Arrays.asList(masterDetail)) + .moduleName(HCM_MDMS_PROJECT_MODULE_NAME) + .build(); + + MdmsCriteria mdmsCriteria = MdmsCriteria.builder() + .moduleDetails(Arrays.asList(moduleDetail)) + .tenantId(downsyncCriteria.getTenantId().split("//.")[0]) + .build(); + + MdmsCriteriaReq mdmsCriteriaReq = MdmsCriteriaReq.builder() + .mdmsCriteria(mdmsCriteria) + .requestInfo(info) + .build(); + + Map mdmsRes = restClient.fetchResult(mdmsUrl, mdmsCriteriaReq, HashMap.class); + List projectTypeRes = null; + try { + projectTypeRes = JsonPath.read(mdmsRes, HCM_MDMS_PROJECTTYPE_RES_PATH); + } catch (Exception e) { + log.error(e.getMessage()); + throw new CustomException("JSONPATH_ERROR", "Failed to parse mdms response"); + } + + return (LinkedHashMap) projectTypeRes.get(0); + + } + + + private Project getProject(DownsyncCriteria downsyncCriteria, RequestInfo info, String projectId) { + + StringBuilder url = new StringBuilder(configs.getProjectHost()) + .append(configs.getProjectSearchUrl()) + .append("?offset=0") + .append("&limit=100") + .append("&tenantId=").append(downsyncCriteria.getTenantId()); + + Project project = Project.builder() + .id(projectId) + .tenantId(downsyncCriteria.getTenantId()) + .build(); + + ProjectRequest projectRequest = ProjectRequest.builder() + .projects(Arrays.asList(project)) + .requestInfo(info) + .build(); + + ProjectResponse res = restClient.fetchResult(url, projectRequest, ProjectResponse.class); + return res.getProject().get(0); + } +} diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java index b14512d7551..38973d34e3c 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/service/ReferralManagementService.java @@ -66,8 +66,7 @@ public class ReferralManagementService { || validator.getClass().equals(RmExistentEntityValidator.class) || validator.getClass().equals(RmReferrerIdValidator.class) || validator.getClass().equals(RmRecipientIdValidator.class) - || validator.getClass().equals(RmSideEffectIdValidator.class) - || validator.getClass().equals(RmRowVersionValidator.class); + || validator.getClass().equals(RmSideEffectIdValidator.class); private final Predicate> isApplicableForUpdate = validator -> validator.getClass().equals(RmProjectBeneficiaryIdValidator.class) @@ -82,7 +81,8 @@ public class ReferralManagementService { private final Predicate> isApplicableForDelete = validator -> validator.getClass().equals(RmNullIdValidator.class) - || validator.getClass().equals(RmNonExistentEntityValidator.class); + || validator.getClass().equals(RmNonExistentEntityValidator.class) + || validator.getClass().equals(RmRowVersionValidator.class); public ReferralManagementService(IdGenService idGenService, ReferralRepository referralRepository, ReferralManagementConfiguration referralManagementConfiguration, ReferralManagementEnrichmentService referralManagementEnrichmentService, List> validators) { diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmExistentEntityValidator.java index 8725344af7d..c12c03054ef 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmExistentEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/RmExistentEntityValidator.java @@ -15,15 +15,16 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; /** - * Validator class for checking the existence of entities with the given client reference IDs. - * This validator checks if the provided referral entities already exist in the database based on their client reference IDs. + * Validator class for checking the existence of referral entities with the given client reference IDs. + * This validator checks if the provided Referral entities already exist in the database based on their client reference IDs. + * * @author kanishq-egov */ @Component @@ -36,47 +37,58 @@ public class RmExistentEntityValidator implements Validator> validate(ReferralBulkRequest request) { - // Map to hold referral entities and their error details + // Map to hold Referral entities and their error details Map> errorDetailsMap = new HashMap<>(); - // Get the list of referral entities from the request + + // Get the list of Referral entities from the request List entities = request.getReferrals(); - // Extract client reference IDs from referral entities without errors + + // Extract client reference IDs from Referral entities that do not have existing errors List clientReferenceIdList = entities.stream() - .filter(notHavingErrors()) - .map(Referral::getClientReferenceId) - .collect(Collectors.toList()); - // Create a search object for querying entities by client reference IDs + .filter(notHavingErrors()) // Filter out entities that already have errors + .map(Referral::getClientReferenceId) // Extract client reference IDs from Referral entities + .collect(Collectors.toList()); // Collect the IDs into a list + + // Create a map for quick lookup of Referral entities by client reference ID + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + + // Create a search object for querying existing Referral entities by client reference IDs ReferralSearch referralSearch = ReferralSearch.builder() - .clientReferenceId(clientReferenceIdList) + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search .build(); - // Check if the client reference ID list is not empty + + // Check if the client reference ID list is not empty before querying the database if (!CollectionUtils.isEmpty(clientReferenceIdList)) { - // Query the repository to find existing entities by client reference IDs - List existentEntities = referralRepository.findById( - clientReferenceIdList, - getIdFieldName(referralSearch), - Boolean.FALSE).getResponse(); - // For each existing entity, populate error details for uniqueness - existentEntities.forEach(entity -> { + // Query the repository to find existing Referral entities with the given client reference IDs + List existingClientReferenceIds = referralRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, add an error to the map for the corresponding Referral entity + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation Error error = getErrorForUniqueEntity(); - populateErrorDetails(entity, error, errorDetailsMap); + // Populate error details for the individual Referral entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); }); } + + // Return the map containing Referral entities and their associated error details return errorDetailsMap; } - } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrExistentEntityValidator.java index 33e3e750911..de041f238e8 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrExistentEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/hfreferral/HfrExistentEntityValidator.java @@ -15,14 +15,14 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; /** - * Validator class for checking the existence of entities with the given client reference IDs. + * Validator class for checking the existence of HFReferral entities with the given client reference IDs. * This validator checks if the provided HFReferral entities already exist in the database based on their client reference IDs. * * @author kanishq-egov @@ -44,41 +44,51 @@ public HfrExistentEntityValidator(HFReferralRepository hfReferralRepository) { } /** - * Validates the existence of entities with the given client reference IDs. + * Validates the existence of HFReferral entities in the HFReferralBulkRequest. + * Checks if the provided HFReferral entities already exist in the database based on their client reference IDs. * * @param request The bulk request containing HFReferral entities. - * @return A map containing HFReferral entities and their associated error details. + * @return A map containing HFReferral entities and their associated error details if any duplicates are found. */ @Override public Map> validate(HFReferralBulkRequest request) { - // Map to hold HFReferral entities and their error details + // Map to hold HFReferral entities and their error details. Map> errorDetailsMap = new HashMap<>(); - // Get the list of HFReferral entities from the request + + // Get the list of HFReferral entities from the request. List entities = request.getHfReferrals(); - // Extract client reference IDs from HFReferral entities without errors + + // Extract client reference IDs from HFReferral entities that do not have existing errors. List clientReferenceIdList = entities.stream() - .filter(notHavingErrors()) - .map(HFReferral::getClientReferenceId) - .collect(Collectors.toList()); - // Create a search object for querying entities by client reference IDs + .filter(notHavingErrors()) // Filter out entities that already have errors. + .map(HFReferral::getClientReferenceId) // Extract client reference IDs from HFReferral entities. + .collect(Collectors.toList()); // Collect the IDs into a list. + + // Create a map for quick lookup of HFReferral entities by client reference ID. + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty. + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map. + + // Create a search object for querying existing HFReferral entities by client reference IDs. HFReferralSearch hfReferralSearch = HFReferralSearch.builder() - .clientReferenceId(clientReferenceIdList) + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search. .build(); - // Check if the client reference ID list is not empty + + // Check if the client reference ID list is not empty before querying the database. if (!CollectionUtils.isEmpty(clientReferenceIdList)) { - // Query the repository to find existing entities by client reference IDs - List existentEntities = hfReferralRepository.findById( - clientReferenceIdList, - Boolean.FALSE, - getIdFieldName(hfReferralSearch) - ); - // For each existing entity, populate error details for uniqueness - existentEntities.forEach(entity -> { + // Query the repository to find existing HFReferral entities with the given client reference IDs. + List existingClientReferenceIds = hfReferralRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, add an error to the map for the corresponding HFReferral entity. + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation. Error error = getErrorForUniqueEntity(); - populateErrorDetails(entity, error, errorDetailsMap); + // Populate error details for the individual HFReferral entity associated with the client reference ID. + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); }); } + + // Return the map containing HFReferral entities and their associated error details. return errorDetailsMap; } - } diff --git a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeExistentEntityValidator.java b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeExistentEntityValidator.java index 9ed78e8db17..961272cb95d 100644 --- a/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeExistentEntityValidator.java +++ b/health-services/referralmanagement/src/main/java/org/egov/referralmanagement/validator/sideeffect/SeExistentEntityValidator.java @@ -15,8 +15,8 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; @@ -44,39 +44,51 @@ public SeExistentEntityValidator(SideEffectRepository sideEffectRepository) { } /** - * Validates the existence of SideEffect entities with the given client reference IDs. + * Validates the existence of SideEffect entities in the SideEffectBulkRequest. + * Checks if the provided SideEffect entities already exist in the database based on their client reference IDs. * * @param request The bulk request containing SideEffect entities. - * @return A map containing SideEffect entities and their associated error details. + * @return A map containing SideEffect entities and their associated error details if any duplicates are found. */ @Override public Map> validate(SideEffectBulkRequest request) { // Map to hold SideEffect entities and their error details Map> errorDetailsMap = new HashMap<>(); + // Get the list of SideEffect entities from the request List entities = request.getSideEffects(); - // Extract client reference IDs from SideEffect entities without errors + + // Extract client reference IDs from SideEffect entities that do not have existing errors List clientReferenceIdList = entities.stream() - .filter(notHavingErrors()) - .map(SideEffect::getClientReferenceId) - .collect(Collectors.toList()); - // Create a search object for querying entities by client reference IDs + .filter(notHavingErrors()) // Filter out entities that already have errors + .map(SideEffect::getClientReferenceId) // Extract client reference IDs from SideEffect entities + .collect(Collectors.toList()); // Collect the IDs into a list + + // Create a map for quick lookup of SideEffect entities by client reference ID + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + + // Create a search object for querying existing SideEffect entities by client reference IDs SideEffectSearch sideEffectSearch = SideEffectSearch.builder() - .clientReferenceId(clientReferenceIdList) + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search .build(); - // Check if the client reference ID list is not empty + + // Check if the client reference ID list is not empty before querying the database if (!CollectionUtils.isEmpty(clientReferenceIdList)) { - // Query the repository to find existing entities by client reference IDs - List existentEntities = sideEffectRepository.findById( - clientReferenceIdList, - getIdFieldName(sideEffectSearch), - Boolean.FALSE); - // For each existing entity, populate error details for uniqueness - existentEntities.forEach(entity -> { + // Query the repository to find existing SideEffect entities with the given client reference IDs + List existingClientReferenceIds = sideEffectRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, add an error to the map for the corresponding SideEffect entity + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation Error error = getErrorForUniqueEntity(); - populateErrorDetails(entity, error, errorDetailsMap); + // Populate error details for the individual SideEffect entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); }); } + + // Return the map containing SideEffect entities and their associated error details return errorDetailsMap; } } diff --git a/health-services/stock/pom.xml b/health-services/stock/pom.xml index fcceea2e322..d204ba58903 100644 --- a/health-services/stock/pom.xml +++ b/health-services/stock/pom.xml @@ -45,7 +45,7 @@ org.egov.common health-services-common - 1.0.17-SNAPSHOT + 1.0.18-SNAPSHOT org.egov.common diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SExistentEntityValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SExistentEntityValidator.java index 7ad90579428..85d5d2bf613 100644 --- a/health-services/stock/src/main/java/org/egov/stock/validator/stock/SExistentEntityValidator.java +++ b/health-services/stock/src/main/java/org/egov/stock/validator/stock/SExistentEntityValidator.java @@ -15,8 +15,8 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; @@ -53,31 +53,41 @@ public SExistentEntityValidator(StockRepository stockRepository) { public Map> validate(StockBulkRequest request) { // Map to hold Stock entities and their error details Map> errorDetailsMap = new HashMap<>(); + // Get the list of Stock entities from the request List entities = request.getStock(); - // Extract client reference IDs from Stock entities without errors + + // Extract client reference IDs from Stock entities that do not already have errors List clientReferenceIdList = entities.stream() - .filter(notHavingErrors()) - .map(Stock::getClientReferenceId) - .collect(Collectors.toList()); - // Create a search object for querying entities by client reference IDs + .filter(notHavingErrors()) // Exclude entities with existing errors + .map(Stock::getClientReferenceId) // Map entities to their client reference IDs + .collect(Collectors.toList()); // Collect IDs into a list + + // Create a map for quick lookup of Stock entities by their client reference ID + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + + // Create a search object to query existing entities by client reference IDs StockSearch stockSearch = StockSearch.builder() - .clientReferenceId(clientReferenceIdList) + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search .build(); - // Check if the client reference ID list is not empty + + // Check if the list of client reference IDs is not empty if (!CollectionUtils.isEmpty(clientReferenceIdList)) { - // Query the repository to find existing entities by client reference IDs - List existentEntities = stockRepository.findById( - clientReferenceIdList, - Boolean.FALSE, - getIdFieldName(stockSearch) - ); - // For each existing entity, populate error details for uniqueness - existentEntities.forEach(entity -> { + // Query the repository to find existing Stock entities with the given client reference IDs + List existingClientReferenceIds = stockRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, add an error to the map for the corresponding Stock entity + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation Error error = getErrorForUniqueEntity(); - populateErrorDetails(entity, error, errorDetailsMap); + // Populate error details for the individual Stock entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); }); } + + // Return the map containing Stock entities and their associated error details return errorDetailsMap; } } diff --git a/health-services/stock/src/main/java/org/egov/stock/validator/stockreconciliation/SrExistentEntityValidator.java b/health-services/stock/src/main/java/org/egov/stock/validator/stockreconciliation/SrExistentEntityValidator.java index e7c0ec35d16..6917135941a 100644 --- a/health-services/stock/src/main/java/org/egov/stock/validator/stockreconciliation/SrExistentEntityValidator.java +++ b/health-services/stock/src/main/java/org/egov/stock/validator/stockreconciliation/SrExistentEntityValidator.java @@ -15,8 +15,8 @@ import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.util.CollectionUtils; +import org.springframework.util.StringUtils; -import static org.egov.common.utils.CommonUtils.getIdFieldName; import static org.egov.common.utils.CommonUtils.notHavingErrors; import static org.egov.common.utils.CommonUtils.populateErrorDetails; import static org.egov.common.utils.ValidatorUtils.getErrorForUniqueEntity; @@ -53,31 +53,42 @@ public SrExistentEntityValidator(StockReconciliationRepository stockReconciliati public Map> validate(StockReconciliationBulkRequest request) { // Map to hold StockReconciliation entities and their error details Map> errorDetailsMap = new HashMap<>(); + // Get the list of StockReconciliation entities from the request List entities = request.getStockReconciliation(); - // Extract client reference IDs from StockReconciliation entities without errors + + // Extract client reference IDs from StockReconciliation entities that do not already have errors List clientReferenceIdList = entities.stream() - .filter(notHavingErrors()) - .map(StockReconciliation::getClientReferenceId) - .collect(Collectors.toList()); - // Create a search object for querying entities by client reference IDs + .filter(notHavingErrors()) // Filter out entities with existing errors + .map(StockReconciliation::getClientReferenceId) // Map entities to their client reference IDs + .collect(Collectors.toList()); // Collect IDs into a list + + // Create a map for quick lookup of StockReconciliation entities by their client reference ID + Map map = entities.stream() + .filter(entity -> StringUtils.hasText(entity.getClientReferenceId())) // Ensure client reference ID is not empty + .collect(Collectors.toMap(entity -> entity.getClientReferenceId(), entity -> entity)); // Collect to a map + + // Create a search object to query existing entities by client reference IDs StockReconciliationSearch stockReconciliationSearch = StockReconciliationSearch.builder() - .clientReferenceId(clientReferenceIdList) + .clientReferenceId(clientReferenceIdList) // Set the client reference IDs for the search .build(); - // Check if the client reference ID list is not empty + + // Check if the list of client reference IDs is not empty if (!CollectionUtils.isEmpty(clientReferenceIdList)) { - // Query the repository to find existing entities by client reference IDs - List existentEntities = stockReconciliationRepository.findById( - clientReferenceIdList, - Boolean.FALSE, - getIdFieldName(stockReconciliationSearch) - ); - // For each existing entity, populate error details for uniqueness - existentEntities.forEach(entity -> { + // Query the repository to find existing StockReconciliation entities with the given client reference IDs + List existingClientReferenceIds = + stockReconciliationRepository.validateClientReferenceIdsFromDB(clientReferenceIdList, Boolean.TRUE); + + // For each existing client reference ID, add an error to the map for the corresponding StockReconciliation entity + existingClientReferenceIds.forEach(clientReferenceId -> { + // Get a predefined error object for unique entity validation Error error = getErrorForUniqueEntity(); - populateErrorDetails(entity, error, errorDetailsMap); + // Populate error details for the individual StockReconciliation entity associated with the client reference ID + populateErrorDetails(map.get(clientReferenceId), error, errorDetailsMap); }); } + + // Return the map containing StockReconciliation entities and their associated error details return errorDetailsMap; } } From 1ea8b5b5b96517e0eab2ae427bb820a544dde191 Mon Sep 17 00:00:00 2001 From: nitish-egov <137176807+nitish-egov@users.noreply.github.com> Date: Mon, 12 Aug 2024 17:02:48 +0530 Subject: [PATCH 273/283] v0.2 admin console merge to master (#849) * Updated the user Password generation logic #761 * Update Listener.ts (#730) * Update Listener.ts * added try catch logic in producer * Feat : added parallel batch execution (#767) * Feat : added parallel batch execution * Refactor * Update utilities/project-factory/src/server/validators/campaignValidators.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fixed the stepper (#765) * changes config (#769) * Project type config and added loggers for process of campaign (#772) * Feat : added themes in generate template (#773) * fixed the ajv package version for build issue * Feat : removed xlsx (#776) * HLM-6177: PARALLEL SEARCH IMPLEMENT, DELIVERY TYPE IMPLEMENT (#778) Co-authored-by: nabeelmd-eGov * css update (#780) Co-authored-by: nabeelmd-eGov * HLM-6179 and HLM-6180 (#777) * HLM-6179 and HLM-6180 * campaign name changes --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * Feat : fixed target generation (#781) * fixed tenantId issue (#784) * fix: resolved AJV-related Jenkins build issue reference #783 #786 (#787) * module ui fix * updated all the package version for build fixes * fixed kafka-error at target generation (#789) * updated core version (#791) * updated core version * updated css also * Update campaignValidators.ts (#794) * Updated the excel generation logic and files * added changes for configurable column in target sheet (#779) * change in filter recursive * lowest level * made target headers genearte through mdms schema * changed config index.ts * changed config index.ts * changes for now * added configurable column logic from schema HLM-6169 * updated validate of target columns through schema * added masterForColumnSchema in index.ts * formatted dataManageService * refactored lock TargetFields func * removed console.log * User creation performance improved (#800) * Feat : Improved user creation performance * Change status color * Update utilities/project-factory/src/server/utils/campaignUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update genericUtils.ts (#801) * Hlm 6170 (#802) * change in filter recursive * lowest level * HLM -6170 added logic for only village level data in target sheet and some refactoring * updated css (#804) * fixed button issue (#805) * HLM 6177: Error card implementation in summary screen (#806) * HLM-6177: PARALLEL SEARCH IMPLEMENT, DELIVERY TYPE IMPLEMENT * Added Error Cards in summary screen and redirection --------- Co-authored-by: nabeelmd-eGov * added error button styles (#807) Co-authored-by: nabeelmd-eGov * updated popUp css (#808) * HLM 6178: Implementing New Pop up screen in boundaries (#809) * added error button styles * Implementing New Pop up screen in boundaries --------- Co-authored-by: nabeelmd-eGov * Facility changes (#812) * Feat : changed facility Template * Feat : locked target templates * fixed colour issue (#813) * Updated the project type conversion logic for the "deliveryType" dont1 and n config * Unique field added (#814) * Feat : changed facility Template * Feat : locked target templates * Feat : added unique check logic * Target schema update (#815) * change in filter recursive * lowest level * updated shcema of target columns to be configurable * removed empty spaces from config index.ts * Active mapping (#817) * Feat : changed facility Template * Feat : locked target templates * Feat : added unique check logic * Feat : added mapping via active field * changes in the schema validation (#816) * Updated the workbench and css module version * Feat : added active inactive boundary check (#818) * Update campaignValidators.ts (#819) * added active inactive validation (#820) * changed api call time (#826) * Feat : added target sum mapping (#825) * added campaign type as filter (#827) * Update genericApis.ts (#828) * Update excelUtils.ts (#829) * UI issue fixes, icon fix in summary error (#831) Co-authored-by: nabeelmd-eGov * Target columns (#830) * change in filter recursive * lowest level * commit * Feat : target flow fixed for LLIN-mz * uat to dev --------- Co-authored-by: admin1 * Feat : freezed target columns (#833) * Target mr dn (#834) * change in filter recursive * lowest level * Feat : skipped validation temporarily * changes in the target validation (#835) * fixed error info (#837) * Added roboto font (#840) * Feat : added roboto font * Fixed config * target validation based on diff campaign types (#843) * change in filter recursive * lowest level * updated validation of target based on campaign type * fixed validation issue (#844) * Updated the workbench package version * fixed validation logic (#846) * fixed validation logic * Update micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Error messages improved (#848) * Feat : imporved error messages and initilised utils for tracking process * Fix ; unused variables fixed * Feat : improved error messages * Fix : download error fix (#850) * Update campaignUtils.ts (#851) * Update campaignUtils.ts * Update utilities/project-factory/src/server/utils/campaignUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update campaignValidators.ts (#853) * HLM 6210: Toast, error focus fix and project type reset delivery data fix (#854) * HLM-6210: campaign type change reset delivery data fix, summary error focus fix * summary error focus fix --------- Co-authored-by: nabeelmd-eGov * HLM-6225_added time out according to data (#855) * Update campaignValidators.ts (#859) * HLM 6210 (#858) * HLM-6210: campaign type change reset delivery data fix, summary error focus fix * summary error focus fix * parallel search fixes --------- Co-authored-by: nabeelmd-eGov * Remove validation (#852) * change in filter recursive * lowest level * removed unnecessary validation for target * spacing refactor * Update campaignValidators.ts (#863) * Header validation (#861) * change in filter recursive * lowest level * removed unnecessary validation for target * changed the logic of header validation * space refactor * Update campaignUtils.ts (#864) * fixed ui error (#865) * Read me (#867) * change in filter recursive * lowest level * removed unnecessary validation for target * changed the logic of header validation * fixed portugese language error * space refactoring * Update Dockerfile * Update Dockerfile * Update migrate.sh * Update Dockerfile * Update campaignValidators.ts (#868) * HLM 6210:campaign type change reset fix (#869) * HLM-6210: campaign type change reset delivery data fix, summary error focus fix * summary error focus fix * parallel search fixes * campaign type change reset fix --------- Co-authored-by: nabeelmd-eGov * Update excelUtils.ts for sheetHeaders wraping (#870) * Update package.json * updated error messages (#871) * feat : added jaeger-client tracing (#872) * updated the table config * Update campaignApis.ts (#875) * removed the schema and updated the db name * fixing generate API call, file auto delete, date error (#877) Co-authored-by: nabeelmd-eGov * Trim resource (#878) * Feat : trimmed resource persist message * Refactor * Removed reject error in produce message * fixed min time, draft logic (#879) * Update index.ts (#880) * added min ui error and facility usage (#883) * added min ui error and facility usage * changes * Update campaignUtils.ts (#884) * HLM 6007 (#885) * fixing generate API call, file auto delete, date error * generate api fix --------- Co-authored-by: nabeelmd-eGov * Update Dockerfile * Feat : docker config update (#886) * Update Dockerfile (#887) * Create buildWorkbenchUI.yml * Update README.md (#917) * Update buildWorkbenchUI.yml * Update README.md * Updated the DB Schema issue of Project-factory * fixed hierarchy order (#919) * User flag hcm (#920) * Feat : docker config update * Feat : added user create flag * Refactored * Update campaignUtils.ts * Update campaignMappingUtils.ts (#922) * Ashish egov patch 2 (#921) * Update index.ts * Update campaignApis.ts * Fixed the project type conversion and product duplicate issue * Update campaignApis.ts (#924) * Update campaignMappingUtils.ts (#925) * Update campaignMappingUtils.ts * Refactored * Update publishProjectFactory.yml * Update buildWorkbenchUI.yml * Update campaignMappingUtils.ts (#926) * Update request.ts (#928) * Update request.ts * Feat : updated httprequest * Feat : warning response added * Refactor * added start and enddate in cycles * Update campaignApis.ts (#930) * Update request.ts (#932) * fixed generate issue (#933) * Fixed project-type resources duplication * updated target error messages (#936) * fixed stepper from draft (#937) * Update Listener.ts * delivery type disable fix, product sku name change (#939) Co-authored-by: nabeelmd-eGov * fixed error message issue (#941) * Redis integration (#940) * Feat : added redis * Feat : added redis retry * updated migration * Feat : changed download logic (#942) * Update README.md (#943) * fixed target validate for different tabs not present (#945) * Enriching already exsisting user (#946) * Feat : adding dropdowns (#952) * HLM-6270: Date logic changes, added localisation code (#953) Co-authored-by: nabeelmd-eGov * changed maximum target message (#954) * changed maximum target message * Update UploadData.js * Call generate (#951) * updated target error messages * generate call while campaign update changes boundaries * some update on call-generate * call-generate * updated call-gnerate logic * added column campaign id in generated resource table * updated config index.ts * removed console.logs * Update utilities/project-factory/src/server/utils/generateUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update utilities/project-factory/src/server/utils/generateUtils.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * added some additional conditions --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * changed facility info message (#955) * HLM 6270 (#957) * refactor * added title text --------- Co-authored-by: nabeelmd-eGov * Update genericUtils.ts (#958) * fixed boundary draft logic (#959) * Boundary code generated has now configurable hierarchy type and boundary name at last based on config (#963) * fixed target validate for different tabs not present * made hierarchytype and bondary name configurable in auto generation of boundary code * added toString() on elment for safety * HLM-6270: Elimated Generate API & enhance download API, Date logic fixes (#966) * refactor * added title text * HLM-6270: Elimated Generate API & enhance download API, Date logic fixes --------- Co-authored-by: nabeelmd-eGov * Ashish table create (#972) * saving * Feat : adding table * Feat : table creating * updated configs * Feat : added table * Feat : table added * Feat : integrated processtracks * Fix : name format (#973) * Update campaignUtils.ts (#974) * configure app static screen and skeleton (#980) * configure app static screen and skeleton * comments resolved * Migration repair (#981) * migration repair * migration repair * migration repair * Updated CampaignCard to add NATIONAL_SUPERVISOR dashboard link * made isActive change (#986) * boundaries on which we split to be fetched from mdms (#982) * fixed target validate for different tabs not present * split boundaries fetch from mdms * updated logic to fetch split on from mdms based on campaign type * fromatting * Update campaignUtils.ts (#988) * Update processTrackUtils.ts (#989) * fixs (#990) * fixs * Update SelectingBoundaries.js * Update processTrackUtils.ts (#991) * Summary screen api loop fix (#992) Co-authored-by: nabeelmd-eGov * Resource activity (#993) * fixed target validate for different tabs not present * resource activity persisting in db * Update processTrackUtils.ts (#994) * added timeout of 2 sec for boundary entity to persist (#996) * fixed target validate for different tabs not present * resource activity persisting in db * added timeout of 2 sec for boundary entity to persist * css version fix (#997) Co-authored-by: nabeelmd-eGov * Process tracking update (#998) * Feat : changed logic of process track * Feat : improved process tracks * improved process tracking * Update campaignUtils.ts (#999) * Update campaignUtils.ts (#1000) * Update campaignUtils.ts * Update Listener.ts * Feat : imporved process track (#1001) * Update campaignManageService.ts (#1003) * Update campaignManageService.ts * Update campaignUtils.ts * Update processTrackUtils.ts * Feat : added user mapping for multiple boundaries with common parent (#1005) * new template will be generated if source is microplan accordingly from mdms (#1004) * fixed target validate for different tabs not present * resource activity persisting in db * added timeout of 2 sec for boundary entity to persist * new template generate if source is microplan * updated logic for generating templates if source of campaign is from microplan * made separate function for checking source is microplan * added separate func for checking source is microplan * refactor * chnaged the checkIFSourceMicoplan func * refactored checkifsourceismicroplan * Fix : fix array fetch from cell (#1006) * Feat : fixed array issue in target (#1007) * Feat : fixed array issue in target * Update index.ts * Some fixes and refactor (#1008) * Feat : fixed array issue in target * Update index.ts * Refactor * Fixed status row * commented harcoded check && added new dashboard icon (#1011) Co-authored-by: nabeelmd-eGov * Fixed sheetrows issues (#1012) * Sheet row fixed (#1013) * Fixed sheetrows issues * Shut down if kafka error * Feat : formated sheet (#1015) * integrated admin schema with mdms_v2 (#1018) * Fix process timeline (#1029) * Feat : formated sheet * Update publishProjectFactory.yml * Update publishProjectFactory.yml * Feat : imporved processTracking and fixed migration script * Feat : fixed error persistence * Fix * Un wrap other rows (#1034) * Feat : formated sheet * Update publishProjectFactory.yml * Update publishProjectFactory.yml * Feat : imporved processTracking and fixed migration script * Feat : fixed error persistence * Unwraped lower rows * Update publishProjectFactory.yml * updated package versions (#1042) * HLM-6325/HLM-6277: Update date with & without boundary screen integration and actionable column added (#1045) * HLM-6007 * css version fix * update date screen added * change add * css fixes and API Integration for search project * Implemented Action component in My Campaign screen * Implemented Date Update with and without boundary with API integration * Boundary change --------- Co-authored-by: nabeelmd-eGov * Facility dynamic generate for source microplan (#1046) * fixed target validate for different tabs not present * resource activity persisting in db * added timeout of 2 sec for boundary entity to persist * added code for generating facility template if source is microplan * updated name * updated version (#1047) * updated core version to fix login forget password issues(#1051) * Fixed update topic (#1056) * updated version (#1061) * Hidden sheet impel (#1077) * Feat : formated sheet * Update publishProjectFactory.yml * Update publishProjectFactory.yml * Feat : imporved processTracking and fixed migration script * Feat : fixed error persistence * Unwraped lower rows * Update campaignUtils.ts * Update publishProjectFactory.yml * Update genericUtils.ts (#1078) * target template download based on delivery conditions if present (#1080) * fixed target validate for different tabs not present * resource activity persisting in db * added timeout of 2 sec for boundary entity to persist * logic for dynamic target generate template based on delivery conditions * fixed stepper color issue from draft (#1083) * fixed reordering of tab issue (#1092) * Hlm 6350 (#1094) * timeline wip * added timeline from summary * removed log * integarte with mdms (#1095) Co-authored-by: nabeelmd-eGov * Update genericUtils.ts (#1097) * Update targetUtils.ts (#1098) * Hlm 6350 (#1100) * timeline wip * added timeline from summary * removed log * integrated timeline with popup * updated version * updated css version * HCMPRE-32: Resolve date update demo points (#1104) * integarte with mdms * HCMPRE-32: Resolve date update demo points * comment resolve --------- Co-authored-by: nabeelmd-eGov * Dynamic target upload and download both with target columns as per delivery conditions when campaign is updated with cahnegs in delivery conditions (#1109) * fixed target validate for different tabs not present * resource activity persisting in db * added timeout of 2 sec for boundary entity to persist * target upload based on dynamic column in reference to deliveryRules * logic for calling generate target tempalte when campaign delivery conditions change * removed console * updated css version (#1102) * added chip for dropdown (#1111) * version fix to resolve issue (#1112) Co-authored-by: nabeelmd-eGov * Ashish patch1 (#1118) * Feat : formated sheet * Update publishProjectFactory.yml * Update publishProjectFactory.yml * Feat : imporved processTracking and fixed migration script * Feat : fixed error persistence * Unwraped lower rows * Update campaignUtils.ts * Update genericValidator.ts * Update publishProjectFactory.yml * Update targetUtils.ts * edit product with prefilled value and count (#1115) * Boundary upload to have not generate boundary code if code is already filled to support migration (#1121) * fixed target validate for different tabs not present * resource activity persisting in db * added timeout of 2 sec for boundary entity to persist * Boundary upload to have not generate boundary code if code is already filled to support migration * Update index.ts * Update constants.ts (#1122) * Update constants.ts * Update utilities/project-factory/src/server/config/constants.ts Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update campaignUtils.ts * Update campaignUtils.ts * Update campaignMappingUtils.ts --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * template downlod for source microplan (#1123) * Different tabs onlevel to fetch from mdms rather than from config in target upload flow (#1124) * template downlod for source microplan * updated logic for getting different tabs based on level from config to fetch it from mdms in target upload flow * Sequence order change in action button (#1125) Co-authored-by: nabeelmd-eGov * reverted the function validateAllDistrictTabsPresentOrNot (#1126) * template downlod for source microplan * updated logic for getting different tabs based on level from config to fetch it from mdms in target upload flow * restored the func validateAllDistrictTabsPresentOrNot to default * Update index.ts (#1129) * Update index.ts * Update Listener.ts * Update Producer.ts * Update generateUtils.ts (#1130) * some changes related to generate boundary template (#1133) * updated logic for target columns acc to delivery conditions only for smc (#1137) * some changes related to generate boundary template * updated logic for making configurable target acc to delivery only for smc * refactored code for including dynamic target columns for specific types according to configs array * updated version and boundary fix (#1141) * updated readmeconfig for sheet (#1142) * HCMPRE-140: Action column fixes, date editable logic change (#1143) * Action column fixes, date editable logic change * added roles for dss --------- Co-authored-by: nabeelmd-eGov * Update constants.ts (#1145) * Update constants.ts * Update processTrackUtils.ts * Update Listener.ts (#1147) * HCMPRE 140 (#1149) * Action column fixes, date editable logic change * added roles for dss * update dates fixes --------- Co-authored-by: nabeelmd-eGov * updated core version (#1150) * Ashish patch2 (#1152) * Update Listener.ts * added new branch * Update Listener.ts * fixed mapping kafka error * mapping kafka fixed * fix kafka * fix kafka * Update publishProjectFactory.yml * Redis cache for generating target when delivery conditions change (#1156) * updated readmeconfig for sheet * added cache for generating target template when only delivery conditions change * added cache time in config * refactored caching code in generate flow for boundary sheet * refactored callGenerate function * Ashish egov patch 2 (#1166) * Update Listener.ts * added new branch * Update Listener.ts * fixed mapping kafka error * mapping kafka fixed * fix kafka * fix kafka * Removing foreign key constraint * Update publishProjectFactory.yml * HCMPRE-154: Update Dates bug fixes, Toast added for error. (#1158) * Action column fixes, date editable logic change * added roles for dss * update dates fixes * HCMPRE-154 update dates bug fixes, Added toast for error * code clean * Update micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/BoundaryWithDate.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Adding date bug * date fix * Update micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DateWithBoundary.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DateWithBoundary.js Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: nabeelmd-eGov Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> * version update (#1168) Co-authored-by: nabeelmd-eGov * HCMPRE-6407 download template changes (#1128) * HLM-6407 adding changes for facility template * HLM-6407 adding changes for facility template * HLM-6407 adding changes for facility template * HLM-6407 codde review comment * HCMPRE-91 code review comments * HLM-6407 using same mdms schema for microplan * HLM-6407 adding changes for facility template * HLM-6407 adding changes for facility template * HLM-6407 adding changes for facility template * HLM-6407 codde review comment * HCMPRE-91 code review comments * HLM-6407 using same mdms schema for microplan * HLM-6407 code review comments * HLM-6407 code review comments * Core ui version fix (#1176) Co-authored-by: nabeelmd-eGov * Ashish egov patch 2 (#1178) * Update Listener.ts * added new branch * Update Listener.ts * fixed mapping kafka error * mapping kafka fixed * fix kafka * fix kafka * Removing foreign key constraint * Producer update * Update publishProjectFactory.yml * Update Producer.ts (#1182) * fixed timeline issues (#1185) * HCMPRE 154 (#1186) * date validation fix * Update date logic * FIX --------- Co-authored-by: nabeelmd-eGov * changes in timeline (#1187) * CSS version add (#1188) * date validation fix * Update date logic * FIX * css add --------- Co-authored-by: nabeelmd-eGov * HCMPRE 154 (#1189) * date validation fix * Update date logic * FIX * css add * non editable fix --------- Co-authored-by: nabeelmd-eGov * limited the number of columns of target for upto only 18 in number (#1190) * updated readmeconfig for sheet * added cache for generating target template when only delivery conditions change * added logic for having only 18 target columns if exceed i will create one column with header OTHER_TARGETS * HCMPRE 154 (#1191) * date validation fix * Update date logic * FIX * css add * non editable fix * date start from tomorrow * css fix for language screen --------- Co-authored-by: nabeelmd-eGov * Produceasync (#1192) * Update Listener.ts * added new branch * Update Listener.ts * fixed mapping kafka error * mapping kafka fixed * fix kafka * fix kafka * Producer update * Feat : updated producemodified message * Update publishProjectFactory.yml * Update publishProjectFactory.yml * HCMPRE 154 (#1193) * date validation fix * Update date logic * FIX * css add * non editable fix * date start from tomorrow * css fix for language screen * disable today date --------- Co-authored-by: nabeelmd-eGov * config updates according to devops (#1197) * updated readmeconfig for sheet * added cache for generating target template when only delivery conditions change * added logic for having only 18 target columns if exceed i will create one column with header OTHER_TARGETS * updated config to fetch from devops accordingly * Update index.ts * All changes (#1201) * Update Listener.ts * added new branch * Update Listener.ts * fixed mapping kafka error * mapping kafka fixed * fix kafka * fix kafka * Removing foreign key constraint * Producer update * Update Producer.ts * Update Producer.ts * Feat : updated producemodified message * Feat : removed waiting * adding constraint * Update V20240731162600__add_uniqiue_constraint_process_track.sql * Update constants.ts * Update publishProjectFactory.yml * HCMPRE 154 (#1202) * date validation fix * Update date logic * FIX * css add * non editable fix * date start from tomorrow * css fix for language screen * disable today date * date and cycle fix --------- Co-authored-by: nabeelmd-eGov * Revert "HCMPRE 154 (#1191)" (#1203) This reverts commit 59ec9531ebfc7535bacf324723edae975166867c. Co-authored-by: nabeelmd-eGov * updated versions (#1205) * Update date change screen date logic fix, info added, hard reload issue fix (#1206) Co-authored-by: nabeelmd-eGov * Config update for project-factory (#1207) * updated readmeconfig for sheet * added cache for generating target template when only delivery conditions change * added logic for having only 18 target columns if exceed i will create one column with header OTHER_TARGETS * updated config to fetch from devops accordingly * updated config for project -factory * Timeline (#1210) * updated versions * fixed user credential button * Kafka fix (#1212) * Update Listener.ts * added new branch * Update Listener.ts * fixed mapping kafka error * mapping kafka fixed * fix kafka * fix kafka * Removing foreign key constraint * Producer update * Revert "Ashish egov patch 2 (#1178)" This reverts commit e86a4dcb10dda9210ce4be75977502af7df366f6. * Update Producer.ts * Update Producer.ts * Feat : updated producemodified message * Feat : removed waiting * adding constraint * Update V20240731162600__add_uniqiue_constraint_process_track.sql * Update constants.ts * Feat : improved kafka * Fix kafka restart issue * fixed the pop up button issue (#1215) * Kafka restart (#1217) * Update Listener.ts * added new branch * Update Listener.ts * fixed mapping kafka error * mapping kafka fixed * fix kafka * fix kafka * Removing foreign key constraint * Producer update * Revert "Ashish egov patch 2 (#1178)" This reverts commit e86a4dcb10dda9210ce4be75977502af7df366f6. * Update Producer.ts * Update Producer.ts * Feat : updated producemodified message * Feat : removed waiting * adding constraint * Update V20240731162600__add_uniqiue_constraint_process_track.sql * Update constants.ts * Feat : improved kafka * Update Producer.ts * Update Producer.ts * Update publishProjectFactory.yml * updated core versions for privacy component (#1223) * Ashish egov patch 1 (#1228) * Update Listener.ts * added new branch * Update Listener.ts * fixed mapping kafka error * mapping kafka fixed * fix kafka * fix kafka * Removing foreign key constraint * Producer update * Revert "Ashish egov patch 2 (#1178)" This reverts commit e86a4dcb10dda9210ce4be75977502af7df366f6. * Update Producer.ts * Update Producer.ts * Feat : updated producemodified message * Feat : removed waiting * adding constraint * Update V20240731162600__add_uniqiue_constraint_process_track.sql * Update constants.ts * Feat : improved kafka * Update Producer.ts * Update Producer.ts * Update campaignUtils.ts * feat : solved localization passing through kafka * Update publishProjectFactory.yml * removed frontend * Update package.json * Squashed commit of the following: commit 3cd21c29c69ab52c960b6d770fe97e85f24c23e4 Merge: 12061ca60e 80f6307123 Author: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Date: Thu Aug 8 15:13:48 2024 +0530 Merge branch 'campaign' into campaign-merged commit 80f6307123c86998364e311757a46f256bd69005 Author: nitish-egov <137176807+nitish-egov@users.noreply.github.com> Date: Wed Aug 7 18:08:15 2024 +0530 Updated changelog (#1242) * default enableDynamicTemplateForWillBe empty string in config * updated changelog and postman collection commit f897dba734e05e55fa1231a81a2e5f86612825a3 Author: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Date: Wed Aug 7 17:25:39 2024 +0530 Update package.json commit dd691e6a26aff0a5131736086b447995ae3f0757 Author: Bhavya-egov <137176879+Bhavya-egov@users.noreply.github.com> Date: Tue Aug 6 13:34:40 2024 +0530 updated workbench version (#1236) commit 3a3073649791815766745c60f48db3fea4fbe7f1 Author: Bhavya-egov <137176879+Bhavya-egov@users.noreply.github.com> Date: Tue Aug 6 11:00:14 2024 +0530 updated micro ui core version (#1233) commit a1f7329c88254f4cd6ab3db2fa06c3259699f2e2 Author: nitish-egov <137176807+nitish-egov@users.noreply.github.com> Date: Mon Aug 5 18:29:40 2024 +0530 default enableDynamicTemplateForWillBe empty string in config (#1231) commit d3c3e95408f7bf25205b6b57a3e109d8eea0af2c Author: nabeelmd-eGov <94039229+nabeelmd-eGov@users.noreply.github.com> Date: Mon Aug 5 18:11:23 2024 +0530 build issue fix for optional chanining issue (#1230) Co-authored-by: nabeelmd-eGov commit 236b8439d9e24a5ecd0494f76ad2504ca693fe31 Author: nabeelmd-eGov <94039229+nabeelmd-eGov@users.noreply.github.com> Date: Mon Aug 5 17:17:20 2024 +0530 fix (#1229) Co-authored-by: nabeelmd-eGov * sending only activity object to kafka in place of request body (#851) --------- Co-authored-by: ashish-egov <137176738+ashish-egov@users.noreply.github.com> Co-authored-by: Jagankumar <53823168+jagankumar-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Bhavya-egov <137176879+Bhavya-egov@users.noreply.github.com> Co-authored-by: nabeelmd-eGov <94039229+nabeelmd-eGov@users.noreply.github.com> Co-authored-by: nabeelmd-eGov Co-authored-by: Priyanka-eGov <74049060+Priyanka-eGov@users.noreply.github.com> --- .vscode/launch.json | 18 + .vscode/settings.json | 3 + frontend/micro-ui/.gitignore | 32 - frontend/micro-ui/Jenkinsfile | 3 - frontend/micro-ui/README.md | 139 - frontend/micro-ui/package.json | 4 - frontend/micro-ui/web/.babelrc | 5 - frontend/micro-ui/web/.env.sample | 3 - frontend/micro-ui/web/CHANGELOG.md | 7 - frontend/micro-ui/web/docker/Dockerfile | 25 - frontend/micro-ui/web/docker/devDockerfile | 26 - frontend/micro-ui/web/docker/masDockerfile | 25 - frontend/micro-ui/web/docker/nginx.conf | 12 - frontend/micro-ui/web/envs.js | 0 frontend/micro-ui/web/install-deps.sh | 14 - .../web/micro-ui-internals/.gitignore | 143 - .../web/micro-ui-internals/.prettierignore | 23 - .../web/micro-ui-internals/.prettierrc.json | 3 - .../micro-ui/web/micro-ui-internals/README.md | 100 - .../micro-ui/web/micro-ui-internals/clean.sh | 28 - .../micro-ui-internals/example/.env-health-qa | 7 - .../micro-ui-internals/example/.env-mz-prod | 7 - .../micro-ui-internals/example/.env-mz-uat | 7 - .../example/.env-unifieddev | 9 - .../micro-ui-internals/example/package.json | 40 - .../example/public/index.html | 34 - .../example/src/UICustomizations.js | 789 ----- .../micro-ui-internals/example/src/index.js | 84 - .../example/src/setupProxy.js | 101 - .../web/micro-ui-internals/package.json | 59 - .../micro-ui-internals/packages/css/README.md | 62 - .../packages/css/gulpfile.js | 71 - .../packages/css/package.json | 65 - .../packages/css/postcss.config.js | 55 - .../css/src/components/microplanning.scss | 363 -- .../packages/css/src/index.scss | 13 - .../css/src/pages/employee/campaign.scss | 109 - .../css/src/pages/employee/campaignCycle.scss | 331 -- .../css/src/pages/employee/coreOverride.scss | 173 - .../css/src/pages/employee/index.scss | 481 --- .../packages/css/src/typography.scss | 512 --- .../packages/css/tailwind.config.js | 233 -- .../modules/campaign-manager/README.md | 159 - .../modules/campaign-manager/package.json | 51 - .../modules/campaign-manager/src/Module.js | 141 - .../src/components/AddProductField.js | 144 - .../src/components/BulkUpload.js | 202 -- .../src/components/CampaignCard.js | 71 - .../src/components/CampaignDates.js | 122 - .../components/CampaignDocumentsPreview.js | 92 - .../src/components/CampaignHeader.js | 32 - .../src/components/CampaignName.js | 66 - .../components/CampaignResourceDocuments.js | 50 - .../src/components/CampaignSummary.js | 484 --- .../src/components/CampaignType.js | 143 - .../src/components/CycleDataPreview.js | 186 - .../src/components/CycleDetaisPreview.js | 143 - .../src/components/DetailsTable.js | 76 - .../src/components/DocumentIcon.js | 29 - .../src/components/PlusMinusInput.js | 47 - .../src/components/RemovableTagNew.js | 16 - .../src/components/SelectingBoundaries.js | 542 --- .../src/components/TimelineCampaign.js | 46 - .../src/components/UploadData.js | 1163 ------- .../src/components/XlsPreview.js | 69 - .../src/components/icons/DustbinIcon.js | 10 - .../src/components/icons/XlsxFile.js | 32 - .../src/configs/CampaignConfig.js | 267 -- .../src/configs/UICustomizations.js | 472 --- .../src/configs/addProductConfig.js | 19 - .../src/configs/attributeConfig.js | 23 - .../src/configs/baseTimeOut.js | 6 - .../src/configs/deliveryConfig.js | 206 -- .../src/configs/headerConfig.js | 20 - .../src/configs/mailConfig.js | 5 - .../src/configs/myCampaignConfig.js | 667 ---- .../src/configs/operatorConfig.js | 27 - .../src/configs/previewConfig.js | 124 - .../src/configs/productType.js | 15 - .../src/configs/schemaConfig.js | 80 - .../campaign-manager/src/hooks/index.js | 47 - .../hooks/services/createCampaignService.js | 19 - .../hooks/services/updateCampaignService.js | 20 - .../src/hooks/services/useSearchCampaign.js | 21 - .../src/hooks/useCreateCampaign.js | 10 - .../src/hooks/useCreateProduct.js | 24 - .../src/hooks/useCreateProductVariant.js | 24 - .../src/hooks/useGenerateIdCampaign.js | 26 - .../src/hooks/useParallelSearch.js | 88 - .../src/hooks/useProductList.js | 53 - .../src/hooks/useResourceData.js | 107 - .../src/hooks/useUpdateCampaign.js | 10 - .../src/pages/employee/AddProduct.js | 161 - .../src/pages/employee/CycleConfiguration.js | 248 -- .../src/pages/employee/MyCampaign.js | 80 - .../src/pages/employee/Response.js | 65 - .../src/pages/employee/SetupCampaign.js | 1491 -------- .../deliveryRule/AddDeliverycontext.js | 813 ----- .../deliveryRule/AddProductscontext.js | 290 -- .../employee/deliveryRule/MultiTabcontext.js | 265 -- .../src/pages/employee/deliveryRule/index.js | 531 --- .../src/pages/employee/index.js | 102 - .../campaign-manager/src/utils/TourSteps.js | 144 - .../src/utils/downloadExcel.js | 46 - .../campaign-manager/src/utils/index.js | 6 - .../modules/hcm-microplanning/package.json | 62 - .../modules/hcm-microplanning/src/Module.js | 99 - .../src/components/CommonComponents.js | 61 - .../src/components/CustomScaleControl.js | 41 - .../src/components/Hypothesis.js | 607 ---- .../src/components/JsonPreviewInExcelForm.js | 113 - .../src/components/Mapping.js | 445 --- .../src/components/MappingHelperComponents.js | 513 --- .../src/components/MicroplanCreatedScreen.js | 111 - .../src/components/MicroplanDetails.js | 294 -- .../src/components/MicroplanPreview.js | 478 --- .../MicroplanPreviewHelperCompoenents.js | 434 --- .../src/components/MicroplanningCard.js | 34 - .../src/components/MicroplanningHeader.js | 29 - .../hcm-microplanning/src/components/Modal.js | 158 - .../src/components/Nagivator.js | 272 -- .../src/components/RuleEngine.js | 876 ----- .../src/components/Upload.js | 1137 ------- .../src/components/UploadHelperComponents.js | 299 -- .../src/components/ZoomControl.js | 29 - .../src/components/resourceMapping.js | 187 - .../src/configs/UICustomizations.js | 324 -- .../src/configs/constants.js | 36 - .../src/configs/timeLineOptions.json | 40 - .../src/configs/tourSteps.js | 193 -- .../hcm-microplanning/src/hooks/index.js | 42 - .../src/hooks/useCreatePlanConfig.js | 8 - .../src/hooks/useGenerateIdCampaign.js | 26 - .../src/hooks/useNumberFormatter.js | 21 - .../src/hooks/useSavedMicroplans.js | 23 - .../src/hooks/useSearchCampaign.js | 8 - .../src/hooks/useSearchPlanConfig.js | 8 - .../src/hooks/useUpdatePlanConfig.js | 8 - .../hcm-microplanning/src/icons/Svg.js | 217 -- .../src/pages/employee/CreateMicroplan.js | 288 -- .../src/pages/employee/Guidelines.js | 54 - .../src/pages/employee/SavedMicroplans.js | 200 -- .../src/pages/employee/SelectCampaign.js | 226 -- .../src/pages/employee/index.js | 128 - .../src/services/CreatePlanConfig.js | 19 - .../hcm-microplanning/src/services/Search.js | 181 - .../src/services/SearchCampaignConfig.js | 22 - .../src/services/SearchPlanConfig.js | 19 - .../src/services/UpdatePlanConfig.js | 18 - .../src/services/searchSavedPlans.js | 67 - .../hcm-microplanning/src/utils/context.js | 31 - .../src/utils/createTemplate.js | 485 --- .../hcm-microplanning/src/utils/excelUtils.js | 150 - .../src/utils/excelValidations.js | 199 -- .../src/utils/exceltojson.js | 99 - .../src/utils/geojsonValidations.js | 234 -- .../hcm-microplanning/src/utils/index.js | 478 --- .../src/utils/jsonToExcelBlob.js | 72 - .../src/utils/mappingUtils.js | 760 ----- .../src/utils/microplanPreviewUtils.js | 413 --- .../src/utils/processHierarchyAndData.js | 351 -- .../src/utils/updateSessionUtils.js | 486 --- .../src/utils/uploadUtils.js | 880 ----- .../Modal/AttendanceActionModal.js | 133 - .../Modal/BPAActionModal.js | 283 -- .../Modal/BPAREGActionModal.js | 153 - .../Modal/ExpenditureActionModal.js | 190 -- .../Modal/FSMActionModal.js | 298 -- .../Modal/NOCActionModal.js | 169 - .../ApplicationDetails/Modal/PTActionModal.js | 190 -- .../ApplicationDetails/Modal/TLActionModal.js | 166 - .../Modal/WNSActionModal.js | 261 -- .../Modal/WorksActionModal.js | 262 -- .../ApplicationDetails/Modal/index.js | 49 - .../components/ApplicationDetailsActionBar.js | 80 - .../components/ApplicationDetailsContent.js | 484 --- .../components/ApplicationDetailsToast.js | 74 - .../ApplicationDetailsWarningPopup.js | 54 - .../components/BPADocuments.js | 234 -- .../components/DocumentsPreview.js | 49 - .../components/InfoDetails.js | 34 - .../components/InspectionReport.js | 49 - .../components/NOCDocuments.js | 202 -- .../components/PermissionCheck.js | 87 - .../components/PropertyDocuments.js | 83 - .../components/PropertyEstimates.js | 39 - .../components/PropertyFloors.js | 49 - .../components/PropertyOwners.js | 94 - .../ApplicationDetails/components/Reason.js | 10 - .../components/ScruntinyDetails.js | 46 - .../components/SubOccupancyTable.js | 126 - .../components/SubWorkTableDetails.js | 77 - .../components/TLCaption.js | 34 - .../components/TLTradeAccessories.js | 52 - .../components/TLTradeUnits.js | 51 - .../components/ViewBreakup.js | 73 - .../components/WSAdditonalDetails.js | 399 --- .../components/WSFeeEstimation.js | 346 -- .../components/WeekDateRange.js | 30 - .../ApplicationDetails/config/AcceptDso.js | 45 - .../ApplicationDetails/config/AssignDso.js | 115 - .../config/BPAApproverApplication.js | 77 - .../config/BPAREGApproverApplication.js | 71 - .../config/CompleteApplication.js | 46 - .../config/NOCApproverApplication.js | 79 - .../config/PTApproverApplication.js | 66 - .../config/PTAssessProperty.js | 26 - .../ApplicationDetails/config/ReassignDso.js | 101 - .../config/RejectApplication.js | 31 - .../config/TLApproverApplication.js | 83 - .../config/WSApproverApplication.js | 73 - .../config/WSDisconnectApplication.js | 89 - .../config/configApproveModal.js | 53 - .../config/configAttendanceApproveModal.js | 27 - .../config/configAttendanceCheckModal.js | 93 - .../config/configAttendanceRejectModal.js | 61 - .../config/configCheckModal.js | 105 - .../config/configRejectModal.js | 127 - .../config/configViewBillApproveModal.js | 57 - .../config/configViewBillCheckModal.js | 107 - .../config/configViewBillRejectModal.js | 59 - .../ApplicationDetails/config/index.js | 47 - .../templates/ApplicationDetails/index.js | 368 -- .../web/micro-ui-internals/publish-develop.sh | 20 - .../web/micro-ui-internals/publish.sh | 20 - .../web/micro-ui-internals/scripts/create.sh | 3 - .../web/micro-ui-internals/scripts/deploy.sh | 8 - .../web/micro-ui-internals/scripts/jenkins.sh | 3 - .../web/micro-ui-internals/scripts/run.sh | 32 - .../micro-ui/web/micro-ui-internals/test.js | 31 - frontend/micro-ui/web/microplan/App.js | 61 - frontend/micro-ui/web/microplan/Dockerfile | 30 - .../micro-ui/web/microplan/install-deps.sh | 18 - .../micro-ui/web/microplan/inter-package.json | 61 - frontend/micro-ui/web/microplan/nginx.conf | 12 - frontend/micro-ui/web/microplan/package.json | 80 - .../micro-ui/web/microplan/webpack.config.js | 52 - frontend/micro-ui/web/package.json | 85 - frontend/micro-ui/web/public/index.html | 38 - frontend/micro-ui/web/public/robots.txt | 3 - frontend/micro-ui/web/src/App.js | 74 - .../micro-ui/web/src/ComponentRegistry.js | 11 - .../src/Customisations/UICustomizations.js | 428 --- .../micro-ui/web/src/Customisations/index.js | 19 - .../web/src/Customisations/pt/index.js | 13 - .../pt/pageComponents/PTAllotmentDetails.js | 64 - .../pt/pageComponents/PTBusinessDetails.js | 68 - .../pt/pageComponents/PTVasikaDetails.js | 79 - .../pt/pageComponents/PropertyUsageType.js | 134 - .../src/Customisations/tl/TLCustomisation.js | 5 - .../web/src/Customisations/tl/index.js | 7 - .../tl/pageComponents/PropertyUsageType.js | 136 - frontend/micro-ui/web/src/index.css | 0 frontend/micro-ui/web/src/index.js | 62 - frontend/micro-ui/web/src/setupProxy.js | 30 - frontend/micro-ui/web/webpack.config.js | 43 - frontend/micro-ui/web/workbench/App.js | 72 - frontend/micro-ui/web/workbench/Dockerfile | 29 - .../micro-ui/web/workbench/install-deps.sh | 18 - .../micro-ui/web/workbench/inter-package.json | 58 - frontend/micro-ui/web/workbench/nginx.conf | 12 - frontend/micro-ui/web/workbench/package.json | 89 - .../micro-ui/web/workbench/webpack.config.js | 44 - health-services/project-factory/CHANGELOG.md | 6 + health-services/project-factory/README.md | 125 +- ...enerated_resource_details_alter_column.sql | 13 + .../V20240625141100__process_details_ddl.sql | 11 + ...generated_resource_detail_alter_column.sql | 24 + ...100__remove_constraint_process_details.sql | 3 + ...__add_uniqiue_constraint_process_track.sql | 10 + .../project-factory/migration/migrate.sh | 1 + .../project-factory/package-lock.json | 2993 ++++++++--------- health-services/project-factory/package.json | 3 +- .../project-factory/postman_collection.json | 413 ++- .../src/server/api/campaignApis.ts | 132 +- .../src/server/api/genericApis.ts | 281 +- .../src/server/config/constants.ts | 41 +- .../src/server/config/createAndSearch.ts | 132 + .../src/server/config/index.ts | 11 +- .../config/models/createRequestSchema.ts | 2 +- .../config/models/downloadRequestSchema.ts | 20 +- .../config/models/generateRequestSchema.ts | 2 - .../campaignManage.controller.ts | 21 +- .../src/server/kafka/Listener.ts | 112 +- .../src/server/kafka/Producer.ts | 124 +- .../server/service/campaignManageService.ts | 23 +- .../src/server/service/dataManageService.ts | 39 +- .../src/server/utils/campaignMappingUtils.ts | 343 +- .../src/server/utils/campaignUtils.ts | 197 +- .../src/server/utils/excelUtils.ts | 90 +- .../src/server/utils/generateUtils.ts | 85 + .../src/server/utils/genericUtils.ts | 311 +- .../src/server/utils/localisationUtils.ts | 34 +- .../src/server/utils/processTrackUtils.ts | 234 +- .../src/server/utils/targetUtils.ts | 137 + .../server/validators/campaignValidators.ts | 180 +- .../src/server/validators/genericValidator.ts | 54 +- health-services/project-factory/yarn.lock | 835 +++-- 298 files changed, 4307 insertions(+), 39852 deletions(-) create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json delete mode 100644 frontend/micro-ui/.gitignore delete mode 100644 frontend/micro-ui/Jenkinsfile delete mode 100644 frontend/micro-ui/README.md delete mode 100644 frontend/micro-ui/package.json delete mode 100644 frontend/micro-ui/web/.babelrc delete mode 100644 frontend/micro-ui/web/.env.sample delete mode 100644 frontend/micro-ui/web/CHANGELOG.md delete mode 100644 frontend/micro-ui/web/docker/Dockerfile delete mode 100644 frontend/micro-ui/web/docker/devDockerfile delete mode 100644 frontend/micro-ui/web/docker/masDockerfile delete mode 100644 frontend/micro-ui/web/docker/nginx.conf delete mode 100644 frontend/micro-ui/web/envs.js delete mode 100755 frontend/micro-ui/web/install-deps.sh delete mode 100644 frontend/micro-ui/web/micro-ui-internals/.gitignore delete mode 100644 frontend/micro-ui/web/micro-ui-internals/.prettierignore delete mode 100644 frontend/micro-ui/web/micro-ui-internals/.prettierrc.json delete mode 100644 frontend/micro-ui/web/micro-ui-internals/README.md delete mode 100644 frontend/micro-ui/web/micro-ui-internals/clean.sh delete mode 100644 frontend/micro-ui/web/micro-ui-internals/example/.env-health-qa delete mode 100644 frontend/micro-ui/web/micro-ui-internals/example/.env-mz-prod delete mode 100644 frontend/micro-ui/web/micro-ui-internals/example/.env-mz-uat delete mode 100644 frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev delete mode 100644 frontend/micro-ui/web/micro-ui-internals/example/package.json delete mode 100644 frontend/micro-ui/web/micro-ui-internals/example/public/index.html delete mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/example/src/setupProxy.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/package.json delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/README.md delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/gulpfile.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/package.json delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/postcss.config.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/index.scss delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/src/typography.scss delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/README.md delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AddProductField.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/BulkUpload.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignCard.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDates.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignDocumentsPreview.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignHeader.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignName.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignResourceDocuments.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignSummary.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CampaignType.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDataPreview.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDetaisPreview.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DetailsTable.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DocumentIcon.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/PlusMinusInput.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RemovableTagNew.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/TimelineCampaign.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/UploadData.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/XlsPreview.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/DustbinIcon.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/icons/XlsxFile.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/CampaignConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/UICustomizations.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/addProductConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/attributeConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/baseTimeOut.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/deliveryConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/headerConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/mailConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/myCampaignConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/operatorConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/previewConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/productType.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/configs/schemaConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/createCampaignService.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/updateCampaignService.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/services/useSearchCampaign.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateCampaign.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProduct.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useCreateProductVariant.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useGenerateIdCampaign.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useParallelSearch.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useProductList.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useResourceData.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/hooks/useUpdateCampaign.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/AddProduct.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/CycleConfiguration.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/MyCampaign.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/Response.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/SetupCampaign.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/AddDeliverycontext.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/AddProductscontext.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/MultiTabcontext.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/TourSteps.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/downloadExcel.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/package.json delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/Module.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CommonComponents.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CustomScaleControl.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Hypothesis.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/JsonPreviewInExcelForm.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MappingHelperComponents.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/UploadHelperComponents.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/UICustomizations.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/mappingUtils.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/AttendanceActionModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAActionModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAREGActionModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/ExpenditureActionModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/FSMActionModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/NOCActionModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/PTActionModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/TLActionModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WNSActionModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WorksActionModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsActionBar.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsContent.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsToast.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsWarningPopup.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/BPADocuments.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/DocumentsPreview.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InfoDetails.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InspectionReport.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/NOCDocuments.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PermissionCheck.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyDocuments.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyEstimates.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyFloors.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyOwners.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/Reason.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ScruntinyDetails.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubOccupancyTable.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubWorkTableDetails.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLCaption.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeAccessories.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeUnits.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ViewBreakup.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSAdditonalDetails.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSFeeEstimation.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WeekDateRange.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AcceptDso.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AssignDso.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAApproverApplication.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAREGApproverApplication.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/CompleteApplication.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/NOCApproverApplication.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTApproverApplication.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTAssessProperty.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/ReassignDso.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/RejectApplication.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/TLApproverApplication.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSApproverApplication.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSDisconnectApplication.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configApproveModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceApproveModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceCheckModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceRejectModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configCheckModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configRejectModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillApproveModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillCheckModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillRejectModal.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/index.js delete mode 100644 frontend/micro-ui/web/micro-ui-internals/publish-develop.sh delete mode 100644 frontend/micro-ui/web/micro-ui-internals/publish.sh delete mode 100755 frontend/micro-ui/web/micro-ui-internals/scripts/create.sh delete mode 100755 frontend/micro-ui/web/micro-ui-internals/scripts/deploy.sh delete mode 100755 frontend/micro-ui/web/micro-ui-internals/scripts/jenkins.sh delete mode 100755 frontend/micro-ui/web/micro-ui-internals/scripts/run.sh delete mode 100644 frontend/micro-ui/web/micro-ui-internals/test.js delete mode 100644 frontend/micro-ui/web/microplan/App.js delete mode 100644 frontend/micro-ui/web/microplan/Dockerfile delete mode 100644 frontend/micro-ui/web/microplan/install-deps.sh delete mode 100644 frontend/micro-ui/web/microplan/inter-package.json delete mode 100644 frontend/micro-ui/web/microplan/nginx.conf delete mode 100644 frontend/micro-ui/web/microplan/package.json delete mode 100644 frontend/micro-ui/web/microplan/webpack.config.js delete mode 100644 frontend/micro-ui/web/package.json delete mode 100644 frontend/micro-ui/web/public/index.html delete mode 100644 frontend/micro-ui/web/public/robots.txt delete mode 100644 frontend/micro-ui/web/src/App.js delete mode 100644 frontend/micro-ui/web/src/ComponentRegistry.js delete mode 100644 frontend/micro-ui/web/src/Customisations/UICustomizations.js delete mode 100644 frontend/micro-ui/web/src/Customisations/index.js delete mode 100644 frontend/micro-ui/web/src/Customisations/pt/index.js delete mode 100644 frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTAllotmentDetails.js delete mode 100644 frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTBusinessDetails.js delete mode 100644 frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTVasikaDetails.js delete mode 100644 frontend/micro-ui/web/src/Customisations/pt/pageComponents/PropertyUsageType.js delete mode 100644 frontend/micro-ui/web/src/Customisations/tl/TLCustomisation.js delete mode 100644 frontend/micro-ui/web/src/Customisations/tl/index.js delete mode 100644 frontend/micro-ui/web/src/Customisations/tl/pageComponents/PropertyUsageType.js delete mode 100644 frontend/micro-ui/web/src/index.css delete mode 100644 frontend/micro-ui/web/src/index.js delete mode 100644 frontend/micro-ui/web/src/setupProxy.js delete mode 100644 frontend/micro-ui/web/webpack.config.js delete mode 100644 frontend/micro-ui/web/workbench/App.js delete mode 100644 frontend/micro-ui/web/workbench/Dockerfile delete mode 100755 frontend/micro-ui/web/workbench/install-deps.sh delete mode 100644 frontend/micro-ui/web/workbench/inter-package.json delete mode 100644 frontend/micro-ui/web/workbench/nginx.conf delete mode 100644 frontend/micro-ui/web/workbench/package.json delete mode 100644 frontend/micro-ui/web/workbench/webpack.config.js create mode 100644 health-services/project-factory/migration/main/V20240624210000__generated_resource_details_alter_column.sql create mode 100644 health-services/project-factory/migration/main/V20240625141100__process_details_ddl.sql create mode 100644 health-services/project-factory/migration/main/V20240708153000__generated_resource_detail_alter_column.sql create mode 100644 health-services/project-factory/migration/main/V20240725155100__remove_constraint_process_details.sql create mode 100644 health-services/project-factory/migration/main/V20240731162600__add_uniqiue_constraint_process_track.sql create mode 100644 health-services/project-factory/src/server/utils/generateUtils.ts create mode 100644 health-services/project-factory/src/server/utils/targetUtils.ts diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000000..d61e0ddfd7d --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,18 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + + { + "type": "node", + "request": "attach", + "name": "Attach to Remote", + "address": "localhost", + "port": 9229, + "localRoot": "${workspaceFolder}", + "remoteRoot": "/app" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000000..14f60307eb1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.inlineSuggest.showToolbar": "onHover" +} \ No newline at end of file diff --git a/frontend/micro-ui/.gitignore b/frontend/micro-ui/.gitignore deleted file mode 100644 index feb4cac5c94..00000000000 --- a/frontend/micro-ui/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -.env -.eslintcache - -# yarn $ -.yarn -yarn.lock -.yarnrc.yml - -# dependencies -node_modules -.yarn -/.pnp -.pnp.js - -# testing -/coverage - -# production -/web/build -dist -# misc -.DS_Store -.env.local -.env.development.local -.env.test.local -.env.production.local - -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/frontend/micro-ui/Jenkinsfile b/frontend/micro-ui/Jenkinsfile deleted file mode 100644 index 1206b9c141d..00000000000 --- a/frontend/micro-ui/Jenkinsfile +++ /dev/null @@ -1,3 +0,0 @@ -library 'ci-libs' - -buildPipeline(configFile: './build/build-config.yml') diff --git a/frontend/micro-ui/README.md b/frontend/micro-ui/README.md deleted file mode 100644 index 9f559d81783..00000000000 --- a/frontend/micro-ui/README.md +++ /dev/null @@ -1,139 +0,0 @@ - -# DIGIT ui - -A React App built on top of DIGIT UI Core. - -# DIGIT - -DIGIT eGovernance Platform Services - -DIGIT (Digital Infrastructure for Governance, Impact & Transformation) is India's largest platform for governance services. Visit https://core.digit.org/ for more details. - -DIGIT platform is microservices based API platform enabling quick rebundling of services as per specific needs. This is a repo that lays down the core platform on top of which other mission services depend. - - -# DIGIT UI - - -This repository contains source code for web implementation of the new Digit UI modules with dependencies and libraries. - -Workbench module is used to Manage the master data (MDMS V2 Service) used across the DIGIT Services / Applications - -It is also used to manage the Localisation data present in the system (Localisation service) - - -## Run Locally - -Clone the project - -```bash - git clone https://github.com/egovernments/DIGIT-Frontend.git -``` - -Go to the Sub directory to run UI -```bash - cd into micro-ui/web/micro-ui-internals -``` - -Install dependencies - -```bash - yarn install -``` - -Add .env file -```bash - micro-ui/web/micro-ui-internals/example/.env -``` - -Start the server - -```bash - yarn start -``` - - -## Environment Variables - -To run this project, you will need to add the following environment variables to your .env file - -`REACT_APP_PROXY_API` :: `{{server url}}` - -`REACT_APP_GLOBAL` :: `{{server url}}` - -`REACT_APP_PROXY_ASSETS` :: `{{server url}}` - -`REACT_APP_USER_TYPE` :: `{{EMPLOYEE||CITIZEN}}` - -`SKIP_PREFLIGHT_CHECK` :: `true` - -[sample .env file](https://github.com/egovernments/Digit-Core/blob/workbench/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev) - -## Tech Stack - -**Libraries:** - -[React](https://react.dev/) - -[React Hook Form](https://www.react-hook-form.com/) - -[React Query](https://tanstack.com/query/v3/) - -[Tailwind CSS](https://tailwindcss.com/) - -[Webpack](https://webpack.js.org/) - -## License - -[MIT](https://choosealicense.com/licenses/mit/) - - -## Author - -- [@jagankumar-egov](https://www.github.com/jagankumar-egov) - - -## Documentation - -[Documentation](https://https://core.digit.org/guides/developer-guide/ui-developer-guide/digit-ui) - - -## Support - -For support, add the issues in https://github.com/egovernments/DIGIT-core/issues. - - -## Modules - - 1. Core - 2. Workbench - 3. HRMS - 4. Dashboard - 5. Engagement - 6. Payment - -## Starting with Digit-UI App (Impelmentation Teams) - MICRO-UI - - -Go to the Sub directory to run UI - -```bash - cd into micro-ui/web -``` - -```bash - yarn install -``` - -Add .env file -```bash - micro-ui/web/.env -``` - -Start the server - -```bash - yarn start -``` - -![Logo](https://s3.ap-south-1.amazonaws.com/works-dev-asset/mseva-white-logo.png) diff --git a/frontend/micro-ui/package.json b/frontend/micro-ui/package.json deleted file mode 100644 index 78ab4e7aa40..00000000000 --- a/frontend/micro-ui/package.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "workbench-ui", - "version": "0.1.0" -} \ No newline at end of file diff --git a/frontend/micro-ui/web/.babelrc b/frontend/micro-ui/web/.babelrc deleted file mode 100644 index 5f90443d15e..00000000000 --- a/frontend/micro-ui/web/.babelrc +++ /dev/null @@ -1,5 +0,0 @@ -{ - "presets": [ - "@babel/preset-env","@babel/preset-react" - ] - } \ No newline at end of file diff --git a/frontend/micro-ui/web/.env.sample b/frontend/micro-ui/web/.env.sample deleted file mode 100644 index e87c7f586c4..00000000000 --- a/frontend/micro-ui/web/.env.sample +++ /dev/null @@ -1,3 +0,0 @@ -SKIP_PREFLIGHT_CHECK=true -REACT_APP_STATE_LEVEL_TENANT_ID=pb -REACT_APP_PROXY_URL=https://works-dev.digit.org diff --git a/frontend/micro-ui/web/CHANGELOG.md b/frontend/micro-ui/web/CHANGELOG.md deleted file mode 100644 index 826105084e8..00000000000 --- a/frontend/micro-ui/web/CHANGELOG.md +++ /dev/null @@ -1,7 +0,0 @@ -# Changelog -All notable changes to this module will be documented in this file. - -## 0.1.0 - 2024-05-28 -#### Base Admin console web - 1. Helps in creating the Campaign and configure delivery rules - 2. Create Data: Validates and creates resource details of type facility,user and boundary. diff --git a/frontend/micro-ui/web/docker/Dockerfile b/frontend/micro-ui/web/docker/Dockerfile deleted file mode 100644 index 8e9b173bb85..00000000000 --- a/frontend/micro-ui/web/docker/Dockerfile +++ /dev/null @@ -1,25 +0,0 @@ -# FROM egovio/alpine-node-builder-14:yarn AS build -FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build -RUN apk update && apk upgrade -RUN apk add --no-cache git>2.30.0 -ARG WORK_DIR -WORKDIR /app -ENV NODE_OPTIONS "--max-old-space-size=8168" - -COPY ${WORK_DIR} . -RUN ls -lah - -#RUN node web/envs.js -RUN cd web/ \ - && ./install-deps.sh \ - && yarn install \ - && yarn build:webpack - -FROM nginx:mainline-alpine -#FROM ghcr.io/egovernments/nginx:mainline-alpine -ENV WORK_DIR=/var/web/digit-ui - -RUN mkdir -p ${WORK_DIR} - -COPY --from=build /app/web/build ${WORK_DIR}/ -COPY --from=build /app/web/docker/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/micro-ui/web/docker/devDockerfile b/frontend/micro-ui/web/docker/devDockerfile deleted file mode 100644 index d7b1ba1870a..00000000000 --- a/frontend/micro-ui/web/docker/devDockerfile +++ /dev/null @@ -1,26 +0,0 @@ -#FROM egovio/alpine-node-builder-14:yarn AS build -FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build -RUN apk update && apk upgrade -RUN apk add --no-cache git>2.30.0 -ARG WORK_DIR -WORKDIR /app -ENV NODE_OPTIONS "--max-old-space-size=1792" - -COPY ${WORK_DIR} . -RUN ls -lah - -#RUN node web/envs.js -RUN cd web/ \ - && node envs.js \ - && ./install-deps.sh \ - && yarn install \ - && yarn build - -#FROM nginx:mainline-alpine -FROM ghcr.io/egovernments/nginx:mainline-alpine -ENV WORK_DIR=/var/web/digit-ui - -RUN mkdir -p ${WORK_DIR} - -COPY --from=build /app/web/build ${WORK_DIR}/ -COPY --from=build /app/web/docker/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/micro-ui/web/docker/masDockerfile b/frontend/micro-ui/web/docker/masDockerfile deleted file mode 100644 index 5d7cf45dd87..00000000000 --- a/frontend/micro-ui/web/docker/masDockerfile +++ /dev/null @@ -1,25 +0,0 @@ -#FROM egovio/alpine-node-builder-14:yarn AS build -FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build -RUN apk update && apk upgrade -RUN apk add --no-cache git>2.30.0 -ARG WORK_DIR -WORKDIR /app -ENV NODE_OPTIONS "--max-old-space-size=3792" - -COPY ${WORK_DIR} . -RUN ls -lah - -#RUN node web/envs.js -RUN cd web/ \ - && node envs.js \ - && yarn install \ - && yarn build - -#FROM nginx:mainline-alpine -FROM ghcr.io/egovernments/nginx:mainline-alpine -ENV WORK_DIR=/var/web/digit-ui - -RUN mkdir -p ${WORK_DIR} - -COPY --from=build /app/web/build ${WORK_DIR}/ -COPY --from=build /app/web/docker/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/micro-ui/web/docker/nginx.conf b/frontend/micro-ui/web/docker/nginx.conf deleted file mode 100644 index 4f532e4a6ed..00000000000 --- a/frontend/micro-ui/web/docker/nginx.conf +++ /dev/null @@ -1,12 +0,0 @@ -server -{ - listen 80; - underscores_in_headers on; - - location /digit-ui - { - root /var/web; - index index.html index.htm; - try_files $uri $uri/ /digit-ui/index.html; - } -} \ No newline at end of file diff --git a/frontend/micro-ui/web/envs.js b/frontend/micro-ui/web/envs.js deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/frontend/micro-ui/web/install-deps.sh b/frontend/micro-ui/web/install-deps.sh deleted file mode 100755 index efaceaee20d..00000000000 --- a/frontend/micro-ui/web/install-deps.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -BRANCH="$(git branch --show-current)" - -echo "Main Branch: $BRANCH" - -INTERNALS="micro-ui-internals" - -cp $INTERNALS/example/src/UICustomizations.js src/Customisations - -cd $INTERNALS && echo "Branch: $(git branch --show-current)" && echo "$(git log -1 --pretty=%B)" && echo "installing packages" - - -# yarn install diff --git a/frontend/micro-ui/web/micro-ui-internals/.gitignore b/frontend/micro-ui/web/micro-ui-internals/.gitignore deleted file mode 100644 index 1747c795d6f..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/.gitignore +++ /dev/null @@ -1,143 +0,0 @@ -# Created by https://www.toptal.com/developers/gitignore/api/node,react -# Edit at https://www.toptal.com/developers/gitignore?templates=node,react - -### eGov ### -packages/css/example/index.css -package-lock.json -locales/ -build/ -packages/**/dist/ - -# yarn # -.yarn -.yarnrc.yml - -### Node ### -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* - -# Diagnostic reports (https://nodejs.org/api/report.html) -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage -*.lcov - -# nyc test coverage -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) -.grunt - -# Bower dependency directory (https://bower.io/) -bower_components - -# node-waf configuration -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) -build/Release - -# Dependency directories -node_modules/ -jspm_packages/ - -# TypeScript v1 declaration files -typings/ - -# TypeScript cache -*.tsbuildinfo - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Microbundle cache -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history -.node_repl_history - -# Output of 'npm pack' -*.tgz - -# Yarn Integrity file -.yarn-integrity - -# dotenv environment variables file -.env -.env.test -.env*.local - -# parcel-bundler cache (https://parceljs.org/) -.cache -.parcel-cache - -# Next.js build output -.next - -# Nuxt.js build / generate output -.nuxt -dist -dist-storybook - -# Gatsby files -.cache/ -# Comment in the public line in if your project uses Gatsby and not Next.js -# https://nextjs.org/blog/next-9-1#public-directory-support -# public - -# vuepress build output -.vuepress/dist - -# Serverless directories -.serverless/ - -# FuseBox cache -.fusebox/ - -# DynamoDB Local files -.dynamodb/ - -# TernJS port file -.tern-port - -# Stores VSCode versions used for testing VSCode extensions -.vscode-test - -### react ### -.DS_* -**/*.backup.* -**/*.back.* - -node_modules - -*.sublime* - -psd -thumb -sketch - -# vs code -.vscode/ - -# End of https://www.toptal.com/developers/gitignore/api/node,react \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/.prettierignore b/frontend/micro-ui/web/micro-ui-internals/.prettierignore deleted file mode 100644 index d54de016ef0..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/.prettierignore +++ /dev/null @@ -1,23 +0,0 @@ - -# See https://help.github.com/ignore-files/ for more about ignoring files. -# dependencies -node_modules -# builds -build -dist -.rpt2_cache -# dev -dev.css -index.css -index.compat.css -index.min.css -# misc -.DS_Store -.env -.env.local -.env.development.local -.env.test.local -.env.production.local -npm-debug.log* -yarn-debug.log* -yarn-error.log* diff --git a/frontend/micro-ui/web/micro-ui-internals/.prettierrc.json b/frontend/micro-ui/web/micro-ui-internals/.prettierrc.json deleted file mode 100644 index b975008d6f8..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/.prettierrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "printWidth": 150 -} diff --git a/frontend/micro-ui/web/micro-ui-internals/README.md b/frontend/micro-ui/web/micro-ui-internals/README.md deleted file mode 100644 index f23a1fcfe9c..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/README.md +++ /dev/null @@ -1,100 +0,0 @@ - -# workbench ui - -A React App built on top of DIGIT UI Core. - - -# DIGIT UI - -DIGIT (Digital Infrastructure for Governance, Impact & Transformation) is India's largest platform for governance services. Visit https://www.digit.org for more details. - -This repository contains source code for web implementation of the new Digit UI modules with dependencies and libraries. - -Workbench module is used to Manage the master data (MDMS V2 Service) used across the DIGIT Services / Applications - -It is also used to manage the Localisation data present in the system (Localisation service) - - -## Run Locally - -Clone the project - -```bash - git clone https://github.com/egovernments/Digit-Core.git -``` - -Go to the Sub directory to run UI -```bash - cd into frontend/micro-ui/web/micro-ui-internals -``` - -Install dependencies - -```bash - yarn install -``` - -Add .env file -```bash - frontend/micro-ui/web/micro-ui-internals/example/.env -``` - -Start the server - -```bash - yarn start -``` - - -## Environment Variables - -To run this project, you will need to add the following environment variables to your .env file - -`REACT_APP_PROXY_API` :: `{{server url}}` - -`REACT_APP_GLOBAL` :: `{{server url}}` - -`REACT_APP_PROXY_ASSETS` :: `{{server url}}` - -`REACT_APP_USER_TYPE` :: `{{EMPLOYEE||CITIZEN}}` - -`SKIP_PREFLIGHT_CHECK` :: `true` - -[sample .env file](https://github.com/egovernments/Digit-Core/blob/workbench/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev) - -## Tech Stack - -**Libraries:** - -[React](https://react.dev/) - -[React Hook Form](https://www.react-hook-form.com/) - -[React Query](https://tanstack.com/query/v3/) - -[Tailwind CSS](https://tailwindcss.com/) - -[Webpack](https://webpack.js.org/) - -## License - -[MIT](https://choosealicense.com/licenses/mit/) - - -## Author - -- [@jagankumar-egov](https://www.github.com/jagankumar-egov) - - -## Documentation - -[Documentation](https://https://core.digit.org/guides/developer-guide/ui-developer-guide/digit-ui) - - -## Support - -For support, add the issues in https://github.com/egovernments/DIGIT-core/issues. - - -![Logo](https://s3.ap-south-1.amazonaws.com/works-dev-asset/mseva-white-logo.png) - diff --git a/frontend/micro-ui/web/micro-ui-internals/clean.sh b/frontend/micro-ui/web/micro-ui-internals/clean.sh deleted file mode 100644 index 2235ef1c1d0..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/clean.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -BASEDIR="$( cd "$( dirname "$0" )" && pwd )" - -msg() { - echo -e "\n\n\033[32;32m$1\033[0m" -} - -msg "Cleaning root" -rm -rf node_modules - -msg "Cleaning css" -cd "$BASEDIR/packages/css" && rm -rf node_modules - -msg "Cleaning libraries" -cd "$BASEDIR/packages/libraries" && rm -rf node_modules - -msg "Cleaning react-components" -cd "$BASEDIR/packages/react-components" && rm -rf node_modules - -msg "Cleaning PGR module" -cd "$BASEDIR/packages/modules/pgr" && rm -rf node_modules - -msg "Cleaning FSM module" -cd "$BASEDIR/packages/modules/fsm" && rm -rf node_modules - -msg "Cleaning Core module" -cd "$BASEDIR/packages/modules/core" && rm -rf node_modules diff --git a/frontend/micro-ui/web/micro-ui-internals/example/.env-health-qa b/frontend/micro-ui/web/micro-ui-internals/example/.env-health-qa deleted file mode 100644 index 73b42b7dfad..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/example/.env-health-qa +++ /dev/null @@ -1,7 +0,0 @@ -SKIP_PREFLIGHT_CHECK=true -REACT_APP_USER_TYPE=EMPLOYEE -REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a -REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c -REACT_APP_PROXY_API=https://health-qa.digit.org -REACT_APP_PROXY_ASSETS=https://health-qa.digit.org -REACT_APP_GLOBAL=https://egov-dev-assets.s3.ap-south-1.amazonaws.com/globalConfigsWorkbenchHCM.js diff --git a/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-prod b/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-prod deleted file mode 100644 index 2d02707d7eb..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-prod +++ /dev/null @@ -1,7 +0,0 @@ -SKIP_PREFLIGHT_CHECK=true -REACT_APP_USER_TYPE=EMPLOYEE -REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a -REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c -REACT_APP_PROXY_API=https://salama.digit.org -REACT_APP_PROXY_ASSETS=https://salama.digit.org -REACT_APP_GLOBAL=https://moz-health-prd.s3.af-south-1.amazonaws.com/globalConfig.js diff --git a/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-uat b/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-uat deleted file mode 100644 index bedf28a95b1..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/example/.env-mz-uat +++ /dev/null @@ -1,7 +0,0 @@ -SKIP_PREFLIGHT_CHECK=true -REACT_APP_USER_TYPE=EMPLOYEE -REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a -REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c -REACT_APP_PROXY_API=https://moz-health-uat.digit.org -REACT_APP_PROXY_ASSETS=https://moz-health-uat.digit.org -REACT_APP_GLOBAL=https://moz-health-uat.s3.ap-south-1.amazonaws.com/globalConfig.js diff --git a/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev b/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev deleted file mode 100644 index 81fd56e040a..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/example/.env-unifieddev +++ /dev/null @@ -1,9 +0,0 @@ -SKIP_PREFLIGHT_CHECK=true -REACT_APP_USER_TYPE=EMPLOYEE -REACT_APP_EMPLOYEE_TOKEN=c835932f-2ad4-4d05-83d6-49e0b8c59f8a -REACT_APP_CITIZEN_TOKEN=7cd58aae-30b3-41ed-a1b3-3417107a993c -REACT_APP_PROXY_API=https://unified-dev.digit.org -REACT_APP_PROXY_ASSETS=https://unified-dev.digit.org -REACT_APP_GLOBAL=https://egov-dev-assets.s3.ap-south-1.amazonaws.com/globalConfigsMicroplan.js -REACT_APP_CONTEXT=works -WORKBENCH=https://egov-dev-assets.s3.ap-south-1.amazonaws.com/globalConfigsWorkbenchHCMMZ.js \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/example/package.json b/frontend/micro-ui/web/micro-ui-internals/example/package.json deleted file mode 100644 index 2d8c8857b45..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/example/package.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "name": "@egovernments/digit-ui-example", - "version": "1.0.0", - "main": "index.js", - "license": "MIT", - "private": true, - "homepage": "digit-ui", - "scripts": { - "start": "react-scripts start" - }, - "devDependencies": { - "@egovernments/digit-ui-libraries": "1.8.2-beta.1", - "@egovernments/digit-ui-module-workbench": "1.0.2-beta.3", - "@egovernments/digit-ui-components": "0.0.2-beta.1", - "@egovernments/digit-ui-module-core": "1.8.2-beta.2", - "@egovernments/digit-ui-module-utilities": "1.0.1-beta.30", - "@egovernments/digit-ui-react-components": "1.8.2-beta.6", - "@egovernments/digit-ui-module-hcmworkbench":"0.0.38", - "@egovernments/digit-ui-module-campaign-manager": "0.0.1", - "@egovernments/digit-ui-module-hcmmicroplanning": "0.0.1", - "http-proxy-middleware": "^1.0.5", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-i18next": "11.16.2", - "react-router-dom": "5.3.0", - "react-scripts": "^4.0.1" - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} diff --git a/frontend/micro-ui/web/micro-ui-internals/example/public/index.html b/frontend/micro-ui/web/micro-ui-internals/example/public/index.html deleted file mode 100644 index 55ad3b5ca00..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/example/public/index.html +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - DIGIT - - - - - - - - - - - - - - - -
- - diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js b/frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js deleted file mode 100644 index dff584d9ab2..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/example/src/UICustomizations.js +++ /dev/null @@ -1,789 +0,0 @@ -import { Link } from "react-router-dom"; -import _ from "lodash"; -import { useLocation, useHistory } from "react-router-dom"; -import { useParams } from "react-router-dom"; - -//create functions here based on module name set in mdms(eg->SearchProjectConfig) -//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName] -// these functions will act as middlewares -var Digit = window.Digit || {}; - -const businessServiceMap = { - "muster roll": "MR", -}; - -const inboxModuleNameMap = { - "muster-roll-approval": "muster-roll-service", -}; - -function filterUniqueByKey(arr, key) { - const uniqueValues = new Set(); - const result = []; - - arr.forEach((obj) => { - const value = obj[key]; - if (!uniqueValues.has(value)) { - uniqueValues.add(value); - result.push(obj); - } - }); - - return result; -} - -const epochTimeForTomorrow12 = () => { - const now = new Date(); - - // Create a new Date object for tomorrow at 12:00 PM - const tomorrowNoon = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 12, 0, 0, 0); - - // Format the date as "YYYY-MM-DD" - const year = tomorrowNoon.getFullYear(); - const month = String(tomorrowNoon.getMonth() + 1).padStart(2, "0"); // Months are 0-indexed - const day = String(tomorrowNoon.getDate()).padStart(2, "0"); - - return Digit.Utils.date.convertDateToEpoch(`${year}-${month}-${day}`); -}; - -function cleanObject(obj) { - for (const key in obj) { - if (Object.hasOwn(obj, key)) { - if (Array.isArray(obj[key])) { - if (obj[key].length === 0) { - delete obj[key]; - } - } else if ( - obj[key] === undefined || - obj[key] === null || - obj[key] === false || - obj[key] === "" || // Check for empty string - (typeof obj[key] === "object" && Object.keys(obj[key]).length === 0) - ) { - delete obj[key]; - } - } - } - return obj; -} - -export const UICustomizations = { - businessServiceMap, - updatePayload: (applicationDetails, data, action, businessService) => { - if (businessService === businessServiceMap.estimate) { - const workflow = { - comment: data.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - estimate: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap.contract) { - const workflow = { - comment: data?.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - contract: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap?.["muster roll"]) { - const workflow = { - comment: data?.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - musterRoll: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap?.["works.purchase"]) { - const workflow = { - comment: data.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - const additionalFieldsToSet = { - projectId: applicationDetails.additionalDetails.projectId, - invoiceDate: applicationDetails.billDate, - invoiceNumber: applicationDetails.referenceId.split("_")?.[1], - contractNumber: applicationDetails.referenceId.split("_")?.[0], - documents: applicationDetails.additionalDetails.documents, - }; - return { - bill: { ...applicationDetails, ...additionalFieldsToSet }, - workflow, - }; - } - }, - enableModalSubmit: (businessService, action, setModalSubmit, data) => { - if (businessService === businessServiceMap?.["muster roll"] && action.action === "APPROVE") { - setModalSubmit(data?.acceptTerms); - } - }, - enableHrmsSearch: (businessService, action) => { - if (businessService === businessServiceMap.estimate) { - return action.action.includes("TECHNICALSANCTION") || action.action.includes("VERIFYANDFORWARD"); - } - if (businessService === businessServiceMap.contract) { - return action.action.includes("VERIFY_AND_FORWARD"); - } - if (businessService === businessServiceMap?.["muster roll"]) { - return action.action.includes("VERIFY"); - } - if (businessService === businessServiceMap?.["works.purchase"]) { - return action.action.includes("VERIFY_AND_FORWARD"); - } - return false; - }, - getBusinessService: (moduleCode) => { - if (moduleCode?.includes("estimate")) { - return businessServiceMap?.estimate; - } else if (moduleCode?.includes("contract")) { - return businessServiceMap?.contract; - } else if (moduleCode?.includes("muster roll")) { - return businessServiceMap?.["muster roll"]; - } else if (moduleCode?.includes("works.purchase")) { - return businessServiceMap?.["works.purchase"]; - } else if (moduleCode?.includes("works.wages")) { - return businessServiceMap?.["works.wages"]; - } else if (moduleCode?.includes("works.supervision")) { - return businessServiceMap?.["works.supervision"]; - } else { - return businessServiceMap; - } - }, - getInboxModuleName: (moduleCode) => { - if (moduleCode?.includes("estimate")) { - return inboxModuleNameMap?.estimate; - } else if (moduleCode?.includes("contract")) { - return inboxModuleNameMap?.contracts; - } else if (moduleCode?.includes("attendence")) { - return inboxModuleNameMap?.attendencemgmt; - } else { - return inboxModuleNameMap; - } - }, - - AttendanceInboxConfig: { - preProcess: (data) => { - //set tenantId - data.body.inbox.tenantId = Digit.ULBService.getCurrentTenantId(); - data.body.inbox.processSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); - - const musterRollNumber = data?.body?.inbox?.moduleSearchCriteria?.musterRollNumber?.trim(); - if (musterRollNumber) data.body.inbox.moduleSearchCriteria.musterRollNumber = musterRollNumber; - - const attendanceRegisterName = data?.body?.inbox?.moduleSearchCriteria?.attendanceRegisterName?.trim(); - if (attendanceRegisterName) data.body.inbox.moduleSearchCriteria.attendanceRegisterName = attendanceRegisterName; - - // deleting them for now(assignee-> need clarity from pintu,ward-> static for now,not implemented BE side) - const assignee = _.clone(data.body.inbox.moduleSearchCriteria.assignee); - delete data.body.inbox.moduleSearchCriteria.assignee; - if (assignee?.code === "ASSIGNED_TO_ME") { - data.body.inbox.moduleSearchCriteria.assignee = Digit.UserService.getUser().info.uuid; - } - - //cloning locality and workflow states to format them - // let locality = _.clone(data.body.inbox.moduleSearchCriteria.locality ? data.body.inbox.moduleSearchCriteria.locality : []); - - let selectedOrg = _.clone(data.body.inbox.moduleSearchCriteria.orgId ? data.body.inbox.moduleSearchCriteria.orgId : null); - delete data.body.inbox.moduleSearchCriteria.orgId; - if (selectedOrg) { - data.body.inbox.moduleSearchCriteria.orgId = selectedOrg?.[0]?.applicationNumber; - } - - // let selectedWard = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : null); - // delete data.body.inbox.moduleSearchCriteria.ward; - // if(selectedWard) { - // data.body.inbox.moduleSearchCriteria.ward = selectedWard?.[0]?.code; - // } - - let states = _.clone(data.body.inbox.moduleSearchCriteria.state ? data.body.inbox.moduleSearchCriteria.state : []); - let ward = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : []); - // delete data.body.inbox.moduleSearchCriteria.locality; - delete data.body.inbox.moduleSearchCriteria.state; - delete data.body.inbox.moduleSearchCriteria.ward; - - // locality = locality?.map((row) => row?.code); - states = Object.keys(states)?.filter((key) => states[key]); - ward = ward?.map((row) => row?.code); - - // //adding formatted data to these keys - // if (locality.length > 0) data.body.inbox.moduleSearchCriteria.locality = locality; - if (states.length > 0) data.body.inbox.moduleSearchCriteria.status = states; - if (ward.length > 0) data.body.inbox.moduleSearchCriteria.ward = ward; - const projectType = _.clone(data.body.inbox.moduleSearchCriteria.projectType ? data.body.inbox.moduleSearchCriteria.projectType : {}); - if (projectType?.code) data.body.inbox.moduleSearchCriteria.projectType = projectType.code; - - //adding tenantId to moduleSearchCriteria - data.body.inbox.moduleSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); - - //setting limit and offset becoz somehow they are not getting set in muster inbox - data.body.inbox.limit = data.state.tableForm.limit; - data.body.inbox.offset = data.state.tableForm.offset; - delete data.state; - return data; - }, - postProcess: (responseArray, uiConfig) => { - const statusOptions = responseArray?.statusMap - ?.filter((item) => item.applicationstatus) - ?.map((item) => ({ code: item.applicationstatus, i18nKey: `COMMON_MASTERS_${item.applicationstatus}` })); - if (uiConfig?.type === "filter") { - let fieldConfig = uiConfig?.fields?.filter((item) => item.type === "dropdown" && item.populators.name === "musterRollStatus"); - if (fieldConfig.length) { - fieldConfig[0].populators.options = statusOptions; - } - } - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - if (key === "ATM_MUSTER_ROLL_ID") { - return ( - - - {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} - - - ); - } - if (key === "ATM_ATTENDANCE_WEEK") { - const week = `${Digit.DateUtils.ConvertTimestampToDate(value?.startDate, "dd/MM/yyyy")}-${Digit.DateUtils.ConvertTimestampToDate( - value?.endDate, - "dd/MM/yyyy" - )}`; - return
{week}
; - } - if (key === "ATM_NO_OF_INDIVIDUALS") { - return
{value?.length}
; - } - if (key === "ATM_AMOUNT_IN_RS") { - return {value ? Digit.Utils.dss.formatterWithoutRound(value, "number") : t("ES_COMMON_NA")}; - } - if (key === "ATM_SLA") { - return parseInt(value) > 0 ? ( - {t(value) || ""} - ) : ( - {t(value) || ""} - ); - } - if (key === "COMMON_WORKFLOW_STATES") { - return {t(`WF_MUSTOR_${value}`)}; - } - //added this in case we change the key and not updated here , it'll throw that nothing was returned from cell error if that case is not handled here. To prevent that error putting this default - return {t(`CASE_NOT_HANDLED`)}; - }, - MobileDetailsOnClick: (row, tenantId) => { - let link; - Object.keys(row).map((key) => { - if (key === "ATM_MUSTER_ROLL_ID") - link = `/${window.contextPath}/employee/attendencemgmt/view-attendance?tenantId=${tenantId}&musterRollNumber=${row[key]}`; - }); - return link; - }, - populateReqCriteria: () => { - const tenantId = Digit.ULBService.getCurrentTenantId(); - return { - url: "/org-services/organisation/v1/_search", - params: { limit: 50, offset: 0 }, - body: { - SearchCriteria: { - tenantId: tenantId, - functions: { - type: "CBO", - }, - }, - }, - config: { - enabled: true, - select: (data) => { - return data?.organisations; - }, - }, - }; - }, - }, - SearchWageSeekerConfig: { - customValidationCheck: (data) => { - //checking both to and from date are present - const { createdFrom, createdTo } = data; - if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === "")) - return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; - - return false; - }, - preProcess: (data) => { - data.params = { ...data.params, tenantId: Digit.ULBService.getCurrentTenantId() }; - - let requestBody = { ...data.body.Individual }; - const pathConfig = { - name: "name.givenName", - }; - const dateConfig = { - createdFrom: "daystart", - createdTo: "dayend", - }; - const selectConfig = { - wardCode: "wardCode[0].code", - socialCategory: "socialCategory.code", - }; - const textConfig = ["name", "individualId"]; - let Individual = Object.keys(requestBody) - .map((key) => { - if (selectConfig[key]) { - requestBody[key] = _.get(requestBody, selectConfig[key], null); - } else if (typeof requestBody[key] == "object") { - requestBody[key] = requestBody[key]?.code; - } else if (textConfig?.includes(key)) { - requestBody[key] = requestBody[key]?.trim(); - } - return key; - }) - .filter((key) => requestBody[key]) - .reduce((acc, curr) => { - if (pathConfig[curr]) { - _.set(acc, pathConfig[curr], requestBody[curr]); - } else if (dateConfig[curr] && dateConfig[curr]?.includes("day")) { - _.set(acc, curr, Digit.Utils.date.convertDateToEpoch(requestBody[curr], dateConfig[curr])); - } else { - _.set(acc, curr, requestBody[curr]); - } - return acc; - }, {}); - - data.body.Individual = { ...Individual }; - return data; - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - //here we can add multiple conditions - //like if a cell is link then we return link - //first we can identify which column it belongs to then we can return relevant result - switch (key) { - case "MASTERS_WAGESEEKER_ID": - return ( - - - {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} - - - ); - - case "MASTERS_SOCIAL_CATEGORY": - return value ? {String(t(`MASTERS_${value}`))} : t("ES_COMMON_NA"); - - case "CORE_COMMON_PROFILE_CITY": - return value ? {String(t(Digit.Utils.locale.getCityLocale(value)))} : t("ES_COMMON_NA"); - - case "MASTERS_WARD": - return value ? ( - {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} - ) : ( - t("ES_COMMON_NA") - ); - - case "MASTERS_LOCALITY": - return value ? ( - {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} - ) : ( - t("ES_COMMON_NA") - ); - default: - return t("ES_COMMON_NA"); - } - }, - MobileDetailsOnClick: (row, tenantId) => { - let link; - Object.keys(row).map((key) => { - if (key === "MASTERS_WAGESEEKER_ID") - link = `/${window.contextPath}/employee/masters/view-wageseeker?tenantId=${tenantId}&wageseekerId=${row[key]}`; - }); - return link; - }, - additionalValidations: (type, data, keys) => { - if (type === "date") { - return data[keys.start] && data[keys.end] ? () => new Date(data[keys.start]).getTime() <= new Date(data[keys.end]).getTime() : true; - } - }, - }, - SearchDefaultConfig: { - customValidationCheck: (data) => { - //checking both to and from date are present - const { createdFrom, createdTo } = data; - if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === "")) - return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; - - return false; - }, - preProcess: (data) => { - const location = useLocation(); - data.params = { ...data.params }; - const { masterName } = useParams(); - - const searchParams = new URLSearchParams(location.search); - const paths = { - SearchProjectConfig: { - basePath: "Projects", - pathConfig: { - // id: "id[0]", - tenantId: "tenantId", - }, - dateConfig: { - endDate: "dayend", - startDate: "daystart", - }, - selectConfig: {}, - textConfig: ["id", "tenantId", "name", "projectNumber", "projectSubType", "projectType"], - }, - SearchProductConfig: { - basePath: "Product", - pathConfig: { - id: "id[0]", - }, - dateConfig: {}, - selectConfig: {}, - textConfig: ["id", "manufacturer", "name", "type"], - }, - SearchHouseholdConfig: { - basePath: "Household", - pathConfig: { - id: "id[0]", - clientReferenceId: "clientReferenceId[0]", - }, - dateConfig: {}, - selectConfig: {}, - textConfig: ["boundaryCode", "clientReferenceId", "id"], - }, - SearchProductVariantConfig: { - basePath: "ProductVariant", - pathConfig: { - id: "id[0]", - }, - dateConfig: {}, - selectConfig: {}, - textConfig: ["productId", "sku", "variation"], - }, - SearchProjectBeneficiaryConfig: { - basePath: "ProjectBeneficiary", - pathConfig: { - id: "id[0]", - clientReferenceId: "clientReferenceId[0]", - }, - dateConfig: { - dateOfRegistration: "daystart", - }, - selectConfig: {}, - textConfig: ["beneficiaryId", "projectId"], - }, - SearchProjectStaffConfig: { - basePath: "ProjectStaff", - pathConfig: { - id: "id[0]", - }, - dateConfig: { - startDate: "daystart", - endDate: "dayend", - }, - selectConfig: {}, - textConfig: ["projectId", "userId"], - }, - SearchProjectResourceConfig: { - basePath: "ProjectResource", - pathConfig: { - id: "id[0]", - }, - dateConfig: {}, - selectConfig: {}, - textConfig: [], - }, - SearchProjectTaskConfig: { - basePath: "Task", - pathConfig: { - id: "id[0]", - clientReferenceId: "clientReferenceId[0]", - }, - dateConfig: { - plannedEndDate: "dayend", - plannedStartDate: "daystart", - actualEndDate: "dayend", - actualStartDate: "daystart", - }, - selectConfig: {}, - textConfig: ["projectId", "localityCode", "projectBeneficiaryId", "status"], - }, - SearchFacilityConfig: { - basePath: "Facility", - pathConfig: { - id: "id[0]", - }, - dateConfig: {}, - selectConfig: {}, - textConfig: ["faciltyUsage", "localityCode", "storageCapacity", "id"], - }, - SearchProjectFacilityConfig: { - basePath: "ProjectFacility", - pathConfig: { - id: "id[0]", - projectId: "projectId[0]", - facilityId: "facilityId[0]", - }, - dateConfig: {}, - selectConfig: {}, - textConfig: [], - }, - }; - - const id = searchParams.get("config") || masterName; - - if (!paths || !paths?.[id]) { - return data; - } - let requestBody = { ...data.body[paths[id]?.basePath] }; - const pathConfig = paths[id]?.pathConfig; - const dateConfig = paths[id]?.dateConfig; - const selectConfig = paths[id]?.selectConfig; - const textConfig = paths[id]?.textConfig; - - if (paths[id].basePath == "Projects") { - data.state.searchForm = { ...data.state.searchForm, tenantId: "mz" }; - } - let Product = Object.keys(requestBody) - .map((key) => { - if (selectConfig[key]) { - requestBody[key] = _.get(requestBody, selectConfig[key], null); - } else if (typeof requestBody[key] == "object") { - requestBody[key] = requestBody[key]?.code; - } else if (textConfig?.includes(key)) { - requestBody[key] = requestBody[key]?.trim(); - } - return key; - }) - .filter((key) => requestBody[key]) - .reduce((acc, curr) => { - if (pathConfig[curr]) { - _.set(acc, pathConfig[curr], requestBody[curr]); - } else if (dateConfig[curr] && dateConfig[curr]?.includes("day")) { - _.set(acc, curr, Digit.Utils.date.convertDateToEpoch(requestBody[curr], dateConfig[curr])); - } else { - _.set(acc, curr, requestBody[curr]); - } - return acc; - }, {}); - - if (paths[id].basePath == "Projects") { - data.body[paths[id].basePath] = [{ ...Product }]; - } else data.body[paths[id].basePath] = { ...Product }; - return data; - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - //here we can add multiple conditions - //like if a cell is link then we return link - //first we can identify which column it belongs to then we can return relevant result - switch (key) { - case "ID": - return ( - - - - ); - - case "MASTERS_SOCIAL_CATEGORY": - return value ? {String(t(`MASTERS_${value}`))} : t("ES_COMMON_NA"); - - case "CORE_COMMON_PROFILE_CITY": - return value ? {String(t(Digit.Utils.locale.getCityLocale(value)))} : t("ES_COMMON_NA"); - - case "MASTERS_WARD": - return value ? ( - {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} - ) : ( - t("ES_COMMON_NA") - ); - - case "MASTERS_LOCALITY": - return value ? ( - {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} - ) : ( - t("ES_COMMON_NA") - ); - default: - return t("ES_COMMON_NA"); - } - }, - MobileDetailsOnClick: (row, tenantId) => { - let link; - Object.keys(row).map((key) => { - if (key === "MASTERS_WAGESEEKER_ID") - link = `/${window.contextPath}/employee/masters/view-wageseeker?tenantId=${tenantId}&wageseekerId=${row[key]}`; - }); - return link; - }, - additionalValidations: (type, data, keys) => { - if (type === "date") { - return data[keys.start] && data[keys.end] ? () => new Date(data[keys.start]).getTime() <= new Date(data[keys.end]).getTime() : true; - } - }, - }, - SearchCampaign: { - preProcess: (data, additionalDetails) => { - const { campaignName = "", endDate = "", projectType = "", startDate = "" } = data?.state?.searchForm || {}; - data.body.CampaignDetails = {}; - data.body.CampaignDetails.pagination = data?.state?.tableForm; - data.body.CampaignDetails.tenantId = Digit.ULBService.getCurrentTenantId(); - // data.body.CampaignDetails.boundaryCode = boundaryCode; - data.body.CampaignDetails.createdBy = Digit.UserService.getUser().info.uuid; - data.body.CampaignDetails.campaignName = campaignName; - data.body.CampaignDetails.status = ["drafted"]; - if (startDate) { - data.body.CampaignDetails.startDate = Digit.Utils.date.convertDateToEpoch(startDate); - } else { - data.body.CampaignDetails.startDate = epochTimeForTomorrow12(); - } - if (endDate) { - data.body.CampaignDetails.endDate = Digit.Utils.date.convertDateToEpoch(endDate); - } - data.body.CampaignDetails.projectType = projectType?.[0]?.code; - - cleanObject(data.body.CampaignDetails); - - return data; - }, - populateProjectType: () => { - const tenantId = Digit.ULBService.getCurrentTenantId(); - - return { - url: "/egov-mdms-service/v1/_search", - params: { tenantId }, - body: { - MdmsCriteria: { - tenantId, - moduleDetails: [ - { - moduleName: "HCM-PROJECT-TYPES", - masterDetails: [ - { - name: "projectTypes", - }, - ], - }, - ], - }, - }, - changeQueryName: "projectType", - config: { - enabled: true, - select: (data) => { - const dropdownData = filterUniqueByKey(data?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes, "code").map((row) => { - return { - ...row, - i18nKey: Digit.Utils.locale.getTransformedLocale(`CAMPAIGN_TYPE_${row.code}`), - }; - }); - return dropdownData; - }, - }, - }; - }, - customValidationCheck: (data) => { - //checking if both to and from date are present then they should be startDate<=endDate - const { startDate, endDate } = data; - const startDateEpoch = Digit.Utils.date.convertDateToEpoch(startDate); - const endDateEpoch = Digit.Utils.date.convertDateToEpoch(endDate); - - if (startDate && endDate && startDateEpoch > endDateEpoch) { - return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; - } - return false; - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - if (key === "CAMPAIGN_DATE") { - return `${Digit.DateUtils.ConvertEpochToDate(value)} - ${Digit.DateUtils.ConvertEpochToDate(row?.endDate)}`; - } - }, - }, - SearchMicroplan: { - preProcess: (data, additionalDetails) => { - const { name, status } = data?.state?.searchForm || {}; - - data.body.PlanConfigurationSearchCriteria = {}; - data.body.PlanConfigurationSearchCriteria.limit = data?.state?.tableForm?.limit; - // data.body.PlanConfigurationSearchCriteria.limit = 10 - data.body.PlanConfigurationSearchCriteria.offset = data?.state?.tableForm?.offset; - data.body.PlanConfigurationSearchCriteria.name = name; - data.body.PlanConfigurationSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); - data.body.PlanConfigurationSearchCriteria.userUuid = Digit.UserService.getUser().info.uuid; - // delete data.body.PlanConfigurationSearchCriteria.pagination - data.body.PlanConfigurationSearchCriteria.status = status?.status; - cleanObject(data.body.PlanConfigurationSearchCriteria); - return data; - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - if (key === "CAMPAIGN_DATE") { - return `${Digit.DateUtils.ConvertEpochToDate(value)} - ${Digit.DateUtils.ConvertEpochToDate(row?.CampaignDetails?.endDate)}`; - } - }, - }, -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/index.js b/frontend/micro-ui/web/micro-ui-internals/example/src/index.js deleted file mode 100644 index c186da539bd..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/example/src/index.js +++ /dev/null @@ -1,84 +0,0 @@ -import React from "react"; -import ReactDOM from "react-dom"; - -import { initLibraries } from "@egovernments/digit-ui-libraries"; -// import { paymentConfigs, PaymentLinks, PaymentModule } from "@egovernments/digit-ui-module-common"; -import { DigitUI } from "@egovernments/digit-ui-module-core"; -import "@egovernments/digit-ui-css/example/index.css"; - -import { UICustomizations } from "./UICustomizations"; -import { initCampaignComponents } from "@egovernments/digit-ui-module-campaign-manager" -import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench"; -import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities"; -import { initWorkbenchHCMComponents } from "@egovernments/digit-ui-module-hcmworkbench"; -import { initMicroplanningComponents } from "@egovernments/digit-ui-module-hcmmicroplanning"; - -var Digit = window.Digit || {}; - -const enabledModules = [ - "DSS", - "HRMS", - "Workbench", - "HCMWORKBENCH", - "Campaign", - // "Engagement", "NDSS","QuickPayLinks", "Payment", - "Utilities", - "Microplanning" - //added to check fsm - // "FSM" -]; - -const initTokens = (stateCode) => { - const userType = window.sessionStorage.getItem("userType") || process.env.REACT_APP_USER_TYPE || "CITIZEN"; - const token = window.localStorage.getItem("token") || process.env[`REACT_APP_${userType}_TOKEN`]; - - const citizenInfo = window.localStorage.getItem("Citizen.user-info"); - - const citizenTenantId = window.localStorage.getItem("Citizen.tenant-id") || stateCode; - - const employeeInfo = window.localStorage.getItem("Employee.user-info"); - const employeeTenantId = window.localStorage.getItem("Employee.tenant-id"); - - const userTypeInfo = userType === "CITIZEN" || userType === "QACT" ? "citizen" : "employee"; - window.Digit.SessionStorage.set("user_type", userTypeInfo); - window.Digit.SessionStorage.set("userType", userTypeInfo); - - if (userType !== "CITIZEN") { - window.Digit.SessionStorage.set("User", { access_token: token, info: userType !== "CITIZEN" ? JSON.parse(employeeInfo) : citizenInfo }); - } else { - // if (!window.Digit.SessionStorage.get("User")?.extraRoleInfo) window.Digit.SessionStorage.set("User", { access_token: token, info: citizenInfo }); - } - - window.Digit.SessionStorage.set("Citizen.tenantId", citizenTenantId); - - if (employeeTenantId && employeeTenantId.length) window.Digit.SessionStorage.set("Employee.tenantId", employeeTenantId); -}; - -const initDigitUI = () => { - window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH") || "digit-ui"; - window.Digit.Customizations = { - commonUiConfig: UICustomizations - }; - window?.Digit.ComponentRegistryService.setupRegistry({ - // PaymentModule, - // ...paymentConfigs, - // PaymentLinks, - }); - initUtilitiesComponents(); - initWorkbenchComponents(); - initWorkbenchHCMComponents(); - initCampaignComponents(); - initMicroplanningComponents(); - - const moduleReducers = (initData) => initData; - - - const stateCode = window?.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || "pb"; - initTokens(stateCode); - - ReactDOM.render(, document.getElementById("root")); -}; - -initLibraries().then(() => { - initDigitUI(); -}); diff --git a/frontend/micro-ui/web/micro-ui-internals/example/src/setupProxy.js b/frontend/micro-ui/web/micro-ui-internals/example/src/setupProxy.js deleted file mode 100644 index 9fbb1258ba9..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/example/src/setupProxy.js +++ /dev/null @@ -1,101 +0,0 @@ -const { createProxyMiddleware } = require("http-proxy-middleware"); - -const createProxy = createProxyMiddleware({ - //target: process.env.REACT_APP_PROXY_API || "https://uat.digit.org", - // target: process.env.REACT_APP_PROXY_API || "https://qa.digit.org", - target: process.env.REACT_APP_PROXY_API || "https://works-dev.digit.org", - changeOrigin: true, - secure: false, -}); -const assetsProxy = createProxyMiddleware({ - target: process.env.REACT_APP_PROXY_ASSETS || "https://works-dev.digit.org", - changeOrigin: true, - secure: false, -}); -const mdmsProxy = createProxyMiddleware({ - target: process.env.REACT_APP_PROXY_ASSETS || "http://localhost:8080", - changeOrigin: true, - secure: false, -}); -module.exports = function (app) { - ["/mdms-v2/v2/_create"].forEach((location) => app.use(location, mdmsProxy)); - [ - "/access/v1/actions/mdms", - "/egov-mdms-service", - "/mdms-v2", - "/egov-idgen", - "/egov-location", - "/localization", - "/egov-workflow-v2", - "/pgr-services", - "/filestore", - "/egov-hrms", - "/user-otp", - "/user", - "/fsm", - "/billing-service", - "/collection-services", - "/pdf-service", - "/pg-service", - "/vehicle", - "/vendor", - "/property-services", - "/fsm-calculator/v1/billingSlab/_search", - "/pt-calculator-v2", - "/dashboard-analytics", - "/echallan-services", - "/egov-searcher/bill-genie/mcollectbills/_get", - "/egov-searcher/bill-genie/billswithaddranduser/_get", - "/egov-searcher/bill-genie/waterbills/_get", - "/egov-searcher/bill-genie/seweragebills/_get", - "/egov-pdf/download/UC/mcollect-challan", - "/egov-hrms/employees/_count", - "/tl-services/v1/_create", - "/tl-services/v1/_search", - "/egov-url-shortening/shortener", - "/inbox/v1/_search", - "/inbox/v2/_search", - "/tl-services", - "/tl-calculator", - "/org-services", - "/edcr", - "/bpa-services", - "/noc-services", - "/egov-user-event", - "/egov-document-uploader", - "/egov-pdf", - "/egov-survey-services", - "/ws-services", - "/sw-services", - "/ws-calculator", - "/sw-calculator/", - "/egov-searcher", - "/report", - "/inbox/v1/dss/_search", - "/loi-service", - "/project/v1/", - "/estimate-service", - "/loi-service", - "/works-inbox-service/v2/_search", - "/egov-pdf/download/WORKSESTIMATE/estimatepdf", - "/muster-roll", - "/individual", - "/mdms-v2", - "/hcm-moz-impl", - "/project", - "/project/staff/v1/_search", - "/project/v1/_search", - "/facility/v1/_search", - "/product/v1/_search", - "/product/variant/v1/_search", - "/hcm-bff/bulk/_transform", - "/hcm-bff/hcm/_processmicroplan", - "/health-hrms", - "/project-factory", - "/boundary-service", - "/product", - "/plan-service", - ].forEach((location) => app.use(location, createProxy)); - ["/pb-egov-assets"].forEach((location) => app.use(location, assetsProxy)); - ["/mdms-v2/v2/_create"].forEach((location) => app.use(location, mdmsProxy)); -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/package.json b/frontend/micro-ui/web/micro-ui-internals/package.json deleted file mode 100644 index d15c627d3ab..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/package.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "name": "egovernments", - "version": "1.0.0", - "main": "index.js", - "workspaces": [ - "example", - "packages/css", - "packages/modules/*" - ], - "author": "JaganKumar ", - "license": "MIT", - "private": true, - "engines": { - "node": ">=14" - }, - "scripts": { - "start": "SKIP_PREFLIGHT_CHECK=true run-s build start:dev", - "sprint": "SKIP_PREFLIGHT_CHECK=true run-s start:script", - "start:dev": "run-p dev:**", - "start:script": "./scripts/create.sh", - "dev:css": "cd packages/css && yarn start", - "publish:css": "cd packages/css && yarn && npm publish --tag workbench-1.0", - "dev:example": "cd example && yarn start", - "dev:campaign": "cd packages/modules/campaign-manager && yarn start", - "dev:hcmmicroplan": "cd packages/modules/hcm-microplanning && yarn start", - "build": "run-p build:**", - "build:campaign": "cd packages/modules/campaign-manager && yarn build", - "build:hcmmicroplan": "cd packages/modules/hcm-microplanning && yarn build", - "deploy:jenkins": "./scripts/jenkins.sh", - "clean": "rm -rf node_modules" - }, - "resolutions": { - "**/@babel/runtime": "7.20.1", - "**/babel-preset-react-app": "10.0.0" - }, - "devDependencies": { - "husky": "7.0.4", - "lint-staged": "12.3.7", - "npm-run-all": "4.1.5", - "prettier": "2.1.2" - }, - "husky": {}, - "lint-staged": { - "*.{js,css,md}": "prettier --write" - }, - "dependencies": { - "ajv": "8.12.0", - "lodash": "4.17.21", - "microbundle-crl": "0.13.11", - "@egovernments/digit-ui-react-components": "1.8.2-beta.6", - "@egovernments/digit-ui-components": "0.0.2-beta.1", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "react-router-dom": "5.3.0" - } -} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/README.md b/frontend/micro-ui/web/micro-ui-internals/packages/css/README.md deleted file mode 100644 index 6efe08ae5c5..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/README.md +++ /dev/null @@ -1,62 +0,0 @@ - - -# digit-ui-css - -## Install - -```bash -npm install --save @egovernments/digit-ui-css -``` - -## Limitation - -```bash -This Package is more specific to DIGIT-UI's can be used across mission's -It is the base css for all Digit UI's -``` - -## Usage - -After adding the dependency make sure you have this dependency in - -```bash -frontend/micro-ui/web/package.json -``` - -```json -"@egovernments/digit-ui-css":"^1.5.0", -``` - -then navigate to App.js - -```bash -frontend/micro-ui/web/public/index.html -``` - -```jsx -/** add this import **/ - - - -``` -### Changelog - -```bash -1.0.7-campaign some css fixes in attribute -1.0.5-campaign some css fixes in previous button -1.0.4-campaign updated styling for create campaign screens -1.0.2-campaign update Styling added for delivery rule screen -1.0.1-campaign Styling added for delivery rule screen -1.0.0-campaign Base version - -``` -## Contributors - -[jagankumar-egov] [nipunarora-eGov] - -### Published from DIGIT Frontend -DIGIT Frontend Repo (https://github.com/egovernments/Digit-Frontend/tree/develop) - -## License - -MIT © [jagankumar-egov](https://github.com/jagankumar-egov) diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/gulpfile.js b/frontend/micro-ui/web/micro-ui-internals/packages/css/gulpfile.js deleted file mode 100644 index 5d1a705494a..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/gulpfile.js +++ /dev/null @@ -1,71 +0,0 @@ -const fs = require("fs"); -const { name, version, author, cssConfig } = JSON.parse(fs.readFileSync("package.json")); - -const headerString = ` -@charset "UTF-8"; -/*! - * ${name} - ${version} - * - * Copyright (c) ${new Date().getFullYear()} ${author} - * - */ - `; -const { series, src, dest, watch, task } = require("gulp"); -const header = require("postcss-header"); - -const clean = require("gulp-clean"); -const postcss = require("gulp-postcss"); -const sass = require('gulp-sass'); - -const postcssPresetEnv = require("postcss-preset-env"); -const cleanCSS = require("gulp-clean-css"); -const rename = require("gulp-rename"); -const livereload = require("gulp-livereload"); - -let output = "./example"; -if (process.env.NODE_ENV === "production") { - output = "./dist"; -} - -function cleanStyles() { - return src(`${output}/*.css`, { read: false }).pipe(clean()); -} - -function styles() { - const plugins = [ - require("postcss-import"), - require("tailwindcss"), - postcssPresetEnv({ stage: 2, autoprefixer: { cascade: false }, features: { "custom-properties": true } }), - require("autoprefixer"), - require("cssnano"), - header({ header: headerString }), - ]; - return src("src/index.scss").pipe(postcss(plugins)).pipe(sass()).pipe(dest(output)); -} - -function minify() { - return src(`${output}/index.css`).pipe(cleanCSS()).pipe(rename(`index.min.css`)).pipe(dest(output)); -} - -function stylesLive() { - styles().pipe(livereload({ start: true })); -} - -function livereloadStyles() { - livereload.listen(); - watch("src/**/*.scss", series(stylesLive)); -} - -exports.styles = styles; -exports.default = series(styles); -exports.watch = livereloadStyles; -if (process.env.NODE_ENV === "production") { - exports.build = series(cleanStyles, styles, minify); -} else { - exports.build = series(styles, livereloadStyles); -} - -// gulp.task("watch:styles", function () { -// livereload.listen(); -// gulp.watch("**/*.scss", ["styles"]); -// }); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json b/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json deleted file mode 100644 index 5f503a9ebf5..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/package.json +++ /dev/null @@ -1,65 +0,0 @@ -{ - "name": "@egovernments/digit-ui-css", - "version": "1.0.56-campaign", - "license": "MIT", - "main": "dist/index.css", - "author": "Jagankumar ", - "engines": { - "node": ">=14" - }, - "cssConfig": { - "prefix": "" - }, - "scripts": { - "start": "gulp build", - "build:prod": "NODE_ENV=production gulp build", - "prepublish": "yarn build:prod", - "deploy": "gulp && cp -R svg example && cp -R img example && gh-pages -d example" - }, - "browserslist": [ - "> 3%", - "last 2 versions" - ], - "style": "./dist/index.css", - "dependencies": { - "node-sass": "4.14.1", - "normalize.css": "8.0.1", - "postcss-scss": "3.0.5", - "tailwindcss": "1.9.6" - }, - "devDependencies": { - "autoprefixer": "10.4.14", - "cssnano": "4.1.11", - "gh-pages": "3.2.3", - "gulp": "4.0.2", - "gulp-clean": "0.4.0", - "gulp-clean-css": "4.3.0", - "gulp-livereload": "4.0.2", - "gulp-postcss": "9.0.1", - "gulp-rename": "2.0.0", - "gulp-sass": "4.1.1", - "postcss": "8.4.26", - "postcss-cli": "8.3.1", - "postcss-header": "2.0.0", - "postcss-import": "12.0.1", - "postcss-prefixer": "2.1.3", - "postcss-preset-env": "6.7.1", - "postcss-scss": "3.0.5", - "sass": "^1.26.11" - }, - "files": [ - "dist/index.min.css", - "dist/index.css", - "svg/**/*.svg", - "img/**/*.png", - "src/**/*.scss", - "src/**/*.css" - ], - "keywords": [ - "digit", - "egov", - "dpg", - "digit-ui", - "css" - ] -} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/postcss.config.js b/frontend/micro-ui/web/micro-ui-internals/packages/css/postcss.config.js deleted file mode 100644 index 18485de221e..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/postcss.config.js +++ /dev/null @@ -1,55 +0,0 @@ -const postcssPresetEnv = require("postcss-preset-env"); - -module.exports = { - parser: require("postcss-scss"), - plugins: [ - require("postcss-import"), - require("postcss-nested").default, - require("tailwindcss"), - require("postcss-preset-env"), - require("autoprefixer"), - // require("cssnano"), - ], -}; - -// const fs = require('fs'); -// const { name, version, author, cssConfig } = JSON.parse(fs.readFileSync('package.json')); - -// const header = ` -// @charset "UTF-8"; -// /*! -// * ${name} - ${version} -// * -// * Copyright (c) ${new Date().getFullYear()} ${author.name} -// */ -// `; - -// module.exports = (ctx) => { -// const prefix = ctx.env === 'compat' ? '' : cssConfig.prefix; -// const devMessage = `🎉🎉🎉🎉 \n${name} ${ctx.env} build was compiled sucessfully! \n`; - - -// return { -// map: ctx.options.map, -// parser: ctx.options.parser, -// plugins: { -// 'postcss-import': { root: ctx.file.dirname }, -// 'postcss-prefixer': { -// prefix, -// ignore: [/\[class\*=.*\]/], -// }, -// 'postcss-preset-env': { -// autoprefixer: { -// cascade: false, -// }, -// features: { -// 'custom-properties': true, -// }, -// }, -// cssnano: ctx.env === 'production' || ctx.env === 'compat' ? {} : false, -// 'postcss-header': { -// header, -// }, -// }, -// }; -// }; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss deleted file mode 100644 index f01756f1e7d..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/components/microplanning.scss +++ /dev/null @@ -1,363 +0,0 @@ -.microplanning { - .upload { - display: flex; - width: 100%; - justify-content: space-between; - margin-top: 1.25rem; - } - - .upload-section-option { - width: 12.5rem; - min-height: 32rem; - background-color: #ffffff; - border-top-left-radius: 0.5rem; - border-bottom-left-radius: 0.5rem; - padding: 0.625rem; - box-shadow: 0px 1px 2px 0px #00000029; - } - - .upload-section-options-active { - min-height: 3.7rem; - display: flex; - align-items: center; - border-bottom: 1px rgba(214, 213, 212, 1) solid; - cursor: pointer; - border-right: 0.3rem solid rgba(244, 119, 56, 1); - background-color: rgba(244, 119, 56, 0.12); - - p { - color: rgba(80, 90, 95, 1); - font-weight: 400; - font-size: 16px; - } - } - - .upload-section-options-inactive { - min-height: 3.7rem; - display: flex; - align-items: center; - border-bottom: 1px rgba(214, 213, 212, 1) solid; - cursor: pointer; - border-right: none; - background-color: rgba(255, 255, 255, 1); - - p { - color: rgba(80, 90, 95, 1); - font-weight: 400; - font-size: 16px; - } - } - - .upload-component { - width: 80%; - height: min-content; - border-radius: 0.25rem; - padding: 1.5rem; - background-color: rgba(255, 255, 255, 1); - margin: 0; - margin-right: 0.3rem; - padding-bottom: 0.625rem; - } - - .upload-component-active { - display: flex; - flex-direction: column; - margin-bottom: 0; - - .greyedout-name { - color: rgba(177, 180, 182, 1); - margin: 0 0.625rem; - font-size: 1.25rem; - padding-top: 0px; - font-weight: 500; - } - - h2 { - margin-top: 0.625rem; - font-size: 2.5rem; - margin: 0.625rem 0; - font-weight: 700; - } - - p { - margin: 0.625rem 0; - padding-top: 0.625; - font-size: 1rem; - margin-top: 0.625rem; - font-weight: 400; - } - } - - .upload-component-inactive { - display: none; - } - - .upload-option-container { - display: flex; - align-items: center; - justify-content: center; - padding: 1.25rem 0; - flex-wrap: wrap; - - .upload-option-container-selected { - border: 2px rgba(244, 119, 56, 1) solid; - color: rgba(244, 119, 56, 1); - } - } - - .upload-option { - border-radius: 0.25rem; - border: 0.0625rem rgba(214, 213, 212, 1) solid; - min-width: 12.5rem; - min-height: 8.75rem; - box-shadow: 0 0.0625rem rgba(0, 0, 0, 0.16); - padding: 0.625rem 0; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - justify-items: center; - margin: 0 1.25rem; - cursor: pointer; - - &:hover { - border: 2px rgba(244, 119, 56, 1) solid; - } - - p { - margin-top: 0.625rem; - } - - .upload-option-selected { - border: 0.125rem rgba(244, 119, 56, 1) solid; - color: rgba(244, 119, 56, 1); - } - - .select-button { - justify-self: end; - border: 1px solid rgba(244, 119, 56, 1); - background-color: rgba(255, 255, 255, 1); - width: 11rem; - height: 2.5rem; - padding: 0.6rem 0.5rem; - color: rgba(244, 119, 56, 1); - font-size: 1rem; - font-weight: 600; - } - - .selected-button { - justify-self: end; - border: 1px solid rgba(244, 119, 56, 1); - background-color: rgba(244, 119, 56, 1); - width: 11rem; - height: 2.5rem; - padding: 0.6rem 0.5rem; - color: rgb(255, 255, 255); - font-size: 1rem; - font-weight: 600; - } - } - - .modal-header { - width: 30rem; - font-weight: 700; - font-size: 1.5rem; - padding-left: 1rem; - margin-bottom: 0; - display: flex; - flex-wrap: wrap; - overflow: hidden; - } - - .modal-body { - overflow: hidden; - padding-left: 1rem; - padding-right: 1rem; - margin-bottom: 1rem; - margin-right: 1rem; - - p { - font-weight: 400; - font-size: 1rem; - } - } - - .upload-file { - min-width: 90%; - min-height: 10rem; - padding-top: 0.625; - border: 1px rgba(214, 213, 212, 1) dotted; - margin: 1rem 0; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - background-color: rgba(250, 250, 250, 255); - } - - .uploaded-file { - border: 1px solid rgba(214, 213, 212, 1); - min-height: 4.75rem; - background-color: rgb(256, 252, 252); - display: flex !important; - flex-direction: row; - justify-content: space-between; - align-items: center; - margin-top: 0.625rem; - padding: 0 0.625rem; - flex-wrap: wrap; - - .uploaded-file-details { - display: flex; - flex-direction: row; - align-items: center; - flex-wrap: wrap; - padding: 1rem 0; - - p { - padding: 0; - margin: 0; - height: min-content; - font-weight: 700; - font-size: 1.5rem; - color: rgba(80, 90, 95, 1); - text-align: start; - } - } - - .uploaded-file-operations { - display: flex !important; - flex-direction: row; - align-items: center; - justify-items: end; - flex-wrap: wrap; - .button { - display: flex !important; - flex-direction: row; - align-items: center !important; - justify-content: center; - margin-left: 1rem; - min-width: 9rem; - height: 2.5rem; - border: 1px rgba(244, 119, 56, 1) solid; - background-color: white; - cursor: pointer; - } - - p { - padding: 0; - margin: 0; - color: rgba(244, 119, 56, 1); - font-weight: 600; - font-size: 1rem; - } - - .deletebutton { - background-color: rgb(255, 255, 255, 0); - border: none; - } - } - } - - .loader-container { - display: flex; - justify-content: center; - align-items: center; - height: 100%; - width: 100%; - display: flex; - flex-direction: column; - background-color: rgba(0, 0, 0, 0.7); - position: fixed; - top: 0; - left: 0; - z-index: 99999; - - .loader { - border: 0.5rem solid rgb(255, 255, 255); - border-top: 0.5rem solid rgba(80, 76, 76, 0); - border-radius: 50%; - width: 3.125rem; - height: 3.125rem; - animation: spin 2s linear infinite; - } - - .loader-inner { - border: 1px solid rgb(255, 255, 255); - border-radius: 50%; - width: 100%; - height: 100%; - } - - .loader-text { - color: whitesmoke; - padding-top: 1.25rem; - } - } - - @keyframes spin { - 0% { - transform: rotate(0deg); - } - - 100% { - transform: rotate(360deg); - } - } - - .toast-container { - position: fixed; - width: 50%; - bottom: 1.25rem; - left: 50%; - transform: translateX(-50%); - color: #fff; - padding: 1rem; - z-index: 9999; - } - - .success { - background-color: rgba(0, 112, 60, 1); - } - - .toast-content { - display: flex; - align-items: center; - justify-content: space-between; - } - - .message { - margin-right: 0.6px; - } - - .close-button { - background: transparent; - border: none; - color: inherit; - cursor: pointer; - } - - .altrady-have-template-button { - display: flex !important; - justify-content: center; - font-weight: 600; - font-size: 1rem; - } - - .download-template-button { - display: flex !important; - justify-content: center; - - .icon { - display: flex; - align-items: center; - margin: 0; - padding: 0; - } - - p { - font-weight: 500; - font-size: 1rem; - } - } -} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/index.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/index.scss deleted file mode 100644 index ff5ace2af3e..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/index.scss +++ /dev/null @@ -1,13 +0,0 @@ -/*@import 'normalize.css';*/ - -/*@import url("https://fonts.googleapis.com/css2?family=Roboto+Condensed:wght@400;500;700&family=Roboto:wght@400;500;700&display=swap");*/ - -@import "tailwindcss/base"; - -@import "tailwindcss/components"; - -@import "tailwindcss/utilities"; - -@import "./components/microplanning.scss"; -@import "./pages/employee/index.scss"; -@import "./pages/employee/campaign.scss"; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss deleted file mode 100644 index 5c6b56289d3..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaign.scss +++ /dev/null @@ -1,109 +0,0 @@ -@import url("../../index.scss"); -@import "../../typography.scss"; - -.summary-header { - @extend .typography.text-heading-l; - font-size: 2.25rem; -} -.date-field-container { - display: grid; - grid-template-columns: 20rem 20rem; - grid-gap: 1.5rem; - width: 70%; - padding-top: 0.3rem; - margin-top: 0rem; -} -.date-field { - display: grid; - grid-template-columns: 1fr 2fr; - align-items: start; -} -.campaign-type { - margin-right: 5rem; - padding-bottom: 1.2rem; - font-weight: bold; -} -.name-container { - margin-right: 4rem; - font-weight: bold; - text-wrap: nowrap; -} -.beneficiary-type { - margin-right: 5.4rem; - font-weight: bold; -} -.campaign-dates { - display: flex; - font-weight: bold; -} -.mandatory-date { - margin-top: 0.8rem; - margin-left: 0.5rem; - color: red !important; - font-size: 1rem; - font-weight: 700; -} -.description-type { - margin-top: 2rem; - margin-bottom: 2rem; -} -.name-description { - margin-top: 2rem; - margin-bottom: 2rem; -} -.dates-description { - margin-top: 1rem; - margin-bottom: 1rem; - padding-bottom: 1.2rem; -} -.selecting-boundary-div { - padding-top: 0.5rem; - .label-field-pair { - margin-bottom: 1.5rem; - } -} -.campaign-table { - border-collapse: collapse; - border-color: transparent; - border-width: 0rem 1.5rem; - tbody { - tr:hover { - background: rgba(#f47738, 0.12); - } - } -} -.info-points { - display: flex; - gap: 0.5rem; - margin-bottom: 0.5rem; -} -.infoClass{ - margin-bottom: 1.5rem -} -.headerWrapperClassName{ - display: none -} -.popup-close-svg{ - display: none; -} -.whoLogo{ - margin-top: -1rem; - margin-bottom: -1rem; -} - -.digit-popup-wrapper{ - &.popUpClass{ - width:45rem; - - .popUpFooter{ - .digit-popup-footer-buttons{ - margin-left: 0px; - width: 100%; - - button{ - flex:1; - } - } - } - } -} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss deleted file mode 100644 index 74296abb568..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/campaignCycle.scss +++ /dev/null @@ -1,331 +0,0 @@ -@import "../../typography.scss"; - -.campaign-cycle-container { - .campaign-tabs-container { - } - .sub-tab-container { - margin-top: 5px; - padding: 1.5rem; - .card-text { - margin-bottom: 0; - } - } - .add-resource-container { - background-color: #fafafa; - border: 1px solid #d6d5d4; - border-radius: 0.4rem; - padding: 1rem; - margin-right: 1.5rem; - margin-bottom: 1.5rem; - .card-text { - margin: 0; - font-weight: 700; - } - .header-container { - display: flex; - align-items: flex-end; - justify-content: space-between; - } - } - .delete-resource-icon { - cursor: pointer; - font-weight: 600; - font-size: 1rem; - color: theme(digitv2.lightTheme.primary); - display: flex; - gap: 0.5rem; - align-items: center; - } - .add-resource-label-field-container { - display: grid; - grid-template-columns: 2fr 1fr; - grid-gap: 2rem; - .options-card { - max-height: 10rem !important; - } - } - .popup-wrap { - .popup-module-main { - max-height: 707px; - overflow-y: auto; - width: 99%; - &::-webkit-scrollbar { - width: 0.5rem; - background: transparent; - } - &::-webkit-scrollbar-thumb { - background: #d6d5d4; /* Color of the scrollbar thumb */ - border-radius: 5px; /* Adjust the border-radius for rounded corners */ - height: 0.5rem; - } - } - .popup-module-action-bar { - .selector-button-primary { - padding: 0.6rem 2.5rem; - height: unset; - margin: 1.5rem; - background-color: theme(digitv2.lightTheme.primary); - } - } - } -} -.selector-button-primary { - background-color: theme(digitv2.lightTheme.primary); -} -.campaign-breadcrumb { - margin: 0; - margin-bottom: 1.5rem; - color: theme(digitv2.lightTheme.primary) !important; -} -.sc-jlZhew.dVtbRz { - overflow: hidden; -} -.campaign-popup-module { - margin: auto; - width: calc(100% - 5rem); -} -.campaign-bulk-upload { - display: flex; - justify-content: space-between; - margin-bottom: 1.5rem; - .campaign-download-template-btn { - font-weight: 700; - } -} -.bulk-info-text { - margin-bottom: 1.5rem; -} -.delete-and-download-button { - display: flex; - gap: 1.5rem; -} -.bulk-upload-file { - .uploaded-file-container { - margin: 0; - margin-bottom: 1.5rem; - } -} -.uploaded-file-container { - margin-left: 0rem; -} -.upload-drag-drop-container { - background-color: #fafafa; - border: 1.5px dashed #d6d5d4; - border-radius: 5px; - padding: 1rem 1rem 1rem 1rem; - display: flex; - align-items: center; - flex-direction: column; - - .drag-drop-text { - text-decoration: none; - - .browse-text { - text-decoration: none; - color: theme(digitv2.lightTheme.primary); - transition: color 0.3s; - } - - .browse-text:hover { - color: theme(digitv2.lightTheme.primary); - text-decoration: underline; - cursor: pointer; - } - } -} - -.upload-drag-drop-container { - margin-left: 0rem; - .drag-drop { - color: #b1b4b6; - } - .browse-text { - text-decoration: underline; - color: theme(digitv2.lightTheme.primary); - transition: color 0.3s; - } -} - -.campaign-counter-container { - padding: 1.5rem; - padding-bottom: 0.5rem; - .card-text { - margin-top: 0; - } - .label-field-pair { - margin-bottom: 1rem; - .card-label { - font-weight: 700; - } - } - .date-field-container { - display: grid; - grid-template-columns: 18.75rem 18.75rem; - grid-gap: 1.5rem; - width: 100%; - } - .PlusMinus { - width: 30%; - input { - width: 100%; - } - } -} - -.campaign-tab-head { - padding: 1rem; - width: 12.5rem; - height: 3rem; - border-radius: 10px 10px 0px 0px; - background-color: #ffffff; - outline: none; - box-sizing: border-box; - font-weight: 700; - font-size: 1rem; - font-family: "Roboto"; - color: #505a5f; - margin-bottom: -6px; - border: 1px solid #d6d5d4; - background-color: #fafafa; - &.active { - height: 3.375rem; - background-color: #ffffff; - outline: none; - font-weight: bold; - color: theme(digitv2.lightTheme.primary); - border: 1px solid theme(digitv2.lightTheme.primary); - border-bottom: 4px solid theme(digitv2.lightTheme.primary); - box-sizing: border-box; - font-size: 1.5rem; - } - :focus { - outline: none; - } -} -.campaign-sub-tab-head { - outline: none; - background-color: #ffffff; - color: theme(digitv2.lightTheme.primary); - border: 1px solid theme(digitv2.lightTheme.primary); - height: 2rem; - width: 9.188rem; - font-size: 1rem; - font-weight: 400; - &.active { - background-color: theme(digitv2.lightTheme.primary); - color: #ffffff; - font-weight: bold; - outline: none; - height: 2rem; - width: 9.188rem; - font-family: "Roboto"; - font-weight: 700; - font-size: 1rem; - } -} -.tab-content-header { - margin-top: 1.5rem; - margin-bottom: 1.5rem !important; -} - -.delivery-rule-container { - padding-top: 0; - .card-header { - .title { - margin: 0 !important; - } - font-size: 1.5rem !important; - margin: 0; - display: flex; - align-content: center; - justify-content: space-between; - } - .attribute-container { - border: 1px solid #d6d5d4; - background-color: #fafafa; - padding: 1rem; - padding-top: 0; - .add-attribute { - width: 74.5%; - justify-content: center; - h2 { - font-size: 1rem; - font-family: Roboto; - width: unset !important; - font-weight: 600; - } - } - } -} -.attribute-field-wrapper { - display: grid; - grid-template-columns: 1fr 1fr 1fr 1fr; - align-items: center; - gap: 2.5rem; - .label-field-pair { - flex-direction: column; - align-items: flex-start !important; - .card-label.card-label-smaller { - font-weight: 700; - } - .employee-select-wrap.form-field { - width: 100%; - } - .digit-employee-card-input { - margin-bottom: 0; - } - } - .options-card { - max-height: 10rem !important; - } - .card-label { - margin-bottom: 0.5rem; - } -} -.add-rule-btn { - margin: auto; - h2 { - font-family: Roboto; - font-size: 1rem; - font-weight: 600; - } -} -.add-product-btn { - h2 { - font-family: Roboto; - font-size: 1rem; - font-weight: 600; - } -} -.popup-wrap.campaign-product-wrapper { - .popup-module { - width: 70%; - padding-left: 1.5rem; - padding-bottom: 1.5rem; - .header-wrap { - font-size: 1.5rem; - font-weight: 700; - .header-content.popup-header-fix { - margin-top: 1.5rem; - } - } - } - .popup-module-action-bar { - margin-top: 1.5rem; - margin-right: 1.5rem; - } -} -.search-button-wrapper { - grid-column-end: -1 !important; - flex-direction: row !important; -} -.add-resource-modal { -} -.add-resource-wrapper { - .link { - color: theme(digitv2.lightTheme.primary); - } -} -.digit-toast-success { - margin-bottom: -0.5rem; -} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss deleted file mode 100644 index 295d90c1264..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/coreOverride.scss +++ /dev/null @@ -1,173 +0,0 @@ -@import "../../typography.scss"; - -/* language selection issue*/ -.customBtn-selected { - background-color: theme(digitv2.lightTheme.primary); -} - -/* login screen issue*/ - -.primary-label-btn { - color: theme(digitv2.lightTheme.primary); -} - -/* landing screen issue*/ - -.employeeCard { - .complaint-links-container .header .logo { - background-color: theme(digitv2.lightTheme.primary); - } - - .complaint-links-container .body { - &.link { - color: theme(digitv2.lightTheme.primary); - } - .inbox-total { - background-color: theme(digitv2.lightTheme.primary); - } - } -} - -.employee .topbar .right .user-img-txt { - background-color: theme(digitv2.lightTheme.primary); -} -/* button component issue*/ - -.action-bar-wrap { - .submit-bar { - background-color: theme(digitv2.lightTheme.primary); - } -} - -.jk-digit-secondary-btn { - color: theme(digitv2.lightTheme.primary); - border-color: theme(digitv2.lightTheme.primary); - - svg { - fill: theme(digitv2.lightTheme.primary); - - path { - fill: theme(digitv2.lightTheme.primary); - } - } -} -.error-boundary .error-container button { - background-color: theme(digitv2.lightTheme.primary); -} - -/* inbox screen issue*/ - -.inbox-search-wrapper { - .search-tabs-container .search-tab-head-selected { - color: theme(digitv2.lightTheme.primary); - border-color: theme(digitv2.lightTheme.primary); - } - .submit-bar { - background-color: theme(digitv2.lightTheme.primary); - } - .search-component-table .link { - color: theme(digitv2.lightTheme.primary); - } - .link-label { - color: theme(digitv2.lightTheme.primary) !important; - } -} -.drag-drop-container .drag-drop-text .browse-text { - color: theme(digitv2.lightTheme.primary); -} -/* toast new componnet css added */ - -.toast-success { - gap: 0.5rem; - height: 3rem; - padding: 0.75rem 0.5rem 0.75rem 0.75rem !important; - background-color: theme(digitv2.alert.success); - transition: bottom 0.5s ease; - grid-gap: 0.5rem; - &.error { - background-color: theme(digitv2.alert.error) !important; - } - - &.warning { - background-color: #f19100; - - &.warning-buttons { - @apply block; - } - } - - h2 { - @apply text-left overflow-hidden whitespace-no-wrap flex-grow flex items-center h-6; - letter-spacing: 0rem; - color: theme(digitv2.lightTheme.paper); - margin: 0rem; - text-overflow: ellipsis; - font-family: Roboto; - font-weight: 500; - font-size: 1.25rem; - font-style: normal; - } - svg { - @apply flex-shrink-0; - } -} - -@keyframes slideInFromBottom { - from { - bottom: -3rem; - } - to { - bottom: 4rem; - } -} - -.toast-success.animate { - animation: slideInFromBottom 0.5s ease forwards; -} - -@media screen and (max-width: 768px) { - .topbar { - background: #0b4b66 !important; - color: #fff; - } -} -header { - @extend .typography.text-heading-xl; -} -.digit-button-primary{ - background-color: theme(digitv2.lightTheme.primary) !important; -} -.digit-button-secondary{ - .icon-label-container{ - h2{ - color: theme(digitv2.lightTheme.primary) !important; - } - } -} - -/*.digit-popup-wrap { - background: rgba(0, 0, 0, 0.7); - @apply flex fixed w-full h-full overflow-auto top-0 left-0 min-h-screen; - z-index: 10000; - max-width: 100% !important; - max-height: 100% !important; -} - -@screen dt { - .digit-popup-wrap { - background: rgba(0, 0, 0, 0.7); - @apply min-h-screen; - } -} - -.digit-popup-close-icon { - @apply flex justify-end; -}*/ - -.employee{ - .digit-employeeSidebar{ - .sidebar{ - z-index:999 - } - } -} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss deleted file mode 100644 index 2b989e87305..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/pages/employee/index.scss +++ /dev/null @@ -1,481 +0,0 @@ -@import "./campaignCycle.scss"; -@import "./coreOverride.scss"; -@import "../../typography.scss"; - -.wbh-header-container { - margin-top: 1.5rem; -} -.main.digit-home-main { - margin-left: 92px; - .employee-app-wrapper.digit-home-app-wrapper { - margin-left: 0; - margin-right: 2rem; - .ground-container.digit-home-ground { - padding: 0; - .employee-app-container.digit-home-employee-app { - .ground-container.moduleCardWrapper.gridModuleWrapper.digit-home-moduleCardWrapper { - gap: 2.5rem; - margin-top: 2rem; - padding: 0; - display: grid !important; - grid-template-columns: repeat(auto-fill, minmax(263px, 1fr)); - .employeeCard.customEmployeeCard.card-home.home-action-cards { - margin: 0 !important; - min-width: 263px !important; - width: auto !important; - } - } - } - } - } -} -.campaign-cycle-container { - .popup-header-fix { - margin-top: 1.5rem !important; - } -} - -.tag.inbox-tag { - max-width: fit-content; - background-color: #d6d5d4; - border-radius: 2rem; - padding: 0.5rem; - display: flex; - align-items: center; - height: 2rem; - margin-bottom: 0.7rem; - grid-gap: 0.2rem; - gap: 0.2rem; -} -.mandatory-span { - margin-left: 0.5rem; - color: red !important; - font-size: 1rem; - font-weight: 700; -} - -.digit-employee-card-input.numeric { - margin-bottom: unset; -} - -.actionBarClass { - display: flex; - justify-content: space-between; - flex-direction: row-reverse; - z-index: 0; -} -.previous-button { - margin-left: 4rem; - min-width: 12.5rem; -} -.info-text { - padding-bottom: 1.5rem; -} - -.view-composer-header-section { - display: flex; - justify-content: space-between; - align-items: baseline; -} -.card-with-background { - margin-top: 1rem; - .card-head { - margin-bottom: 1rem; - color: #505a5f; - } -} -.no-data-found { - display: flex; - flex-direction: column; - align-items: center; - .error-msg { - margin-top: 1rem; - } -} -.search-tab-head { - color: #505a5f; -} -.search-tabs-container { - border-bottom: none; - margin-bottom: 0; -} -.delivery-preview-card { - margin-bottom: 1.5rem !important; - background-color: #fafafa; - border: 1px solid #d6d5d4; - width: 70%; - .custom-table-label { - font-size: 1.5rem; - font-weight: 700; - color: #505a5f; - margin-bottom: 1rem; - } - .campaign-attribute-table { - margin-bottom: 1rem; - border: 1px solid #d6d5d4; - overflow: hidden; - border-radius: 4px; - table { - border-width: 0px !important; - background-color: #fafafa; - border: 1px solid #d6d5d4; - border-collapse: collapse; - border-radius: 1rem; - tbody { - tr:nth-child(odd) { - background-color: white; - } - } - th { - border-right: 1px solid #d6d5d4; - } - th:last-child { - border-right: none; - } - td { - padding: 1rem; - border-right: 1px solid #d6d5d4; - } - td:last-child { - padding: 1rem; - border-right: none; - } - } - } - .campaign-product-table { - margin-bottom: 1rem; - border: 1px solid #d6d5d4; - overflow: hidden; - border-radius: 4px; - table { - background-color: #fafafa; - border: 1px solid #d6d5d4; - border-collapse: collapse; - border-radius: 1rem; - border-width: 0px !important; - tbody { - background-color: #fff; - tr:nth-child(odd) { - background-color: white; - } - } - th { - border-right: 1px solid #d6d5d4; - } - th:last-child { - border-right: none; - } - td { - padding: 1rem; - border-right: 1px solid #d6d5d4; - } - td:last-child { - border-right: none; - } - } - } -} -.cycle-paragraph { - font-weight: 700; - font-size: 24px; - color: #505a5f; - margin-top: 0.5rem; -} -.header-end { - margin-right: 1rem; -} -.digit-stepper-container { - margin-bottom: 1.5rem; -} -.employee-app-wrapper { - margin: 0rem 1rem; -} -input[type="date"]::-webkit-calendar-picker-indicator { - position: absolute; - right: 5px; - top: 20%; - transform: translateY(-10%); -} -.campaign-preview-edit-container { - display: flex; - gap: 1rem; - span { - color: theme(digitv2.lightTheme.primary); - } -} -.campaign-attribute-table { - border: 1px solid #d6d5d4; - overflow: hidden; - border-radius: 4px; - tbody { - tr:nth-child(odd) { - background-color: white; - } - } -} -tbody { - tr:nth-child(odd) { - background-color: white; - } -} -.popup-wrap.campaign-data-preview { - flex-direction: column; -} - -.digit-employee-card-input.numeric { - pointer-events: none; -} -.product-tag-container { - display: flex; - flex-wrap: wrap; - gap: 1.5rem; - margin-bottom: 1rem; -} - -.workbench-download-template-btn { - font-weight: 700; -} -.digit-employee-card-input.numeric { - text-align: center; -} -.in-between { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 2rem; - @media screen and (min-width: 1024px) { - grid-gap: 10rem; - } -} -.setup-campaign { - .setup-campaign-card { - padding-bottom: 1.5rem; - } - .digit-dropdown-options-card { - max-height: 10rem !important; - } - .digit-field { - margin-bottom: 0 !important; - } -} -.campaign-summary-container { - .setup-campaign-card { - .employeeCard.employeeCard-override { - padding: 1.5rem; - margin-bottom: 1.5rem !important; - } - } - .row { - justify-content: flex-start; - gap: 5rem; - h2 { - margin: 0; - width: 272px; - } - .value { - width: unset; - p { - margin: 0; - } - } - } - .digit-infobanner-wrap.error { - margin-left: 0; - margin-bottom: 1.5rem; - min-width: 100%; - .digit-button-primary { - height: 1.5rem; - background-color: #d4351c !important; - .icon-label-container.primary.large { - font-size: 14px; - .digit-button-label { - font-size: 14px; - color: #ffffff; - } - } - } - } -} -.view-composer-header-section { - .employee-card-sub-header { - @extend .typography.text-heading-m; - margin-bottom: 1.5rem; - } - .employee-card-sub-header.error { - color: #d4351c; - display: flex; - align-items: center; - gap: 0.5rem; - } -} -.add-new-product-container { - border: 1px solid #d6d5d4; - background-color: #fafafa; - width: 70%; - padding-top: 0; - .heading-bar { - font-weight: 700; - display: flex; - align-items: baseline; - justify-content: space-between; - .card-text { - margin-top: 1rem; - margin-bottom: 1rem; - } - } - .label-field-pair { - gap: 5rem; - align-items: baseline; - .product-label-field { - width: 12rem; - text-wrap: nowrap; - font-weight: 700; - } - } -} -.page-padding-fix { - margin-top: 1.5rem; -} -.addProductActionClass { - display: flex; - flex-direction: row-reverse; - justify-content: space-between; - .submit-bar { - width: max-content; - padding-left: 1.5rem; - padding-right: 1.5rem; - } -} -.loginFormStyleEmployee { - .loginCardClassName { - .digit-header-content { - &:not(label) { - display: flex; - justify-content: center; - } - } - } -} -.selecting-boundaries-dropdown { - .digit-multiselectdropdown-server { - max-height: 15rem; - } -} -.hover { - cursor: pointer; -} -.digit-dropdown-employee-select-wrap { - .digit-dropdown-employee-select-wrap--elipses { - font-size: 1rem !important; - } -} -.digit-dropdown-employee-select-wrap.language-dropdown { - .digit-dropdown-options-card { - min-width: fit-content; - } -} -.digit-popup-wrapper.boundaries-pop-module.default { - width: 36rem; - .digit-popup-footer { - .digit-popup-footer-buttons { - width: 100% !important; - display: grid; - grid-template-columns: 1fr 1fr; - .digit-button-secondary { - width: 100%; - } - .digit-button-primary { - width: 100%; - } - } - } -} -.campaign-type-alert-button { - .digit-button-label { - width: 100% !important; - } -} -.campaign-pop-module { - padding: 1.5rem; - border-radius: 4px; - width: 36rem; -} -.campaign-modal-heading { - font-size: 2rem; - font-weight: 700; - margin: 0 !important; -} -.campaign-pop-main { - font-size: 1.25rem; - padding: 0 !important; - font-size: 400; - .card-text { - margin-bottom: 1.5rem !important; - } - .popup-module-action-bar.campaign-pop-action { - .selector-button-border { - background-color: #ffffff; - border: 1px solid #c84c0e; - h2 { - color: #c84c0e !important; - } - } - } -} - -.digit-toast-success { - max-width: 90%; - margin-left: auto; - margin-right: auto; - height: auto; - .toast-label { - line-height: 1.5; - word-break: break-word; - height: auto; - white-space: unset; - } -} - -.digit-dropdown-select.error { - border: 1px solid #d4351c; -} -.campaign-type-wrapper { - .digit-error-icon-message-wrap { - margin-top: 4px; - font-size: 14px; - } -} -.individualElement { - h2 { - color: theme(digitv2.lightTheme.text-primary); - } -} -.link { - color: #c84c0e !important; -} -.employeeCard.employeeCard-override.card-error { - border: 1px solid #d4351c; -} -.label-field-pair.delivery-type-radio { - gap: 5rem; - .digit-radio-options-wrap { - gap: 2rem; - margin-bottom: 0 !important; - .radio-option-container { - margin-bottom: 0; - align-items: center; - } - } -} -.bold { - font-weight: 700; -} -.summary-doc-error { - p { - margin-top: 0; - margin-bottom: 0; - } - .digit-infobanner-wrap.error { - margin-bottom: 0.5rem; - margin-top: 1.5rem; - } -} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/typography.scss b/frontend/micro-ui/web/micro-ui-internals/packages/css/src/typography.scss deleted file mode 100644 index 4a50014cf88..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/src/typography.scss +++ /dev/null @@ -1,512 +0,0 @@ -.typography { - &.text-heading-xl { - font-family: theme(digitv2.fontFamily.rc); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.bold); - color: theme(digitv2.lightTheme.text-primary); - line-height: theme(digitv2.lineHeight.normal); - - @media (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.heading-xl.desktop); - } - - @media (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.heading-xl.tablet); - } - - @media (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.heading-xl.mobile); - } - } - - &.text-heading-l { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.bold); - color: theme(digitv2.lightTheme.text-primary); - line-height: theme(digitv2.lineHeight.normal); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.heading-l.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.heading-l.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.heading-l.mobile); - } - } - - &.text-heading-m { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.bold); - color: theme(digitv2.lightTheme.text-primary); - line-height: theme(digitv2.lineHeight.normal); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.heading-m.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.heading-m.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.heading-m.desktop); - } - } - - &.text-heading-s { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.bold); - color: theme(digitv2.lightTheme.text-primary); - line-height: theme(digitv2.lineHeight.normal); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.heading-s.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.heading-s.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.heading-s.mobile); - } - } - - &.text-heading-xs { - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.heading-xs.mobile); - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.bold); - color: theme(digitv2.lightTheme.text-primary); - line-height: theme(digitv2.lineHeight.normal); - } - } - - &.text-caption-l { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.italic); - font-weight: theme(digitv2.fontWeight.medium); - color: theme(digitv2.lightTheme.text-primary); - line-height: theme(digitv2.lineHeight.normal); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.caption-l.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.caption-l.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.caption-l.mobile); - } - } - - &.text-caption-m { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.italic); - font-weight: theme(digitv2.fontWeight.medium); - color: theme(digitv2.lightTheme.text-primary); - line-height: theme(digitv2.lineHeight.normal); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.caption-m.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.caption-m.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.caption-m.mobile); - } - } - - &.text-caption-s { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.italic); - font-weight: theme(digitv2.fontWeight.medium); - color: theme(digitv2.lightTheme.text-primary); - line-height: theme(digitv2.lineHeight.normal); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.caption-s.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.caption-s.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.caption-s.desktop); - } - } - - &.text-body-l { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.italic); - font-weight: theme(digitv2.fontWeight.regular); - color: theme(digitv2.lightTheme.text-primary); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.body-l.desktop); - line-height: theme(digitv2.lineHeight.line-height-body-l.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.body-l.tablet); - line-height: theme(digitv2.lineHeight.line-height-body-l.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.body-l.mobile); - line-height: theme(digitv2.lineHeight.line-height-body-l.mobile); - } - } - - &.text-body-s { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.italic); - font-weight: theme(digitv2.fontWeight.regular); - color: theme(digitv2.lightTheme.text-primary); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.body-s.desktop); - line-height: theme(digitv2.lineHeight.line-height-body-s.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.body-s.tablet); - line-height: theme(digitv2.lineHeight.line-height-body-s.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.body-s.mobile); - line-height: theme(digitv2.lineHeight.line-height-body-s.mobile); - } - } - - &.text-body-xs { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.italic); - font-weight: theme(digitv2.fontWeight.regular); - color: theme(digitv2.lightTheme.text-primary); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.body-xs.desktop); - line-height: theme(digitv2.lineHeight.line-height-body-xs.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.body-xs.tablet); - line-height: theme(digitv2.lineHeight.line-height-body-xs.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.body-xs.mobile); - line-height: theme(digitv2.lineHeight.line-height-body-xs.mobile); - } - } - - &.text-label { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.italic); - font-weight: theme(digitv2.fontWeight.regular); - color: theme(digitv2.lightTheme.text-primary); - line-height: theme(digitv2.lineHeight.normal); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.label.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.label.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.label.mobile); - } - } - - &.text-link { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.regular); - color: theme(digitv2.lightTheme.text-primary); - line-height: theme(digitv2.lineHeight.normal); - text-decoration: theme(digitv2.textDecorationLine.underline); - - @media screen and (min-width: theme(digitv2.screens.desktop)) { - font-size: theme(digitv2.fontSize.link.desktop); - } - - @media screen and (min-width: theme(digitv2.screens.tablet)) { - font-size: theme(digitv2.fontSize.link.tablet); - } - - @media screen and (min-width: theme(digitv2.screens.mobile)) { - font-size: theme(digitv2.fontSize.link.mobile); - } - } - - &.heading-xl { - font-family: theme(digitv2.fontFamily.rc); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.bold); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.heading-xl.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.heading-xl.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.heading-xl.desktop); - } - } - - &.heading-l { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.bold); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.heading-l.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.heading-l.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.heading-l.desktop); - } - } - - &.heading-m { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.bold); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.heading-m.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.heading-m.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.heading-m.desktop); - } - } - - &.heading-s { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.bold); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.heading-s.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.heading-s.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.heading-s.desktop); - } - } - - &.heading-xs { - font-size: theme(digitv2.fontSize.heading-xs.mobile); - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.bold); - } - - &.caption-l { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.italic); - font-weight: theme(digitv2.fontWeight.medium); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.caption-l.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.caption-l.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.caption-l.desktop); - } - } - - &.caption-m { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.italic); - font-weight: theme(digitv2.fontWeight.medium); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.caption-m.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.caption-m.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.caption-m.desktop); - } - } - - &.caption-s { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.italic); - font-weight: theme(digitv2.fontWeight.medium); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.caption-s.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.caption-s.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.caption-s.desktop); - } - } - - &.body-l { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.regular); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.body-l.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.body-l.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.body-l.desktop); - } - } - - &.body-s { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.regular); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.body-s.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.body-s.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.body-s.desktop); - } - } - - &.body-xs { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.regular); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.body-xs.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.body-xs.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.body-xs.desktop); - } - } - - &.label { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.regular); - - @media (max-width: 30rem) { - /* Media query for mobile */ - font-size: theme(digitv2.fontSize.label.mobile); - } - - @media (min-width: 30.063rem) and (max-width: 47.938rem) { - /* Media query for tablets */ - font-size: theme(digitv2.fontSize.label.tablet); - } - - @media (min-width: 48rem) { - /* Media query for desktop */ - font-size: theme(digitv2.fontSize.label.desktop); - } - } - - &.link { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.regular); - text-decoration: theme(digitv2.textDecorationLine.underline); - font-size: theme(digitv2.fontSize.link.desktop); - } - - &.button { - font-family: theme(digitv2.fontFamily.sans); - font-style: theme(digitv2.fontStyle.normal); - font-weight: theme(digitv2.fontWeight.medium); - font-size: theme(digitv2.fontSize.button.desktop); - } -} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js b/frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js deleted file mode 100644 index c9b2a06dedf..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/css/tailwind.config.js +++ /dev/null @@ -1,233 +0,0 @@ -module.exports = { - future: { - removeDeprecatedGapUtilities: true, - purgeLayersByDefault: true, - }, - purge: { enabled: true, content: ["./example/index.html"] }, - theme: { - screens: { - dt: "780px", - sm: { max: "425px" }, - }, - colors: { - primary: { - light: "#F18F5E", - main: "#F47738", - dark: "#C8602B", - }, - secondary: "#22394D", - text: { - primary: "#0B0C0C", - secondary: "#505A5F", - }, - link: { - normal: "#1D70B8", - hover: "#003078", - }, - border: "#D6D5D4", - inputBorder: "#464646", - "input-border": "#464646", - focus: "#F47738", - error: "#D4351C", - success: "#00703C", - black: "#000000", - grey: { - dark: "#9E9E9E", - mid: "#EEEEEE", - light: "#FAFAFA", - bg: "#E3E3E3", - }, - white: "#FFFFFF", - }, - fontFamily: { - sans: ["Roboto", "sans-serif"], - rc: ['"Roboto Condensed"', "sans-serif"], - }, - fontSize: { - "heading-xl-dt": ["48px", "56px"], - "heading-xl": ["32px", "40px"], - "heading-l-dt": ["36px", "40px"], - "heading-l": ["24px", "32px"], - "heading-m-dt": ["24px", "32px"], - "heading-m": ["18px", "28px"], - "heading-s": ["16px", "24px"], - "caption-xl-dt": ["27px", "32px"], - "caption-xl": ["18px", "26px"], - "caption-l-dt": ["24px", "28px"], - "caption-l": ["18px", "21px"], - "caption-m-dt": ["19px", "23px"], - "caption-m": ["16px", "19px"], - "form-field": ["16px", "20px"], - "body-l-dt": ["19px", "28px"], - "body-l": ["16px", "24px"], - "body-s-dt": ["16px", "24px"], - "body-s": ["14px", "16px"], - legend: ["19px", "23px"], - link: ["16px", "24px"], - "text-btn": ["16px", "24px"], - }, - fontWeight: { - regular: 400, - medium: 500, - bold: 700, - }, - padding: { - sm: "8px", - md: "16px", - lg: "24px", - xl: "36px", - }, - margin: { - xs: "4px", - sm: "8px", - md: "16px", - lg: "24px", - xl: "64px", - }, - borderWidth: { - default: "1px", - 0: "0", - 2: "1px", - 4: "4px", - 10: "10px", - }, - boxShadow: { - card: "0 1px 2px 0 rgba(0, 0, 0, 0.16)", - radiobtn: "0 0 0 5px #F47738", - }, - inset: { - 0: 0, - 6: "6px", - 10: "10px", - }, - extend: {}, - digitv2: { - lightTheme: { - primary: "#C84C0E", - "text-color-primary": "#0B0C0C", - "text-color-secondary": "#505A5F", - "text-color-disabled": "#B1B4B6", - background: "#EEEEEE", - paper: "#FFFFFF", - "paper-secondary": "#FAFAFA", - divider: "#D6D5D4", - "header-sidenav": "#0B4B66", - "input-border": "#505A5F", - "primary-bg": "#FEEFE7", - "text-primary": "#363636", - "error-v2": "#D4351C", - }, - alert: { - error: "#b91900", - "error-bg": "#EFC7C1", - success: "#00703C", - "success-bg": "#BAD6C9", - info: "#3498DB", - "info-bg": "#C7E0F1", - }, - chart: { - "chart-1": "#048BD0", - "chart-1-gradient": "#048BD0", - "chart-2": "#FBC02D", - "chart-2-gradient": "#FBC02D", - "chart-3": "#8E29BF", - "chart-4": "#EA8A3B", - "chart-5": "#0BABDE", - }, - fontSize: { - "heading-xl": { - mobile: "2rem", - tablet: "2.25rem", - desktop: "2.5rem", - }, - "heading-l": { - mobile: "1.5rem", - tablet: "1.75rem", - desktop: "2rem", - }, - "heading-m": { - mobile: "1.25rem", - tablet: "1.375rem", - desktop: "1.5rem", - }, - "heading-s": { - mobile: "1rem", - tablet: "1rem", - desktop: "1rem", - }, - "heading-xs": { - mobile: "0.75rem", - }, - "caption-l": { - mobile: "1.5rem", - tablet: "1.75rem", - desktop: "1.75rem", - }, - "caption-m": { - mobile: "1.25rem", - tablet: "1.5rem", - desktop: "1.5rem", - }, - "caption-s": { - mobile: "1rem", - tablet: "1.25rem", - desktop: "1.25rem", - }, - "body-l": { - mobile: "1rem", - tablet: "1.25rem", - desktop: "1.25rem", - }, - "body-s": { - mobile: "0.875rem", - tablet: "1rem", - desktop: "1rem", - }, - "body-xs": { - mobile: "0.75rem", - tablet: "0.875rem", - desktop: "0.875rem", - }, - label: { - mobile: "1rem", - tablet: "1rem", - desktop: "1rem", - }, - link: { - mobile: "1rem", - tablet: "1rem", - desktop: "1rem", - }, - }, - fontFamily: { - sans: ["Roboto"], - rc: ['"Roboto Condensed"'], - }, - fontStyle: { - normal: "normal", - italic: "italic", - }, - textDecorationLine: { - underline: "underline", - }, - fontWeight: { - regular: 400, - medium: 500, - bold: 700, - }, - lineHeight: { - "line-height-body-l": { mobile: "1.5rem", tablet: "1.75rem", desktop: "1.75rem" }, - "line-height-body-s": { mobile: "1.0938rem", tablet: "1.5rem", desktop: "1.5rem" }, - "line-height-body-xs": { mobile: "1.125rem", tablet: "1.5rem", desktop: "1.5rem" }, - normal: "normal", - }, - screens: { - mobile: "400px", - tablet: "768px", - desktop: "1024px", - }, - }, - }, - variants: {}, - plugins: [], -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/README.md b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/README.md deleted file mode 100644 index 0d206b3021e..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/README.md +++ /dev/null @@ -1,159 +0,0 @@ -# digit-ui-module-workbench - -## Install - -```bash -npm install --save digit-ui-module-workbench -``` - -## Limitation - -```bash -This Package is more specific to DIGIT-UI's can be used across mission's -``` - -## Usage - -After adding the dependency make sure you have this dependency in - -```bash -frontend/micro-ui/web/package.json -``` - -```json -"@egovernments/digit-ui-module-workbench":"1.0.0", -``` - -then navigate to App.js - -```bash - frontend/micro-ui/web/src/App.js -``` - -```jsx -/** add this import **/ - -import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench"; - -/** inside enabledModules add this new module key **/ - -const enabledModules = ["workbench"]; - -/** inside init Function call this function **/ - -const initDigitUI = () => { - initWorkbenchComponents(); -}; - -``` - -In MDMS - -_Add this configuration to enable this module [MDMS Enabling Workbench Module](https://github.com/egovernments/works-mdms-data/blob/588d241ba3a9ab30f4d4c2c387a513da811620ca/data/pg/tenant/citymodule.json#L227)_ - -## List of Screens available in this versions were as follows - -1 . Search Master Data - > -Provides a screen based on Schema and renders the search result if data is present - > -It also provides a dynamic filter based on which data can be filtered - - -2 . Add Master Data based on selected schema - > -Provides a screen to add new master data according to the schema - > -Provides a Dropdown if it has any referenced master - -3 . Update Master data for selected data. - > -View the master data from search screen - > -Disable/Enable the master data if required - > -Update the master data value except the unique-identifier field mentioned in the schema - - - -4 . Localisation screens - > -Provides a screen to search the localisation present in the environment - > -Add new localisation - > -Update existing localisation - > -Bulk Upload of Localisation data - -5 . MDMS UI Schema - -6 . Data push for any API based on schema - -### Mandatory changes to use Workbench module - -1 . Assuming core module is already updated with 1.5.38+ and related changes were taken - -2 . add the following hook method in micro-ui-internals/packages/libraries/src/hooks/useCustomAPIMutationHook.js - -reference:: -https://github.com/egovernments/DIGIT-Dev/blob/6e711bdc005c226c7debd533209681fc77078a3e/frontend/micro-ui/web/micro-ui-internals/packages/libraries/src/hooks/useCustomAPIMutationHook.js - -3 . add the following utility method in micro-ui-internals/packages/libraries/src/utils/index.js -```jsx -didEmployeeHasAtleastOneRole - -const didEmployeeHasAtleastOneRole = (roles = []) => { - return roles.some((role) => didEmployeeHasRole(role)); -}; - -``` - -4 . stylesheet link has to be added -```jsx - -``` -Reference commit for the enabling workbench -https://github.com/egovernments/DIGIT-OSS/pull/99/commits/6e711bdc005c226c7debd533209681fc77078a3e - - - -### Changelog - -```bash -1.0.1-beta.1 Republished after merging with Master due to version issues. -1.0.0-beta.14 Added info message in localisation search -1.0.0-beta.13 Added new role to support hcm localisation create -1.0.0-beta.13 Added customisable label for custom dropdown through workbench ui schema -1.0.0-beta.11 Added customisable label for custom dropdown through workbench ui schema -1.0.0-beta.10 fixed the dropdown undefined issue -1.0.0-beta.9 Added new role to support hcm manage masters -1.0.0-beta.8 minor fixes -1.0.0-beta.7 Added Bulk Upload Ui for MDMS Add -1.0.0-beta.6 Added Bulk Upload Ui for MDMS Add -1.0.0-beta.5 Fixed some loading issue -1.0.0-beta.2 custom api support added -1.0.0-beta.1 republished due to some version issues -1.0.1 Fixes related to the limits -1.0.0 Workbench v1.0 release -1.0.0-beta workbench base version beta release -0.0.3 readme updated -0.0.2 readme updated -0.0.1 base version -``` - -### Contributors - -- [jagankumar-egov](https://github.com/jagankumar-egov) -- [nipun-egov](https://github.com/nipun-egov) - - -## License - -[MIT](https://choosealicense.com/licenses/mit/) - -## Documentation - -Documentation Site (https://core.digit.org/guides/developer-guide/ui-developer-guide/digit-ui) -Workbench Documentation(https://workbench.digit.org/platform/functional-specifications/workbench-ui) - -## Maintainer - -- [jagankumar-egov](https://www.github.com/jagankumar-egov) - - -### Published from DIGIT Frontend -DIGIT Frontend Repo (https://github.com/egovernments/Digit-Frontend/tree/master) - - -![Logo](https://s3.ap-south-1.amazonaws.com/works-dev-asset/mseva-white-logo.png) - diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json deleted file mode 100644 index 41e43fdb6fd..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/package.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "name": "@egovernments/digit-ui-module-campaign-manager", - "version": "0.0.1", - "description": "Campaign", - "main": "dist/index.js", - "module": "dist/index.modern.js", - "source": "src/Module.js", - "files": [ - "dist" - ], - "scripts": { - "start": "microbundle-crl watch --no-compress --format modern,cjs", - "build": "microbundle-crl --compress --no-sourcemap --format cjs", - "prepublish": "yarn build" - }, - "peerDependencies": { - "react": "17.0.2", - "react-router-dom": "5.3.0" - }, - "dependencies": { - "@egovernments/digit-ui-react-components": "1.8.2-beta.6", - "@egovernments/digit-ui-components": "0.0.2-beta.1", - "@rjsf/core": "5.10.0", - "@rjsf/utils": "5.10.0", - "@rjsf/validator-ajv8": "5.10.0", - "ajv": "8.12.0", - "react": "17.0.2", - "react-date-range": "1.4.0", - "react-dom": "17.0.2", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "react-router-dom": "5.3.0", - "react-select": "5.7.4", - "react-table": "7.7.0", - "xlsx": "0.17.5", - "react-drag-drop-files": "^2.3.10", - "@cyntler/react-doc-viewer": "1.10.3" - }, - "author": "JaganKumar ", - "license": "MIT", - "keywords": [ - "digit", - "egov", - "dpg", - "digit-ui", - "workbench", - "campaign", - "Campaign" - ] -} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js deleted file mode 100644 index cc2f33443d4..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/Module.js +++ /dev/null @@ -1,141 +0,0 @@ -import { Loader, TourProvider } from "@egovernments/digit-ui-react-components"; -import React from "react"; -import { useRouteMatch } from "react-router-dom"; -import EmployeeApp from "./pages/employee"; -import { CustomisedHooks } from "./hooks"; -import { UICustomizations } from "./configs/UICustomizations"; -import CampaignCard from "./components/CampaignCard"; -import CycleConfiguration from "./pages/employee/CycleConfiguration"; -import DeliverySetup from "./pages/employee/deliveryRule"; -import TimelineCampaign from "./components/TimelineCampaign"; -import CampaignDates from "./components/CampaignDates"; -import CampaignType from "./components/CampaignType"; -import CampaignName from "./components/CampaignName"; -import MyCampaign from "./pages/employee/MyCampaign"; -import CampaignSummary from "./components/CampaignSummary"; -import CycleDetaisPreview from "./components/CycleDetaisPreview"; -import Response from "./pages/employee/Response"; -import SelectingBoundaries from "./components/SelectingBoundaries"; -import UploadData from "./components/UploadData"; -import CampaignSelection from "./components/CampaignType"; -import CampaignDocumentsPreview from "./components/CampaignDocumentsPreview"; -import AddProduct from "./pages/employee/AddProduct"; -import AddProductField from "./components/AddProductField"; -import CycleDataPreview from "./components/CycleDataPreview"; -import { ErrorBoundary } from "@egovernments/digit-ui-components"; -import CampaignResourceDocuments from "./components/CampaignResourceDocuments"; - -/** - * The CampaignModule function fetches store data based on state code, module code, and language, and - * renders the EmployeeApp component within a TourProvider component if the data is not loading. - * @returns The CampaignModule component returns either a Loader component if data is still loading, or - * a TourProvider component wrapping an EmployeeApp component with specific props passed to it. - */ -const CampaignModule = ({ stateCode, userType, tenants }) => { - const tenantId = Digit.ULBService.getCurrentTenantId(); - const { data: BOUNDARY_HIERARCHY_TYPE } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "hierarchyConfig" }], { - select: (data) => { - return data?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.hierarchy; - }, - }); - - const moduleCode = ["campaignmanager", "workbench", "mdms", "schema", "hcm-admin-schemas", `boundary-${BOUNDARY_HIERARCHY_TYPE}`]; - const { path, url } = useRouteMatch(); - const language = Digit.StoreData.getCurrentLanguage(); - const { isLoading, data: store } = Digit.Services.useStore({ - stateCode, - moduleCode, - language, - }); - - if (isLoading) { - return ; - } - - return ( - - - - - - ); -}; - -const componentsToRegister = { - CampaignModule: CampaignModule, - CampaignCard: CampaignCard, - UploadData, - DeliveryRule: DeliverySetup, - CycleConfiguration: CycleConfiguration, - TimelineCampaign, - CampaignDates, - CampaignType, - CampaignName, - MyCampaign, - CampaignSummary, - CycleDetaisPreview, - Response, - SelectingBoundaries, - CampaignSelection, - CampaignDocumentsPreview: CampaignDocumentsPreview, - AddProduct, - AddProductField, - CycleDataPreview, - CampaignResourceDocuments, -}; - -const overrideHooks = () => { - Object.keys(CustomisedHooks).map((ele) => { - if (ele === "Hooks") { - Object.keys(CustomisedHooks[ele]).map((hook) => { - Object.keys(CustomisedHooks[ele][hook]).map((method) => { - setupHooks(hook, method, CustomisedHooks[ele][hook][method]); - }); - }); - } else if (ele === "Utils") { - Object.keys(CustomisedHooks[ele]).map((hook) => { - Object.keys(CustomisedHooks[ele][hook]).map((method) => { - setupHooks(hook, method, CustomisedHooks[ele][hook][method], false); - }); - }); - } else { - Object.keys(CustomisedHooks[ele]).map((method) => { - setupLibraries(ele, method, CustomisedHooks[ele][method]); - }); - } - }); -}; - -/* To Overide any existing hook we need to use similar method */ -const setupHooks = (HookName, HookFunction, method, isHook = true) => { - window.Digit = window.Digit || {}; - window.Digit[isHook ? "Hooks" : "Utils"] = window.Digit[isHook ? "Hooks" : "Utils"] || {}; - window.Digit[isHook ? "Hooks" : "Utils"][HookName] = window.Digit[isHook ? "Hooks" : "Utils"][HookName] || {}; - window.Digit[isHook ? "Hooks" : "Utils"][HookName][HookFunction] = method; -}; -/* To Overide any existing libraries we need to use similar method */ -const setupLibraries = (Library, service, method) => { - window.Digit = window.Digit || {}; - window.Digit[Library] = window.Digit[Library] || {}; - window.Digit[Library][service] = method; -}; - -/* To Overide any existing config/middlewares we need to use similar method */ -const updateCustomConfigs = () => { - setupLibraries("Customizations", "commonUiConfig", { ...window?.Digit?.Customizations?.commonUiConfig, ...UICustomizations }); - // setupLibraries("Utils", "parsingUtils", { ...window?.Digit?.Utils?.parsingUtils, ...parsingUtils }); -}; - -/** - * The `initCampaignComponents` function initializes campaign components by overriding hooks, updating - * custom configurations, and registering components. - */ -const initCampaignComponents = () => { - overrideHooks(); - updateCustomConfigs(); - Object.entries(componentsToRegister).forEach(([key, value]) => { - Digit.ComponentRegistryService.setComponent(key, value); - }); -}; - -export { initCampaignComponents }; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AddProductField.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AddProductField.js deleted file mode 100644 index 94a73fd6b24..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/AddProductField.js +++ /dev/null @@ -1,144 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { AddIcon, Button, Card, CardText, Header, TextInput, Dropdown } from "@egovernments/digit-ui-react-components"; -import { useTranslation } from "react-i18next"; -import { LabelFieldPair } from "@egovernments/digit-ui-react-components"; -import { DustbinIcon } from "./icons/DustbinIcon"; -// import { productType } from "../configs/productType"; -import { PRIMARY_COLOR } from "../utils"; - -const AddProductField = ({ onSelect }) => { - const { t } = useTranslation(); - const tenantId = Digit.ULBService.getCurrentTenantId(); - const { isLoading: productTypeLoading, data: productType } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "productType" }], { - select: (data) => { - return data?.["HCM-ADMIN-CONSOLE"]?.productType; - }, - }); - const [productFieldData, setProductFieldData] = useState([{ key: 1, name: null, type: null, variant: null }]); - - useEffect(() => { - onSelect("addProduct", productFieldData); - }, [productFieldData]); - - const addMoreField = () => { - setProductFieldData((prev) => [ - ...prev, - { - key: prev.length + 1, - name: null, - type: null, - variant: null, - }, - ]); - }; - - const deleteProductField = (index) => { - setProductFieldData((prev) => { - const temp = prev.filter((i) => i.key !== index); - return temp.map((i, n) => ({ ...i, key: n + 1 })); - }); - }; - - const handleUpdateField = (data, target, index) => { - setProductFieldData((prev) => { - return prev.map((i) => { - if (i.key === index) { - return { - ...i, - [target]: data, - }; - } - return { - ...i, - }; - }); - }); - }; - - return ( - -
{t(`HCM_CAMPAIGN_ADD_NEW_PRODUCT_HEADER`)}
-

- {t(`HCM_CAMPAIGN_ADD_NEW_PRODUCT_DESCRIPTION_PRE_TEXT`)} {t(`HCM_CAMPAIGN_ADD_NEW_PRODUCT_DESCRIPTION_BOLD_TEXT`)} - {t(`HCM_CAMPAIGN_ADD_NEW_PRODUCT_DESCRIPTION_POST_TEXT`)} -

- {productFieldData?.map((field, index) => { - return ( - -
- Product {field?.key} - {productFieldData?.length > 1 && ( -
deleteProductField(field.key)} - style={{ - cursor: "pointer", - fontWeight: "600", - marginLeft: "1rem", - fontSize: "1rem", - color: PRIMARY_COLOR, - display: "flex", - gap: "0.5rem", - alignItems: "center", - marginTop: "1rem", - }} - > - - {t(`CAMPAIGN_DELETE_ROW_TEXT`)} -
- )} -
- -
- {`${t("HCM_PRODUCT_NAME")}`} - * -
- handleUpdateField(event.target.value, "name", field.key)} - /> -
- -
- {`${t("HCM_PRODUCT_TYPE")}`} - * -
- { - handleUpdateField(value, "type", field.key); - }} - /> -
- -
- {`${t("HCM_PRODUCT_VARIANT")}`} - * -
- handleUpdateField(event.target.value, "variant", field?.key)} - /> -
-
- ); - })} - - ))} - - ); -}; - -const CycleDataPreview = ({ data, items, index, errors, onErrorClick, cardErrors }) => { - const { t } = useTranslation(); - const [deliveryData, setDeliveryData] = useState(data?.deliveries); - const [activeTab, setActiveTab] = useState(1); - - useEffect(() => { - setDeliveryData(data?.deliveries); - }, [data?.deliveries]); - - const handleTabChange = (tabIndex, index) => { - setDeliveryData((prev) => { - return prev.map((i) => { - if (i.deliveryIndex == tabIndex) { - return { - ...i, - active: true, - }; - } else { - return { - ...i, - active: false, - }; - } - }); - }); - }; - // return null; - return ( - <> - {cardErrors?.map((i) => ( - ]} - /> - ))} - {/* {i.error ? i.error : i.message)} */} -
- {data?.startDate && ( - - )} - {data?.endDate && ( - - )} -
- -
- - - - {deliveryData - .find((i) => i.active === true) - ?.deliveryRules?.map((rules, ruleIndex) => { - return ( - - {rules?.attributes?.length > 0 && ( - - )} - {rules?.products?.length > 0 && ( - - )} - - ); - })} - - {/* - {item?.conditions?.length > 0 && ( - - )} - {item?.products?.length > 0 && ( - - )} - */} - - ); -}; - -export default CycleDataPreview; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDetaisPreview.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDetaisPreview.js deleted file mode 100644 index 515b25191d9..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/CycleDetaisPreview.js +++ /dev/null @@ -1,143 +0,0 @@ -import { Card, LabelFieldPair, Row } from "@egovernments/digit-ui-react-components"; -import React, { Fragment } from "react"; -import { useTranslation } from "react-i18next"; -import DetailsTable from "./DetailsTable"; - -function mergeObjects(item) { - const arr = item?.conditions; - const mergedArr = []; - const mergedAttributes = new Set(); - - arr.forEach((obj) => { - if (!mergedAttributes.has(obj.attribute)) { - const sameAttrObjs = arr.filter((o) => o.attribute === obj.attribute); - - if (sameAttrObjs.length > 1) { - const fromValue = Math.min(...sameAttrObjs.map((o) => o.value)); - const toValue = Math.max(...sameAttrObjs.map((o) => o.value)); - - mergedArr.push({ - fromValue, - toValue, - value: fromValue > 0 && toValue > 0 ? `${fromValue} to ${toValue}` : null, - operator: "IN_BETWEEN", - attribute: obj.attribute, - }); - - mergedAttributes.add(obj.attribute); - } else { - mergedArr.push(obj); - } - } - }); - - return { ...item, conditions: mergedArr }; -} - -const CycleDetaisPreview = ({ data, items, index }) => { - const { t } = useTranslation(); - const item = mergeObjects(items); - - return ( - <> - - - {/* - {`${t("CYCLE_NUMBER")}`} - {item?.cycleNumber} - - - {`${t("DELIVERY_NUMBER")}`} - {item?.deliveryNumber} - */} - {item?.startDate || item?.endDate ? ( - -
-

- {t(`CYCLE`)} {item?.cycleNumber} -

-
- {item?.startDate && ( - - )} - {item?.endDate && ( - - )} -
- ) : null} - - - {item?.conditions?.length > 0 && ( - - )} - {item?.products?.length > 0 && ( - - )} - - - ); -}; - -export default CycleDetaisPreview; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DetailsTable.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DetailsTable.js deleted file mode 100644 index 5c6e01fcc22..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DetailsTable.js +++ /dev/null @@ -1,76 +0,0 @@ -import React, { Fragment } from "react"; -import { useTable } from "react-table"; -import { useTranslation } from "react-i18next"; -import { CardLabel, CardSubHeader } from "@egovernments/digit-ui-react-components"; - -const DetailsTable = ({ className = "", columnsData, rowsData, summaryRows, cardHeader }) => { - const { t } = useTranslation(); - - const columns = React.useMemo(() => columnsData, [t]); - - const data = React.useMemo(() => { - const temp = rowsData.map((i) => ({ - ...i, - operator: t(i?.operator), - attribute: i?.attribute ? t(`CAMPAIGN_ATTRIBUTE_${i?.attribute?.toUpperCase()}`) : "", - })); - return temp; - }, [rowsData]); - - const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable({ - columns, - data, - }); - - return ( - <> - {cardHeader && ( - - {cardHeader?.value} - - )} -
- - - {headerGroups.map((headerGroup) => ( - - {headerGroup.headers.map((column) => ( - - ))} - - ))} - - - - {rows.map((row) => { - prepareRow(row); - return ( - - {row.cells.map((cell) => ( - - ))} - - ); - })} - - {summaryRows && ( - - {summaryRows.map((cell, index) => ( - - ))} - - )} - -
- {column.render("Header")} -
- {cell.render("Cell")} -
- {index === 4 ? {cell} : cell} -
-
- - ); -}; - -export default DetailsTable; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DocumentIcon.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DocumentIcon.js deleted file mode 100644 index 9b61bf67136..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/DocumentIcon.js +++ /dev/null @@ -1,29 +0,0 @@ -import React from "react"; -export const DocumentIcon = ({ styles = {}, className, fill = "#D4351C" }) => ( - - - - - - - - - - - - - - - - - - - - -); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/PlusMinusInput.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/PlusMinusInput.js deleted file mode 100644 index 89d7b574032..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/PlusMinusInput.js +++ /dev/null @@ -1,47 +0,0 @@ -import React, { useState } from "react"; - -const PlusMinusInput = (props, customProps) => { - let count = props?.defaultValues || 1; - - function incrementCount() { - if (count >= 1) { - count = count + 1; - props.onSelect(count); - } else { - count = 1; - props.onSelect(count); - } - } - function decrementCount() { - if (count > 1) { - count = count - 1; - props.onSelect(count); - } else { - count = 1; - props.onSelect(count); - } - } - - return ( - -
- - - -
-
- ); -}; - -export default PlusMinusInput; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RemovableTagNew.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RemovableTagNew.js deleted file mode 100644 index b04159181a6..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/RemovableTagNew.js +++ /dev/null @@ -1,16 +0,0 @@ -import React from "react"; -import { Close } from "@egovernments/digit-ui-react-components"; - -const RemoveableTagNew = ({ text = {}, onClick, extraStyles, disabled = false }) => ( -
- {text?.label && {`${text?.label} :`}} - - {text?.value} - - - - -
-); - -export default RemoveableTagNew; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js deleted file mode 100644 index 239cf948ee0..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/components/SelectingBoundaries.js +++ /dev/null @@ -1,542 +0,0 @@ -import React, { useEffect, useState, Fragment, useMemo } from "react"; -import { CardText, LabelFieldPair, Card, Header, CardLabel, LoaderWithGap } from "@egovernments/digit-ui-react-components"; -import { useTranslation } from "react-i18next"; -import { InfoCard, MultiSelectDropdown, PopUp, Button, Toast } from "@egovernments/digit-ui-components"; -import { mailConfig } from "../configs/mailConfig"; -/** - * The function `SelectingBoundaries` in JavaScript handles the selection of boundaries based on - * hierarchy data and allows users to choose specific boundaries within the hierarchy. - * @returns The `SelectingBoundaries` component is being returned. It consists of JSX elements - * including Cards, Headers, Dropdowns, MultiSelectDropdowns, and InfoCard. The component allows users - * to select hierarchy types and boundaries based on the data fetched from API calls. It also handles - * the selection of boundaries and updates the state accordingly. The component is designed to be - * interactive and user-friendly for selecting boundaries within - */ -function SelectingBoundaries({ onSelect, formData, ...props }) { - const { t } = useTranslation(); - const tenantId = Digit.ULBService.getCurrentTenantId(); - const [params, setParams] = useState(props?.props?.dataParams); - const [hierarchy, setHierarchy] = useState(params?.hierarchyType); - const [boundaryType, setBoundaryType] = useState( - props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData ? undefined : null - ); - const [targetedData, setTargetedData] = useState(); - const [boundaryData, setBoundaryData] = useState(props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData || {}); - // const [parentArray, setParentArray] = useState(props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData.filter(item => item.includeAllChildren).map(item => item.code) || null); - const [parentArray, setParentArray] = useState(null); - const [boundaryTypeDataresult, setBoundaryTypeDataresult] = useState(null); - const [selectedData, setSelectedData] = useState(props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData || []); - const [parentBoundaryTypeRoot, setParentBoundaryTypeRoot] = useState( - (props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData?.find((item) => item?.isRoot === true) || {}) - ?.boundaryType || null - ); - const [showToast, setShowToast] = useState(null); - const [updatedHierarchy, setUpdatedHierarchy] = useState({}); - const [hierarchyTypeDataresult, setHierarchyTypeDataresult] = useState(params?.hierarchy); - const [executionCount, setExecutionCount] = useState(0); - // State variable to store the lowest hierarchy level - // const [lowestHierarchy, setLowestHierarchy] = useState(null); - const [showPopUp, setShowPopUp] = useState(null); - const [restrictSelection, setRestrictSelection] = useState(null); - const [updateBoundary, setUpdateBoundary] = useState(null); - const [loaderEnabled, setLoaderEnabled] = useState(false); - const { isLoading, data: hierarchyConfig } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "hierarchyConfig" }]); - - // const lowestHierarchy = hierarchyConfig?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.lowestHierarchy; - const lowestHierarchy = useMemo(() => hierarchyConfig?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.lowestHierarchy, [hierarchyConfig]); - const lowestChild = hierarchyTypeDataresult?.boundaryHierarchy.filter((item) => item.parentBoundaryType === lowestHierarchy)?.[0]?.boundaryType; - const searchParams = new URLSearchParams(location.search); - const isDraft = searchParams.get("draft"); - - useEffect(() => { - if (!updateBoundary) { - if ( - props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile?.length > 0 || - props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile?.length > 0 || - props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile?.length > 0 - ) { - setRestrictSelection(true); - } - } - }, [props?.props?.sessionData, updateBoundary]); - - useEffect(() => { - if (props?.props?.dataParams) { - setParams(props?.props?.dataParams); - } - }, [props?.props?.dataParams]); - - useEffect(() => { - onSelect("boundaryType", { boundaryData: boundaryData, selectedData: selectedData, updateBoundary: updateBoundary }); - }, [boundaryData, selectedData]); - - useEffect(() => { - setHierarchy(params?.hierarchyType); - }, [params?.hierarchyType]); - - useEffect(() => { - if (params?.hierarchy) { - const sortHierarchy = (hierarchy) => { - const boundaryMap = new Map(); - hierarchy.forEach(item => { - boundaryMap.set(item.boundaryType, item); - }); - - const sortedHierarchy = []; - let currentType = null; - - while (sortedHierarchy.length < hierarchy.length) { - for (let i = 0; i < hierarchy.length; i++) { - if (hierarchy[i].parentBoundaryType === currentType) { - sortedHierarchy.push(hierarchy[i]); - currentType = hierarchy[i].boundaryType; - break; - } - } - } - - return sortedHierarchy; - }; - - const sortedHierarchy = sortHierarchy(params.hierarchy.boundaryHierarchy); - setHierarchyTypeDataresult({ - ...params.hierarchy, - boundaryHierarchy: sortedHierarchy - }); - } - }, [params?.hierarchy]); - - useEffect(() => { - if (executionCount < 5) { - onSelect("boundaryType", { boundaryData: boundaryData, selectedData: selectedData, updateBoundary: updateBoundary }); - setExecutionCount((prevCount) => prevCount + 1); - } - }); - - useEffect(() => { - setBoundaryData( - props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData - ? props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData - : {} - ); - setSelectedData( - props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData - ? props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.selectedData - : [] - ); - }, [props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType]); - - const closeToast = () => { - setShowToast(null); - }; - - useEffect(() => { - if (hierarchyTypeDataresult) { - const boundaryDataObj = {}; - hierarchyTypeDataresult?.boundaryHierarchy?.forEach((boundary) => { - boundaryDataObj[boundary?.boundaryType] = []; - }); - if (!props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData || Object.keys(boundaryData).length === 0) { - setBoundaryData(boundaryDataObj); - } - const boundaryWithTypeNullParent = hierarchyTypeDataresult?.boundaryHierarchy?.find((boundary) => boundary?.parentBoundaryType === null); - // Set the boundary type with null parentBoundaryType - if (boundaryWithTypeNullParent) { - if (!props?.props?.sessionData?.HCM_CAMPAIGN_SELECTING_BOUNDARY_DATA?.boundaryType?.boundaryData || Object.keys(boundaryData).length === 0) { - setBoundaryType(boundaryWithTypeNullParent?.boundaryType); - } - setParentBoundaryTypeRoot(boundaryWithTypeNullParent?.boundaryType); - } - createHierarchyStructure(hierarchyTypeDataresult); - } - }, [hierarchyTypeDataresult]); - - function createHierarchyStructure(hierarchyTypeDataresult) { - const hierarchyStructure = {}; - - // Recursive function to gather all descendants for a given boundary type - function gatherDescendants(boundaryType) { - const descendants = []; - hierarchyTypeDataresult; - - // Find all children for the current boundary type - const children = hierarchyTypeDataresult?.boundaryHierarchy?.filter((item) => item?.parentBoundaryType === boundaryType); - - // Recursively gather descendants for each child - children.forEach((child) => { - const childBoundaryType = child?.boundaryType; - const childDescendants = gatherDescendants(childBoundaryType); - descendants.push(childBoundaryType, ...childDescendants); - }); - - return descendants; - } - - // Iterate through the boundaryHierarchy array to populate hierarchyStructure - hierarchyTypeDataresult?.boundaryHierarchy?.forEach((item) => { - const boundaryType = item?.boundaryType; - const descendants = gatherDescendants(boundaryType); - - hierarchyStructure[boundaryType] = descendants; - }); - - setUpdatedHierarchy(hierarchyStructure); - } - - const newData = []; - const fetchBoundaryTypeData = async () => { - if (boundaryType === undefined || boundaryType === lowestChild) { - // Do nothing if boundaryType is undefined - return; - } - if (parentArray === null) { - const reqCriteriaBoundaryTypeSearch = Digit.CustomService.getResponse({ - url: "/boundary-service/boundary-relationships/_search", - params: { - tenantId: tenantId, - hierarchyType: hierarchy, - boundaryType: boundaryType, - parent: null, - }, - body: {}, - }); - // setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_LOADING_BOUNDARY") }); - const boundaryTypeData = await reqCriteriaBoundaryTypeSearch; - setBoundaryTypeDataresult([{ parentCode: null, boundaryTypeData: boundaryTypeData }]); - // closeToast(); - } else { - // for (const parentCode of parentArray) { - // const reqCriteriaBoundaryTypeSearch = Digit.CustomService.getResponse({ - // url: "/boundary-service/boundary-relationships/_search", - // params: { - // tenantId: tenantId, - // hierarchyType: hierarchy, - // boundaryType: boundaryType, - // parent: parentCode, - // }, - // body: {}, - // }); - // // setShowToast({ key: "info", label: t("HCM_PLEASE_WAIT_LOADING_BOUNDARY") }); - // setLoaderEnabled(true); - // const boundaryTypeData = await reqCriteriaBoundaryTypeSearch; - // newData.push({ parentCode, boundaryTypeData }); - // } - setLoaderEnabled(true); - const temp = await Digit.Hooks.campaign.useParallelSearch({ - parentArray: parentArray, - tenantId: tenantId, - boundaryType: boundaryType, - hierarchy: hierarchy, - targetedData: targetedData, - }); - const newDataArray = [...newData, ...temp]; - setBoundaryTypeDataresult(newDataArray); - setTimeout(() => { - setLoaderEnabled(false); - }, 100); - // closeToast(); - } - }; - - useEffect(() => { - fetchBoundaryTypeData(); - }, [boundaryType, parentArray, selectedData]); - - useEffect(() => { - if (boundaryTypeDataresult) { - if (boundaryType !== undefined) { - const updatedBoundaryData = { - ...boundaryData, - [boundaryType]: boundaryTypeDataresult, - }; - setBoundaryData(updatedBoundaryData); - } else { - const updatedBoundaryData = { - ...boundaryData, - [boundaryTypeDataresult?.[0]?.boundaryTypeData?.TenantBoundary?.[0]?.boundary?.[0]?.boundaryType]: boundaryTypeDataresult, - }; - setBoundaryData(updatedBoundaryData); - } - } - }, [boundaryTypeDataresult]); - - const checkDataPresent = ({ action }) => { - if (action === false) { - setShowPopUp(false); - setUpdateBoundary(true); - setRestrictSelection(false); - return; - } - if (action === true) { - setShowPopUp(false); - setUpdateBoundary(false); - return; - } - }; - - const handleBoundaryChange = (data, boundary) => { - setTargetedData(boundary?.boundaryType); - if ( - !updateBoundary && - restrictSelection && - (props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_BOUNDARY_DATA?.uploadBoundary?.uploadedFile?.length > 0 || - props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_FACILITY_DATA?.uploadFacility?.uploadedFile?.length > 0 || - props?.props?.sessionData?.HCM_CAMPAIGN_UPLOAD_USER_DATA?.uploadUser?.uploadedFile?.length > 0) - ) { - setShowPopUp(true); - return; - } - if (!data || data.length === 0) { - const check = updatedHierarchy[boundary?.boundaryType]; - - if (check) { - const typesToRemove = [boundary?.boundaryType, ...check]; - const updatedSelectedData = selectedData?.filter((item) => !typesToRemove?.includes(item?.type)); - const updatedBoundaryData = { ...boundaryData }; - - typesToRemove.forEach((type) => { - if (type !== boundary?.boundaryType && updatedBoundaryData?.hasOwnProperty(type)) { - updatedBoundaryData[type] = []; - } - }); - if (!_.isEqual(selectedData, updatedSelectedData)) { - setSelectedData(updatedSelectedData); - } - setBoundaryData(updatedBoundaryData); - } - return; - } - - let res = []; - data && - data?.map((ob) => { - res.push(ob?.[1]); - }); - - // const transformedRes = res?.map((item) => ({ - // code: item.code, - // type: item.type || item.boundaryType, - // isRoot: item.boundaryType === parentBoundaryTypeRoot, - // includeAllChildren: item.type === lowestHierarchy || item.boundaryType === lowestHierarchy, - // parent: item?.parent, - // })); - - let transformedRes = []; - if (!isDraft) { - transformedRes = res?.map((item) => ({ - code: item.code, - type: item.type || item.boundaryType, - isRoot: item.boundaryType === parentBoundaryTypeRoot, - includeAllChildren: item.type === lowestHierarchy || item.boundaryType === lowestHierarchy, - parent: item?.parent, - })); - } else { - // transformedRes = selectedData.filter((item) => item?.type === boundary?.boundaryType) - const filteredData = selectedData.filter((item) => item?.type === boundary?.boundaryType); - if (filteredData.length === 0) { - // If no selected data for the particular boundary type, run the transformation logic - transformedRes = res?.map((item) => ({ - code: item.code, - type: item.type || item.boundaryType, - isRoot: item.boundaryType === parentBoundaryTypeRoot, - includeAllChildren: item.type === lowestHierarchy || item.boundaryType === lowestHierarchy, - parent: item?.parent, - })); - } else { - transformedRes = filteredData; - } - } - - const newBoundaryType = transformedRes?.[0]?.type; - const existingBoundaryType = selectedData?.length > 0 ? selectedData?.[0]?.type : null; - if (existingBoundaryType === newBoundaryType) { - // Update only the data for the specific boundaryType - const flattenedRes = transformedRes.flat(); - const updatedSelectedData = selectedData - ?.map((item) => { - if (item.type === newBoundaryType) { - return transformedRes?.flat(); - } else { - return item; - } - }) - .flat(); - if (!_.isEqual(selectedData, updatedSelectedData)) { - setSelectedData(updatedSelectedData); - } - } else { - // Update only the data for the new boundaryType - const mergedData = [...selectedData?.filter((item) => item?.type !== newBoundaryType), ...transformedRes]; - - // Filter out items with undefined type - const filteredData = mergedData?.filter( - (item, index, self) => item?.type !== undefined && index === self?.findIndex((t) => t?.code === item?.code) - ); - - // Filter out items whose parent is not present in the array - - const updatedSelectedData = []; - const addChildren = (item) => { - updatedSelectedData.push(item); - const children = filteredData.filter((child) => child.parent === item.code); - children.forEach((child) => addChildren(child)); - }; - filteredData.filter((item) => item.isRoot).forEach((rootItem) => addChildren(rootItem)); - if (!_.isEqual(selectedData, updatedSelectedData)) { - setSelectedData(updatedSelectedData); - } - } - const parentBoundaryEntry = hierarchyTypeDataresult - ? hierarchyTypeDataresult?.boundaryHierarchy?.find( - (e) => e?.parentBoundaryType === res?.[0]?.boundaryType || e?.parentBoundaryType === res?.[0]?.type - ) - : null; - setBoundaryType(parentBoundaryEntry?.boundaryType); - const codes = res?.map((item) => item?.code); - if (JSON.stringify(codes) !== JSON.stringify(parentArray)) { - setParentArray(codes); - } - }; - - return ( - <> - {loaderEnabled && } - -
-
{t(`CAMPAIGN_SELECT_BOUNDARY`)}
- {t(`CAMPAIGN_SELECT_BOUNDARIES_DESCRIPTION`)} - {hierarchyTypeDataresult?.boundaryHierarchy - .filter((boundary, index, array) => { - // Find the index of the lowest hierarchy - const lowestIndex = array.findIndex((b) => b.boundaryType === lowestHierarchy); - // Include only those boundaries that are above or equal to the lowest hierarchy - return index <= lowestIndex; - }) - .map((boundary, index) => - boundary?.parentBoundaryType == null ? ( - - - {/* {t(`${hierarchy}_${boundary?.boundaryType}`?.toUpperCase())} */} - {t((hierarchy + "_" + boundary?.boundaryType).toUpperCase())} - - * - -
- item?.boundaryTypeData?.TenantBoundary?.[0]?.boundary)?.flat() || [] - } - optionsKey={"code"} - selected={selectedData?.filter((item) => item?.type === boundary?.boundaryType) || []} - onSelect={(value) => { - handleBoundaryChange(value, boundary); - }} - /> -
-
- ) : ( - - - {t((hierarchy + "_" + boundary?.boundaryType).toUpperCase())} - * - -
- ({ - code: item?.parentCode, - options: - item?.boundaryTypeData?.TenantBoundary?.[0]?.boundary?.map((child) => ({ - code: child?.code, - type: child?.boundaryType, - parent: item?.parentCode, - })) || [], - })) || [] - } - optionsKey={"code"} - onSelect={(value) => { - handleBoundaryChange(value, boundary); - }} - selected={selectedData?.filter((item) => item?.type === boundary?.boundaryType) || []} - addCategorySelectAllCheck={true} - addSelectAllCheck={true} - variant="nestedmultiselect" - /> -
-
- ) - )} -
-
- - {t("HCM_BOUNDARY_INFO ")} - - {mailConfig?.mailId} - - , - ]} - label={"Info"} - /> - {showPopUp && ( - - {t("ES_CAMPAIGN_UPDATE_BOUNDARY_MODAL_TEXT") + " "} - , - ]} - onOverlayClick={() => { - setShowPopUp(false); - }} - footerChildren={[ - - ))} - - ); -}; - -const TabContent = ({ activeSubTab, subTabCount = 3, onSubTabChange, project }) => { - const { campaignData, dispatchCampaignData } = useContext(CycleContext); - const { t } = useTranslation(); - - return ( - - -
- {t(`CAMPAIGN_TAB_TEXT`)} - {t(`CAMPAIGN_TAB_SUB_TEXT_${project?.code ? project?.code?.toUpperCase() : project?.toUpperCase()}`)} -
- {/* Add content specific to each tab as needed */} - , - - {t(`CAMPAIGN_TAB_INFO_TEXT_${project?.code ? project?.code?.toUpperCase() : project?.toUpperCase()}`)} - - ]} - label={"Info"} - /> -
- ); -}; - -const SubTabs = ({ onSubTabChange }) => { - const { campaignData, dispatchCampaignData } = useContext(CycleContext); - const { t } = useTranslation(); - - return ( -
- {campaignData - ?.find((i) => i?.active === true) - ?.deliveries.map((_, index) => ( - - ))} -
- ); -}; - -const MultiTab = ({ tabCount = 3, subTabCount = 2 }) => { - const [activeTab, setActiveTab] = useState(0); - const [activeSubTab, setActiveSubTab] = useState(0); - const { campaignData, dispatchCampaignData } = useContext(CycleContext); - const { t } = useTranslation(); - const tempSession = Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA"); - const handleTabChange = (tabIndex, index) => { - dispatchCampaignData({ - type: "TAB_CHANGE_UPDATE", - payload: { tabIndex: tabIndex, index: index }, // Your updated campaign data - }); - setActiveTab(index); - setActiveSubTab(0); // Reset sub-tab when changing the main tab - }; - - const handleSubTabChange = (subTabIndex, itemIndex) => { - dispatchCampaignData({ - type: "SUBTAB_CHANGE_UPDATE", - payload: { subTabIndex: subTabIndex }, // Your updated campaign data - }); - }; - - return ( - <> -
- {t( - `CAMPAIGN_PROJECT_${ - tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.code - ? tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.code?.toUpperCase() - : tempSession?.HCM_CAMPAIGN_TYPE?.projectType?.toUpperCase() - }` - )} -
- -
-
- -
- - -
- - ); -}; - -export default MultiTab; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/index.js deleted file mode 100644 index ebdf2c5088f..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/deliveryRule/index.js +++ /dev/null @@ -1,531 +0,0 @@ -import React, { createContext, useContext, useEffect, useReducer, useState } from "react"; -import MultiTab from "./MultiTabcontext"; -import { Loader } from "@egovernments/digit-ui-react-components"; -// import { deliveryConfig } from "../../../configs/deliveryConfig"; - -const CycleContext = createContext(); - -function makeSequential(jsonArray, keyName) { - return jsonArray.map((item, index) => ({ - ...item, - [keyName]: index + 1, - })); -} - -function DeliverySetup({ onSelect, config, formData, control, tabCount = 2, subTabCount = 3, ...props }) { - // Campaign Tab Skeleton function - const [cycleData, setCycleData] = useState(config?.customProps?.sessionData?.["HCM_CAMPAIGN_CYCLE_CONFIGURE"]?.cycleConfigure); - const saved = window.Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA")?.HCM_CAMPAIGN_DELIVERY_DATA?.deliveryRule; - const selectedProjectType = window.Digit.SessionStorage.get("HCM_CAMPAIGN_MANAGER_FORM_DATA")?.HCM_CAMPAIGN_TYPE?.projectType?.code; - const tenantId = Digit.ULBService.getCurrentTenantId(); - const searchParams = new URLSearchParams(location.search); - const activeCycle = searchParams.get("activeCycle"); - const { isLoading: deliveryConfigLoading, data: filteredDeliveryConfig } = Digit.Hooks.useCustomMDMS( - tenantId, - "HCM-ADMIN-CONSOLE", - [{ name: "deliveryConfig" }], - { - select: (data) => { - const temp = data?.["HCM-ADMIN-CONSOLE"]?.deliveryConfig; - return temp?.find((i) => i?.projectType === selectedProjectType); - // return deliveryConfig?.find((i) => i?.projectType === selectedProjectType); - }, - } - ); - // const [filteredDeliveryConfig, setFilteredDeliveryConfig] = useState(deliveryConfig?.find((i) => i?.projectType === selectedProjectType)); - // useEffect(() => { - // if (!deliveryConfigLoading) { - // const temp = deliveryConfig?.find((i) => i?.projectType === selectedProjectType); - // setFilteredDeliveryConfig(temp); - // } - // }, [deliveryConfigLoading, filteredDeliveryConfig]); - // const filteredDeliveryConfig = deliveryConfig.find((i) => i.projectType === selectedProjectType); - useEffect(() => { - setCycleData(config?.customProps?.sessionData?.["HCM_CAMPAIGN_CYCLE_CONFIGURE"]?.cycleConfigure); - }, [config?.customProps?.sessionData?.["HCM_CAMPAIGN_CYCLE_CONFIGURE"]?.cycleConfigure]); - - const generateTabsData = (tabs, subTabs) => { - if (!saved || saved?.length === 0) { - return [...Array(tabs)].map((_, tabIndex) => ({ - cycleIndex: `${tabIndex + 1}`, - active: activeCycle == tabIndex + 1 ? true : tabIndex === 0 ? true : false, - deliveries: [...Array(subTabs || 1)].map((_, subTabIndex) => ({ - deliveryIndex: `${subTabIndex + 1}`, - active: subTabIndex === 0 ? true : false, - deliveryRules: - filteredDeliveryConfig?.projectType === "LLIN-mz" - ? filteredDeliveryConfig?.deliveryConfig?.map((item, index) => { - return { - ruleKey: index + 1, - delivery: {}, - attributes: item?.attributeConfig - ? item?.attributeConfig?.map((i, c) => { - if (i?.operatorValue === "IN_BETWEEN") { - return { - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - toValue: i?.fromValue, - fromValue: i?.toValue, - }; - } - return { - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - value: i?.value, - }; - }) - : [{ key: 1, attribute: null, operator: null, value: "" }], - // products: [], - products: item?.productConfig - ? item?.productConfig?.map((i, c) => ({ - ...i, - })) - : [], - }; - }) - : filteredDeliveryConfig && filteredDeliveryConfig?.deliveryConfig?.[subTabIndex] - ? filteredDeliveryConfig?.deliveryConfig?.[subTabIndex]?.conditionConfig?.map((item, index) => { - if (item) { - return { - ruleKey: index + 1, - delivery: {}, - deliveryType: item?.deliveryType, - attributes: item?.attributeConfig - ? item?.attributeConfig?.map((i, c) => { - if (i?.operatorValue === "IN_BETWEEN") { - return { - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - toValue: i?.fromValue, - fromValue: i?.toValue, - }; - } - return { - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - value: i?.value, - }; - }) - : [{ key: 1, attribute: null, operator: null, value: "" }], - // products: [], - products: item?.productConfig - ? item?.productConfig?.map((i, c) => ({ - ...i, - })) - : [], - }; - } else { - return { - ruleKey: index + 1, - delivery: {}, - deliveryType: null, - attributes: [{ key: 1, attribute: null, operator: null, value: "" }], - products: [], - }; - } - }) - : [ - { - ruleKey: 1, - delivery: {}, - attributes: - filteredDeliveryConfig && filteredDeliveryConfig?.attributeConfig - ? filteredDeliveryConfig?.attributeConfig?.map((i, c) => ({ - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - value: i?.value, - })) - : // : filteredDeliveryConfig?.projectType === "LLIN-mz" - // ? filteredDeliveryConfig?.attributeConfig?.map((i, c) => ({ key: c + 1, attribute: i.attrValue, operator: null, value: "" })) - [{ key: 1, attribute: null, operator: null, value: "" }], - products: [], - }, - ], - })), - })); - } - // if no change - if (saved && saved?.length == tabs && saved?.[0]?.deliveries?.length === subTabs) { - return saved.map((i, n) => { - return { - ...i, - active: activeCycle ? (activeCycle == n + 1 ? true : false) : n === 0 ? true : false, - }; - }); - } - // if cycle number decrease - if (saved?.length > tabs) { - // const temp = saved; - saved.splice(tabs); - // return temp; - } - // if cycle number increase - if (tabs > saved?.length) { - // const temp = saved; - for (let i = saved.length + 1; i <= tabs; i++) { - const newIndex = i.toString(); - saved.push({ - cycleIndex: newIndex, - active: false, - deliveries: [...Array(subTabs || 1)].map((_, subTabIndex) => ({ - deliveryIndex: `${subTabIndex + 1}`, - active: subTabIndex === 0, - deliveryRules: - filteredDeliveryConfig?.projectType === "LLIN-mz" - ? filteredDeliveryConfig?.deliveryConfig?.map((item, index) => { - return { - ruleKey: index + 1, - delivery: {}, - attributes: item?.attributeConfig - ? item?.attributeConfig?.map((i, c) => { - if (i?.operatorValue === "IN_BETWEEN") { - return { - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - toValue: i?.fromValue, - fromValue: i?.toValue, - }; - } - return { - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - value: i?.value, - }; - }) - : [{ key: 1, attribute: null, operator: null, value: "" }], - // products: [], - products: item?.productConfig - ? item?.productConfig?.map((i, c) => ({ - ...i, - })) - : [], - }; - }) - : filteredDeliveryConfig && filteredDeliveryConfig?.deliveryConfig?.[subTabIndex]?.conditionConfig - ? filteredDeliveryConfig?.deliveryConfig?.[subTabIndex]?.conditionConfig?.map((item, index) => { - if (item) { - return { - ruleKey: index + 1, - delivery: {}, - deliveryType: item?.deliveryType, - attributes: item?.attributeConfig - ? item?.attributeConfig?.map((i, c) => { - if (i?.operatorValue === "IN_BETWEEN") { - return { - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - toValue: i?.fromValue, - fromValue: i?.toValue, - }; - } - return { - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - value: i?.value, - }; - }) - : [{ key: 1, attribute: null, operator: null, value: "" }], - // products: [], - products: item?.productConfig - ? item?.productConfig?.map((i, c) => ({ - ...i, - })) - : [], - }; - } else { - return { - ruleKey: index + 1, - delivery: {}, - deliveryType: null, - attributes: [{ key: 1, attribute: null, operator: null, value: "" }], - products: [], - }; - } - }) - : [ - { - ruleKey: 1, - delivery: {}, - deliveryType: null, - attributes: - // filteredDeliveryConfig?.projectType === "MR-DN" - // ? filteredDeliveryConfig?.attributeConfig?.map((i, c) => ({ - // key: c + 1, - // attribute: { code: i?.attrValue }, - // operator: { code: i?.operatorValue }, - // value: i?.value, - // })) - // : filteredDeliveryConfig?.projectType === "LLIN-mz" - // ? filteredDeliveryConfig?.attributeConfig?.map((i, c) => ({ - // key: c + 1, - // attribute: i.attrValue, - // operator: null, - // value: "", - // })) - // : - [{ key: 1, attribute: null, operator: null, value: "" }], - // products: [], - products: [], - }, - ], - })), - }); - } - // return temp; - } - // if delivery number decrease - - saved.forEach((cycle) => { - // Remove deliveries if there are more deliveries than the specified number - if (cycle.deliveries.length > subTabs) { - cycle.deliveries.splice(subTabs); - } - - // Add deliveries if there are fewer deliveries than the specified number - if (subTabs > cycle.deliveries.length) { - for (let i = cycle.deliveries.length + 1; i <= subTabs; i++) { - const newIndex = i.toString(); - cycle.deliveries.push({ - deliveryIndex: newIndex, - active: false, - deliveryRules: - filteredDeliveryConfig?.projectType === "LLIN-mz" - ? filteredDeliveryConfig?.deliveryConfig?.map((item, index) => { - return { - ruleKey: index + 1, - delivery: {}, - attributes: item?.attributeConfig - ? item?.attributeConfig?.map((i, c) => { - if (i?.operatorValue === "IN_BETWEEN") { - return { - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - toValue: i?.fromValue, - fromValue: i?.toValue, - }; - } - return { - key: c + 1, - attribute: { code: i?.attrValue }, - operator: { code: i?.operatorValue }, - value: i?.value, - }; - }) - : [{ key: 1, attribute: null, operator: null, value: "" }], - // products: [], - products: item?.productConfig - ? item?.productConfig?.map((i, c) => ({ - ...i, - })) - : [], - }; - }) - : [ - { - ruleKey: 1, - delivery: {}, - attributes: [{ key: 1, attribute: null, operator: null, value: "" }], - products: [], - }, - ], - }); - } - } - }); - - return saved; - // if delivery number increase - - //if no above case - }; - - // Reducer function - const campaignDataReducer = (state, action) => { - switch (action.type) { - case "GENERATE_CAMPAIGN_DATA": - return generateTabsData(action.cycle, action.deliveries); - case "UPDATE_CAMPAIGN_DATA": - const changeUpdate = state.map((i) => { - if (i.active) { - const activeDelivery = i.deliveries.find((j) => j.active === true); - if (activeDelivery) { - return { - ...i, - deliveries: i.deliveries.map((j) => ({ - ...j, - deliveryRules: j.active ? action.payload.currentDeliveryRules : j.deliveryRules, - })), - }; - } - } - return i; - }); - return changeUpdate; - case "TAB_CHANGE_UPDATE": - const temp = state.map((i) => ({ - ...i, - active: i.cycleIndex == action.payload.tabIndex ? true : false, - })); - return temp; - // return action.payload; - case "SUBTAB_CHANGE_UPDATE": - const tempSub = state.map((camp, index) => { - if (camp.active === true) { - return { - ...camp, - deliveries: camp.deliveries.map((deliver) => ({ - ...deliver, - active: deliver.deliveryIndex == action.payload.subTabIndex ? true : false, - })), - }; - } - return camp; - }); - return tempSub; - case "ADD_DELIVERY_RULE": - const updatedDeliveryRules = [ - ...action.payload.currentDeliveryRules, - { - ruleKey: action.payload.currentDeliveryRules.length + 1, - delivery: {}, - attributes: [{ key: 1, attribute: null, operator: null, value: "" }], - products: [], - }, - ]; - const updatedData = state.map((i) => { - if (i.active) { - const activeDelivery = i.deliveries.find((j) => j.active); - if (activeDelivery) { - return { - ...i, - deliveries: i.deliveries.map((j) => ({ - ...j, - deliveryRules: j.active ? updatedDeliveryRules : j.deliveryRules, - })), - }; - } - } - return i; - }); - return updatedData; - case "REMOVE_DELIVERY_RULE": - const updatedDeleted = state.map((i) => { - if (i.active) { - const activeDelivery = i.deliveries.find((j) => j.active); - const w = makeSequential( - activeDelivery.deliveryRules.filter((j) => j.ruleKey != action.payload.item.ruleKey), - "ruleKey" - ); - if (activeDelivery) { - return { - ...i, - deliveries: i.deliveries.map((j) => ({ - ...j, - deliveryRules: j.active ? w : j.deliveryRules, - })), - }; - } - } - return i; - }); - return updatedDeleted; - case "UPDATE_DELIVERY_RULE": - return action.payload; - case "ADD_ATTRIBUTE": - return action.payload; - case "REMOVE_ATTRIBUTE": - return action.payload; - case "UPDATE_ATTRIBUTE": - return action.payload; - case "ADD_PRODUCT": - const prodTemp = action.payload.productData.map((i) => ({ ...i, value: i?.value?.id, name: i?.value?.displayName })); - const updatedState = state.map((cycle) => { - if (cycle.active) { - const updatedDeliveries = cycle.deliveries.map((dd) => { - if (dd.active) { - const updatedRules = dd.deliveryRules.map((rule) => { - if (rule.ruleKey === action.payload.delivery.ruleKey) { - return { - ...rule, - products: [...rule.products, ...prodTemp], - }; - } - return rule; - }); - return { - ...dd, - deliveryRules: updatedRules, - }; - } - return dd; - }); - return { - ...cycle, - deliveries: updatedDeliveries, - }; - } - return cycle; - }); - return updatedState; - case "REMOVE_PRODUCT": - return action.payload; - case "UPDATE_PRODUCT": - return action.payload; - default: - return state; - } - }; - - const [campaignData, dispatchCampaignData] = useReducer( - campaignDataReducer, - generateTabsData(cycleData?.cycleConfgureDate?.cycle, cycleData?.cycleConfgureDate?.deliveries) - ); - const [executionCount, setExecutionCount] = useState(0); - - useEffect(() => { - dispatchCampaignData({ - type: "GENERATE_CAMPAIGN_DATA", - cycle: cycleData?.cycleConfgureDate?.cycle, - deliveries: cycleData?.cycleConfgureDate?.deliveries, - }); - }, [cycleData]); - - useEffect(() => { - onSelect("deliveryRule", campaignData); - }, [campaignData]); - - useEffect(() => { - if (executionCount < 5) { - onSelect("deliveryRule", campaignData); - setExecutionCount((prevCount) => prevCount + 1); - } - }); - - if (deliveryConfigLoading) { - return ; - } - return ( - - - - ); -} - -export default DeliverySetup; -export { CycleContext }; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/index.js deleted file mode 100644 index 2353f85fc50..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/pages/employee/index.js +++ /dev/null @@ -1,102 +0,0 @@ -import React, { useEffect } from "react"; -import { Switch, useLocation } from "react-router-dom"; -import { useTranslation } from "react-i18next"; -import { PrivateRoute, AppContainer, BreadCrumb } from "@egovernments/digit-ui-react-components"; -// import CampaignHeader from "../../components/CampaignHeader"; -import SetupCampaign from "./SetupCampaign"; -import SelectingBoundaries from "../../components/SelectingBoundaries"; - -/** - * The CampaignBreadCrumb function generates breadcrumb navigation for a campaign setup page in a React - * application. - * @returns The CampaignBreadCrumb component is returning a BreadCrumb component with the specified - * crumbs array and spanStyle prop. The crumbs array contains two objects with path, content, and show - * properties for each breadcrumb item. The spanStyle prop is set to { maxWidth: "min-content" }. - */ -const CampaignBreadCrumb = ({ location, defaultPath }) => { - const { t } = useTranslation(); - const search = useLocation().search; - const pathVar = location.pathname.replace(defaultPath + "/", "").split("?")?.[0]; - - const crumbs = [ - { - path: `/${window?.contextPath}/employee`, - content: t("CAMPAIGN_HOME"), - show: true, - }, - { - path: pathVar === "my-campaign" ? "" : `/${window?.contextPath}/employee/campaign/my-campaign`, - content: t("MY_CAMPAIGN"), - show: pathVar === "my-campaign" ? true : false, - }, - { - path: pathVar === "setup-campaign" ? "" : `/${window?.contextPath}/employee/campaign/setup-campaign`, - content: t("CREATE_NEW_CAMPAIGN"), - show: pathVar === "setup-campaign" ? true : false, - }, - ]; - - return ; -}; - -/** - * The `App` function in JavaScript defines a component that handles different routes and renders - * corresponding components based on the path provided. - * @returns The `App` component is returning a JSX structure that includes a `div` with a className of - * "wbh-header-container" containing a `CampaignBreadCrumb` component and a `Switch` component. Inside - * the `Switch` component, there are several `PrivateRoute` components with different paths and - * corresponding components such as `UploadBoundaryData`, `CycleConfiguration`, `DeliveryRule`, ` - */ -const App = ({ path, BOUNDARY_HIERARCHY_TYPE }) => { - const location = useLocation(); - const UploadBoundaryData = Digit?.ComponentRegistryService?.getComponent("UploadBoundaryData"); - const CycleConfiguration = Digit?.ComponentRegistryService?.getComponent("CycleConfiguration"); - const DeliveryRule = Digit?.ComponentRegistryService?.getComponent("DeliveryRule"); - const MyCampaign = Digit?.ComponentRegistryService?.getComponent("MyCampaign"); - const CampaignSummary = Digit?.ComponentRegistryService?.getComponent("CampaignSummary"); - const Response = Digit?.ComponentRegistryService?.getComponent("Response"); - const AddProduct = Digit?.ComponentRegistryService?.getComponent("AddProduct"); - - useEffect(() => { - if (window.location.pathname !== "/workbench-ui/employee/campaign/setup-campaign") { - window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA"); - window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_UPLOAD_ID"); - } - if (window.location.pathname === "/workbench-ui/employee/campaign/response") { - window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA"); - window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_UPLOAD_ID"); - } - return () => { - if (window.location.pathname !== "/workbench-ui/employee/campaign/setup-campaign") { - window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_FORM_DATA"); - window.Digit.SessionStorage.del("HCM_CAMPAIGN_MANAGER_UPLOAD_ID"); - } - }; - }, []); - return ( - -
- {window?.location?.pathname === "/workbench-ui/employee/campaign/add-product" || - window?.location?.pathname === "/workbench-ui/employee/campaign/response" ? null : ( - - )} - {/* */} -
- - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - -
- ); -}; - -export default App; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/TourSteps.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/TourSteps.js deleted file mode 100644 index 5ab880c52cf..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/TourSteps.js +++ /dev/null @@ -1,144 +0,0 @@ -export const TourSteps = { - '/workbench-ui/employee/workbench/manage-master-data':[ - { - content: - 'Welcome to Manage Master Data screen. Here you can search and update any master data that is configured for the logged in user tenant', - target: '.manage-master-wrapper', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - }, - { - content: - 'Select any module name where the master is present', - target: '.wbh-mdms-module-name', - disableBeacon: true, - placement: 'center', - title:"Manage Master Data" - }, - - { - content: - 'Select any master name where the master is present', - target: '.wbh-mdms-master-name', - disableBeacon: true, - placement: 'center', - title:"Manage Master Data" - }, - ], - '/workbench-ui/employee/workbench/mdms-search-v2':[ - { - content: - 'Welcome to the master data search screen. Here you can search the master data added under this master', - target: '.search-wrapper', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - }, - { - content: - 'Select any field value and enter the text by which data can be filtered', - target: '.label-field-pair', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - }, - { - content: - 'Filter the master data by clicking on this search by selecting any field and exact value', - target: '.search-button-wrapper', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - }, - { - content: - 'To add new master data under this master click on the Add Master Data button', - target: '.mdms-add-btn', - disableBeacon: true, - placement: 'auto', - title:"Manage Master Data" - }, - - ], - '/workbench-ui/employee/workbench/mdms-add-v2':[ - { - content: - 'Welcome to the master data search screen. Here you can search the master data added under this master', - target: '.field-string', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - }, - { - content: - 'select the Reference master data', - target: '.form-select ', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - }, - { - content: - 'Fill all the details by clicking on the Add Master Data', - target: '.submit-bar', - disableBeacon: true, - placement: 'auto', - title:"Manage Master Data" - }, - - ], - '/workbench-ui/employee/workbench/mdms-view':[ - { - content: - 'Welcome to the master data search screen. Here you can search the master data added under this master', - target: '.action-bar-wrap', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - }, - { - content: - 'select the Reference master data', - target: '.menu-wrap', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - } - ], - '/workbench-ui/employee/workbench/localisation-search':[ - { - content: - 'Welcome to the master data search screen. Here you can search the master data added under this master', - target: '.search-wrapper', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - }, - { - content: - 'Select any field value and enter the text by which data can be filtered', - target: '.label-field-pair', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - }, - { - content: - 'Filter the master data by clicking on this search by selecting any field and exact value', - target: '.search-button-wrapper', - disableBeacon: true, - placement: 'bottom', - title:"Manage Master Data" - }, - { - content: - 'To add new master data under this master click on the Add Master Data button', - target: '.mdms-add-btn', - disableBeacon: true, - placement: 'auto', - title:"Manage Master Data" - }, - - ], -} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/downloadExcel.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/downloadExcel.js deleted file mode 100644 index 978ea2bfd74..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/downloadExcel.js +++ /dev/null @@ -1,46 +0,0 @@ -import axios from "axios"; - -/* Fetching sheet as json object from the API , converting them into blob and downloading it. - * Way to use the function. Just import the funtion downloadExcelWithCustomName and pass the filestoreid and customName you want to download the file. - * Rest this function will take care for you and download it in your system. - * - * Eg. -> - * const handleDownload = (id, name) => { - * downloadExcelWithCustomName({fileStoreId: id, customName: name}); - * } - * - */ - -export const downloadExcelWithCustomName = ({ fileStoreId = null, customName = null }) => { - const downloadExcel = (blob, fileName) => { - const link = document.createElement("a"); - link.href = URL.createObjectURL(blob); - link.download = fileName + ".xlsx"; - document.body.append(link); - link.click(); - link.remove(); - setTimeout(() => URL.revokeObjectURL(link.href), 7000); - }; - - if (fileStoreId) { - axios - .get("/filestore/v1/files/id", { - responseType: "arraybuffer", - headers: { - "Content-Type": "application/json", - Accept: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - "auth-token": Digit.UserService.getUser()?.["access_token"], - }, - params: { - tenantId: Digit.ULBService.getCurrentTenantId(), - fileStoreId: fileStoreId, - }, - }) - .then(async (res) => { - downloadExcel( - new Blob([res.data], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }), - customName ? customName : "download" - ); - }); - } -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/index.js deleted file mode 100644 index 5e308bf82f7..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/campaign-manager/src/utils/index.js +++ /dev/null @@ -1,6 +0,0 @@ -import _ from "lodash"; -import { downloadExcelWithCustomName } from "./downloadExcel"; - -export default {}; -export { downloadExcelWithCustomName }; -export const PRIMARY_COLOR = "#C84C0E"; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/package.json b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/package.json deleted file mode 100644 index 6fcb736c4e5..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/package.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "name": "@egovernments/digit-ui-module-hcmmicroplanning", - "version": "0.0.1", - "description": "HCM-Microplanning", - "main": "dist/index.js", - "module": "dist/index.modern.js", - "source": "src/Module.js", - "files": [ - "dist" - ], - "scripts": { - "start": "microbundle-crl watch --no-compress --format modern,cjs", - "build": "microbundle-crl --compress --no-sourcemap --format cjs", - "prepublish": "yarn build" - }, - "peerDependencies": { - "react": "17.0.2", - "react-router-dom": "5.3.0" - }, - "dependencies": { - "@cyntler/react-doc-viewer": "1.10.3", - "@egovernments/digit-ui-components": "0.0.2-beta.2", - "@egovernments/digit-ui-react-components": "1.8.2-beta.4", - "@egovernments/digit-ui-svg-components": "1.0.8", - "@rjsf/core": "5.10.0", - "@rjsf/utils": "5.10.0", - "@rjsf/validator-ajv8": "5.10.0", - "@turf/turf": "^6.5.0", - "ajv": "^8.12.0", - "axios": "^1.6.8", - "chroma-js": "^2.4.2", - "exceljs": "^4.4.0", - "focus-trap-react": "^10.2.3", - "geojson-validation": "^1.0.2", - "jszip": "^3.10.1", - "leaflet": "^1.9.4", - "react": "17.0.2", - "react-date-range": "^1.4.0", - "react-dom": "17.0.2", - "react-drag-drop-files": "^2.3.10", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-joyride": "2.5.5", - "react-query": "3.6.1", - "react-router-dom": "5.3.0", - "react-select": "5.7.4", - "safe-buffer": "^5.2.1", - "shpjs": "^4.0.4", - "uuid": "^9.0.1", - "xlsx": "0.17.5" - }, - "license": "MIT", - "keywords": [ - "digit", - "egov", - "dpg", - "digit-ui", - "workbench", - "workbench-hcm", - "hcm-microplanning" - ] -} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/Module.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/Module.js deleted file mode 100644 index b27e7b19922..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/Module.js +++ /dev/null @@ -1,99 +0,0 @@ -import { Loader, TourProvider } from "@egovernments/digit-ui-react-components"; -import React from "react"; -import { useRouteMatch } from "react-router-dom"; -import EmployeeApp from "./pages/employee"; -import { CustomisedHooks } from "./hooks"; -import { UICustomizations } from "./configs/UICustomizations"; -// import WorkbenchCard from "./components/WorkbenchCard"; -import MicroplanningCard from "./components/MicroplanningCard"; -import MicroplanDetails from "./components/MicroplanDetails"; -import { ProviderContext } from "./utils/context"; - -const MicroplanningModule = ({ stateCode, userType, tenants }) => { - const tenantId = Digit.ULBService.getCurrentTenantId(); - const { data: BOUNDARY_HIERARCHY_TYPE } = Digit.Hooks.useCustomMDMS(tenantId, "HCM-ADMIN-CONSOLE", [{ name: "hierarchyConfig" }], { - select: (data) => { - return data?.["HCM-ADMIN-CONSOLE"]?.hierarchyConfig?.[0]?.hierarchy; - }, - }); - const moduleCode = ["Microplanning", `boundary-${BOUNDARY_HIERARCHY_TYPE}`, "hcm-admin-schemas"]; - const { path, url } = useRouteMatch(); - const language = Digit.StoreData.getCurrentLanguage(); - const { isLoading, data: store } = Digit.Services.useStore({ - stateCode, - moduleCode, - language, - }); - - if (isLoading) { - return ; - } - - return ( - - - - - - ); -}; - -const componentsToRegister = { - MicroplanningModule, - MicroplanningCard, - MicroplanDetails, - // DigitJSONForm, - // DSSCard: null, // TO HIDE THE DSS CARD IN HOME SCREEN as per workbench - // HRMSCard // Overridden the HRMS card as per workbench -}; - -const overrideHooks = () => { - Object.keys(CustomisedHooks).map((ele) => { - if (ele === "Hooks") { - Object.keys(CustomisedHooks[ele]).map((hook) => { - Object.keys(CustomisedHooks[ele][hook]).map((method) => { - setupHooks(hook, method, CustomisedHooks[ele][hook][method]); - }); - }); - } else if (ele === "Utils") { - Object.keys(CustomisedHooks[ele]).map((hook) => { - Object.keys(CustomisedHooks[ele][hook]).map((method) => { - setupHooks(hook, method, CustomisedHooks[ele][hook][method], false); - }); - }); - } else { - Object.keys(CustomisedHooks[ele]).map((method) => { - setupLibraries(ele, method, CustomisedHooks[ele][method]); - }); - } - }); -}; - -/* To Overide any existing hook we need to use similar method */ -const setupHooks = (HookName, HookFunction, method, isHook = true) => { - window.Digit = window.Digit || {}; - window.Digit[isHook ? "Hooks" : "Utils"] = window.Digit[isHook ? "Hooks" : "Utils"] || {}; - window.Digit[isHook ? "Hooks" : "Utils"][HookName] = window.Digit[isHook ? "Hooks" : "Utils"][HookName] || {}; - window.Digit[isHook ? "Hooks" : "Utils"][HookName][HookFunction] = method; -}; -/* To Overide any existing libraries we need to use similar method */ -const setupLibraries = (Library, service, method) => { - window.Digit = window.Digit || {}; - window.Digit[Library] = window.Digit[Library] || {}; - window.Digit[Library][service] = method; -}; - -/* To Overide any existing config/middlewares we need to use similar method */ -const updateCustomConfigs = () => { - setupLibraries("Customizations", "commonUiConfig", { ...window?.Digit?.Customizations?.commonUiConfig, ...UICustomizations }); -}; - -const initMicroplanningComponents = () => { - overrideHooks(); - updateCustomConfigs(); - Object.entries(componentsToRegister).forEach(([key, value]) => { - Digit.ComponentRegistryService.setComponent(key, value); - }); -}; - -export { initMicroplanningComponents }; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CommonComponents.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CommonComponents.js deleted file mode 100644 index a358dbbedb1..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CommonComponents.js +++ /dev/null @@ -1,61 +0,0 @@ -import { AutoRenew, Close, FileDownload } from "@egovernments/digit-ui-svg-components"; -import React, { useCallback } from "react"; -import PropTypes from "prop-types"; - -export const ButtonType1 = (props) => { - return ( -
-

{props.text}

-
- ); -}; - -ButtonType1.propTypes = { - text: PropTypes.string.isRequired, -}; - -export const ButtonType2 = (props) => { - return ( -
- {props.showDownloadIcon && ( -
- -
- )} -

{props.text}

-
- ); -}; - -ButtonType2.propTypes = { - text: PropTypes.string.isRequired, - showDownloadIcon: PropTypes.bool, -}; - -export const ModalHeading = (props) => { - return ( -

- {props.label} -

- ); -}; - -ModalHeading.propTypes = { - label: PropTypes.string.isRequired, - className: PropTypes.string, - style: PropTypes.object, -}; - -export const CloseButton = ({ clickHandler, style = {} }) => { - return ( - - ); -}; - -CloseButton.propTypes = { - clickHandler: PropTypes.func.isRequired, - style: PropTypes.object, -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CustomScaleControl.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CustomScaleControl.js deleted file mode 100644 index f2deacbd46d..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/CustomScaleControl.js +++ /dev/null @@ -1,41 +0,0 @@ -import React, { useEffect, useState } from "react"; - -const CustomScaleControl = ({ map }) => { - if (!map) return null; - const [scaleText, setScaleText] = useState(""); - // Function to calculate and update the scale text - const updateScale = () => { - // Calculate the scale based on the map's current zoom level - const maxWidthMeters = map.containerPointToLatLng([0, map.getSize().y]).distanceTo(map.containerPointToLatLng([100, map.getSize().y])); - const scale = maxWidthMeters / 1000; // Convert to kilometers - - // Format the scale text - const scaleTextData = scale < 1 ? `${Math.round(scale * 1000)} m` : `${Math.round(Math.round(scale.toFixed(0) / 10) * 10)} km`; - - // Update the scale text in the container element - setScaleText(scaleTextData); - }; - - // Effect to update the scale text when the map component mounts and on map zoom change - useEffect(() => { - // Update the scale text initially - updateScale(); - - // Register the map's zoom events to update the scale text - map.on("zoomend", updateScale); - - // Clean up event listener when the component unmounts - return () => { - map.off("zoomend", updateScale); - }; - }, [map]); - - return ( -
- {scaleText} - - ); -}; - -export default CustomScaleControl; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Hypothesis.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Hypothesis.js deleted file mode 100644 index c2cf8bac4fb..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Hypothesis.js +++ /dev/null @@ -1,607 +0,0 @@ -import React, { useState, useEffect, useCallback, Fragment, useRef } from "react"; -import { useTranslation } from "react-i18next"; -import { Trash } from "@egovernments/digit-ui-svg-components"; -import { CloseButton, ModalHeading } from "./CommonComponents"; -import { Dropdown, TextInput, Toast } from "@egovernments/digit-ui-components"; -import { useMyContext } from "../utils/context"; -import { tourSteps } from "../configs/tourSteps"; -import { v4 as uuidv4 } from "uuid"; -import { PlusWithSurroundingCircle } from "../icons/Svg"; -import { PRIMARY_THEME_COLOR } from "../configs/constants"; -import { Button, Modal } from "@egovernments/digit-ui-react-components"; -const page = "hypothesis"; - -const Hypothesis = ({ - campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, - microplanData, - setMicroplanData, - checkDataCompletion, - setCheckDataCompletion, - currentPage, - pages, - setToast, -}) => { - const { t } = useTranslation(); - - // States - const [editable, setEditable] = useState(true); - const [modal, setModalState] = useState("none"); - const [assumptions, setAssumptions] = useState([]); - const [hypothesisAssumptionsList, setHypothesisAssumptionsList] = useState([]); - const [itemForDeletion, setItemForDeletion] = useState(); - const [exampleOption, setExampleOption] = useState(""); - // const [toast, setToast] = useState(); - const [autofillHypothesis, setAutofillHypothesis] = useState([]); - const { state, dispatch } = useMyContext(); - const [orignalHypothesisCount, setOrignalHypothesisCount] = useState(0); - - // Set TourSteps - useEffect(() => { - const tourData = tourSteps(t)?.[page] || {}; - if (state?.tourStateData?.name === page) return; - dispatch({ - type: "SETINITDATA", - state: { tourStateData: tourData }, - }); - }, []); - - const setModal = (modalString) => { - const elements = document.querySelectorAll(".popup-wrap-rest-unfocus"); - elements.forEach((element) => { - element.classList.toggle("popup-wrap-rest-unfocus-active"); - }); - setModalState(modalString); - }; - - // UseEffect to extract data on first render - useEffect(() => { - if (pages) { - const previouspage = pages[currentPage?.id - 1]; - if (previouspage?.checkForCompleteness && !microplanData?.status?.[previouspage?.name]) setEditable(false); - else setEditable(true); - } - if (microplanData?.hypothesis) { - const temp = microplanData?.hypothesis; - setAssumptions(temp); - } - - fetchDataAndUpdateState(); - }, []); - - const fetchDataAndUpdateState = useCallback(() => { - const hypothesisAssumptions = state?.HypothesisAssumptions || []; - const temp = hypothesisAssumptions.find((item) => item.campaignType === campaignType); - if (!temp?.assumptions) return; - - const hypothesisAssumptionsList = Array.isArray(temp.assumptions) ? temp.assumptions : []; - setOrignalHypothesisCount(hypothesisAssumptionsList.length); - setExampleOption(hypothesisAssumptionsList.length !== 0 ? hypothesisAssumptionsList[0] : ""); - - const currentHypothesis = microplanData?.hypothesis || assumptions; - const newAssumptions = setAutofillHypothesisData(hypothesisAssumptionsList, currentHypothesis, setAssumptions); - - const newHypothesislist = filterHypothesisList( - newAssumptions.length !== 0 ? newAssumptions : microplanData.hypothesis, - hypothesisAssumptionsList - ); - setHypothesisAssumptionsList(newHypothesislist); - }, [campaignType, microplanData, state, assumptions, setAssumptions]); - - // UseEffect for checking completeness of data before moveing to next section - useEffect(() => { - if (!assumptions || checkDataCompletion !== "true" || !setCheckDataCompletion) return; - // uncomment to activate data change save check - // if (!microplanData?.hypothesis || !_.isEqual(assumptions, microplanData.hypothesis)) setModal("data-change-check"); - // else - updateData(true); - }, [checkDataCompletion]); - - // UseEffect to store current data - useEffect(() => { - if (!assumptions || !setMicroplanData) return; - setMicroplanData((previous) => ({ ...previous, hypothesis: assumptions })); - }, [assumptions]); - - // UseEffect to add a event listener for keyboard - useEffect(() => { - window.addEventListener("keydown", handleKeyPress); - - return () => window.removeEventListener("keydown", handleKeyPress); - }, [modal]); - - const handleKeyPress = (event) => { - // if (modal !== "upload-guidelines") return; - if (["x", "Escape"].includes(event.key)) { - // Perform the desired action when "x" or "esc" is pressed - // if (modal === "upload-guidelines") - setCheckDataCompletion("false"); - setModal("none"); - } - }; - - // check if data has changed or not - const updateData = useCallback( - (check) => { - if (!assumptions || !setMicroplanData) return; - if (check) { - if (assumptions.some((item) => item.active && parseFloat(item.value) === 0)) { - setToast({ state: "error", message: t("ERROR_HYPOTHESIS_VALUE_SHOULD_NOT_BE_ZERO") }); - setCheckDataCompletion("false"); - return; - } - let newAssumptions = assumptions.map((item) => { - if (parseFloat(item.value) === 0) { - return { ...item, value: 0.01 }; - } - return item; - }); - setMicroplanData((previous) => ({ ...previous, hypothesis: newAssumptions })); - setAssumptions(newAssumptions); - let checkValid = validateAssumptions(assumptions); - checkValid = checkValid && assumptions.filter((subItem) => subItem?.active).length !== 0; - if (checkValid) setCheckDataCompletion("valid"); - else setCheckDataCompletion("invalid"); - } else { - let checkValid = microplanData?.hypothesis?.every((item) => Object.values(item).every((data) => data !== "")); - checkValid = checkValid && assumptions.length !== 0; - if (checkValid) setCheckDataCompletion("valid"); - else setCheckDataCompletion("invalid"); - } - }, - [assumptions, setMicroplanData, microplanData, setCheckDataCompletion] - ); - - const validateAssumptions = useCallback((assumptions) => { - return assumptions.filter((item) => item?.active).every((item) => Object.values(item).every((data) => data !== "")) && assumptions.length !== 0; - }, []); - - const cancelUpdateData = useCallback(() => { - setCheckDataCompletion("false"); - setModal("none"); - }, [setCheckDataCompletion, setModal]); - - const closeModal = useCallback(() => { - setModal("none"); - }, []); - - // Function to Delete an assumption - const deleteAssumptionHandlerCallback = useCallback(() => { - deleteAssumptionHandler(itemForDeletion, setItemForDeletion, setAssumptions, setHypothesisAssumptionsList, setToast, t); - closeModal(); - }, [itemForDeletion, deleteAssumptionHandler, setItemForDeletion, setAssumptions, setHypothesisAssumptionsList, closeModal, setToast, t]); - - const sectionClass = `jk-header-btn-wrapper hypothesis-section ${editable ? "" : "non-editable-component"} popup-wrap-rest-unfocus `; - - return ( - <> -
-
- {/* NonInterractable Section */} - - {/* Interractable Section that includes the example as well as the assumptions */} - -
-
-
- {modal === "delete-conformation" && ( - } - actionCancelLabel={t("YES")} - actionCancelOnSubmit={deleteAssumptionHandlerCallback} - actionSaveLabel={t("NO")} - actionSaveOnSubmit={closeModal} - > -
-

{t("HYPOTHESIS_INSTRUCTIONS_DELETE_ENTRY_CONFIRMATION")}

-
-
- )} -
- - ); -}; - -// Function to add a new assumption -const addAssumptionsHandler = (setAssumptions) => { - const uuid = uuidv4(); - setAssumptions((previous) => [ - ...previous, - { - id: uuid, - // previous.length ? previous[previous.length - 1].id + 1 : 0, - key: "", - value: "", - active: true, - }, - ]); -}; - -// Defination for NonInterractable Section -const NonInterractableSection = React.memo(({ t }) => { - return ( -
-

{t("HEADING_HYPOTHESIS")}

-

{t("INSTRUCTION_HYPOTHESIS")}

-
- ); -}); - -// Defination for NonInterractable Section -const InterractableSection = React.memo( - ({ assumptions, setAssumptions, hypothesisAssumptionsList, setHypothesisAssumptionsList, setModal, setItemForDeletion, exampleOption, t }) => { - const itemRefs = useRef([]); - const [expandedIndex, setExpandedIndex] = useState(null); - const scrollContainerRef = useRef(null); - const [renderCycle, setRenderCycle] = useState(0); - - useEffect(() => { - if (expandedIndex !== null) { - setRenderCycle(0); // Reset render cycle count when expandedIndex changes - } - }, [expandedIndex]); - - useEffect(() => { - // Scroll to the expanded item after the state has updated and the DOM has re-rendered - if (renderCycle < 2) { - setRenderCycle((prev) => prev + 1); // Increment render cycle count - } else if (expandedIndex !== null && itemRefs.current[expandedIndex]) { - try { - const parentElement = itemRefs.current[expandedIndex]; - const childElement = itemRefs.current[expandedIndex].children[1]; - - if (parentElement) { - const scrollContainer = scrollContainerRef.current; - const parentRect = parentElement.getBoundingClientRect(); - const containerRect = scrollContainer.getBoundingClientRect(); - - // Calculate the offset from the top of the container - const offset = parentRect.top - containerRect.top; - - // Scroll the container - scrollContainer.scrollTo({ - top: scrollContainer.scrollTop + offset - 10, - behavior: "smooth", - }); - } - - if (childElement) { - childElement.focus(); - } - } catch (error) { - console.error("Error scrolling to element:", error); - } - } - }, [renderCycle, expandedIndex]); - - useEffect(() => { - if (expandedIndex !== null) { - const observer = new MutationObserver(() => { - setRenderCycle((prev) => prev + 1); // Trigger render cycle when the DOM changes - }); - - if (itemRefs.current[expandedIndex]) { - observer.observe(itemRefs.current[expandedIndex], { childList: true, subtree: true }); - } - - return () => observer.disconnect(); - } - }, [expandedIndex]); - - const toggleExpand = (index) => { - setExpandedIndex(index === expandedIndex ? null : index); - }; - - // Handler for deleting an assumption on conformation - const deleteHandler = useCallback( - (item) => { - setModal("delete-conformation"); - setItemForDeletion(item); - }, - [setModal, setItemForDeletion] - ); - - return ( -
- -
-
-
-

{t("KEY")}

-
-
-

{t("VALUE")}

-
-
- -
-
- {assumptions - ?.filter((item) => item.active) - ?.map((item, index) => ( -
item.active)?.length - 1 ? "last-container" : "" - } `} - > -
{ - itemRefs.current[index] = el; - }} - onClick={() => { - toggleExpand(index); - }} - > - -
-
- -
-
- ))} -
-
- ); - } -); - -const Example = ({ exampleOption, t }) => { - return ( -
-

{t("EXAMPLE")}

-
-
-

{t("KEY")}

- -

{t("HYPOTHESIS_KEY_HELP_TEXT")}

-
-
-

{t("VALUE")}

- -

{t("HYPOTHESIS_VALUE_HELP_TEXT")}

-
-
-
- ); -}; - -const deleteAssumptionHandler = (item, setItemForDeletion, setAssumptions, setHypothesisAssumptionsList, setToast, t) => { - let add = true; - setAssumptions((previous) => { - if (!previous.length) return []; - if (previous.filter((item) => item.active)?.length <= 1) { - setToast({ state: "error", message: t("ERROR_CANNOT_DELETE_LAST_HYPOTHESIS") }); - add = false; - return previous; - } - // const filteredData = previous.filter((data) => data.id !== item.id); - const deletionElementIndex = previous.findIndex((data) => data.id === item.id); - const filteredData = previous.map((data, index) => (index === deletionElementIndex ? { ...data, active: false } : data)); - return filteredData || []; - }); - if (add && item && item.key) - setHypothesisAssumptionsList((previous) => { - if (!previous.includes(item.key)) return [...previous, item.key]; - return previous; // Return previous array if key already exists - }); - setItemForDeletion(); -}; - -const Select = React.memo(({ item, assumptions, setAssumptions, disabled = false, options, setOptions, t }) => { - const [selected, setSelected] = useState(); - const [filteredOptions, setFilteredOptions] = useState([]); - - useEffect(() => { - if (item?.key) setSelected({ code: item.key }); - }, [item]); - - useEffect(() => { - if (!options) return; - const filteredOptions = options.length ? options : []; - if (item?.key && !filteredOptions.includes(item.key)) { - setFilteredOptions([item.key, ...filteredOptions]); - } else setFilteredOptions(filteredOptions); - }, [options]); - - const selectChangeHandler = useCallback( - (e) => { - const existingEntry = assumptions.find((item) => item?.active && item?.key === e?.code); - if (existingEntry) return; - const newDataSegment = { - ...item, - id: item.id, - key: e?.code, - value: item.value, - }; - setAssumptions((previous) => { - const filteredAssumptionsList = previous.map((data) => { - if (data.id === item.id) return newDataSegment; - return data; - }); - return filteredAssumptionsList; - }); - - setOptions((previous) => { - let newOptions = previous.filter((item) => item !== e?.code); - if (selected && !newOptions.includes(selected?.code)) newOptions.unshift(selected?.code); - return newOptions; - }); - }, - [assumptions, item, selected, setAssumptions, setOptions] - ); - - return ( - ({ code: item }))} - selected={selected} - optionKey="code" - select={selectChangeHandler} - // style={{ width: "100%", backgroundColor: "rgb(0,0,0,0)", position:"sticky" }} - optionCardStyles={{ position: "absolute" }} - placeholder={t("SELECT_OPTION")} - showToolTip={true} - /> - ); -}); - -const Input = React.memo(({ item, setAssumptions, t, disabled = false }) => { - const [inputValue, setInputValue] = useState(""); - - useEffect(() => { - if (item) setInputValue(item.value); - }, [item]); - - const inputChangeHandler = useCallback( - (e) => { - if (e.target.value.includes("+") || e.target.value.includes("e")) return; - if ((e.target.value < 0 || e.target.value > 10000000000) && e.target.value !== "") return; - let value; - const decimalIndex = e.target.value.indexOf("."); - if (decimalIndex !== -1) { - const numDecimals = e.target.value.length - decimalIndex - 1; - value = e.target.value; - if (numDecimals <= 2) { - value = e.target.value; - } else if (numDecimals > 2) { - value = value.substring(0, decimalIndex + 3); - } - } else value = Number.parseFloat(e.target.value); - - setInputValue(!Number.isNaN(value) ? value : ""); - const newDataSegment = { - ...item, - id: item.id, - key: item.key, - value: !Number.isNaN(value) ? value : "", - }; - setAssumptions((previous) => { - const filteredAssumptionsList = previous.map((data) => { - if (data.id === item.id) { - return newDataSegment; - } - return data; - }); - return filteredAssumptionsList; - }); - }, - [item, setAssumptions] - ); - - return ( - - ); -}); - -const setAutofillHypothesisData = (autofillHypothesis, assumptions, setAssumptions) => { - if (assumptions?.length !== 0) return []; - let newAssumptions = []; - for (let i in autofillHypothesis) { - const uuid = uuidv4(); - newAssumptions.push({ - id: uuid, - key: autofillHypothesis[Number(i)], - value: "", - active: true, - }); - } - setAssumptions(newAssumptions); - return newAssumptions; -}; - -const filterHypothesisList = (assumptions, hypothesisList) => { - let alreadySelectedHypothesis = assumptions.filter((item) => item?.active).map((item) => item?.key) || []; - return hypothesisList.filter((item) => !alreadySelectedHypothesis.includes(item)); -}; - -export default Hypothesis; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/JsonPreviewInExcelForm.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/JsonPreviewInExcelForm.js deleted file mode 100644 index 23bbef8ae29..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/JsonPreviewInExcelForm.js +++ /dev/null @@ -1,113 +0,0 @@ -import { Button, DownloadIcon, SVG } from "@egovernments/digit-ui-react-components"; -import React, { useState } from "react"; -import { useTranslation } from "react-i18next"; -import { PRIMARY_THEME_COLOR } from "../configs/constants"; - -export const JsonPreviewInExcelForm = (props) => { - const { t } = useTranslation(); - const sheetsData = props?.sheetsData; - const [currentSheetName, setCurrentSheetName] = useState(Object.keys(sheetsData).length > 0 ? Object.keys(sheetsData)[0] : undefined); - return ( -
-
-
-
- {props?.errorLocationObject?.[currentSheetName] &&

{t("USER_DIRECTIONS_FOR_ERROR_MESSAGE")}

} - {/* {Object.entries(sheetsData).map(([sheetName, sheetData], index) => ( */} -
- - - - {sheetsData?.[currentSheetName]?.[0] - ?.filter((header) => header) - .map((header) => ( - - ))} - - - - {sheetsData?.[currentSheetName]?.slice(1).map((rowData, rowIndex) => ( - - {Object.values(sheetsData?.[currentSheetName]?.[0])?.map((_, cellIndex) => { - const headerName = sheetsData?.[currentSheetName]?.[0]?.[cellIndex]; - const error = headerName ? props?.errorLocationObject?.[currentSheetName]?.[rowIndex]?.[headerName] : undefined; - let convertedError; - if (typeof error?.[0] === "object") { - let { error: actualError, ...otherProperties } = error[0]; - convertedError = t(actualError, otherProperties?.values); - } else { - convertedError = t(error); - } - const rowHasError = - typeof props?.errorLocationObject?.[currentSheetName]?.[rowIndex] === "object" - ? Object.keys(props?.errorLocationObject?.[currentSheetName]?.[rowIndex]).length !== 0 - : undefined; - return ( - - ); - })} - - ))} - -
{t(header)}
- {cellIndex === 0 && rowHasError &&
} - - {rowData[cellIndex] || rowData[cellIndex] === 0 ? rowData[cellIndex] : ""} -
-
-
- {Object.entries(sheetsData).map(([sheetName, sheetData], index) => ( - - ))} -
- {/* ))} */} -
-
- ); -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js deleted file mode 100644 index 75f953c8804..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Mapping.js +++ /dev/null @@ -1,445 +0,0 @@ -// Importing necessary modules -import { Card, Header } from "@egovernments/digit-ui-components"; -import L from "leaflet"; -import "leaflet/dist/leaflet.css"; -import React, { useCallback, useEffect, useRef, useState, Fragment } from "react"; -import { useTranslation } from "react-i18next"; -import ZoomControl from "./ZoomControl"; -import CustomScaleControl from "./CustomScaleControl"; -import * as DigitSvgs from "@egovernments/digit-ui-svg-components"; -import { LoaderWithGap } from "@egovernments/digit-ui-react-components"; -import { tourSteps } from "../configs/tourSteps"; -import { useMyContext } from "../utils/context"; -import { - MapFilterIndex, - MapChoroplethIndex, - ChoroplethSelection, - FilterSection, - BoundarySelection, - BaseMapSwitcher, -} from "./MappingHelperComponents"; -import { - enableMapInteractions, - disableMapInteractions, - removeAllLayers, - filterBoundarySelection, - findBounds, - addGeojsonToMap, - addFilterProperties, - addChoroplethProperties, - prepareGeojson, - extractGeoData, -} from "../utils/mappingUtils"; - -const page = "mapping"; - -// Mapping component definition -const Mapping = ({ - campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, - microplanData, - setMicroplanData, - checkDataCompletion, - setCheckDataCompletion, - currentPage, - pages, - setToast, - ...props -}) => { - //fetch campaign data - const { id = "" } = Digit.Hooks.useQueryParams(); - const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( - { - CampaignDetails: { - tenantId: Digit.ULBService.getCurrentTenantId(), - ids: [id], - }, - }, - { - enabled: !!id, - } - ); - - // request body for boundary hierarchy api - var reqCriteria = { - url: `/boundary-service/boundary-hierarchy-definition/_search`, - params: {}, - body: { - BoundaryTypeHierarchySearchCriteria: { - tenantId: Digit.ULBService.getStateId(), - // hierarchyType: "Microplan", - hierarchyType: campaignData?.hierarchyType, - }, - }, - config: { - enabled: !!campaignData?.hierarchyType, - select: (data) => { - return ( - data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map((item) => ({ - ...item, - parentBoundaryType: item?.parentBoundaryType - ? `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.parentBoundaryType)}` - : null, - boundaryType: `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}`, - })) || {} - ); - }, - }, - }; - const { isLoading: ishierarchyLoading, data: hierarchy } = Digit.Hooks.useCustomAPIHook(reqCriteria); - // request body for boundary hierarchy api - var reqCriteria = { - url: `/boundary-service/boundary/_search`, - params: { codes: Digit.ULBService.getCurrentTenantId(), tenantId: Digit.ULBService.getCurrentTenantId() }, - body: {}, - config: { - select: (data) => { - return data?.Boundary || {}; - }, - }, - }; - const { isLoading: isBoundaryLoading, data: Boundary } = Digit.Hooks.useCustomAPIHook(reqCriteria); - - // Setting up state variables - const [editable, setEditable] = useState(true); - const { t } = useTranslation(); - var [map, setMap] = useState(null); - var [_mapNode, set__mapNode] = useState("map"); - const [layers, setLayer] = useState([]); - const [validationSchemas, setValidationSchemas] = useState([]); - const [filterDataOrigin, setFilterDataOrigin] = useState({}); - const [dataAvailability, setDataAvailability] = useState("true"); - // const [toast, setToast] = useState(); - const [baseMaps, setBaseMaps] = useState({}); - const [selectedBaseMap, setSelectedBaseMap] = useState({}); - const [selectedBaseMapName, setSelectedBaseMapName] = useState(""); - const [showBaseMapSelector, setShowBaseMapSelector] = useState(false); - const [boundaryData, setBoundaryData] = useState({}); // State for boundary data - const [filterData, setFilterData] = useState({}); // State for facility data - const [boundarySelections, setBoundarySelections] = useState({}); - const [isboundarySelectionSelected, setIsboundarySelectionSelected] = useState(false); - const { state, dispatch } = useMyContext(); - const [filterPropertyNames, setFilterPropertyNames] = useState(); - const [filterProperties, setFilterProperties] = useState(); - const [showFilterOptions, setShowFilterOptions] = useState(false); - const [filterSelections, setFilterSelections] = useState([]); - const [choroplethProperties, setChoroplethProperties] = useState([]); - const [showChoroplethOptions, setShowChoroplethOptions] = useState(false); - const [choroplethProperty, setChoroplethProperty] = useState(); - const [dataCompleteness, setDataCompleteness] = useState(); - const basemapRef = useRef(); - const filterBoundaryRef = useRef(); - const showChoroplethOptionRef = useRef(); - const showFilterOptionRef = useRef(); - const [loader, setLoader] = useState(false); - - // Set TourSteps - useEffect(() => { - const tourData = tourSteps(t)?.[page] || {}; - if (state?.tourStateData?.name === page) return; - dispatch({ - type: "SETINITDATA", - state: { tourStateData: tourData }, - }); - }, []); - - // Effect to initialize map when data is fetched - useEffect(() => { - if (!state || !Boundary) return; - const UIConfiguration = state?.UIConfiguration; - if (UIConfiguration) { - const filterDataOriginList = UIConfiguration.find((item) => item.name === "mapping"); - setFilterDataOrigin(filterDataOriginList); - } - const BaseMapLayers = state?.BaseMapLayers; - const schemas = state?.Schemas; - if (schemas) setValidationSchemas(schemas); - if (!BaseMapLayers || (BaseMapLayers && BaseMapLayers.length === 0)) return; - let baseMaps = {}; - let defaultBaseMap = undefined; - BaseMapLayers.forEach((item) => { - if (item.url) { - const layer = L.tileLayer(item.url, { - minZoom: item?.minZoom, - maxZoom: item?.maxZoom, - attribution: item?.attribution, - }); - baseMaps[item?.name] = { - metadata: item, - layer, - }; - if (!defaultBaseMap) - defaultBaseMap = { - name: item?.name, - layer, - }; - } - }); - setSelectedBaseMapName(defaultBaseMap?.name); - setBaseMaps(baseMaps); - if (!map) { - init(_mapNode, defaultBaseMap, Boundary); - } - }, [Boundary]); - - useEffect(() => { - if (map && filterDataOrigin && Object.keys(filterDataOrigin).length !== 0) { - setLoader("LOADING"); - // Check if all the data is present or not, if it is then extract it in a format that can be used for mapping and other mapping related operations - extractGeoData( - campaignType, - microplanData, - filterDataOrigin, - validationSchemas, - setToast, - setDataAvailability, - hierarchy, - setBoundaryData, - setFilterData, - setFilterProperties, - setFilterSelections, - setFilterPropertyNames, - state, - setChoroplethProperties, - setDataCompleteness, - t - ); - setLoader(false); - } - }, [filterDataOrigin, hierarchy]); - - // Function to initialize map - const init = (id, defaultBaseMap, Boundary) => { - if (map !== null) return; - - // let bounds = findBounds(Boundary); - - let mapConfig = { - center: [0, 0], - zoomControl: false, - zoom: 3, - scrollwheel: true, - minZoom: 3, - }; - - let map_i = L.map(id, mapConfig); - var verticalBounds = L.latLngBounds(L.latLng(-90, -170), L.latLng(85, 190)); - map_i.on("drag", () => { - map_i.panInsideBounds(verticalBounds, { animate: true }); - }); - map_i.on("zoom", () => { - map_i.panInsideBounds(verticalBounds, { animate: true }); - }); - const defaultBaseLayer = defaultBaseMap?.layer.addTo(map_i); - // if (bounds) map_i.fitBounds(bounds); - setSelectedBaseMap(defaultBaseLayer); - setMap(map_i); - }; - - const handleBaseMapToggle = (newBaseMap) => { - if (map) { - const currentBaseLayer = selectedBaseMap; - if (currentBaseLayer) { - currentBaseLayer.remove(); - } - const newBaseLayer = baseMaps[newBaseMap].layer.addTo(map); - // Add the new base layer to the bottom of the layer stack - newBaseLayer.addTo(map); - - // Update the baseLayer state - setSelectedBaseMap(newBaseLayer); - setSelectedBaseMapName(newBaseMap); - } - }; - - // showing selected boundary data - useEffect(() => { - if (!boundarySelections && !choroplethProperty && !filterSelections) return; - setLoader("LOADING"); - try { - removeAllLayers(map, layers); - const { filteredSelection, childrenList } = filterBoundarySelection(boundaryData, boundarySelections); - let newLayer = []; - let addOn = { - fillColor: "rgba(255, 107, 43, 0)", - weight: 3.5, - opacity: 1, - color: "rgba(176, 176, 176, 1)", - fillOpacity: 0, - fill: "rgb(4,136,219,1)", - child: !childrenList || childrenList.length === 0, // so that this layer also has mounse in and mouse out events - }; - let geojsonsBase = prepareGeojson(boundaryData, "ALL", addOn); - if (geojsonsBase) { - let baseLayer = addGeojsonToMap(map, geojsonsBase, t); - if (baseLayer) newLayer.push(baseLayer); - let bounds = findBounds(geojsonsBase); - if (bounds) map.fitBounds(bounds); - } - - addOn = { - fillColor: "rgba(255, 107, 43, 1)", - weight: 2.5, - opacity: 1, - color: "rgba(255, 255, 255, 1)", - fillOpacity: 0.22, - fill: "rgb(4,136,219)", - }; - - let geojsonLayer; - if (choroplethProperty) { - if (dataCompleteness === "partial" || dataCompleteness === "false" || dataCompleteness === undefined) { - setToast({ - state: "warning", - message: t("DISPLAYING_DATA_ONLY_FOR_UPLOADED_BOUNDARIES"), - }); - } - - let choroplethGeojson = prepareGeojson(boundaryData, "ALL", { ...addOn, child: true, fillColor: "rgb(0,0,0,0)" }) || []; - if (choroplethGeojson && choroplethGeojson.length !== 0) - choroplethGeojson = addChoroplethProperties(choroplethGeojson, choroplethProperty, filteredSelection); - geojsonLayer = addGeojsonToMap(map, choroplethGeojson, t); - if (geojsonLayer) { - newLayer.push(geojsonLayer); - } - } - geojsonLayer = null; - const geojsons = prepareGeojson(boundaryData, filteredSelection, addOn); - if (geojsons && geojsons.length > 0) { - geojsonLayer = addGeojsonToMap(map, geojsons, t); - newLayer.push(geojsonLayer); - let bounds = findBounds(geojsons); - if (bounds) map.fitBounds(bounds); - } - - const childrenGeojson = prepareGeojson(boundaryData, childrenList, { ...addOn, opacity: 0, fillOpacity: 0, child: true }); - let childrenGeojsonLayer = addGeojsonToMap(map, childrenGeojson, t); - if (childrenGeojsonLayer) newLayer.push(childrenGeojsonLayer); - - //filters - const filterGeojsons = prepareGeojson(filterData, filteredSelection && filteredSelection.length !== 0 ? filteredSelection : "ALL", addOn); - const filterGeojsonWithProperties = addFilterProperties(filterGeojsons, filterSelections, filterPropertyNames, state?.MapFilters); - let filterGeojsonLayer = addGeojsonToMap(map, filterGeojsonWithProperties, t); - if (filterGeojsonLayer) newLayer.push(filterGeojsonLayer); - - setLayer(newLayer); - } catch (error) { - console.error("Error while adding geojson to map: ", error.message); - } - setLoader(false); - }, [boundarySelections, choroplethProperty, filterSelections]); - - const handleOutsideClickAndSubmitSimultaneously = useCallback(() => { - if (isboundarySelectionSelected) setIsboundarySelectionSelected(false); - if (showBaseMapSelector) setShowBaseMapSelector(false); - if (showFilterOptions) setShowFilterOptions(false); - if (showChoroplethOptions) setShowChoroplethOptions(false); - }, [ - isboundarySelectionSelected, - showBaseMapSelector, - showFilterOptions, - showChoroplethOptions, - setIsboundarySelectionSelected, - setShowBaseMapSelector, - setShowFilterOptions, - setShowChoroplethOptions, - ]); - Digit?.Hooks.useClickOutside(filterBoundaryRef, handleOutsideClickAndSubmitSimultaneously, isboundarySelectionSelected, { capture: true }); - Digit?.Hooks.useClickOutside(basemapRef, handleOutsideClickAndSubmitSimultaneously, showBaseMapSelector, { capture: true }); - Digit?.Hooks.useClickOutside(showFilterOptionRef, handleOutsideClickAndSubmitSimultaneously, showFilterOptions, { capture: true }); - Digit?.Hooks.useClickOutside(showChoroplethOptionRef, handleOutsideClickAndSubmitSimultaneously, showChoroplethOptions, { capture: true }); - - // function to stop mouse event propogation from custom comopents to leaflet map - const handleMouseDownAndScroll = (event) => { - event?.stopPropagation(); - disableMapInteractions(map); - }; - - const handleMouseUpAndScroll = (event) => { - enableMapInteractions(map); - }; - useEffect(() => { - if (isboundarySelectionSelected || showBaseMapSelector || showFilterOptions || showChoroplethOptions) handleMouseDownAndScroll(); - else handleMouseUpAndScroll(); - }, [isboundarySelectionSelected, showBaseMapSelector, showFilterOptions, showChoroplethOptions, choroplethProperty, filterPropertyNames]); - - // Rendering component - return ( -
-
{t("MAPPING")}
- - - {/* Container for map */} - -
-
-
- -
- {filterProperties && Object.keys(filterProperties).length !== 0 && ( - - )} - -
- -
- -
- {DigitSvgs.NorthArrow && } -
- -
- -
- {filterSelections && filterSelections.length > 0 && ( - - )} - {choroplethProperty && } -
-
-
-
- {loader && } -
- ); -}; - -// Exporting Mapping component -export default Mapping; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MappingHelperComponents.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MappingHelperComponents.js deleted file mode 100644 index 9cea19a943f..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MappingHelperComponents.js +++ /dev/null @@ -1,513 +0,0 @@ -// Importing necessary modules -import { Card, CardLabel, MultiSelectDropdown, Button, CheckBox, RadioButtons } from "@egovernments/digit-ui-components"; -import "leaflet/dist/leaflet.css"; -import React, { memo, useCallback, useEffect, useMemo, useRef, useState, Fragment } from "react"; -import * as DigitSvgs from "@egovernments/digit-ui-svg-components"; -import { CardSectionHeader, InfoIconOutline, LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; -import { fetchDropdownValues } from "../utils/processHierarchyAndData"; -import { MapChoroplethGradientColors, PRIMARY_THEME_COLOR } from "../configs/constants"; -import { ModalHeading } from "./CommonComponents"; -import * as MicroplanIconCollection from "../icons/Svg"; -import { generatePreviewUrl } from "../utils/mappingUtils"; - -const IconCollection = { ...MicroplanIconCollection, ...DigitSvgs }; - -export function checkTruthyKeys(obj) { - for (let key in obj) { - if (Object.hasOwn(obj, key)) { - if (obj[key] && !(Array.isArray(obj[key]) && obj[key].length === 0)) { - return true; - } - } - } - return false; -} - -export const MapFilterIndex = ({ filterSelections, MapFilters, t }) => { - return ( -
- {filterSelections && filterSelections.length > 0 ? ( - <> - {filterSelections.map((item, index) => ( - //
- - //

{t(item)}

- //
- ))} - - ) : ( - "" - )} -
- ); -}; - -// Function to create the gradient from the colors array for choropleth index -export const MapChoroplethIndex = ({ t, choroplethProperty }) => { - const createGradientString = (colors) => { - return colors.map((color) => `${color.color} ${color.percent}%`).join(", "); - }; - - const gradientString = createGradientString(MapChoroplethGradientColors); - const gradientStyle = { - background: `linear-gradient(to right, ${gradientString})`, - }; - - return ( -
-
-

0%

-
-

100%

-
-

{t(choroplethProperty)}

-
- ); -}; - -export const FilterItemBuilder = ({ item, MapFilters, t }) => { - let temp = MapFilters?.find((e) => e?.name === item)?.icon?.index; - let DynamicIcon = IconCollection?.[temp]; - // let icon; - // if (typeof DynamicIcon === "function") icon = DynamicIcon({}); - return DynamicIcon && typeof DynamicIcon === "function" ? ( -
- -

{t(item)}

-
- ) : ( - //
- "" - ); -}; - -export const ChoroplethSelection = memo( - ({ - choroplethProperties, - showChoroplethOptions, - showChoroplethOptionRef, - setShowChoroplethOptions, - choroplethProperty, - setChoroplethProperty, - t, - }) => { - const handleChange = useCallback( - (value) => { - setChoroplethProperty(value?.code); - }, - [choroplethProperties] - ); - - return ( -
-
setShowChoroplethOptions((previous) => !previous)} - onKeyUp={() => setShowChoroplethOptions((previous) => !previous)} - tabIndex={0} - > -

{t("VISUALIZATIONS")}

-
- {DigitSvgs.FilterAlt && } -
-
- {showChoroplethOptions && ( -
-
- ({ name: item, id: item, code: item }))} - optionsKey="name" - onSelect={handleChange} - selectedOption={choroplethProperty} - /> -
-
- )} -
- ); - } -); - -export const FilterSection = memo( - ({ filterProperties, showFilterOptionRef, showFilterOptions, setShowFilterOptions, filterSelections, setFilterSelections, t }) => { - const handleChange = useCallback( - (e, item) => { - let tempFilterSelections = [...filterSelections]; // Clone the array to avoid mutating state directly - if (filterSelections.includes(item)) { - tempFilterSelections = tempFilterSelections.filter((element) => element !== item); - } else { - tempFilterSelections.push(item); - } - setFilterSelections(tempFilterSelections); - }, - [filterSelections] - ); - - return ( -
-
setShowFilterOptions((previous) => !previous)} - onKeyUp={() => setShowFilterOptions((previous) => !previous)} - tabIndex={0} - > -

{t("FILTERS")}

-
- {DigitSvgs.FilterAlt && } -
-
- {showFilterOptions && ( -
-
- {filterProperties.map((item) => ( -
- handleChange(e, item)} - label={t(item)} - checked={!!filterSelections.includes(item)} - mainClassName="mainClassName" - labelClassName="labelClassName" - inputWrapperClassName="inputWrapperClassName" - inputClassName="inputClassName" - inputIconClassname="inputIconClassname" - iconFill={PRIMARY_THEME_COLOR} - onLabelClick={(e) => handleChange(e, item)} - /> -
- ))} -
-
- )} -
- ); - } -); - -export const BoundarySelection = memo( - ({ - boundarySelections, - setBoundarySelections, - boundaryData, - hierarchy, - filterBoundaryRef, - isboundarySelectionSelected, - setIsboundarySelectionSelected, - t, - }) => { - const [processedHierarchy, setProcessedHierarchy] = useState([]); - const [isLoading, setIsLoading] = useState(false); - const [showConfirmationModal, setShowConformationModal] = useState(false); - const itemRefs = useRef([]); - const [expandedIndex, setExpandedIndex] = useState(null); - const scrollContainerRef = useRef(null); - const [changedBoundaryType, setChangedBoundaryType] = useState(""); - const [isScrollable, setIsScrollable] = useState(false); - - useEffect(() => { - // Scroll to the expanded item's child element after the state has updated and the DOM has re-rendered - if (expandedIndex !== null && itemRefs.current[expandedIndex]) { - // Use a timeout to ensure the DOM has updated - setTimeout(() => { - const childElement = itemRefs.current[expandedIndex].children[0]; // Assuming child content is the second child - // if (childElement) { - // childElement.scrollIntoView({ behavior: 'smooth' }); - // } - if (childElement) { - const scrollContainer = scrollContainerRef.current; - const childElementBound = childElement.getBoundingClientRect(); - const containerRect = scrollContainer.getBoundingClientRect(); - - // Calculate the offset from the top of the container - const offset = childElementBound.top - containerRect.top; - - // Scroll the container - scrollContainer.scrollTo({ - top: scrollContainer.scrollTop + offset - 10, - behavior: "smooth", - }); - } - }, 0); - } - }, [expandedIndex]); - - const toggleExpand = (index) => { - setExpandedIndex(index === expandedIndex ? null : index); - }; - - // Filtering out dropdown values - useEffect(() => { - if (!boundaryData || !hierarchy) return; - const processedHierarchyTemp = fetchDropdownValues( - boundaryData, - processedHierarchy.length !== 0 ? processedHierarchy : hierarchy, - boundarySelections, - changedBoundaryType - ); - setProcessedHierarchy(processedHierarchyTemp); - setIsLoading(false); - }, [boundaryData, hierarchy, boundarySelections]); - - const handleClearAll = () => { - setShowConformationModal(true); - }; - - const handleSubmitConfModal = () => { - setBoundarySelections({}); - setShowConformationModal(false); - }; - - const handleCancelConfModal = () => { - setShowConformationModal(false); - }; - - const checkScrollbar = () => { - if (scrollContainerRef.current) { - setIsScrollable(scrollContainerRef.current.scrollHeight > scrollContainerRef.current.clientHeight); - } - }; - - useEffect(() => { - // Initial check - checkScrollbar(); - - // Check on resize - window.addEventListener("resize", checkScrollbar); - - // Cleanup event listeners on component unmount - return () => { - window.removeEventListener("resize", checkScrollbar); - }; - }, [isboundarySelectionSelected]); - - useEffect(() => { - const content = scrollContainerRef.current; - content.addEventListener("scroll", checkScrollbar); - - return () => { - content.removeEventListener("scroll", checkScrollbar); - }; - }, [scrollContainerRef]); - - return ( -
- {isLoading && } -
- ); - } -); - -export const BaseMapSwitcher = ({ - baseMaps, - showBaseMapSelector, - setShowBaseMapSelector, - handleBaseMapToggle, - selectedBaseMapName, - basemapRef, - t, -}) => { - if (!baseMaps) return null; - return ( -
-
setShowBaseMapSelector((previous) => !previous)} - onKeyUp={() => setShowBaseMapSelector((previous) => !previous)} - tabIndex={0} - > -

{t("LAYERS")}

-
{DigitSvgs.Layers && }
-
-
- {showBaseMapSelector && ( -
- {Object.entries(baseMaps).map(([name, baseMap], index) => { - return ( -
- {t("ERROR_LOADING_BASE_MAP")} handleBaseMapToggle(name)} - /> -

{t(name)}

-
- ); - })} -
- )} -
-
- ); -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js deleted file mode 100644 index b6a2fb9a205..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanCreatedScreen.js +++ /dev/null @@ -1,111 +0,0 @@ -import React, { memo } from "react"; -import { ActionBar, ArrowForward, Banner } from "@egovernments/digit-ui-components"; -import { useTranslation } from "react-i18next"; -import { ArrowBack, FileDownload } from "@egovernments/digit-ui-svg-components"; -import { convertJsonToXlsx, writeWorkbookToBuffer } from "../utils/jsonToExcelBlob"; -import { Button } from "@egovernments/digit-ui-react-components"; -import { useHistory } from "react-router-dom"; -import { Link } from "react-router-dom/cjs/react-router-dom.min"; -import { PRIMARY_THEME_COLOR, commonColumn } from "../configs/constants"; -import { colorHeaders } from "../utils/uploadUtils"; - -const MicroplanCreatedScreen = memo(({ microplanData, ...props }) => { - const { t } = useTranslation(); - const history = useHistory(); - - const downloadMicroplan = async () => { - try { - if (!microplanData?.microplanPreview) return; - const data = _.cloneDeep(microplanData?.microplanPreview?.previewData); - const commonColumnIndex = data[0]?.findIndex((item) => item === commonColumn); - data[0] = data[0].map((item) => t(item)); - - for (const i in data) { - data[i] = data[i].map((item, index) => - item ? (typeof item === "number" ? item : index === commonColumnIndex ? item : t(item)) : t("NO_DATA") - ); - } - - const headers = data?.[0] || []; - const workbook = await convertJsonToXlsx({ [microplanData?.microplanDetails?.name]: data }, {}, true); - colorHeaders(workbook, headers, [], []); - const blob = await writeWorkbookToBuffer(workbook); - - if (!blob) { - return; - } - - const url = URL.createObjectURL(blob); - const link = document.createElement("a"); - link.href = url; - - const fileNameParts = microplanData?.microplanDetails?.name; - if (!fileNameParts) { - return; - } - - link.download = fileNameParts; - link.click(); - URL.revokeObjectURL(url); - } catch (error) { - console.error(`Failed to download microplan: ${error.message}`, error); - } - }; - - const clickGoHome = () => { - history.push("/microplan-ui/employee"); - }; - - return ( -
-
-
- -
-

{t("MICROPLAN_GENERATED_SUCCESSFULLY_DESCRIPTIION")}

-
-
-
- - - {/* Back button */} -
- ); -}); - -export default MicroplanCreatedScreen; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js deleted file mode 100644 index fbc73bd6569..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanDetails.js +++ /dev/null @@ -1,294 +0,0 @@ -import React, { Fragment, useState, useEffect, useCallback } from "react"; -import { - Card, - CardSubHeader, - CardSectionHeader, - StatusTable, - Row, - Loader, - LabelFieldPair, - CardLabel, - TextInput, - LoaderWithGap, -} from "@egovernments/digit-ui-react-components"; -import { useTranslation } from "react-i18next"; -import { tourSteps } from "../configs/tourSteps"; -import { useMyContext } from "../utils/context"; -import { InfoCard, Modal, Toast } from "@egovernments/digit-ui-components"; -import { CloseButton, ModalHeading } from "./CommonComponents"; -import { PRIMARY_THEME_COLOR } from "../configs/constants"; -import SearchPlanConfig from "../services/SearchPlanConfig"; - -const page = "microplanDetails"; - -const MicroplanDetails = ({ - MicroplanName = "default", - campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, - microplanData, - setMicroplanData, - checkDataCompletion, - setCheckDataCompletion, - currentPage, - pages, - setToast, - ...props -}) => { - const { t } = useTranslation(); - const [microplan, setMicroplan] = useState(Digit.SessionStorage.get("microplanData")?.microplanDetails?.name); - const { state, dispatch } = useMyContext(); - const [modal, setModal] = useState("none"); - // const [toast, setToast] = useState(); - const [showNamingConventions, setShowNamingConventions] = useState(false); - const [loader, setLoader] = useState(false); - - //fetch campaign data - const { id = "" } = Digit.Hooks.useQueryParams(); - const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( - { - CampaignDetails: { - tenantId: Digit.ULBService.getCurrentTenantId(), - ids: [id], - }, - }, - { - enabled: !!id, - select: (data) => { - const campaignCard = [ - { - label: t("CAMPAIGN_NAME"), - value: data?.campaignName ? data?.campaignName : t("ES_COMMON_NA"), - }, - { - label: t(`CAMPAIGN_TYPE`), - value: data?.projectType ? t(`CAMPAIGN_TYPE_${data?.projectType}`) : t("ES_COMMON_NA"), - }, - { - label: t(`CAMPAIGN_BENEFICIARY_TYPE`), - value: data?.additionalDetails?.beneficiaryType - ? t(`CAMPAIGN_BENEFICIARY_TYPE${data?.additionalDetails?.beneficiaryType}`) - : t("ES_COMMON_NA"), - }, - { - label: t("CAMPAIGN_DATE"), - value: data.startDate - ? data.endDate - ? `${Digit.DateUtils.ConvertEpochToDate(data.startDate)} - ${Digit.DateUtils.ConvertEpochToDate(data.endDate)}` - : Digit.DateUtils.ConvertEpochToDate(data.startDate) - : t("ES_COMMON_NA"), - }, - ]; - return campaignCard; - }, - } - ); - - // Set TourSteps - useEffect(() => { - const tourData = tourSteps(t)?.[page] || {}; - if (state?.tourStateData?.name === page) return; - dispatch({ - type: "SETINITDATA", - state: { tourStateData: tourData }, - }); - }, []); - - // Save data to ssn of data change - useEffect(() => { - setMicroplanData((previous) => ({ - ...previous, - microplanDetails: { - name: microplan, - }, - })); - }, [microplan]); - - useEffect(() => { - if (checkDataCompletion !== "true" || !setCheckDataCompletion) return; - - updateData(true); - }, [checkDataCompletion]); - - // UseEffect to add a event listener for keyboard - useEffect(() => { - window.addEventListener("keydown", handleKeyPress); - - return () => window.removeEventListener("keydown", handleKeyPress); - }, [modal]); - - const handleKeyPress = (event) => { - // if (modal !== "upload-guidelines") return; - if (["x", "Escape"].includes(event.key)) { - // Perform the desired action when "x" or "esc" is pressed - // if (modal === "upload-guidelines") - setCheckDataCompletion("false"); - setModal("none"); - } - }; - const validateMicroplanName = async () => { - try { - setLoader("LOADING"); - const body = { - PlanConfigurationSearchCriteria: { - name: microplan, - tenantId: Digit.ULBService.getCurrentTenantId(), - }, - }; - const response = await SearchPlanConfig(body); - if (response?.PlanConfiguration?.length === 0) { - return true; - } - if (response?.PlanConfiguration?.length === 1) { - if (response?.PlanConfiguration[0].id === microplanData?.planConfigurationId) { - setLoader(); - return true; - } - } - setLoader(); - return false; - } catch (error) { - console.error("Error while checking microplan name duplication: ", error.message); - setLoader(); - return false; - } - }; - // check if data has changed or not - const updateData = useCallback( - async (check) => { - if (checkDataCompletion !== "true" || !setCheckDataCompletion) return; - if (!microplan || !validateName(microplan)) { - setCheckDataCompletion("false"); - setShowNamingConventions(true); - return setToast({ state: "error", message: t("ERROR_MICROPLAN_NAME_CRITERIA") }); - } - const valid = await validateMicroplanName(); - if (!valid) { - setToast({ state: "error", message: t("ERROR_DUPLICATE_MICROPLAN_NAME") }); - setCheckDataCompletion("false"); - return; - } - if (check) { - setMicroplanData((previous) => ({ - ...previous, - microplanDetails: { - name: microplan, - }, - })); - if (!["", null, undefined].includes(microplan)) { - setCheckDataCompletion("valid"); - } else { - setCheckDataCompletion("invalid"); - } - } else { - if (!["", null, undefined].includes(microplanData?.microplanDetails?.name)) { - setCheckDataCompletion("valid"); - } else { - setCheckDataCompletion("invalid"); - } - } - }, - [checkDataCompletion, microplan, microplanData, setCheckDataCompletion, setMicroplanData, validateMicroplanName] - ); - - // const cancelUpdateData = useCallback(() => { - // setCheckDataCompletion(false); - // setModal('none'); - // }, [setCheckDataCompletion, setModal]); - function validateName(name) { - const microplanNamingRegxString = state?.UIConfiguration?.find((item) => item.name === "microplanNamingRegx")?.microplanNamingRegx; - const namePattern = new RegExp(microplanNamingRegxString); - return namePattern.test(name); - } - const onChangeMicroplanName = (e) => { - setMicroplan(e.target.value); - }; - - if (isCampaignLoading) { - return ; - } - - return ( - <> - {loader && } - - - {t("CAMPAIGN_DETAILS")} - - - - {campaignData?.length > 0 && - campaignData?.map((row, idx) => { - return ( - - ); - })} - - - - {t("NAME_YOUR_MP")} -

{t("MP_FOOTER")}

- - - {`${t("NAME_OF_MP")} `}

*

-
-
- -
-
-
- - {state?.UIConfiguration?.find((item) => item.name === "microplanNamingConvention")?.microplanNamingConvention?.map((item, index) => ( -
-

- {t(index + 1)}. -

-

- {t(item)} -

-
- ))} -
, - ]} - /> - - ); -}; - -export default MicroplanDetails; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js deleted file mode 100644 index 1be6619e7a7..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreview.js +++ /dev/null @@ -1,478 +0,0 @@ -import { Header, Loader } from "@egovernments/digit-ui-components"; -import React, { useCallback, useEffect, useMemo, useState, Fragment } from "react"; -import { useTranslation } from "react-i18next"; -import { processHierarchyAndData } from "../utils/processHierarchyAndData"; -import { ModalHeading } from "./CommonComponents"; -import { PRIMARY_THEME_COLOR } from "../configs/constants"; -import { LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; -import { tourSteps } from "../configs/tourSteps"; -import { useMyContext } from "../utils/context"; -import { - fetchMicroplanPreviewData, - filterObjects, - updateHyothesisAPICall, - filterMicroplanDataToShowWithHierarchySelection, -} from "../utils/microplanPreviewUtils"; -import { - HypothesisValues, - BoundarySelection, - DataPreview, - AppplyChangedHypothesisConfirmation, - Aggregates, -} from "./MicroplanPreviewHelperCompoenents"; - -const page = "microplanPreview"; - -const MicroplanPreview = ({ - campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, - microplanData, - setMicroplanData, - checkDataCompletion, - setCheckDataCompletion, - currentPage, - pages, - navigationEvent, - setToast, - ...props -}) => { - const { mutate: UpdateMutate } = Digit.Hooks.microplan.useUpdatePlanConfig(); - const userInfo = Digit.SessionStorage.get("User")?.info; - const { id: campaignId = "" } = Digit.Hooks.useQueryParams(); - const { t } = useTranslation(); - const [hypothesisAssumptionsList, setHypothesisAssumptionsList] = useState([]); - const [data, setData] = useState([]); - const [dataToShow, setDataToShow] = useState([]); - const [joinByColumns, setJoinByColumns] = useState([]); - const [validationSchemas, setValidationSchemas] = useState([]); - const [resources, setResources] = useState([]); - const [formulaConfiguration, setFormulaConfiguration] = useState([]); - const [boundarySelections, setBoundarySelections] = useState({}); // state for hierarchy from the data available from uploaded data - const [boundaryData, setBoundaryData] = useState({}); // State for boundary data - // const [toast, setToast] = useState(); - const [modal, setModal] = useState("none"); - const [operatorsObject, setOperatorsObject] = useState([]); - - const [loaderActivation, setLoaderActivation] = useState(false); - - const [userEditedResources, setUserEditedResources] = useState({}); // state to maintain a record of the resources that the user has edited ( boundaryCode : {resource : value}) - const [microplanPreviewAggregates, setMicroplaPreviewAggregates] = useState(); - const { state, dispatch } = useMyContext(); - const [updateHypothesis, setUpdateHypothesis] = useState(false); - //fetch campaign data - const { id = "" } = Digit.Hooks.useQueryParams(); - const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( - { - CampaignDetails: { - tenantId: Digit.ULBService.getCurrentTenantId(), - ids: [id], - }, - }, - { - enabled: !!id, - } - ); - - // request body for boundary hierarchy api - const reqCriteria = { - url: `/boundary-service/boundary-hierarchy-definition/_search`, - params: {}, - body: { - BoundaryTypeHierarchySearchCriteria: { - tenantId: Digit.ULBService.getStateId(), - hierarchyType: campaignData?.hierarchyType, - }, - }, - config: { - enabled: !!campaignData?.hierarchyType, - select: (data) => { - return ( - data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map((item) => ({ - ...item, - parentBoundaryType: item?.parentBoundaryType - ? `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.parentBoundaryType)}` - : null, - boundaryType: `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}`, - })) || {} - ); - }, - }, - }; - const { isLoading: ishierarchyLoading, data: hierarchyRawData } = Digit.Hooks.useCustomAPIHook(reqCriteria); - const hierarchy = useMemo(() => { - return hierarchyRawData?.map((item) => item?.boundaryType); - }, [hierarchyRawData]); - // Set TourSteps - useEffect(() => { - const tourData = tourSteps(t)?.[page] || {}; - if (state?.tourStateData?.name === page) return; - dispatch({ - type: "SETINITDATA", - state: { tourStateData: tourData }, - }); - }, []); - - // UseEffect to extract data on first render - useEffect(() => { - if (microplanData && (microplanData?.ruleEngine || microplanData?.hypothesis)) { - const hypothesisAssumptions = microplanData?.hypothesis || []; - const formulaConfiguration = microplanData?.ruleEngine?.filter((item) => Object.values(item).every((key) => key !== "")) || []; - if (hypothesisAssumptions.length !== 0 && hypothesisAssumptionsList.length === 0) { - setHypothesisAssumptionsList(hypothesisAssumptions); - } - if (formulaConfiguration.length !== 0) { - setFormulaConfiguration(formulaConfiguration); - } - } - if (microplanData?.microplanPreview?.userEditedResources) { - setUserEditedResources(microplanData?.microplanPreview?.userEditedResources); - } - }, []); - - // Fetch and assign MDMS data - useEffect(() => { - if (!state) return; - const UIConfiguration = state?.UIConfiguration; - const schemas = state?.Schemas; - let resourcelist = state?.Resources; - let microplanPreviewAggregatesList = state?.MicroplanPreviewAggregates; - microplanPreviewAggregatesList = microplanPreviewAggregatesList.find((item) => item.campaignType === campaignType)?.data; - if (schemas) setValidationSchemas(schemas); - resourcelist = resourcelist.find((item) => item.campaignType === campaignType)?.data; - if (resourcelist) setResources(resourcelist); - if (UIConfiguration) { - const joinWithColumns = UIConfiguration.find((item) => item.name === "microplanPreview")?.joinWithColumns; - setJoinByColumns(joinWithColumns); - } - let temp; - if (UIConfiguration) temp = UIConfiguration.find((item) => item.name === "ruleConfigure"); - if (temp?.ruleConfigureOperators) { - setOperatorsObject(temp.ruleConfigureOperators); - } - if (microplanPreviewAggregatesList) setMicroplaPreviewAggregates(microplanPreviewAggregatesList); - }, []); - - // UseEffect for checking completeness of data before moveing to next section - useEffect(() => { - if (!dataToShow || checkDataCompletion !== "true" || !setCheckDataCompletion) return; - const check = filterObjects(hypothesisAssumptionsList, microplanData?.hypothesis); - if (check.length === 0) { - if (navigationEvent?.name === "next") return setModal("confirm-microplan-generation"); - return createMicroplan(false, false); - } - setModal("confirm-apply-changed-hypothesis"); - }, [checkDataCompletion]); - - // check if data has changed or not - const updateData = useCallback( - (doPerform) => { - // Update the microplan data with selected hierarchy and resources - // This function also handles setting the completion check based on the action to be performed - if (!setMicroplanData) return; - try { - let tempData = filterMicroplanDataToShowWithHierarchySelection(data, {}, hierarchy); - // Adding resources to the data we need to show - tempData = Digit.Utils.microplan.addResourcesToFilteredDataToShow( - tempData, - resources, - hypothesisAssumptionsList, - formulaConfiguration, - userEditedResources, - t - ); - setMicroplanData((previous) => ({ - ...previous, - microplanPreview: { - previewData: tempData, - userEditedResources, - }, - })); - if (doPerform) { - return setCheckDataCompletion("perform-action"); - } - setCheckDataCompletion("false"); - } catch (error) { - console.error("Failed to update data:", error); - } - }, - [ - resources, - boundarySelections, - hierarchy, - hypothesisAssumptionsList, - formulaConfiguration, - userEditedResources, - setMicroplanData, - setCheckDataCompletion, - ] - ); - - const cancelUpdateData = useCallback(() => { - setUpdateHypothesis(false); - if (navigationEvent?.name === "next") setModal("confirm-microplan-generation"); - else createMicroplan(false, false); - }, [setCheckDataCompletion, setModal]); - - useEffect(() => { - if (boundarySelections && Object.values(boundarySelections).every((item) => item.length === 0) && hierarchy) { - const tempBoundarySelection = {}; - for (const item of hierarchy) { - tempBoundarySelection[item] = []; - } - setBoundarySelections(tempBoundarySelection); - } - }, [hierarchy]); - - // UseEffect to add a event listener for keyboard - useEffect(() => { - window.addEventListener("keydown", handleKeyPress); - - return () => window.removeEventListener("keydown", handleKeyPress); - }, [modal]); - - const handleKeyPress = (event) => { - // if (modal !== "upload-guidelines") return; - if (["x", "Escape"].includes(event.key)) { - // Perform the desired action when "x" or "esc" is pressed - setCheckDataCompletion("false"); - setModal("none"); - } - }; - - const cancleNavigation = () => { - if (navigationEvent?.name !== "next") setCheckDataCompletion("false"); - setModal("none"); - }; - - const createMicroplan = useCallback( - (doCreation, updateHypothesis) => { - if (!hypothesisAssumptionsList || !setMicroplanData) return; - const updateDataWrapper = () => { - if (doCreation || navigationEvent?.name !== "next") { - return updateData(true); - } - updateData(false); - }; - const setCheckDataCompletionWrapper = (value) => { - if (!doCreation) { - return setCheckDataCompletion("false"); - } - setCheckDataCompletion(value); - }; - const microData = updateHypothesis ? updateMicroplanData(hypothesisAssumptionsList) : microplanData; - setLoaderActivation(true); - updateHyothesisAPICall( - microData, - setMicroplanData, - operatorsObject, - microData?.microplanDetails?.name, - campaignId, - UpdateMutate, - setToast, - updateDataWrapper, - setLoaderActivation, - doCreation && navigationEvent?.name === "next" ? "GENERATED" : "DRAFT", - cancleNavigation, - state, - campaignType, - navigationEvent, - setCheckDataCompletionWrapper, - t - ); - - setUpdateHypothesis(false); - setModal("none"); - }, - [ - hypothesisAssumptionsList, - setMicroplanData, - operatorsObject, - campaignId, - UpdateMutate, - setToast, - updateData, - setLoaderActivation, - navigationEvent, - t, - ] - ); - - const updateMicroplanData = useCallback( - (hypothesisAssumptionsList) => { - let microData = {}; - setMicroplanData((previous) => { - microData = { ...previous, hypothesis: hypothesisAssumptionsList }; - return microData; - }); - return microData; - }, - [setMicroplanData] - ); - - // Set microplan preview data - useEffect(() => { - if (data?.length !== 0 || !hierarchyRawData || !hierarchy || validationSchemas?.length === 0) return; - - const combinedData = fetchMicroplanPreviewData(campaignType, microplanData, validationSchemas, hierarchy); - // process and form hierarchy - if (combinedData && hierarchy) { - const { hierarchyLists, hierarchicalData } = processHierarchyAndData(hierarchyRawData, [combinedData]); - setBoundaryData({ Microplan: { hierarchyLists, hierarchicalData } }); - } - if (combinedData) { - setData(combinedData); - setDataToShow(combinedData); - } - }, [hierarchy, hierarchyRawData, microplanData]); - - useEffect(() => { - if (!boundarySelections && !resources) return; - let tempData = filterMicroplanDataToShowWithHierarchySelection(data, boundarySelections, hierarchy); - // Adding resources to the data we need to show - tempData = Digit.Utils.microplan.addResourcesToFilteredDataToShow( - tempData, - resources, - hypothesisAssumptionsList, - formulaConfiguration, - userEditedResources, - t - ); - setDataToShow(tempData); - setMicroplanData((previous) => ({ ...previous, microplanPreview: { ...previous.microplanPreview, previewData: tempData, userEditedResources } })); - }, [boundarySelections, resources, hypothesisAssumptionsList, userEditedResources]); - - if (isCampaignLoading || ishierarchyLoading) { - return ( -
- -
- ); - } - - return ( - <> -
-
-

{t(campaignData?.campaignName)}

-
{t(microplanData?.microplanDetails?.name)}
-

{t("MICROPLAN_PREVIEW_CREATE_BY", { username: userInfo?.name })}

-
-
-
- -
-
- -
-
-

{t("MICROPLAN_PREVIEW_HYPOTHESIS_HEADING")}

-

{t("MICROPLAN_PREVIEW_HYPOTHESIS_INSTRUCTIONS")}

- -
-
- {dataToShow?.length != 0 ? ( - - ) : ( -
{t("NO_DATA_AVAILABLE")}
- )} -
-
- {modal === "confirm-apply-changed-hypothesis" && ( - } - actionCancelLabel={t("YES")} - actionCancelOnSubmit={() => { - setUpdateHypothesis(true); - if (navigationEvent?.name === "next") setModal("confirm-microplan-generation"); - else createMicroplan(false, true); - }} - actionSaveLabel={t("NO")} - actionSaveOnSubmit={cancelUpdateData} - formId="modal-action" - > - - - )} - {modal === "confirm-microplan-generation" && ( - } - actionCancelLabel={t("YES")} - actionCancelOnSubmit={() => createMicroplan(true, updateHypothesis)} - actionSaveLabel={t("NO")} - actionSaveOnSubmit={() => createMicroplan(false, updateHypothesis)} - formId="modal-action" - > -
-

{t("INSTRUCTIONS_MICROPLAN_GENERATION_CONFIRMATION")}

-
-
- )} -
- {loaderActivation && } - - ); -}; - -export default MicroplanPreview; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js deleted file mode 100644 index e92335d6581..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanPreviewHelperCompoenents.js +++ /dev/null @@ -1,434 +0,0 @@ -import { CardLabel, Loader, MultiSelectDropdown, TextInput } from "@egovernments/digit-ui-components"; -import React, { memo, useCallback, useEffect, useMemo, useState, Fragment, useRef } from "react"; -import { fetchDropdownValues } from "../utils/processHierarchyAndData"; -import { CloseButton, ModalHeading } from "./CommonComponents"; -import { PRIMARY_THEME_COLOR, commonColumn } from "../configs/constants"; -import { Button, LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; -import { useNumberFormatter } from "../hooks/useNumberFormatter"; -import { calculateAggregateValue, filterObjects, useHypothesis } from "../utils/microplanPreviewUtils"; - -export const HypothesisValues = memo(({ boundarySelections, hypothesisAssumptionsList, setHypothesisAssumptionsList, setToast, setModal, t }) => { - const [tempHypothesisList, setTempHypothesisList] = useState(hypothesisAssumptionsList || []); - const { valueChangeHandler } = useHypothesis(tempHypothesisList, hypothesisAssumptionsList); - const contentRef = useRef(null); - const [isScrollable, setIsScrollable] = useState(false); - - const applyNewHypothesis = () => { - if (tempHypothesisList.some((item) => item.active && (Number.isNaN(parseFloat(item.value)) || parseFloat(item.value) === 0))) { - setToast({ state: "error", message: t("ERROR_HYPOTHESIS_VALUE_SHOULD_NOT_BE_ZERO") }); - return; - } - if (Object.keys(boundarySelections).length !== 0 && Object.values(boundarySelections)?.every((item) => item?.length !== 0)) - return setToast({ state: "error", message: t("HYPOTHESIS_CAN_BE_ONLY_APPLIED_ON_ADMIN_LEVEL_ZORO") }); - setHypothesisAssumptionsList(tempHypothesisList); - }; - const checkScrollbar = () => { - if (contentRef.current) { - setIsScrollable(contentRef.current.scrollHeight > contentRef.current.clientHeight); - } - }; - - useEffect(() => { - // Initial check - checkScrollbar(); - - // Check on resize - window.addEventListener("resize", checkScrollbar); - - // Cleanup event listeners on component unmount - return () => { - window.removeEventListener("resize", checkScrollbar); - }; - }, []); - - useEffect(() => { - const content = contentRef.current; - content.addEventListener("scroll", checkScrollbar); - - return () => { - content.removeEventListener("scroll", checkScrollbar); - }; - }, [contentRef]); - - return ( -
-
- {tempHypothesisList - .filter((item) => item?.active) - ?.filter((item) => item.key !== "") - .map((item, index) => ( -
-

{t(item?.key)}

-
- {/* Dropdown for boundaries */} - - valueChangeHandler({ item, newValue: value?.target?.value }, setTempHypothesisList, boundarySelections, setToast, t) - } - disable={false} - /> -
-
- ))} -
-
-
-
- ); -}); - -export const BoundarySelection = memo(({ boundarySelections, setBoundarySelections, boundaryData, hierarchy, t }) => { - const [processedHierarchy, setProcessedHierarchy] = useState([]); - const [isLoading, setIsLoading] = useState(false); - const [changedBoundaryType, setChangedBoundaryType] = useState(""); - - // Filtering out dropdown values - useEffect(() => { - if (!boundaryData || !hierarchy) return; - - const processedHierarchyTemp = fetchDropdownValues( - boundaryData, - processedHierarchy.length !== 0 ? processedHierarchy : hierarchy, - boundarySelections, - changedBoundaryType - ); - setProcessedHierarchy(processedHierarchyTemp); - setIsLoading(false); - }, [boundaryData, hierarchy, boundarySelections]); - - return ( -
- {isLoading && } - {processedHierarchy?.map((item, index) => ( -
- {t(item?.boundaryType)} - {item?.parentBoundaryType === null ? ( - 5 ? { height: "13.75rem" } : {}} - type={"multiselectdropdown"} - t={t} - options={item?.dropDownOptions || []} - optionsKey="name" - addSelectAllCheck={true} - onSelect={(e) => { - setChangedBoundaryType(item?.boundaryType); - Digit.Utils.microplan.handleSelection( - e, - item?.boundaryType, - boundarySelections, - hierarchy, - setBoundarySelections, - boundaryData, - setIsLoading - ); - }} - /> - ) : ( - 5 ? { height: "13.75rem" } : {}} - type={"multiselectdropdown"} - t={t} - options={Digit.Utils.microplan.processDropdownForNestedMultiSelect(item?.dropDownOptions) || []} - optionsKey="name" - addSelectAllCheck={true} - onSelect={(e) => { - setChangedBoundaryType(item?.boundaryType); - Digit.Utils.microplan.handleSelection( - e, - item?.boundaryType, - boundarySelections, - hierarchy, - setBoundarySelections, - boundaryData, - setIsLoading - ); - }} - variant="nestedmultiselect" - /> - )} -
- ))} -
- ); -}); - -export const DataPreview = memo( - ({ previewData, isCampaignLoading, ishierarchyLoading, resources, userEditedResources, setUserEditedResources, modal, setModal, data, t }) => { - if (!previewData) return; - const [tempResourceChanges, setTempResourceChanges] = useState(userEditedResources); - const [selectedRow, setSelectedRow] = useState(); - const conmmonColumnIndex = useMemo(() => { - return previewData?.[0]?.indexOf(commonColumn); - }, [previewData]); - if (isCampaignLoading || ishierarchyLoading) { - return ( -
- -
- ); - } - - const rowClick = useCallback((rowIndex) => { - setSelectedRow(rowIndex); - setModal("change-preview-data"); - }, []); - - const finaliseRowDataChange = () => { - setUserEditedResources(tempResourceChanges); - setModal("none"); - setSelectedRow(undefined); - }; - - const modalCloseHandler = () => { - setModal("none"); - setSelectedRow(undefined); - }; - - return ( -
-
- - - - {previewData[0].map((header, columnIndex) => ( - - ))} - - - - {previewData.slice(1).map((rowData, rowIndex) => { - const rowDataList = Object.values(previewData[0]).map((header, cellIndex) => ( - - )); - return ( - { - rowClick(rowIndex + 1); - }} - // style={{...(userEditedResources?.[rowData?.[conmmonColumnIndex]] && Object.keys(userEditedResources?.[rowData?.[conmmonColumnIndex]]).length !==0 - // ? { borderL: "1px solid rgba(244, 119, 56, 0.12)" } - // : {}),}} - > - {rowDataList} - - ); - })} - -
- {t(header)} -
- {cellIndex === 0 && - userEditedResources?.[rowData?.[conmmonColumnIndex]] && - Object.keys(userEditedResources?.[rowData?.[conmmonColumnIndex]]).length !== 0 &&
} - - {rowData[cellIndex] || rowData[cellIndex] === 0 ? rowData[cellIndex] : t("NO_DATA")} -
-
- {modal === "change-preview-data" && ( -
- } - headerBarEnd={} - actionCancelLabel={t("CANCLE")} - actionCancelOnSubmit={modalCloseHandler} - actionSaveLabel={t("SAVE_CHANGES")} - actionSaveOnSubmit={finaliseRowDataChange} - formId="modal-action" - > - - -
- )} -
- ); - } -); - -export const AppplyChangedHypothesisConfirmation = ({ newhypothesisList, hypothesisList, t }) => { - const data = filterObjects(newhypothesisList, hypothesisList); - return ( -
-
-

{t("INSTRUCTION_PROCEED_WITH_NEW_HYPOTHESIS")}

-
- - {t("MICROPLAN_PREVIEW_HYPOTHESIS")} - -
- - - - - - - - - - {data?.map((row, index) => ( - - - - - - ))} - -
{t("KEYS")}{t("OLD_VALUE")}{t("NEW_VALUE")}
{t(row?.key)}{t(row?.oldValue)}{t(row?.value)}
-
-
- ); -}; - -export const EditResourceData = ({ previewData, selectedRow, resources, tempResourceChanges, setTempResourceChanges, data, t }) => { - const conmmonColumnData = useMemo(() => { - const index = previewData?.[0]?.indexOf(commonColumn); - if (index === -1) return; - return previewData?.[selectedRow]?.[index]; - }, [previewData]); - - const valueChangeHandler = (item, value) => { - if (!conmmonColumnData) return; - if (isNaN(value) || (!isFinite(value) && value !== "")) return; - let changedDataAgainstBoundaryCode = tempResourceChanges?.[conmmonColumnData] || {}; - changedDataAgainstBoundaryCode[item] = value === "" ? undefined : parseFloat(value); - setTempResourceChanges((previous) => ({ ...previous, [conmmonColumnData]: changedDataAgainstBoundaryCode })); - }; - - return ( -
- - - - - - - - - - {data[0].map((item) => { - let index = data?.[0]?.indexOf(item); - if (index === -1) return; - const currentData = data?.[selectedRow]?.[index]; - return ( - - - - - - ); - })} - {resources.map((item) => { - let index = previewData?.[0]?.indexOf(item); - if (index === -1) return; - const currentData = previewData?.[selectedRow]?.[index]; - - return ( - - - - - - ); - })} - -
{t("COLUMNS")}{t("OLD_VALUE")}{t("NEW_VALUE")}
-

{t(item)}

-
-

{currentData || t("NO_DATA")}

-
- -
-

{t(item)}

-
-

{currentData || t("NO_DATA")}

-
- valueChangeHandler(item, value.target.value)} - /> -
-
- ); -}; - -export const Aggregates = memo(({ microplanPreviewAggregates, dataToShow, NumberFormatMappingForTranslation, t }) => { - const { formatNumber } = useNumberFormatter(NumberFormatMappingForTranslation?.reduce((acc, obj) => Object.assign(acc, obj), {})); - - if (!microplanPreviewAggregates) return null; - return ( -
- {microplanPreviewAggregates.map((item, index) => { - const aggregate = calculateAggregateValue(item, dataToShow); - return ( -
-

{isNaN(parseInt(aggregate)) ? 0 : formatNumber(parseInt(aggregate))}

-

{typeof item === "object" && item.name ? t(item.name) : t(item)}

-
- ); - })} -
- ); -}); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js deleted file mode 100644 index 9a1dd8f5500..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningCard.js +++ /dev/null @@ -1,34 +0,0 @@ -import { EmployeeModuleCard, WorksMgmtIcon } from "@egovernments/digit-ui-react-components"; -import React from "react"; -import { useTranslation } from "react-i18next"; - -const ROLES = { - MICROPLAN: ["MICROPLAN_ADMIN"], -}; - -const MicroplanningCard = () => { - const { t } = useTranslation(); - const tenantId = Digit.ULBService.getCurrentTenantId(); - - const generateLink = (labelKey, pathSuffix) => { - return { - label: t(labelKey), - link: `/${window?.contextPath}/employee/microplanning/${pathSuffix}`, - roles: ROLES.MICROPLAN, - }; - }; - - let links = [generateLink("CREATE_NEW_MICROPLAN", "select-campaign"), generateLink("OPEN_SAVED_MICROPLANS", "saved-microplans")]; - - links = links.filter((link) => (link?.roles && link?.roles?.length > 0 ? Digit.Utils.didEmployeeHasAtleastOneRole(link?.roles) : true)); - - const propsForModuleCard = { - Icon: , - moduleName: t("Microplanning"), - kpis: [], - links: links, - }; - return ; -}; - -export default MicroplanningCard; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js deleted file mode 100644 index 2a35e9c0995..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/MicroplanningHeader.js +++ /dev/null @@ -1,29 +0,0 @@ -import { Help, Tutorial, useTourState } from "@egovernments/digit-ui-react-components"; -import React, { Fragment } from "react"; -import { useTranslation } from "react-i18next"; -import { useLocation } from "react-router-dom"; -import { useMyContext } from "../utils/context"; -import { PRIMARY_THEME_COLOR } from "../configs/constants"; - -const MicroplanningHeader = () => { - const { tourState, setTourState } = useTourState(); - const { state } = useMyContext(); - const { t } = useTranslation(); - //using location.pathname we can update the stepIndex accordingly when help is clicked from any other screen(other than home screen) - const { pathname } = useLocation(); - - const startTour = () => { - if (state?.tourStateData) setTourState(state.tourStateData); - }; - - return ( - <> - -
- -
- - ); -}; - -export default MicroplanningHeader; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js deleted file mode 100644 index 0792ee2e52d..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Modal.js +++ /dev/null @@ -1,158 +0,0 @@ -import React, { useEffect } from "react"; -import { PopUp, HeaderBar, Toast, CloseButton, ButtonSelector } from "@egovernments/digit-ui-react-components"; -import { Close } from "@egovernments/digit-ui-svg-components"; -import { PRIMARY_THEME_COLOR } from "../configs/constants"; - -const Modal = ({ - headerBarMain, - headerBarEnd, - popupStyles, - children = {}, - actionCancelLabel, - actionCancelOnSubmit, - actionSaveLabel, - actionSaveOnSubmit, - error, - setError, - formId, - isDisabled, - hideSubmit, - style = {}, - footerLeftButtonstyle = {}, - footerRightButtonstyle = {}, - footerLeftButtonBody, - footerRightButtonBody, - popupModuleMianStyles, - headerBarMainStyle, - isOBPSFlow = false, - popupModuleActionBarStyles = {}, -}) => { - /** - * TODO: It needs to be done from the desgin changes - */ - const mobileView = Digit.Utils.browser.isMobile(); - useEffect(() => { - document.body.style.overflowY = "hidden"; - return () => { - document.body.style.overflowY = "auto"; - }; - }, []); - - return ( - -
- -
- {children} -
- {actionCancelLabel || footerLeftButtonBody ? ( - 0 ? style : footerLeftButtonstyle} - /> - ) : null} - {!hideSubmit ? ( - 0 ? style : footerRightButtonstyle} - /> - ) : null} -
-
-
- {error && setError(null)} type="error" />} -
- ); -}; - -const moduleActionBarStyle = (isOBPSFlow, popupModuleActionBarStyles) => { - return isOBPSFlow - ? !mobileView - ? { marginRight: "18px" } - : { position: "absolute", bottom: "5%", right: "10%", left: window.location.href.includes("employee") ? "0%" : "7%" } - : popupModuleActionBarStyles; -}; - -// Wrapper for modal -export const ModalWrapper = ({ - closeModal, - LeftButtonHandler, - RightButtonHandler, - footerLeftButtonBody, - footerRightButtonBody, - header, - bodyText, - body, - popupStyles, - headerBarMainStyle, - popupModuleActionBarStyles, - hideSubmit, - closeButton = false, - actionCancelLabel, -}) => { - return ( - - {" "} - - - ) : ( - "" - ) - } - actionCancelOnSubmit={LeftButtonHandler} - actionSaveOnSubmit={RightButtonHandler} - formId="microplanning" - popupStyles={{ width: "33.375rem", borderRadius: "0.25rem", ...(popupStyles ? popupStyles : {}) }} - headerBarMainStyle={{ margin: 0, width: "33.375rem", overflow: "hidden", ...(headerBarMainStyle ? headerBarMainStyle : {}) }} - popupModuleMianStyles={{ margin: 0, padding: 0 }} - popupModuleActionBarStyles={popupModuleActionBarStyles ? popupModuleActionBarStyles : { justifyContent: "space-between", padding: "1rem" }} - style={{}} - hideSubmit={hideSubmit ? hideSubmit : false} - footerLeftButtonstyle={{ - padding: 0, - alignSelf: "flex-start", - height: "fit-content", - textStyles: { fontWeight: "600" }, - backgroundColor: "rgba(255, 255, 255, 1)", - color: PRIMARY_THEME_COLOR, - minWidth: "15.063rem", - border: `0.063rem solid ${PRIMARY_THEME_COLOR}`, - }} - footerRightButtonstyle={{ - padding: 0, - alignSelf: "flex-end", - height: "fit-content", - textStyles: { fontWeight: "500" }, - backgroundColor: PRIMARY_THEME_COLOR, - color: "rgba(255, 255, 255, 1)", - minWidth: "15.063rem", - boxShadow: "0px -2px 0px 0px rgba(11, 12, 12, 1) inset", - }} - footerLeftButtonBody={footerLeftButtonBody} - footerRightButtonBody={footerRightButtonBody} - actionCancelLabel={actionCancelLabel} - > - {bodyText && ( -
-

{bodyText}

-
- )} - {body ? body : ""} -
- ); -}; - -export default Modal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js deleted file mode 100644 index 06d04ef2296..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Nagivator.js +++ /dev/null @@ -1,272 +0,0 @@ -import { ActionBar, Stepper, Toast } from "@egovernments/digit-ui-components"; -import PropTypes from "prop-types"; -import React, { useState, useEffect, useCallback } from "react"; -import { useTranslation } from "react-i18next"; -import { Button } from "@egovernments/digit-ui-react-components"; -import { ArrowBack, ArrowForward } from "@egovernments/digit-ui-svg-components"; -import { PRIMARY_THEME_COLOR } from "../configs/constants"; -import { memo } from "react"; - -/** - * - * @param { config: Object, checkDataCompleteness: boolean, components: Object, childProps: Object, stepNavigationActive: boolean, nextEventAddon: function, setCurrentPageExternally: function, completeNavigation } props - * @returns - * - */ -// Main component for creating a microplan -const Navigator = memo((props) => { - // States - const [currentPage, setCurrentPage] = useState(); - // const [toast, setToast] = useState(); - const [navigationEvent, setNavigationEvent] = useState(); - const [activeSteps, setActiveSteps] = useState(Digit.SessionStorage.get("microplanHelperData")?.activeSteps || -1); - /** - * checkDataCompletion - * "true": check for data completeness - * "false": do nothing - * "valid": data is present - * "invalid": whole or a part of the data is missing - * "perform-action": move to the respective step ( had to add this as mutate addons need some buffer time) - */ - const [checkDataCompletion, setCheckDataCompletion] = useState("false"); - - const { t } = useTranslation(); - - // Effect to set initial current page when timeline options change - useEffect(() => { - if (!props.config || props.config.length === 0) return; - let response; - if (props.setCurrentPageExternally) { - response = props.setCurrentPageExternally({ setCurrentPage, method: "set" }); - } - if (!response) setCurrentPage(props.config[0]); - }, [props.config]); - - // Might need it later - // Effect to handle data completion validation and show toast - useEffect(() => { - if (checkDataCompletion === "invalid") { - if (navigationEvent && navigationEvent.name === "next") { - props?.setToast({ state: "error", message: t("MICROPLAN_PLEASE_FILL_ALL_THE_FIELDS_AND_RESOLVE_ALL_THE_ERRORS") }); - } else if (navigationEvent && navigationEvent.name === "step" && navigationEvent.step !== undefined) { - if (navigationEvent.step > currentPage.id) - props?.setToast({ state: "error", message: t("MICROPLAN_PLEASE_FILL_ALL_THE_FIELDS_AND_RESOLVE_ALL_THE_ERRORS") }); - else onStepClick(navigationEvent.step); - } else if (navigationEvent && navigationEvent.name === "previousStep") previousStep(); - setCheckDataCompletion("false"); - } - }, [checkDataCompletion]); - - // Effect to handle navigation events and transition between steps - useEffect(() => { - // if (checkDataCompletion !== "valid" || navigationEvent === undefined) return; - if ( - checkDataCompletion === "valid" && - ((navigationEvent.step && currentPage.id + 1 === navigationEvent.step) || currentPage.id > navigationEvent.step || !navigationEvent.step) - ) { - if (typeof props.nextEventAddon === "function") { - if (LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null) - props.nextEventAddon(currentPage, checkDataCompletion, setCheckDataCompletion); - else props.nextEventAddon(currentPage, true, setCheckDataCompletion); - } else { - setCheckDataCompletion("perform-action"); - } - } - }, [navigationEvent, checkDataCompletion, props.nextEventAddon]); - - useEffect(() => { - handleNavigationEvent( - checkDataCompletion, - navigationEvent, - currentPage, - setCheckDataCompletion, - setNavigationEvent, - onStepClick, - nextStep, - previousStep, - props - ); - }, [checkDataCompletion, navigationEvent]); - - // Function to navigate to the next step - const nextStep = useCallback(() => { - if (!currentPage) return; - changeCurrentPage(props.config[currentPage?.id + 1]); - if (currentPage?.id + 1 > props.config.length - 1) return; - setCurrentPage((previous) => props.config[previous?.id + 1]); - }, [currentPage]); - - // Function to navigate to the previous step - const previousStep = useCallback(() => { - changeCurrentPage(props.config[currentPage?.id - 1]); - setCurrentPage((previous) => props.config[previous?.id - 1]); - }, [currentPage]); - - // Function to handle step click and navigate to the selected step - const onStepClick = useCallback((index) => { - const newCurrentPage = props.config.find((item) => item.id === index); - changeCurrentPage(newCurrentPage); - setCurrentPage(newCurrentPage); - }); - - // Function to handle next button click - const previousbuttonClickHandler = useCallback(() => { - if ( - (props.checkDataCompleteness && - props?.config[currentPage?.id]?.checkForCompleteness && - LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null) || - currentPage?.id === props.config[props.config.length - 1].id - ) { - setNavigationEvent({ name: "previousStep" }); - setCheckDataCompletion("true"); - } else previousStep(); - }, [props.checkDataCompleteness, previousStep, setNavigationEvent]); - - // Function to handle next button click - const nextbuttonClickHandler = useCallback(() => { - if ( - props.checkDataCompleteness && - props?.config[currentPage?.id]?.checkForCompleteness && - LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null - ) { - setCheckDataCompletion("true"); - setNavigationEvent({ name: "next" }); - } else nextStep(); - }, [props.checkDataCompleteness, nextStep, setNavigationEvent]); - - // Function to handle step click - const stepClickHandler = useCallback( - (index) => { - if (index === currentPage?.id) return; - if (!props.stepNavigationActive) return; - if ( - (props.checkDataCompleteness && - props?.config[currentPage?.id]?.checkForCompleteness && - LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null) || - currentPage?.id === props.config[props.config.length - 1].id - ) { - setCheckDataCompletion("true"); - setNavigationEvent({ name: "step", step: index }); - } else { - onStepClick(index); - } - }, - [props.checkDataCompleteness, props.stepNavigationActive, onStepClick] - ); - - // Function to set current page - const changeCurrentPage = (newPage) => { - if (props.setCurrentPageExternally) { - props.setCurrentPageExternally({ currentPage: newPage, method: "save" }); - } - }; - - const completeNavigation = () => { - setNavigationEvent({ name: "next" }); - setCheckDataCompletion("true"); - }; - - // changing active state - useEffect(() => { - if (currentPage?.id > activeSteps) { - setActiveSteps(currentPage?.id); - Digit.SessionStorage.set("microplanHelperData", { ...(Digit.SessionStorage.get("microplanHelperData") || {}), activeSteps: currentPage?.id }); - } - }, [currentPage]); - - return ( -
- {/* Stepper component */} - t(item.name))} - direction="horizontal" - activeSteps={activeSteps >= 0 ? activeSteps + 1 : null} - onStepClick={stepClickHandler} - /> - - {/* Load custom component based on current page */} - {props?.components[currentPage?.component] ? ( - LoadCustomComponent({ component: props.components[currentPage?.component] }) !== null ? ( - - ) : ( -
{t("COMMON_DATA_NOT_PRESENT")}
- ) - ) : ( - "" - )} - - {/* Action bar */} - - {/* Back button */} - {currentPage?.id > 0 && ( - - -
- ); -}); - -// Component to load custom component based on current page -const LoadCustomComponent = (props) => { - if (props && !props.component) return null; - const secondaryProps = props.secondaryProps; - return ; -}; -LoadCustomComponent.propTypes = { - component: PropTypes.elementType.isRequired, - secondaryProps: PropTypes.object, -}; - -const handleNavigationEvent = ( - checkDataCompletion, - navigationEvent, - currentPage, - setCheckDataCompletion, - setNavigationEvent, - onStepClick, - nextStep, - previousStep, - props -) => { - if (checkDataCompletion === "perform-action") { - if (navigationEvent && navigationEvent.name === "next") { - if (currentPage?.id === props.config.length - 1 && typeof props?.completeNavigation === "function") { - return props?.completeNavigation(); - } - nextStep(); - } else if (navigationEvent && navigationEvent.name === "step" && navigationEvent.step !== undefined) onStepClick(navigationEvent.step); - else if (navigationEvent && navigationEvent.name === "previousStep") previousStep(); - setCheckDataCompletion("false"); - setNavigationEvent(undefined); - } -}; - -export default Navigator; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js deleted file mode 100644 index 7ece3cce04d..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/RuleEngine.js +++ /dev/null @@ -1,876 +0,0 @@ -import React, { useState, useEffect, useCallback, Fragment, useRef } from "react"; -import { useTranslation } from "react-i18next"; -import { Info, Trash } from "@egovernments/digit-ui-svg-components"; -import { ModalHeading } from "./CommonComponents"; -import { Button, Modal } from "@egovernments/digit-ui-react-components"; -import { Dropdown, InfoCard, Toast } from "@egovernments/digit-ui-components"; -import { tourSteps } from "../configs/tourSteps"; -import { useMyContext } from "../utils/context"; -import { v4 as uuidv4 } from "uuid"; -import { PlusWithSurroundingCircle } from "../icons/Svg"; -import { PRIMARY_THEME_COLOR } from "../configs/constants"; - -const page = "ruleEngine"; - -const RuleEngine = ({ - campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, - microplanData, - setMicroplanData, - checkDataCompletion, - setCheckDataCompletion, - currentPage, - pages, - setToast, -}) => { - const { t } = useTranslation(); - - // States - const [editable, setEditable] = useState(true); - const [modal, setModalState] = useState("none"); - const [rules, setRules] = useState([]); - const [hypothesisAssumptionsList, setHypothesisAssumptionsList] = useState([]); - const [itemForDeletion, setItemForDeletion] = useState(); - const [exampleOption, setExampleOption] = useState(""); - const [inputs, setInputs] = useState([]); - const [outputs, setOutputs] = useState([]); - const [operators, setOperators] = useState([]); - const [validationSchemas, setValidationSchemas] = useState([]); - const [autofillData, setAutoFillData] = useState([]); - const { state, dispatch } = useMyContext(); - const [originalRuleOutputCount, setOriginalRuleOutputCount] = useState(0); - // const [toast, setToast] = useState(); - const [pureInputList, setPureInputList] = useState([]); - // Set TourSteps - useEffect(() => { - const tourData = tourSteps(t)?.[page] || {}; - if (state?.tourStateData?.name === page) return; - dispatch({ - type: "SETINITDATA", - state: { tourStateData: tourData }, - }); - }, []); - - const setModal = (modalString) => { - const elements = document.querySelectorAll(".popup-wrap-rest-unfocus"); - elements.forEach((element) => { - element.classList.toggle("popup-wrap-rest-unfocus-active"); - }); - setModalState(modalString); - }; - - // UseEffect to extract data on first render - useEffect(() => { - if (pages) { - const previouspage = pages[currentPage?.id - 1]; - if (previouspage?.checkForCompleteness && !microplanData?.status?.[previouspage?.name]) setEditable(false); - else setEditable(true); - } - }, []); - - // UseEffect for checking completeness of data before moveing to next section - useEffect(() => { - if (!rules || checkDataCompletion !== "true" || !setCheckDataCompletion) return; - // uncomment to activate data change save check - // if (!microplanData?.ruleEngine || !_.isEqual(rules, microplanData.ruleEngine)) setModal("data-change-check"); - // else - updateData(true); - }, [checkDataCompletion]); - - // UseEffect to store current data - useEffect(() => { - if (!rules || !setMicroplanData) return; - setMicroplanData((previous) => ({ ...previous, ruleEngine: rules })); - }, [rules]); - - // UseEffect to add a event listener for keyboard - useEffect(() => { - window.addEventListener("keydown", handleKeyPress); - - return () => window.removeEventListener("keydown", handleKeyPress); - }, [modal]); - - const handleKeyPress = (event) => { - // if (modal !== "upload-guidelines") return; - if (["x", "Escape"].includes(event.key)) { - // Perform the desired action when "x" or "esc" is pressed - // if (modal === "upload-guidelines") - setCheckDataCompletion("false"); - setModal("none"); - } - }; - - // check if data has changed or not - const updateData = useCallback( - (check) => { - if (!rules || !setMicroplanData) return; - if (check) { - setMicroplanData((previous) => ({ ...previous, ruleEngine: rules })); - const activeRules = rules.filter((item) => item.active); - const isValid = activeRules.every((item) => Object.values(item).every((data) => data !== "")) && activeRules.length !== 0; - if (isValid) setCheckDataCompletion("valid"); - else setCheckDataCompletion("invalid"); - } else { - let isValid = microplanData?.ruleEngine?.every((item) => Object.values(item).every((data) => data !== "")); - isValid = isValid && rules.length !== 0; - if (isValid) setCheckDataCompletion("valid"); - else setCheckDataCompletion("invalid"); - } - }, - [rules, setMicroplanData, microplanData, setCheckDataCompletion] - ); - - const cancelUpdateData = useCallback(() => { - setCheckDataCompletion(false); - setModal("none"); - }, [setCheckDataCompletion, setModal]); - - // useEffect to initialise the data from MDMS - useEffect(() => { - if (!state) return; - const schemas = state?.Schemas; - const hypothesisAssumptions = []; - microplanData?.hypothesis?.filter((item) => item.active).forEach((item) => (item.key !== "" ? hypothesisAssumptions.push(item.key) : null)); - const ruleConfigureOutput = state?.RuleConfigureOutput; - const UIConfiguration = state?.UIConfiguration; - const ruleConfigureInputs = getRuleConfigInputsFromSchema(campaignType, microplanData, schemas) || []; - let AutoFilledRuleConfigurationsList = state?.AutoFilledRuleConfigurations; - AutoFilledRuleConfigurationsList = AutoFilledRuleConfigurationsList.find((item) => item.campaignType === campaignType)?.data; - microplanData?.ruleEngine?.forEach((item) => { - if (Object.values(item).every((e) => e !== "")) ruleConfigureInputs.push(item?.output); - }); - if (schemas) setValidationSchemas(schemas); - - let temp; - setHypothesisAssumptionsList(hypothesisAssumptions); - let outputs; - if (ruleConfigureOutput) temp = ruleConfigureOutput?.find((item) => item.campaignType === campaignType); - if (temp?.data) { - let data = temp.data; - setOriginalRuleOutputCount(data.length); - microplanData?.ruleEngine?.forEach((item) => { - if (item.active) { - const filteredData = data.filter((e) => e !== item?.output); - data = filteredData; - } - }); - outputs = data; - setOutputs(data); - } - - if (ruleConfigureInputs) setInputs(ruleConfigureInputs); - let operator; - if (UIConfiguration) temp = UIConfiguration.find((item) => item.name === "ruleConfigure"); - if (temp?.ruleConfigureOperators) { - temp = temp.ruleConfigureOperators.map((item) => item.name); - operator = temp; - setOperators(temp); - } - // if (AutoFilledRuleConfigurationsList) setAutoFillData(AutoFilledRuleConfigurationsList); - // Pure inputs - output not there - const pureInputs = getRuleConfigInputsFromSchema(campaignType, microplanData, schemas); - setPureInputList(pureInputs); - - const ssnRuleOutputs = microplanData?.ruleEngine?.reduce((acc, item) => { - if (item?.active && item?.output) acc.push(item?.output); - return acc; - }, []); - const tempOutput = [...outputs, ...(ssnRuleOutputs ? ssnRuleOutputs : [])]; - setExampleOption({ - output: tempOutput.length ? tempOutput[0] : "", - input: pureInputs.length ? pureInputs[0] : "", - operator: operator.length ? operator[0] : "", - assumptionValue: hypothesisAssumptions.length ? hypothesisAssumptions[0] : "", - }); - - let filteredRules = []; - let response; - if (microplanData?.ruleEngine && microplanData?.hypothesis) { - const hypothesisAssumptions = microplanData?.hypothesis?.filter((item) => item.active && item.key !== "").map((item) => item.key) || []; - if (hypothesisAssumptions.length !== 0) { - setHypothesisAssumptionsList(hypothesisAssumptions); - response = filterRulesAsPerConstrains( - microplanData.ruleEngine, - [], - hypothesisAssumptions, - tempOutput, - operator, - pureInputs, - setInputs, - setOutputs, - false - ); - filteredRules = response?.rules; - - // setRuleEngineDataFromSsn(microplanData.ruleEngine, hypothesisAssumptions, setRules); - } - } - if (response?.rulesDeleted) - setToast({ - state: "warning", - message: t("WARNING_RULES_DELETED_DUE_TO_PRIOR_SECTION_DATA_CHANGES"), - }); - if (!AutoFilledRuleConfigurationsList || !outputs || !hypothesisAssumptions || !schemas) return; - - response = filterRulesAsPerConstrains( - AutoFilledRuleConfigurationsList, - filteredRules, - hypothesisAssumptions, - outputs, - operator, - pureInputs, - setInputs, - setOutputs, - true - ); - - if (response?.rules) setRules(response?.rules); - }, []); - - const closeModal = useCallback(() => { - setModal("none"); - }, [setModal]); - - // Function to Delete an assumption - const deleteAssumptionHandlerCallback = useCallback(() => { - deleteAssumptionHandler(itemForDeletion, setItemForDeletion, setRules, setOutputs, setInputs, pureInputList); - closeModal(); - }, [itemForDeletion, deleteAssumptionHandler, setItemForDeletion, setRules, setOutputs, setInputs, closeModal, pureInputList]); - - const sectionClass = `jk-header-btn-wrapper rule-engine-section ${editable ? "" : "non-editable-component"} popup-wrap-rest-unfocus`; - return ( - <> -
-
-
- {/* NonInterractable Section */} - - {/* Interractable Section that includes the example as well as the rules */} - -
- -
-
- {/* delete conformation */} -
- {modal === "delete-conformation" && ( - } - actionCancelLabel={t("YES")} - actionCancelOnSubmit={deleteAssumptionHandlerCallback} - actionSaveLabel={t("NO")} - actionSaveOnSubmit={closeModal} - > -
-

{t("RULE_ENGINE_INSTRUCTIONS_DELETE_ENTRY_CONFIRMATION")}

-
-
- )} -
- - ); -}; - -// Function to add a new assumption -const addRulesHandler = (setRules) => { - const uuid = uuidv4(); - setRules((previous) => [ - ...previous, - { - id: uuid, - // previous.length ? previous[previous.length - 1].id + 1 : 0, - output: "", - input: "", - operator: "", - assumptionValue: "", - active: true, - }, - ]); -}; - -// Defination for NonInterractable Section -const NonInterractableSection = React.memo(({ t }) => { - return ( -
-

{t("HEADING_RULE_ENGINE")}

-

{t("INSTRUCTION_RULE_ENGINE")}

-
- ); -}); - -// Defination for NonInterractable Section -const InterractableSection = React.memo( - ({ - rules, - setRules, - hypothesisAssumptionsList, - setHypothesisAssumptionsList, - setModal, - setItemForDeletion, - exampleOption, - inputs, - outputs, - operators, - setInputs, - setOutputs, - setOperators, - pureInputList, - t, - }) => { - // References to the items in the list - const itemRefs = useRef([]); - // State to keep track of the currently expanded item index - const [expandedIndex, setExpandedIndex] = useState(null); - // Reference to the scroll container - const scrollContainerRef = useRef(null); - // State to track the render cycle count - const [renderCycle, setRenderCycle] = useState(0); - - // Effect to reset the render cycle count whenever the expandedIndex changes - useEffect(() => { - if (expandedIndex !== null) { - setRenderCycle(0); - } - }, [expandedIndex]); - - // Effect to handle scrolling to the expanded item after the DOM has updated - useEffect(() => { - if (renderCycle < 3) { - // Increment render cycle count to ensure multiple render checks - setRenderCycle((prev) => prev + 1); - } else if (expandedIndex !== null && itemRefs.current[expandedIndex]) { - try { - const parentElement = itemRefs.current[expandedIndex]; - const childElement = itemRefs.current[expandedIndex].children[1]; - - if (parentElement) { - const scrollContainer = scrollContainerRef.current; - const parentRect = parentElement.getBoundingClientRect(); - const containerRect = scrollContainer.getBoundingClientRect(); - - // Calculate the offset from the top of the container - const offset = parentRect.top - containerRect.top; - - // Scroll the container to the target position - scrollContainer.scrollTo({ - top: scrollContainer.scrollTop + offset - 100, - behavior: "smooth", - }); - } - - if (childElement) { - // Focus the child element if it exists - childElement.focus(); - } - } catch (error) { - console.error("Error scrolling to element:", error); - } - } - }, [renderCycle, expandedIndex]); - - // Effect to observe DOM changes in the expanded item and trigger render cycle - useEffect(() => { - if (expandedIndex !== null) { - const observer = new MutationObserver(() => { - setRenderCycle((prev) => prev + 1); - }); - - if (itemRefs.current[expandedIndex]) { - observer.observe(itemRefs.current[expandedIndex], { childList: true, subtree: true }); - } - - return () => observer.disconnect(); - } - }, [expandedIndex]); - - // Function to toggle the expanded state of an item - const toggleExpand = (index) => { - setExpandedIndex(index === expandedIndex ? null : index); - }; - - // Handler for deleting an assumption on conformation - const deleteHandler = useCallback( - (item) => { - setModal("delete-conformation"); - setItemForDeletion(item); - }, - [setModal, setItemForDeletion] - ); - - return ( -
- -
-
-
-

{t("VALUE")}

-
-
=
-
-

{t("RULE_ENGINE_INPUT")}

-
-
-

{t("RULE_ENGINE_OPERATOR")}

-
-
-

{t("KEY")}

-
-
- -
-
- {rules - .filter((item) => item.active) - .map((item, index) => ( -
{ - itemRefs.current[index] = el; - }} - onClick={() => toggleExpand(index)} - > -
- -
-
- -
-
- -
-
- ))} -
-
- ); - } -); - -const Example = ({ exampleOption, t }) => { - return ( -
-
-

{t("EXAMPLE")}

-
-
-

{t("VALUE")}

- -

{t("RULE_ENGINE_VALUE_HELP_TEXT")}

-
- -
-

{"="}

- -
=
-

{"="}

-
- -
-

{t("RULE_ENGINE_INPUT")}

- -

{t("RULE_ENGINE_INPUT_HELP_TEXT")}

-
-
-

{t("RULE_ENGINE_OPERATOR")}

- -

{t("RULE_ENGINE_OPERATOR_HELP_TEXT")}

-
-
-

{t("KEY")}

- -

{t("RULE_ENGINE_KEY_HELP_TEXT")}

-
-
-
-
- -
-
- ); -}; - -const deleteAssumptionHandler = (item, setItemForDeletion, setRules, setOutputs, setInputs, pureInputList) => { - try { - const outputToRemove = []; - setRules((previous) => { - if (!previous.length) return []; - const deletionElementIndex = previous.findIndex((data) => data.id === item.id); - const filteredData = previous.map((data, index) => (index === deletionElementIndex ? { ...data, active: false } : data)); - const newRules = filteredData.reduce((acc, dataItem, index) => { - if (dataItem.active) { - const possibleOutputs = acc.reduce((reducedData, element, index) => { - if (element.active && !Object.values(element).some((e) => e === "")) reducedData.push(element?.output); - return reducedData; - }, []); - possibleOutputs.push(...pureInputList); - if (!possibleOutputs.includes(dataItem?.input)) { - if (dataItem?.output !== "") outputToRemove.push(dataItem.output); - acc.push({ ...dataItem, input: "", oldInput: dataItem?.input ? dataItem?.input : dataItem?.oldInput }); - } else { - acc.push(dataItem); - } - } else { - acc.push(dataItem); - } - return acc; - }, []); - - return newRules || []; - }); - if (item?.output) { - setOutputs((previous) => { - if (!previous?.includes(item.output)) return previous ? [...previous, item.output] : [item.output]; - }); - setInputs((previous) => { - return previous?.filter((e) => e !== item.output && !outputToRemove.includes(e)); - }); - } - setItemForDeletion(); - } catch (error) { - console.error("Error while deleting a rule: ", error.message); - } -}; - -const Select = React.memo( - ({ item, rules, setRules, disabled = false, options, setOptions, toChange, unique, setInputs, outputs, pureInputList, t }) => { - const [selected, setSelected] = useState(""); - const [filteredOptions, setFilteredOptions] = useState([]); - - useEffect(() => { - if (item) { - if (outputs?.some((e) => e === item.input)) { - if (rules.filter((item) => item.active).some((e) => e?.output === item?.input)) setSelected({ code: item?.[toChange] }); - } else setSelected({ code: item[toChange] }); - } - }, [item]); - - useEffect(() => { - if (!options) return; - const filteredOptions = options.length ? options : []; - let filteredOptionPlaceHolder = []; - if (item?.[toChange] && !filteredOptions.includes(item[toChange])) { - filteredOptionPlaceHolder = [item[toChange], ...filteredOptions]; - } else filteredOptionPlaceHolder = filteredOptions; - - if (toChange === "input") { - const currentRuleIndex = rules.findIndex((e) => e?.id === item?.id); - filteredOptionPlaceHolder = filteredOptionPlaceHolder.filter((data) => { - let priorOutputs = []; - if (currentRuleIndex !== -1) { - priorOutputs = rules.reduce((acc, item, index) => { - if (item.active && index < currentRuleIndex) acc.push(item?.output); - return acc; - }, []); - } - priorOutputs.push(...pureInputList); - return data !== item.output && priorOutputs.includes(data); - }); - } - setFilteredOptions(filteredOptionPlaceHolder); - }, [options]); - - const selectChangeHandler = useCallback( - (e) => { - if (e.code === "SELECT_OPTION") return; - const existingEntry = rules.find((item) => item.active && item[toChange] === e.code); - if (existingEntry && unique) { - console.error("Attempted to add a duplicate entry where uniqueness is required."); - return; - } - const newDataSegment = { ...item }; - newDataSegment[toChange] = e.code; - setRules((previous) => { - const filteredAssumptionsList = previous.map((data) => { - if (data.id === item.id) return newDataSegment; - return data; - }); - return filteredAssumptionsList; - }); - if (typeof setInputs === "function") { - setInputs((previous) => { - let temp = _.cloneDeep(previous); - if (toChange === "output") { - temp = temp.filter((item) => item !== selected?.code); - } - if (!temp.includes(newDataSegment.output) && Object.values(newDataSegment).every((item) => item !== "")) - temp = [...temp, newDataSegment.output]; - - const currentRuleIndex = rules.findIndex((e) => e?.id === item?.id); - temp = temp.filter((data) => { - let priorOutputs = []; - if (currentRuleIndex !== -1) { - priorOutputs = rules.reduce((acc, item, index) => { - if (index < currentRuleIndex) acc.push(item?.output); - return acc; - }, []); - } - priorOutputs.push(...pureInputList); - return data !== item.output && priorOutputs.includes(data); - }); - return temp; - }); - } - if (unique) - setOptions((previous) => { - const newOptions = previous.filter((item) => item !== e.code); - if (selected?.code && !newOptions.includes(selected?.code)) newOptions.unshift(selected?.code); - return newOptions; - }); - }, - [rules, item, selected, setRules, setOptions, setInputs] - ); - - return ( - ({ code: item }))} - selected={selected} - select={selectChangeHandler} - optionKey="code" - placeholder={t("SELECT_OPTION")} - showToolTip={true} - /> - ); - } -); - -// get schema for validation -const getRuleConfigInputsFromSchema = (campaignType, microplanData, schemas) => { - if (!schemas || !microplanData || !microplanData?.upload || !campaignType) return []; - const sortData = []; - if (!schemas) return; - for (const value of microplanData?.upload?.filter((value) => value?.active && value?.error === null) || []) { - sortData.push({ section: value?.section, fileType: value?.fileType }); - } - const filteredSchemas = - schemas?.filter((schema) => { - if (schema.campaignType) { - return schema.campaignType === campaignType && sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); - } - return sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); - }) || []; - const finalData = filteredSchemas - ?.flatMap((item) => - Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.isRuleConfigureInputs) { - acc.push(key); - } - return acc; - }, []) - ) - .filter((item) => !!item); - return [...new Set(finalData)]; -}; - -// This function adding the rules configures in MDMS with respect to the canpaign when rule section is empty -const filterRulesAsPerConstrains = (autofillData, rules, hypothesisAssumptionsList, outputs, operators, inputs, setInputs, setOutputs, autofill) => { - if (rules && rules.filter((item) => item.active).length !== 0) return { rules }; - - let wereRulesNotDeleted = true; - const newRules = []; - const ruleOuputList = rules ? rules.filter((item) => item.active).map((item) => item?.output) : []; - let rulePlusInputs; - if (ruleOuputList) rulePlusInputs = [...inputs, ...ruleOuputList]; - else rulePlusInputs = inputs; - for (const item of autofillData) { - let active = !(item && item.active === false); - const ruleNotCompleteCheck = (!autofill && item && Object.values(item).filter((e) => e === "").length === 0) || autofill; - if ( - (ruleOuputList?.includes(item?.output) || - (outputs && !outputs.includes(item?.output)) || - (rulePlusInputs && !rulePlusInputs.includes(item?.input)) || - (operators && !operators.includes(item?.operator)) || - (hypothesisAssumptionsList && !hypothesisAssumptionsList.includes(item?.assumptionValue)) || - !outputs || - !rulePlusInputs || - !operators || - !hypothesisAssumptionsList) && - ruleNotCompleteCheck - ) { - if (autofill) { - continue; - } - if (active) { - wereRulesNotDeleted = false; - active = false; - } - } - if (!item["id"]) { - const uuid = uuidv4(); - item["id"] = uuid; - } - item.active = active; - newRules.push(item); - if (active && ruleNotCompleteCheck) { - rulePlusInputs?.push(item?.output); - ruleOuputList?.push(item?.output); - } - } - if (newRules.length !== 0) { - let newOutputs = []; - outputs.forEach((e) => { - if (!ruleOuputList.includes(e)) { - newOutputs.push(e); - } - }); - setOutputs(newOutputs); - setInputs(rulePlusInputs); - // setRules((previous) => [...previous, ...newRules]); - } - - return { rules: [...(rules ? rules : []), ...newRules], rulesDeleted: !autofill && !wereRulesNotDeleted }; -}; - -export default RuleEngine; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js deleted file mode 100644 index e6309dd74f3..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/Upload.js +++ /dev/null @@ -1,1137 +0,0 @@ -import React, { useState, useEffect, useMemo, Fragment, useCallback } from "react"; -import { useTranslation } from "react-i18next"; -import { LoaderWithGap, Modal } from "@egovernments/digit-ui-react-components"; -import { ModalWrapper } from "./Modal"; -import { geojsonPropertiesValidation } from "../utils/geojsonValidations"; -import { SpatialDataPropertyMapping } from "./resourceMapping"; -import { JsonPreviewInExcelForm } from "./JsonPreviewInExcelForm"; -import { ButtonType1, ButtonType2, CloseButton, ModalHeading } from "./CommonComponents"; -import { Loader } from "@egovernments/digit-ui-components"; -import { EXCEL, FILE_STORE, GEOJSON, PRIMARY_THEME_COLOR, SHAPEFILE } from "../configs/constants"; -import { tourSteps } from "../configs/tourSteps"; -import { useMyContext } from "../utils/context"; -import { v4 as uuidv4 } from "uuid"; -import { - handleExcelFile, - validateNamingConvention, - findReadMe, - downloadTemplate, - getSchema, - prepareExcelFileBlobWithErrors, - boundaryDataGeneration, - handleGeojsonFile, - handleShapefiles, - convertToSheetArray, - findGuideLine, - delay, -} from "../utils/uploadUtils"; -import { UploadGuideLines, UploadedFile, FileUploadComponent, UploadComponents, UploadInstructions, UploadSection } from "./UploadHelperComponents"; - -const page = "upload"; - -const Upload = ({ - MicroplanName = "default", - campaignType = Digit.SessionStorage.get("microplanHelperData")?.campaignData?.projectType, - microplanData, - setMicroplanData, - checkDataCompletion, - setCheckDataCompletion, - currentPage, - pages, - navigationEvent, - setToast, -}) => { - const { t } = useTranslation(); - - // States - const [editable, setEditable] = useState(true); - const [sections, setSections] = useState([]); - const [selectedSection, setSelectedSection] = useState(null); - const [modal, setModalState] = useState("none"); - const [selectedFileType, setSelectedFileType] = useState(null); - const [dataPresent, setDataPresent] = useState(false); - const [dataUpload, setDataUpload] = useState(false); - const [loader, setLoader] = useState(false); - const [fileData, setFileData] = useState(); - const [uploadedFileError, setUploadedFileError] = useState(); - const [fileDataList, setFileDataList] = useState([]); - const [validationSchemas, setValidationSchemas] = useState([]); - const [template, setTemplate] = useState([]); - const [resourceMapping, setResourceMapping] = useState([]); - const [previewUploadedData, setPreviewUploadedData] = useState(); - const { state, dispatch } = useMyContext(); - - //fetch campaign data - const { id = "" } = Digit.Hooks.useQueryParams(); - const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( - { - CampaignDetails: { - tenantId: Digit.ULBService.getCurrentTenantId(), - ids: [id], - }, - }, - { - enabled: !!id, - } - ); - - // request body for boundary hierarchy api - const reqCriteria = { - url: `/boundary-service/boundary-hierarchy-definition/_search`, - params: {}, - body: { - BoundaryTypeHierarchySearchCriteria: { - tenantId: Digit.ULBService.getCurrentTenantId(), - hierarchyType: campaignData?.hierarchyType, - // hierarchyType: "Microplan", - }, - }, - config: { - enabled: !!campaignData?.hierarchyType, - select: (data) => { - return ( - data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map( - (item) => `${campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item?.boundaryType)}` - ) || {} - ); - }, - }, - }; - const { isLoading: ishierarchyLoading, data: hierarchy } = Digit.Hooks.useCustomAPIHook(reqCriteria); - // Set TourSteps - useEffect(() => { - const tourData = tourSteps(t)?.[page] || {}; - if (state?.tourStateData?.name === page) return; - dispatch({ - type: "SETINITDATA", - state: { tourStateData: tourData }, - }); - }, [t]); - - const setModal = (modalString) => { - const elements = document.querySelectorAll(".popup-wrap-rest-unfocus"); - elements.forEach((element) => { - element.classList.toggle("popup-wrap-rest-unfocus-active"); - }); - setModalState(modalString); - }; - - // UseEffect for checking completeness of data before moveing to next section - useEffect(() => { - if (!fileDataList || checkDataCompletion !== "true" || !setCheckDataCompletion) return; - updateData(true); - }, [checkDataCompletion]); - - // UseEffect to store current data - useEffect(() => { - if (!fileDataList || !setMicroplanData) return; - setMicroplanData((previous) => ({ ...previous, upload: fileDataList })); - }, [fileDataList]); - - // check if data has changed or not - const updateData = useCallback( - (check) => { - if (!fileDataList || !setMicroplanData) return; - - // if user has selected a file type and wants to go back to file type selection he/she can click back buttom - const currentSectionIndex = sections.findIndex((item) => item.id === selectedSection.id); - if (!dataPresent) { - if (navigationEvent?.name !== "step") { - if (navigationEvent?.name === "next") { - if (currentSectionIndex < sections.length - 1) { - setSelectedSection(sections[currentSectionIndex + 1]); - setCheckDataCompletion("false"); - return; - } - } else if (navigationEvent?.name === "previousStep") { - if (dataUpload) { - setDataUpload(false); - setSelectedFileType(null); - setCheckDataCompletion("false"); - return; - } - if (currentSectionIndex > 0) { - setSelectedSection(sections[currentSectionIndex - 1]); - setCheckDataCompletion("false"); - return; - } - } - } - } else { - if (navigationEvent?.name === "next") { - if (currentSectionIndex < sections.length - 1) { - setSelectedSection(sections[currentSectionIndex + 1]); - setCheckDataCompletion("false"); - return; - } - } else if (navigationEvent?.name === "previousStep") { - if (currentSectionIndex > 0) { - setSelectedSection(sections[currentSectionIndex - 1]); - setCheckDataCompletion("false"); - return; - } - } - } - - if (check) { - setMicroplanData((previous) => ({ ...previous, upload: fileDataList })); - const valueList = fileDataList ? fileDataList : []; - const sectionCheckList = sections?.filter((item) => item.required); - - if ( - valueList.length !== 0 && - sectionCheckList.every((item) => { - const filteredList = fileDataList?.filter((e) => e.active && e.templateIdentifier === item.id); - if (filteredList?.length === 0) return false; - return filteredList?.every((element) => element?.error === null) && fileDataList && !fileDataList.some((e) => e?.active && e?.error); - }) - ) - setCheckDataCompletion("valid"); - else setCheckDataCompletion("invalid"); - } else { - const valueList = microplanData?.Upload ? Object.values(microplanData?.Upload) : []; - if ( - valueList.length !== 0 && - sectionCheckList.every((item) => - fileDataList?.filter((e) => e.templateIdentifier === item.id)?.every((element) => element.active && element?.error === null) - ) - ) - setCheckDataCompletion("valid"); - else setCheckDataCompletion("invalid"); - } - }, - [fileDataList, setMicroplanData, microplanData, setCheckDataCompletion, dataPresent, dataUpload, navigationEvent] - ); - - // UseEffect to extract data on first render - useEffect(() => { - if (microplanData?.upload) { - setFileDataList(microplanData.upload); - } - - if (pages) { - const previouspage = pages[currentPage?.id - 1]; - if (previouspage?.checkForCompleteness && !microplanData?.status?.[previouspage?.name]) setEditable(false); - else setEditable(true); - } - }, []); - - // UseEffect to add a event listener for keyboard - useEffect(() => { - window.addEventListener("keydown", handleKeyPress); - - return () => window.removeEventListener("keydown", handleKeyPress); - }, [modal, previewUploadedData]); - - const handleKeyPress = (event) => { - // if (modal !== "upload-guidelines") return; - if (["x", "Escape"].includes(event.key)) { - // Perform the desired action when "x" or "esc" is pressed - if (modal === "upload-guidelines") { - setModal("none"); - } - if (previewUploadedData) setPreviewUploadedData(undefined); - } - }; - - // Effect to update sections and selected section when data changes - useEffect(() => { - if (state) { - const uploadSections = state?.UploadConfiguration; - const schemas = state?.Schemas; - if (schemas) setValidationSchemas(schemas); - if (uploadSections) { - setSelectedSection(uploadSections.length > 0 ? uploadSections[0] : null); - setSections(uploadSections); - } - } - }, []); - - // Memoized section options to prevent unnecessary re-renders - const sectionOptions = useMemo(() => { - if (!sections) return []; - return sections.map((item) => ( - e.active && e.templateIdentifier === item.id && !e.error)?.length !== 0} - /> - )); - }, [sections, selectedSection, fileDataList]); - - const showDownloadTemplate = () => { - if (selectedSection?.UploadFileTypes) { - const schema = getSchema(campaignType, selectedFileType?.id, selectedSection.id, validationSchemas); - if (schema?.template?.showTemplateDownload) return true; - } - return false; - }; - - // Handler for when a file type is selected for uplaod - const selectFileTypeHandler = (e) => { - if (selectedSection?.UploadFileTypes) { - const schema = getSchema(campaignType, e.target.name, selectedSection.id, validationSchemas); - setSelectedFileType(selectedSection.UploadFileTypes.find((item) => item.id === e.target.name)); - if (schema?.template?.showTemplateDownload) setModal("upload-modal"); - else UploadFileClickHandler(false); - return; - } - setToast({ - state: "error", - message: t("ERROR_UNKNOWN"), - }); - setLoader(false); - return; - }; - - // Memoized section components to prevent unnecessary re-renders - const sectionComponents = useMemo(() => { - if (!sections) return; - return sections.map((item) => ( - - )); - }, [sections, selectedSection, selectedFileType]); - - // Close model click handler - const closeModal = () => { - setResourceMapping([]); - setModal("none"); - }; - - // handler for show file upload screen - const UploadFileClickHandler = (download = false) => { - if (download) { - downloadTemplateHandler(); - } - setModal("none"); - setDataUpload(true); - }; - const readMeConstant = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName"); - const downloadTemplateHandler = () => { - const downloadParams = { - campaignType, - type: selectedFileType.id, - section: selectedSection.id, - setToast, - campaignData, - hierarchyType: campaignData?.hierarchyType, - Schemas: validationSchemas, - HierarchyConfigurations: state?.HierarchyConfigurations, - setLoader, - hierarchy, - readMeData: state?.ReadMeData, - readMeSheetName: readMeConstant ? readMeConstant.value : undefined, - t, - }; - downloadTemplate(downloadParams); - }; - // Effect for updating current session data in case of section change - useEffect(() => { - if (selectedSection) { - let file = fileDataList?.find((item) => item.active && item.templateIdentifier === selectedSection.id); - if (file?.resourceMapping) { - setSelectedFileType(selectedSection.UploadFileTypes.find((item) => item?.id === file?.fileType)); - setUploadedFileError(file?.error); - setFileData(file); - setDataPresent(true); - } else { - resetSectionState(); - } - } else { - resetSectionState(); - } - }, [selectedSection]); - - const resetSectionState = () => { - setUploadedFileError(null); - setSelectedFileType(null); - setDataPresent(false); - setResourceMapping([]); - setDataUpload(false); - }; - - // Function for handling upload file event - const UploadFileToFileStorage = async (file) => { - if (!file) return; - try { - // setting loader - setLoader("FILE_UPLOADING"); - let check; - let fileDataToStore; - let errorMsg; - let errorLocationObject; // object containing the location and type of error - let response; - let callMapping = false; - // Checking if the file follows name convention rules - if (!validateNamingConvention(file, selectedFileType["namingConvention"], setToast, t)) { - setLoader(false); - return; - } - - let schemaData; - if (selectedFileType.id !== SHAPEFILE) { - // Check if validation schema is present or not - schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); - if (!schemaData) { - setToast({ - state: "error", - message: t("ERROR_VALIDATION_SCHEMA_ABSENT"), - }); - setLoader(false); - return; - } - } - let resourceMappingData = []; - let additionalSheets = []; - // Handling different filetypes - switch (selectedFileType.id) { - case EXCEL: - // let response = handleExcelFile(file,schemaData); - try { - response = await handleExcelFile( - file, - schemaData, - hierarchy, - selectedFileType, - {}, - setUploadedFileError, - t, - campaignData, - state?.CommonConstants?.find((item) => item?.name === "readMeSheetName")?.value - ); - check = response.check; - errorMsg = response.errorMsg; - errorLocationObject = response.errors; - fileDataToStore = response.fileDataToStore; - resourceMappingData = response?.tempResourceMappingData || []; - additionalSheets = response?.additionalSheets; - if (check === true) { - if (response?.toast) setToast(response.toast); - else setToast({ state: "success", message: t("FILE_UPLOADED_SUCCESSFULLY") }); - } else if (response.toast) { - setToast(response.toast); - } else { - setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); - } - if (response.interruptUpload) { - setLoader(false); - return; - } - } catch (error) { - console.error("Excel parsing error", error.message); - setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); - handleValidationErrorResponse(t("ERROR_UPLOADED_FILE")); - return; - } - break; - case GEOJSON: - try { - response = await handleGeojsonFile(file, schemaData, setUploadedFileError, t); - file = new File([file], file.name, { type: "application/geo+json" }); - if (response.check === false && response.stopUpload) { - setLoader(false); - setToast(response.toast); - return; - } - check = response.check; - errorMsg = response.error; - fileDataToStore = response.fileDataToStore; - callMapping = true; - } catch (error) { - // console.error("Geojson parsing error", error.message); - setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); - handleValidationErrorResponse(t("ERROR_UPLOADED_FILE")); - return; - } - break; - case SHAPEFILE: - try { - response = await handleShapefiles(file, schemaData, setUploadedFileError, selectedFileType, setToast, t); - file = new File([file], file.name, { type: "application/octet-stream" }); - check = response.check; - errorMsg = response.error; - fileDataToStore = response.fileDataToStore; - callMapping = true; - } catch (error) { - console.error("Shapefile parsing error", error.message); - setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); - handleValidationErrorResponse(t("ERROR_UPLOADED_FILE")); - return; - } - break; - default: - setToast({ - state: "error", - message: t("ERROR_UNKNOWN_FILETYPE"), - }); - setLoader(false); - return; - } - let filestoreId; - if (!errorMsg && !callMapping) { - try { - const filestoreResponse = await Digit.UploadServices.Filestorage(FILE_STORE, file, Digit.ULBService.getCurrentTenantId()); - if (filestoreResponse?.data?.files?.length > 0) { - filestoreId = filestoreResponse?.data?.files[0]?.fileStoreId; - } else { - errorMsg = t("ERROR_UPLOADING_FILE"); - setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); - setFileData((previous) => ({ ...previous, error: errorMsg })); - setUploadedFileError(errorMsg); - } - } catch (errorData) { - console.error(errorData.message); - errorMsg = t("ERROR_UPLOADING_FILE"); - setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); - setUploadedFileError(errorMsg); - handleValidationErrorResponse(t("ERROR_UPLOADING_FILE")); - return; - } - } - - if (selectedFileType.id === EXCEL) { - resourceMappingData = resourceMappingData.map((item) => ({ ...item, filestoreId })); - } - const uuid = uuidv4(); - // creating a fileObject to save all the data collectively - let fileObject = { - id: uuid, - templateIdentifier: `${selectedSection.id}`, - fileName: file.name, - section: selectedSection.id, - fileType: selectedFileType.id, - data: fileDataToStore, - file, - error: errorMsg ? errorMsg : null, - filestoreId, - resourceMapping: resourceMappingData, - active: true, - additionalSheets, - errorLocationObject, // contains location and type of error - }; - setFileDataList((prevFileDataList) => { - let temp = _.cloneDeep(prevFileDataList); - if (!temp) return temp; - let index = prevFileDataList?.findIndex((item) => item.active && item.templateIdentifier === selectedSection.id); - if (index !== -1) - temp[index] = { ...temp[index], resourceMapping: temp[index]?.resourceMapping.map((e) => ({ active: false, ...e })), active: false }; - temp.push(fileObject); - return temp; - }); - setFileData(fileObject); - if (errorMsg === undefined && callMapping) { - setModal("spatial-data-property-mapping"); - } - setDataPresent(true); - setLoader(false); - } catch (error) { - console.error(error.message); - console.error("File Upload error", error?.message); - setUploadedFileError("ERROR_UPLOADING_FILE"); - setLoader(false); - } - }; - - // Reupload the selected file - const reuplaodFile = () => { - setResourceMapping([]); - setFileData(undefined); - setDataPresent(false); - setUploadedFileError(null); - setDataUpload(false); - setSelectedFileType(null); - closeModal(); - }; - - const convertAndCombineFileData = () => { - let combinedData = fileData?.data ? Object.entries(fileData.data)?.map(([key, value]) => ({ sheetName: key, data: value })) : []; - if (fileData?.additionalSheets) { - for (const sheet of fileData.additionalSheets) { - if (sheet?.data && sheet.sheetName) { - const index = sheet?.position < combinedData.length && sheet.position !== -1 ? sheet.position : combinedData.length; - combinedData.splice(index, 0, sheet); - } - } - } - return combinedData; - }; - - // Function for creating blob out of data - const dataToBlob = async () => { - try { - let blob; - const schema = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); - const filteredReadMeData = findReadMe(state?.ReadMeData, campaignType, selectedFileType.id, selectedSection.id); - let combinedData = convertAndCombineFileData(); - const readMeSheetName = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName")?.value; - switch (fileData.fileType) { - case EXCEL: - if (fileData?.errorLocationObject?.length !== 0) - blob = await prepareExcelFileBlobWithErrors( - combinedData, - fileData.errorLocationObject, - schema, - hierarchy, - filteredReadMeData, - readMeSheetName, - t - ); - else blob = fileData.file; - break; - case SHAPEFILE: - case GEOJSON: - if (fileData?.data) { - const result = convertToSheetArray(Digit.Utils.microplan.convertGeojsonToExcelSingleSheet(fileData?.data?.features, fileData?.section)); - - if (fileData?.errorLocationObject?.length !== 0) - blob = await prepareExcelFileBlobWithErrors( - result, - fileData.errorLocationObject, - schema, - hierarchy, - filteredReadMeData, - readMeSheetName, - t - ); - } - break; - } - return blob; - } catch (error) { - console.error("Error generating blob:", error); - return; - } - }; - - // Download the selected file - const downloadFile = async () => { - setLoader("LOADING"); - try { - await delay(100); - let blob = await dataToBlob(); - if (blob) { - // Crating a url object for the blob - const url = URL.createObjectURL(blob); - const link = document.createElement("a"); - link.href = url; - - // Forming a name for downloaded file - let fileNameParts = fileData.fileName.split("."); - fileNameParts.pop(); - fileNameParts.push("xlsx"); - fileNameParts.join("."); - - //Downloading the file - link.download = fileNameParts.join("."); - link.click(); - URL.revokeObjectURL(url); - } else { - let downloadUrl = await Digit.UploadServices.Filefetch([fileData.filestoreId], Digit.ULBService.getCurrentTenantId()); - const link = document.createElement("a"); - link.href = downloadUrl; - // Forming a name for downloaded file - let fileNameParts = fileData.fileName.split("."); - fileNameParts.pop(); - fileNameParts.push("xlsx"); - fileNameParts.join("."); - link.download = fileNameParts; // Replace with the desired file name and extension - document.body.appendChild(link); - link.click(); - document.body.removeChild(link); - } - } catch (error) { - console.error(error.message); - setToast({ - state: "error", - message: t("ERROR_UNKNOWN_ERROR"), - }); - } - setLoader(false); - }; - - // delete the selected file - const deleteFile = () => { - setResourceMapping([]); - setFileDataList((previous) => { - let temp = _.cloneDeep(previous); - if (!temp) return temp; - let index = temp?.findIndex((item) => { - return item.id === fileData.id; - }); - if (index !== -1) - temp[index] = { ...temp[index], resourceMapping: temp[index]?.resourceMapping.map((e) => ({ active: false, ...e })), active: false }; - return temp; - }); - setFileData(undefined); - setDataPresent(false); - setUploadedFileError(null); - setDataUpload(false); - setSelectedFileType(null); - closeModal(); - }; - - // Function for handling the validations for geojson and shapefiles after mapping of properties - const validationForMappingAndDataSaving = async () => { - try { - setLoader("LOADING"); - const schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); - let error; - if (!checkForSchemaData(schemaData)) return; - const { data, valid, errors } = computeMappedDataAndItsValidations(schemaData); - error = errors; - if (!valid) return; - let filestoreId; - if (!error) { - filestoreId = await saveFileToFileStore(); - } - let resourceMappingData; - if (filestoreId) { - resourceMappingData = resourceMapping.map((item) => { - return { ...item, filestoreId }; - }); - } - setResourceMapping([]); - - let boundaryDataAgainstBoundaryCode = (await boundaryDataGeneration(schemaData, campaignData, t)) || {}; - const mappedToList = resourceMappingData.map((item) => item.mappedTo); - if (hierarchy.every((item) => !mappedToList.includes(t(item)))) { - data.features.forEach((feature) => { - const boundaryCode = feature.properties.boundaryCode; - let additionalDetails = {}; - for (let i = 0; i < hierarchy.length; i++) { - if (boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] || boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] === "") { - additionalDetails[hierarchy[i]] = boundaryDataAgainstBoundaryCode[boundaryCode][i]; - } else { - additionalDetails[hierarchy[i]] = ""; - } - } - feature.properties = { ...additionalDetails, ...feature.properties }; - }); - } - - let fileObject = _.cloneDeep(fileData); - fileObject = { ...fileData, data, resourceMapping: resourceMappingData, error: error ? error : null, filestoreId }; - setFileData(fileObject); - setFileDataList((prevFileDataList) => { - let temp = _.cloneDeep(prevFileDataList); - if (!temp) return temp; - let index = prevFileDataList?.findIndex((item) => item.id === fileData.id); - if (index !== -1) temp[index] = fileObject; - // temp.push(fileObject); - return temp; - }); - - setToast({ state: "success", message: t("FILE_UPLOADED_SUCCESSFULLY") }); - setLoader(false); - } catch (error) { - console.error(error.message); - setUploadedFileError(t("ERROR_UPLOADING_FILE")); - setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); - setLoader(false); - handleValidationErrorResponse("ERROR_UPLOADING_FILE"); - } - }; - const saveFileToFileStore = async () => { - try { - const filestoreResponse = await Digit.UploadServices.Filestorage(FILE_STORE, fileData.file, Digit.ULBService.getCurrentTenantId()); - if (filestoreResponse?.data?.files?.length > 0) { - return filestoreResponse?.data?.files[0]?.fileStoreId; - } - error = t("ERROR_UPLOADING_FILE"); - setToast({ state: "error", message: t("ERROR_UPLOADING_FILE") }); - setResourceMapping([]); - setUploadedFileError(error); - } catch (errorData) { - console.error("Error while uploading file to filestore: ", errorData?.message); - let error = t("ERROR_UPLOADING_FILE"); - handleValidationErrorResponse(error); - setResourceMapping([]); - return; - } - }; - const computeMappedDataAndItsValidations = (schemaData) => { - const data = computeGeojsonWithMappedProperties(); - const response = geojsonPropertiesValidation(data, schemaData.schema, fileData?.section, t); - if (!response.valid) { - handleValidationErrorResponse(response.message, response.errors); - return { data: data, errors: response.errors, valid: response.valid }; - } - return { data: data, valid: response.valid }; - }; - - const handleValidationErrorResponse = (error, errorLocationObject = {}) => { - const fileObject = fileData; - if (fileObject) { - fileObject.error = [error]; - if (errorLocationObject) fileObject.errorLocationObject = errorLocationObject; - setFileData((previous) => ({ ...previous, error, errorLocationObject })); - setFileDataList((prevFileDataList) => { - let temp = _.cloneDeep(prevFileDataList); - if (!temp) return temp; - let index = prevFileDataList?.findIndex((item) => item.id === fileData.id); - temp[index] = fileObject; - return temp; - }); - setToast({ state: "error", message: t("ERROR_UPLOADED_FILE") }); - if (error) setUploadedFileError(error); - } - setLoader(false); - }; - - const checkForSchemaData = (schemaData) => { - if (resourceMapping?.length === 0) { - setToast({ state: "warning", message: t("WARNING_INCOMPLETE_MAPPING") }); - setLoader(false); - return false; - } - - if (!schemaData || !schemaData.schema || !schemaData.schema["Properties"]) { - setToast({ state: "error", message: t("ERROR_VALIDATION_SCHEMA_ABSENT") }); - setLoader(false); - return; - } - - let columns = []; - if (schemaData?.doHierarchyCheckInUploadedData) { - columns.push(...hierarchy); - } - columns.push( - ...Object.entries(schemaData?.schema?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.isRequired) { - acc.push(key); - } - return acc; - }, []) - ); - - const resourceMappingLength = resourceMapping.filter((e) => !!e?.mappedFrom && columns.includes(e?.mappedTo)).length; - if (resourceMappingLength !== columns?.length) { - setToast({ state: "warning", message: t("WARNING_INCOMPLETE_MAPPING") }); - setLoader(false); - return false; - } - setModal("none"); - return true; - }; - - const computeGeojsonWithMappedProperties = () => { - const schemaData = getSchema(campaignType, selectedFileType.id, selectedSection.id, validationSchemas); - let schemaKeys; - if (schemaData?.schema?.["Properties"]) schemaKeys = hierarchy.concat(Object.keys(schemaData.schema["Properties"])); - // Sorting the resourceMapping list inorder to maintain the column sequence - const sortedSecondList = Digit.Utils.microplan.sortSecondListBasedOnFirstListOrder(schemaKeys, resourceMapping); - // Creating a object with input data with MDMS keys - const newFeatures = fileData.data["features"].map((item) => { - let newProperties = {}; - - sortedSecondList.forEach((e) => { - newProperties[e["mappedTo"]] = item["properties"][e["mappedFrom"]]; - }); - item["properties"] = newProperties; - return item; - }); - let data = fileData.data; - data["features"] = newFeatures; - return data; - }; - - // Handler for checing file extension and showing errors in case it is wrong - const onTypeErrorWhileFileUpload = () => { - switch (selectedFileType.id) { - case EXCEL: - setToast({ state: "error", message: t("ERROR_EXCEL_EXTENSION") }); - break; - case GEOJSON: - setToast({ state: "error", message: t("ERROR_GEOJSON_EXTENSION") }); - break; - case SHAPEFILE: - setToast({ state: "error", message: t("ERROR_SHAPE_FILE_EXTENSION") }); - break; - } - }; - - // Cancle mapping and uplaod in case of geojson and shapefiles - const cancelUpload = () => { - setFileDataList((previous) => { - let temp = previous?.filter((item) => item.id !== fileData?.id); - return temp; - }); - setFileData(undefined); - setDataPresent(false); - setUploadedFileError(null); - setDataUpload(false); - setSelectedFileType(null); - closeModal(); - }; - - const openDataPreview = () => { - let data; - switch (fileData.fileType) { - case EXCEL: - data = fileData.data; - break; - case SHAPEFILE: - case GEOJSON: - if (!fileData || !fileData.data) { - setToast({ - state: "error", - message: t("ERROR_DATA_NOT_PRESENT"), - }); - return; - } - data = Digit.Utils.microplan.convertGeojsonToExcelSingleSheet(fileData?.data?.features, fileData?.section); - break; - } - if (!data || Object.keys(data).length === 0) { - setToast({ - state: "error", - message: t("ERROR_DATA_NOT_PRESENT"), - }); - return; - } - setPreviewUploadedData(data); - }; - - if (isCampaignLoading || ishierarchyLoading) { - return ( -
- -
- ); - } - - return ( - <> -
-
-
- {!dataPresent ? ( - dataUpload ? ( -
- e.id === selectedSection.id)[0]} - selectedSection={selectedSection} - selectedFileType={selectedFileType} - UploadFileToFileStorage={UploadFileToFileStorage} - onTypeError={onTypeErrorWhileFileUpload} - downloadTemplateHandler={downloadTemplateHandler} - showDownloadTemplate={showDownloadTemplate} - /> -
- ) : ( -
{sectionComponents}
- ) - ) : ( -
- {selectedSection != null && fileData !== null && ( - { - setModal("reupload-conformation"); - }} - DownloadFile={downloadFile} - DeleteFile={() => { - setModal("delete-conformation"); - }} - error={uploadedFileError} - openDataPreview={openDataPreview} - downloadTemplateHandler={downloadTemplateHandler} - showDownloadTemplate={showDownloadTemplate} - /> - )} -
- )} - {!dataPresent && dataUpload && ( - { - setModal("upload-guidelines"); - }} - t={t} - /> - )} -
- -
{sectionOptions}
-
- -
- {modal === "upload-modal" && ( - { - closeModal(); - setSelectedFileType(null); - }} - LeftButtonHandler={() => UploadFileClickHandler(false)} - RightButtonHandler={() => UploadFileClickHandler(true)} - sections={sections} - popupModuleActionBarStyles={{ - flex: 1, - justifyContent: "space-between", - padding: "1rem", - gap: "1rem", - }} - footerLeftButtonBody={} - footerRightButtonBody={} - header={ - - } - bodyText={t(`INSTRUCTIONS_DOWNLOAD_TEMPLATE_FOR_${selectedSection.code}_${selectedFileType.code}`)} - /> - )} - {modal === "delete-conformation" && ( - } - actionCancelLabel={t("YES")} - actionCancelOnSubmit={deleteFile} - actionSaveLabel={t("NO")} - actionSaveOnSubmit={closeModal} - > -
-

{t("INSTRUCTIONS_DELETE_FILE_CONFIRMATION")}

-
-
- )} - {modal === "reupload-conformation" && ( - } - actionCancelLabel={t("YES")} - actionCancelOnSubmit={reuplaodFile} - actionSaveLabel={t("NO")} - actionSaveOnSubmit={closeModal} - > -
-

{t("INSTRUCTIONS_REUPLOAD_FILE_CONFIRMATION")}

-
-
- )} - {modal === "spatial-data-property-mapping" && ( - } - actionSaveOnSubmit={validationForMappingAndDataSaving} - actionSaveLabel={t("COMPLETE_MAPPING")} - headerBarEnd={} - > -
-

{t("INSTRUCTION_SPATIAL_DATA_PROPERTY_MAPPING")}

-
- -
- )} - {modal === "upload-guidelines" && ( - - } - headerBarEnd={} - > - - - )} - {loader && } - - {previewUploadedData && ( -
- setPreviewUploadedData(undefined)} - onDownload={downloadFile} - /> -
- )} -
-
- - ); -}; - -export default Upload; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/UploadHelperComponents.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/UploadHelperComponents.js deleted file mode 100644 index 5a520c4a1bd..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/UploadHelperComponents.js +++ /dev/null @@ -1,299 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import * as Icons from "@egovernments/digit-ui-svg-components"; -import { FileUploader } from "react-drag-drop-files"; -import { InfoButton, InfoCard } from "@egovernments/digit-ui-components"; -import { PRIMARY_THEME_COLOR } from "../configs/constants"; - -// Component for rendering individual section option -export const UploadSection = ({ item, selected, setSelectedSection, uploadDone }) => { - const { t } = useTranslation(); - // Handle click on section option - const handleClick = () => { - setSelectedSection(item); - }; - - return ( -
-
- -
-

{t(item.code)}

- {uploadDone && ( -
- -
- )} -
- ); -}; - -export const UploadInstructions = ({ setModal, t }) => { - return ( - - {t("REFER")} -
- {t("INFORMATION_DESCRIPTION_LINK")} -
-
, - ]} - /> - ); -}; - -// Component for rendering individual upload option -export const UploadComponents = ({ item, selected, uploadOptions, selectedFileType, selectFileTypeHandler }) => { - const { t } = useTranslation(); - const title = item.code; - - // Component for rendering individual upload option container - const UploadOptionContainer = ({ item, selectedFileType, selectFileTypeHandler }) => { - const [isHovered, setIsHovered] = useState(false); - - const handleMouseEnter = () => { - setIsHovered(true); - }; - - const handleMouseLeave = () => { - setIsHovered(false); - }; - - return ( -
- -

{t(item.code)}

- -
- ); - }; - - return ( -
-
-
-

{t(`HEADING_UPLOAD_DATA_${title}`)}

-
- -

{t(`INSTRUCTIONS_DATA_UPLOAD_OPTIONS_${title}`)}

-
-
- {uploadOptions?.map((item) => ( - - ))} -
-
- ); -}; - -// Component for uploading file -export const FileUploadComponent = ({ - selectedSection, - selectedFileType, - UploadFileToFileStorage, - section, - onTypeError, - downloadTemplateHandler, - showDownloadTemplate, -}) => { - if (!selectedSection || !selectedFileType) return
; - const { t } = useTranslation(); - let types; - section["UploadFileTypes"].forEach((item) => { - if (item.id === selectedFileType.id) types = item.fileExtension; - }); - return ( -
-
-
-

{t(`HEADING_FILE_UPLOAD_${selectedSection.code}_${selectedFileType.code}`)}

- {showDownloadTemplate() && ( - - )} -
-

{t(`INSTRUCTIONS_FILE_UPLOAD_FROM_TEMPLATE_${selectedSection.code}`)}

- -
- -
- {t(`INSTRUCTIONS_UPLOAD_${selectedFileType.code}`)} 
{t("INSTRUCTIONS_UPLOAD_BROWSE_FILES")}
-
-
-
-
-
- ); -}; - -// Component to display uploaded file -export const UploadedFile = ({ - selectedSection, - selectedFileType, - file, - ReuplaodFile, - DownloadFile, - DeleteFile, - error, - openDataPreview, - downloadTemplateHandler, - showDownloadTemplate, -}) => { - const { t } = useTranslation(); - const [errorList, setErrorList] = useState([]); - useEffect(() => { - let tempErrorList = []; - if (file?.errorLocationObject) { - for (const [sheetName, values] of Object.entries(file?.errorLocationObject)) { - for (const [row, columns] of Object.entries(values)) { - for (const [column, errors] of Object.entries(columns)) { - for (const error of errors) { - let convertedError; - if (typeof error === "object") { - let { error: actualError, ...otherProperties } = error; - convertedError = t(actualError, otherProperties?.values); - } else { - convertedError = t(error); - } - tempErrorList.push( - t("ERROR_UPLOAD_DATA_LOCATION_AND_MESSAGE", { - rowNumber: Number(row) + 1, - columnName: t(column), - error: convertedError, - sheetName: sheetName, - }) - ); - } - } - } - } - } - if (tempErrorList.length !== 0) { - setErrorList(tempErrorList); - } - }, [file]); - return ( -
-
-
-

{t(`HEADING_FILE_UPLOAD_${selectedSection.code}_${selectedFileType.code}`)}

- {showDownloadTemplate() && ( - - )} -
-

{t(`INSTRUCTIONS_FILE_UPLOAD_FROM_TEMPLATE_${selectedSection.code}`)}

- -
-
-
- -
-

{file.fileName}

-
-
- - - -
-
-
- {error && Array.isArray(error) && ( - , -
- {error?.map((item) => { - if (item !== "ERROR_REFER_UPLOAD_PREVIEW_TO_SEE_THE_ERRORS") { - return

{t(item)}

; - } - return null; - })} - {errorList.length !== 0 && errorList.map((item) =>

{item}

)} -
, - ]} - /> - )} -
- ); -}; - -// Uplaod GuideLines -export const UploadGuideLines = ({ uploadGuideLines, t }) => { - const formMsgFromObject = (item) => { - if (!item?.hasLink) { - return t(item?.name); - } - return ( - <> - {t(item?.name)} {t(item?.linkName)}{" "} - - ); - }; - return ( -
- {uploadGuideLines?.map((item, index) => ( -
-

- {t(index + 1)}. -

-
- {formMsgFromObject(item)} -
-
- ))} -
- ); -}; - -export const CustomIcon = (props) => { - if (!props.Icon) return null; - return ; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js deleted file mode 100644 index 5a0cdabf735..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/ZoomControl.js +++ /dev/null @@ -1,29 +0,0 @@ -import React, { memo, useCallback } from "react"; -import { useTranslation } from "react-i18next"; - -const ZoomControl = memo(({ map, t }) => { - if (!map) return
{t("LOADING_MAP")}
; - - const zoomIn = useCallback(() => { - map.zoomIn(); - }, [map]); - - const zoomOut = useCallback(() => { - map.zoomOut(); - }, [map]); - - return ( -
-
- - -
-
- ); -}); - -export default ZoomControl; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js deleted file mode 100644 index df1eb78c135..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/components/resourceMapping.js +++ /dev/null @@ -1,187 +0,0 @@ -import { Dropdown } from "@egovernments/digit-ui-components"; -import { Table } from "@egovernments/digit-ui-react-components"; -import { PaginationFirst, PaginationLast, PaginationNext, PaginationPrevious } from "@egovernments/digit-ui-svg-components"; -import React, { useState, useEffect, useMemo, useRef, useCallback } from "react"; -const SCROLL_OFFSET = 100; - -export const SpatialDataPropertyMapping = ({ uploadedData, resourceMapping, setResourceMapping, schema, setToast, hierarchy, close, t }) => { - // If no data is uploaded, display a message - if (!uploadedData) return
{t("NO_DATA_TO_DO_MAPPING")}
; - - const itemRefs = useRef([]); - const [expandedIndex, setExpandedIndex] = useState(null); - // State to track the render cycle count - const [renderCycle, setRenderCycle] = useState(0); - const scrollContainerRef = useRef(null); - - // Effect to reset the render cycle count whenever the expandedIndex changes - useEffect(() => { - if (expandedIndex !== null) { - setRenderCycle(0); - } - }, [expandedIndex]); - - // Effect to handle scrolling to the expanded item after the DOM has updated - useEffect(() => { - if (renderCycle < 3) { - // Increment render cycle count to ensure multiple render checks - setRenderCycle((prev) => prev + 1); - } else if (expandedIndex !== null && itemRefs.current[expandedIndex]) { - try { - const parentElement = itemRefs.current[expandedIndex]; - const childElement = itemRefs.current[expandedIndex].children[1]; - - if (parentElement) { - const scrollContainer = scrollContainerRef.current; - const parentRect = parentElement.getBoundingClientRect(); - const containerRect = scrollContainer.getBoundingClientRect(); - - // Calculate the offset from the top of the container - const offset = parentRect.top - containerRect.top; - // Scroll the container to the target position - scrollContainer.scrollTo({ - top: scrollContainer.scrollTop + offset - SCROLL_OFFSET, - behavior: "smooth", - }); - } - - if (childElement) { - // Focus the child element if it exists - childElement.focus(); - } - } catch (error) { - console.error("Error scrolling to element:", error); - } - } - }, [renderCycle, expandedIndex]); - - // Effect to observe DOM changes in the expanded item and trigger render cycle - useEffect(() => { - if (expandedIndex !== null) { - const observer = new MutationObserver(() => { - setRenderCycle((prev) => prev + 1); - }); - - if (itemRefs.current[expandedIndex]) { - observer.observe(itemRefs.current[expandedIndex], { childList: true, subtree: true }); - } - - return () => observer.disconnect(); - } - }, [expandedIndex]); - - // State variables - const [userColumns, setUserColumns] = useState([]); - const [templateColumns, setTemplateColumns] = useState([]); - - // Fetch template columns when schema changes - useEffect(() => { - if (!schema || !schema["schema"] || !schema.schema["Properties"]) - return setToast({ state: "error", message: t("ERROR_VALIDATION_SCHEMA_ABSENT") }); - - const columns = Object.keys(schema.schema["Properties"]); - if (columns) { - const newTemplateColumns = schema && !schema.doHierarchyCheckInUploadedData ? columns : [...hierarchy, ...columns]; - setTemplateColumns(newTemplateColumns); - } - }, [schema]); - - // Update user columns when uploaded data changes - useEffect(() => { - const userUploadedColumns = new Set(); - uploadedData?.["features"]?.forEach((item) => { - Object.keys(item["properties"]).forEach((key) => userUploadedColumns.add(key)); - }); - - //field level validations - for (const item of userUploadedColumns) { - if (item.length < 2) { - setToast({ state: "error", message: t("ERROR_FIELD_LENGTH") }); - close(); - } - } - setUserColumns((preUserColumns) => [...preUserColumns, ...userUploadedColumns]); - }, [uploadedData]); - - // Dropdown component for selecting user columns - const DropDownUserColumnSelect = ({ id, index }) => { - const [selectedOption, setSelectedOption] = useState(""); - useEffect(() => { - const obj = resourceMapping.find((item) => item["mappedTo"] === id); - if (obj) setSelectedOption({ code: obj["mappedFrom"] }); - else setSelectedOption(); - }, [id, resourceMapping]); - - const handleSelectChange = (event) => { - const newValue = event.code; - setSelectedOption(event); - setResourceMapping((previous) => { - const revisedData = previous.filter((item) => !(item["mappedTo"] === id || item["mappedFrom"] === newValue)); - return [...revisedData, { mappedTo: id, mappedFrom: newValue }]; - }); - }; - - const toggleExpand = (index) => { - setExpandedIndex(index === expandedIndex ? null : index); - }; - - return ( -
{ - itemRefs.current[index] = el; - }} - onClick={() => toggleExpand(index)} - onKeyDown={() => toggleExpand(index)} - > - ({ code: item }))} - selected={selectedOption} - optionKey="code" - select={handleSelectChange} - style={{ width: "100%", backgroundColor: "rgb(0,0,0,0)" }} - showToolTip={true} - /> -
- ); - }; - - const tableColumns = useMemo( - () => [ - { - Header: t("COLUMNS_IN_TEMPLATE"), - accessor: "COLUMNS_IN_TEMPLATE", - }, - { - Header: t("COLUMNS_IN_USER_UPLOAD"), - accessor: "COLUMNS_IN_USER_UPLOAD", - Cell: ({ cell: { value }, row: { index } }) => - useMemo(() => , [value, index]), - }, - ], - [userColumns, setResourceMapping, resourceMapping, t, itemRefs] - ); - const data = useMemo(() => templateColumns.map((item) => ({ COLUMNS_IN_TEMPLATE: t(item), COLUMNS_IN_USER_UPLOAD: item })), [templateColumns]); - return ( -
- { - return { style: {} }; - }} - getHeaderProps={(cellInfo) => { - return { style: {} }; - }} - /> - - ); -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/UICustomizations.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/UICustomizations.js deleted file mode 100644 index 8f7fd717aba..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/UICustomizations.js +++ /dev/null @@ -1,324 +0,0 @@ -import _ from "lodash"; - -//create functions here based on module name set in mdms(eg->SearchProjectConfig) -//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName] -// these functions will act as middlewares -// var Digit = window.Digit || {}; - -const businessServiceMap = { - "muster roll": "MR", -}; - -const inboxModuleNameMap = { - "muster-roll-approval": "muster-roll-service", -}; - -function filterUniqueByKey(arr, key) { - const uniqueValues = new Set(); - const result = []; - - arr.forEach((obj) => { - const value = obj[key]; - if (!uniqueValues.has(value)) { - uniqueValues.add(value); - result.push(obj); - } - }); - - return result; -} - -const epochTimeForTomorrow12 = () => { - const now = new Date(); - - // Create a new Date object for tomorrow at 12:00 PM - const tomorrowNoon = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 12, 0, 0, 0); - - // Format the date as "YYYY-MM-DD" - const year = tomorrowNoon.getFullYear(); - const month = String(tomorrowNoon.getMonth() + 1).padStart(2, "0"); // Months are 0-indexed - const day = String(tomorrowNoon.getDate()).padStart(2, "0"); - - return Digit.Utils.date.convertDateToEpoch(`${year}-${month}-${day}`); -}; - -function cleanObject(obj) { - for (const key in obj) { - if (Object.hasOwn(obj, key)) { - if (Array.isArray(obj[key])) { - if (obj[key].length === 0) { - delete obj[key]; - } - } else if ( - obj[key] === undefined || - obj[key] === null || - obj[key] === false || - obj[key] === "" || // Check for empty string - (typeof obj[key] === "object" && Object.keys(obj[key]).length === 0) - ) { - delete obj[key]; - } - } - } - return obj; -} - -export const UICustomizations = { - businessServiceMap, - updatePayload: (applicationDetails, data, action, businessService) => { - if (businessService === businessServiceMap.estimate) { - const workflow = { - comment: data.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - estimate: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap.contract) { - const workflow = { - comment: data?.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - contract: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap?.["muster roll"]) { - const workflow = { - comment: data?.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - musterRoll: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap?.["works.purchase"]) { - const workflow = { - comment: data.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - const additionalFieldsToSet = { - projectId: applicationDetails.additionalDetails.projectId, - invoiceDate: applicationDetails.billDate, - invoiceNumber: applicationDetails.referenceId.split("_")?.[1], - contractNumber: applicationDetails.referenceId.split("_")?.[0], - documents: applicationDetails.additionalDetails.documents, - }; - return { - bill: { ...applicationDetails, ...additionalFieldsToSet }, - workflow, - }; - } - }, - enableModalSubmit: (businessService, action, setModalSubmit, data) => { - if (businessService === businessServiceMap?.["muster roll"] && action.action === "APPROVE") { - setModalSubmit(data?.acceptTerms); - } - }, - enableHrmsSearch: (businessService, action) => { - if (businessService === businessServiceMap.estimate) { - return action.action.includes("TECHNICALSANCTION") || action.action.includes("VERIFYANDFORWARD"); - } - if (businessService === businessServiceMap.contract) { - return action.action.includes("VERIFY_AND_FORWARD"); - } - if (businessService === businessServiceMap?.["muster roll"]) { - return action.action.includes("VERIFY"); - } - if (businessService === businessServiceMap?.["works.purchase"]) { - return action.action.includes("VERIFY_AND_FORWARD"); - } - return false; - }, - getBusinessService: (moduleCode) => { - if (moduleCode?.includes("estimate")) { - return businessServiceMap?.estimate; - } else if (moduleCode?.includes("contract")) { - return businessServiceMap?.contract; - } else if (moduleCode?.includes("muster roll")) { - return businessServiceMap?.["muster roll"]; - } else if (moduleCode?.includes("works.purchase")) { - return businessServiceMap?.["works.purchase"]; - } else if (moduleCode?.includes("works.wages")) { - return businessServiceMap?.["works.wages"]; - } else if (moduleCode?.includes("works.supervision")) { - return businessServiceMap?.["works.supervision"]; - } else { - return businessServiceMap; - } - }, - getInboxModuleName: (moduleCode) => { - if (moduleCode?.includes("estimate")) { - return inboxModuleNameMap?.estimate; - } else if (moduleCode?.includes("contract")) { - return inboxModuleNameMap?.contracts; - } else if (moduleCode?.includes("attendence")) { - return inboxModuleNameMap?.attendencemgmt; - } else { - return inboxModuleNameMap; - } - }, - SearchCampaign: { - preProcess: (data, additionalDetails) => { - const { campaignName = "", endDate = "", projectType = "", startDate = "" } = data?.state?.searchForm || {}; - data.body.CampaignDetails = {}; - data.body.CampaignDetails.pagination = data?.state?.tableForm; - data.body.CampaignDetails.tenantId = Digit.ULBService.getCurrentTenantId(); - // data.body.CampaignDetails.boundaryCode = boundaryCode; - data.body.CampaignDetails.createdBy = Digit.UserService.getUser().info.uuid; - data.body.CampaignDetails.campaignName = campaignName; - data.body.CampaignDetails.status = ["drafted"]; - if (startDate) { - data.body.CampaignDetails.startDate = Digit.Utils.date.convertDateToEpoch(startDate); - } else { - data.body.CampaignDetails.startDate = epochTimeForTomorrow12(); - } - if (endDate) { - data.body.CampaignDetails.endDate = Digit.Utils.date.convertDateToEpoch(endDate); - } - data.body.CampaignDetails.projectType = projectType?.[0]?.code; - - cleanObject(data.body.CampaignDetails); - - return data; - }, - populateProjectType: () => { - const tenantId = Digit.ULBService.getCurrentTenantId(); - - return { - url: "/egov-mdms-service/v1/_search", - params: { tenantId }, - body: { - MdmsCriteria: { - tenantId, - moduleDetails: [ - { - moduleName: "HCM-PROJECT-TYPES", - masterDetails: [ - { - name: "projectTypes", - }, - ], - }, - ], - }, - }, - changeQueryName: "projectType", - config: { - enabled: true, - select: (data) => { - const dropdownData = filterUniqueByKey(data?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes, "code").map((row) => { - return { - ...row, - i18nKey: Digit.Utils.locale.getTransformedLocale(`CAMPAIGN_TYPE_${row.code}`), - }; - }); - return dropdownData; - }, - }, - }; - }, - customValidationCheck: (data) => { - //checking if both to and from date are present then they should be startDate<=endDate - const { startDate, endDate } = data; - const startDateEpoch = Digit.Utils.date.convertDateToEpoch(startDate); - const endDateEpoch = Digit.Utils.date.convertDateToEpoch(endDate); - - if (startDate && endDate && startDateEpoch > endDateEpoch) { - return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; - } - return false; - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - if (key === "CAMPAIGN_DATE") { - return `${Digit.DateUtils.ConvertEpochToDate(value)} - ${Digit.DateUtils.ConvertEpochToDate(row?.endDate)}`; - } - }, - }, - SearchMicroplan: { - preProcess: (data, additionalDetails) => { - const { name, status } = data?.state?.searchForm || {}; - - data.body.PlanConfigurationSearchCriteria = {}; - data.body.PlanConfigurationSearchCriteria.limit = data?.state?.tableForm?.limit; - // data.body.PlanConfigurationSearchCriteria.limit = 10 - data.body.PlanConfigurationSearchCriteria.offset = data?.state?.tableForm?.offset; - data.body.PlanConfigurationSearchCriteria.name = name; - data.body.PlanConfigurationSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); - data.body.PlanConfigurationSearchCriteria.userUuid = Digit.UserService.getUser().info.uuid; - // delete data.body.PlanConfigurationSearchCriteria.pagination - data.body.PlanConfigurationSearchCriteria.status = status?.status; - cleanObject(data.body.PlanConfigurationSearchCriteria); - return data; - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - if (key === "CAMPAIGN_DATE") { - return `${Digit.DateUtils.ConvertEpochToDate(value)} - ${Digit.DateUtils.ConvertEpochToDate(row?.CampaignDetails?.endDate)}`; - } - }, - }, -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js deleted file mode 100644 index c9f5af95d46..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/constants.js +++ /dev/null @@ -1,36 +0,0 @@ -export const LOCALITY = "Locality"; - -export const EXCEL = "Excel"; - -export const GEOJSON = "GeoJSON"; - -export const SHAPEFILE = "Shapefile"; - -export const commonColumn = "boundaryCode"; - -export const ACCEPT_HEADERS = { - GeoJSON: "application/geo+json", - Shapefile: "application/shapefile", - Excel: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", -}; - -// Define the colors of the gradient for choropleth mapping -export const MapChoroplethGradientColors = [ - { percent: 0, color: "#edd1cf" }, - { percent: 100, color: "#b52626" }, -]; - -export const PRIMARY_THEME_COLOR = "#C84C0E"; - -export const BOUNDARY_DATA_SHEET = "MICROPLAN_BOUNDARY_DATA_SHEET"; -export const FACILITY_DATA_SHEET = "MICROPLAN_FACILITY_DATA_SHEET"; - -export const FILE_STORE = "microplan"; - -export const SHEET_PASSWORD = "eGov_sheet_password"; - -export const SHEET_COLUMN_WIDTH = 40; - -export const SCHEMA_PROPERTIES_PREFIX = "DISPLAY"; - -export const UNPROTECT_TILL_ROW = "10000"; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json deleted file mode 100644 index 768e323ef86..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/timeLineOptions.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "timeLineOptions": [ - { - "id": 0, - "name": "MICROPLAN_DETAILS", - "component": "MicroplanDetails", - "checkForCompleteness": true - }, - { - "id": 1, - "name": "UPLOAD_DATA", - "component": "Upload", - "checkForCompleteness": true - }, - { - "id": 2, - "name": "HYPOTHESIS", - "component": "Hypothesis", - "checkForCompleteness": true - }, - { - "id": 3, - "name": "FORMULA_CONFIGURATION", - "component": "RuleEngine", - "checkForCompleteness": true - }, - { - "id": 4, - "name": "MAPPING", - "component": "Mapping", - "checkForCompleteness": false - }, - { - "id": 5, - "name": "MICROPLAN_GENERATION", - "component": "MicroplanPreview", - "checkForCompleteness": false - } - ] -} diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js deleted file mode 100644 index 241f8ec64ec..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/configs/tourSteps.js +++ /dev/null @@ -1,193 +0,0 @@ -export const tourSteps = (t) => { - return { - microplanDetails: { - name: "microplanDetails", - run: true, - steps: [ - { - content: t("HELP_MICROPLAN_DETAILS_CAMPAIGN_DETAILS"), - target: ".microplan-campaign-detials", - disableBeacon: true, - placement: "bottom", - title: "", - disableScrolling: true, - disableOverlay :true, - }, - { - content: t("HELP_MICROPLAN_DETAILS_MICROPLAN_NAME"), - target: ".microplan-name", - disableBeacon: true, - placement: "bottom", - title: "", - disableScrolling: true, - disableOverlay :true, - }, - ], - tourActive: true, - }, - upload: { - name: "upload", - run: true, - steps: [ - { - content: t("HELP_UPLOAD_FILETYPE_OPTION_CONTAINER"), - target: ".upload-option-container", - disableBeacon: true, - placement: "top-end", - title: "", - disableScrolling: true, - disableOverlay :true, - }, - ], - tourActive: true, - }, - hypothesis: { - name: "hypothesis", - run: true, - steps: [ - { - content: t("HELP_HYPOTHESIS_INTERACTABLE_SECTION"), - target: ".hypothesis-help", - disableBeacon: true, - placement: "right-start", - title: "", - disableScrolling: true, - disableOverlay :true, - }, - // { - // content: - // t("HELP_RULE_ENGINE_INPUT"), - // target: ".last-container .key", - // disableBeacon: true, - // placement: "top-start", - // title: "", - // }, - // { - // content: - // t("HELP_HYPOTHESIS_DELETE_BUTTON"), - // target: ".last-containe .delete-button-help-locator", - // disableBeacon: true, - // placement: "top-start", - // title: "", - // }, - { - content: t("HELP_HYPOTHESIS_ADD_BUTTON"), - target: ".add-button-help", - disableBeacon: true, - placement: "top-start", - title: "", - disableOverlay :true, - }, - ], - tourActive: true, - }, - ruleEngine: { - name: "ruleEngine", - run: true, - steps: [ - { - content: t("HELP_RULE_ENGINE_INTERACTABLE_SECTION"), - target: ".rule-engine-help", - disableBeacon: true, - placement: "right-start", - title: "", - disableScrolling: true, - disableOverlay :true, - }, - { - content: t("HELP_RULE_ENGINE_INPUT"), - target: ".user-input-section .interactable-section .select-and-input-wrapper-first .input", - disableBeacon: true, - placement: "top-end", - title: "", - disableOverlay :true, - }, - { - content: t("HELP_RULE_ENGINE_DELETE_BUTTON"), - target: ".select-and-input-wrapper-first .delete-button", - disableBeacon: true, - placement: "left-start", - title: "", - disableOverlay :true, - }, - { - content: t("HELP_RULE_ENGINE_ADD_BUTTON"), - target: ".add-button-help", - disableBeacon: true, - placement: "top-start", - title: "", - disableOverlay :true, - }, - ], - tourActive: true, - }, - mapping: { - name: "mapping", - run: true, - steps: [ - { - content: t("HELP_MAPPING_BOUNDARY_SELECTION"), - target: ".filter-by-boundary .button-primary", - disableBeacon: true, - placement: "right-end", - title: "", - disableScrolling: true, - disableOverlay :true, - }, - { - content: t("HELP_MAPPING_BASE_MAP"), - target: ".base-map-selector .icon-first", - disableBeacon: true, - placement: "left-start", - title: "", - disableScrolling: true, - disableOverlay :true, - }, - { - content: t("HELP_MAPPING_FILTER"), - target: ".filter-icon p", - disableBeacon: true, - placement: "left-start", - title: "", - disableScrolling: true, - disableOverlay :true, - }, - { - content: t("HELP_MAPPING_VIRTUALIZATION"), - target: ".virtualization-icon p", - disableBeacon: true, - placement: "left-start", - title: "", - disableScrolling: true, - disableOverlay :true, - }, - { - content: t("HELP_MAPPING_MAP_GEOMETRIES"), - target: ".map-container", - disableBeacon: true, - placement: "top-end", - title: "", - disableScrolling: true, - disableOverlay :true, - }, - ], - tourActive: true, - }, - microplanPreview: { - name: "microplanPreview", - run: true, - steps: [ - { - content: t("HELP_MICROPLAN_DETAILS_EDIT_ROWS"), - target: ".preview-container", - disableBeacon: true, - placement: "top-end", - title: "", - disableOverlay :true, - disableScrolling: true, - }, - ], - tourActive: true, - }, - }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js deleted file mode 100644 index 1241d678738..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/index.js +++ /dev/null @@ -1,42 +0,0 @@ -import utils from "../utils"; -import useCreatePlanConfig from "./useCreatePlanConfig"; -import useSearchPlanConfig from "./useSearchPlanConfig"; -import useUpdatePlanConfig from "./useUpdatePlanConfig"; -import useSavedMicroplans from "./useSavedMicroplans"; -import useSearchCampaign from "./useSearchCampaign"; -import { useGenerateIdCampaign } from "./useGenerateIdCampaign"; -const UserService = {}; - -const microplan = { - useCreatePlanConfig, - useSearchPlanConfig, - useUpdatePlanConfig, - useSavedMicroplans, - useSearchCampaign, - useGenerateIdCampaign, -}; - -const contracts = {}; - -const Hooks = { - attendance: { - update: () => {}, - }, - microplan, - contracts, -}; - -const Utils = { - browser: { - sample: () => {}, - }, - microplan: { - ...utils, - }, -}; - -export const CustomisedHooks = { - Hooks, - UserService, - Utils, -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js deleted file mode 100644 index 6afb891b15b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useCreatePlanConfig.js +++ /dev/null @@ -1,8 +0,0 @@ -import { useMutation } from "react-query"; -import CreatePlanConfig from "../services/CreatePlanConfig"; - -const useCreatePlanConfig = () => { - return useMutation(data => CreatePlanConfig(data)) -} - -export default useCreatePlanConfig; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js deleted file mode 100644 index f315dda5ff8..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useGenerateIdCampaign.js +++ /dev/null @@ -1,26 +0,0 @@ -export const useGenerateIdCampaign = ({ type, hierarchyType, filters, campaignId, config = {} }) => { - const updatedFilters = filters?.map(({ type, ...rest }) => ({ - ...rest, - boundaryType: type, - })); - const reqCriteria = { - url: `/project-factory/v1/data/_generate`, - changeQueryName: `${type}${hierarchyType}${filters}`, - params: { - tenantId: Digit.ULBService.getCurrentTenantId(), - type: type, - forceUpdate: true, - hierarchyType: hierarchyType, - campaignId: campaignId, - }, - body: type === "boundary" ? (updatedFilters === undefined ? { Filters: null } : { Filters: { boundaries: updatedFilters } }) : {}, - config: { - ...config, - cacheTime: 0, - staleTime: 0, - }, - }; - const { data: Data, refetch, isLoading } = Digit.Hooks.useCustomAPIHook(reqCriteria); - - return { isLoading: isLoading, data: Data?.GeneratedResource?.[0]?.id, refetch }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js deleted file mode 100644 index 15e423d59e0..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useNumberFormatter.js +++ /dev/null @@ -1,21 +0,0 @@ -import { useTranslation } from "react-i18next"; - -export const useNumberFormatter = (FormatMapping) => { - const { i18n } = useTranslation(); - - const formatNumber = (value, options) => { - try { - const currentLanguage = i18n.language; - const fallbackLanguage = i18n.options.fallbackLng[0]; // Get the first language in the fallback list - const locale = FormatMapping?.[currentLanguage] || FormatMapping?.[fallbackLanguage] || currentLanguage || ""; - return new Intl.NumberFormat(locale, options).format(value); - } catch (error) { - console.error("Error formatting number:", error); - return value; - } - }; - - return { formatNumber }; -}; - -export default useNumberFormatter; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js deleted file mode 100644 index 23c1259c6c4..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSavedMicroplans.js +++ /dev/null @@ -1,23 +0,0 @@ -import { useQuery } from "react-query"; -import SearchSavedPlans from "../services/searchSavedPlans"; - -const useSavedMicroplans = (reqCriteria) => { - const { body, config, params, state, url } = reqCriteria; - const { isLoading, data, isFetching, refetch } = useQuery(["SAVED_MICROPLANS", url], () => SearchSavedPlans(body), { - ...config, - cacheTime: 0, - staleTime: 0, - onError: (err) => console.error("Error fetching saved microplans:", err), - }); - - return { - isLoading, - isFetching, - data, - refetch, - revalidate: () => {}, - }; -}; - -// () => SearchSavedPlans(data) -export default useSavedMicroplans; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js deleted file mode 100644 index e2644f00ca9..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchCampaign.js +++ /dev/null @@ -1,8 +0,0 @@ -import { useQuery } from "react-query"; -import SearchCampaignConfig from "../services/SearchCampaignConfig"; - -const useSearchCampaign = (data, config = {}) => { - return useQuery(["SEARCH_CAMPAIGN",data], () => SearchCampaignConfig(data), { ...config }); -}; - -export default useSearchCampaign; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js deleted file mode 100644 index 003fdaa4f51..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useSearchPlanConfig.js +++ /dev/null @@ -1,8 +0,0 @@ -import { useMutation } from "react-query"; -import SearchPlanConfig from "../services/SearchPlanConfig"; - -const useSearchPlanConfig = (data, config = {}) => { - return useQuery([data?.tenantId, data?.id, data?.name, data?.executionPlanId, data?.userUuid, data?.offset, data?.limit], () => SearchPlanConfig(data), { ...config }); -}; - -export default useSearchPlanConfig; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js deleted file mode 100644 index 17b16145a08..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/hooks/useUpdatePlanConfig.js +++ /dev/null @@ -1,8 +0,0 @@ -import { useMutation } from "react-query"; -import UpdatePlanConfig from "../services/UpdatePlanConfig"; - -const useUpdatePlanConfig = () => { - return useMutation(data => UpdatePlanConfig(data)) -} - -export default useUpdatePlanConfig; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js deleted file mode 100644 index 03f82f59456..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/icons/Svg.js +++ /dev/null @@ -1,217 +0,0 @@ -import React from "react"; - -export const PopulationSvg = (style) => { - return ` - - - - - - - - - - - - `; -}; - -export const HelpOutlineIcon = ({ className = "", fill = "", style = {} }) => ( - - - - - - - - - - -); - -export const DefaultMapMarkerSvg = (style) => { - return ` - - - - - `; -}; - - -export const WarehouseMarker = ({ - className = "", - fill = "white", - fillBackground = "#42BBFF", - style = {}, - width = "3.125rem", - height = "3.125rem", -}) => { - return ` - - - - - - - - - - - - `; -}; - -export const Warehouse = ({ className = "", fill = "white", fillBackground = "#42BBFF", style = {}, width = "1.5rem", height = "1.5rem" }) => { - return ( - - - - - - - - - - - - ); -}; - -export const Church = ({ className = "", fill = "white", fillBackground = "#064466", style = {}, width = "1.5rem", height = "1.5rem" }) => { - return ( - - - - - - - - - - - - - ); -}; - -export const School = ({ className = "", fill = "white", fillBackground = "#FF7B42", style = {}, width = "1.5rem", height = "1.5rem" }) => { - return ( - - - - - - - - - - - - - - - - - ); -}; - -export const HealthFacility = ({ className = "", fill = "white", fillBackground = "#0C9219", style = {}, width = "1.5rem", height = "1.5rem" , onClick=null}) => { - return ( - - - - - - - - - - - - ); -}; - -export const ChurchMarker = ({ className = "", fill = "white", fillBackground = "#064466", style = {}, width = "3.125rem", height = "3.125rem" }) => { - return ` - - - - - -`; -}; - -export const SchoolMarker = ({ className = "", fill = "white", fillBackground = "#FF7B42", style = {}, width = "3.125rem", height = "3.125rem" }) => { - return ` - - - - - - - - - - - - - - - - -`; -}; - -export const HealthFacilityMarker = ({ - className = "", - fill = "white", - fillBackground = "#0C9219", - style = {}, - width = "3.125rem", - height = "3.125rem", -}) => { - return ` - - - - - - - - - - - -`; -}; - - - - - -export const PlusWithSurroundingCircle = ({ className = "", fill = "white", fillBackground = "#FF7B42", style = {}, width = "1rem", height = "1rem" ,onClick=null }) => { - return ( - - - - ); -}; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js deleted file mode 100644 index 3885795450c..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/CreateMicroplan.js +++ /dev/null @@ -1,288 +0,0 @@ -import React, { useState, useEffect, useCallback, Fragment } from "react"; -import { useTranslation } from "react-i18next"; -import { timeLineOptions } from "../../configs/timeLineOptions.json"; -import Upload from "../../components/Upload"; -import Hypothesis from "../../components/Hypothesis"; -import RuleEngine from "../../components/RuleEngine"; -import Mapping from "../../components/Mapping"; -import Navigator from "../../components/Nagivator"; -import { Toast } from "@egovernments/digit-ui-components"; -import MicroplanPreview from "../../components/MicroplanPreview"; -import MicroplanDetails from "../../components/MicroplanDetails"; - -export const components = { - MicroplanDetails, - Upload, - Hypothesis, - RuleEngine, - Mapping, - MicroplanPreview, -}; - -import MicroplanCreatedScreen from "../../components/MicroplanCreatedScreen"; -import { LoaderWithGap, Tutorial } from "@egovernments/digit-ui-react-components"; -import { useMyContext } from "../../utils/context"; -import { updateSessionUtils } from "../../utils/updateSessionUtils"; -import { render } from "react-dom"; - -// Main component for creating a microplan -const CreateMicroplan = () => { - // Fetching data using custom MDMS hook - const { id: campaignId = "" } = Digit.Hooks.useQueryParams(); - const { mutate: CreateMutate } = Digit.Hooks.microplan.useCreatePlanConfig(); - const { mutate: UpdateMutate } = Digit.Hooks.microplan.useUpdatePlanConfig(); - const [toRender, setToRender] = useState("navigator"); - const { t } = useTranslation(); - - // States - const [microplanData, setMicroplanData] = useState(); - const [operatorsObject, setOperatorsObject] = useState([]); - const [toast, setToast] = useState(); - const [checkForCompleteness, setCheckForCompletion] = useState([]); - const [loaderActivation, setLoaderActivation] = useState(false); - const { state } = useMyContext(); - - //fetch campaign data - const { id = "" } = Digit.Hooks.useQueryParams(); - const { isLoading: isCampaignLoading, data: campaignData } = Digit.Hooks.microplan.useSearchCampaign( - { - CampaignDetails: { - tenantId: Digit.ULBService.getCurrentTenantId(), - ids: [id], - }, - }, - { - enabled: !!id, - } - ); - // to save microplan helper data to ssn - useEffect(() => { - if (campaignData) Digit.SessionStorage.set("microplanHelperData", { ...Digit.SessionStorage.get("microplanHelperData"), campaignData }); - }, [campaignData]); - - const campaignType = campaignData?.projectType; - - // request body for boundary hierarchy api - const reqCriteria = { - url: `/boundary-service/boundary-hierarchy-definition/_search`, - params: {}, - body: { - BoundaryTypeHierarchySearchCriteria: { - tenantId: Digit.ULBService.getStateId(), - hierarchyType: campaignData?.hierarchyType, - }, - }, - config: { - enabled: !!campaignData?.hierarchyType, - select: (data) => { - return data?.BoundaryHierarchy?.[0]?.boundaryHierarchy?.map((item) => item?.boundaryType) || {}; - }, - }, - }; - const { isLoading: ishierarchyLoading, data: hierarchyData } = Digit.Hooks.useCustomAPIHook(reqCriteria); - - // useEffect to initialise the data from MDMS - useEffect(() => { - let temp; - if (!state || !state.UIConfiguration) return; - const UIConfiguration = state?.UIConfiguration || {}; - if (UIConfiguration) temp = UIConfiguration.find((item) => item.name === "ruleConfigure"); - if (!temp?.ruleConfigureOperators) return; - setOperatorsObject(temp.ruleConfigureOperators); - }, []); - - // useEffect to store data in session storage - useEffect(() => { - if (!microplanData) return; - Digit.SessionStorage.set("microplanData", microplanData); - }, [microplanData]); - - // useEffect to store data in session storage - useEffect(() => { - const data = Digit.SessionStorage.get("microplanData"); - if (data?.microplanStatus === "GENERATED") setToRender("success-screen"); - let statusData = {}; - let toCheckCompletenesData = []; - timeLineOptions.forEach((item) => { - statusData[item.name] = false; - if (item?.checkForCompleteness) toCheckCompletenesData.push(item.name); - }); - if (data && data?.status) { - if (Object.keys(data?.status) === 0) setMicroplanData({ ...data, status: statusData }); - else setMicroplanData({ ...data }); - } - setCheckForCompletion(toCheckCompletenesData); - }, []); - - // An addon function to pass to Navigator - const nextEventAddon = useCallback( - async (currentPage, checkDataCompletion, setCheckDataCompletion) => { - if (!microplanData) { - setCheckDataCompletion("perform-action"); - return; - } - setMicroplanData((previous) => ({ - ...previous, - status: { ...previous?.status, [currentPage?.name]: checkDataCompletion === "valid" }, - })); - - setCheckDataCompletion("false"); - let body = Digit.Utils.microplan.mapDataForApi( - microplanData, - operatorsObject, - microplanData?.microplanDetails?.name, - campaignId, - "DRAFT", - microplanData?.planConfigurationId ? "update" : "create" - ); - if (!Digit.Utils.microplan.planConfigRequestBodyValidator(body, state, campaignType)) { - setCheckDataCompletion("perform-action"); - return; - } - setLoaderActivation(true); - try { - if (!microplanData?.planConfigurationId) { - await createPlanConfiguration(body, setCheckDataCompletion, setLoaderActivation, state); - } else if (microplanData?.planConfigurationId) { - await updatePlanConfiguration(body, setCheckDataCompletion, setLoaderActivation, state); - } - } catch (error) { - console.error("Failed to create/update plan configuration:", error); - } - }, - [microplanData, UpdateMutate, CreateMutate] - ); - - const createPlanConfiguration = async (body, setCheckDataCompletion, setLoaderActivation, state) => { - await CreateMutate(body, { - onSuccess: async (data) => { - const readMeConstant = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName"); - const additionalProps = { - hierarchyData: hierarchyData, - t, - campaignType, - campaignData, - readMeSheetName: readMeConstant ? readMeConstant.value : undefined, - }; - const computedSession = await updateSessionUtils.computeSessionObject(data?.PlanConfiguration[0], state, additionalProps); - if (computedSession) { - computedSession.microplanStatus = "DRAFT"; - setMicroplanData(computedSession); - } else { - console.error("Failed to compute session data."); - } - setLoaderActivation(false); - setCheckDataCompletion("perform-action"); - }, - onError: (error, variables) => { - setToast({ - message: t("ERROR_DATA_NOT_SAVED"), - state: "error", - transitionTime: 10000, - }); - setTimeout(() => { - setLoaderActivation(false); - setCheckDataCompletion("false"); - }, 2000); - }, - }); - }; - - const updatePlanConfiguration = async (body, setCheckDataCompletion, setLoaderActivation, state) => { - body.PlanConfiguration["id"] = microplanData?.planConfigurationId; - body.PlanConfiguration["auditDetails"] = microplanData?.auditDetails; - await UpdateMutate(body, { - onSuccess: async (data) => { - const readMeConstant = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName"); - const additionalProps = { - hierarchyData: hierarchyData, - t, - campaignType, - campaignData, - readMeSheetName: readMeConstant ? readMeConstant.value : undefined, - }; - const computedSession = await updateSessionUtils.computeSessionObject(data?.PlanConfiguration[0], state, additionalProps); - if (computedSession) { - computedSession.microplanStatus = "DRAFT"; - setMicroplanData(computedSession); - } else { - console.error("Failed to compute session data."); - } - setLoaderActivation(false); - setCheckDataCompletion("perform-action"); - }, - onError: (error, variables) => { - setToast({ - message: t("ERROR_DATA_NOT_SAVED"), - state: "error", - transitionTime: 10000, - }); - setTimeout(() => { - setLoaderActivation(false); - setCheckDataCompletion("false"); - }, 2000); - }, - }); - }; - - const setCurrentPageExternally = useCallback( - (props) => { - switch (props.method) { - case "set": { - let currentPage; - const data = Digit.SessionStorage.get("microplanData"); - if (data?.currentPage) currentPage = data.currentPage; - if (currentPage && props?.setCurrentPage && timeLineOptions.find((item) => item.id === currentPage?.id)) { - props.setCurrentPage(currentPage); - return true; - } - break; - } - case "save": { - if (props.currentPage) { - setMicroplanData((previous) => ({ ...previous, currentPage: props.currentPage })); - } - break; - } - } - }, - [microplanData, setMicroplanData, Navigator] - ); - - const completeNavigation = useCallback(() => { - setToRender("success-screen"); - }, [setToRender]); - - return ( - <> -
- {toRender === "navigator" && ( - - )} - {toRender === "success-screen" && } -
- {toast && ( - setToast(undefined)} - /> - )} - {loaderActivation && } - - ); -}; - -export default CreateMicroplan; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js deleted file mode 100644 index 7534c1b2af1..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/Guidelines.js +++ /dev/null @@ -1,54 +0,0 @@ -import React, { Fragment } from "react"; -import { useTranslation } from "react-i18next"; -import { Link } from "react-router-dom"; -import { ArrowForward } from "@egovernments/digit-ui-svg-components"; -import { Button } from "@egovernments/digit-ui-react-components"; -import { useHistory } from "react-router-dom"; -import { ActionBar } from "@egovernments/digit-ui-components"; - -const Guidelines = ({ path }) => { - const { t } = useTranslation(); - const history = useHistory() - // Keeping inline style for now because design for this screen is not given yet - const { id = "" } = Digit.Hooks.useQueryParams(); - const onNextClick = ()=>{ - history.push(`/${window.contextPath}/employee/microplanning/create-microplan?id=${id}`); - } - return ( - <> - -
- {t("CREATE_MICROPLAN_GUIDELINES")} -
- - {/* Action bar */} - - {/* Next/Submit button */} - - - - ); -}; - -export default Guidelines; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js deleted file mode 100644 index bbb0aef7628..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SavedMicroplans.js +++ /dev/null @@ -1,200 +0,0 @@ -import React, { useState } from "react"; -import { useTranslation } from "react-i18next"; -import { Header, InboxSearchComposerV2, Loader } from "@egovernments/digit-ui-react-components"; -import { useHistory } from "react-router-dom"; -import { updateSessionUtils } from "../../utils/updateSessionUtils"; -import { useMyContext } from "../../utils/context"; - -const configs = { - label: "SAVED_MICROPLANS", - type: "search", - apiDetails: { - serviceName: "/plan-service/config/_search", - requestParam: {}, - requestBody: {}, - minParametersForSearchForm: 0, - masterName: "commonUiConfig", - moduleName: "SearchMicroplan", - tableFormJsonPath: "requestBody.PlanConfigurationSearchCriteria.pagination", - searchFormJsonPath: "requestBody.PlanConfigurationSearchCriteria", - }, - sections: { - search: { - uiConfig: { - type: "search", - typeMobile: "filter", - headerLabel: "SAVED_MICROPLANS", - headerStyle: null, - primaryLabel: "ES_COMMON_SEARCH", - secondaryLabel: "ES_COMMON_CLEAR_SEARCH", - minReqFields: 0, - // "showFormInstruction": "TQM_SEARCH_HINT", - defaultValues: { - name: "", - status: "", - }, - fields: [ - { - label: "MICROPLAN_NAME", - type: "text", - isMandatory: false, - disable: false, - populators: { - name: "name", - style: { - marginBottom: "0px", - }, - }, - }, - { - label: "MICROPLAN_STATUS", - type: "dropdown", - isMandatory: false, - disable: false, - populators: { - name: "status", - optionsKey: "status", - optionsCustomStyle: { - top: "2.3rem", - }, - mdmsConfig: { - masterName: "MicroplanStatus", - moduleName: "hcm-microplanning", - localePrefix: "MICROPLAN_STATUS", - }, - }, - }, - ], - }, - label: "", - children: {}, - show: true, - // "labelMobile": "TQM_INBOX_SEARCH" - }, - searchResult: { - uiConfig: { - columns: [ - { - label: "MICROPLAN_NAME", - jsonPath: "name", - }, - { - label: "MICROPLAN_STATUS", - jsonPath: "status", - prefix: "MICROPLAN_STATUS_COLUMN_", - translate: true, - }, - { - label: "CAMPAIGNS_ASSIGNED", - jsonPath: "CampaignDetails.campaignName", - }, - { - label: "CAMPAIGN_DATE", - jsonPath: "CampaignDetails.startDate", - additionalCustomization: true, - }, - ], - showActionBarMobileCard: true, - actionButtonLabelMobileCard: "TQM_VIEW_RESULTS", - enableGlobalSearch: false, - enableColumnSort: true, - resultsJsonPath: "PlanConfiguration", - tableClassName: "table pqm-table", - noColumnBorder: true, - rowClassName: "table-row-mdms table-row-mdms-hover", - }, - children: {}, - show: true, - }, - }, - additionalSections: {}, - persistFormData: true, - showAsRemovableTagsInMobile: false, - customHookName: "microplan.useSavedMicroplans", -}; - -const SavedMicroplans = () => { - const [showLoader, setShowLoader] = useState(false); - const { state } = useMyContext(); - const history = useHistory(); - const { t } = useTranslation(); - - const fetchHierarchyData = async (hierarchyType) => { - const response = await Digit.CustomService.getResponse({ - url: "/boundary-service/boundary-hierarchy-definition/_search", - useCache: false, - method: "POST", - userService: false, - body: { - BoundaryTypeHierarchySearchCriteria: { - tenantId: Digit.ULBService.getStateId(), - hierarchyType, - }, - }, - }); - if (response?.BoundaryHierarchy?.length) { - return response.BoundaryHierarchy[0].boundaryHierarchy.map((item) => item.boundaryType); - } - console.error("Invalid response structure"); - }; - - const computeAdditionalProps = (row, state, t, hierarchyData) => { - const campaignDetails = row?.original?.CampaignDetails; - const readMeSheetName = state?.CommonConstants?.find((item) => item?.name === "readMeSheetName")?.value; - return { - hierarchyData, - t, - campaignType: campaignDetails?.projectType, - campaignData: campaignDetails, - readMeSheetName, - }; - }; - - const onClickRow = (row) => { - const handleClick = async () => { - setShowLoader(true); - try { - const campaignType = row?.original?.CampaignDetails?.projectType; - const hierarchyData = await fetchHierarchyData(row?.original?.CampaignDetails?.hierarchyType); - const additionalProps = computeAdditionalProps(row, state, t, hierarchyData); - - // Compute the session object based on the row?.original data and then re-route - const computedSession = await updateSessionUtils.computeSessionObject(row.original, state, additionalProps); - Digit.SessionStorage.set("microplanData", computedSession); - - setShowLoader(false); - history.push(`/${window.contextPath}/employee/microplanning/create-microplan?id=${row?.original?.executionPlanId}`); - } catch (error) { - console.error(`Failed to process the request: ${error.message}`); - setShowLoader(false); - } - }; - - handleClick(); - }; - - const savedMircoplanSession = Digit.Hooks.useSessionStorage("SAVED_MICROPLAN_SESSION", {}); - - if (showLoader) { - return ; - } - - return ( - -
{t(configs?.label)}
-
- -
-
- ); -}; - -export default SavedMicroplans; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js deleted file mode 100644 index 8f2131eefdd..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/SelectCampaign.js +++ /dev/null @@ -1,226 +0,0 @@ -import React, { useEffect, useMemo } from "react"; -import { useTranslation } from "react-i18next"; -import { Header, InboxSearchComposer, InboxSearchComposerV2, Loader } from "@egovernments/digit-ui-react-components"; -import { useHistory, useParams } from "react-router-dom"; - -const configs = { - label: "SELECT_CAMPAIGN", - type: "search", - apiDetails: { - serviceName: "/project-factory/v1/project-type/search", - requestParam: {}, - requestBody: {}, - minParametersForSearchForm: 0, - masterName: "commonUiConfig", - moduleName: "SearchCampaign", - tableFormJsonPath: "requestBody.CampaignDetails.pagination", - searchFormJsonPath: "requestBody.CampaignDetails", - }, - sections: { - search: { - uiConfig: { - type: "search", - // typeMobile: "filter", - headerLabel: "SELECT_CAMPAIGN", - headerStyle: null, - primaryLabel: "ES_COMMON_SEARCH", - secondaryLabel: "ES_COMMON_CLEAR_SEARCH", - minReqFields: 1, - // "showFormInstruction": "TQM_SEARCH_HINT", - defaultValues: { - campaignName: "", - projectType: "", - startDate: "", - endDate: "", - boundaryCode: "", - }, - fields: [ - { - label: "CAMPAIGN_NAME", - type: "text", - isMandatory: false, - disable: false, - populators: { - name: "campaignName", - style: { - marginBottom: "0px", - }, - error: "ERR_MIN_LENGTH_CAMPAIGN_NAME", - validationErrorStyles: { - marginTop: "0.3rem", - }, - validation: { - minLength: 2, - }, - }, - }, - // { - // label: "CAMPAIGN_TYPE", - // type: "dropdown", - // isMandatory: false, - // disable: false, - // populators: { - // name: "projectType", - // optionsKey: "name", - // optionsCustomStyle: { - // top: "2.3rem", - // }, - // mdmsConfig: { - // masterName: "projectTypes", - // moduleName: "HCM-PROJECT-TYPES", - // localePrefix: "CAMPAIGN_TYPE", - // }, - // }, - // }, - { - label: "CAMPAIGN_TYPE", - type: "apidropdown", - isMandatory: false, - disable: false, - populators: { - name: "projectType", - optionsKey: "i18nKey", - optionsCustomStyle: { - top: "2.3rem", - }, - allowMultiSelect: false, - masterName: "commonUiConfig", - moduleName: "SearchCampaign", - customfn: "populateProjectType", - }, - }, - { - label: "CAMPAIGN_START_DATE", - type: "date", - isMandatory: false, - key: "startDate", - disable: false, - preProcess: { - updateDependent: ["populators.max"], - }, - populators: { - name: "startDate", - style: { - marginBottom: "0px", - }, - error: "DATE_VALIDATION_MSG", - }, - }, - { - label: "CAMPAIGN_END_DATE", - type: "date", - isMandatory: false, - disable: false, - key: "endDate", - preProcess: { - updateDependent: ["populators.max"], - }, - populators: { - name: "endDate", - error: "DATE_VALIDATION_MSG", - min: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString().slice(0, 10), - style: { - marginBottom: "0px", - }, - }, - }, - // { - // label: "CAMPAIGN_BOUNDARY", - // type: "text", - // isMandatory: false, - // disable: false, - // populators: { - // name: "boundaryCode", - // style: { - // marginBottom: "0px", - // }, - // }, - // }, - ], - }, - label: "", - children: {}, - show: true, - // "labelMobile": "TQM_INBOX_SEARCH" - }, - searchResult: { - uiConfig: { - columns: [ - { - label: "CAMPAIGN_NAME", - jsonPath: "campaignName", - // "additionalCustomization": true - }, - { - label: "CAMPAIGN_TYPE", - jsonPath: "projectType", - // "additionalCustomization": false, - prefix: "CAMPAIGN_TYPE_", - translate: true, - }, - { - label: "CAMPAIGN_BOUNDARY_CAMP", - jsonPath: "boundaryCode", - // "additionalCustomization": false, - prefix: "CAMPAIGN_BOUNDARY_", - translate: true, - }, - { - label: "CAMPAIGN_BENEFICIARY_TYPE", - jsonPath: "additionalDetails.beneficiaryType", - prefix: "CAMPAIGN_BENEFICIARY_TYPE_", - translate: true, - }, - { - label: "CAMPAIGN_DATE", - jsonPath: "startDate", - additionalCustomization: true, - }, - ], - showActionBarMobileCard: true, - actionButtonLabelMobileCard: "TQM_VIEW_RESULTS", - enableGlobalSearch: false, - enableColumnSort: true, - resultsJsonPath: "CampaignDetails", - tableClassName: "table pqm-table", - rowClassName: "table-row-mdms table-row-mdms-hover", - noColumnBorder: true, - }, - children: {}, - show: true, - }, - }, - additionalSections: {}, - persistFormData: true, - showAsRemovableTagsInMobile: false, -}; -const SelectCampaign = () => { - const { t } = useTranslation(); - const history = useHistory(); - - const onClickRow = (row) => { - // history.push(`/${window.contextPath}/employee/microplanning/help-guidelines?id=${row?.original?.id}`); - history.push(`/${window.contextPath}/employee/microplanning/create-microplan?id=${row?.original?.id}`); - }; - - const SelectCampaignSession = Digit.Hooks.useSessionStorage("SELECT_CAMPAIGN_SESSION", {}); - - return ( - -
{t(configs?.label)}
-
- -
-
- ); -}; - -export default SelectCampaign; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js deleted file mode 100644 index 6f58779637a..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/pages/employee/index.js +++ /dev/null @@ -1,128 +0,0 @@ -import React, { useEffect } from "react"; -import { Switch, useLocation } from "react-router-dom"; -import { useTranslation } from "react-i18next"; -import { PrivateRoute, AppContainer, BreadCrumb, Loader } from "@egovernments/digit-ui-react-components"; -import MicroplanningHeader from "../../components/MicroplanningHeader"; -import Guidelines from "./Guidelines"; -import CreateMicroplan from "./CreateMicroplan"; -import SavedMicroplans from "./SavedMicroplans"; -import SelectCampaign from "./SelectCampaign"; -import { useMyContext } from "../../utils/context"; - -const MicroplanningBreadCrumb = ({ location, defaultPath }) => { - const { t } = useTranslation(); - const pathVar = location.pathname.replace(`${defaultPath}/`, "").split("?")?.[0]; - const { masterName, moduleName, uniqueIdentifier } = Digit.Hooks.useQueryParams(); - - const crumbs = [ - { - path: `/${window?.contextPath}/employee`, - content: t("Home"), - show: true, - }, - // { - // content: t(`UPLOAD`) , - // show: pathVar.includes("upload")?true: false, - // }, - // { - // content: t(`HYPOTHESIS`) , - // show: pathVar.includes("hypothesis")?true: false, - // }, - // { - // content: t(`RULE_ENGINE`) , - // show: pathVar.includes("rule-engine")?true: false, - // }, - { - content: t(`CREATE_MICROPLAN`), - show: pathVar.includes("create-microplan"), - }, - { - content: t(`SAVED_MICROPLANS_TEXT`), - show: pathVar.includes("saved-microplan"), - }, - { - content: t(`CREATE_MICROPLAN`), - show: pathVar.includes("select-campaign"), - }, - ]; - return ; -}; - -const App = ({ path }) => { - const { dispatch } = useMyContext(); - - const location = useLocation(); - const MDMSCreateSession = Digit.Hooks.useSessionStorage("MDMS_add", {}); - const [sessionFormData, setSessionFormData, clearSessionFormData] = MDMSCreateSession; - - const MDMSViewSession = Digit.Hooks.useSessionStorage("MDMS_view", {}); - const [sessionFormDataView, setSessionFormDataView, clearSessionFormDataView] = MDMSViewSession; - - const { isLoading: isLoadingMdmsBaseData, data } = Digit.Hooks.useCustomMDMS( - Digit.ULBService.getCurrentTenantId(), - "hcm-microplanning", - [ - { name: "UploadConfiguration" }, - { name: "UIConfiguration" }, - { name: "Schemas" }, - { name: "RuleConfigureOutput" }, - { name: "Resources" }, - { name: "HypothesisAssumptions" }, - { name: "BaseMapLayers" }, - { name: "MicroplanPreviewAggregates" }, - { name: "AutoFilledRuleConfigurations" }, - { name: "MapFilters" }, - { name: "HierarchyConfigurations" }, - { name: "NumberFormatMappingForTranslation" }, - { name: "UploadGuidelines" }, - { name: "ReadMeData" }, - { name: "CommonConstants" }, - ], - { - select: (data) => { - dispatch({ - type: "SETINITDATA", - state: { - ...data?.["hcm-microplanning"], - }, - }); - }, - } - ); - - //destroying session - useEffect(() => { - const pathVar = location.pathname.replace(`${path}/`, "").split("?")?.[0]; - Digit.Utils.microplan.destroySessionHelper(pathVar, ["create-microplan"], "microplanData"); - Digit.Utils.microplan.destroySessionHelper(pathVar, ["create-microplan"], "microplanHelperData"); - Digit.Utils.microplan.destroySessionHelper(pathVar, ["select-campaign"], "SELECT_CAMPAIGN_SESSION"); - Digit.Utils.microplan.destroySessionHelper(pathVar, ["saved-microplans"], "SAVED_MICROPLAN_SESSION"); - }, [location]); - - if (isLoadingMdmsBaseData) { - return ; - } - - return ( - -
- - -
- - - {/* } /> - } /> - } /> */} - } /> - - } /> - } /> - } /> - - -
- ); -}; - -export default App; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js deleted file mode 100644 index cabc9b67b56..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/CreatePlanConfig.js +++ /dev/null @@ -1,19 +0,0 @@ -const CreatePlanConfig = async (body) => { - try { - const response = await Digit.CustomService.getResponse({ - url: "/plan-service/config/_create", - useCache: false, - method: "POST", - userService: true, - body, - }); - return response; - } catch (error) { - if (error?.response?.data?.Errors) { - throw new Error(error.response.data.Errors[0].message); - } - throw new Error("An unknown error occurred"); - } -}; - -export default CreatePlanConfig; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js deleted file mode 100644 index 83d4fb5fc72..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/Search.js +++ /dev/null @@ -1,181 +0,0 @@ -import _ from "lodash"; - -const createProjectsArray = (t, project, searchParams, headerLocale) => { - let totalProjects = { - searchedProject: {}, - subProjects: [], - }; - let basicDetails = {}; - let totalProjectsLength = project.length; - // for(let projectIndex = 0; projectIndex < totalProjectsLength; projectIndex++) { - let currentProject = project[0]; - const headerDetails = { - title: " ", - asSectionHeader: true, - values: [ - { title: "WORKS_PROJECT_ID", value: currentProject?.projectNumber || "NA" }, - { title: "ES_COMMON_PROPOSAL_DATE", value: Digit.Utils.pt.convertEpochToDate(currentProject?.additionalDetails?.dateOfProposal) || "NA" }, - { title: "WORKS_PROJECT_NAME", value: currentProject?.name || "NA" }, - { title: "PROJECT_PROJECT_DESC", value: currentProject?.description || "NA" }, - ], - }; - - const projectDetails = { - title: "WORKS_PROJECT_DETAILS", - asSectionHeader: true, - values: [ - { title: "PROJECT_LOR", value: currentProject?.referenceID || "NA" }, - { - title: "WORKS_PROJECT_TYPE", - value: currentProject?.projectType ? t(`COMMON_MASTERS_${Digit.Utils.locale.getTransformedLocale(currentProject?.projectType)}`) : "NA", - }, - { - title: "PROJECT_TARGET_DEMOGRAPHY", - value: currentProject?.additionalDetails?.targetDemography - ? t(`COMMON_MASTERS_${currentProject?.additionalDetails?.targetDemography}`) - : "NA", - }, - { - title: "PROJECT_ESTIMATED_COST", - value: currentProject?.additionalDetails?.estimatedCostInRs - ? `₹ ${Digit.Utils.dss.formatterWithoutRound(currentProject?.additionalDetails?.estimatedCostInRs, "number")}` - : "NA", - }, - ], - }; - - const locationDetails = { - title: "WORKS_LOCATION_DETAILS", - asSectionHeader: true, - values: [ - { - title: "WORKS_GEO_LOCATION", - value: - currentProject?.address?.latitude || currentProject?.address?.longitude - ? `${currentProject?.address?.latitude}, ${currentProject?.address?.longitude}` - : "NA", - }, - { - title: "WORKS_CITY", - value: currentProject?.address?.city ? t(`TENANT_TENANTS_${Digit.Utils.locale.getTransformedLocale(currentProject?.address?.city)}`) : "NA", - }, //will check with Backend - { title: "WORKS_WARD", value: currentProject?.address?.boundary ? t(`${headerLocale}_ADMIN_${currentProject?.address?.boundary}`) : "NA" }, ///backend to update this - { - title: "WORKS_LOCALITY", - value: currentProject?.additionalDetails?.locality ? t(`${headerLocale}_ADMIN_${currentProject?.additionalDetails?.locality}`) : "NA", - }, - ], - }; - - // const financialDetails = { - // title: "WORKS_FINANCIAL_DETAILS", - // asSectionHeader: false, - // values: [ - // { title: "WORKS_HEAD_OF_ACCOUNTS", value: currentProject?.additionalDetails?.fund ? t(`COMMON_MASTERS_FUND_${currentProject?.additionalDetails?.fund}`) : "NA" }, - // ], - // }; - - let documentDetails = { - title: "", - asSectionHeader: true, - additionalDetails: { - documents: [ - { - title: "WORKS_RELEVANT_DOCUMENTS", - BS: "Works", - values: currentProject?.documents?.map((document) => { - if (document?.status !== "INACTIVE") { - return { - title: document?.documentType === "OTHERS" ? document?.additionalDetails?.otherCategoryName : t(`PROJECT_${document?.documentType}`), - documentType: document?.documentType, - documentUid: document?.fileStore, - fileStoreId: document?.fileStore, - }; - } - return {}; - }), - }, - ], - }, - }; - - //filter any empty object - documentDetails.additionalDetails.documents[0].values = documentDetails?.additionalDetails?.documents?.[0]?.values?.filter((value) => { - if (value?.title) { - return value; - } - }); - - // if(currentProject?.projectNumber === searchParams?.Projects?.[0]?.projectNumber) { - basicDetails = { - projectID: currentProject?.projectNumber, - projectProposalDate: Digit.Utils.pt.convertEpochToDate(currentProject?.additionalDetails?.dateOfProposal) || "NA", - projectName: currentProject?.name || "NA", - projectDesc: currentProject?.description || "NA", - projectHasSubProject: totalProjectsLength > 1 ? "COMMON_YES" : "COMMON_NO", - projectParentProjectID: currentProject?.ancestors?.[0]?.projectNumber || "NA", - uuid: currentProject?.id, - address: currentProject?.address, - ward: currentProject?.address?.boundary, - locality: currentProject?.additionalDetails?.locality, - }; - totalProjects.searchedProject = { - basicDetails, - headerDetails, - projectDetails, - locationDetails, - documentDetails, - }; - // } - // } - return totalProjects; -}; - -export const Search = { - viewProjectDetailsScreen: async ( - t, - tenantId, - searchParams, - filters = { limit: 10, offset: 0, includeAncestors: true, includeDescendants: true }, - headerLocale - ) => { - const response = await Digit.WorksService?.searchProject(tenantId, searchParams, filters); - - let projectDetails = { - searchedProject: { - basicDetails: {}, - details: { - projectDetails: [], - }, - }, - }; - - if (response?.Project) { - let projects = createProjectsArray(t, response?.Project, searchParams, headerLocale); - - //searched Project details - projectDetails.searchedProject["basicDetails"] = projects?.searchedProject?.basicDetails; - projectDetails.searchedProject["details"]["projectDetails"] = { - applicationDetails: [ - projects?.searchedProject?.headerDetails, - projects?.searchedProject?.projectDetails, - projects?.searchedProject?.locationDetails, - projects?.searchedProject?.documentDetails, - ], - }; //rest categories will come here - } - - return { - projectDetails: response?.Project ? projectDetails : [], - response: response?.Project, - processInstancesDetails: [], - workflowDetails: [], - applicationData: {}, - isNoDataFound: response?.Project?.length === 0, - }; - }, - searchEstimate: async (tenantId, filters) => { - const response = await Digit.WorksService?.estimateSearch({ tenantId, filters }); - return response?.estimates; - }, -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js deleted file mode 100644 index bb6a9f26916..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchCampaignConfig.js +++ /dev/null @@ -1,22 +0,0 @@ -const SearchCampaignConfig = async (body) => { - try { - const response = await Digit.CustomService.getResponse({ - url: "/project-factory/v1/project-type/search", - useCache: false, - method: "POST", - userService: false, - body, - }); - if (response?.CampaignDetails?.length === 0) { - throw new Error("Campaign not found with the given id"); - } - return response?.CampaignDetails?.[0]; - } catch (error) { - if (error?.response?.data?.Errors) { - throw new Error(error.response.data.Errors[0].message); - } - throw new Error("An unknown error occurred"); - } -}; - -export default SearchCampaignConfig; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js deleted file mode 100644 index 1fe11f206a7..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/SearchPlanConfig.js +++ /dev/null @@ -1,19 +0,0 @@ -const SearchPlanConfig = async (body) => { - try { - const response = await Digit.CustomService.getResponse({ - url: "/plan-service/config/_search", - useCache: false, - method: "POST", - userService: true, - body, - }); - return response; - } catch (error) { - if (error?.response?.data?.Errors) { - throw new Error(error.response.data.Errors[0].message); - } - throw new Error("An unknown error occurred"); - } -}; - -export default SearchPlanConfig; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js deleted file mode 100644 index d1623cbd167..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/UpdatePlanConfig.js +++ /dev/null @@ -1,18 +0,0 @@ -const UpdatePlanConfig = async (body) => { - try { - const response = await Digit.CustomService.getResponse({ - url: "/plan-service/config/_update", - useCache: false, - method: "POST", - userService: true, - body, - }); - return response; - } catch (error) { - if (error?.response?.data?.Errors) { - throw new Error(error.response.data.Errors[0].message); - } - throw new Error("An unknown error occurred"); - } -}; -export default UpdatePlanConfig; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js deleted file mode 100644 index ba4342526a8..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/services/searchSavedPlans.js +++ /dev/null @@ -1,67 +0,0 @@ -function mergeArrays(array1, key1, array2, key2) { - const mergedArray = []; - - // Create a map of values from array2 using key2 - const map = new Map(); - array2.forEach((item) => { - map.set(item[key2], item); - }); - - // Iterate over array1 and merge with matching items from array2 - array1.forEach((item) => { - const matchingItem = map.get(item[key1]); - if (matchingItem) { - // Merge properties from both items and append to 'CampaignDetails' - const mergedItem = { ...item, CampaignDetails: { ...matchingItem } }; - mergedArray.push(mergedItem); - } else { - // No matching item found in array2, add array1 item with empty 'CampaignDetails' - const mergedItem = { ...item, CampaignDetails: {} }; - mergedArray.push(mergedItem); - } - }); - return mergedArray; -} - -const SearchSavedPlans = async (body) => { - try { - //here get response from both apis and process data and return - const responsePlan = await Digit.CustomService.getResponse({ - url: "/plan-service/config/_search", - useCache: false, - method: "POST", - userService: false, - body, - }); - - const { PlanConfiguration } = responsePlan; - if (!PlanConfiguration || PlanConfiguration.length === 0) return []; - - const executionPlanIds = PlanConfiguration?.map((row) => row?.executionPlanId)?.filter((item) => item); - const CampaignDetails = { - tenantId: Digit.ULBService.getCurrentTenantId(), - ids: executionPlanIds, - }; - - const responseCampaign = await Digit.CustomService.getResponse({ - url: "/project-factory/v1/project-type/search", - useCache: false, - method: "POST", - userService: false, - body: { - CampaignDetails, - }, - }); - const finalResult = { - PlanConfiguration: mergeArrays(responsePlan?.PlanConfiguration, "executionPlanId", responseCampaign?.CampaignDetails, "id"), - }; - return finalResult; - } catch (error) { - if (error?.response?.data?.Errors) { - throw new Error(error.response.data.Errors[0].message); - } - throw new Error("An unknown error occurred"); - } -}; - -export default SearchSavedPlans; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js deleted file mode 100644 index 5e6c18f699e..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/context.js +++ /dev/null @@ -1,31 +0,0 @@ -import React,{useContext,createContext,useReducer} from "react" - -const MyContext = createContext() -const initialState = { - -} - -const reducer = (state=initialState,action) => { - switch (action.type) { - case "SETINITDATA": - return {...state,...action.state} - default: - return state; - } -} - -export const useMyContext = () => { - - return useContext(MyContext) -} - -export const ProviderContext = ({children}) => { - - const [state,dispatch] = useReducer(reducer,initialState) - - return ( - - {children} - - ) -} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js deleted file mode 100644 index a3f79c2358e..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/createTemplate.js +++ /dev/null @@ -1,485 +0,0 @@ -import { BOUNDARY_DATA_SHEET, FACILITY_DATA_SHEET, SCHEMA_PROPERTIES_PREFIX, commonColumn } from "../configs/constants"; - -export const fetchBoundaryData = async (tenantId, hierarchyType, codes) => { - // request for boundary relation api - const reqCriteria = { - url: "/boundary-service/boundary-relationships/_search", - params: { tenantId, hierarchyType, codes, includeChildren: true }, - body: {}, - }; - let response; - try { - response = (await Digit.CustomService.getResponse(reqCriteria))?.TenantBoundary?.[0]?.boundary || {}; - } catch (error) { - console.error("Error in fetching boundary Data: ", error.message); - } - return response; -}; - -export const getFacilities = async (params, body) => { - // request for boundary relation api - const reqCriteria = { - url: "/facility/v1/_search", - params: params, - body: body, - }; - let response; - try { - response = (await Digit.CustomService.getResponse(reqCriteria))?.Facilities || {}; - } catch (error) { - if (error.response) { - throw new Error(`Failed to fetch facility data: ${error.response.data.message}`); - } - if (error.request) { - // Network error - throw new Error("Network error while fetching facility data"); - } - // Other errors - throw new Error(`Error while fetching facility data: ${error.message}`); - } - return response; -}; - -// export const fetchColumnsFromMdms = (schema)=>{ -// return -// } - -/** - * - * @param {*} xlsxData - * @param {*} boundaryData - * @returns xlsxData with boundary data added - */ -export const addBoundaryData = (xlsxData, boundaryData, hierarchyType) => { - // Return the original data if there is no boundary data to add - if (!boundaryData) return xlsxData; - - // Initialize the array to hold new data - let newXlsxData = []; - - // Recursive function to convert boundary data into sheet format - const convertBoundaryDataToSheets = (boundaryData, currentBoundaryPredecessor = [], hierarchyAccumulator = [], dataAccumulator = []) => { - // Return if boundary data is not valid or not an array - if (!boundaryData || !Array.isArray(boundaryData)) return; - - // Clone the current boundary predecessor to avoid modifying the original data - const rowData = [...currentBoundaryPredecessor]; - // Clone the data accumulator to preserve the accumulated data - let tempDataAccumulator = [...dataAccumulator]; - // Use a set to accumulate unique hierarchy levels - let tempHierarchyAccumulator = new Set(hierarchyAccumulator); - - // Iterate over each item in the boundary data array - for (const item of boundaryData) { - if (item?.code) { - // Create a new row with the current item's code - const tempRow = [...rowData, item?.code]; - let response; - // Add the current item's boundary type to the hierarchy - tempHierarchyAccumulator.add(item.boundaryType); - - // If the current item has children, recursively process them - if (item.children) - response = convertBoundaryDataToSheets(item.children, tempRow, tempHierarchyAccumulator, [...tempDataAccumulator, tempRow]); - - // Update the accumulators with the response from the recursive call - if (response) { - tempDataAccumulator = response.tempDataAccumulator; - tempHierarchyAccumulator = response.tempHierarchyAccumulator; - } - } - } - - // Return the accumulated data and hierarchy - return { tempDataAccumulator, tempHierarchyAccumulator }; - }; - - // Convert the boundary data into sheet format and extract the sorted data and hierarchy - let { tempDataAccumulator: sortedBoundaryDataForXlsxSheet, tempHierarchyAccumulator: hierarchy } = convertBoundaryDataToSheets(boundaryData); - - // Add the hierarchy as the first row of the sheet - hierarchy = [...hierarchy].map((item) => `${hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item)}`); - sortedBoundaryDataForXlsxSheet = [[...hierarchy], ...sortedBoundaryDataForXlsxSheet]; - - // Determine the maximum row length to ensure all rows have the same length - const topIndex = Math.max(...sortedBoundaryDataForXlsxSheet.map((row) => row.length)) - 1; - - // Ensure all rows are of the same length by filling them with empty strings - sortedBoundaryDataForXlsxSheet = sortedBoundaryDataForXlsxSheet.map((item, index) => { - let newItem = item; - if (index !== 0) { - if (!newItem) { - newItem = []; - } - const itemLength = newItem.length; - while (newItem.length <= topIndex) { - newItem.push(""); - } - newItem.push(newItem[itemLength - 1]); - } else { - newItem.push(commonColumn); - } - - return newItem; - }); - - // Add the new sheet data to the original data - newXlsxData = [...xlsxData, ...newXlsxData, { sheetName: BOUNDARY_DATA_SHEET, data: sortedBoundaryDataForXlsxSheet }]; - - // Return the updated data - return newXlsxData; -}; - -const fillDataWithBlanks = (data, tillRow) => { - while (data.length < tillRow) { - data.push([]); - } - - const maxLength = Math.max(...data.map((row) => row.length)); - return data.map((row) => [...row, ...new Array(maxLength - row.length).fill("")]); -}; -const generateLocalisationKeyForSchemaProperties = (code) => { - if (!code) return code; - return `${SCHEMA_PROPERTIES_PREFIX}_${code}`; -}; -/** - * - * @param {array} xlsxData , xlsx data - * @param {object} schema , schema to refer to - * @returns {Array of Object} , xlsxData with schema data added - * - * adds schema data to sheets - */ -const addSchemaData = (xlsxData, schema, extraColumnsToAdd) => { - if (!schema) return xlsxData; - let columnSchema = schema.schema?.Properties || {}; - const newXlsxData = []; - const columnList = [[], [], [], []]; // Initialize columnList with four empty arrays - - for (const [key, value] of Object.entries(columnSchema)) { - if (key === commonColumn) continue; - - columnList[0].push(generateLocalisationKeyForSchemaProperties(key)); // Add key to the first array - - // columnList[1].push(value.type || ""); // Add type to the second array - - // columnList[2].push(value.isRequired ? "MANDATORY" : "OPTIONAL"); // Add requirement status to the third array - - // columnList[3].push(value.pattern || ""); // Add pattern to the fourth array - } - - if (extraColumnsToAdd) columnList[0].push(...extraColumnsToAdd); - - for (let { sheetName, data } of xlsxData) { - data = fillDataWithBlanks(data, 4); - columnList.forEach((item, index) => { - // Append the new items to the row - if (data[index]) { - data[index] = [...data[index], ...item]; - } else { - data[index] = [...item]; - } - }); - - newXlsxData.push({ sheetName, data }); - } - - return newXlsxData; -}; - -/** - * - * @param {Array of Object} xlsxData - * @param {string} hierarchyLevelName - */ -const devideXlsxDataHierarchyLevelWise = (xlsxData, hierarchyLevelName) => { - if (!hierarchyLevelName) return xlsxData; // Return original data if no hierarchy level name - - const result = []; // Initialize result array - - // Iterate over each sheet in the xlsxData - for (const sheet of xlsxData) { - const sheetData = sheet.data; - const hierarchyLevelIndex = sheetData[0].indexOf(hierarchyLevelName); - - // If hierarchy level name not found, skip this sheet - if (hierarchyLevelIndex === -1) { - result.push(sheet); - continue; - } - - const { sheetsMap, danglingDataMap } = processSheetData(sheetData, hierarchyLevelIndex); - - // Combine danglingDataMap with sheetsMap - for (const key of Object.keys(danglingDataMap)) { - if (sheetsMap[key]) { - sheetsMap[key].data = [sheetData[0], ...danglingDataMap[key], ...sheetsMap[key].data.slice(1)]; - } else { - sheetsMap[key] = { - sheetName: key, - data: [...danglingDataMap[key], sheetData[0]], - }; - } - } - - // Add sheetsMap values to result - result.push(...Object.values(sheetsMap)); - } - - return result.length > 0 ? result : xlsxData; // Return result or original data if result is empty -}; - -// Function to process sheet data and return sheetsMap and danglingDataMap -const processSheetData = (sheetData, hierarchyLevelIndex) => { - const sheetsMap = {}; - const danglingDataMap = {}; - let emptyHierarchyRow = []; - let lastWasEmpty = true; - - // Iterate through sheet data starting from the second row (skipping header) - for (let i = 1; i < sheetData.length; i++) { - const row = sheetData[i]; - const hierarchyValue = row[hierarchyLevelIndex]; - - if (emptyHierarchyRow.length && hierarchyValue !== "") { - danglingDataMap[hierarchyValue] = emptyHierarchyRow; - } - - if (hierarchyValue === "" && lastWasEmpty) { - emptyHierarchyRow.push(row); - } else { - emptyHierarchyRow = []; - } - - if (!sheetsMap[hierarchyValue] && hierarchyValue !== "") { - sheetsMap[hierarchyValue] = { - sheetName: hierarchyValue, - data: [sheetData[0]], - }; - } - - if (hierarchyValue === row[hierarchyLevelIndex] && hierarchyValue !== "") { - sheetsMap[hierarchyValue].data.push(row); - } - - lastWasEmpty = hierarchyValue === ""; - } - - return { sheetsMap, danglingDataMap }; -}; - -export const filterBoundaries = (boundaryData, boundaryFilters) => { - if (!boundaryFilters) return boundaryData; - // Define a helper function to recursively filter boundaries - function filterRecursive(boundary) { - // Find the filter that matches the current boundary - const filter = boundaryFilters?.find((f) => f.code === boundary.code && f.type === boundary.boundaryType); - - // If no filter is found, return the boundary with its children filtered recursively - if (!filter) { - return { - ...boundary, - children: boundary.children.map(filterRecursive), - }; - } - - // If the boundary has no children, handle the case where includeAllChildren is false - if (!boundary.children.length) { - // Return the boundary with an empty children array - return { - ...boundary, - children: [], - }; - } - - // If includeAllChildren is true, return the boundary with all children - if (filter.includeAllChildren) { - return { - ...boundary, - children: boundary.children.map(filterRecursive), - }; - } - - // Filter children based on the filters - const filteredChildren = boundary.children - .filter((child) => boundaryFilters.some((f) => f.code === child.code && f.type === child.boundaryType)) - .map(filterRecursive); - - // Return the boundary with filtered children - return { - ...boundary, - children: filteredChildren, - }; - } - - // Map through the boundary data and apply the recursive filter function to each boundary - const filteredData = boundaryData.map(filterRecursive); - return filteredData; -}; - -/** - * Retrieves all facilities for a given tenant ID. - * @param tenantId The ID of the tenant. - * @returns An array of facilities. - */ -async function getAllFacilities(tenantId) { - // Retrieve all facilities for the given tenant ID - const facilitySearchBody = { - Facility: { isPermanent: true }, - }; - - const facilitySearchParams = { - limit: 50, - offset: 0, - tenantId: tenantId, - }; - - const searchedFacilities = []; - let searchAgain = true; - - while (searchAgain) { - const response = await getFacilities(facilitySearchParams, facilitySearchBody); - if (response) { - searchAgain = response.length >= 50; - searchedFacilities.push(...response); - facilitySearchParams.offset += 50; - } else searchAgain = false; - } - - return searchedFacilities; -} - -const addFacilitySheet = (xlsxData, mapping, facilities, schema, t) => { - if (!mapping) return xlsxData; - // Create header row - const headers = Object.keys(mapping); - - // Create data rows - const dataRow = []; - for (const facility of facilities) { - facility.isPermanent = facility.isPermanent ? t("PERMAENENT") : t("TEMPORARY"); - dataRow.push(headers.map((header) => facility[mapping[header]])); - } - headers.push(commonColumn); - const additionalCols = []; - if (schema?.schema?.Properties) { - const properties = Object.keys(schema.schema.Properties); - for (const col of properties) { - if (!headers.includes(col)) { - additionalCols.push(col); - } - } - } - headers.push(...additionalCols); - // Combine headers and data rows - const arrayOfArrays = [headers.map((item) => generateLocalisationKeyForSchemaProperties(item)), ...dataRow]; - - const facilitySheet = { - sheetName: FACILITY_DATA_SHEET, - data: arrayOfArrays, - }; - const updatedXlsxData = [facilitySheet, ...xlsxData]; - return updatedXlsxData; -}; - -const addReadMeSheet = (xlsxData, readMeData, readMeSheetName) => { - if (!readMeSheetName) return xlsxData; - const data = readMeData.reduce((acc, item) => { - if (item?.header) { - acc.push([item.header], ...(item.points || []).map((item) => [item]), [], [], [], []); - } - return acc; - }, []); - - const readMeSheet = { - sheetName: readMeSheetName, - data: [["MICROPLAN_TEMPLATE_README_MAIN_HEADER"], [], [], [], ...data], - }; - xlsxData.unshift(readMeSheet); - return xlsxData; -}; - -/** - * @param {Object} options - * @param {boolean} options.hierarchyLevelWiseSheets - * @param {string} options.hierarchyLevelName - * @param {boolean} options.addFacilityData - * @param {Object} options.schema - * @param {Object[]} options.boundaries - * @param {string} options.tenantId - * @param {string} options.hierarchyType - * @param {Object} options.readMeData - * @param {string} options.readMeSheetName - * @param {string} options.t // Assuming t is some context or translation object - */ -export const createTemplate = async ({ - hierarchyLevelWiseSheets = true, - hierarchyLevelName, - addFacilityData = false, - schema, - boundaries, - tenantId, - hierarchyType, - readMeData, - readMeSheetName, - t, -}) => { - // Fetch or retrieve boundary data - const filteredBoundaries = await fetchFilteredBoundaries(boundaries, tenantId, hierarchyType); - - // Initialize xlsxData array - let xlsxData = []; - - // Add boundary data to xlsxData - xlsxData = addBoundaryData(xlsxData, filteredBoundaries, hierarchyType); - - // Handle hierarchy level sheets - if (hierarchyLevelWiseSheets) { - xlsxData = devideXlsxDataHierarchyLevelWise(xlsxData, hierarchyLevelName); - } - - // Handle facility data addition - if (addFacilityData) { - xlsxData = await addFacilityDataToSheets(xlsxData, schema, tenantId, t); - } else { - // If no facility data, add schema data directly - xlsxData = addSchemaData(xlsxData, schema); - } - - // Add readme sheet data if provided - xlsxData = addReadMeSheet(xlsxData, readMeData, readMeSheetName); - - return xlsxData; -}; - -// Function to fetch filtered boundaries -const fetchFilteredBoundaries = async (boundaries, tenantId, hierarchyType) => { - const rootBoundary = boundaries?.find((boundary) => boundary.isRoot); - const sessionData = Digit.SessionStorage.get("microplanHelperData") || {}; - let boundaryData = sessionData.filteredBoundaries; - - if (!boundaryData) { - boundaryData = await fetchBoundaryData(tenantId, hierarchyType, rootBoundary?.code); - const filteredBoundaries = await filterBoundaries(boundaryData, boundaries); - Digit.SessionStorage.set("microplanHelperData", { - ...sessionData, - filteredBoundaries: filteredBoundaries, - }); - return filteredBoundaries; - } - return boundaryData; -}; - -// Function to add facility data to sheets -const addFacilityDataToSheets = async (xlsxData, schema, tenantId, t) => { - const facilities = await getAllFacilities(tenantId); - if (schema?.template?.facilitySchemaApiMapping) { - return addFacilitySheet(xlsxData, schema.template.facilitySchemaApiMapping, facilities, schema, t); - } - // If no specific facility schema mapping, add default facility data - const facilitySheet = { - sheetName: FACILITY_DATA_SHEET, - data: [], - }; - return addSchemaData([facilitySheet], schema); -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js deleted file mode 100644 index b50b2ad48a6..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelUtils.js +++ /dev/null @@ -1,150 +0,0 @@ -import { SHEET_PASSWORD, UNPROTECT_TILL_ROW } from "../configs/constants"; - -export function updateFontNameToRoboto(worksheet) { - worksheet.eachRow({ includeEmpty: true }, (row) => { - row.eachCell({ includeEmpty: true }, (cell) => { - // Preserve existing font properties - const existingFont = cell.font || {}; - - // Update only the font name to Roboto - cell.font = { - ...existingFont, // Spread existing properties - name: "Roboto", // Update the font name - }; - }); - }); -} - -export const freezeWorkbookValues = async (workbook) => { - workbook.eachSheet((worksheet) => { - worksheet.eachRow((row) => { - row.eachCell((cell) => { - // Lock each cell - cell.protection = { - locked: true, - }; - }); - }); - // Protect the worksheet - worksheet.protect(SHEET_PASSWORD, { - selectLockedCells: true, - selectUnlockedCells: true, - }); - }); - - return workbook; -}; - -export const unfreezeColumnsByHeader = async (workbook, headers) => { - workbook.eachSheet((worksheet) => { - const headerRow = worksheet.getRow(1); // Assuming headers are in the first row - const columnsToUnfreeze = []; - - headerRow.eachCell((cell, colNumber) => { - if (headers.includes(cell.value)) { - columnsToUnfreeze.push(colNumber); - } - }); - - worksheet.eachRow((row, rowNumber) => { - if (rowNumber === 1) return; - columnsToUnfreeze.forEach((colNumber) => { - const cell = row.getCell(colNumber); - cell.protection = { - locked: false, - }; - }); - }); - - // Re-protect the worksheet after modifying cell protection - worksheet.protect(SHEET_PASSWORD, { - selectLockedCells: true, - selectUnlockedCells: true, - }); - }); - - return workbook; -}; - -export const freezeSheetValues = async (workbook, sheetName) => { - const worksheet = workbook.getWorksheet(sheetName); - if (worksheet) { - worksheet.eachRow((row) => { - row.eachCell((cell) => { - // Lock each cell - cell.protection = { - locked: true, - }; - }); - }); - // Protect the worksheet - worksheet.protect(SHEET_PASSWORD, { - selectLockedCells: true, - selectUnlockedCells: true, - }); - } - - return workbook; -}; - -export const freezeCellsWithData = async (workbook, sheetName) => { - const worksheet = workbook.getWorksheet(sheetName); - if (worksheet) { - worksheet.eachRow((row) => { - row.eachCell((cell) => { - if (cell.value) { - // Check if the cell has data - cell.protection = { - locked: true, - }; - } else { - cell.protection = { - locked: false, - }; - } - }); - }); - // Protect the worksheet - worksheet.protect(SHEET_PASSWORD, { - selectLockedCells: true, - selectUnlockedCells: true, - }); - } - - return workbook; -}; -export const performUnfreezeCells = async (workbook, sheetName) => { - const sheet = workbook.getWorksheet(sheetName); - - let lastFilledColumn = 1; - sheet.getRow(1).eachCell((cell, colNumber) => { - if (cell.value !== undefined && cell.value !== null && cell.value !== "") { - lastFilledColumn = colNumber; - } - }); - - for (let row = 1; row <= parseInt(UNPROTECT_TILL_ROW); row++) { - for (let col = 1; col <= lastFilledColumn; col++) { - const cell = sheet.getCell(row, col); - if (!cell.value && cell.value !== 0) { - cell.protection = { locked: false }; - } - } - } - sheet.protect(SHEET_PASSWORD, { selectLockedCells: true, selectUnlockedCells: true }); -}; - -export const hideUniqueIdentifierColumn = async (workbook, sheetName, column) => { - const sheet = workbook.getWorksheet(sheetName); - for (const item of column) { - let colIndex; - sheet.getRow(1).eachCell((cell, colNumber) => { - if (cell.value === item) { - colIndex = colNumber; - } - }); - if (column && sheet.getColumn(colIndex)) { - sheet.getColumn(colIndex).hidden = true; - } - } -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js deleted file mode 100644 index 0d2a344a8f1..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/excelValidations.js +++ /dev/null @@ -1,199 +0,0 @@ -import Ajv from "ajv"; -const ajv = new Ajv({ allErrors: true }); -ajv.addKeyword("isRequired"); -ajv.addKeyword("isLocationDataColumns"); -ajv.addKeyword("isRuleConfigureInputs"); -ajv.addKeyword("isFilterPropertyOfMapSection"); -ajv.addKeyword("isVisualizationPropertyOfMapSection"); -ajv.addKeyword("toShowInMicroplanPreview"); - -// Function responsible for excel data validation with respect to the template/schema provided -const translateSchema = (schemaData) => { - const required = Object.entries(schemaData?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.isRequired) { - acc.push(key); - } - return acc; - }, []); - - return { required, properties: schemaData.Properties }; -}; - -const createSchema = (properties, required) => { - return { - type: "object", - patternProperties: { - ".*": { - type: "array", - items: { - type: "object", - properties: properties, - required: required, - additionalProperties: true, - }, - }, - }, - minProperties: 1, - additionalProperties: false, - }; -}; - -const extractLocationDataColumns = (schemaData) => { - return Object.entries(schemaData?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.isLocationDataColumns) { - acc.push(key); - } - return acc; - }, []); -}; - -const setNestedError = (errors, path, error) => { - if (!path.length) return; - - let current = errors; - for (let i = 0; i < path.length - 1; i++) { - if (!current[path[i]]) { - current[path[i]] = {}; - } - current = current[path[i]]; - } - - if (!current[path[path.length - 1]]) { - current[path[path.length - 1]] = []; - } - - current[path[path.length - 1]] = [...new Set([...current[path[path.length - 1]], error])]; -}; - -const formatErrors = (validateExcelErrors, locationDataColumns, t) => { - const errors = {}; - let hasDataErrors = "false"; // true, false, missing_properties, unknown - const missingColumnsList = new Set(); - let errorMessages = {}; - - validateExcelErrors.forEach((error) => { - let tempErrorStore = ""; - let instancePathTypeGlobal; - - switch (error.keyword) { - case "additionalProperties": - tempErrorStore = "ERROR_ADDITIONAL_PROPERTIES"; - hasDataErrors = "true"; - break; - case "type": - { - const instancePathType = error.instancePath.split("/"); - const neededType = error.params?.type; - instancePathTypeGlobal = instancePathType; - tempErrorStore = locationDataColumns.includes(instancePathType[instancePathType.length - 1]) - ? "ERROR_INCORRECT_LOCATION_COORDINATES" - : neededType === "number" - ? "ERROR_MUST_BE_A_NUMBER" - : "ERROR_MUST_BE_A_STRING"; - hasDataErrors = "true"; - } - break; - case "required": - { - const missing = error.params.missingProperty; - const instancePathType = error.instancePath.split("/"); - instancePathTypeGlobal = [...instancePathType, missing]; - tempErrorStore = "ERROR_MANDATORY_FIELDS_CANT_BE_EMPTY"; - missingColumnsList.add(missing); - hasDataErrors = "true"; - } - break; - case "maximum": - case "minimum": - { - const instancePathMinMax = error.instancePath.split("/"); - instancePathTypeGlobal = instancePathMinMax; - tempErrorStore = locationDataColumns.includes(instancePathMinMax[instancePathTypeGlobal.length - 1]) - ? "ERROR_INCORRECT_LOCATION_COORDINATES" - : "ERROR_DATA_EXCEEDS_LIMIT_CONSTRAINTS"; - hasDataErrors = "true"; - } - break; - case "pattern": - tempErrorStore = "ERROR_VALUE_NOT_ALLOWED"; - hasDataErrors = "true"; - break; - case "minProperties": - hasDataErrors = "minProperties"; - break; - case "enum": - { - const instancePathType = error.instancePath.split("/"); - instancePathTypeGlobal = instancePathType; - tempErrorStore = { - error: "ERROR_UPLOAD_DATA_ENUM", - values: { allowedValues: error.params?.allowedValues?.map((item) => t(item)).join(", ") }, - }; - hasDataErrors = "true"; - } - break; - default: - hasDataErrors = "unknown"; - } - - if (tempErrorStore && instancePathTypeGlobal) { - setNestedError(errors, instancePathTypeGlobal.slice(1, 4), tempErrorStore); - } - - switch (hasDataErrors) { - case "true": - errorMessages = { dataError: "ERROR_REFER_UPLOAD_PREVIEW_TO_SEE_THE_ERRORS" }; - break; - case "minProperties": - errorMessages = { minProperties: "ERROR_UPLOADED_DATA_IS_EMPTY" }; - break; - case "unknown": - errorMessages = { unknown: "ERROR_UNKNOWN" }; - break; - case "false": - break; - } - }); - - return { - valid: !hasDataErrors, - message: errorMessages ? [...new Set(Object.values(errorMessages))] : [], - errors, - missingColumnsList, - }; -}; - -export const excelValidations = (data, schemaData, t) => { - const { required, properties } = translateSchema(schemaData); - const schema = createSchema(properties, required); - const validateExcel = ajv.compile(schema); - const valid = validateExcel(data); - const locationDataColumns = extractLocationDataColumns(schemaData); - - if (!valid) { - const validationResult = formatErrors(validateExcel.errors, locationDataColumns, t); - ajv.removeSchema(); - return validationResult; - } - - ajv.removeSchema(); - return { valid }; -}; - -export const checkForErrorInUploadedFileExcel = async (fileInJson, schemaData, t) => { - try { - const valid = excelValidations(fileInJson, schemaData, t); - if (valid.valid) { - return { valid: true }; - } - return { - valid: false, - message: valid.message, - errors: valid.errors, - missingProperties: valid.missingColumnsList, - }; - } catch (error) { - console.error("Error in excel validations: ", error?.message); - return { valid: false, message: ["ERROR_PARSING_FILE"] }; - } -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js deleted file mode 100644 index f2d4f277ba6..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/exceltojson.js +++ /dev/null @@ -1,99 +0,0 @@ -import ExcelJS from "exceljs"; - -// input is a xlsx blob -// options {header} -// header: true -> have seperate header so data will be in key: value pair -export const parseXlsxToJsonMultipleSheets = async (file, options = {}) => { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - - reader.onload = async (event) => { - try { - const arrayBuffer = event.target.result; - const workbook = await loadWorkbook(arrayBuffer); - const jsonData = processWorkbook(workbook, options); - resolve(jsonData); - } catch (error) { - console.error(error); - resolve({ error: true }); - } - }; - - reader.onerror = (error) => { - console.error(error); - resolve({ error: true, details: error }); - }; - - reader.readAsArrayBuffer(file); - }); -}; - -const loadWorkbook = async (arrayBuffer) => { - const workbook = new ExcelJS.Workbook(); - await workbook.xlsx.load(arrayBuffer); - return workbook; -}; - -const processWorkbook = (workbook, options) => { - const jsonData = {}; - workbook.eachSheet((worksheet) => { - const jsonSheetData = processSheet(worksheet, options); - if (jsonSheetData.length !== 0 && jsonSheetData?.[0].length !== 0) { - jsonData[worksheet.name] = jsonSheetData; - } - }); - return jsonData; -}; - -const processSheet = (worksheet, options) => { - const jsonSheetData = []; - let headers = []; - - worksheet.eachRow({ includeEmpty: true }, (row, rowNumber) => { - const rowData = cleanRowData(row.values); - if (options.header && rowNumber === 1) { - headers = rowData; - } else if (options.header && headers.length > 0) { - jsonSheetData.push(mapRowToHeaders(rowData, headers)); - } else { - jsonSheetData.push(rowData); - } - }); - - removeTrailingEmptyRows(jsonSheetData); - return jsonSheetData; -}; - -const cleanRowData = (rowData) => { - return rowData.slice(1).map((cell) => (typeof cell === "string" ? cell.trim() : cell)); -}; - -const mapRowToHeaders = (rowData, headers) => { - const rowObject = {}; - headers.forEach((header, index) => { - rowObject[header] = rowData[index]; - }); - return rowObject; -}; - -const removeTrailingEmptyRows = (data) => { - while (data.length > 0) { - const lastRow = data[data.length - 1]; - const isEmptyRow = checkIfRowIsEmpty(lastRow); - if (isEmptyRow) { - data.pop(); - } else { - break; - } - } -}; - -const checkIfRowIsEmpty = (row) => { - if (Array.isArray(row)) { - return row.filter((item) => item !== "").length === 0; - } - if (typeof row === "object" && row !== null) { - return Object.values(row).filter((item) => item !== "").length === 0; - } - return false; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js deleted file mode 100644 index 42a465740b5..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/geojsonValidations.js +++ /dev/null @@ -1,234 +0,0 @@ -import gjv from "geojson-validation"; -import Ajv from "ajv"; -const ajv = new Ajv({ allErrors: true }); -ajv.addKeyword("isRequired"); -ajv.addKeyword("isLocationDataColumns"); -ajv.addKeyword("isRuleConfigureInputs"); -ajv.addKeyword("isFilterPropertyOfMapSection"); -ajv.addKeyword("isVisualizationPropertyOfMapSection"); -ajv.addKeyword("toShowInMicroplanPreview"); - -//the postion must be valid point on the earth, x between -180 and 180 -gjv.define("Position", (position) => { - let errors = []; - if (position[0] < -180 || position[0] > 180) { - errors.push("Location Coordinates Error: the x must be between -180 and 180"); - } - if (position[1] < -90 || position[1] > 90) { - errors.push("Location Coordinates Error: the y must be between -90 and 90"); - } - return errors; -}); - -// Main functino for geojson validation that includes structural and property validations -export const geojsonValidations = (data, schemaData, t) => { - const valid = geojsonStructureValidation(data); - return valid.valid ? { valid: true } : { valid: false, message: valid.message || ["ERROR_INVALID_GEOJSON"] }; -}; - -// Funciton responsible for structural verification of geojson data -export const geojsonStructureValidation = (data) => { - let valid = true; - const trace = {}; - for (let i = 0; i < data["features"].length; i++) { - const check = gjv.valid(data["features"][i]); - valid = valid && check; - const errors = gjv.isFeature(data["features"][i], true); - // check if the location coordinates are according to the provided guidlines - if (errors.some((str) => str.includes("Location Coordinates Error:"))) return { valid: false, message: ["ERROR_INCORRECT_LOCATION_COORDINATES"] }; - if (!check) trace[i] = [errors]; - // let error; - // Object.keys(data["features"][i]["properties"]).forEach((j) => { - // if (j.length > 10) error = { valid: false, trace, message: ["ERROR_FIELD_NAME"] }; - // return j; - // }); - // if (error) return error; - } - return { valid, trace }; -}; - -const geometryValidation = (data) => { - let firstType; - for (const feature of data.features) { - if (!feature.geometry || !feature.geometry.type) { - return false; // Missing geometry or geometry type - } - if (!firstType) { - firstType = feature.geometry.type; - } else { - // Check if the current geometry type matches the first one - if (feature.geometry.type !== firstType) { - return false; // Different geometry types found - } - } - } - return true; -}; - -// Function responsible for property verification of geojson data -export const geojsonPropertiesValidation = (data, schemaData, name, t) => { - const translate = () => { - const required = Object.entries(schemaData?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.isRequired) { - acc.push(key); - } - return acc; - }, []); - - // const properties = prepareProperties(schemaData.Properties, t); - return { required, properties: schemaData.Properties }; - }; - const { required, properties } = translate(); - const schema = { - type: "object", - properties: { - type: { const: "FeatureCollection" }, - }, - patternProperties: { - "^features$": { - type: "array", - items: { - type: "object", - patternProperties: { - "^properties$": { - type: "object", - patternProperties: properties, - required: required, - additionalProperties: true, - }, - }, - }, - }, - }, - additionalProperties: true, - }; - const validateGeojson = ajv.compile(schema); - const valid = validateGeojson(data); - const errors = {}; - let hasDataErrors = "false"; // true, false, missing_properties, unknown - const missingColumnsList = new Set(); - let errorMessages = []; - if (!valid) { - for (let i = 0; i < validateGeojson.errors.length; i++) { - let tempErrorStore = ""; - let instancePathTypeGlobal = validateGeojson.errors[i].instancePath.split("/"); - switch (validateGeojson.errors[i].keyword) { - case "additionalProperties": { - tempErrorStore = "ERROR_ADDITIONAL_PROPERTIES"; - hasDataErrors = "true"; - break; - } - case "type": - { - const instancePathType = validateGeojson.errors[i].instancePath.split("/"); - const neededType = validateGeojson.errors[i].params?.type; - instancePathTypeGlobal = instancePathType; - tempErrorStore = neededType === "number" ? "ERROR_MUST_BE_A_NUMBER" : "ERROR_MUST_BE_A_STRING"; - hasDataErrors = "true"; - } - break; - case "const": { - if (validateGeojson.errors[i].params.allowedValue === "FeatureCollection") tempErrorStore = "ERROR_FEATURECOLLECTION"; - hasDataErrors = "true"; - break; - } - case "required": { - const missing = validateGeojson.errors[i].params.missingProperty; - const instancePathType = validateGeojson.errors[i].instancePath.split("/"); - instancePathTypeGlobal = [...instancePathType, missing]; - tempErrorStore = "ERROR_MANDATORY_FIELDS_CANT_BE_EMPTY"; - missingColumnsList.add(missing); - // hasDataErrors = "missing_properties"; - hasDataErrors = "true"; - break; - } - case "pattern": - tempErrorStore = "ERROR_VALUE_NOT_ALLOWED"; - hasDataErrors = "true"; - break; - case "minProperties": { - hasDataErrors = "minProperties"; - break; - } - case "enum": { - const instancePathType = validateGeojson.errors[i].instancePath.split("/"); - instancePathTypeGlobal = instancePathType; - tempErrorStore = { - error: "ERROR_UPLOAD_DATA_ENUM", - values: { allowedValues: validateGeojson.errors[i]?.params?.allowedValues?.map((item) => t(item)).join(", ") }, - }; - hasDataErrors = "true"; - break; - } - default: - hasDataErrors = "unknown"; - break; - } - if (tempErrorStore) - errors[name] = { - ...(errors[name] ? errors[name] : {}), - [instancePathTypeGlobal[2]]: { - ...(errors?.[name]?.[instancePathTypeGlobal[2]] ? errors?.[name]?.[instancePathTypeGlobal[2]] : {}), - [instancePathTypeGlobal[4]]: [ - ...new Set( - ...(errors?.[name]?.[instancePathTypeGlobal[2]]?.[instancePathTypeGlobal[4]] - ? errors?.[name]?.[instancePathTypeGlobal[2]]?.[instancePathTypeGlobal[4]] - : []) - ), - tempErrorStore, - ], - }, - }; - - switch (hasDataErrors) { - case "true": - errorMessages = { ...errorMessages, dataError: t("ERROR_REFER_UPLOAD_PREVIEW_TO_SEE_THE_ERRORS") }; - break; - case "unknown": - errorMessages = { ...errorMessages, unkown: t("ERROR_UNKNOWN") }; - break; - case "missing_properties": - errorMessages = { - ...errorMessages, - missingProperty: t("ERROR_MISSING_PROPERTY", { properties: [...missingColumnsList].map((item) => t(item)).join(", ") }), - }; - break; - case "false": - break; - } - } - - ajv.removeSchema(); - return { - valid: !hasDataErrors, - message: errorMessages ? [...new Set(Object.values(errorMessages))] : [], - errors, - validationError: validateGeojson.errors, - }; - } - ajv.removeSchema(); - if (!geometryValidation(data)) return { valid: false, message: t("ERROR_MULTIPLE_GEOMETRY_TYPES") }; - return { valid: true }; -}; - -//////////////////////////// -// // Might be needed -// function filterOutWordAndLocalise(inputString, operation) { -// // Define a regular expression to match the string parts -// var regex = /(\w+)/g; // Matches one or more word characters - -// // Replace each match using the provided function -// var replacedString = inputString.replace(regex, function (match) { -// // Apply the function to each matched string part -// return operation(match); -// }); - -// return replacedString; -// } -// const prepareProperties = (properties, t) => { -// let newProperties = {}; -// Object.keys(properties).forEach((item) => (newProperties[filterOutWordAndLocalise(item, t)] = properties[item])); -// return newProperties; -// }; - -//////////////////////////// diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js deleted file mode 100644 index 0d21a93ca46..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/index.js +++ /dev/null @@ -1,478 +0,0 @@ -import _ from "lodash"; -import { findChildren, findParent } from "../utils/processHierarchyAndData"; -import { EXCEL, LOCALITY, commonColumn } from "../configs/constants"; - -const formatDates = (value, type) => { - let newValue = value; - if (type !== "EPOC" && (!newValue || Number.isNaN(Number(newValue)))) { - newValue = new Date(); - } - switch (type) { - case "date": - return new Date(newValue)?.toISOString?.()?.split?.("T")?.[0]; - case "datetime": - return new Date(newValue).toISOString(); - case "EPOC": - return String(new Date(newValue)?.getTime()); - } -}; - -// get schema for validation -const getSchema = (campaignType, type, section, schemas) => { - if (!campaignType || !type || !section || !schemas) return {}; - return schemas.find((schema) => { - if (!schema.campaignType) { - return schema.type === type && schema.section === section; - } - return schema.campaignType === campaignType && schema.type === type && schema.section === section; - }); -}; - -// Sorting 2 lists, The first list is a list of string and second one is list of Objects -const sortSecondListBasedOnFirstListOrder = (firstList, secondList) => { - if (!firstList) return []; - // Create a map to store the indices of elements in the first list - const indexMap = {}; - firstList.forEach((value, index) => { - indexMap[value] = index; - }); - - // Sort the second list based on the order of elements in the first list - secondList.sort((objecta, objectb) => { - // Get the mappedTo values of each object - const mappedToA = objecta.mappedTo; - const mappedToB = objectb.mappedTo; - - // Get the indices of mappedTo values in the first list - const indexA = indexMap[mappedToA]; - const indexB = indexMap[mappedToB]; - - // Compare the indices - return indexA - indexB; - }); - - return secondList; -}; - -const computeGeojsonWithMappedProperties = ({ campaignType, fileType, templateIdentifier, validationSchemas }) => { - const schemaData = getSchema(campaignType, fileType, templateIdentifier, validationSchemas); - let schemaKeys; - if (schemaData?.schema?.["Properties"]) schemaKeys = hierarchy.concat(Object.keys(schemaData.schema["Properties"])); - // Sorting the resourceMapping list inorder to maintain the column sequence - const sortedSecondList = sortSecondListBasedOnFirstListOrder(schemaKeys, resourceMapping); - // Creating a object with input data with MDMS keys - const newFeatures = fileData.data["features"].map((item) => { - const newProperties = sortedSecondList.reduce( - (acc, e) => ({ - ...acc, - [e["mappedTo"]]: item["properties"][e["mappedFrom"]], - }), - {} - ); - item["properties"] = newProperties; - return item; - }); - const data = fileData.data; - data["features"] = newFeatures; - return data; -}; - -const destroySessionHelper = (currentPath, pathList, sessionName) => { - if (!pathList.includes(currentPath)) { - sessionStorage.removeItem(`Digit.${sessionName}`); - } -}; - -const convertGeojsonToExcelSingleSheet = (InputData, fileName) => { - if (!InputData || !Array.isArray(InputData) || InputData.length === 0) { - return null; - } - - // Extract keys from the first feature's properties - const keys = Object.keys(InputData?.[0]?.properties); - - if (!keys || keys.length === 0) { - return null; - } - - // Extract corresponding values for each feature - const values = InputData?.map((feature) => { - return keys.map((key) => feature.properties[key]); - }); - - // Group keys and values into the desired format - return { [fileName]: [keys, ...values] }; -}; - -const areObjectsEqual = (obj1, obj2) => { - return obj1.name === obj2.name && obj1.code === obj2.code; -}; - -const computeDifferences = (data1, data2) => { - const removed = {}; - const added = {}; - - for (const key in data1) { - if (Object.hasOwn(data2, key)) { - removed[key] = data1[key].filter((item1) => !data2[key].some((item2) => areObjectsEqual(item1, item2))); - added[key] = data2[key].filter((item2) => !data1[key].some((item1) => areObjectsEqual(item1, item2))); - } else { - removed[key] = data1[key]; - added[key] = []; - } - } - - for (const key in data2) { - if (!data1.hasOwnProperty(key)) { - added[key] = data2[key]; - removed[key] = []; - } - } - - return { removed, added }; -}; - -const extractNames = (data) => { - return Object.values(data) - .flatMap((items) => items) - .filter((item) => item.name) - .map((item) => item.name); -}; -// function that handles dropdown selection. used in: mapping and microplan preview -const handleSelection = (e, boundaryType, boundarySelections, hierarchy, setBoundarySelections, boundaryData, setIsLoading) => { - setIsLoading(true); - if (!e || !boundaryType) return; - const selections = e.map((item) => item?.[1]); - const newComputedSelection = { ...boundarySelections, [boundaryType]: selections }; - const { removed, added } = computeDifferences(boundarySelections, newComputedSelection); - // for(const item in removed){ - if (removed && Object.keys(removed).length !== 0 && Object.values(removed)?.flatMap((item) => item).length !== 0) { - const filteredRemoved = extractNames(removed); - const children = Object.values(findChildren(filteredRemoved, Object.values(boundaryData)?.[0]?.hierarchicalData))?.map((item) => item?.name); - for (const key in newComputedSelection) { - newComputedSelection[key] = newComputedSelection[key].filter((item) => !children.includes(item?.name)); - } - } - setBoundarySelections(newComputedSelection); -}; - -// Preventing default action when we scroll on input[number] is that it increments or decrements the number -const inputScrollPrevention = (e) => { - e.target.addEventListener("wheel", (e) => e.preventDefault(), { passive: false }); -}; - -const mapDataForApi = (data, Operators, microplanName, campaignId, status, reqType = "update") => { - const files = extractFiles(data, reqType); - const resourceMapping = extractResourceMapping(data, reqType); - const assumptions = extractAssumptions(data, reqType); - const operations = extractOperations(data, Operators, reqType); - - return createApiRequestBody(status, microplanName, campaignId, files, assumptions, operations, resourceMapping); -}; - -const extractFiles = (data, reqType) => { - const files = []; - if (data && data.upload) { - Object.values(data.upload).forEach((item) => { - if (isValidFile(item, reqType)) { - files.push(mapFile(item)); - } - }); - } - return files; -}; - -const isValidFile = (item, reqType) => { - if (!item || item.error || !item.filestoreId) return false; - if (reqType === "create" && !item.active) return false; - return true; -}; - -const mapFile = (item) => ({ - active: item.active, - filestoreId: item.filestoreId, - inputFileType: item.fileType, - templateIdentifier: item.section, - id: item.fileId, -}); - -const extractResourceMapping = (data, reqType) => { - let resourceMapping = []; - if (data && data.upload) { - Object.values(data.upload).forEach((item) => { - if (isValidResourceMapping(item, reqType)) { - resourceMapping.push(item.resourceMapping); - } - }); - resourceMapping = resourceMapping.flat(); - } - return resourceMapping; -}; - -const isValidResourceMapping = (item, reqType) => { - if (reqType === "create" && item.resourceMapping && item.resourceMapping.every((i) => i.active === false)) return false; - if (!item || !item.resourceMapping || item.error || !Array.isArray(item.resourceMapping)) return false; - if (!item.resourceMapping.every((i) => i.mappedFrom && i.mappedTo)) return false; - return true; -}; - -const extractAssumptions = (data, reqType) => { - if (!data || !data.hypothesis) return []; - return data.hypothesis.reduce((acc, item) => { - if (isValidAssumption(item, reqType)) { - acc.push({ ...item }); - } - return acc; - }, []); -}; - -const isValidAssumption = (item, reqType) => { - if (reqType === "create" && !item.active) return false; - if (!item.key || !item.value) return false; - return true; -}; - -const extractOperations = (data, Operators, reqType) => { - if (!data || !data.ruleEngine) return []; - return data.ruleEngine.reduce((acc, item) => { - if (isValidOperation(item, reqType)) { - acc.push(mapOperation(item, Operators)); - } - return acc; - }, []); -}; - -const isValidOperation = (item, reqType) => { - if (reqType === "create" && !item.active) return false; - if (!item.active && !item.input) return true; - if (!item.active && !item.operator && !item.output && !item.input && !item.assumptionValue) return false; - return true; -}; - -const mapOperation = (item, Operators) => { - const data = { ...item }; - const operator = Operators.find((e) => e.name === data.operator); - if (operator && operator.code) data.operator = operator.code; - if (data.oldInput) data.input = data.oldInput; - return data; -}; - -const createApiRequestBody = (status, microplanName, campaignId, files, assumptions, operations, resourceMapping) => ({ - PlanConfiguration: { - status, - tenantId: Digit.ULBService.getStateId(), - name: microplanName, - executionPlanId: campaignId, - files, - assumptions, - operations, - resourceMapping, - }, -}); - -const addResourcesToFilteredDataToShow = (previewData, resources, hypothesisAssumptionsList, formulaConfiguration, userEditedResources, t) => { - // Clone the preview data to avoid mutating the original data - const data = _.cloneDeep(previewData); - - // Helper function to check for user-edited data - const checkUserEditedData = (commonColumnData, resourceName) => { - if (userEditedResources && userEditedResources[commonColumnData]) { - return userEditedResources[commonColumnData][resourceName]; - } - }; - - // Ensure the previewData has at least one row and the first row is an array - if (!Array.isArray(data) || !Array.isArray(data[0])) { - return []; - } - - // Identify the index of the common column - const conmmonColumnIndex = data[0].indexOf(commonColumn); - if (conmmonColumnIndex === -1) { - return []; - } - - // Ensure resources is a valid array - if (!Array.isArray(resources)) { - return data; - } - - // Process each row of the data - const combinedData = data.map((item, index) => { - if (!Array.isArray(item)) { - return item; - } - - if (index === 0) { - // Add resource names to the header row - resources.forEach((e) => item.push(e)); - return item; - } - - // Process each resource for the current row - resources.forEach((resourceName, resourceIndex) => { - let savedData = checkUserEditedData(item[conmmonColumnIndex], resourceName); - if (savedData !== undefined) { - item.push(savedData); - } else { - let calculations = calculateResource(resourceName, item, formulaConfiguration, previewData[0], hypothesisAssumptionsList, t); - if (calculations !== null) calculations = Math.round(calculations); - item.push(calculations !== null && calculations !== undefined ? calculations : undefined); - } - }); - - return item; - }); - - return combinedData; -}; - -const calculateResource = (resourceName, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t) => { - let formula = formulaConfiguration?.find((item) => item?.active && item?.output === resourceName); - if (!formula) return null; - - // Finding Input - // check for Uploaded Data - const inputValue = findInputValue(formula, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t); - if (inputValue === undefined || inputValue === null) return null; - const assumptionValue = hypothesisAssumptionsList?.find((item) => item?.active && item?.key === formula?.assumptionValue)?.value; - if (assumptionValue === undefined) return null; - - return findResult(inputValue, assumptionValue, formula?.operator); -}; - -// function to find input value, it calls calculateResource fucntion recurcively until it get a proper value -const findInputValue = (formula, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t) => { - const inputIndex = headers?.indexOf(formula?.input); - if (inputIndex === -1 || !rowData[inputIndex]) { - // let tempFormula = formulaConfiguration.find((item) => item?.output === formula?.input); - return calculateResource(formula?.input, rowData, formulaConfiguration, headers, hypothesisAssumptionsList, t); - } else return rowData[inputIndex]; -}; - -const findResult = (inputValue, assumptionValue, operator) => { - switch (operator) { - case "DEVIDED_BY": - if (assumptionValue === 0) return; - return inputValue / assumptionValue; - case "MULTIPLIED_BY": - return inputValue * assumptionValue; - case "ADDITION": - return inputValue + assumptionValue; - case "SUBSTRACTION": - return inputValue - assumptionValue; - case "RAISE_TO": - return inputValue ** assumptionValue; - default: - return; - } -}; - -const fetchData = (state, campaignType) => { - let hypothesis = []; - let rulesOutputs = []; - let uploadList = []; - - hypothesis = state?.HypothesisAssumptions?.find((item) => item.campaignType === campaignType)?.assumptions; - rulesOutputs = state?.RuleConfigureOutput?.find((item) => item.campaignType === campaignType)?.data; - uploadList = state?.UploadConfiguration?.reduce((acc, item) => { - if (item.required) acc.push(item.id); - return acc; - }, []); - return { hypothesisList: hypothesis, rulesOutputs, uploadList }; -}; -const hypothesisCheck = (hypothesis, validList) => { - if (hypothesis && Array.isArray(hypothesis) && hypothesis.length !== 0 && validList && Array.isArray(validList) && validList.length !== 0) { - return hypothesis.filter((item) => item.active).every((item) => validList.includes(item.key)); - } - return false; -}; -const ruleOutputCheck = (rules, ruleOuputList) => { - if ( - rules && - Array.isArray(rules) && - rules.filter((item) => item.active).length !== 0 && - ruleOuputList && - Array.isArray(ruleOuputList) && - ruleOuputList.length !== 0 - ) { - return rules.filter((item) => item.active).every((item) => ruleOuputList.includes(item.output)); - } - return false; -}; -const emptyRuleCheck = (rules) => { - return !rules || rules.filter((item) => item.active && Object.values(item)?.filter((e) => e === "").length !== 0).length === 0; -}; -const ruleHypothesisCheck = (rules, ruleHypothesis) => { - if (rules && Array.isArray(rules) && rules.length !== 0 && ruleHypothesis && Array.isArray(ruleHypothesis) && ruleHypothesis.length !== 0) { - return rules.filter((item) => item.active).every((item) => ruleHypothesis.includes(item.assumptionValue)); - } - return false; -}; -const uploadCheck = (uploads, uploadList) => { - if (uploads && Array.isArray(uploads) && uploads.length !== 0 && uploadList && Array.isArray(uploadList) && uploadList.length !== 0) { - return uploads.some((item) => uploadList.includes(item.templateIdentifier) && item.active); - } - return false; -}; -const planConfigRequestBodyValidator = (data, state, campaignType) => { - if (!data || !campaignType || !state) return false; - - const { hypothesisList, rulesOutputs, uploadList } = fetchData(state, campaignType); - let checks = - // microplan name check - (!data || !data.name) && - hypothesisCheck(data?.PlanConfiguration?.assumptions, hypothesisList) && - emptyRuleCheck(data?.PlanConfiguration?.operations) && - ruleOutputCheck(data?.PlanConfiguration?.operations, rulesOutputs) && - ruleHypothesisCheck( - data?.PlanConfiguration?.operations, - data?.PlanConfiguration?.assumptions?.filter((item) => item.active)?.map((item) => item.key) - ) && - uploadCheck(data?.PlanConfiguration?.files, uploadList); - return checks; - // if() -}; - -const processDropdownForNestedMultiSelect = (dropDownOptions) => { - if (!dropDownOptions) return dropDownOptions; - const result = dropDownOptions.reduce((acc, item) => { - const { parent, ...rest } = item; - - // Find the group by parentBoundaryType - let group = acc.find((g) => g.name === parent?.name); - - // If not found, create a new group - if (!group) { - group = { name: parent?.name, options: [] }; - acc.push(group); - } - - // Add the item to the options of the found/created group - group.options.push(rest); - - return acc; - }, []); - return result; -}; - -const transformIntoLocalisationCode = (code) => { - return code?.toUpperCase(); -}; - -export default { - formatDates, - computeGeojsonWithMappedProperties, - destroySessionHelper, - mapDataForApi, - inputScrollPrevention, - handleSelection, - convertGeojsonToExcelSingleSheet, - sortSecondListBasedOnFirstListOrder, - addResourcesToFilteredDataToShow, - calculateResource, - planConfigRequestBodyValidator, - getSchema, - processDropdownForNestedMultiSelect, - transformIntoLocalisationCode, -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js deleted file mode 100644 index ae470038a91..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/jsonToExcelBlob.js +++ /dev/null @@ -1,72 +0,0 @@ -import ExcelJS from "exceljs"; -import { SHEET_COLUMN_WIDTH } from "../configs/constants"; - -export const convertJsonToXlsx = async (jsonData, columnWithStyle, returnWorkbook = false) => { - const workbook = new ExcelJS.Workbook(); - - for (const [sheetName, data] of Object.entries(jsonData)) { - const worksheet = workbook.addWorksheet(sheetName); - populateWorksheet(worksheet, data, columnWithStyle); - } - - if (returnWorkbook) return workbook; - return await writeWorkbookToBuffer(workbook); -}; - -const populateWorksheet = (worksheet, data, columnWithStyle) => { - data.forEach((row, rowIndex) => { - const newRow = worksheet.addRow(row); - if (columnWithStyle?.errorColumn && rowIndex > 0) { - applyStyleToColumn(newRow, data[0], columnWithStyle); - } - }); - - styleHeaderRow(worksheet); - setColumnWidths(worksheet); -}; - -/** - * Applies a specified style to a column in a given row of a spreadsheet. - * - * @param {Object} newRow - The row object where the style will be applied. - * @param {Array} headerRow - The header row array containing column names. - * @param {Object} columnWithStyle - An object containing the column name and the style to be applied. - * @param {string} columnWithStyle.errorColumn - The name of the column where the style should be applied. - * @param {Object} columnWithStyle.style - The style properties to be applied to the cell. - */ -const applyStyleToColumn = (newRow, headerRow, columnWithStyle) => { - const errorColumnIndex = headerRow.indexOf(columnWithStyle.errorColumn); - if (errorColumnIndex !== -1) { - const columnIndex = errorColumnIndex + 1; - const newCell = newRow.getCell(columnIndex); - if (columnWithStyle.style && newCell) { - for (const key in columnWithStyle.style) { - newCell[key] = columnWithStyle.style[key]; - } - } - } -}; - -const styleHeaderRow = (worksheet) => { - const headerRow = worksheet.getRow(1); - if (headerRow) { - headerRow.font = { bold: true }; - } -}; - -const setColumnWidths = (worksheet) => { - // Iterate over all rows in the worksheet - worksheet.eachRow((worksheetRow, rowNumber) => { - worksheetRow.eachCell((cell, colNumber) => { - // Update column width based on the length of the cell's text - const currentWidth = worksheet.getColumn(colNumber).width || SHEET_COLUMN_WIDTH; // Default width or current width - const newWidth = Math.max(currentWidth, cell.value.toString().length + 2); // Add padding - worksheet.getColumn(colNumber).width = newWidth; - }); - }); -}; - -export const writeWorkbookToBuffer = async (workbook) => { - const buffer = await workbook.xlsx.writeBuffer({ compression: true }); - return new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/mappingUtils.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/mappingUtils.js deleted file mode 100644 index f742ffd5e47..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/mappingUtils.js +++ /dev/null @@ -1,760 +0,0 @@ -import L from "leaflet"; -import "leaflet/dist/leaflet.css"; -import { processHierarchyAndData, findChildren, calculateAggregateForTree } from "../utils/processHierarchyAndData"; -import { EXCEL, GEOJSON, SHAPEFILE, MapChoroplethGradientColors } from "../configs/constants"; -import { PopulationSvg } from "../icons/Svg"; -import chroma from "chroma-js"; -import * as MicroplanIconCollection from "../icons/Svg"; -import * as DigitSvgs from "@egovernments/digit-ui-svg-components"; - -const IconCollection = { ...MicroplanIconCollection, ...DigitSvgs }; - -export const generatePreviewUrl = (baseMapUrl, center = [0, 0], zoom = 5) => { - const lon = Math.floor(((center[1] + 180) / 360) * Math.pow(0, zoom)); - const lat = Math.floor( - ((1 - Math.log(Math.tan((center[0] * Math.PI) / 180) + 1 / Math.cos((center[0] * Math.PI) / 180)) / Math.PI) / 2) * Math.pow(2, zoom) - ); - if (baseMapUrl) { - return baseMapUrl.replace("{z}", zoom).replace("{x}", lat).replace("{y}", lon); - } - // Return a default preview URL or handle this case as needed - return "default-preview-url.jpg"; // todo -}; - -// get schema for validation -export const getSchema = (campaignType, type, section, schemas) => { - return schemas.find((schema) => { - if (!schema.campaignType) { - return schema.type === type && schema.section === section; - } - return schema.campaignType === campaignType && schema.type === type && schema.section === section; - }); -}; - -export const calculateAggregateForTreeMicroplanWrapper = (entity) => { - if (!entity || typeof entity !== "object") return {}; - let newObject = {}; - for (let [key, value] of Object.entries(entity)) { - if (!value?.["hierarchicalData"]) continue; - let aggregatedTree = calculateAggregateForTree(value?.["hierarchicalData"]); - newObject[key] = { ...value, hierarchicalData: aggregatedTree }; - } - return newObject; -}; - -export const extractGeoData = ( - campaignType, - microplanData, - filterDataOrigin, - validationSchemas, - setToast, - setDataAvailability, - hierarchy, - setBoundaryData, - setFilterData, - setFilterProperties, - setFilterSelections, - setFilterPropertyNames, - state, - setChoroplethProperties, - setDataCompleteness, - t -) => { - if (!hierarchy) return; - - const initializeDataAvailability = (microplanData) => (microplanData?.upload ? "initialStage" : undefined); - - const checkFileActivity = (fileData) => fileData.active; - - const checkFileSection = (fileData, filterDataOrigin) => - filterDataOrigin?.boundriesDataOrigin?.includes(fileData?.section) || filterDataOrigin?.layerDataOrigin?.includes(fileData?.section); - - const getFileValidationSchema = (campaignType, fileData, validationSchemas) => - getSchema(campaignType, fileData?.fileType, fileData?.section, validationSchemas); - - const updateDataAvailabilityCheck = (dataAvailabilityCheck, condition, partialState) => - condition ? partialState : dataAvailabilityCheck === "initialStage" ? "false" : partialState; - - const handleFileDataError = (dataAvailabilityCheck, fileData) => - fileData?.error ? updateDataAvailabilityCheck(dataAvailabilityCheck, true, "partial") : dataAvailabilityCheck; - - const addResourcesToFilteredData = (data, resources, hypothesisAssumptionsList, formulaConfiguration, microplanData, t) => - Digit.Utils.microplan.addResourcesToFilteredDataToShow( - data, - resources, - hypothesisAssumptionsList, - formulaConfiguration, - microplanData?.microplanPreview?.userEditedResources || [], - t - ); - - const processFileData = ( - fileData, - schema, - filterDataOrigin, - virtualizationPropertiesCollector, - filterPropertiesCollector, - filterPropertieNameCollector, - resources, - hypothesisAssumptionsList, - formulaConfiguration, - t - ) => { - const properties = Object.entries(schema?.schema?.Properties || {}); - const latLngColumns = []; - const filterProperty = []; - - for (const [key, value] of properties) { - if (value?.isLocationDataColumns) latLngColumns.push(t(key)); - if (filterDataOrigin?.layerDataOrigin?.includes(fileData?.section) && value?.isFilterPropertyOfMapSection) filterProperty.push(key); - if (value?.isVisualizationPropertyOfMapSection && filterDataOrigin?.boundriesDataOrigin?.includes(fileData?.section)) - virtualizationPropertiesCollector.add(key); - } - - filterProperty.forEach((property) => filterPropertieNameCollector.add(property)); - - return { latLngColumns, filterProperty }; - }; - - const processExcelFile = (fileData, latLngColumns, resources, formulaConfiguration, hypothesisAssumptionsList, schema, t) => { - let dataAvailabilityCheck = "true"; - const columnList = Object.values(fileData?.data)?.[0]?.[0]; - const check = latLngColumns.every((colName) => columnList.includes(t(colName))); - - if (!check) dataAvailabilityCheck = "partial"; - - let dataWithResources = Object.values(fileData?.data); - if (resources && formulaConfiguration && hypothesisAssumptionsList && schema?.showResourcesInMappingSection) { - dataWithResources = dataWithResources.map((item) => - addResourcesToFilteredData(item, resources, hypothesisAssumptionsList, formulaConfiguration, microplanData, t) - ); - } - - const hasLocationData = dataWithResources.some((item) => item.some((row) => row.includes("lat") && row.includes("long"))); - - const convertedData = dataWithResources.map((item) => - item.map((row, rowIndex) => { - if (rowIndex === 0) { - if (row.indexOf("features") === -1) row.push("feature"); - return row; - } - const latIndex = item[0].findIndex((cell) => cell === "lat"); - const lonIndex = item[0].findIndex((cell) => cell === "long"); - const properties = item[0].reduce((acc, cell, index) => ({ ...acc, [cell]: row[index] }), {}); - const feature = - latIndex !== -1 && lonIndex !== -1 - ? { - type: "Feature", - properties, - geometry: { - type: "Point", - coordinates: [row[lonIndex], row[latIndex]], - }, - } - : null; - row.push(feature); - return row; - }) - ); - - return { dataAvailabilityCheck, hasLocationData, convertedData }; - }; - - const processGeoJsonFile = (fileData, filterProperty, resources, formulaConfiguration, hypothesisAssumptionsList, t) => { - const dataAvailabilityCheck = "true"; - const keys = [...Object.keys(fileData?.data.features[0].properties), "feature"]; - const values = fileData?.data.features.map((feature) => keys.map((key) => (key === "feature" ? feature : feature.properties[key] || null))); - - const dataWithResources = [[...keys, ...resources], ...values]; - const processedDataWithResources = dataWithResources.map((item, index) => { - if (index === 0) return item; - const newProperties = keys.reduce((acc, key, i) => (key !== "feature" ? { ...acc, [key]: item[i] } : acc), {}); - item[item.length - 1] = { ...item[item.length - 1], properties: newProperties }; - return item; - }); - - return { dataAvailabilityCheck, dataWithResources: processedDataWithResources }; - }; - - const updateFilterPropertiesCollector = (fileData, filterProperty, filterPropertiesCollector) => { - filterProperty.forEach((item) => { - Object.values(fileData?.data).forEach((data) => { - const filterPropertyIndex = data[0].indexOf(item); - if (filterPropertyIndex !== -1) data.slice(1).forEach((e) => filterPropertiesCollector.add(e[filterPropertyIndex])); - }); - }); - }; - - const setAvailabilityAndToastMessages = (dataAvailabilityCheck, combineList, files, setToast, t) => { - if (dataAvailabilityCheck === "true") { - const sectionWiseCheck = combineList.every((item) => Object.keys(files).includes(item)); - if (!sectionWiseCheck) dataAvailabilityCheck = "partial"; - } - - if (dataAvailabilityCheck === "initialStage" && (combineList.length === 0 || Object.keys(files).length === 0)) dataAvailabilityCheck = "false"; - - const toastMessages = { - false: { state: "warning", message: t("MAPPING_NO_DATA_TO_SHOW") }, - partial: { state: "warning", message: t("MAPPING_PARTIAL_DATA_TO_SHOW") }, - undefined: { state: "error", message: t("MAPPING_NO_DATA_TO_SHOW") }, - }; - - setToast(toastMessages[dataAvailabilityCheck]); - return dataAvailabilityCheck; - }; - - const setFinalDataAndProperties = ( - dataAvailabilityCheck, - setBoundary, - setFilter, - setBoundaryData, - setFilterData, - setFilterProperties, - setFilterSelections, - setFilterPropertyNames, - filterPropertiesCollector, - filterPropertieNameCollector, - virtualizationPropertiesCollector, - setChoroplethProperties, - resources - ) => { - setDataCompleteness(dataAvailabilityCheck); - setBoundary = calculateAggregateForTreeMicroplanWrapper(setBoundary); - setFilter = calculateAggregateForTreeMicroplanWrapper(setFilter); - setBoundaryData((previous) => ({ ...previous, ...setBoundary })); - setFilterData((previous) => ({ ...previous, ...setFilter })); - setFilterProperties([...filterPropertiesCollector]); - setFilterSelections([...filterPropertiesCollector]); - setFilterPropertyNames([...filterPropertieNameCollector]); - const tempVirtualizationPropertiesCollectorArray = [...virtualizationPropertiesCollector]; - if (tempVirtualizationPropertiesCollectorArray.length !== 0) - setChoroplethProperties([...tempVirtualizationPropertiesCollectorArray, ...(resources || [])]); - }; - - let setBoundary = {}; - let setFilter = {}; - const virtualizationPropertiesCollector = new Set(); - const filterPropertiesCollector = new Set(); - const filterPropertieNameCollector = new Set(); - const resources = state?.Resources?.find((item) => item.campaignType === campaignType)?.data; - const hypothesisAssumptionsList = microplanData?.hypothesis; - const formulaConfiguration = microplanData?.ruleEngine; - - let dataAvailabilityCheck = initializeDataAvailability(microplanData); - if (!dataAvailabilityCheck) return setToast({ state: "error", message: t("MAPPING_NO_DATA_TO_SHOW") }); - - const files = _.cloneDeep(microplanData.upload); - for (const fileData of files) { - if (!checkFileActivity(fileData) || !checkFileSection(fileData, filterDataOrigin)) { - dataAvailabilityCheck = "false"; - continue; - } - - if (!fileData?.fileType || !fileData?.section) continue; - - const schema = getFileValidationSchema(campaignType, fileData, validationSchemas); - dataAvailabilityCheck = handleFileDataError(dataAvailabilityCheck, fileData); - - const { latLngColumns, filterProperty } = processFileData( - fileData, - schema, - filterDataOrigin, - virtualizationPropertiesCollector, - filterPropertiesCollector, - filterPropertieNameCollector, - resources, - hypothesisAssumptionsList, - formulaConfiguration, - t - ); - - if (fileData?.data && Object.keys(fileData?.data).length > 0) { - switch (fileData?.fileType) { - case EXCEL: - const { dataAvailabilityCheck: excelDataAvailabilityCheck, hasLocationData, convertedData } = processExcelFile( - fileData, - latLngColumns, - resources, - formulaConfiguration, - hypothesisAssumptionsList, - schema, - t - ); - dataAvailabilityCheck = excelDataAvailabilityCheck; - if (hasLocationData) updateFilterPropertiesCollector(fileData, filterProperty, filterPropertiesCollector); - const { hierarchyLists: excelHierarchyLists, hierarchicalData: excelHierarchicalData } = processHierarchyAndData(hierarchy, convertedData); - if (filterDataOrigin?.boundriesDataOrigin?.includes(fileData.section)) - setBoundary = { ...setBoundary, [fileData.section]: { hierarchyLists: excelHierarchyLists, hierarchicalData: excelHierarchicalData } }; - else if (filterDataOrigin?.layerDataOrigin?.includes(fileData.section)) - setFilter = { ...setFilter, [fileData.section]: { hierarchyLists: excelHierarchyLists, hierarchicalData: excelHierarchicalData } }; - break; - case GEOJSON: - case SHAPEFILE: - const { dataAvailabilityCheck: geoJsonDataAvailabilityCheck, dataWithResources } = processGeoJsonFile( - fileData, - filterProperty, - resources, - formulaConfiguration, - hypothesisAssumptionsList, - t - ); - dataAvailabilityCheck = geoJsonDataAvailabilityCheck; - const { hierarchyLists: geoJsonHierarchyLists, hierarchicalData: geoJsonHierarchicalData } = processHierarchyAndData(hierarchy, [ - dataWithResources, - ]); - if (filterDataOrigin?.boundriesDataOrigin?.includes(fileData.section)) - setBoundary = { - ...setBoundary, - [fileData.section]: { hierarchyLists: geoJsonHierarchyLists, hierarchicalData: geoJsonHierarchicalData }, - }; - else if (filterDataOrigin?.layerDataOrigin?.includes(fileData.section)) - setFilter = { ...setFilter, [fileData.section]: { hierarchyLists: geoJsonHierarchyLists, hierarchicalData: geoJsonHierarchicalData } }; - break; - default: - break; - } - } - } - - const combineList = [...(filterDataOrigin?.boundriesDataOrigin || []), ...(filterDataOrigin?.layerDataOrigin || [])]; - dataAvailabilityCheck = setAvailabilityAndToastMessages(dataAvailabilityCheck, combineList, files, setToast, t); - - setFinalDataAndProperties( - dataAvailabilityCheck, - setBoundary, - setFilter, - setBoundaryData, - setFilterData, - setFilterProperties, - setFilterSelections, - setFilterPropertyNames, - filterPropertiesCollector, - filterPropertieNameCollector, - virtualizationPropertiesCollector, - setChoroplethProperties, - resources - ); -}; - -//prepare geojson to show on the map -export const prepareGeojson = (boundaryData, selection, style = {}) => { - if (!boundaryData || Object.keys(boundaryData).length === 0) return []; - let geojsonRawFeatures = []; - if (selection === "ALL") { - for (let data of Object.values(boundaryData)) { - const templist = fetchFeatures(data?.hierarchicalData, selection, [], style); - if (templist?.length !== 0) geojsonRawFeatures = [...geojsonRawFeatures, ...templist]; - } - } else if (Array.isArray(selection)) { - for (let data of Object.values(boundaryData)) { - const templist = fetchFeatures(data?.hierarchicalData, selection, [], style); - if (templist?.length !== 0) geojsonRawFeatures = [...geojsonRawFeatures, ...templist]; - } - } - - return geojsonRawFeatures.filter(Boolean); -}; -export const fetchFeatures = (data, parameter = "ALL", outputList = [], addOn = {}) => { - let tempStorage = []; - if (parameter === "ALL") { - // outputList(Object.values(data).flatMap(item=>item?.data?.feature)) - for (let [entityKey, entityValue] of Object.entries(data)) { - if (entityValue?.data?.feature) { - let feature = entityValue.data.feature; - feature.properties["name"] = entityKey; - feature.properties["addOn"] = addOn; - if (entityValue?.children) tempStorage = [...tempStorage, feature, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; - else tempStorage = [...tempStorage, feature]; - } else { - tempStorage = [...tempStorage, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; - } - } - return tempStorage; - } - if (Array.isArray(parameter)) { - for (let [entityKey, entityValue] of Object.entries(data)) { - if (parameter.includes(entityKey) && entityValue && entityValue.data && entityValue.data.feature) { - let feature = entityValue.data.feature; - feature.properties["name"] = entityKey; - feature.properties["addOn"] = addOn; - if (entityValue?.children) tempStorage = [...tempStorage, feature, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; - else tempStorage = [...tempStorage, feature]; - } - if (entityValue?.children) tempStorage = [...tempStorage, ...fetchFeatures(entityValue?.children, parameter, outputList, addOn)]; - } - return tempStorage; - } -}; - -export const addChoroplethProperties = (geojson, choroplethProperty, filteredSelection) => { - // Calculate min and max values of the property - const values = geojson.map((feature) => feature.properties[choroplethProperty]).filter((item) => !!item || item === 0) || []; - if (!values || values.length === 0) return []; - const convertedValues = values.map((item) => (!isNaN(item) ? item : 0)); - const minValue = Math.min(...convertedValues); - const maxValue = Math.max(...convertedValues); - - // Create a new geojson object - const newGeojson = geojson.map((feature) => { - const newFeature = { ...feature, properties: { ...feature.properties, addOn: { ...feature.properties.addOn } } }; - let color; - - if (choroplethProperty) { - color = interpolateColor(newFeature.properties[choroplethProperty], minValue, maxValue, MapChoroplethGradientColors); - } - - newFeature.properties.addOn.fillColor = color; - newFeature.properties.addOn.color = "rgba(0, 0, 0, 1)"; - if (!filteredSelection || filteredSelection.length === 0 || filteredSelection.includes(newFeature.properties.name)) { - newFeature.properties.addOn.fillOpacity = 1; - } else { - newFeature.properties.addOn.fillOpacity = 0.4; - newFeature.properties.addOn.opacity = 0.7; - } - - return newFeature; - }); - return newGeojson; -}; - -/** - * filterGeojsons : json - * filterSelection : array - * MapFilters : - */ -export const addFilterProperties = (filterGeojsons, filterSelections, filterPropertyNames, iconMapping) => { - try { - if (!filterGeojsons || !iconMapping || !filterSelections) return []; - let newFilterGeojson = []; - filterGeojsons.forEach((item) => { - if (filterPropertyNames && filterPropertyNames.length !== 0 && item.properties) { - let icon; - filterPropertyNames.forEach((name) => { - if (item.properties[name]) { - let temp = item.properties[name]; - if (!filterSelections.includes(temp)) return; - temp = iconMapping?.find((e) => e?.name == temp)?.icon?.marker; - let DynamicIcon = IconCollection?.[temp]; - if (typeof DynamicIcon === "function") { - icon = L.divIcon({ - className: "custom-svg-icon", - html: DynamicIcon({}), - iconAnchor: [25, 50], - }); - newFilterGeojson.push({ ...item, properties: { ...item?.properties, addOn: { ...item?.properties?.addOn, icon: icon } } }); - } else { - icon = DefaultMapMarker({}); - newFilterGeojson.push({ ...item, properties: { ...item?.properties, addOn: { ...item?.properties?.addOn, icon: icon } } }); - } - } - }); - } - return item; - }); - return newFilterGeojson; - } catch (error) { - console.error(error.message); - } -}; - -/** - * map: map - * geojson: geojson - * t: translator - */ - -export const addGeojsonToMap = (map, geojson, t) => { - try { - if (!map || !geojson) return false; - const geojsonLayer = L.geoJSON(geojson, { - style: (feature) => { - if (Object.keys(feature.properties.addOn).length !== 0) { - return feature.properties.addOn; - } - return { - weight: 2, - opacity: 1, - color: "rgba(176, 176, 176, 1)", - fillColor: "rgb(0,0,0,0)", - // fillColor: choroplethProperty ? color : "rgb(0,0,0,0)", - fillOpacity: 0, - // fillOpacity: choroplethProperty ? (feature?.properties?.style?.fillOpacity ? feature.properties.style.fillOpacity : 0.7) : 0, - }; - }, - pointToLayer: (feature, latlng) => { - if (feature.properties.addOn.icon) { - let icon = feature.properties.addOn.icon; - if (icon) { - return L.marker(latlng, { - icon: icon, - }); - } - } - return L.marker(latlng, { - icon: MapMarker(feature.properties.addOn), - }); - }, - onEachFeature: (feature, layer) => { - let popupContent; - popupContent = "
"; - popupContent += "
"; - popupContent += `
${feature.properties["name"]}
`; - for (let prop in feature.properties) { - if (prop !== "name" && prop !== "addOn" && prop !== "feature") { - let data = feature.properties[prop] ? feature.properties[prop] : t("NO_DATA"); - popupContent += - ""; - } - } - popupContent += "
" + - t(prop) + - "" + - data + - "
"; - layer.bindPopup(popupContent, { - minWidth: "28rem", - padding: "0", - }); - // Adjust map here when pop up closes - layer.on("popupclose", () => { - map.fitBounds(geojsonLayer.getBounds()); - }); - layer.on({ - mouseover: (e) => { - const layer = e.target; - if (layer.feature.properties.addOn && !layer.feature.properties.addOn.child) { - return; - } - if (layer.setStyle) - layer.setStyle({ - weight: 2.7, - opacity: 1, - color: "rgba(255, 255, 255, 1)", - }); - // layer.openPopup(); - }, - mouseout: (e) => { - const layer = e.target; - if (layer.feature.properties.addOn && !layer.feature.properties.addOn.child) { - return; - } - if (layer.setStyle) { - if (layer.feature.properties.addOn && Object.keys(layer.feature.properties.addOn).length !== 0) - layer.setStyle({ - ...layer.feature.properties.addOn, - }); - else - layer.setStyle({ - weight: 2, - color: "rgba(176, 176, 176, 1)", - }); - } - // layer.closePopup(); - }, - }); - }, - }); - geojsonLayer.addTo(map); - return geojsonLayer; - } catch (error) { - console.error(error.message); - } -}; - -export const interpolateColor = (value, minValue, maxValue, colors) => { - // Handle case where min and max values are the same - if (minValue === maxValue) { - // Return a default color or handle the case as needed - return colors[0].color; - } - - // Normalize the value to a percentage between 0 and 100 - const percent = !isNaN(value) ? ((value - minValue) / (maxValue - minValue)) * 100 : 0; - // Find the two colors to interpolate between - let lowerColor, upperColor; - for (let i = 0; i < colors.length - 1; i++) { - if (!isNaN(percent) && percent >= colors[i].percent && percent <= colors[i + 1].percent) { - lowerColor = colors[i]; - upperColor = colors[i + 1]; - break; - } - } - // Interpolate between the two colors - const t = (percent - lowerColor.percent) / (upperColor.percent - lowerColor.percent); - return chroma.mix(lowerColor.color, upperColor.color, t, "lab").hex(); -}; - -// Find bounds for multiple geojson together -export const findBounds = (data, buffer = 0.1) => { - if (!Array.isArray(data) || data.length === 0) { - return null; - } - - // Initialize variables to store bounds - var minLat = Number.MAX_VALUE; - var maxLat = -Number.MAX_VALUE; - var minLng = Number.MAX_VALUE; - var maxLng = -Number.MAX_VALUE; - - // Iterate through the data to find bounds - data.forEach(function (feature) { - if (!feature || !feature.geometry || !feature.geometry.type || !feature.geometry.coordinates) { - return null; - } - - var coords = feature.geometry.coordinates; - var geometryType = feature.geometry.type; - - switch (geometryType) { - case "Point": - var coord = coords; - var lat = coord[1]; - var lng = coord[0]; - minLat = Math.min(minLat, lat); - maxLat = Math.max(maxLat, lat); - minLng = Math.min(minLng, lng); - maxLng = Math.max(maxLng, lng); - break; - case "MultiPoint": - coords.forEach(function (coord) { - var lat = coord[1]; - var lng = coord[0]; - minLat = Math.min(minLat, lat); - maxLat = Math.max(maxLat, lat); - minLng = Math.min(minLng, lng); - maxLng = Math.max(maxLng, lng); - }); - break; - case "LineString": - case "MultiLineString": - case "Polygon": - case "MultiPolygon": - coords.forEach(function (polygons) { - if ((geometryType === "Polygon" || geometryType === "MultiPolygon") && Array.isArray(polygons[0][0])) { - polygons.forEach(function (coordinates) { - coordinates.forEach(function (coord) { - if (!Array.isArray(coord) || coord.length !== 2 || typeof coord[0] !== "number" || typeof coord[1] !== "number") { - return null; - } - - var lat = coord[1]; - var lng = coord[0]; - minLat = Math.min(minLat, lat); - maxLat = Math.max(maxLat, lat); - minLng = Math.min(minLng, lng); - maxLng = Math.max(maxLng, lng); - }); - }); - } else { - polygons.forEach(function (coord) { - if (!Array.isArray(coord) || coord.length !== 2 || typeof coord[0] !== "number" || typeof coord[1] !== "number") { - return null; - } - - var lat = coord[1]; - var lng = coord[0]; - minLat = Math.min(minLat, lat); - maxLat = Math.max(maxLat, lat); - minLng = Math.min(minLng, lng); - maxLng = Math.max(maxLng, lng); - }); - } - }); - break; - default: - return null; - } - }); - - // Check if valid bounds found - if (minLat === Number.MAX_VALUE || maxLat === -Number.MAX_VALUE || minLng === Number.MAX_VALUE || maxLng === -Number.MAX_VALUE) { - return null; - } - // Apply buffer to bounds - minLat -= buffer; - maxLat += buffer; - minLng -= buffer; - maxLng += buffer; - - // Set bounds for the Leaflet map - var bounds = [ - [minLat, minLng], - [maxLat, maxLng], - ]; - - return bounds; -}; - -export const filterBoundarySelection = (boundaryData, boundarySelections) => { - if (Object.keys(boundaryData).length === 0 || Object.keys(boundarySelections).length === 0) return []; - let selectionList = []; - Object.values(boundarySelections).forEach((item) => (selectionList = [...selectionList, ...item.map((e) => e.name)])); - let childrenList = []; - const set1 = new Set(selectionList); - selectionList = selectionList.filter((item) => { - const children = findChildren([item], Object.values(boundaryData)?.[0]?.hierarchicalData); - if (children) { - let childrenKeyList = getAllKeys(children); - childrenList = [...childrenList, ...childrenKeyList]; - const nonePresent = childrenKeyList.every((item) => !set1.has(item)); - const allPresent = childrenKeyList.every((item) => set1.has(item)); - return nonePresent ? true : allPresent ? true : false; - } - return true; - }); - return { filteredSelection: selectionList, childrenList }; -}; - -// Recursive function to extract all keys -export const getAllKeys = (obj, keys = []) => { - for (let [key, value] of Object.entries(obj)) { - keys.push(key); - if (value.children) { - getAllKeys(value.children, keys); - } - } - return keys; -}; - -// Remove all layers from the map -export const removeAllLayers = (map, layer) => { - if (!map) return; - layer.forEach((layer) => { - map.removeLayer(layer); - }); -}; -// Map-Marker -export const MapMarker = (style = {}) => { - return L.divIcon({ - className: "custom-svg-icon", - html: PopulationSvg(style), - iconAnchor: [25, 50], - }); -}; -export const DefaultMapMarker = (style = {}) => { - return L.divIcon({ - className: "custom-svg-icon", - html: IconCollection.DefaultMapMarkerSvg(style), - iconAnchor: [25, 50], - }); -}; - -export const disableMapInteractions = (map) => { - if (!map) return; - map.dragging.disable(); - map.scrollWheelZoom.disable(); - map.touchZoom.disable(); - map.doubleClickZoom.disable(); - map.boxZoom.disable(); - map.keyboard.disable(); -}; - -export const enableMapInteractions = (map) => { - if (!map) return; - map.dragging.enable(); - map.scrollWheelZoom.enable(); - map.touchZoom.enable(); - map.doubleClickZoom.enable(); - map.boxZoom.enable(); - map.keyboard.enable(); -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js deleted file mode 100644 index ff5cd55208f..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/microplanPreviewUtils.js +++ /dev/null @@ -1,413 +0,0 @@ -import { EXCEL, GEOJSON, SHAPEFILE, commonColumn } from "../configs/constants"; - -export const calculateAggregateValue = (aggregateName, dataToShow) => { - if (!aggregateName || !dataToShow || dataToShow.length === 0) return; - let aggregateNameList = aggregateName; - if (typeof aggregateName !== "object") aggregateNameList = { name: aggregateName, entities: [aggregateName] }; - let aggregateData = 0; - if (aggregateNameList) - for (const item of aggregateNameList.entities) { - const columnIndex = dataToShow?.[0].indexOf(item); - dataToShow.slice(1).forEach((e) => { - if (e?.[columnIndex]) aggregateData = aggregateData + Number(e[columnIndex]); - }); - } - return aggregateData; -}; - -export const fetchMicroplanData = (microplanData, campaignType, validationSchemas) => { - if (!microplanData) return []; - - let combinesDataList = []; - // Check if microplanData and its upload property exist - if (microplanData?.upload) { - let files = microplanData?.upload; - // Loop through each file in the microplan upload - for (let fileData of files) { - const schema = getSchema(campaignType, fileData.fileType, fileData.templateIdentifier, validationSchemas); - - // Check if the file is not part of boundary or layer data origins - if (!fileData.active || !fileData.fileType || !fileData?.section) continue; // Skip files with errors or missing properties - - // Check if file contains latitude and longitude columns - if (fileData?.data) { - // Check file type and update data availability accordingly - switch (fileData?.fileType) { - case EXCEL: { - // extract dada - const mergedData = schema?.template?.hierarchyLevelWiseSheets ? Object.values(fileData?.data).flat() : Object.values(fileData?.data)?.[0]; - - let commonColumnIndex = mergedData?.[0]?.indexOf(commonColumn); - - let uniqueEntries; - if (commonColumnIndex !== undefined) - uniqueEntries = schema?.template?.hierarchyLevelWiseSheets - ? Array.from(new Map(mergedData.map((entry) => [entry[commonColumnIndex], entry])).values()) - : mergedData; - if (uniqueEntries) combinesDataList.push(uniqueEntries); - break; - } - case GEOJSON: - case SHAPEFILE: { - // Extract keys from the first feature's properties - let keys = Object.keys(fileData?.data.features[0].properties); - - // Extract corresponding values for each feature - const values = fileData?.data?.features.map((feature) => { - // list with features added to it - const temp = keys.map((key) => { - // if (feature.properties[key] === "") { - // return null; - // } - return feature.properties[key]; - }); - return temp; - }); - - let data = [keys, ...values]; - combinesDataList.push(data); - } - } - } - } - } - return combinesDataList; -}; - -// get schema for validation -export const getSchema = (campaignType, type, section, schemas) => { - return schemas.find((schema) => - schema.campaignType - ? schema.campaignType === campaignType && schema.type === type && schema.section === section - : schema.type === type && schema.section === section - ); -}; - -export const fetchMicroplanPreviewData = (campaignType, microplanData, validationSchemas, hierarchy) => { - try { - const filteredSchemaColumns = getFilteredSchemaColumnsList(campaignType, microplanData, validationSchemas, hierarchy); - const fetchedData = fetchMicroplanData(microplanData, campaignType, validationSchemas); - const dataAfterJoins = performDataJoins(fetchedData, filteredSchemaColumns); - return dataAfterJoins; - } catch (error) { - console.error("Error in fetch microplan data: ", error.message); - } -}; - -const getFilteredSchemaColumnsList = (campaignType, microplanData, validationSchemas, hierarchy) => { - let filteredSchemaColumns = getRequiredColumnsFromSchema(campaignType, microplanData, validationSchemas) || []; - if (hierarchy) { - filteredSchemaColumns = [...hierarchy, commonColumn, ...filteredSchemaColumns.filter((e) => e !== commonColumn)]; - } - return filteredSchemaColumns; -}; - -const performDataJoins = (fetchedData, filteredSchemaColumns) => { - return fetchedData.reduce((accumulator, currentData, index) => { - if (index === 0) { - return innerJoinLists(currentData, null, commonColumn, filteredSchemaColumns); - } - return innerJoinLists(accumulator, currentData, commonColumn, filteredSchemaColumns); - }, null); -}; - -export const filterObjects = (arr1, arr2) => { - if (!arr1 || !arr2) return []; - // Create a new array to store the filtered objects - let filteredArray = []; - - // Iterate through the first array - arr1.forEach((obj1) => { - // Find the corresponding object in the second array - let obj2 = _.cloneDeep(arr2.find((item) => item.key === obj1.key)); - - // If the object with the same key is found in the second array and their values are the same - if (obj2 && obj1.value !== obj2.value) { - // Push the object to the filtered array - obj1.oldValue = obj2.value; - filteredArray.push(obj1); - } - }); - - return filteredArray; -}; - -export const useHypothesis = (tempHypothesisList, hypothesisAssumptionsList) => { - // Handles the change in hypothesis value - const valueChangeHandler = (e, setTempHypothesisList, boundarySelections, setToast, t) => { - // Checks it the boundary filters at at root level ( given constraints ) - if (Object.keys(boundarySelections).length !== 0 && Object.values(boundarySelections)?.every((item) => item?.length !== 0)) - return setToast({ state: "error", message: t("HYPOTHESIS_CAN_BE_ONLY_APPLIED_ON_ADMIN_LEVEL_ZORO") }); - - // validating user input - if (e?.newValue.includes("+") || e?.newValue.includes("e")) return; - if ((e?.newValue < 0 || e.newValue > 10000000000) && e?.newValue !== "") return; - let value; - const decimalIndex = e.newValue.indexOf("."); - if (decimalIndex !== -1) { - const numDecimals = e.newValue.length - decimalIndex - 1; - if (numDecimals <= 2) { - value = e.newValue; - } else if (numDecimals > 2) { - value = e.newValue.substring(0, decimalIndex + 3); - } - } else value = parseFloat(e.newValue); - value = !isNaN(value) ? value : ""; - - // update the state with user input - let newhypothesisEntityIndex = hypothesisAssumptionsList.findIndex((item) => item?.id === e?.item?.id); - let unprocessedHypothesisList = _.cloneDeep(tempHypothesisList); - if (newhypothesisEntityIndex !== -1) unprocessedHypothesisList[newhypothesisEntityIndex].value = value; - setTempHypothesisList(unprocessedHypothesisList); - }; - - return { - valueChangeHandler, - }; -}; - -const validateRequestBody = (body, state, campaignType, setLoaderActivation, setToast, setCheckDataCompletion, navigationEvent, t) => { - if (!Digit.Utils.microplan.planConfigRequestBodyValidator(body, state, campaignType)) { - setLoaderActivation(false); - if (navigationEvent.name === "next") { - setToast({ - message: t("ERROR_DATA_NOT_SAVED"), - state: "error", - }); - setCheckDataCompletion("false"); - } else { - setCheckDataCompletion("perform-action"); - } - return false; - } - return true; -}; - -const handleApiSuccess = (data, updateData, setLoaderActivation, setMicroplanData, status) => { - updateData(); - setLoaderActivation(false); - setMicroplanData((previous) => ({ ...previous, microplanStatus: status })); -}; - -const handleApiError = (error, variables, setLoaderActivation, setToast, status, cancleNavigation, updateData, t) => { - setLoaderActivation(false); - setToast({ - message: t("ERROR_DATA_NOT_SAVED"), - state: "error", - }); - if (status === "GENERATED") { - cancleNavigation(); - } else { - updateData(); - } -}; - -const constructRequestBody = (microplanData, operatorsObject, MicroplanName, campaignId, status) => { - const body = Digit.Utils.microplan.mapDataForApi(microplanData, operatorsObject, MicroplanName, campaignId, status); - body.PlanConfiguration["id"] = microplanData?.planConfigurationId; - body.PlanConfiguration["auditDetails"] = microplanData?.auditDetails; - return body; -}; - -export const updateHyothesisAPICall = async ( - microplanData, - setMicroplanData, - operatorsObject, - MicroplanName, - campaignId, - UpdateMutate, - setToast, - updateData, - setLoaderActivation, - status, - cancleNavigation, - state, - campaignType, - navigationEvent, - setCheckDataCompletion, - t -) => { - try { - const body = constructRequestBody(microplanData, operatorsObject, MicroplanName, campaignId, status); - const isValid = validateRequestBody(body, state, campaignType, setLoaderActivation, setToast, setCheckDataCompletion, navigationEvent, t); - if (!isValid) return; - - await UpdateMutate(body, { - onSuccess: (data) => handleApiSuccess(data, updateData, setLoaderActivation, setMicroplanData, status), - onError: (error, variables) => handleApiError(error, variables, setLoaderActivation, setToast, status, cancleNavigation, updateData, t), - }); - } catch (error) { - setLoaderActivation(false); - setToast({ - message: t("ERROR_DATA_NOT_SAVED"), - state: "error", - }); - } -}; - -// get schema for validation -export const getRequiredColumnsFromSchema = (campaignType, microplanData, schemas) => { - if (!schemas || !microplanData || !microplanData?.upload || !campaignType) return []; - const sortData = []; - if (microplanData?.upload) { - for (const value of microplanData.upload) { - if (value.active && value?.error === null) { - sortData.push({ section: value.section, fileType: value?.fileType }); - } - } - } - const filteredSchemas = - schemas?.filter((schema) => { - if (schema.campaignType) { - return schema.campaignType === campaignType && sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); - } - return sortData.some((entry) => entry.section === schema.section && entry.fileType === schema.type); - }) || []; - - let finalData = []; - let tempdata; - - tempdata = filteredSchemas - ?.flatMap((item) => - Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.isRuleConfigureInputs && value?.toShowInMicroplanPreview) { - acc.push(key); - } - return acc; - }, []) - ) - .filter((item) => !!item); - finalData = [...finalData, ...tempdata]; - - tempdata = filteredSchemas - ?.flatMap((item) => - Object.entries(item?.schema?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.toShowInMicroplanPreview) acc.push(key); - return acc; - }, []) - ) - .filter((item) => !!item); - finalData = [...finalData, ...tempdata]; - return [...new Set(finalData)]; -}; - -/** - * Combines two datasets based on a common column, duplicating rows from data1 for each matching row in data2. - * The final dataset's columns and their order are determined by listOfColumnsNeededInFinalData. - * If data2 is not provided, rows from data1 are included with null values for missing columns. - */ -export const innerJoinLists = (data1, data2, commonColumnName, listOfColumnsNeededInFinalData) => { - // Error handling: Check if data1 array is provided - if (!Array.isArray(data1)) { - throw new Error("The first data input must be an array."); - } - - // Error handling: Check if common column name is provided - if (typeof commonColumnName !== "string") { - throw new Error("Common column name must be a string."); - } - - // Error handling: Check if listOfColumnsNeededInFinalData is provided and is an array - if (!Array.isArray(listOfColumnsNeededInFinalData)) { - throw new Error("listOfColumnsNeededInFinalData must be an array."); - } - - // Find the index of the common column in the first dataset - const commonColumnIndex1 = data1[0].indexOf(commonColumnName); - - // Error handling: Check if common column exists in the first dataset - if (commonColumnIndex1 === -1) { - throw new Error(`Common column "${commonColumnName}" not found in the first dataset.`); - } - - let commonColumnIndex2 = -1; - const data2Map = new Map(); - if (data2) { - // Find the index of the common column in the second dataset - commonColumnIndex2 = data2[0].indexOf(commonColumnName); - - // Error handling: Check if common column exists in the second dataset - if (commonColumnIndex2 === -1) { - throw new Error(`Common column "${commonColumnName}" not found in the second dataset.`); - } - - // Create a map for the second dataset for quick lookup by the common column value - for (let i = 1; i < data2.length; i++) { - const row = data2[i]; - const commonValue = row[commonColumnIndex2]; - if (!data2Map.has(commonValue)) { - data2Map.set(commonValue, []); - } - data2Map.get(commonValue).push(row); - } - } - - // Determine the headers for the final combined dataset based on listOfColumnsNeededInFinalData - const combinedHeaders = listOfColumnsNeededInFinalData.filter((header) => data1[0].includes(header) || data2?.[0].includes(header)); - - // Combine rows - const combinedData = [combinedHeaders]; - const addedCommonValues = new Set(); - for (let i = 1; i < data1.length; i++) { - const row1 = data1[i]; - const commonValue = row1[commonColumnIndex1]; - const rows2 = data2 ? data2Map.get(commonValue) || [[null]] : [[null]]; // Handle missing common values with a placeholder array of null - - // Check if rows2 is the placeholder array - const isPlaceholderArray = rows2.length === 1 && rows2[0].every((value) => value === null); - - // Create combined rows for each row in data2 - if (isPlaceholderArray) { - // If no corresponding row found in data2, use row from data1 with null values for missing columns - const combinedRow = combinedHeaders.map((header) => { - const index1 = data1[0].indexOf(header); - return index1 !== -1 ? row1[index1] : null; - }); - combinedData.push(combinedRow); - } else { - // If corresponding rows found in data2, combine each row from data2 with row from data1 - rows2.forEach((row2) => { - const combinedRow = combinedHeaders.map((header) => { - const index1 = data1[0].indexOf(header); - const index2 = data2 ? data2[0].indexOf(header) : -1; - return index1 !== -1 ? row1[index1] : index2 !== -1 ? row2[index2] : null; - }); - combinedData.push(combinedRow); - }); - } - addedCommonValues.add(commonValue); - } - // Add rows from data2 that do not have a matching row in data1 - if (data2) { - for (let i = 1; i < data2.length; i++) { - const row2 = data2[i]; - const commonValue = row2[commonColumnIndex2]; - if (!addedCommonValues.has(commonValue)) { - const combinedRow = combinedHeaders.map((header) => { - // const index1 = data1[0].indexOf(header); - const index2 = data2[0].indexOf(header); - return index2 !== -1 ? row2[index2] : null; - }); - combinedData.push(combinedRow); - } - } - } - - return combinedData; -}; - -// function to filter the microplan data with respect to the hierarchy selected by the user -export const filterMicroplanDataToShowWithHierarchySelection = (data, selections, hierarchy, hierarchyIndex = 0) => { - if (!selections || selections?.length === 0) return data; - if (hierarchyIndex >= hierarchy?.length) return data; - const filteredHirarchyLevelList = selections?.[hierarchy?.[hierarchyIndex]]?.map((item) => item?.name); - if (!filteredHirarchyLevelList || filteredHirarchyLevelList?.length === 0) return data; - const columnDataIndexForHierarchyLevel = data?.[0]?.indexOf(hierarchy?.[hierarchyIndex]); - if (columnDataIndexForHierarchyLevel === -1) return data; - const levelFilteredData = data.filter((item, index) => { - if (index === 0) return true; - if (item?.[columnDataIndexForHierarchyLevel] && filteredHirarchyLevelList.includes(item?.[columnDataIndexForHierarchyLevel])) return true; - return false; - }); - return filterMicroplanDataToShowWithHierarchySelection(levelFilteredData, selections, hierarchy, hierarchyIndex + 1); -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js deleted file mode 100644 index 09e24a4658e..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/processHierarchyAndData.js +++ /dev/null @@ -1,351 +0,0 @@ -export const processHierarchyAndData = (hierarchy, allData) => { - const hierarchyLists = {}; - let hierarchicalData = {}; - try { - // Process hierarchy - hierarchy.forEach((item) => { - hierarchyLists[item.boundaryType] = []; - }); - - // Process all sets of data - allData.forEach((data) => { - const dataHierarchicalData = {}; - - // Process data for this set - data.slice(1).forEach((row) => { - // Exclude the header row - let currentNode = dataHierarchicalData; - let parent = null; - hierarchy.forEach((item, index) => { - const boundaryType = item.boundaryType; - const dataIndex = data?.[0].indexOf(boundaryType); - if (dataIndex === -1) return; - const cellValue = row[dataIndex]; - if (!cellValue) return; - // Populate hierarchy lists - if (!hierarchyLists[boundaryType].includes(cellValue) && cellValue !== null && cellValue !== "" && cellValue !== undefined) { - hierarchyLists[boundaryType].push(cellValue); - } - - // Populate hierarchical data - if (!currentNode[cellValue]) { - currentNode[cellValue] = { - name: cellValue, - boundaryType: boundaryType, - children: {}, - data: null, - }; - } - - // Assign row data to the correct hierarchical level - if (cellValue) { - if (index === hierarchy.length - 1) { - currentNode[cellValue].data = createDataObject(data[0], row); - } else if (index + 1 < hierarchy.length) { - let nextHierarchyList = hierarchy.slice(index + 1); - let check = true; - nextHierarchyList.forEach((e) => { - const boundaryType = e.boundaryType; - const dataIndex = data?.[0].indexOf(boundaryType); - if (dataIndex === -1) return; - check = check && !row[dataIndex]; - }); - if (check) currentNode[cellValue].data = createDataObject(data[0], row); - } - } - currentNode = currentNode[cellValue].children; - }); - }); - - // Merge dataHierarchicalData into hierarchicalData - hierarchicalData = mergeHierarchicalData(hierarchicalData, dataHierarchicalData); - }); - - // Remove null element from children of each province - Object.values(hierarchicalData).forEach((country) => { - if (country.children[null]) { - country.data = country.children[null].data; - country.children[null] = undefined; - } - }); - } catch (error) { - console.error("Error in processing hierarchy and uploaded data: ", error.message); - // Return empty objects in case of error - return { hierarchyLists: {}, hierarchicalData: {} }; - } - - return { hierarchyLists, hierarchicalData }; -}; - -// Function to merge two hierarchical data objects -const mergeHierarchicalData = (data1, data2) => { - for (const [key, value] of Object.entries(data2)) { - if (!data1[key]) { - if (!value.data) value.data = {}; - data1[key] = value || {}; - } else { - data1[key].data = value.data; // Merge data - mergeHierarchicalData(data1[key].children, value.children); // Recursively merge children - } - if (data1[key].data?.feature) { - const { feature, ...temp } = value.data ? _.cloneDeep(value.data) : {}; - data1[key].data.feature.properties = { ...data1[key].data?.feature?.properties, ...temp }; - } - } - return data1; -}; - -// Function to create a data object with key-value pairs from headers and row data -const createDataObject = (headers, row) => { - const dataObject = {}; - headers.forEach((header, index) => { - dataObject[header] = row[index]; - }); - return dataObject; -}; - -// Find parent in hierarchy -export const findParent = (name, hierarchy, parent, accumulator = []) => { - if (!name || !hierarchy) return null; - for (let key in hierarchy) { - if (hierarchy[key]?.name == name) { - accumulator.push(parent); - } - if (hierarchy[key]?.children) { - let response = findParent(name, hierarchy[key]?.children, hierarchy[key], accumulator); - if (response) - response.forEach((item) => { - if (!accumulator.includes(item)) { - accumulator.push(item); - } - }); - } else { - return accumulator; - } - } - return accumulator; -}; - -/** - * - * @param {Array of parents} parents - * @param {hierarchycal Object data} hierarchy - * @returns An Array containing all the cummulative children - */ -export const findChildren = (parents, hierarchy) => { - const hierarchyTraveller = (parents, hierarchy, accumulator = {}) => { - let tempData = []; - if (accumulator && Object.keys(accumulator).length !== 0) - tempData = { - ...accumulator, - ...hierarchy.reduce((data, item) => { - if (parents.includes(item?.name) && item?.children) { - for (const key in item.children) { - if (!data[key]) { - data[key] = item.children[key]; - } - } - } - return data; - }, {}), - }; - else - tempData = hierarchy.reduce((data, item) => { - if (parents.includes(item?.name) && item?.children) { - for (const key in item.children) { - if (!data[key]) { - data[key] = item.children[key]; - } - } - } - return data; - }, {}); - for (let parent of hierarchy) { - if (parent?.children) tempData = hierarchyTraveller(parents, Object.values(parent?.children), tempData); - } - return tempData; - }; - return hierarchyTraveller(parents, Object.values(hierarchy), {}); -}; - -// Fetched data from tree -export const fetchDropdownValues = (boundaryData, hierarchy, boundarySelections, changedBoundaryType) => { - if ( - !hierarchy || - !boundaryData || - !boundarySelections || - hierarchy.length === 0 || - Object.keys(hierarchy).length === 0 || - Object.keys(boundaryData).length === 0 - ) - return []; - let TempHierarchy = _.cloneDeep(hierarchy); - if (!boundarySelections || Object.values(boundarySelections)?.every((item) => item?.length === 0)) { - for (let i in TempHierarchy) { - if (i === "0") { - TempHierarchy[0].dropDownOptions = findByBoundaryType( - TempHierarchy?.[0]?.boundaryType, - Object.values(boundaryData)?.[0]?.hierarchicalData - ).map((data, index) => ({ - name: data, - code: data, - boundaryType: TempHierarchy?.[0]?.boundaryType, - parentBoundaryType: undefined, - })); - } else TempHierarchy[i].dropDownOptions = []; - } - } else { - const currentHierarchy = findCurrentFilteredHierarchy(Object.values(boundaryData)?.[0]?.hierarchicalData, boundarySelections, TempHierarchy); - let currentDropdownIndex = 0; - hierarchy.forEach((e, index) => { - if (e && e?.boundaryType == changedBoundaryType) { - // && boundarySelections && boundarySelections[e.boundaryType] && boundarySelections[e.boundaryType].length !== 0) { - currentDropdownIndex = index; - } - }); - Object.entries(boundarySelections)?.forEach(([key, value]) => { - let currentindex = hierarchy.findIndex((e) => e?.boundaryType === key); - if (currentDropdownIndex !== currentindex) return; - let childIndex = hierarchy.findIndex((e) => e?.parentBoundaryType === key); - if (childIndex == -1) return; - if (TempHierarchy?.[childIndex]) { - let newDropDownValuesForChild = []; - for (const element of value) { - let tempStore = Object.values(findChildren([element.name], currentHierarchy)).map((value) => ({ - name: value?.name, - code: value?.name, - parent: element, - boundaryType: TempHierarchy[childIndex]?.boundaryType, - parentBoundaryType: TempHierarchy[childIndex]?.parentBoundaryType, - })); - if (tempStore) newDropDownValuesForChild.push(...tempStore); - } - // if (TempHierarchy[childIndex].dropDownOptions) - // TempHierarchy[childIndex].dropDownOptions = [...TempHierarchy[childIndex].dropDownOptions, ...newDropDownValuesForChild]; - TempHierarchy[childIndex].dropDownOptions = newDropDownValuesForChild; - } - }); - } - return TempHierarchy; -}; - -const findByBoundaryType = (boundaryType, hierarchy) => { - for (let [key, value] of Object.entries(hierarchy)) { - if (value?.boundaryType === boundaryType) return Object.keys(hierarchy).filter(Boolean); - if (value?.children) return findByBoundaryType(boundaryType, value?.children); - return []; - } - return []; -}; - -// makes a tree with the boundary selections as there might be duplicates in different branches that are not yet selected -const findCurrentFilteredHierarchy = (hierarchyTree, boundarySelections, hierarchy) => { - const newtree = constructNewHierarchyTree(hierarchy, hierarchyTree, boundarySelections); - return newtree; -}; - -const constructNewHierarchyTree = (hierarchy, oldTree, boundarySelection, level = 0) => { - // let newTree = { ...oldTree }; // Initialize a new hierarchy tree - let newTree = {}; // Initialize a new hierarchy tree - if (!hierarchy?.[level]) return; - const levelName = hierarchy[level].boundaryType; - - // Get the selections for this level from the boundary selection object - const selections = boundarySelection[levelName] || []; - // If there are selections for this level - if (selections.length > 0) { - // Construct the new hierarchy tree based on selections - for (const selection of selections) { - const { name } = selection; - // If the selection exists in the existing hierarchy tree - if (oldTree[name]) { - // Add the selected division to the new hierarchy tree - newTree[name] = { ...oldTree[name] }; - // If there are children, recursively construct the children - if (oldTree[name].children) { - oldTree[name].children; - const nonNullObject = Object.entries(oldTree[name].children).reduce((acc, [key, value]) => { - if (value.name !== null) { - acc[key] = value; - } - return acc; - }, {}); - newTree[name].children = constructNewHierarchyTree(hierarchy, nonNullObject, boundarySelection, level + 1); - } - } - } - } else { - const nonNullObject = Object.entries(oldTree).reduce((acc, [key, value]) => { - if (value.name !== null) { - acc[key] = value; - } - return acc; - }, {}); - newTree = nonNullObject; - } - - return newTree; -}; - -// Recursively calculates aggregate values for numerical properties within the `data` objects of each node in a hierarchical tree structure. -// Updates the `properties` object within the `feature` object of each node with the aggregate values, if present. -export const calculateAggregateForTree = (tree) => { - try { - function calculateAggregate(node) { - if (!node.children || Object.keys(node.children).length === 0) { - // if the node has no children, return a new node with its own data - return { ...node, data: { ...node.data } }; - } - - // Recursively calculate aggregate values for each child - const newChildren = {}; - - for (const childKey in node.children) { - const child = node.children[childKey]; - const newChild = calculateAggregate(child); - newChildren[childKey] = newChild; - } - - // Aggregate numerical values dynamically - const aggregate = {}; - for (const childKey in newChildren) { - const child = newChildren[childKey]; - for (const prop in child.data) { - if (typeof child.data[prop] === "number") { - aggregate[prop] = (aggregate[prop] || 0) + child.data[prop]; - } - } - } - - // Create a new node with updated data - const newNode = { - ...node, - data: { ...node.data, ...aggregate }, - children: newChildren, - }; - - // Update properties in the feature object - if (newNode.data.feature) { - newNode.data.feature.properties = { ...newNode.data.feature.properties, ...aggregate }; - } - - return newNode; - } - - const newTree = {}; - - // Iterate over each node object - for (const nodeKey in tree) { - const node = tree[nodeKey]; - // Calculate aggregate values for the current node - const newNode = calculateAggregate(node); - // Add the updated node to the new tree - newTree[nodeKey] = newNode; - } - - return newTree; - } catch (error) { - console.error("Failed to calculate treenode aggregates"); - return {}; - } -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js deleted file mode 100644 index 129ec488b43..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/updateSessionUtils.js +++ /dev/null @@ -1,486 +0,0 @@ -import { Request } from "@egovernments/digit-ui-libraries"; -import { parseXlsxToJsonMultipleSheetsForSessionUtil } from "../utils/exceltojson"; -import JSZip from "jszip"; -import * as XLSX from "xlsx"; -import axios from "axios"; -import shp from "shpjs"; -import { EXCEL, GEOJSON, SHAPEFILE, ACCEPT_HEADERS, LOCALITY, commonColumn } from "../configs/constants"; -import { addBoundaryData, fetchBoundaryData, filterBoundaries } from "./createTemplate"; -import { handleExcelFile } from "./uploadUtils"; - -function handleExcelArrayBuffer(arrayBuffer, file) { - return new Promise((resolve, reject) => { - try { - // Read the response as an array buffer - // const arrayBuffer = response.arrayBuffer(); - - // Convert the array buffer to binary string - const data = new Uint8Array(arrayBuffer); - const binaryString = String.fromCharCode.apply(null, data); - - // Parse the binary string into a workbook - const workbook = XLSX.read(binaryString, { type: "binary" }); - - // Assuming there's only one sheet in the workbook - const sheetName = workbook.SheetNames[0]; - const sheet = workbook.Sheets[sheetName]; - - // Convert the sheet to JSON object - const jsonData = XLSX.utils.sheet_to_json(sheet); - - resolve(jsonData); - } catch (error) { - reject(error); - } - }); -} - -function shpToGeoJSON(shpBuffer, file) { - return new Promise((resolve, reject) => { - try { - shp(shpBuffer) - .then((geojson) => { - resolve({ jsonData: geojson, file }); - }) - .catch((error) => reject(error)); - } catch (error) { - reject(error); - } - }); -} - -function parseGeoJSONResponse(arrayBuffer, file) { - return new Promise((resolve, reject) => { - try { - const decoder = new TextDecoder("utf-8"); - const jsonString = decoder.decode(arrayBuffer); - const jsonData = JSON.parse(jsonString); - resolve({ jsonData, file }); - } catch (error) { - reject(error); - } - }); -} - -// Function to read blob data and parse it into JSON -function parseBlobToJSON(blob, file) { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - - reader.onload = function (event) { - const data = new Uint8Array(event.target.result); - const workbook = XLSX.read(data, { type: "array" }); - const jsonData = {}; - - workbook.SheetNames.forEach((sheetName) => { - const sheetData = XLSX.utils.sheet_to_json(workbook.Sheets[sheetName]); - jsonData[sheetName] = sheetData; - }); - - resolve({ jsonData, file }); - }; - - reader.onerror = function () { - reject(new Error("Error reading the blob data")); - }; - - reader.readAsArrayBuffer(blob); - }); -} - -export const updateSessionUtils = { - computeSessionObject: async (row, state, additionalProps) => { - const sessionObj = {}; - const setCurrentPage = () => { - sessionObj.currentPage = { - id: 0, - name: "MICROPLAN_DETAILS", - component: "MicroplanDetails", - checkForCompleteness: true, - }; - }; - - //currently hardcoded - const setMicroplanStatus = () => { - sessionObj.status = { - MICROPLAN_DETAILS: true, - UPLOAD_DATA: true, - HYPOTHESIS: true, - FORMULA_CONFIGURATION: true, - }; - }; - - const setMicroplanDetails = () => { - if (row.name) { - sessionObj.microplanDetails = { - name: row?.name, - }; - } - }; - - const setMicroplanHypothesis = () => { - if (row.assumptions.length > 0) { - sessionObj.hypothesis = row.assumptions?.filter((item) => item?.active); - } - }; - - const sortRules = (rules) => { - // Step 1: Identify all unique rule outputs - const allOutputs = [...new Set(rules.map((rule) => rule.output))]; - - // Step 2: Build input-output relationships - const inputOutputMap = new Map(); // Map to store input -> output relationship - rules.forEach((rule) => { - const { input, output } = rule; - if (!inputOutputMap.has(input)) { - inputOutputMap.set(input, []); - } - inputOutputMap.get(input).push(output); - }); - - // Step 3: Sort the output list based on dependencies - const sortedOutputList = []; - const visited = new Set(); - - const dfs = (output) => { - if (!visited.has(output)) { - visited.add(output); - if (inputOutputMap.has(output)) { - inputOutputMap.get(output).forEach((input) => { - dfs(input); - }); - } - sortedOutputList.push(output); - } - }; - - // Sort outputs based on dependencies - allOutputs.forEach((output) => { - dfs(output); - }); - - // Reverse to get outputs in the correct order (outputs first) - sortedOutputList.reverse(); - - // Step 4: Arrange rules based on sorted output list - const sortedRules = []; - const ruleMap = new Map(rules.map((rule) => [rule.id, rule])); - - sortedOutputList.forEach((output) => { - rules - .filter((rule) => rule.output === output) - .forEach((rule) => { - sortedRules.push(rule); - }); - }); - - return sortedRules; - }; - - const setMicroplanRuleEngine = () => { - const rulesList = state.UIConfiguration?.filter((item) => item.name === "ruleConfigure")?.[0]?.ruleConfigureOperators; - let sortedRules = sortRules(row.operations); - if (row.operations.length > 0) { - sessionObj.ruleEngine = sortedRules?.map((item) => { - return { - ...item, - operator: rulesList.filter((rule) => rule.code === item.operator)?.[0]?.name, - }; - }); - } - }; - - const setDraftValues = () => { - sessionObj.planConfigurationId = row?.id; - sessionObj.auditDetails = row.auditDetails; - }; - - const fetchBoundaryDataWrapper = async (schemaData) => { - let boundaryDataAgainstBoundaryCode = {}; - // if (!schemaData?.doHierarchyCheckInUploadedData) { - try { - const rootBoundary = additionalProps.campaignData?.boundaries?.filter((boundary) => boundary.isRoot); // Retrieve session storage data once and store it in a variable - const sessionData = Digit.SessionStorage.get("microplanHelperData") || {}; - let boundaryData = sessionData.filteredBoundaries; - let filteredBoundaries; - if (!boundaryData) { - // Only fetch boundary data if not present in session storage - boundaryData = await fetchBoundaryData( - await Digit.ULBService.getCurrentTenantId(), - additionalProps.campaignData?.hierarchyType, - rootBoundary?.[0]?.code - ); - filteredBoundaries = await filterBoundaries(boundaryData, additionalProps.campaignData?.boundaries); - - // Update the session storage with the new filtered boundaries - Digit.SessionStorage.set("microplanHelperData", { - ...sessionData, - filteredBoundaries: filteredBoundaries, - }); - } else { - filteredBoundaries = boundaryData; - } - const xlsxData = addBoundaryData([], filteredBoundaries, additionalProps.campaignData?.hierarchyType)?.[0]?.data; - xlsxData.forEach((item, i) => { - if (i === 0) return; - let boundaryCodeIndex = xlsxData?.[0]?.indexOf(commonColumn); - if (boundaryCodeIndex >= item.length) { - // If boundaryCodeIndex is out of bounds, return the item as is - boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item.slice().map(additionalProps.t); - } else { - // Otherwise, remove the element at boundaryCodeIndex - boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item - .slice(0, boundaryCodeIndex) - .concat(item.slice(boundaryCodeIndex + 1)) - .map(additionalProps.t); - } - }); - } catch (error) { - console.error(error?.message); - } - // } - return boundaryDataAgainstBoundaryCode; - }; - - const handleGeoJson = async (file, result, upload, translatedData, active, processedData, shapefileOrigin = false) => { - if (!file) { - console.error(`${shapefileOrigin ? "Shapefile" : "Geojson"} file is undefined`); - return upload; - } - - const { inputFileType, templateIdentifier, filestoreId, id: fileId } = file || {}; - let uploadObject = createUploadObject(templateIdentifier, inputFileType, fileId, filestoreId, shapefileOrigin ? ".zip" : ".geojson", active); - - const schema = findSchema(inputFileType, templateIdentifier, additionalProps?.campaignType); - if (!schema) { - console.error("Schema got undefined while handling geojson at handleGeoJson"); - return [...upload, uploadObject]; - } - - await handleGeoJsonSpecific(schema, uploadObject, templateIdentifier, result, translatedData, filestoreId, processedData); - upload.push(uploadObject); - return upload; - }; - - const handleExcel = (file, result, upload, translatedData, active) => { - if (!file) { - console.error("Excel file is undefined"); - return upload; - } - - const { inputFileType, templateIdentifier, filestoreId, id: fileId } = file || {}; - let uploadObject = createUploadObject(templateIdentifier, inputFileType, fileId, filestoreId, ".xlsx", active), - schema = findSchema(inputFileType, templateIdentifier, additionalProps.campaignType); - if (!schema) { - console.error("Schema got undefined while handling excel at handleExcel"); - return [...upload, uploadObject]; - } - - uploadObject.data = result; //resultAfterMapping?.tempFileDataToStore; - upload.push(uploadObject); - return upload; - }; - - const createUploadObject = (templateIdentifier, inputFileType, fileId, filestoreId, extension, active) => ({ - id: fileId, - templateIdentifier, - section: templateIdentifier, - fileName: `${templateIdentifier}${extension}`, - fileType: inputFileType, - file: null, - fileId: fileId, - filestoreId: filestoreId, - error: null, - resourceMapping: row?.resourceMapping?.filter((resourse) => resourse.filestoreId === filestoreId).map((item) => ({ ...item, filestoreId })), - data: {}, - active, - }); - - const findSchema = (inputFileType, templateIdentifier, campaignType) => { - return state?.Schemas?.find( - (schema) => - schema.type === inputFileType && schema.section === templateIdentifier && (!schema.campaignType || schema.campaignType === campaignType) - ); - }; - - const handleGeoJsonSpecific = async (schema, upload, templateIdentifier, result, translatedData, filestoreId, processedData) => { - let schemaKeys; - if (schema?.schema?.["Properties"]) { - schemaKeys = additionalProps.hierarchyData?.concat(Object.keys(schema.schema["Properties"])); - } - upload.data = result; - if (processedData) return; - const mappedToList = upload?.resourceMapping.map((item) => item.mappedTo); - let sortedSecondList = Digit.Utils.microplan.sortSecondListBasedOnFirstListOrder(schemaKeys, upload?.resourceMapping); - const newFeatures = result["features"].map((item) => { - let newProperties = {}; - sortedSecondList - ?.filter((resourse) => resourse.filestoreId === filestoreId) - .forEach((e) => { - newProperties[e["mappedTo"]] = item["properties"][e["mappedFrom"]]; - }); - item["properties"] = newProperties; - return item; - }); - upload.data.features = newFeatures; - if ( - additionalProps.hierarchyData?.every( - (item) => - !mappedToList.includes(`${additionalProps.campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item)}`) - ) - ) { - let boundaryDataAgainstBoundaryCode = await fetchBoundaryDataWrapper(schema); - upload.data.features.forEach((feature) => { - const boundaryCode = feature.properties.boundaryCode; - let additionalDetails = {}; - for (let i = 0; i < additionalProps.hierarchyData?.length; i++) { - if (boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] || boundaryDataAgainstBoundaryCode[boundaryCode]?.[i] === "") { - additionalDetails[additionalProps.hierarchyData?.[i]] = boundaryDataAgainstBoundaryCode[boundaryCode][i]; - } else { - additionalDetails[additionalProps.hierarchyData?.[i]] = ""; - } - } - feature.properties = { ...additionalDetails, ...feature.properties }; - }); - } - }; - - const fetchFiles = async () => { - const files = row?.files; - if (!files || files.length === 0) { - return []; - } - - const promises = []; - let storedData = []; - for (const { filestoreId, inputFileType, templateIdentifier, id, active } of files) { - if (!active) continue; - const schemaData = findSchema(inputFileType, templateIdentifier, additionalProps?.campaignType); - if (!schemaData) { - console.error("Schema got undefined while handling geojson at handleGeoJson"); - return [...upload, uploadObject]; - } - const boundaryDataAgainstBoundaryCode = {}; - let fileData = { - filestoreId, - inputFileType, - templateIdentifier, - id, - }; - let dataInSsn = Digit.SessionStorage.get("microplanData")?.upload?.find((item) => item.active && item.id === id); - if (dataInSsn && dataInSsn.filestoreId === filestoreId) { - storedData.push({ file: fileData, jsonData: dataInSsn?.data, processedData: true, translatedData: false, active }); - } else { - const promiseToAttach = axios - .get("/filestore/v1/files/id", { - responseType: "arraybuffer", - headers: { - "Content-Type": "application/json", - Accept: ACCEPT_HEADERS[inputFileType], - "auth-token": Digit.UserService.getUser()?.["access_token"], - }, - params: { - tenantId: Digit.ULBService.getCurrentTenantId(), - fileStoreId: filestoreId, - }, - }) - .then(async (res) => { - if (inputFileType === EXCEL) { - try { - const file = new Blob([res.data], { type: ACCEPT_HEADERS[inputFileType] }); - const response = await handleExcelFile( - file, - schemaData, - additionalProps.hierarchyData.map( - (item) => `${additionalProps.campaignData?.hierarchyType}_${Digit.Utils.microplan.transformIntoLocalisationCode(item)}` - ), - { id: inputFileType }, - boundaryDataAgainstBoundaryCode, - () => {}, - additionalProps.t, - additionalProps.campaignData, - additionalProps.readMeSheetName - ); - let fileData = { - filestoreId, - inputFileType, - templateIdentifier, - id, - }; - - return { jsonData: response.fileDataToStore, file: fileData, translatedData: true, active }; - } catch (error) { - console.error(error); - } - } else if (inputFileType === GEOJSON) { - let response = await parseGeoJSONResponse(res.data, { - filestoreId, - inputFileType, - templateIdentifier, - id, - }); - return { ...response, translatedData: true, active }; - } else if (inputFileType === SHAPEFILE) { - const geoJson = await shpToGeoJSON(res.data, { - filestoreId, - inputFileType, - templateIdentifier, - id, - }); - return { ...geoJson, translatedData: true, active }; - } - }); - promises.push(promiseToAttach); - } - } - - const resolvedPromises = await Promise.all(promises); - let result = storedData; - if (resolvedPromises) result = [...storedData, ...resolvedPromises]; - return result; - }; - const setMicroplanUpload = async (filesResponse) => { - //here based on files response set data in session - if (filesResponse.length === 0) { - return {}; - } - //populate this object based on the files and return - let upload = []; - - await filesResponse.forEach(async ({ jsonData, file, translatedData, active, processedData }, idx) => { - switch (file?.inputFileType) { - case "Shapefile": - upload = await handleGeoJson(file, jsonData, upload, translatedData, active, processedData, true); - break; - case "Excel": - upload = handleExcel(file, jsonData, upload, translatedData, active); - break; - case "GeoJSON": - upload = await handleGeoJson(file, jsonData, upload, translatedData, active, processedData); - break; - default: - break; - } - }); - //here basically parse the files data from filestore parse it and populate upload object based on file type -> excel,shape,geojson - return upload; - }; - - try { - setCurrentPage(); - setMicroplanStatus(); - setMicroplanDetails(); - setMicroplanHypothesis(); - setMicroplanRuleEngine(); - setDraftValues(); - // calling fucntion to cache filtered boundary data - await fetchBoundaryDataWrapper({}); - const filesResponse = await fetchFiles(); - const upload = await setMicroplanUpload(filesResponse); - sessionObj.upload = upload; - return sessionObj; - } catch (error) { - console.error(error.message); - } - }, -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js deleted file mode 100644 index 066f47c47f3..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/hcm-microplanning/src/utils/uploadUtils.js +++ /dev/null @@ -1,880 +0,0 @@ -import ExcelJS from "exceljs"; -import { - freezeSheetValues, - freezeWorkbookValues, - hideUniqueIdentifierColumn, - performUnfreezeCells, - unfreezeColumnsByHeader, - updateFontNameToRoboto, -} from "../utils/excelUtils"; -import { addBoundaryData, createTemplate, fetchBoundaryData, filterBoundaries } from "../utils/createTemplate"; -import { BOUNDARY_DATA_SHEET, EXCEL, FACILITY_DATA_SHEET, SCHEMA_PROPERTIES_PREFIX, SHEET_COLUMN_WIDTH, commonColumn } from "../configs/constants"; -import shp from "shpjs"; -import JSZip from "jszip"; -import { checkForErrorInUploadedFileExcel } from "../utils/excelValidations"; -import { convertJsonToXlsx } from "../utils/jsonToExcelBlob"; -import { parseXlsxToJsonMultipleSheets } from "../utils/exceltojson"; -import { geojsonValidations } from "../utils/geojsonValidations"; - -// Function for checking the uploaded file for nameing conventions -export const validateNamingConvention = (file, namingConvention, setToast, t) => { - try { - let processedConvention = namingConvention.replace("$", ".[^.]*$"); - const regx = new RegExp(processedConvention); - - if (regx && !regx.test(file.name)) { - setToast({ - state: "error", - message: t("ERROR_NAMING_CONVENSION"), - }); - return false; - } - return true; - } catch (error) { - console.error(error.message); - setToast({ - state: "error", - message: t("ERROR_UNKNOWN"), - }); - } -}; - -// Function for reading ancd checking geojson data -export const readGeojson = async (file, t) => { - return new Promise((resolve, reject) => { - if (!file) return resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } }); - - const reader = new FileReader(); - reader.onload = (e) => { - try { - const geoJSONData = JSON.parse(e.target.result); - const trimmedGeoJSONData = trimJSON(geoJSONData); - resolve({ valid: true, geojsonData: trimmedGeoJSONData }); - } catch (error) { - resolve({ valid: false, toast: { state: "error", message: t("ERROR_INCORRECT_FORMAT") } }); - } - }; - reader.onerror = (error) => { - resolve({ valid: false, toast: { state: "error", message: t("ERROR_CORRUPTED_FILE") } }); - }; - - reader.readAsText(file); - }); -}; - -// Function to recursively trim leading and trailing spaces from string values in a JSON object -export const trimJSON = (jsonObject) => { - if (typeof jsonObject !== "object") { - return jsonObject; // If not an object, return as is - } - - if (Array.isArray(jsonObject)) { - return jsonObject.map((item) => trimJSON(item)); // If it's an array, recursively trim each item - } - - const trimmedObject = {}; - for (const key in jsonObject) { - if (Object.hasOwn(jsonObject, key)) { - const value = jsonObject[key]; - // Trim string values, recursively trim objects - trimmedObject[key.trim()] = typeof value === "string" ? value.trim() : typeof value === "object" ? trimJSON(value) : value; - } - } - return trimmedObject; -}; -// Function for reading and validating shape file data -export const readAndValidateShapeFiles = async (file, t, namingConvention) => { - return new Promise((resolve, reject) => { - const readAndValidate = async () => { - if (!file) { - resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } }); - } - const fileRegex = new RegExp(namingConvention.replace("$", ".*$")); - // File Size Check - const fileSizeInBytes = file.size; - const maxSizeInBytes = 2 * 1024 * 1024 * 1024; // 2 GB - - // Check if file size is within limit - if (fileSizeInBytes > maxSizeInBytes) - resolve({ valid: false, message: t("ERROR_FILE_SIZE"), toast: { state: "error", message: t("ERROR_FILE_SIZE") } }); - - try { - const zip = await JSZip.loadAsync(file); - const isEPSG4326 = await checkProjection(zip); - if (!isEPSG4326) { - resolve({ valid: false, message: t("ERROR_WRONG_PRJ"), toast: { state: "error", message: t("ERROR_WRONG_PRJ") } }); - } - const files = Object.keys(zip.files); - const allFilesMatchRegex = files.every((fl) => { - return fileRegex.test(fl); - }); - let regx = new RegExp(namingConvention.replace("$", "\\.shp$")); - const shpFile = zip.file(regx)[0]; - regx = new RegExp(namingConvention.replace("$", "\\.shx$")); - const shxFile = zip.file(regx)[0]; - regx = new RegExp(namingConvention.replace("$", "\\.dbf$")); - const dbfFile = zip.file(regx)[0]; - - let geojson; - if (shpFile && dbfFile) { - const shpArrayBuffer = await shpFile.async("arraybuffer"); - const dbfArrayBuffer = await dbfFile.async("arraybuffer"); - - geojson = shp.combine([shp.parseShp(shpArrayBuffer), shp.parseDbf(dbfArrayBuffer)]); - } - if (shpFile && dbfFile && shxFile && allFilesMatchRegex) resolve({ valid: true, data: geojson }); - else if (!allFilesMatchRegex) - resolve({ - valid: false, - message: [t("ERROR_CONTENT_NAMING_CONVENSION")], - toast: { state: "error", data: geojson, message: t("ERROR_CONTENT_NAMING_CONVENSION") }, - }); - else if (!shpFile) - resolve({ valid: false, message: [t("ERROR_SHP_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_SHP_MISSING") } }); - else if (!dbfFile) - resolve({ valid: false, message: [t("ERROR_DBF_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_DBF_MISSING") } }); - else if (!shxFile) - resolve({ valid: false, message: [t("ERROR_SHX_MISSING")], toast: { state: "error", data: geojson, message: t("ERROR_SHX_MISSING") } }); - } catch (error) { - resolve({ valid: false, toast: { state: "error", message: t("ERROR_PARSING_FILE") } }); - } - }; - readAndValidate(); - }); -}; - -// Function for projections check in case of shapefile data -export const checkProjection = async (zip) => { - const prjFile = zip.file(/.prj$/i)[0]; - if (!prjFile) { - return "absent"; - } - - const prjText = await prjFile.async("text"); - - if (prjText.includes("GEOGCS") && prjText.includes("WGS_1984") && prjText.includes("DATUM") && prjText.includes("D_WGS_1984")) { - return "EPSG:4326"; - } - return false; -}; - -// find readMe as per campaign, template identifier and file type -export const findReadMe = (readMeCollection, campaignType, type, section) => { - if (!readMeCollection) return readMeCollection; - return ( - readMeCollection.find( - (readMe) => readMe.fileType === type && readMe.templateIdentifier === section && (!readMe.campaignType || readMe.campaignType === campaignType) - )?.data || {} - ); -}; - -// Function to handle the template download -export const downloadTemplate = async ({ - campaignType, - type, - section, - setToast, - campaignData, - hierarchyType, - Schemas, - HierarchyConfigurations, - setLoader, - hierarchy, - readMeData, - readMeSheetName, - t, -}) => { - try { - setLoader("LOADING"); - await delay(100); - // Find the template based on the provided parameters - const schema = getSchema(campaignType, type, section, Schemas); - const hierarchyLevelName = HierarchyConfigurations?.find((item) => item.name === "devideBoundaryDataBy")?.value; - const filteredReadMeData = findReadMe(readMeData, campaignType, type, section); - let template = await createTemplate({ - hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets, - hierarchyLevelName, - addFacilityData: schema?.template?.includeFacilityData, - schema, - boundaries: campaignData?.boundaries, - tenantId: Digit.ULBService.getCurrentTenantId(), - hierarchyType, - readMeData: filteredReadMeData, - readMeSheetName, - t, - }); - const translatedTemplate = translateTemplate(template, t); - - // Create a new workbook - const workbook = new ExcelJS.Workbook(); - - formatTemplate(translatedTemplate, workbook); - - // Color headers - colorHeaders( - workbook, - [...hierarchy.map((item) => t(item)), t(commonColumn)], - schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [], - [] - ); - - formatAndColorReadMeFile( - workbook, - filteredReadMeData?.map((item) => item?.header), - readMeSheetName - ); - - // protextData - await protectData({ - workbook, - hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets, - addFacilityData: schema?.template?.includeFacilityData, - schema, - t, - }); - - // Write the workbook to a buffer - workbook.xlsx.writeBuffer({ compression: true }).then((buffer) => { - // Create a Blob from the buffer - const blob = new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); - // Create a URL for the Blob - const url = URL.createObjectURL(blob); - // Create a link element and simulate click to trigger download - const link = document.createElement("a"); - link.href = url; - link.download = `${t(section)}.xlsx`; - link.click(); - // Revoke the URL to release the Blob - URL.revokeObjectURL(url); - setLoader(false); - }); - } catch (error) { - setLoader(false); - console.error(error?.message); - setToast({ state: "error", message: t("ERROR_DOWNLOADING_TEMPLATE") }); - } -}; - -export const formatAndColorReadMeFile = (workbook, headerSet, readMeSheetName) => { - const readMeSheet = workbook.getWorksheet(readMeSheetName); - if (!readMeSheet) return; - setAndFormatHeaders(readMeSheet); - formatWorksheet(readMeSheet, headerSet); -}; - -export function setAndFormatHeaders(worksheet) { - const row = worksheet.getRow(1); - // Color the header cell - row.eachCell((cell) => { - cell.fill = { - type: "pattern", - pattern: "solid", - fgColor: { argb: "f25449" }, // Header cell color - }; - cell.alignment = { vertical: "middle", horizontal: "center", wrapText: true }; // Center align and wrap text - cell.font = { bold: true }; - }); -} -export function formatWorksheet(worksheet, headerSet) { - // Add the data rows with text wrapping - const lineHeight = 15; // Set an approximate line height - const maxCharactersPerLine = 100; // Set a maximum number of characters per line for wrapping - - worksheet.eachRow((row) => { - row.eachCell({ includeEmpty: true }, (cell) => { - cell.alignment = { vertical: "middle", horizontal: "left", wrapText: true }; // Apply text wrapping - // Calculate the required row height based on content length - const numberOfLines = Math.ceil(cell?.value.length / maxCharactersPerLine); - row.height = numberOfLines * lineHeight; - - // Make the header text bold - if (headerSet?.includes(cell.value)) { - cell.font = { bold: true }; - } - }); - }); - worksheet.getColumn(1).width = 130; -} - -export const protectData = async ({ workbook, hierarchyLevelWiseSheets = true, addFacilityData = false, schema, t }) => { - if (hierarchyLevelWiseSheets) { - if (addFacilityData) { - await freezeSheetValues(workbook, t(BOUNDARY_DATA_SHEET)); - await performUnfreezeCells(workbook, t(FACILITY_DATA_SHEET)); - if (schema?.template?.propertiesToHide && Array.isArray(schema.template.propertiesToHide)) { - let tempPropertiesToHide = schema?.template?.propertiesToHide.map((item) => t(generateLocalisationKeyForSchemaProperties(item))); - await hideUniqueIdentifierColumn(workbook, t(FACILITY_DATA_SHEET), tempPropertiesToHide); - } - if (schema?.template?.facilitySchemaApiMapping) { - } else { - } - } else { - await freezeWorkbookValues(workbook); - await unfreezeColumnsByHeader( - workbook, - schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [] - ); - } - } else { - // total boundary Data in one sheet - if (addFacilityData) { - await freezeSheetValues(workbook, t(BOUNDARY_DATA_SHEET)); - await performUnfreezeCells(workbook, t(FACILITY_DATA_SHEET)); - if (schema?.template?.propertiesToHide && Array.isArray(schema.template.propertiesToHide)) { - let tempPropertiesToHide = schema?.template?.propertiesToHide.map((item) => t(generateLocalisationKeyForSchemaProperties(item))); - await hideUniqueIdentifierColumn(workbook, t(FACILITY_DATA_SHEET), tempPropertiesToHide); - } - - if (schema?.template?.facilitySchemaApiMapping) { - } else { - } - } else { - await freezeWorkbookValues(workbook); - await unfreezeColumnsByHeader( - workbook, - schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [] - ); - } - } -}; - -export const colorHeaders = async (workbook, headerList1, headerList2, headerList3) => { - try { - // Iterate through each sheet - workbook.eachSheet((sheet, sheetId) => { - // Get the first row - const firstRow = sheet.getRow(1); - - // Iterate through each cell in the first row - firstRow.eachCell((cell, colNumber) => { - const cellValue = cell.value.toString(); - - // Check conditions and set colors - if (headerList1?.includes(cellValue)) { - cell.fill = { - type: "pattern", - pattern: "solid", - fgColor: { argb: "ff9248" }, - }; - } else if (headerList2?.includes(cellValue)) { - cell.fill = { - type: "pattern", - pattern: "solid", - fgColor: { argb: "93C47D" }, - }; - } else if (headerList3?.includes(cellValue)) { - cell.fill = { - type: "pattern", - pattern: "solid", - fgColor: { argb: "CCCC00" }, - }; - } - }); - }); - } catch (error) { - console.error("Error coloring headers:", error); - } -}; - -export const formatTemplate = (template, workbook) => { - template.forEach(({ sheetName, data }) => { - // Create a new worksheet with properties - const worksheet = workbook.addWorksheet(sheetName); - data?.forEach((row, index) => { - const worksheetRow = worksheet.addRow(row); - - // Apply fill color to each cell in the first row and make cells bold - if (index === 0) { - worksheetRow.eachCell((cell, colNumber) => { - // Set font to bold - cell.font = { bold: true }; - - // Enable text wrapping - cell.alignment = { wrapText: true }; - // Update column width based on the length of the cell's text - const currentWidth = worksheet.getColumn(colNumber).width || SHEET_COLUMN_WIDTH; // Default width or current width - const newWidth = Math.max(currentWidth, cell.value.toString().length + 2); // Add padding - worksheet.getColumn(colNumber).width = newWidth; - }); - } - }); - updateFontNameToRoboto(worksheet); - }); -}; - -export const translateTemplate = (template, t) => { - // Initialize an array to hold the transformed result - const transformedResult = []; - - // Iterate over each sheet in the divided data - for (const sheet of template) { - const sheetData = sheet.data; - - // Find the index of the boundaryCode column in the header row - const boundaryCodeIndex = sheetData[0].indexOf(commonColumn); - - const sheetName = t(sheet.sheetName); - const transformedSheet = { - sheetName: sheetName.length > 31 ? sheetName.slice(0, 31) : sheetName, - data: [], - }; - - // Iterate over each row in the sheet data - for (const [rowIndex, row] of sheetData.entries()) { - // Transform each entity in the row using the transformFunction - const transformedRow = row.map((entity, index) => { - // Skip transformation for the boundaryCode column - if ((index === boundaryCodeIndex && rowIndex !== 0) || typeof entity === "number") { - return entity; - } - return t(entity); - }); - transformedSheet.data.push(transformedRow); - } - - // Add the transformed sheet to the transformed result - transformedResult.push(transformedSheet); - } - - return transformedResult; -}; - -// get schema for validation -export const getSchema = (campaignType, type, section, schemas) => { - return schemas.find((schema) => { - if (!schema.campaignType) { - return schema.type === type && schema.section === section; - } - return schema.campaignType === campaignType && schema.type === type && schema.section === section; - }); -}; - -// Performs resource mapping and data filtering for Excel files based on provided schema data, hierarchy, and file data. -export const resourceMappingAndDataFilteringForExcelFiles = (schemaData, hierarchy, selectedFileType, fileDataToStore, t) => { - const resourceMappingData = []; - const newFileData = {}; - if (selectedFileType.id === EXCEL && fileDataToStore) { - // Extract all unique column names from fileDataToStore and then doing thir resource mapping - const columnForMapping = new Set(Object.values(fileDataToStore).flatMap((value) => value?.[0] || [])); - if (schemaData?.schema?.["Properties"]) { - const schemaKeys = Object.keys(schemaData.schema["Properties"]) - .map((item) => generateLocalisationKeyForSchemaProperties(item)) - .concat([...hierarchy, commonColumn]); - schemaKeys.forEach((item) => { - if (columnForMapping.has(t(item))) { - resourceMappingData.push({ - mappedFrom: t(item), - mappedTo: revertLocalisationKey(item), - }); - } - }); - } - - // Filtering the columns with respect to the resource mapping and removing the columns that are not needed - Object.entries(fileDataToStore).forEach(([key, value]) => { - const data = []; - const headers = []; - const toRemove = []; - if (value && value.length > 0) { - value[0].forEach((item, index) => { - const mappedTo = resourceMappingData.find((e) => e.mappedFrom === item)?.mappedTo; - if (!mappedTo) { - toRemove.push(index); - return; - } - headers.push(mappedTo); - return; - }); - for (let i = 1; i < value?.length; i++) { - let temp = []; - for (let j = 0; j < value[i].length; j++) { - if (!toRemove.includes(j)) { - temp.push(value[i][j]); - } - } - data.push(temp); - } - } - newFileData[key] = [headers, ...data]; - }); - } - return { tempResourceMappingData: resourceMappingData, tempFileDataToStore: newFileData }; -}; -export const revertLocalisationKey = (localisedCode) => { - if (!localisedCode || !localisedCode.startsWith(SCHEMA_PROPERTIES_PREFIX + "_")) { - return localisedCode; - } - return localisedCode.substring(SCHEMA_PROPERTIES_PREFIX.length + 1); -}; -export const prepareExcelFileBlobWithErrors = async (data, errors, schema, hierarchy, readMeData, readMeSheetName, t) => { - let tempData = [...data]; - // Process each dataset within the data object - const processedData = {}; - const schemaCols = schema?.schema?.Properties ? Object.keys(schema.schema.Properties) : []; - for (const sheet of tempData) { - const dataset = [...sheet.data]; - - // Add the 'error' column to the header - dataset[0] = dataset[0].map((item) => { - if (item !== commonColumn && schemaCols.includes(item)) { - return t(generateLocalisationKeyForSchemaProperties(item)); - } - return t(item); - }); - if (sheet.sheetName !== t(BOUNDARY_DATA_SHEET) && sheet.sheetName !== t(readMeSheetName)) { - // Process each data row - if (errors) { - dataset[0].push(t("MICROPLAN_ERROR_STATUS_COLUMN"), t("MICROPLAN_ERROR_COLUMN")); - let headerCount = 0; - for (let i = 1; i < dataset.length; i++) { - const row = dataset[i]; - if (i === 1 && row) { - headerCount = row.length; - } - - if (headerCount > row.length) { - row.push(...Array(headerCount - row.length).fill("")); - } - - // Check if there are errors for the given commonColumnData - const errorInfo = errors?.[sheet.sheetName]?.[i - 1]; - if (errorInfo) { - let rowDataAddOn = Object.entries(errorInfo) - .map(([key, value]) => { - return `${t(key)}: ${value.map((item) => t(item)).join(", ")}`; - }) - .join(". "); - row.push(t("MICROPLAN_ERROR_STATUS_INVALID"), rowDataAddOn); - } else { - row.push(""); - } - } - } - } - processedData[sheet.sheetName] = dataset; - } - const errorColumns = ["MICROPLAN_ERROR_STATUS_COLUMN", "MICROPLAN_ERROR_COLUMN"]; - const style = { - font: { color: { argb: "B91900" } }, - border: { - top: { style: "thin", color: { argb: "B91900" } }, - left: { style: "thin", color: { argb: "B91900" } }, - bottom: { style: "thin", color: { argb: "B91900" } }, - right: { style: "thin", color: { argb: "B91900" } }, - }, - }; - const workbook = await convertToWorkBook(processedData, { errorColumns, style }); - colorHeaders( - workbook, - [...hierarchy.map((item) => t(item)), t(commonColumn)], - schema?.schema?.Properties ? Object.keys(schema.schema.Properties).map((item) => t(generateLocalisationKeyForSchemaProperties(item))) : [], - [t("MICROPLAN_ERROR_STATUS_COLUMN"), t("MICROPLAN_ERROR_COLUMN")] - ); - - formatAndColorReadMeFile( - workbook, - readMeData?.map((item) => item?.header), - readMeSheetName - ); - - // protextData - await protectData({ - workbook, - hierarchyLevelWiseSheets: schema?.template?.hierarchyLevelWiseSheets, - addFacilityData: schema?.template?.includeFacilityData, - schema, - t, - }); - return await workbook.xlsx.writeBuffer({ compression: true }).then((buffer) => { - // Create a Blob from the buffer - return new Blob([buffer], { type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" }); - }); - // return xlsxBlob; -}; -export const convertToWorkBook = async (jsonData, columnWithStyle) => { - const workbook = new ExcelJS.Workbook(); - - // Iterate over each sheet in jsonData - for (const [sheetName, data] of Object.entries(jsonData)) { - // Create a new worksheet - const worksheet = workbook.addWorksheet(sheetName); - - // Convert data to worksheet - for (const row of data) { - const newRow = worksheet.addRow(row); - const rowHasData = row?.filter((item) => item !== "").length !== 0; - // Apply red font color to the errorColumn if it exists - if (rowHasData && columnWithStyle?.errorColumns) { - for (const errorColumn of columnWithStyle?.errorColumns) { - const errorColumnIndex = data[0].indexOf(errorColumn); - if (errorColumnIndex !== -1) { - const columnIndex = errorColumnIndex + 1; - if (columnIndex > 0) { - const newCell = newRow.getCell(columnIndex); - if (columnWithStyle.style && newCell) for (const key in columnWithStyle.style) newCell[key] = columnWithStyle.style[key]; - } - } - } - } - } - - // Make the first row bold - if (worksheet.getRow(1)) { - worksheet.getRow(1).font = { bold: true }; - } - - // Set column widths - const columnCount = data?.[0]?.length || 0; - const wscols = Array(columnCount).fill({ width: 30 }); - wscols.forEach((col, colIndex) => { - worksheet.getColumn(colIndex + 1).width = col.width; - }); - } - return workbook; -}; -export const boundaryDataGeneration = async (schemaData, campaignData, t) => { - let boundaryDataAgainstBoundaryCode = {}; - if (schemaData && !schemaData.doHierarchyCheckInUploadedData) { - try { - const rootBoundary = campaignData?.boundaries?.filter((boundary) => boundary.isRoot); // Retrieve session storage data once and store it in a variable - const sessionData = Digit.SessionStorage.get("microplanHelperData") || {}; - let boundaryData = sessionData.filteredBoundaries; - let filteredBoundaries; - if (!boundaryData) { - // Only fetch boundary data if not present in session storage - boundaryData = await fetchBoundaryData(Digit.ULBService.getCurrentTenantId(), campaignData?.hierarchyType, rootBoundary?.[0]?.code); - filteredBoundaries = filterBoundaries(boundaryData, campaignData?.boundaries); - - // Update the session storage with the new filtered boundaries - Digit.SessionStorage.set("microplanHelperData", { - ...sessionData, - filteredBoundaries: filteredBoundaries, - }); - } else { - filteredBoundaries = boundaryData; - } - const xlsxData = addBoundaryData([], filteredBoundaries, campaignData?.hierarchyType)?.[0]?.data; - xlsxData.forEach((item, i) => { - if (i === 0) return; - let boundaryCodeIndex = xlsxData?.[0]?.indexOf(commonColumn); - if (boundaryCodeIndex >= item.length) { - // If boundaryCodeIndex is out of bounds, return the item as is - boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item.slice().map(t); - } else { - // Otherwise, remove the element at boundaryCodeIndex - boundaryDataAgainstBoundaryCode[item[boundaryCodeIndex]] = item - .slice(0, boundaryCodeIndex) - .concat(item.slice(boundaryCodeIndex + 1)) - .map(t); - } - }); - return boundaryDataAgainstBoundaryCode; - } catch (error) { - console.error(error?.message); - } - } -}; - -export const handleExcelFile = async ( - file, - schemaData, - hierarchy, - selectedFileType, - boundaryDataAgainstBoundaryCode, - setUploadedFileError, - t, - campaignData, - readMeSheetName -) => { - try { - // Converting the file to preserve the sequence of columns so that it can be stored - let fileDataToStore = await parseXlsxToJsonMultipleSheets(file, { header: 0 }); - const additionalSheets = []; - if (fileDataToStore[t(BOUNDARY_DATA_SHEET)]) { - additionalSheets.push({ sheetName: t(BOUNDARY_DATA_SHEET), data: fileDataToStore[t(BOUNDARY_DATA_SHEET)], position: -1 }); - delete fileDataToStore[t(BOUNDARY_DATA_SHEET)]; - } - if (fileDataToStore[t(readMeSheetName)]) { - additionalSheets.push({ sheetName: t(readMeSheetName), data: fileDataToStore[t(readMeSheetName)], position: 0 }); - delete fileDataToStore[t(readMeSheetName)]; - } - let { tempResourceMappingData, tempFileDataToStore } = resourceMappingAndDataFilteringForExcelFiles( - schemaData, - hierarchy, - selectedFileType, - fileDataToStore, - t - ); - fileDataToStore = await convertJsonToXlsx(tempFileDataToStore); - // Converting the input file to json format - let result = await parseXlsxToJsonMultipleSheets(fileDataToStore, { header: 1 }); - if (result?.error) { - return { - check: false, - interruptUpload: true, - error: result.error, - fileDataToStore: {}, - toast: { state: "error", message: t("ERROR_CORRUPTED_FILE") }, - }; - } - let extraColumns = [commonColumn]; - // checking if the hierarchy and common column is present the uploaded data - extraColumns = [...hierarchy, commonColumn]; - let data = Object.values(tempFileDataToStore); - let errorMsg; - let errors; // object containing the location and type of error - let toast; - let hierarchyDataPresent = true; - let latLngColumns = - Object.entries(schemaData?.schema?.Properties || {}).reduce((acc, [key, value]) => { - if (value?.isLocationDataColumns) { - acc.push(key); - } - return acc; - }, []) || []; - data.forEach((item) => { - const keys = item[0]; - if (keys?.length !== 0) { - if (!extraColumns?.every((e) => keys.includes(e))) { - if (schemaData && !schemaData.doHierarchyCheckInUploadedData) { - hierarchyDataPresent = false; - } else { - errorMsg = { - check: false, - interruptUpload: true, - error: t("ERROR_BOUNDARY_DATA_COLUMNS_ABSENT"), - fileDataToStore: {}, - toast: { state: "error", message: t("ERROR_BOUNDARY_DATA_COLUMNS_ABSENT") }, - }; - } - } - if (!latLngColumns?.every((e) => keys.includes(e))) { - toast = { state: "warning", message: t("ERROR_UPLOAD_EXCEL_LOCATION_DATA_MISSING") }; - } - } - }); - if (errorMsg && !errorMsg?.check) return errorMsg; - // Running Validations for uploaded file - let response = await checkForErrorInUploadedFileExcel(result, schemaData.schema, t); - if (!response.valid) setUploadedFileError(response.message); - errorMsg = response.message; - errors = response.errors; - const missingProperties = response.missingProperties; - let check = response.valid; - try { - if ( - schemaData && - !schemaData.doHierarchyCheckInUploadedData && - !hierarchyDataPresent && - boundaryDataAgainstBoundaryCode && - (!missingProperties || [...missingProperties]?.includes(commonColumn)) - ) { - let tempBoundaryDataAgainstBoundaryCode = (await boundaryDataGeneration(schemaData, campaignData, t)) || {}; - for (const sheet in tempFileDataToStore) { - const commonColumnIndex = tempFileDataToStore[sheet]?.[0]?.indexOf(commonColumn); - if (commonColumnIndex !== -1) { - const dataCollector = []; - for (let index = 0; index < tempFileDataToStore[sheet].length; index++) { - let row = tempFileDataToStore[sheet][index]; - const commonColumnValues = row[commonColumnIndex]?.split(",").map((item) => item.trim()); - if (!commonColumnValues) { - dataCollector.push([...new Array(hierarchy.length).fill(""), ...row]); - continue; - } - for (const value of commonColumnValues) { - const newRowData = [...row]; - newRowData[commonColumnIndex] = value; - dataCollector.push([ - ...(tempBoundaryDataAgainstBoundaryCode[value] - ? tempBoundaryDataAgainstBoundaryCode[value] - : index !== 0 - ? new Array(hierarchy.length).fill("") - : []), - ...newRowData, - ]); - } - } - tempFileDataToStore[sheet] = dataCollector; - } - - tempFileDataToStore[sheet][0] = [...hierarchy, ...tempFileDataToStore[sheet][0]]; - } - } - } catch (error) { - console.error("Error in boundary adding operaiton: ", error); - } - tempFileDataToStore = addMissingPropertiesToFileData(tempFileDataToStore, missingProperties); - return { check, errors, errorMsg, fileDataToStore: tempFileDataToStore, tempResourceMappingData, toast, additionalSheets }; - } catch (error) { - console.error("Error in handling Excel file:", error.message); - } -}; -export const addMissingPropertiesToFileData = (data, missingProperties) => { - if (!data || !missingProperties) return data; - let tempData = {}; - Object.entries(data).forEach(([key, value], index) => { - const filteredMissingProperties = [...missingProperties]?.reduce((acc, item) => { - if (!value?.[0]?.includes(item)) { - acc.push(item); - } - return acc; - }, []); - const newTempHeaders = value?.[0].length !== 0 ? [...value[0], ...filteredMissingProperties] : [...filteredMissingProperties]; - tempData[key] = [newTempHeaders, ...value.slice(1)]; - }); - return tempData; -}; - -export const handleGeojsonFile = async (file, schemaData, setUploadedFileError, t) => { - // Reading and checking geojson data - const data = await readGeojson(file, t); - if (!data.valid) { - return { check: false, stopUpload: true, toast: data.toast }; - } - - // Running geojson validaiton on uploaded file - let response = geojsonValidations(data.geojsonData, schemaData.schema, t); - if (!response.valid) setUploadedFileError(response.message); - let check = response.valid; - let error = response.message; - let fileDataToStore = data.geojsonData; - return { check, error, fileDataToStore }; -}; - -const generateLocalisationKeyForSchemaProperties = (code) => { - if (!code) return code; - return `${SCHEMA_PROPERTIES_PREFIX}_${code}`; -}; -export const handleShapefiles = async (file, schemaData, setUploadedFileError, selectedFileType, setToast, t) => { - // Reading and validating the uploaded geojson file - let response = await readAndValidateShapeFiles(file, t, selectedFileType["namingConvention"]); - if (!response.valid) { - setUploadedFileError(response.message); - setToast(response.toast); - } - let check = response.valid; - let error = response.message; - let fileDataToStore = response.data; - return { check, error, fileDataToStore }; -}; - -export const convertToSheetArray = (data) => { - if (!data) return []; - const convertedSheetData = []; - for (const [key, value] of Object.entries(data)) { - convertedSheetData.push({ sheetName: key, data: value }); - } - return convertedSheetData; -}; - -//find guideline -export const findGuideLine = (campaignType, type, section, guidelineArray) => { - if (!guidelineArray) return guidelineArray; - return guidelineArray.find( - (guideline) => - guideline.fileType === type && guideline.templateIdentifier === section && (!guideline.campaignType || guideline.campaignType === campaignType) - )?.guidelines; -}; - -// Utility function to introduce a delay -export const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/AttendanceActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/AttendanceActionModal.js deleted file mode 100644 index a2c50215207..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/AttendanceActionModal.js +++ /dev/null @@ -1,133 +0,0 @@ -import React, { useState, useEffect } from "react"; -import _ from "lodash"; -import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; -import { configAttendanceApproveModal, configAttendanceRejectModal, configAttendanceCheckModal } from "../config"; - - -const Heading = (props) => { - return

{props.label}

; -}; - -const Close = () => ( - - - - -); - -const CloseBtn = (props) => { - return ( -
- -
- ); -}; - -const AttendanceActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode,applicationDetails,workflowDetails, saveAttendanceState}) => { - const [config, setConfig] = useState({}); - - const userUuid = Digit.UserService.getUser()?.info.uuid; - const { isLoading, data:employeeData } = Digit.Hooks.hrms.useHRMSSearch( - { uuids : userUuid }, tenantId - ); - - const empData = employeeData?.Employees[0] - const empDepartment = empData?.assignments?.[0].department - const empDesignation = empData?.assignments?.[0].designation - const empName = empData?.user?.name - - useEffect(() => { - const selectedAction = action?.action - switch(selectedAction) { - case "VERIFY": - submitBasedOnAction(action, 'Verify muster roll') - break; - case "REJECT": - setConfig( - configAttendanceRejectModal({ - t, - action, - empDepartment, - empDesignation, - empName - }) - ) - break; - case "APPROVE": - setConfig( - configAttendanceApproveModal({ - t, - action - }) - ) - break; - case "RESUBMIT": - submitBasedOnAction(action, 'Resubmit muster roll') - break; - case "SAVE": - submitBasedOnAction(action, 'Verify muster roll') - break; - default: - break - } - }, [employeeData]); - - function onSubmit (data) { - submitBasedOnAction(action, data?.comments) - } - - const submitBasedOnAction = (action, comments) => { - let musterRoll = { tenantId, id: applicationDetails?.applicationDetails?.[0]?.applicationData?.id} - let workflow = { action: action?.action, comments: (comments || `${action?.action} done`), assignees: [] } - - const selectedAction = action?.action - switch(selectedAction) { - case "SAVE": - musterRoll.individualEntries = saveAttendanceState?.updatePayload - workflow.action = 'VERIFY' - break; - case "RESUBMIT": - musterRoll.additionalDetails = { computeAttendance : true } - break; - default: - break; - } - const dataTobeSubmitted = {musterRoll, workflow} - submitAction(dataTobeSubmitted) - } - - const cardStyle = () => { - if(config.label.heading === "Processing Details") { - return { - "padding" : "0px" - } - } - return {} - } - - return action && config?.form ? ( - } - headerBarEnd={} - actionCancelLabel={t(config.label.cancel)} - actionCancelOnSubmit={closeModal} - actionSaveLabel={t(config.label.submit)} - actionSaveOnSubmit={() => {}} - formId="modal-action" - > - - - ) : ( - - ); -} - -export default AttendanceActionModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAActionModal.js deleted file mode 100644 index 269bbefa1dd..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAActionModal.js +++ /dev/null @@ -1,283 +0,0 @@ -import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; -import React, { useState, useEffect } from "react"; -import { useQueryClient } from "react-query"; -import { configBPAApproverApplication } from "../config"; -import * as predefinedConfig from "../config"; - -const Heading = (props) => { - return

{props.label}

; -}; - -const Close = () => ( - - - - -); - -const CloseBtn = (props) => { - return ( -
- -
- ); -}; - -const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationDetails, applicationData, businessService, moduleCode,workflowDetails }) => { - const mutation1 = Digit.Hooks.obps.useObpsAPI( - applicationData?.landInfo?.address?.city ? applicationData?.landInfo?.address?.city : tenantId, - false - ); - const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( - tenantId, - { - roles: workflowDetails?.data?.initialActionState?.nextActions?.filter(ele=>ele?.action==action?.action)?.[0]?.assigneeRoles?.map(role=>({code:role})), - isActive: true, - }, - { enabled: !action?.isTerminateState } - ); - - const queryClient = useQueryClient(); - const [config, setConfig] = useState({}); - const [defaultValues, setDefaultValues] = useState({}); - const [approvers, setApprovers] = useState([]); - const [selectedApprover, setSelectedApprover] = useState({}); - const [file, setFile] = useState(null); - const [uploadedFile, setUploadedFile] = useState(null); - const [error, setError] = useState(null); - const [selectedFinancialYear, setSelectedFinancialYear] = useState(null); - const mobileView = Digit.Utils.browser.isMobile() ? true : false; - - useEffect(() => { - setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); - }, [approverData]); - - function selectFile(e) { - setFile(e.target.files[0]); - } - - useEffect(() => { - (async () => { - setError(null); - if (file) { - const allowedFileTypesRegex = /(.*?)(jpg|jpeg|png|image|pdf)$/i - if (file.size >= 5242880) { - setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); - } else if (file?.type && !allowedFileTypesRegex.test(file?.type)) { - setError(t(`NOT_SUPPORTED_FILE_TYPE`)) - } else { - try { - const response = await Digit.UploadServices.Filestorage("OBPS", file, Digit.ULBService.getStateId() || tenantId?.split(".")[0]); - if (response?.data?.files?.length > 0) { - setUploadedFile(response?.data?.files[0]?.fileStoreId); - } else { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } catch (err) { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } - } - })(); - }, [file]); - - const getInspectionDocs = (docs) => { - let refinedDocs = []; - docs && docs.map((doc,ind) => { - refinedDocs.push({ - "documentType":(doc.documentType+"_"+doc.documentType.split("_")[1]).replaceAll("_","."), - "fileStoreId":doc.fileStoreId, - "fileStore":doc.fileStoreId, - "fileName":"", - "dropDownValues": { - "value": (doc.documentType+"_"+doc.documentType.split("_")[1]).replaceAll("_","."), - } - }) - }) - return refinedDocs; - } - - const getQuestion = (data) => { - let refinedQues = []; - var i; - for(i=0; i { - let formdata = [], inspectionOb = []; - - if (data?.additionalDetails?.fieldinspection_pending?.length > 0) { - inspectionOb = data?.additionalDetails?.fieldinspection_pending - } - - if(data.status == "FIELDINSPECTION_INPROGRESS") { - formdata = JSON.parse(sessionStorage.getItem("INSPECTION_DATA")); - formdata?.length > 0 && formdata.map((ob,ind) => { - inspectionOb.push({ - docs: getInspectionDocs(ob.Documents), - date: ob.InspectionDate, - questions: getQuestion(ob), - time: ob?.InspectionTime, - }) - }) - inspectionOb = inspectionOb.filter((ob) => ob.docs && ob.docs.length>0); - } else { - sessionStorage.removeItem("INSPECTION_DATA") - } - - let fieldinspection_pending = [ ...inspectionOb]; - return fieldinspection_pending; - } - - const getDocuments = (applicationData) => { - let documentsformdata = JSON.parse(sessionStorage.getItem("BPA_DOCUMENTS")); - let documentList = []; - documentsformdata.map(doc => { - if(doc?.uploadedDocuments?.[0]?.values?.length > 0) documentList = [...documentList, ...doc?.uploadedDocuments?.[0]?.values]; - if(doc?.newUploadedDocs?.length > 0) documentList = [...documentList, ...doc?.newUploadedDocs] - }); - return documentList; - } - - const getPendingApprovals = () => { - const approvals = Digit.SessionStorage.get("OBPS_APPROVAL_CHECKS"); - const newApprovals = Digit.SessionStorage.get("OBPS_NEW_APPROVALS"); - let result = approvals?.reduce((acc, approval) => approval?.checked ? acc.push(approval?.label) && acc : acc, []); - result = result?.concat(newApprovals !== null?newApprovals.filter(ob => ob.label !== "").map(approval => approval?.label):[]); - return result; - } - - function submit(data) { - let workflow = { action: action?.action, comments: data?.comments, businessService, moduleName: moduleCode }; - applicationData = { - ...applicationData, - documents: getDocuments(applicationData), - additionalDetails: {...applicationData?.additionalDetails, fieldinspection_pending:getfeildInspection(applicationData), pendingapproval: getPendingApprovals() }, - workflow:{ - action: action?.action, - comment: data?.comments?.length > 0 ? data?.comments : null, - comments: data?.comments?.length > 0 ? data?.comments : null, - assignee: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], - assignes: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], - varificationDocuments: uploadedFile - ? [ - { - documentType: action?.action + " DOC", - fileName: file?.name, - fileStoreId: uploadedFile, - }, - ] - : null, - }, - action: action?.action, - comment: data?.comments, - assignee: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], - wfDocuments: uploadedFile - ? [ - { - documentType: action?.action + " DOC", - fileName: file?.name, - fileStoreId: uploadedFile, - }, - ] - : null, - }; - - const nocDetails = applicationDetails?.nocData?.map(noc => { - const uploadedDocuments = Digit.SessionStorage.get(noc?.nocType) || []; - return { - Noc: { - ...noc, - documents: [ - ...(noc?.documents?noc?.documents:[]), - ...(uploadedDocuments?uploadedDocuments:[]) - ] - } - } - }) - - let nocData = []; - if (nocDetails) { - nocDetails.map(noc => { - if ( - noc?.Noc?.applicationStatus?.toUpperCase() != "APPROVED" && - noc?.Noc?.applicationStatus?.toUpperCase() != "AUTO_APPROVED" && - noc?.Noc?.applicationStatus?.toUpperCase() != "REJECTED" && - noc?.Noc?.applicationStatus?.toUpperCase() != "AUTO_REJECTED" && - noc?.Noc?.applicationStatus?.toUpperCase() != "VOIDED" - ) { - nocData.push(noc); - } - }) - } - - submitAction({ - BPA:applicationData - }, nocData?.length > 0 ? nocData : false, {isStakeholder: false, bpa: true}); - } - - - useEffect(() => { - if (action) { - setConfig( - configBPAApproverApplication({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - businessService, - assigneeLabel: "WF_ASSIGNEE_NAME_LABEL", - error - }) - ); - } - }, [action, approvers, selectedFinancialYear, uploadedFile, error]); - - return action && config.form ? ( - } - headerBarEnd={} - actionCancelLabel={t(config.label.cancel)} - actionCancelOnSubmit={closeModal} - actionSaveLabel={t(config.label.submit)} - actionSaveOnSubmit={() => { }} - formId="modal-action" - isOBPSFlow={true} - popupStyles={mobileView?{width:"720px"}:{}} - style={!mobileView?{minHeight: "45px", height: "auto", width:"107px",paddingLeft:"0px",paddingRight:"0px"}:{minHeight: "45px", height: "auto",width:"44%"}} - popupModuleMianStyles={mobileView?{paddingLeft:"5px"}: {}} - > - {PTALoading ? ( - - ) : ( - - )} - - ) : ( - - ); -}; - -export default ActionModal; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAREGActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAREGActionModal.js deleted file mode 100644 index dc0bfe07776..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/BPAREGActionModal.js +++ /dev/null @@ -1,153 +0,0 @@ -import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; -import React, { useState, useEffect } from "react"; -import { configBPAREGApproverApplication } from "../config"; -import * as predefinedConfig from "../config"; - -const Heading = (props) => { - return

{props.label}

; -}; - -const Close = () => ( - - - - -); - -const CloseBtn = (props) => { - return ( -
- -
- ); -}; - -const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode }) => { - const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( - tenantId, - { - roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), - isActive: true, - }, - { enabled: !action?.isTerminateState } - ); - - const [config, setConfig] = useState({}); - const [defaultValues, setDefaultValues] = useState({}); - const [approvers, setApprovers] = useState([]); - const [selectedApprover, setSelectedApprover] = useState({}); - const [file, setFile] = useState(null); - const [uploadedFile, setUploadedFile] = useState(null); - const [error, setError] = useState(null); - const mobileView = Digit.Utils.browser.isMobile() ? true : false; - - useEffect(() => { - setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); - }, [approverData]); - - function selectFile(e) { - setFile(e.target.files[0]); - } - - useEffect(() => { - (async () => { - setError(null); - if (file) { - const allowedFileTypesRegex = /(.*?)(jpg|jpeg|png|image|pdf)$/i - if (file.size >= 5242880) { - setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); - } else if (file?.type && !allowedFileTypesRegex.test(file?.type)) { - setError(t(`NOT_SUPPORTED_FILE_TYPE`)) - } else { - try { - const response = await Digit.UploadServices.Filestorage("OBPS", file, Digit.ULBService.getStateId() || tenantId?.split(".")[0]); - if (response?.data?.files?.length > 0) { - setUploadedFile(response?.data?.files[0]?.fileStoreId); - } else { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } catch (err) { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } - } - })(); - }, [file]); - - function submit(data) { - let workflow = { action: action?.action, comments: data?.comments, businessService, moduleName: moduleCode }; - applicationData = { - ...applicationData, - action: action?.action, - comment: data?.comments, - assignee: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], - wfDocuments: uploadedFile - ? [ - { - documentType: action?.action + " DOC", - fileName: file?.name, - fileStoreId: uploadedFile, - }, - ] - : null, - }; - submitAction({ - Licenses: [applicationData], - }, false, {isStakeholder: true, bpa: false}); - } - - useEffect(() => { - if (action) { - setConfig( - configBPAREGApproverApplication({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - businessService, - error - }) - ); - } - }, [action, approvers, uploadedFile, error]); - - return action && config.form ? ( - } - headerBarEnd={} - actionCancelLabel={t(config.label.cancel)} - actionCancelOnSubmit={closeModal} - actionSaveLabel={t(config.label.submit)} - actionSaveOnSubmit={() => { }} - formId="modal-action" - isOBPSFlow={true} - popupStyles={mobileView?{width:"720px"}:{}} - style={!mobileView?{height: "45px", width:"107px",paddingLeft:"0px",paddingRight:"0px"}:{height:"45px",width:"44%"}} - popupModuleMianStyles={mobileView?{paddingLeft:"5px"}: {}} - > - {PTALoading ? ( - - ) : ( - - )} - - ) : ( - - ); -}; - -export default ActionModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/ExpenditureActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/ExpenditureActionModal.js deleted file mode 100644 index 95393b5ae05..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/ExpenditureActionModal.js +++ /dev/null @@ -1,190 +0,0 @@ -import { Loader, Modal, FormComposer, WorkflowModal } from "@egovernments/digit-ui-react-components"; -import React, { useState, useEffect, Fragment } from "react"; -import { configViewBillApproveModal, configViewBillRejectModal, configViewBillCheckModal } from "../config"; -import _ from "lodash"; - -const Heading = (props) => { - return

{props.label}

; -}; - -const Close = () => ( - - - - -); - -const CloseBtn = (props) => { - return ( -
- -
- ); -}; - -const ExpenditureActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode,applicationDetails,workflowDetails }) => { - - let { loiNumber, estimateNumber } = Digit.Hooks.useQueryParams(); - const [config, setConfig] = useState({}); - const [defaultValues, setDefaultValues] = useState({}); - const [approvers, setApprovers] = useState([]); - const [selectedApprover, setSelectedApprover] = useState({}); - - const [department, setDepartment] = useState([]); - const [selectedDept,setSelectedDept] = useState({}) - - const [designation, setDesignation] = useState([]); - const [selectedDesignation,setSelectedDesignation] = useState({}) - - const mdmsConfig = { - moduleName: "common-masters", - department : { - masterName: "Department", - localePrefix: "COMMON_MASTERS_DEPARTMENT", - }, - designation : { - masterName: "Designation", - localePrefix: "COMMON_MASTERS_DESIGNATION", - } - } - - const { isLoading: mdmsLoading, data: mdmsData,isSuccess:mdmsSuccess } = Digit.Hooks.useCustomMDMS( - Digit.ULBService.getStateId(), - mdmsConfig?.moduleName, - [{name : mdmsConfig?.designation?.masterName}, {name : mdmsConfig?.department?.masterName}, {name : mdmsConfig?.rejectReasons?.masterName}], - { - select: (data) => { - let designationData = _.get(data, `${mdmsConfig?.moduleName}.${mdmsConfig?.designation?.masterName}`, []); - designationData = designationData.filter((opt) => opt?.active).map((opt) => ({ ...opt, name: `${mdmsConfig?.designation?.localePrefix}_${opt.code}` })); - designationData?.map(designation => {designation.i18nKey = designation?.name}) - - let departmentData = _.get(data, `${mdmsConfig?.moduleName}.${mdmsConfig?.department?.masterName}`, []); - departmentData = departmentData.filter((opt) => opt?.active).map((opt) => ({ ...opt, name: `${mdmsConfig?.department?.localePrefix}_${opt.code}` })); - departmentData?.map(department => { department.i18nKey = department?.name}) - - return {designationData, departmentData}; - }, - enabled: mdmsConfig?.moduleName ? true : false, - } - ); - useEffect(() => { - setDepartment(mdmsData?.departmentData) - setDesignation(mdmsData?.designationData) - }, [mdmsData]); - - - - const { isLoading: approverLoading, isError, error, data: employeeDatav1 } = Digit.Hooks.hrms.useHRMSSearch({ designations: selectedDesignation?.code, departments: selectedDept?.code, roles: action?.assigneeRoles?.toString(), isActive: true }, Digit.ULBService.getCurrentTenantId(), null, null, { enabled: action?.action === "CHECK" || action?.action === "TECHNICALSANCATION"}); - - - employeeDatav1?.Employees.map(emp => emp.nameOfEmp = emp?.user?.name || "NA") - - useEffect(() => { - setApprovers(employeeDatav1?.Employees?.length > 0 ? employeeDatav1?.Employees.filter(emp => emp?.nameOfEmp !== "NA") : []) - }, [employeeDatav1]) - - useEffect(() => { - - if(action?.action?.includes("CHECK")){ - setConfig( - configViewBillCheckModal({ - t, - action, - businessService, - approvers, - selectedApprover, - setSelectedApprover, - designation, - selectedDesignation, - setSelectedDesignation, - department, - selectedDept, - setSelectedDept, - approverLoading - }) - ) - }else if(action?.action?.includes("APPROVE")){ - setConfig( - configViewBillApproveModal({ - t, - action - }) - ) - } - else if(action?.action?.includes("REJECT")){ - setConfig( - configViewBillRejectModal({ - t, - action, - }) - ) - } - }, [approvers,designation,department]); - - const dummy_exp_response = { - CHECK : { - header: "Bill Forwarded Successfully", - id: "Bill/2021-22/09/0001", - info: "Bill ID", - message: "Bill has been successfully created and forwarded for approval.", - responseData:{}, - requestData:{}, - links : [] - }, - REJECT : { - header: "Bill Rejected Successfully", - id: "Bill/2021-22/09/0001", - info: "Bill ID", - message: "Bill has been Rejected.", - responseData:{}, - requestData:{}, - links : [] - }, - APPROVE : { - header: "Bill Approved Successfully", - id: "Bill/2021-22/09/0001", - info: "Bill ID", - message: "Bill has been approved", - responseData:{}, - requestData:{}, - links : [] - } - } - - - function submit (_data) { - const workflow = { - action: action?.action, - comment: _data?.comments, - response : dummy_exp_response, - type : "bills", - assignees: selectedApprover?.uuid ? [selectedApprover?.uuid] : undefined - } - submitAction({workflow}); - } - - const cardStyle = () => { - if(config.label.heading === "Processing Details") { - return { - "padding" : "0px" - } - } - return {} - } - - return ( - <> - { - action && config?.form ? - - : - mdmsLoading ? - : null - } - ) -} - -export default ExpenditureActionModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/FSMActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/FSMActionModal.js deleted file mode 100644 index af0e0e8e701..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/FSMActionModal.js +++ /dev/null @@ -1,298 +0,0 @@ -import { Loader, Modal, FormComposer, Toast } from "@egovernments/digit-ui-react-components"; -import React, { useState, useEffect } from "react"; -import { useQueryClient } from "react-query"; - -import { configAssignDso, configCompleteApplication, configReassignDSO, configAcceptDso, configRejectApplication } from "../config"; - -const Heading = (props) => { - return

{props.label}

; -}; - -const Close = () => ( - - - - -); - -const CloseBtn = (props) => { - return ( -
- -
- ); -}; - -const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData }) => { - const { data: dsoData, isLoading: isDsoLoading, isSuccess: isDsoSuccess, error: dsoError } = Digit.Hooks.fsm.useDsoSearch(tenantId); - const { isLoading, isSuccess, isError, data: applicationData, error } = Digit.Hooks.fsm.useSearch( - tenantId, - { applicationNos: id }, - { - staleTime: Infinity, - select: (details) => { - let { additionalDetails } = details; - - const parseTillObject = (str) => { - if (typeof str === "object") return str; - else return parseTillObject(JSON.parse(str)); - }; - - additionalDetails = parseTillObject(additionalDetails); - return { ...details, additionalDetails }; - }, - } - ); - const client = useQueryClient(); - const stateCode = Digit.ULBService.getStateId(); - const { data: vehicleList, isLoading: isVehicleData, isSuccess: isVehicleDataLoaded } = Digit.Hooks.fsm.useMDMS( - stateCode, - "Vehicle", - "VehicleType", - { staleTime: Infinity } - ); - const [dsoList, setDsoList] = useState([]); - const [vehicleNoList, setVehicleNoList] = useState([]); - const [config, setConfig] = useState({}); - const [dso, setDSO] = useState(null); - const [vehicleNo, setVehicleNo] = useState(null); - const [vehicleMenu, setVehicleMenu] = useState([]); - const [vehicle, setVehicle] = useState(null); - const [defaultValues, setDefautValue] = useState({ - capacity: vehicle?.capacity, - wasteCollected: vehicle?.capacity, - }); - // const [toastError, setToastError] = useState(false); - const { data: Reason, isLoading: isReasonLoading } = Digit.Hooks.fsm.useMDMS(stateCode, "FSM", "Reason", { staleTime: Infinity }, [ - "ReassignReason", - "RejectionReason", - "DeclineReason", - "CancelReason", - ]); - - const [reassignReason, selectReassignReason] = useState(null); - const [rejectionReason, setRejectionReason] = useState(null); - const [declineReason, setDeclineReason] = useState(null); - const [cancelReason, selectCancelReason] = useState(null); - - const [formValve, setFormValve] = useState(false); - - useEffect(() => { - if (isSuccess && isVehicleDataLoaded) { - const [vehicle] = vehicleList.filter((item) => item.code === applicationData.vehicleType); - setVehicleMenu([vehicle]); - setVehicle(vehicle); - setDefautValue({ - capacity: vehicle?.capacity, - wasteCollected: vehicle?.capacity, - }); - } - }, [isVehicleDataLoaded, isSuccess]); - - useEffect(() => { - if (vehicle && isDsoSuccess) { - const dsoList = dsoData.filter((dso) => dso.vehicles.find((dsoVehicle) => dsoVehicle.type === vehicle.code)); - setDsoList(dsoList); - } - }, [vehicle, isDsoSuccess]); - - useEffect(() => { - if (isSuccess && isDsoSuccess && applicationData.dsoId) { - const [dso] = dsoData.filter((dso) => dso.id === applicationData.dsoId); - const vehicleNoList = dso.vehicles.filter((vehicle) => vehicle.type === applicationData.vehicleType); - setVehicleNoList(vehicleNoList); - } - }, [isSuccess, isDsoSuccess]); - - useEffect(() => { - reassignReason || (actionData && actionData[0] && actionData[0].comment?.length > 0) ? setFormValve(true) : setFormValve(false); - }, [reassignReason]); - - useEffect(() => { - setFormValve(rejectionReason ? true : false); - }, [rejectionReason]); - - useEffect(() => { - setFormValve(declineReason ? true : false); - }, [declineReason]); - - useEffect(() => { - setFormValve(cancelReason ? true : false); - }, [cancelReason]); - - function selectDSO(dsoDetails) { - setDSO(dsoDetails); - } - - function selectVehicleNo(vehicleNo) { - setVehicleNo(vehicleNo); - } - - function selectVehicle(value) { - setVehicle(value); - setDefautValue({ - capacity: value?.capacity, - wasteCollected: value?.capacity, - }); - } - - function addCommentToWorkflow(state, workflow, data) { - workflow.comments = data.comments ? state.code + "~" + data.comments : state.code; - } - - function submit(data) { - const workflow = { action: action }; - - if (dso) applicationData.dsoId = dso.id; - if (vehicleNo && action === "ACCEPT") applicationData.vehicleId = vehicleNo.id; - if (vehicleNo && action === "DSO_ACCEPT") applicationData.vehicleId = vehicleNo.id; - if (vehicle && action === "ASSIGN") applicationData.vehicleType = vehicle.code; - if (data.date) applicationData.possibleServiceDate = new Date(`${data.date}`).getTime(); - if (data.desluged) applicationData.completedOn = new Date(data.desluged).getTime(); - if (data.wasteCollected) applicationData.wasteCollected = data.wasteCollected; - if (reassignReason) addCommentToWorkflow(reassignReason, workflow, data); - if (rejectionReason) addCommentToWorkflow(rejectionReason, workflow, data); - if (declineReason) addCommentToWorkflow(declineReason, workflow, data); - if (cancelReason) addCommentToWorkflow(cancelReason, workflow, data); - - submitAction({ fsm: applicationData, workflow }); - } - useEffect(() => { - switch (action) { - case "DSO_ACCEPT": - case "ACCEPT": - setFormValve(vehicleNo ? true : false); - return setConfig( - configAcceptDso({ - t, - dsoData, - dso, - vehicle, - vehicleNo, - vehicleNoList, - selectVehicleNo, - action, - }) - ); - - case "ASSIGN": - case "GENERATE_DEMAND": - case "FSM_GENERATE_DEMAND": - setFormValve(dso && vehicle ? true : false); - return setConfig( - configAssignDso({ - t, - dsoData, - dso, - selectDSO, - vehicleMenu, - vehicle, - selectVehicle, - action, - }) - ); - case "REASSIGN": - case "REASSING": - case "FSM_REASSING": - dso && vehicle && (reassignReason || (actionData && actionData[0] && actionData[0].comment?.length > 0)) - ? setFormValve(true) - : setFormValve(false); - return setConfig( - configReassignDSO({ - t, - dsoData, - dso, - selectDSO, - vehicleMenu, - vehicle, - selectVehicle, - reassignReasonMenu: Reason?.ReassignReason, - reassignReason, - selectReassignReason, - action, - showReassignReason: actionData && actionData[0] && actionData[0].comment?.length > 0 ? false : true, - }) - ); - case "COMPLETE": - case "COMPLETED": - setFormValve(true); - return setConfig(configCompleteApplication({ t, vehicle, applicationCreatedTime: applicationData?.auditDetails?.createdTime, action })); - case "SUBMIT": - case "FSM_SUBMIT": - return history.push(`/${window?.contextPath}/employee/fsm/modify-application/` + applicationNumber); - case "DECLINE": - case "DSO_REJECT": - //declinereason - setFormValve(declineReason ? true : false); - return setConfig( - configRejectApplication({ - t, - rejectMenu: Reason?.DeclineReason, - setReason: setDeclineReason, - reason: declineReason, - action, - }) - ); - case "REJECT": - case "SENDBACK": - // rejectionReason - setFormValve(rejectionReason ? true : false); - return setConfig( - configRejectApplication({ - t, - rejectMenu: Reason?.RejectionReason, - setReason: setRejectionReason, - reason: rejectionReason, - action, - }) - ); - case "CANCEL": - ///cancellreason - setFormValve(cancelReason ? true : false); - return setConfig( - configRejectApplication({ - t, - rejectMenu: Reason?.CancelReason, - setReason: selectCancelReason, - reason: cancelReason, - action, - }) - ); - - case "PAY": - case "ADDITIONAL_PAY_REQUEST": - case "FSM_PAY": - return history.push(`/${window?.contextPath}/employee/payment/collect/FSM.TRIP_CHARGES/${applicationNumber}`); - default: - break; - } - }, [action, isDsoLoading, dso, vehicleMenu, rejectionReason, vehicleNo, vehicleNoList, Reason]); - - return action && config.form && !isDsoLoading && !isReasonLoading && isVehicleDataLoaded ? ( - } - headerBarEnd={} - actionCancelLabel={t(config.label.cancel)} - actionCancelOnSubmit={closeModal} - actionSaveLabel={t(config.label.submit)} - actionSaveOnSubmit={() => {}} - formId="modal-action" - isDisabled={!formValve} - > - - {/* {toastError && } */} - - ) : ( - - ); -}; - -export default ActionModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/NOCActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/NOCActionModal.js deleted file mode 100644 index 09266ca1b7b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/NOCActionModal.js +++ /dev/null @@ -1,169 +0,0 @@ -import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; -import React, { useState, useEffect } from "react"; -import { useQueryClient } from "react-query"; -import { useHistory } from "react-router-dom"; -import { configNOCApproverApplication } from "../config"; -import * as predefinedConfig from "../config"; - -const Heading = (props) => { - return

{props.label}

; -}; - -const Close = () => ( - - - - -); - -const CloseBtn = (props) => { - return ( -
- -
- ); -}; - -const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode }) => { - - const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( - tenantId, - { - roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), - isActive: true, - }, - { enabled: !action?.isTerminateState } - ); - - const queryClient = useQueryClient(); - const [config, setConfig] = useState({}); - const [defaultValues, setDefaultValues] = useState({}); - const [approvers, setApprovers] = useState([]); - const [selectedApprover, setSelectedApprover] = useState({}); - const [file, setFile] = useState(null); - const [uploadedFile, setUploadedFile] = useState(null); - const [error, setError] = useState(null); - const mobileView = Digit.Utils.browser.isMobile() ? true : false; - const history = useHistory(); - - useEffect(() => { - setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); - }, [approverData]); - - function selectFile(e) { - setFile(e.target.files[0]); - } - - useEffect(() => { - (async () => { - setError(null); - if (file) { - const allowedFileTypesRegex = /(.*?)(jpg|jpeg|png|image|pdf)$/i - if (file.size >= 5242880) { - setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); - } else if (file?.type && !allowedFileTypesRegex.test(file?.type)) { - setError(t(`NOT_SUPPORTED_FILE_TYPE`)) - } else { - try { - const response = await Digit.UploadServices.Filestorage("NOC", file, Digit.ULBService.getStateId() || tenantId?.split(".")[0]); - if (response?.data?.files?.length > 0) { - setUploadedFile(response?.data?.files[0]?.fileStoreId); - } else { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } catch (err) { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } - } - })(); - }, [file]); - - - function submit(data) { - let enteredDocs = JSON.parse(sessionStorage.getItem("NewNOCDocs")); - let newDocs = applicationData?.documents?.length > 0 ? [...applicationData?.documents] : []; - enteredDocs.map((d,index) => { - newDocs.push(d); - }) - applicationData = { - ...applicationData, - workflow:{ - action: action?.action, - comment: data?.comments ? data?.comments : null, - assignee: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], - documents: uploadedFile - ? [ - { - documentType: action?.action + " DOC", - fileName: file?.name, - fileStoreId: uploadedFile, - }, - ] - : null, - }, - documents: newDocs, - }; - - - submitAction({ - Noc: applicationData, - }, false, {isNoc: true}); - } - - useEffect(() => { - if (action) { - setConfig( - configNOCApproverApplication({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - businessService, - assigneeLabel: "WF_ASSIGNEE_NAME_LABEL", - error - }) - ); - } - }, [action, approvers, uploadedFile, error]); - - return action && config.form ? ( - } - headerBarEnd={} - actionCancelLabel={t(config.label.cancel)} - actionCancelOnSubmit={closeModal} - actionSaveLabel={t(config.label.submit)} - actionSaveOnSubmit={() => { }} - formId="modal-action" - isOBPSFlow={true} - popupStyles={mobileView?{width:"720px"}:{}} - style={!mobileView?{height: "45px", width:"107px",paddingLeft:"0px",paddingRight:"0px"}:{height:"45px",width:"44%"}} - popupModuleMianStyles={mobileView?{paddingLeft:"5px"}: {}} - > - {PTALoading ? ( - - ) : ( - - )} - - ) : ( - - ); -}; - -export default ActionModal; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/PTActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/PTActionModal.js deleted file mode 100644 index 37b3d996177..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/PTActionModal.js +++ /dev/null @@ -1,190 +0,0 @@ -import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; -import React, { useState, useEffect } from "react"; - -import { configPTApproverApplication, configPTAssessProperty } from "../config"; -import * as predefinedConfig from "../config"; - -const Heading = (props) => { - return

{props.label}

; -}; - -const Close = () => ( - - - - -); - -const CloseBtn = (props) => { - return ( -
- -
- ); -}; - -const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode }) => { - const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( - tenantId, - { - roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), - isActive: true, - }, - { enabled: !action?.isTerminateState } - ); - const { isLoading: financialYearsLoading, data: financialYearsData } = Digit.Hooks.pt.useMDMS( - tenantId, - businessService, - "FINANCIAL_YEARLS", - {}, - { - details: { - tenantId: Digit.ULBService.getStateId(), - moduleDetails: [{ moduleName: "egf-master", masterDetails: [{ name: "FinancialYear", filter: "[?(@.module == 'PT')]" }] }], - }, - } - ); - - const [config, setConfig] = useState({}); - const [defaultValues, setDefaultValues] = useState({}); - const [approvers, setApprovers] = useState([]); - const [selectedApprover, setSelectedApprover] = useState(null); - const [file, setFile] = useState(null); - const [uploadedFile, setUploadedFile] = useState(null); - const [error, setError] = useState(null); - const [financialYears, setFinancialYears] = useState([]); - const [selectedFinancialYear, setSelectedFinancialYear] = useState(null); - const [disableActionSubmit, setDisableActionSubmit] = useState(false); - - useEffect(() => { - if (financialYearsData && financialYearsData["egf-master"]) { - setFinancialYears(financialYearsData["egf-master"]?.["FinancialYear"]); - } - }, [financialYearsData]); - - useEffect(() => { - setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); - }, [approverData]); - - function selectFile(e) { - setFile(e.target.files[0]); - } - - useEffect(() => { - (async () => { - setError(null); - if (file) { - if (file.size >= 5242880) { - setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); - } else { - try { - const response = await Digit.UploadServices.Filestorage("PT", file, Digit.ULBService.getStateId()); - if (response?.data?.files?.length > 0) { - setUploadedFile(response?.data?.files[0]?.fileStoreId); - } else { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } catch (err) { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } - } - })(); - }, [file]); - - function submit(data) { - if (!action?.showFinancialYearsModal) { - let workflow = { action: action?.action, comment: data?.comments, businessService, moduleName: moduleCode }; - workflow["assignes"] = action?.isTerminateState || !selectedApprover ? [] : [selectedApprover]; - if (uploadedFile) - workflow["documents"] = [ - { - documentType: action?.action + " DOC", - fileName: file?.name, - fileStoreId: uploadedFile, - }, - ]; - - submitAction({ - Property: { - ...applicationData, - workflow, - }, - }); - } else { - submitAction({ - customFunctionToExecute: action?.customFunctionToExecute, - Assessment: { - financialYear: selectedFinancialYear?.name, - propertyId: applicationData?.propertyId, - tenantId, - source: applicationData?.source, - channel: applicationData?.channel, - assessmentDate: Date.now(), - }, - }); - } - } - - useEffect(() => { - if (action) { - if (action?.showFinancialYearsModal) { - setConfig( - configPTAssessProperty({ - t, - action, - financialYears, - selectedFinancialYear, - setSelectedFinancialYear, - }) - ); - } else { - setConfig( - configPTApproverApplication({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - businessService, - }) - ); - } - } - }, [action, approvers, financialYears, selectedFinancialYear, uploadedFile]); - - return action && config.form ? ( - } - headerBarEnd={} - actionCancelLabel={t(config.label.cancel)} - actionCancelOnSubmit={closeModal} - actionSaveLabel={t(config.label.submit)} - actionSaveOnSubmit={() => {}} - isDisabled={!action.showFinancialYearsModal ? PTALoading || (action?.docUploadRequired && !uploadedFile) : !selectedFinancialYear} - formId="modal-action" - > - {financialYearsLoading ? ( - - ) : ( - - )} - - ) : ( - - ); -}; - -export default ActionModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/TLActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/TLActionModal.js deleted file mode 100644 index f11658a987a..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/TLActionModal.js +++ /dev/null @@ -1,166 +0,0 @@ -import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; -import React, { useState, useEffect } from "react"; - -import { configTLApproverApplication } from "../config"; -import * as predefinedConfig from "../config"; - -const Heading = (props) => { - return

{props.label}

; -}; - -const Close = () => ( - - - - -); - -const CloseBtn = (props) => { - return ( -
- -
- ); -}; - -const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode }) => { - const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( - tenantId, - { - roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), - isActive: true, - }, - { enabled: !action?.isTerminateState } - ); - const { isLoading: financialYearsLoading, data: financialYearsData } = Digit.Hooks.pt.useMDMS( - tenantId, - businessService, - "FINANCIAL_YEARLS", - {}, - { - details: { - tenantId: Digit.ULBService.getStateId(), - moduleDetails: [{ moduleName: "egf-master", masterDetails: [{ name: "FinancialYear", filter: "[?(@.module == 'TL')]" }] }], - }, - } - ); - - const [config, setConfig] = useState({}); - const [defaultValues, setDefaultValues] = useState({}); - const [approvers, setApprovers] = useState([]); - const [selectedApprover, setSelectedApprover] = useState({}); - const [file, setFile] = useState(null); - const [uploadedFile, setUploadedFile] = useState(null); - const [error, setError] = useState(null); - const [financialYears, setFinancialYears] = useState([]); - const [selectedFinancialYear, setSelectedFinancialYear] = useState(null); - - useEffect(() => { - if (financialYearsData && financialYearsData["egf-master"]) { - setFinancialYears(financialYearsData["egf-master"]?.["FinancialYear"]); - } - }, [financialYearsData]); - - useEffect(() => { - setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); - }, [approverData]); - - function selectFile(e) { - setFile(e.target.files[0]); - } - - useEffect(() => { - (async () => { - setError(null); - if (file) { - if (file.size >= 5242880) { - setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); - } else { - try { - const response = await Digit.UploadServices.Filestorage("PT", file, Digit.ULBService.getStateId()); - if (response?.data?.files?.length > 0) { - setUploadedFile(response?.data?.files[0]?.fileStoreId); - } else { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } catch (err) { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } - } - })(); - }, [file]); - - function submit(data) { - let workflow = { action: action?.action, comments: data?.comments, businessService, moduleName: moduleCode }; - applicationData = { - ...applicationData, - action: action?.action, - comment: data?.comments, - assignee: !selectedApprover?.uuid ? null : [selectedApprover?.uuid], - // assignee: action?.isTerminateState ? [] : [selectedApprover?.uuid], - wfDocuments: uploadedFile - ? [ - { - documentType: action?.action + " DOC", - fileName: file?.name, - fileStoreId: uploadedFile, - }, - ] - : null, - }; - submitAction({ - Licenses: [applicationData], - }); - } - - useEffect(() => { - if (action) { - setConfig( - configTLApproverApplication({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - businessService, - }) - ); - } - }, [action, approvers, financialYears, selectedFinancialYear, uploadedFile]); - - return action && config.form ? ( - } - headerBarEnd={} - actionCancelLabel={t(config.label.cancel)} - actionCancelOnSubmit={closeModal} - actionSaveLabel={t(config.label.submit)} - actionSaveOnSubmit={() => {}} - // isDisabled={!action.showFinancialYearsModal ? PTALoading || (!action?.isTerminateState && !selectedApprover?.uuid) : !selectedFinancialYear} - formId="modal-action" - > - {financialYearsLoading ? ( - - ) : ( - - )} - - ) : ( - - ); -}; - -export default ActionModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WNSActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WNSActionModal.js deleted file mode 100644 index eb64a09804b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WNSActionModal.js +++ /dev/null @@ -1,261 +0,0 @@ -import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; -import React, { useState, useEffect } from "react"; -import { configWSApproverApplication, configWSDisConnectApplication } from "../config"; -import * as predefinedConfig from "../config"; -import cloneDeep from "lodash/cloneDeep"; - - -const Heading = (props) => { - return

{props.label}

; -}; - -const Close = () => ( - - - - -); - -const CloseBtn = (props) => { - return ( -
- -
- ); -}; - -const convertDateToEpochNew = (dateString, dayStartOrEnd = "dayend") => { - //example input format : "2018-10-02" - try { - const parts = dateString.match(/(\d{4})-(\d{1,2})-(\d{1,2})/); - const DateObj = new Date(Date.UTC(parts[1], parts[3] - 1, parts[2])); - - DateObj.setMinutes(DateObj.getMinutes() + DateObj.getTimezoneOffset()); - if (dayStartOrEnd === "dayend") { - DateObj.setHours(DateObj.getHours() + 24); - DateObj.setSeconds(DateObj.getSeconds() - 1); - } - return DateObj.getTime(); - } catch (e) { - return dateString; - } -}; - -const ActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode }) => { - const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( - tenantId, - { - roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), - isActive: true, - }, - { enabled: !action?.isTerminateState } - ); - - const [config, setConfig] = useState({}); - const [defaultValues, setDefaultValues] = useState({}); - const [approvers, setApprovers] = useState([]); - const [selectedApprover, setSelectedApprover] = useState({}); - const [file, setFile] = useState(null); - const [uploadedFile, setUploadedFile] = useState(null); - const [error, setError] = useState(null); - - useEffect(() => { - setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); - }, [approverData]); - - function selectFile(e) { - setFile(e.target.files[0]); - } - - useEffect(() => { - (async () => { - setError(null); - if (file) { - const allowedFileTypesRegex = /(.*?)(jpg|jpeg|png|image|pdf)$/i - if (file.size >= 5242880) { - setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); - } else if (file?.type && !allowedFileTypesRegex.test(file?.type)) { - setError(t(`NOT_SUPPORTED_FILE_TYPE`)) - } else { - try { - const response = await Digit.UploadServices.Filestorage("WS", file, Digit.ULBService.getCurrentTenantId()); - if (response?.data?.files?.length > 0) { - setUploadedFile(response?.data?.files[0]?.fileStoreId); - } else { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } catch (err) { - console.error("Modal -> err ", err); - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } - } - })(); - }, [file]); - - function submit(data) { - if(applicationData?.isBillAmend){ - const comments = data?.comments ? data.comments : null - - const additionalDetails = { ...applicationData?.billAmendmentDetails?.additionalDetails, comments } - const amendment = { - ...applicationData?.billAmendmentDetails, - workflow:{ - businessId:applicationData?.billAmendmentDetails?.amendmentId, - action:action?.action, - tenantId:tenantId, - businessService:"BS.AMENDMENT", - moduleName:"BS" - }, - additionalDetails, - comment: data?.comments || "", - wfDocuments: uploadedFile - ? [ - { - documentType: action?.action + " DOC", - fileName: file?.name, - fileStoreId: uploadedFile, - }, - ] - : null, - processInstance: { - action: action?.action, - assignes: !selectedApprover?.uuid ? [] : [{ uuid: selectedApprover?.uuid }], - comment: data?.comments || "", - documents: uploadedFile - ? [ - { - documentType: action?.action + " DOC", - fileName: file?.name, - fileStoreId: uploadedFile, - }, - ] - : [] - } - } - //amendment?.additionalDetails?.comments = comments - submitAction({AmendmentUpdate:amendment}) - return - } - let workflow = { action: action?.action, comments: data?.comments, businessService, moduleName: moduleCode }; - applicationData = { - ...applicationData, - action: action?.action, - comment: data?.comments || "", - assignee: !selectedApprover?.uuid ? [] : [selectedApprover?.uuid], - assignes: !selectedApprover?.uuid ? [] : [{ uuid: selectedApprover?.uuid }], - wfDocuments: uploadedFile - ? [ - { - documentType: action?.action + " DOC", - fileName: file?.name, - fileStoreId: uploadedFile, - }, - ] - : null, - processInstance: { - ...applicationData?.processInstance, - action: action?.action, - assignes: !selectedApprover?.uuid ? [] : [{ uuid: selectedApprover?.uuid }], - comment: data?.comments || "", - documents: uploadedFile - ? [ - { - documentType: action?.action + " DOC", - fileName: file?.name, - fileStoreId: uploadedFile, - }, - ] - : [] - } - }; - - if (data?.date) { - const connectionExecutionDate = cloneDeep(data?.date); - applicationData.connectionExecutionDate = convertDateToEpochNew(connectionExecutionDate) - } - if (applicationData?.processInstance?.businessService == "DisconnectWSConnection" || applicationData?.processInstance?.businessService == "DisconnectSWConnection"){ - applicationData?.serviceType == "WATER" ? - submitAction({ WaterConnection: applicationData, disconnectRequest: true }) : - submitAction({ SewerageConnection: applicationData, disconnectRequest: true }) - } else { - const adhocRebateData = sessionStorage.getItem("Digit.ADHOC_ADD_REBATE_DATA"); - const parsedAdhocRebateData = adhocRebateData ? JSON.parse(adhocRebateData) : ""; - if (parsedAdhocRebateData?.value?.adhocPenalty) applicationData.additionalDetails.adhocPenalty = parseInt(parsedAdhocRebateData?.value?.adhocPenalty) || ""; - if (parsedAdhocRebateData?.value?.adhocPenaltyComment) applicationData.additionalDetails.adhocPenaltyComment = parsedAdhocRebateData?.value?.adhocPenaltyComment || ""; - if (parsedAdhocRebateData?.value?.adhocPenaltyReason) applicationData.additionalDetails.adhocPenaltyReason = parsedAdhocRebateData?.value?.adhocPenaltyReason || ""; - if (parsedAdhocRebateData?.value?.adhocRebate) applicationData.additionalDetails.adhocRebate = parseInt(parsedAdhocRebateData?.value?.adhocRebate) || ""; - if (parsedAdhocRebateData?.value?.adhocRebateComment) applicationData.additionalDetails.adhocRebateComment = parsedAdhocRebateData?.value?.adhocRebateComment || ""; - if (parsedAdhocRebateData?.value?.adhocRebateReason) applicationData.additionalDetails.adhocRebateReason = parsedAdhocRebateData?.value?.adhocRebateReason || ""; - applicationData?.serviceType == "WATER" ? submitAction({ WaterConnection: applicationData }) : submitAction({ SewerageConnection: applicationData }); - } - } - - useEffect(() => { - if (applicationData?.processInstance?.businessService == "DisconnectWSConnection" || applicationData?.processInstance?.businessService == "DisconnectSWConnection") { - if (action) { - setConfig( - configWSDisConnectApplication({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - businessService, - error - }) - ); - } - } else { - if (action) { - setConfig( - configWSApproverApplication({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - businessService, - error - }) - ); - } - } - }, [action, approvers, uploadedFile, error]); - - return action && config.form ? ( - } - headerBarEnd={} - actionCancelLabel={t(config.label.cancel)} - actionCancelOnSubmit={closeModal} - actionSaveLabel={t(config.label.submit)} - actionSaveOnSubmit={() => { }} - formId="modal-action" - > - {PTALoading ? ( - - ) : ( - - )} - - ) : ( - - ); -}; - -export default ActionModal; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WorksActionModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WorksActionModal.js deleted file mode 100644 index dd19cf33a1e..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/WorksActionModal.js +++ /dev/null @@ -1,262 +0,0 @@ -import { Loader, Modal, FormComposer } from "@egovernments/digit-ui-react-components"; -import React, { useState, useEffect } from "react"; -import { configApproveModal, configRejectModal, configCheckModal } from "../config"; - -import cloneDeep from "lodash/cloneDeep"; - - -const Heading = (props) => { - return

{props.label}

; -}; - -const Close = () => ( - - - - -); - -const CloseBtn = (props) => { - return ( -
- -
- ); -}; - -const convertDateToEpochNew = (dateString, dayStartOrEnd = "dayend") => { - //example input format : "2018-10-02" - try { - const parts = dateString.match(/(\d{4})-(\d{1,2})-(\d{1,2})/); - const DateObj = new Date(Date.UTC(parts[1], parts[3] - 1, parts[2])); - - DateObj.setMinutes(DateObj.getMinutes() + DateObj.getTimezoneOffset()); - if (dayStartOrEnd === "dayend") { - DateObj.setHours(DateObj.getHours() + 24); - DateObj.setSeconds(DateObj.getSeconds() - 1); - } - return DateObj.getTime(); - } catch (e) { - return dateString; - } -}; - - -const WorksActionModal = ({ t, action, tenantId, state, id, closeModal, submitAction, actionData, applicationData, businessService, moduleCode,applicationDetails,workflowDetails }) => { - //here according to the action selected render appropriate modal - - // const { data: approverData, isLoading: PTALoading } = Digit.Hooks.useEmployeeSearch( - // tenantId, - // { - // roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), - // isActive: true, - // }, - // { enabled: !action?.isTerminateState } - // ); - let { loiNumber, estimateNumber } = Digit.Hooks.useQueryParams(); - const [config, setConfig] = useState({}); - const [approvers, setApprovers] = useState([]); - const [selectedApprover, setSelectedApprover] = useState({}); - - const [department, setDepartment] = useState([]); - const [selectedDept,setSelectedDept] = useState({}) - - const [rejectionReason, setRejectionReason] = useState([]); - const [selectedReason,setSelectedReason] = useState([]) - - const [designation, setDesignation] = useState([]); - const [selectedDesignation,setSelectedDesignation] = useState({}) - - //get approverDept,designation,approver(hrms),rejectionReason - - const rejectReasons = [ - { - name: "Estimate Details are incorrect" - }, - { - name: "Financial Details are incorrect" - }, - { - name: "Agreement Details are incorrect" - }, - { - name: "Vendor Details are incorrect" - }, - { - name: "Attachments provided are wrong" - }, - { - name: "Others" - }, - ] - - const { isLoading: mdmsLoading, data: mdmsData,isSuccess:mdmsSuccess } = Digit.Hooks.useCustomMDMS( - Digit.ULBService.getCurrentTenantId(), - "common-masters", - [ - { - "name": "Designation" - }, - { - "name": "Department" - } - ] - ); - - mdmsData?.["common-masters"]?.Designation?.map(designation => { - designation.i18nKey = `ES_COMMON_DESIGNATION_${designation?.name}` - }) - - mdmsData?.["common-masters"]?.Department?.map(department => { - department.i18nKey = `ES_COMMON_${department?.code}` - }) - // const { data: approverData, isLoading: approverLoading } = Digit.Hooks.useEmployeeSearch( - // tenantId, - // { - // roles: action?.assigneeRoles?.map?.((e) => ({ code: e })), - // isActive: true, - // }, - // { enabled: !action?.isTerminateState } - // ); - - - // const { isLoading: approverLoading, isError,isSuccess:approverSuccess, error, data: employeeDatav1 } = Digit.Hooks.hrms.useHRMSSearch({ Designation: selectedDesignation?.code, Department: selectedDept?.code }, Digit.ULBService.getCurrentTenantId(), null, null, { enabled: !!(selectedDept?.code && selectedDesignation?.code) }); - // employeeDatav1?.Employees.map(emp => emp.nameOfEmp = emp.user.name) - - - // useEffect(() => { - - // setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); - // }, [approverData]); - - useEffect(() => { - - //setApprovers(approverData?.Employees?.map((employee) => ({ uuid: employee?.uuid, name: employee?.user?.name }))); - //setApprovers(employeeDatav1?.Employees?.length > 0 ? employeeDatav1?.Employees : []) - setDepartment(mdmsData?.["common-masters"]?.Department) - setDesignation(mdmsData?.["common-masters"]?.Designation) - setRejectionReason(rejectReasons) - }, [mdmsData]); - - - - const { isLoading: approverLoading, isError, error, data: employeeDatav1 } = Digit.Hooks.hrms.useHRMSSearch({ designations: selectedDesignation?.code, departments: selectedDept?.code, roles: action?.assigneeRoles?.toString(), isActive: true }, Digit.ULBService.getCurrentTenantId(), null, null, { enabled: action?.action === "CHECK" || action?.action === "TECHNICALSANCATION"}); - - - employeeDatav1?.Employees.map(emp => emp.nameOfEmp = emp?.user?.name || "NA") - - useEffect(() => { - setApprovers(employeeDatav1?.Employees?.length > 0 ? employeeDatav1?.Employees.filter(emp => emp?.nameOfEmp !== "NA") : []) - }, [employeeDatav1]) - - - // if (employeeDatav1?.Employees?.length > 0) { - // setApprovers(employeeDatav1?.Employees) - // } - - useEffect(() => { - - if(action?.action?.includes("CHECK") || action?.action?.includes("TECHNICALSANCATION")){ - setConfig( - configCheckModal({ - t, - action, - businessService, - approvers, - selectedApprover, - setSelectedApprover, - designation, - selectedDesignation, - setSelectedDesignation, - department, - selectedDept, - setSelectedDept, - approverLoading - }) - ) - }else if(action?.action?.includes("APPROVE") || action?.action?.includes("ADMINSANCTION")){ - setConfig( - configApproveModal({ - t, - action - }) - ) - } - else if(action?.action?.includes("REJECT")){ - setConfig( - configRejectModal({ - t, - action, - rejectReasons, - selectedReason, - setSelectedReason, - loiNumber, - department, - estimateNumber - }) - ) - } - }, [approvers,designation,department]); - - - function submit (_data) { - //make the update object here and call submitAction - //if the action is reject then you need to make a search call and get creater's uuid - const workflow = { - action: action?.action, - comment: _data?.comments, - assignees: selectedApprover?.uuid ? [selectedApprover?.uuid] : undefined - } - - if(action?.action.includes("REJECT")) { - workflow.assignee = [applicationData?.auditDetails?.createdBy] - } - - Object.keys(workflow).forEach(key => { - if (workflow[key] === undefined) { - delete workflow[key]; - } - }); - {estimateNumber ? submitAction({estimate:applicationData,workflow}) : - submitAction({letterOfIndent:applicationData,workflow})} - - } - - // if(mdmsLoading || approverLoading ) { - // return - // } - - - - - - return action && config?.form ? ( - } - headerBarEnd={} - actionCancelLabel={t(config.label.cancel)} - actionCancelOnSubmit={closeModal} - actionSaveLabel={t(config.label.submit)} - actionSaveOnSubmit={() => { }} - formId="modal-action" - > - {mdmsLoading ? ( - - ) : ( - - )} - - ) : ( - - ); -} - -export default WorksActionModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/index.js deleted file mode 100644 index 56465790b8b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/Modal/index.js +++ /dev/null @@ -1,49 +0,0 @@ -import React, { useState, useEffect } from "react"; -import FSMActionModal from "./FSMActionModal"; -import PTActionModal from "./PTActionModal"; -import TLActionModal from "./TLActionModal"; -import BPAREGActionModal from "./BPAREGActionModal"; -import BPAActionModal from "./BPAActionModal"; -import NOCActionModal from "./NOCActionModal"; -import WNSActionModal from "./WNSActionModal"; -import WorksActionModal from "./WorksActionModal"; -import AttendanceActionModal from "./AttendanceActionModal"; -import ExpenditureActionModal from "./ExpenditureActionModal"; - -const ActionModal = (props) => { - if (props?.businessService.includes("PT")) { - return ; - } - - if (props?.businessService.includes("NewTL") || props?.businessService.includes("TL") || props?.businessService.includes("EDITRENEWAL") || props?.businessService.includes("DIRECTRENEWAL")) { - return ; - } - - if (props?.moduleCode.includes("BPAREG")) { - return ; - } - - if (props?.moduleCode.includes("BPA")) { - return ; - } - - if (props?.moduleCode.includes("NOC")) { - return ; - } - - if (props?.moduleCode.includes("WS")) { - return ; - } - if (props?.moduleCode.includes("works")) { - return ; - } - if (props?.moduleCode.includes("AttendenceMgmt")) { - return ; - } - if (props?.moduleCode.includes("Expenditure")) { - return ; - } - -}; - -export default ActionModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsActionBar.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsActionBar.js deleted file mode 100644 index 7ad3a0f95ce..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsActionBar.js +++ /dev/null @@ -1,80 +0,0 @@ -import React, {useEffect, useRef} from "react"; -import { useTranslation } from "react-i18next"; -import { SubmitBar, ActionBar, Menu } from "@egovernments/digit-ui-react-components"; - -function ApplicationDetailsActionBar({ workflowDetails, displayMenu, onActionSelect, setDisplayMenu, businessService, forcedActionPrefix,ActionBarStyle={},MenuStyle={}, saveAttendanceState }) { - const { t } = useTranslation(); - let user = Digit.UserService.getUser(); - const menuRef = useRef(); - if (window.location.href.includes("/obps") || window.location.href.includes("/noc")) { - const userInfos = sessionStorage.getItem("Digit.citizen.userRequestObject"); - const userInfo = userInfos ? JSON.parse(userInfos) : {}; - user = userInfo?.value; - } - const userRoles = user?.info?.roles?.map((e) => e.code); - let isSingleButton = false; - let isMenuBotton = false; - let actions = workflowDetails?.data?.actionState?.nextActions?.filter((e) => { - return userRoles.some((role) => e.roles?.includes(role)) || !e.roles; - }) || workflowDetails?.data?.nextActions?.filter((e) => { - return userRoles.some((role) => e.roles?.includes(role)) || !e.roles; - }); - - const closeMenu = () => { - setDisplayMenu(false); - } - Digit.Hooks.useClickOutside(menuRef, closeMenu, displayMenu ); - - if (((window.location.href.includes("/obps") || window.location.href.includes("/noc")) && actions?.length == 1) || (actions?.[0]?.redirectionUrl?.pathname.includes("/pt/property-details/")) && actions?.length == 1) { - isMenuBotton = false; - isSingleButton = true; - } else if (actions?.length > 0) { - isMenuBotton = true; - isSingleButton = false; - } - - if(saveAttendanceState?.displaySave) { - isMenuBotton = false; - isSingleButton = true; - actions = [ - { - action: "SAVE", - state: "UPDATED" - } - ] - } - - return ( - - {!workflowDetails?.isLoading && isMenuBotton && !isSingleButton && ( - - {displayMenu && (workflowDetails?.data?.actionState?.nextActions || workflowDetails?.data?.nextActions) ? ( - - ) : null} - setDisplayMenu(!displayMenu)} /> - - )} - {!workflowDetails?.isLoading && !isMenuBotton && isSingleButton && ( - - - - )} - - ); -} - -export default ApplicationDetailsActionBar; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsContent.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsContent.js deleted file mode 100644 index 5596d7b694b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsContent.js +++ /dev/null @@ -1,484 +0,0 @@ -import { - BreakLine, - Card, - CardSectionHeader, - CardSubHeader, - CheckPoint, - CollapseAndExpandGroups, - ConnectingCheckPoints, - ViewImages, - Loader, - Row, - StatusTable, - Table, -} from "@egovernments/digit-ui-react-components"; -import { values } from "lodash"; -import React, { Fragment, useCallback, useReducer, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { Link } from "react-router-dom"; -import BPADocuments from "./BPADocuments"; -import InspectionReport from "./InspectionReport"; -import NOCDocuments from "./NOCDocuments"; -import PermissionCheck from "./PermissionCheck"; -import PropertyDocuments from "./PropertyDocuments"; -import PropertyEstimates from "./PropertyEstimates"; -import PropertyFloors from "./PropertyFloors"; -import PropertyOwners from "./PropertyOwners"; -import ScruntinyDetails from "./ScruntinyDetails"; -import SubOccupancyTable from "./SubOccupancyTable"; -import TLCaption from "./TLCaption"; -import TLTradeAccessories from "./TLTradeAccessories"; -import TLTradeUnits from "./TLTradeUnits"; -//import WSAdditonalDetails from "./WSAdditonalDetails"; -import WSFeeEstimation from "./WSFeeEstimation"; -//import WSInfoLabel from "../../../ws/src/pageComponents/WSInfoLabel"; -import DocumentsPreview from "./DocumentsPreview"; -import InfoDetails from "./InfoDetails"; -import ViewBreakup from "./ViewBreakup"; -import SubWorkTableDetails from "./SubWorkTableDetails"; - - - -function ApplicationDetailsContent({ - applicationDetails, - workflowDetails, - isDataLoading, - applicationData, - businessService, - timelineStatusPrefix, - showTimeLine = true, - statusAttribute = "status", - paymentsList, - oldValue, - isInfoLabel = false, - noBoxShadow = false, - sectionHeadStyle = false, - modify, - setSaveAttendanceState -}) { - const { t } = useTranslation(); - const [localSearchParams, setLocalSearchParams] = useState(() => ({})); - - - const handleDateRangeChange = useCallback((data) => { - setLocalSearchParams(() => ({ ...data })); - }, []); - - function OpenImage(imageSource, index, thumbnailsToShow) { - window.open(thumbnailsToShow?.fullImage?.[0], "_blank"); - } - - const convertEpochToDateDMY = (dateEpoch) => { - if (dateEpoch == null || dateEpoch == undefined || dateEpoch == "") { - return "NA"; - } - const dateFromApi = new Date(dateEpoch); - let month = dateFromApi.getMonth() + 1; - let day = dateFromApi.getDate(); - let year = dateFromApi.getFullYear(); - month = (month > 9 ? "" : "0") + month; - day = (day > 9 ? "" : "0") + day; - return `${day}/${month}/${year}`; - }; - const getTimelineCaptions = (checkpoint) => { - if (checkpoint.state === "OPEN" || (checkpoint.status === "INITIATED" && !window.location.href.includes("/obps/"))) { - const caption = { - date: convertEpochToDateDMY(applicationData?.auditDetails?.createdTime), - source: applicationData?.channel || "", - }; - return ; - } else if (window.location.href.includes("/obps/") || window.location.href.includes("/noc/") || window.location.href.includes("/ws/")) { - //From BE side assigneeMobileNumber is masked/unmasked with connectionHoldersMobileNumber and not assigneeMobileNumber - const privacy = { uuid: checkpoint?.assignes?.[0]?.uuid, fieldName: ["connectionHoldersMobileNumber"], model: "WaterConnectionOwner" }; - const caption = { - date: checkpoint?.auditDetails?.lastModified, - name: checkpoint?.assignes?.[0]?.name, - mobileNumber: - applicationData?.processInstance?.assignes?.[0]?.uuid === checkpoint?.assignes?.[0]?.uuid && - applicationData?.processInstance?.assignes?.[0]?.mobileNumber - ? applicationData?.processInstance?.assignes?.[0]?.mobileNumber - : checkpoint?.assignes?.[0]?.mobileNumber, - comment: t(checkpoint?.comment), - wfComment: checkpoint.wfComment, - thumbnailsToShow: checkpoint?.thumbnailsToShow, - }; - return ; - } else { - const caption = { - date: `${Digit.DateUtils?.ConvertTimestampToDate(checkpoint.auditDetails.lastModifiedEpoch)} ${Digit.DateUtils?.ConvertEpochToTimeInHours( - checkpoint.auditDetails.lastModifiedEpoch - )} ${Digit.DateUtils?.getDayfromTimeStamp(checkpoint.auditDetails.lastModifiedEpoch)}`, - // name: checkpoint?.assigner?.name, - name: checkpoint?.assignes?.[0]?.name, - // mobileNumber: checkpoint?.assigner?.mobileNumber, - wfComment: checkpoint?.wfComment, - mobileNumber: checkpoint?.assignes?.[0]?.mobileNumber, - }; - - return ; - } - }; - - const getTranslatedValues = (dataValue, isNotTranslated) => { - if (dataValue) { - return !isNotTranslated ? t(dataValue) : dataValue; - } else { - return t("NA"); - } - }; - - const checkLocation = - window.location.href.includes("employee/tl") || window.location.href.includes("employee/obps") || window.location.href.includes("employee/noc"); - const isNocLocation = window.location.href.includes("employee/noc"); - const isBPALocation = window.location.href.includes("employee/obps"); - let isWS = window.location.href.includes("employee/ws") || window.location.href.includes("employee/works")|| window.location.href.includes("employee/project") || window.location.href.includes("employee/estimate") ; - - - - const getRowStyles = (tab="") => { - - if (window.location.href.includes("employee/obps") || window.location.href.includes("employee/noc")) { - return { justifyContent: "space-between", fontSize: "16px", lineHeight: "19px", color: "#0B0C0C" }; - } else if (checkLocation) { - return { justifyContent: "space-between", fontSize: "16px", lineHeight: "19px", color: "#0B0C0C" }; - } - else if ( tab==="fieldSurvey") { - return { - justifyContent: "space-between", flexDirection:"column" - } - } - else { - return {}; - } - - }; - const getTextStyles = (tab="") => { - if ( tab==="fieldSurvey" ) { - return { - marginTop:"1rem", - marginBottom:"1rem" - } - } - else { - return {}; - } - - }; - const getLabelStyles = (tab = "") => { - if ( tab === "fieldSurvey") { - return { - width:"100%" - } - } - else { - return {}; - } - - }; - - const getTableStyles = () => { - if (window.location.href.includes("employee/obps") || window.location.href.includes("employee/noc")) { - return { position: "relative", marginTop: "19px" }; - } else if (checkLocation) { - return { position: "relative", marginTop: "19px" }; - } else { - return {}; - } - }; - - const getMainDivStyles = () => { - if ( - window.location.href.includes("employee/obps") || - window.location.href.includes("employee/noc") || - window.location.href.includes("employee/ws") || - window.location.href.includes("employee/works") || - window.location.href.includes("employee/contracts") - ) { - return { lineHeight: "19px", maxWidth: "950px", minWidth: "280px" }; - } else if (checkLocation) { - return { lineHeight: "19px", maxWidth: "600px", minWidth: "280px" }; - } else { - return {}; - } - }; - - const getTextValue = (value) => { - if (value?.skip) return value.value; - else if (value?.isUnit) return value?.value ? `${getTranslatedValues(value?.value, value?.isNotTranslated)} ${t(value?.isUnit)}` : t("N/A"); - else if (value?.value === "Approved") return { `${getTranslatedValues(value?.value, value?.isNotTranslated)}`} - else if (value?.value === "Rejected") return {t(value?.value)} - else return value?.value ? getTranslatedValues(value?.value, value?.isNotTranslated) : t("N/A"); - }; - - const getClickInfoDetails = () => { - if (window.location.href.includes("disconnection") || window.location.href.includes("application")) { - return "WS_DISCONNECTION_CLICK_ON_INFO_LABEL"; - } else { - return "WS_CLICK_ON_INFO_LABEL"; - } - }; - - const getClickInfoDetails1 = () => { - if (window.location.href.includes("disconnection") || window.location.href.includes("application")) { - return "WS_DISCONNECTION_CLICK_ON_INFO1_LABEL"; - } else { - return ""; - } - }; - - const getCardStyles = () => { - let styles = { position: "relative" } - if (noBoxShadow) styles = { ...styles, boxShadow: "none" }; - return styles; - }; - - return ( - - - {isInfoLabel ? ( - - ) : null} - {applicationDetails?.applicationDetails?.map((detail, index) => ( - - -
- {index === 0 && !detail.asSectionHeader ? ( - {t(detail.title)} - ) : ( - - - {isNocLocation ? `${t(detail.title)}` : t(detail.title)} - {detail?.Component ? : null} - - - )} - {/* TODO, Later will move to classes */} - {/* Here Render the table for adjustment amount details detail.isTable is true for that table*/} - {/* {detail?.isTable && ( - - - {detail?.headers.map((header) => ( - - ))} - - - {detail?.tableRows.map((row,index)=>{ - if(index===detail?.tableRows.length - 1){ - return <> -
- - {row.map(element => )} - - - } - return - {row.map(element => )} - })} -
{t(header)}
{t(element)}
{t(element)}
- )} */} - {detail?.isTable && } - - - {detail?.title && - !detail?.title.includes("NOC") && - detail?.values?.map((value, index) => { - if (value.map === true && value.value !== "N/A") { - return } />; - } - if (value?.isLink == true) { - return ( - - - - {t(value?.title)} - - -
- ) : isNocLocation || isBPALocation ? ( - `${t(value.title)}` - ) : ( - t(value.title) - ) - } - text={ -
- - - {value?.value} - - -
- } - last={index === detail?.values?.length - 1} - caption={value.caption} - className="border-none" - rowContainerStyle={getRowStyles()} - /> - ); - } - return ( - { }} />: getTextValue(value)} - last={index === detail?.values?.length - 1} - caption={value.caption} - className="border-none" - /* privacy object set to the Row Component */ - privacy={value?.privacy} - // TODO, Later will move to classes - rowContainerStyle={getRowStyles(detail?.tab)} - textStyle={getTextStyles(detail?.tab)} - labelStyle={getLabelStyles(detail?.tab)} - /> - ); - })} - -
- - - {detail?.additionalDetails?.table - ? detail?.additionalDetails?.table?.weekTable?.tableHeader && ( - <> - - {t(detail?.additionalDetails?.table?.weekTable?.tableHeader)} - - - ) - : null} - - {detail?.additionalDetails?.inspectionReport && ( - - )} - {applicationDetails?.applicationData?.additionalDetails?.fieldinspection_pending?.length > 0 && detail?.additionalDetails?.fiReport && ( - - )} - {/* {detail?.additionalDetails?.FIdocuments && detail?.additionalDetails?.values?.map((doc,index) => ( -
- {doc.isNotDuplicate &&
- - - -
-
-
} -
- )) } */} - {detail?.additionalDetails?.floors && } - {detail?.additionalDetails?.owners && } - {detail?.additionalDetails?.units && } - {detail?.additionalDetails?.accessories && } - {detail?.additionalDetails?.permissions && workflowDetails?.data?.nextActions?.length > 0 && ( - - )} - {detail?.additionalDetails?.obpsDocuments && ( - - )} - {detail?.additionalDetails?.noc && ( - - )} - {detail?.additionalDetails?.scruntinyDetails && } - {detail?.additionalDetails?.buildingExtractionDetails && } - {detail?.additionalDetails?.subOccupancyTableDetails && ( - - )} - {detail?.additionalDetails?.documentsWithUrl && } - {detail?.additionalDetails?.documents && } - {detail?.additionalDetails?.taxHeadEstimatesCalculation && ( - - )} - {/* {detail?.isWaterConnectionDetails && } */} - {detail?.additionalDetails?.redirectUrl && ( -
- - - {detail?.additionalDetails?.redirectUrl?.title} - - -
- )} - {detail?.additionalDetails?.estimationDetails && } - {detail?.additionalDetails?.estimationDetails && } - - - ))} - {showTimeLine && workflowDetails?.data?.timeline?.length > 0 && ( - - {workflowDetails?.breakLineRequired === undefined ? : workflowDetails?.breakLineRequired ? : null} - {(workflowDetails?.isLoading || isDataLoading) && } - {!workflowDetails?.isLoading && !isDataLoading && ( - - - {/* {t("ES_APPLICATION_DETAILS_APPLICATION_TIMELINE")} */} - {t("WORKS_WORKFLOW_HISTORY")} - - {workflowDetails?.data?.timeline && workflowDetails?.data?.timeline?.length === 1 ? ( - - ) : ( - - {workflowDetails?.data?.timeline && - workflowDetails?.data?.timeline.map((checkpoint, index, arr) => { - return ( - - - - ); - })} - - )} - - )} - - )} - - - ); -} - -export default ApplicationDetailsContent; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsToast.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsToast.js deleted file mode 100644 index 9540495f32a..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsToast.js +++ /dev/null @@ -1,74 +0,0 @@ -import React from "react"; -import { Toast } from "@egovernments/digit-ui-react-components"; - -function ApplicationDetailsToast({ t, showToast, closeToast, businessService }) { - if (businessService?.includes("NewTL") || businessService?.includes("TL") || businessService?.includes("EDITRENEWAL")) { - let label = ""; - switch (showToast?.action?.action) { - case "SENDBACK": - label = showToast?.key === "error" ? showToast?.error?.message : t("TL_SENDBACK_CHECKLIST_MESSAGE_HEAD"); - break; - case "FORWARD": - label = showToast?.key === "error" ? showToast?.error?.message : t("TL_FORWARD_SUCCESS_MESSAGE_MAIN"); - break; - case "APPROVE": - label = showToast?.key === "error" ? showToast?.error?.message : t("TL_APPROVAL_CHECKLIST_MESSAGE_HEAD"); - break; - case "SENDBACKTOCITIZEN": - label = showToast?.key === "error" ? showToast?.error?.message : t("TL_SENDBACK_TOCITIZEN_CHECKLIST_MESSAGE_HEAD"); - break; - case "REJECT": - label = showToast?.key === "error" ? showToast?.error?.message : t("TL_APPROVAL_REJ_MESSAGE_HEAD"); - break; - case "RESUBMIT": - label = showToast?.key === "error" ? showToast?.error?.message : t("TL_APPLICATION_RESUBMIT_SUCCESS_MESSAGE_MAIN"); - break; - case "CANCEL": - label = showToast?.key === "error" ? showToast?.error?.message : t("TL_TL_CANCELLED_MESSAGE_HEAD"); - break; - default: - label = showToast?.key === "error" ? showToast?.error?.message : t(`ES_${businessService}_${showToast?.action?.action}_UPDATE_SUCCESS`); - } - return {showToast && }; - } else if (businessService?.includes("BPA") || businessService?.includes("BPA_LOW") || businessService?.includes("BPA_OC")) { - const getMessage = (messages = []) => { - let returnValue = messages[0]; - if(messages?.length == 2) returnValue = businessService?.includes("BPA_OC") ? t(messages[1]) : t(messages [0]); - else returnValue = t(messages[0]); - return returnValue; - } - let label = ""; - switch (showToast?.action?.action) { - case "REVOCATE": - label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_APPROVAL_REVOCATED_MESSAGE_HEAD", "BPA_APPROVAL_OC_REVOCATED_MESSAGE_HEAD"]); - break; - case "VERIFY_AND_FORWARD": - label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_FORWARD_SUCCESS_MESSAGE_MAIN"]); - break; - case "SEND_BACK_TO_CITIZEN": - label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_SENDBACK_SUCCESS_MESSAGE_MAIN"]); - break; - case "APPROVE": - label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_APPROVAL_CHECKLIST_MESSAGE_HEAD"]); - break; - case "REJECT": - label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_APPROVAL_REJECTED_MESSAGE_HEAD", "BPA_OC_APPROVAL_REJECTED_MESSAGE_HEAD"]); - break; - case "FORWARD": - label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_FORWARD_SUCCESS_MESSAGE_MAIN"]); - break; - case "SEND_BACK_FOR_DOCUMENT_VERIFICATION": - case "SEND_BACK_FOR_FIELD_INSPECTION": - label = showToast?.key === "error" ? showToast?.error?.message : getMessage(["BPA_SENDBACK_SUCCESS_MESSAGE_MAIN"]); - break; - default: - label = showToast?.key === "error" ? showToast?.error?.message : t(`ES_${businessService}_${showToast?.action?.action}_UPDATE_SUCCESS`); - } - return {showToast && }; - } else { - const label = showToast?.key === "error" ? showToast?.error?.message : `ES_${businessService}_${showToast?.action?.action}_UPDATE_SUCCESS`; - return {showToast && }; - } -} - -export default ApplicationDetailsToast; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsWarningPopup.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsWarningPopup.js deleted file mode 100644 index e95b9e038cd..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ApplicationDetailsWarningPopup.js +++ /dev/null @@ -1,54 +0,0 @@ -import { Card, ButtonSelector, CardText, CardSubHeader, Modal, CardSectionHeader, Row } from "@egovernments/digit-ui-react-components"; -import React from "react"; -import { useTranslation } from "react-i18next"; - -const Close = () => ( - - - - - ); - -const CloseBtn = (props) => { - return ( -
- -
- ); - }; - -function ApplicationDetailsWarningPopup({ action,workflowDetails,businessService,isWarningPop,closeWarningPopup }) { -const { t } = useTranslation(); -const isMobile = window.Digit.Utils.browser.isMobile(); -return ( - - {t("PT_DUES_ARE_PENDING")}} - headerBarEnd={ - { - closeWarningPopup(); - }} - /> - } - hideSubmit={true} - isDisabled={false} - popupStyles={isMobile ? {} : { width: "29%", marginTop: "auto" }} - > - -
-

{t("PT_YOU_HAVE")} ₹{action?.AmountDueForPay} {t("PT_DUE_WARNING_MSG2")}

-
- -
- - window.location.assign(`${window.location.origin}${action?.redirectionUrl?.pathname}`)} style={{ marginLeft: "10px" }} /> -
-
-
- ) -
-) -} - -export default ApplicationDetailsWarningPopup; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/BPADocuments.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/BPADocuments.js deleted file mode 100644 index 9a1febe081b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/BPADocuments.js +++ /dev/null @@ -1,234 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { - CardLabel, - Dropdown, - LabelFieldPair, - MultiUploadWrapper, - CardSubHeader -} from "@egovernments/digit-ui-react-components"; -import DocumentsPreview from "./DocumentsPreview"; - -const BPADocuments = ({ t, formData, applicationData, docs, bpaActionsDetails }) => { - const applicationStatus = applicationData?.status || ""; - const actions = bpaActionsDetails?.data?.nextActions || []; - const stateId = Digit.ULBService.getStateId(); - const [documents, setDocuments] = useState(formData?.documents?.documents || []); - const [error, setError] = useState(null); - const [bpaTaxDocuments, setBpaTaxDocuments] = useState([]); - const [enableSubmit, setEnableSubmit] = useState(true) - const [checkRequiredFields, setCheckRequiredFields] = useState(false); - const [checkEnablingDocs, setCheckEnablingDocs] = useState(false); - - const { isLoading: bpaDocsLoading, data: bpaDocs } = Digit.Hooks.obps.useMDMS(stateId, "BPA", ["DocTypeMapping"]); - const { isLoading: commonDocsLoading, data: commonDocs } = Digit.Hooks.obps.useMDMS(stateId, "common-masters", ["DocumentType"]); - - useEffect(() => { - let filtredBpaDocs = []; - if (bpaDocs?.BPA?.DocTypeMapping) { - // filtredBpaDocs = bpaDocs?.BPA?.DocTypeMapping?.filter(data => (data.WFState == "INPROGRESS")) - filtredBpaDocs = bpaDocs?.BPA?.DocTypeMapping?.filter(data => (data.WFState == applicationData?.status ? applicationData?.status : "INPROGRESS" && data.RiskType == applicationData?.riskType && data.ServiceType == applicationData?.additionalDetails?.serviceType && data.applicationType == applicationData?.additionalDetails?.applicationType)) - } - let documentsList = []; - filtredBpaDocs?.[0]?.docTypes?.forEach(doc => { - let code = doc.code; doc.dropdownData = []; doc.uploadedDocuments = []; - commonDocs?.["common-masters"]?.DocumentType?.forEach(value => { - let values = value.code.slice(0, code.length); - if (code === values) { - doc.hasDropdown = true; - value.i18nKey = value.code; - doc.dropdownData.push(value); - } - }); - doc.uploadedDocuments[0] = {}; - doc.uploadedDocuments[0].values = []; - docs?.[0]?.values?.map(upDocs => { - if (code === `${upDocs?.documentType?.split('.')[0]}.${upDocs?.documentType?.split('.')[1]}`) { - doc.uploadedDocuments[0].values.push(upDocs) - } - }) - documentsList.push(doc); - }); - sessionStorage.setItem("BPA_DOCUMENTS", JSON.stringify(documentsList)); - setBpaTaxDocuments(documentsList); - - }, [!bpaDocsLoading, !commonDocsLoading]); - - useEffect(() => { - let count = 0; - bpaTaxDocuments.map(doc => { - let isRequired = false; - documents.map(data => { - if (doc.required && doc.code == `${data.documentType.split('.')[0]}.${data.documentType.split('.')[1]}`) { - isRequired = true; - } - }); - if (!isRequired && doc.required) { - count = count + 1; - } - }); - if ((count == "0" || count == 0) && documents.length > 0) setEnableSubmit(false); - else setEnableSubmit(true); - }, [documents, checkRequiredFields]) - - useEffect(() => { - if ( applicationStatus === "DOC_VERIFICATION_INPROGRESS" && actions?.length > 0 ) setCheckEnablingDocs(true); - else setCheckEnablingDocs(false); - }, [applicationData, bpaActionsDetails]) - - return ( -
- {bpaTaxDocuments?.map((document, index) => { - return ( -
- -
- ); - })} -
- ); -} - -function SelectDocument({ - t, - document: doc, - setDocuments, - error, - setError, - documents, - setCheckRequiredFields, - index, - applicationStatus, - actions, - bpaTaxDocuments, - checkEnablingDocs -}) { - - const filteredDocument = documents?.filter((item) => item?.documentType?.includes(doc?.code))[0]; - const tenantId = Digit.ULBService.getStateId(); - const [selectedDocument, setSelectedDocument] = useState( - filteredDocument - ? { ...filteredDocument, active: true, code: filteredDocument?.documentType, i18nKey: filteredDocument?.documentType } - : doc?.dropdownData?.length === 1 - ? doc?.dropdownData[0] - : {} - ); - const [file, setFile] = useState(null); - const [uploadedFile, setUploadedFile] = useState(() => filteredDocument?.fileStoreId || null); - const [selectArrayFiles, SetSelectArrayFiles] = useState([]); - const handleSelectDocument = (value) => setSelectedDocument(value); - const allowedFileTypes = /(.*?)(jpg|jpeg|png|image|pdf)$/i; - - function selectfiles(e) { - e && setFile(e.file); - } - - - useEffect(() => { - if (selectedDocument?.code) { - setDocuments((prev) => { - const filteredDocumentsByDocumentType = prev?.filter((item) => item?.documentType !== selectedDocument?.code); - if (uploadedFile?.length === 0 || uploadedFile === null) return filteredDocumentsByDocumentType; - const filteredDocumentsByFileStoreId = filteredDocumentsByDocumentType?.filter((item) => item?.fileStoreId !== uploadedFile); - return [ - ...filteredDocumentsByFileStoreId, - { - documentType: selectedDocument?.code, - fileStoreId: uploadedFile, - documentUid: uploadedFile, - fileName: file?.name || "", - id: documents ? documents.find(x => x.documentType === selectedDocument?.code)?.id : undefined, - }, - ]; - }); - } - }, [uploadedFile, selectedDocument]); - - useEffect(() => { - (async () => { - if (selectArrayFiles.length > 0) { - sessionStorage.removeItem("BPA_DOCUMENTS"); - doc.newUploadedDocs = []; - selectArrayFiles.map(newDoc => { - if (selectedDocument?.code) { - doc.newUploadedDocs.push({ - documentType: selectedDocument?.code, - fileStoreId: newDoc?.fileStoreId?.fileStoreId, - documentUid: newDoc?.fileStoreId?.fileStoreId, - tenantId: newDoc?.fileStoreId?.tenantId - }); - } - }) - bpaTaxDocuments[index] = doc; - sessionStorage.setItem("BPA_DOCUMENTS", JSON.stringify(bpaTaxDocuments)); - } - })(); - }, [selectArrayFiles, selectedDocument]); - - useEffect(() => { - (async () => { - - })(); - }, [file]); - - const getData = (index, state) => { - let data = Object.fromEntries(state); - let newArr = Object.values(data); - if (Object.keys(data).length !== 0) SetSelectArrayFiles(newArr); - selectfiles(newArr[newArr.length - 1]); - } - - return ( -
- {`${t(doc?.code)}`} - {doc?.uploadedDocuments?.length && } - { - checkEnablingDocs ? -
- - {doc?.required ? `${t(doc?.code)}* ` : `${t(doc?.code)}`} - - - - -
- getData(index, e)} - t={t} - allowedFileTypesRegex={allowedFileTypes} - allowedMaxSizeInMB={5} - acceptFiles= "image/*, .pdf, .png, .jpeg, .jpg" - /> -
-
-
: null - } -
- ); -} - -export default BPADocuments; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/DocumentsPreview.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/DocumentsPreview.js deleted file mode 100644 index dfd57683def..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/DocumentsPreview.js +++ /dev/null @@ -1,49 +0,0 @@ -import React from "react"; -import { useTranslation } from "react-i18next"; -import { CardSubHeader, PDFSvg } from "@egovernments/digit-ui-react-components"; - -function DocumentsPreview({ documents, svgStyles = {}, isSendBackFlow = false, isHrLine = false, titleStyles }) { - const { t } = useTranslation(); - const isStakeholderApplication = window.location.href.includes("stakeholder"); - - return ( -
- {!isStakeholderApplication && documents?.map((document, index) => ( - - {document?.title ? {t(document?.title)} : null} -
- {document?.values && document?.values.length > 0 ? document?.values?.map((value, index) => ( - -
- -
-

{t(value?.title)}

- {isSendBackFlow ? value?.documentType?.includes("NOC") ?

{t(value?.documentType.split(".")[1])}

:

{t(value?.documentType)}

: ""} -
- )) : !(window.location.href.includes("citizen")) &&

{t("BPA_NO_DOCUMENTS_UPLOADED_LABEL")}

} -
- {isHrLine && documents?.length != index + 1 ?
: null} -
- ))} - {isStakeholderApplication && documents?.map((document, index) => ( - - {document?.title ? {t(document?.title)} : null} -
- {document?.values && document?.values.length > 0 ? document?.values?.map((value, index) => ( - -
-

{t(value?.title)}

- {value?.docInfo ?
{`${t(value?.docInfo)}`}
: null} - -

{`${t(value?.title)}`}

-
-
- )) : !(window.location.href.includes("citizen")) &&

{t("BPA_NO_DOCUMENTS_UPLOADED_LABEL")}

} -
-
- ))} -
- ); -} - -export default DocumentsPreview; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InfoDetails.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InfoDetails.js deleted file mode 100644 index 12e2f64fac6..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InfoDetails.js +++ /dev/null @@ -1,34 +0,0 @@ -import React from "react"; -import { InfoBannerIcon } from "@egovernments/digit-ui-react-components"; - -const EyeSvgINdex = ({ style }) => { - return - - - - - -} -const InfoDetails = ({ t, userType = false, infoBannerLabel = "", infoClickLable = "", infoClickInfoLabel = "", infoClickInfoLabel1 = "" }) => { - userType = userType || Digit.SessionStorage.get("userType"); - return ( - -
-
-
- -

{t(infoBannerLabel)}

-
- {`${t(infoClickLable)} `} - - {` ${t(infoClickInfoLabel)}`} -
- {` ${t(infoClickInfoLabel1)}`} -
-
-
-
- ); -}; - -export default InfoDetails; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InspectionReport.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InspectionReport.js deleted file mode 100644 index a824b05a435..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/InspectionReport.js +++ /dev/null @@ -1,49 +0,0 @@ -import { StatusTable, Row, CardHeader, CardSectionHeader } from "@egovernments/digit-ui-react-components"; -import React from "react"; -import { useTranslation } from "react-i18next"; -import DocumentsPreview from "./DocumentsPreview"; - -const getDocuments = (fiDocuments) => { - const returnDocuments = [{ - title: "BPA_DOCUMENT_DETAILS_LABEL", - values: fiDocuments?.map(doc => ({ - title: doc?.documentType?.replaceAll('.', '_'), - documentType: doc?.documentType, - documentUid: doc?.documentUid, - fileStoreId: doc?.fileStoreId, - id: doc?.id, - url: doc?.url - })) - }]; - return returnDocuments; -}; - -function InspectionReport({ fiReport, isCitizen=false }) { - const { t } = useTranslation(); - - return ( - -
- {isCitizen?{`${t(`BPA_FI_REPORT`)}`}: - {`${t(`BPA_FI_REPORT`)}`}} - {fiReport.map((fiData, index) => -
- - {fiReport?.length == 1 ? `${t(`BPA_FI_REPORT`)}` : `${t(`BPA_FI_REPORT`)} - ${index + 1}`} - - - {fiData?.questions?.length && - fiData?.questions?.map((qstn) => -
- - -
)} - -
-
)} -
-
- ); -} - -export default InspectionReport; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/NOCDocuments.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/NOCDocuments.js deleted file mode 100644 index 1581744f756..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/NOCDocuments.js +++ /dev/null @@ -1,202 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { - CardLabel, - MultiUploadWrapper, - StatusTable, - Row, - LabelFieldPair -} from "@egovernments/digit-ui-react-components"; -import DocumentsPreview from "./DocumentsPreview"; - -function SelectDocument({ - t, - document: doc, - setNocDocuments, - setError, - nocDocuments -}) { - const filteredDocument = nocDocuments?.filter((item) => item?.documentType?.includes(doc?.code))[0]; - const tenantId = Digit.ULBService.getStateId(); - const [selectedDocument, setSelectedDocument] = useState(); - const [file, setFile] = useState(null); - const [uploadedFile, setUploadedFile] = useState(() => filteredDocument?.fileStoreId || null); - const handleSelectDocument = (value) => setSelectedDocument(value); - const allowedFileTypes = /(.*?)(jpg|jpeg|png|image|pdf)$/i; - - function selectfile(e) { - e && setFile(e.file); - } - - useEffect(() => { - if (doc?.dropdownData?.[0]?.code) { - setNocDocuments((prev) => { - const filteredDocumentsByDocumentType = prev?.filter((item) => item?.documentType !== doc?.dropdownData?.[0]?.code); - - if (uploadedFile?.length === 0 || uploadedFile === null) { - return filteredDocumentsByDocumentType; - } - - const filteredDocumentsByFileStoreId = filteredDocumentsByDocumentType?.filter((item) => item?.fileStoreId !== uploadedFile); - return [ - ...filteredDocumentsByFileStoreId, - { - documentType: doc?.dropdownData?.[0].code, - fileStoreId: uploadedFile, - documentUid: uploadedFile, - fileName: file?.name || "", - }, - ]; - }); - } - }, [uploadedFile]); - - - useEffect(() => { - (async () => { - setError(null); - if (file) { - const allowedFileTypesRegex = /(.*?)(jpg|jpeg|png|image|pdf)$/i - if (file.size >= 5242880) { - setError(t("CS_MAXIMUM_UPLOAD_SIZE_EXCEEDED")); - } else if (file?.type && !allowedFileTypesRegex.test(file?.type)) { - setError(t(`NOT_SUPPORTED_FILE_TYPE`)) - } else { - try { - setUploadedFile(null); - const response = await Digit.UploadServices.Filestorage("PT", file, Digit.ULBService.getStateId()); - if (response?.data?.files?.length > 0) { - setUploadedFile(response?.data?.files[0]?.fileStoreId); - } else { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } catch (err) { - setError(t("CS_FILE_UPLOAD_ERROR")); - } - } - } - })(); - }, [file]); - - const getData =(state) => { - let data = Object.fromEntries(state); - let newArr = Object.values(data); - selectfile(newArr[newArr.length-1]); - } - - return ( -
- - {doc?.required ? `${t("TL_BUTTON_UPLOAD FILE")}*` : `${t("TL_BUTTON_UPLOAD FILE")}`} -
- getData(e)} - t={t} - allowedFileTypesRegex={allowedFileTypes} - allowedMaxSizeInMB={5} - acceptFiles="image/*, .pdf, .png, .jpeg, .jpg" - /> -
-
-
- ); -} -const NOCDocuments = ({ t, noc, docs, isNoc, applicationData,NOCdata, bpaActionsDetails }) => { - const tenantId = Digit.ULBService.getStateId(); - const stateId = Digit.ULBService.getStateId(); - const bpaApplicationStatus = applicationData?.status || ""; - const actions = bpaActionsDetails?.data?.nextActions || []; - const { isLoading: nocDocsLoading, data: nocDocs } = Digit.Hooks.obps.useMDMS(stateId, "NOC", ["DocumentTypeMapping"], { enabled: isNoc }); - const { isLoading: bpaDocsLoading, data: bpaDocs } = Digit.Hooks.obps.useMDMS(stateId, "BPA", ["DocTypeMapping"], { enabled: !isNoc }); - const { isLoading: commonDocsLoading, data: commonDocs } = Digit.Hooks.obps.useMDMS(stateId, "common-masters", ["DocumentType"]); - const [commonDocMaping, setCommonDocMaping] = useState([]); - const [nocTaxDocuments, setNocTaxDocuments] = useState([]); - const [checkEnablingDocs, setCheckEnablingDocs] = useState(false); - const [nocDocuments, setNocDocuments] = Digit.Hooks.useSessionStorage(noc?.nocType, []); - const [error, setError] = useState(null); - const isEmployee = window.location.href.includes("/employee/") - - useEffect(() => { - setCommonDocMaping(commonDocs?.["common-masters"]?.DocumentType); - }, [commonDocs]); - - useEffect(() => { - let documents = []; - let filteredData - if (isNoc) { - filteredData = nocDocs?.NOC?.DocumentTypeMapping?.filter((data => { - return data?.applicationType === noc?.applicationType && data?.nocType === noc?.nocType - })); - } - else { - filteredData = bpaDocs?.BPA?.DocTypeMapping?.filter(data => (data.WFState == applicationData?.status && data.RiskType == applicationData?.riskType && data.ServiceType == applicationData?.additionalDetails?.serviceType && data.applicationType == applicationData?.additionalDetails?.applicationType)) - } - if (filteredData?.[0]?.docTypes?.[0]) { - filteredData[0].docTypes[0].nocType = filteredData[0].nocType; - filteredData[0].docTypes[0].additionalDetails = { - submissionDetails: noc?.additionalDetails, - applicationStatus: noc?.applicationStatus, - appNumberLink: noc?.applicationNo, - nocNo: noc?.nocNo - } - documents.push(filteredData[0].docTypes[0]); - } - let documentsList = []; - if (documents && documents.length > 0) { - documents.map((doc) => { - let code = doc.documentType; - let nocType = doc.nocType; - doc.dropdownData = []; - commonDocMaping?.forEach((value) => { - let values = value.code.slice(0, code?.length); - if (code === values) { - doc.hasDropdown = true; - doc.dropdownData.push(value); - } - }); - documentsList.push(doc); - }); - setNocTaxDocuments(documentsList); - } - }, [nocDocs, commonDocMaping]); - - useEffect(() => { - if (bpaApplicationStatus === 'NOC_VERIFICATION_INPROGRESS' && actions?.length > 0) setCheckEnablingDocs(true); - else setCheckEnablingDocs(false); - }, [applicationData, bpaActionsDetails]) - - return ( -
- - - {NOCdata && NOCdata.map((noc,index) => { - if (noc?.value) { - if (noc?.field == "STATUS") { - return - } else { - return - } - } - })} - - - {checkEnablingDocs && nocTaxDocuments?.map((document, index) => { - return ( - - ); - })} -
- ); -} - -export default NOCDocuments; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PermissionCheck.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PermissionCheck.js deleted file mode 100644 index 89007789722..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PermissionCheck.js +++ /dev/null @@ -1,87 +0,0 @@ -import { CheckBox, LinkButton, TextInput,Close, CardSubHeader } from "@egovernments/digit-ui-react-components"; -import React, { useEffect, useState } from "react"; - -const PermissionCheck = ({ permissions, t }) => { - const [approvalChecks, setApprovalChecks, clearApprovals] = Digit.Hooks.useSessionStorage("OBPS_APPROVAL_CHECKS", permissions?.map(permission => ({ label: permission, checked: false }))); //useState(() => permissions?.map(permission => ({ label: permission, checked: false }))) - const [newApprovals, setNewApprovals, clearNewApprovals] = Digit.Hooks.useSessionStorage('OBPS_NEW_APPROVALS', []); - - useEffect(() => { - return () => { - Digit.SessionStorage.del("OBPS_NEW_APPROVALS"); - Digit.SessionStorage.del("OBPS_APPROVAL_CHECKS"); - } - }, []) - - const handleAdd = () => { - setNewApprovals([...newApprovals, { label: '' }]); - } - - const handleRemove = (index) => { - const values = [...newApprovals]; - values.splice(index, 1); - setNewApprovals([...values]); - } - - const handleChange = (event, index) => { - setNewApprovals(() => { - return newApprovals?.map((approval, id) => { - if (index === id) { - return { - label: event?.target?.value, - } - } - return approval; - }) - }) - } - - const handleCheck = (event, label, index) => { - const isChecked = event.target.checked; - setApprovalChecks(() => { - return approvalChecks?.map((approval, id) => { - if (index === id) { - return { - ...approval, - checked: isChecked - } - } - return approval; - }) - }) - } - - return ( -
- {t("BPA_PERMIT_CONDITIONS")} - {approvalChecks?.map((permission, index) => ( - handleCheck(event, permission?.label, index))} - isLabelFirst={true} - index={index} - /> - ))} - {newApprovals?.map((approval, index) => ( -
handleChange(event, index)} textInputStyle={{maxWidth: "830px", width: "830px"}} placeholder={"Enter permit conditions.........."} /> - { - - - -
- } - style={{ }} - onClick={(e) => handleRemove(index)} - />} -
- ))} - -
- ) -} - -export default PermissionCheck; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyDocuments.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyDocuments.js deleted file mode 100644 index ea8cd1eb104..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyDocuments.js +++ /dev/null @@ -1,83 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import { CardSubHeader, PDFSvg } from "@egovernments/digit-ui-react-components"; - -// const PDFSvg = ({ width = 34, height = 34, style, viewBox = "0 0 34 34" }) => ( -// -// -// -// ); - -function PropertyDocuments({ documents, svgStyles = {}, isSendBackFlow=false }) { - const { t } = useTranslation(); - const [filesArray, setFilesArray] = useState(() => [] ); - const tenantId = Digit.ULBService.getCurrentTenantId(); - const [pdfFiles, setPdfFiles] = useState({}); - - useEffect(() => { - let acc = []; - documents?.forEach((element, index, array) => { - acc = [...acc, ...(element.values?element.values:[])]; - }); - setFilesArray(acc?.map((value) => value?.fileStoreId)); - }, [documents]); - - useEffect(() => { - if (filesArray?.length && documents?.[0]?.BS === "BillAmend") { - Digit.UploadServices.Filefetch(filesArray, Digit.ULBService.getCurrentTenantId()).then((res) => { - setPdfFiles(res?.data); - }); - } - else if(filesArray?.length) - { - Digit.UploadServices.Filefetch(filesArray, Digit.ULBService.getStateId()).then((res) => { - setPdfFiles(res?.data); - }); - } - - }, [filesArray]); - - const checkLocation = window.location.href.includes("employee/tl") || window.location.href.includes("/obps") || window.location.href.includes("employee/ws"); - const isStakeholderApplication = window.location.href.includes("stakeholder"); - - return ( -
- {!isStakeholderApplication && documents?.map((document, index) => ( - - {document?.title ? {t(document?.title)}: null} -
- {document?.values && document?.values.length>0 ? document?.values?.map((value, index) => ( - -
- -
-

{t(value?.title)}

- {isSendBackFlow? value?.documentType?.includes("NOC")?

{t(value?.documentType.split(".")[1])}

:

{t(value?.documentType)}

:""} -
- )):!(window.location.href.includes("citizen"))&&

{t("BPA_NO_DOCUMENTS_UPLOADED_LABEL")}

} -
-
- ))} - {isStakeholderApplication && documents?.map((document, index) => ( - - {document?.title ? {t(document?.title)} : null} -
- {document?.values && document?.values.length>0 ? document?.values?.map((value, index) => ( - -
-

{t(value?.title)}

- {value?.docInfo ?
{`${t(value?.docInfo)}`}
: null} - - {/*
{decodeURIComponent(pdfFiles[value.fileStoreId]?.split(",")[0].split("?")[0].split("/").pop().slice(13))}
*/} -

{`${t(value?.title)}`}

-
-
- )):!(window.location.href.includes("citizen"))&&

{t("BPA_NO_DOCUMENTS_UPLOADED_LABEL")}

} -
-
- ))} -
- ); -} - -export default PropertyDocuments; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyEstimates.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyEstimates.js deleted file mode 100644 index c4cde76709f..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyEstimates.js +++ /dev/null @@ -1,39 +0,0 @@ -import React from "react"; -import { useTranslation } from "react-i18next"; -import { StatusTable, Row, BreakLine } from "@egovernments/digit-ui-react-components"; - -function PropertyEstimates({ taxHeadEstimatesCalculation }) { - const { taxHeadEstimates } = taxHeadEstimatesCalculation; - const { t } = useTranslation(); - - return ( -
- - - - {taxHeadEstimates?.map((estimate, index) => { - return ( - - ); - })} - - - -
- ); -} - -export default PropertyEstimates; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyFloors.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyFloors.js deleted file mode 100644 index 4f33bbdcff4..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyFloors.js +++ /dev/null @@ -1,49 +0,0 @@ -import React from "react"; -import { useTranslation } from "react-i18next"; -import { CardSubHeader, StatusTable, Row, CardSectionHeader } from "@egovernments/digit-ui-react-components"; - -function PropertyFloors({ floors }) { - const { t } = useTranslation(); - - return ( - - {floors.map((floor) => ( -
- {t(floor?.title)} - {floor?.values?.map((value, index) => { - return ( - - - {t(value.title)} - - -
- {value?.values?.map((value, index) => { - if (value.map === true && value.value !== "N/A") { - return } />; - } - return ( - - ); - })} -
-
-
- ); - })} -
- ))} -
- ); -} - -export default PropertyFloors; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyOwners.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyOwners.js deleted file mode 100644 index dac9f41c79b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/PropertyOwners.js +++ /dev/null @@ -1,94 +0,0 @@ -import { CardSubHeader, Row, StatusTable } from "@egovernments/digit-ui-react-components"; -import React from "react"; -import { useTranslation } from "react-i18next"; - -function PropertyOwners({ owners }) { - const { t } = useTranslation(); - - const checkLocation = true; - const checkOwnerLength = owners?.length || 1; - let cardStyles = { marginTop: "19px" }; - let statusTableStyles = { position: "relative", padding: "8px" }; - let rowContainerStyle = { justifyContent: "space-between", fontSize: "16px", lineHeight: "19px", color: "#0B0C0C" }; - if (checkLocation && Number(checkOwnerLength) > 1) { - cardStyles = { - marginTop: "19px", - background: "#FAFAFA", - border: "1px solid #D6D5D4", - borderRadius: "4px", - padding: "8px", - lineHeight: "19px", - maxWidth: "600px", - minWidth: "280px", - }; - } else if (checkLocation && !(Number(checkOwnerLength) > 1)) { - cardStyles = { marginTop: "19px", lineHeight: "19px", maxWidth: "600px", minWidth: "280px" }; - statusTableStyles = { position: "relative", marginTop: "19px" }; - } - - if (window.location.href.includes("obps")) { - cardStyles = { ...cardStyles, maxWidth: "950px" }; - cardStyles = { ...cardStyles, maxWidth: "950px" }; - rowContainerStyle = {}; - } - - return ( - - {owners.map((owner, index) => ( -
- {/* TODO, Later will move to classes */} - 1 - ? { marginBottom: "8px", paddingBottom: "9px", color: "#0B0C0C", fontSize: "16px", lineHeight: "19px" } - : { marginBottom: "8px", color: "#505A5F", fontSize: "24px" } - } - > - {checkLocation && Number(checkOwnerLength) > 1 ? `${t(owner?.title)} ${index + 1}` : t(owner?.title)} - - - -
- {owner?.values?.map((value, index) => { - if (value.map === true && value.value !== "N/A") { - return } />; - } - return ( - - - - ); - })} -
-
-
- ))} -
- ); -} - -export default PropertyOwners; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/Reason.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/Reason.js deleted file mode 100644 index 0f226935c5b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/Reason.js +++ /dev/null @@ -1,10 +0,0 @@ -import React from "react"; - -const Reason = ({ headComment, otherComment }) => ( -
-

{headComment}

-

{otherComment}

-
-); - -export default Reason; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ScruntinyDetails.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ScruntinyDetails.js deleted file mode 100644 index bde27623ba8..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ScruntinyDetails.js +++ /dev/null @@ -1,46 +0,0 @@ -import { StatusTable, Row, PDFSvg, CardLabel, CardSubHeader } from "@egovernments/digit-ui-react-components"; -import React, { Fragment } from "react"; -import { useTranslation } from "react-i18next"; - -const ScruntinyDetails = ({ scrutinyDetails, paymentsList=[] }) => { - const { t } = useTranslation(); - let count = 0; - const getTextValues = (data) => { - if (data?.value && data?.isTransLate) return {t(data?.value)}; - else if (data?.value && data?.isTransLate) return t(data?.value); - else if (data?.value) return data?.value; - else t("NA"); - } - return ( - - {!scrutinyDetails?.isChecklist &&
- -
- {scrutinyDetails?.values?.map((value, index) => { - if (value?.isUnit) return - else if (value?.isHeader && !value?.isUnit) return {t(value?.title)} - else if (value?.isSubTitle && !value?.isUnit) return {t(value?.title)} - else return - })} - {scrutinyDetails?.permit?.map((value,ind) => { - return {value?.title} - })} -
-
- {scrutinyDetails?.scruntinyDetails?.map((report, index) => { - return ( - - - -

{t(report?.text)}

-
- ) - })} -
-
-
} -
- ) -} - -export default ScruntinyDetails; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubOccupancyTable.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubOccupancyTable.js deleted file mode 100644 index e266bed6be2..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubOccupancyTable.js +++ /dev/null @@ -1,126 +0,0 @@ -import React, { Fragment, useMemo } from "react"; -import { Table, StatusTable, Row, CardSubHeader, CardSectionHeader } from "@egovernments/digit-ui-react-components"; -import { useTranslation } from "react-i18next"; - -const SubOccupancyTable = ({ edcrDetails, applicationData }) => { - const { t } = useTranslation(); - const isMobile = window.Digit.Utils.browser.isMobile(); - - const tableHeader = [ - { - name: "BPA_TABLE_COL_FLOOR", - id: "Floor", - }, - { - name: "BPA_TABLE_COL_LEVEL", - id: "Level", - }, - { - name: "BPA_TABLE_COL_OCCUPANCY", - id: "Occupancy", - }, - { - name: "BPA_TABLE_COL_BUILDUPAREA", - id: "BuildupArea", - }, - { - name: "BPA_TABLE_COL_FLOORAREA", - id: "FloorArea", - }, - { - name: "BPA_TABLE_COL_CARPETAREA", - id: "CarpetArea", - } - ] - - const accessData = (plot) => { - const name = plot; - return (originalRow, rowIndex, columns) => { - return originalRow[name]; - } - } - - - const tableColumns = useMemo( - () => { - return tableHeader.map((ob) => ({ - Header: t(`${ob.name}`), - accessor: accessData(ob.id), - id: ob.id - })); - }); - - function getFloorData(block) { - let floors = []; - block?.building?.floors.map((ob) => { - floors.push({ - Floor: t(`BPA_FLOOR_NAME_${ob.number}`), - Level: ob.number, - Occupancy: t(`${ob.occupancies?.[0]?.type}`), - BuildupArea: ob.occupancies?.[0]?.builtUpArea, - FloorArea: ob.occupancies?.[0]?.floorArea || 0, - CarpetArea: ob.occupancies?.[0]?.CarpetArea || 0, - key: t(`BPA_FLOOR_NAME_${ob.number}`), - }); - }); - return floors; - } - - const stringReplaceAll = (str = "", searcher = "", replaceWith = "") => { - if (searcher == "") return str; - while (str.includes(searcher)) { - str = str.replace(searcher, replaceWith); - } - return str; - }; - - function getSubOccupancyValues(index) { - let values = applicationData?.landInfo?.unit; - let returnValue = ""; - if (values?.length > 0) { - let splitArray = values[index]?.usageCategory?.split(','); - if (splitArray?.length) { - const returnValueArray = splitArray.map(data => data ? `${t(`BPA_SUBOCCUPANCYTYPE_${stringReplaceAll(data?.toUpperCase(), "-", "_")}`)}` : "NA"); - returnValue = returnValueArray.join(', ') - } - } - return returnValue ? returnValue : "NA"; - } - - return ( - -
- - {edcrDetails?.values?.map((value, index) => { - if (value?.isHeader) return {t(value?.title)} - else return - })} - - - {edcrDetails?.subOccupancyTableDetails?.[0]?.value?.planDetail?.blocks.map((block, index) => ( -
0 ? {marginBottom: "30px", background: "#FAFAFA", border: "1px solid #D6D5D4", padding: "8px", borderRadius: "4px", maxWidth: "950px", minWidth: "280px"} : {marginBottom: "30px"}}> - {t("BPA_BLOCK_SUBHEADER")} {index + 1} - - - -
- { return { style: {} } }} - /> - - ))} - - - ) -} - -export default SubOccupancyTable; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubWorkTableDetails.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubWorkTableDetails.js deleted file mode 100644 index 08b89e68419..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/SubWorkTableDetails.js +++ /dev/null @@ -1,77 +0,0 @@ -import { EditIcon } from '@egovernments/digit-ui-react-components'; -import React from 'react' -import { useTranslation } from "react-i18next"; -import { useHistory } from 'react-router-dom'; - -const SubWorkTableDetails = ({data}) => { - const { t } = useTranslation(); - const history = useHistory(); - const getStyles = (index) => { - let obj = {} - switch (index) { - case 1: - obj = { "width": "1vw" } - break; - case 2: - obj = { "width": "60vw" } - break; - case 3: - obj = { "width": "20vw" } - break; - case 4: - obj = { "width": "10vw" } - break; - default: - obj = { "width": "1vw" } - break; - } - return obj - } - const renderHeader = (headers) => { - return headers?.map((key, index) => { - return - }) - } - - const renderBody = (rows) => { - return rows?.map((row, index) => { - return - - - {row[1] === t("WORKS_TOTAL_AMT") - ? - : } - {row[3] && } - {/* */} - - }) - } - - return ( -
{t(key)}
{row[0]} { row[1] === t("WORKS_TOTAL_AMT") ?
{row[1]}
:
{row[1]}
}
{row[2]}
{row[2]}
-
history.push( - { - pathname: `/digit-ui/employee/contracts/create-contract?estimateNumber=${data?.state?.estimateNumber}&task=${data?.state?.estimateDetails[index]?.name}&subEstimate=${data?.state?.estimateDetails[index]?.estimateDetailNumber}`, - state:{index, data} - } - )}> - {row[3]} -
-
{showDelete() && removeRow(row)}>}
- - {renderHeader(data?.headers)} - - - {renderBody(data?.tableRows)} - {/* - - - - - */} - -
- ) -} - -export default SubWorkTableDetails \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLCaption.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLCaption.js deleted file mode 100644 index e5fbcde20cd..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLCaption.js +++ /dev/null @@ -1,34 +0,0 @@ -import React from "react"; -import { useTranslation } from "react-i18next"; -import { TelePhone, DisplayPhotos, UnMaskComponent } from "@egovernments/digit-ui-react-components"; -import Reason from "./Reason"; - -const TLCaption = ({ data,OpenImage,privacy={}}) => { - - const { t } = useTranslation(); - return ( -
- {data.date &&

{data.date}

} -

{data.name}

- {data.mobileNumber && - -

    

- -
} - {data.source &&

{t("ES_APPLICATION_DETAILS_APPLICATION_CHANNEL_" + data.source.toUpperCase())}

} - {data.comment && } - {data?.wfComment ?
{data?.wfComment?.map( e => -
-

{t("WF_COMMON_COMMENTS")}

-

{e}

-
- )}
: null} - {data?.thumbnailsToShow?.thumbs?.length > 0 ?
-

{t("CS_COMMON_ATTACHMENTS")}

- {OpenImage(src, index,data?.thumbnailsToShow)}} /> -
: null} -
- ); -}; - -export default TLCaption; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeAccessories.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeAccessories.js deleted file mode 100644 index 536a2ce3eca..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeAccessories.js +++ /dev/null @@ -1,52 +0,0 @@ - -import React from "react"; -import { useTranslation } from "react-i18next"; -import { CardSubHeader, StatusTable, Row, CardSectionHeader } from "@egovernments/digit-ui-react-components"; - -function TLTradeAccessories({ units }) { - const { t } = useTranslation(); - return ( - - {units.map((unit, index) => ( - // TODO, Later will move to classes -
- {`${t(unit?.title)} ${index + 1}`} - - -
- {unit?.values?.map((value, index) => { - if (value.map === true && value.value !== "N/A") { - return } />; - } - return ( - - ); - })} -
-
-
- ))} -
- ); -} - -export default TLTradeAccessories; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeUnits.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeUnits.js deleted file mode 100644 index bf1c1fbc780..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/TLTradeUnits.js +++ /dev/null @@ -1,51 +0,0 @@ -import React from "react"; -import { useTranslation } from "react-i18next"; -import { CardSubHeader, StatusTable, Row, CardSectionHeader } from "@egovernments/digit-ui-react-components"; - -function TLTradeUnits({ units }) { - const { t } = useTranslation(); - return ( - - {units.map((unit, index) => ( - // TODO, Later will move to classes -
- {`${t(unit?.title)} ${index + 1}`} - - -
- {unit?.values?.map((value, index) => { - if (value.map === true && value.value !== "N/A") { - return } />; - } - return ( - - ); - })} -
-
-
- ))} -
- ); -} - -export default TLTradeUnits; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ViewBreakup.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ViewBreakup.js deleted file mode 100644 index 5608aeb2d2a..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/ViewBreakup.js +++ /dev/null @@ -1,73 +0,0 @@ -import React, { useState, Fragment } from "react"; -import { useTranslation } from "react-i18next"; -import { CardSectionHeader, Modal, Row, StatusTable } from "@egovernments/digit-ui-react-components"; - -const ViewBreakup = ({ wsAdditionalDetails, workflowDetails }) => { - const { t } = useTranslation(); - const [popup, showPopUp] = useState(false); - const [breakUpData, setBreakUpData] = useState({}); - - const Heading = (props) => { - return

{props.label}

; - }; - - const Close = () => ( - - - - - ); - - const CloseBtn = (props) => { - return ( -
- -
- ); - }; - - const onPopupOpen = () => { - let breakupData = wsAdditionalDetails.additionalDetails.data || {}; - const sessionBillData = sessionStorage.getItem("Digit.ADHOC_BILL_ADD_REBATE_DATA"); - const sessionBillFormData = sessionBillData ? JSON.parse(sessionBillData) : {}; - if (sessionBillFormData?.value?.totalAmount) breakupData = sessionBillFormData?.value; - setBreakUpData(breakupData); - showPopUp(true); - } - - return ( - -
- {wsAdditionalDetails?.additionalDetails?.isViewBreakup ?
onPopupOpen()} style={{ marginTop: "12px" }}> - {t("WS_PAYMENT_VIEW_BREAKUP")} -
: null - } - {popup && - } - headerBarEnd={ { showPopUp(false); }} />} - hideSubmit={true} - popupStyles={{ overflowY: "auto" }} //maxHeight: "calc(100% - 90px)" - headerBarMainStyle={{ marginBottom: "0px" }} - popupModuleMianStyles={{ paddingTop: "0px" }} - > - { - {t("WS_APPLICATION_FEE_HEADER")} - {breakUpData?.billSlabData?.FEE?.map(data => ₹{Number(data?.amount) || 0}} textStyle={{ textAlign: "right" }} />)} -
- ₹{Number(breakUpData?.fee) || 0}} textStyle={{ textAlign: "right", fontWeight: "700", fontSize: "24px" }} /> - {t("WS_SERVICE_FEE_HEADER")} - {breakUpData?.billSlabData?.CHARGES?.map(data => ₹{Number(data?.amount) || 0}} textStyle={{ textAlign: "right" }} />)} -
- ₹{Number(breakUpData?.charge) || 0}} textStyle={{ textAlign: "right", fontWeight: "700", fontSize: "24px" }} /> - {breakUpData?.billSlabData?.TAX?.map(data => ₹{Number(data?.amount) || 0}} textStyle={{ textAlign: "right" }} />)} -
- ₹{Number(breakUpData?.totalAmount) || 0}} textStyle={{ textAlign: "right", fontWeight: "700", fontSize: "24px" }} /> -
} -
} -
-
- ) -} - -export default ViewBreakup; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSAdditonalDetails.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSAdditonalDetails.js deleted file mode 100644 index 06814062d96..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSAdditonalDetails.js +++ /dev/null @@ -1,399 +0,0 @@ -import { StatusTable, Row, CardSubHeader } from "@egovernments/digit-ui-react-components"; -import React, { Fragment } from "react"; -import { useTranslation } from "react-i18next"; -import { getQueryStringParams } from "../../../ws/src/utils"; - -const cardSubHeaderStyles = () => { - // return { fontSize: "24px", padding: "0px", margin: "0px", color: "#505A5F" }; - return { fontSize: "24px", marginBottom: "16px", marginTop: "32px" }; -}; - -const cardDivStyles = () => { - return { - border: "1px solid #D6D5D4", - background: "#FAFAFA", - borderRadius: "4px", - padding: "10px 10px 0px 10px", - marginBottom: "10px", - display: "flex", - }; -}; - -const convertEpochToDate = (dateEpoch) => { - if (dateEpoch) { - const dateFromApi = new Date(dateEpoch); - let month = dateFromApi.getMonth() + 1; - let day = dateFromApi.getDate(); - let year = dateFromApi.getFullYear(); - month = (month > 9 ? "" : "0") + month; - day = (day > 9 ? "" : "0") + day; - return `${day}/${month}/${year}`; - } else { - return null; - } -}; - -const WSAdditonalDetails = ({ wsAdditionalDetails, oldValue }) => { - const { t } = useTranslation(); - let filters = getQueryStringParams(location.search); - const serviceType = filters?.service; - const isModify = filters?.mode; - - const oldValueData = oldValue?.[1]; - - const stringReplaceAll = (str = "", searcher = "", replaceWith = "") => { - if (searcher == "") return str; - while (str.includes(searcher)) { - str = str.replace(searcher, replaceWith); - } - return str; - }; - - const renderSWConnectionDetails = () => { - return ( -
- {oldValueData?.connectionType ? ( - - ) : ( -
{"NA"}
- )} - - {oldValueData?.noOfWaterClosets ? ( - - ) : ( -
{"NA"}
- )} - {oldValueData?.noOfToilets ? ( - - ) : ( -
{"NA"}
- )} -
- ); - }; - - const renderWSConnectionDetails = () => { - return ( -
- {oldValueData?.connectionType && ( )} - {oldValueData?.noOfTaps && ( )} - {oldValueData?.waterSource && ( )} - {oldValueData?.pipeSize && ( )} - {oldValueData?.waterSource && ( )} -
- ); - }; - - const renderSWPlumberDetails = () => { - return ( -
- {oldValueData?.additionalDetails?.detailsProvidedBy !== wsAdditionalDetails?.additionalDetails?.plumberDetails[0]?.value && - oldValueData?.additionalDetails?.detailsProvidedBy !== null ? ( - - ) : ( -
{"NA"}
- )} - {oldValueData?.plumberInfo ? ( - - ) : ( -
{"NA"}
- )} - {oldValueData?.plumberInfo ? ( - - ) : ( -
{"NA"}
- )} - {oldValueData?.plumberInfo ? ( - - ) : ( -
{"NA"}
- )} -
- ); - }; - - const renderWSPlumberDetails = () => { - return ( -
- {oldValueData?.additionalDetails?.detailsProvidedBy !== wsAdditionalDetails?.additionalDetails?.plumberDetails[0]?.value ? ( - - ) : ( -
{"NA"}
- )} -
- ); - }; - - const renderSWRoadCuttingDetails = () => { - { - oldValueData?.roadCuttingInfo?.map((info) => { - return ( -
- - -
- ); - }); - } - }; - - const renderSWActivationDetails = () => { - return ( -
- {oldValueData?.connectionExecutionDate ? ( - - ) : ( -
{"NA"}
- )} -
- ); - }; - - const renderWSActivationDetails = () => { - return ( -
- {oldValueData?.meterId && ( )} - {oldValueData?.additionalDetails?.initialMeterReading && ( )} - {oldValueData?.meterInstallationDate && ( )} - {oldValueData?.connectionExecutionDate && ( )} -
- ); - }; - - var { connectionDetails, plumberDetails, roadCuttingDetails, activationDetails } = wsAdditionalDetails?.additionalDetails || {connectionDetails:[], plumberDetails: []}; - - // binding old values with new values - if(isModify === "MODIFY"){ - - connectionDetails = connectionDetails?.map((value) => { - if(value.title == "WS_SERV_DETAIL_CONN_TYPE" && oldValueData?.connectionType) value["oldValue"] = [ - { value:value?.value, className:"newValue", style:{ display:"inline"} }, - { - value:`${t("WS_OLD_LABEL_NAME")} ${oldValueData?.connectionType}`, - className:"oldValue", style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"} - }]; - if(value.title == "WS_SERV_DETAIL_NO_OF_TAPS" && oldValueData?.noOfTaps) value["oldValue"] = [ - {value:value?.value,className:"newValue", style:{ display:"inline"}}, - {value:`${t("WS_OLD_LABEL_NAME")} ${oldValueData?.noOfTaps}`, style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"},className:"oldValue"} - ]; - if(value.title == "WS_SERV_DETAIL_WATER_SOURCE" && oldValueData?.waterSource) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${t(oldValueData?.waterSource?.toUpperCase()?.split(".")[0])}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - if(value.title == "WS_PIPE_SIZE_IN_INCHES_LABEL" && oldValueData?.pipeSize) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.pipeSize}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - if(value.title == "WS_SERV_DETAIL_WATER_SUB_SOURCE" && oldValueData?.waterSource) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${t(oldValueData?.waterSource?.toUpperCase()?.split(".")[1])}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - if(value.title == "WS_NUMBER_WATER_CLOSETS_LABEL" && oldValueData?.noOfWaterClosets) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.noOfWaterClosets}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - if(value.title == "WS_SERV_DETAIL_NO_OF_TOILETS" && oldValueData?.noOfWaterClosets) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.noOfWaterClosets}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - - return value; - }) - - plumberDetails = plumberDetails?.map((value) => { - if(value.title == "WS_ADDN_DETAILS_PLUMBER_PROVIDED_BY" && oldValueData?.additionalDetails?.detailsProvidedBy && oldValueData?.additionalDetails?.detailsProvidedBy !== value.value ) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.additionalDetails?.detailsProvidedBy}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - if(value.title == "WS_ADDN_DETAILS_PLUMBER_LICENCE_NO_LABEL" && oldValueData?.plumberInfo[0]?.licenseNo ) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.plumberInfo[0]?.licenseNo}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - if(value.title == "WS_ADDN_DETAILS_PLUMBER_NAME_LABEL" && oldValueData?.plumberInfo[0]?.name ) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.plumberInfo[0]?.name}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - if(value.title == "WS_PLUMBER_MOBILE_NO_LABEL" && oldValueData?.plumberInfo[0]?.mobileNumber ) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.plumberInfo[0]?.mobileNumber}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - return value; - }) - - roadCuttingDetails = roadCuttingDetails?.map((roadDetail) => { - const roadDetailValues = roadDetail?.values?.map((value) => { - if(value.title == "WS_ADDN_DETAIL_ROAD_TYPE" && oldValueData?.roadCuttingInfo[0]?.roadType) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.roadCuttingInfo[0]?.roadType}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - if(value.title == "WS_ROAD_CUTTING_AREA_LABEL" && oldValueData?.roadCuttingInfo[0]?.roadCuttingArea) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.roadCuttingInfo[0]?.roadCuttingArea}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - return value; - }) - return ({...roadDetail,values:roadDetailValues}); - }) - - activationDetails = activationDetails?.map((value) => { - if(value.title == "WS_SERV_DETAIL_CONN_EXECUTION_DATE" && oldValueData?.connectionExecutionDate) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${convertEpochToDate(oldValueData?.connectionExecutionDate)}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - - if(value.title == "WS_SERV_DETAIL_METER_ID" && oldValueData?.meterId) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.meterId}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - - if(value.title == "WS_INITIAL_METER_READING_LABEL" && oldValueData?.initialMeterReading) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${oldValueData?.initialMeterReading}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - - if(value.title == "WS_INSTALLATION_DATE_LABEL" && oldValueData?.meterInstallationDate) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${convertEpochToDate(oldValueData?.meterInstallationDate)}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - if(value.title == "WS_SERV_DETAIL_CONN_EXECUTION_DATE" && oldValueData?.connectionExecutionDate) value["oldValue"] = [ - {value:value?.value, className:"newValue", style:{ display:"inline"}}, - { - value: `${t("WS_OLD_LABEL_NAME")} ${convertEpochToDate(oldValueData?.connectionExecutionDate)}`, - style:{color:'gray', paddingLeft:"10px", display:"inline", fontSize:"13px"}, className:"oldValue" - } - ]; - return value; - }) - }; - - return ( - -
- {wsAdditionalDetails?.additionalDetails?.connectionDetails && ( - - {t("WS_COMMON_CONNECTION_DETAIL")} -
-
- {connectionDetails?.map((value, index) => { - return ( -
- -
- ); - })} -
-
-
- )} - {wsAdditionalDetails?.additionalDetails?.plumberDetails && ( - - {t("WS_COMMON_PLUMBER_DETAILS")} -
-
- - {plumberDetails?.map((value, index) => { - return ; - })} -
-
-
- )} - {wsAdditionalDetails?.additionalDetails?.roadCuttingDetails && ( - - {t("WS_ROAD_CUTTING_DETAILS")} -
-
- {roadCuttingDetails?.map((value) => { - return ( -
1 - ? { - border: "1px solid #D6D5D4", - background: "#FAFAFA", - borderRadius: "4px", - padding: "10px 10px 0px 10px", - margin: "5px 0px", - } - : {} - } - > - {value?.values?.map((roadValue) => ( - - ))} -
- ); - })} -
-
-
- )} - {wsAdditionalDetails?.additionalDetails?.activationDetails && ( - - {t("WS_ACTIVATION_DETAILS")} -
-
- {activationDetails?.map((value, index) => { - return ( - - ); - })} -
-
-
- )} -
-
- ); -}; - -export default WSAdditonalDetails; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSFeeEstimation.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSFeeEstimation.js deleted file mode 100644 index 9a4fe591f9d..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WSFeeEstimation.js +++ /dev/null @@ -1,346 +0,0 @@ -import React, { useState, Fragment, useEffect } from "react"; -import { useTranslation } from "react-i18next"; -import { Card, CardSectionHeader, CardLabel } from "@egovernments/digit-ui-react-components"; -import { Modal, Dropdown, Row, StatusTable, TextInput, Toast } from "@egovernments/digit-ui-react-components"; -import cloneDeep from "lodash/cloneDeep"; - -const Penality_menu = [ - { - title: "PT_PENDING_DUES_FROM_EARLIER", - value: "Pending dues from earlier", - }, - { - title: "PT_MISCALCULATION_OF_EARLIER_ASSESSMENT", - value: "Miscalculation of earlier Assessment", - }, - { - title: "PT_ONE_TIME_PENALITY", - value: "One time penality", - }, - { - title: "PT_OTHERS", - value: "Others", - }, -] -const Rebate_menu = [ - { - title: "PT_ADVANCED_PAID_BY_CITIZEN_EARLIER", - value: "Advanced Paid By Citizen Earlier", - }, - { - title: "PT_REBATE_PROVIDED_BY_COMMISSIONER_EO", - value: "Rebate provided by commissioner/EO", - }, - { - title: "PT_ADDITIONAL_AMOUNT_CHARGED_FROM_THE_CITIZEN", - value: "Additional amount charged from the citizen", - }, - { - title: "PT_OTHERS", - value: "Others", - }, -]; - - -const WSFeeEstimation = ({ wsAdditionalDetails, workflowDetails }) => { - const { t } = useTranslation(); - const [sessionFormData, setSessionFormData, clearSessionFormData] = Digit.Hooks.useSessionStorage("ADHOC_ADD_REBATE_DATA", {}); - const [sessionBillFormData, setSessionBillFormData, clearBillSessionFormData] = Digit.Hooks.useSessionStorage("ADHOC_BILL_ADD_REBATE_DATA", {}); - const isPaid = wsAdditionalDetails?.additionalDetails?.isPaid ? true : false; - const [popup, showPopUp] = useState(false); - const [fields, setFields] = useState(sessionFormData ? sessionFormData : {}); - const [showToast, setShowToast] = useState(null); - const [billDetails, setBillDetails] = useState(wsAdditionalDetails.additionalDetails.data ? wsAdditionalDetails.additionalDetails.data : {}); - const [values, setValues] = useState(wsAdditionalDetails.additionalDetails.values ? wsAdditionalDetails.additionalDetails.values : []); - - const stateCode = Digit.ULBService.getStateId(); - const { isMdmsLoading, data: mdmsRes } = Digit.Hooks.ws.useMDMS(stateCode, "BillingService", ["TaxHeadMaster"]); - - useEffect(() => { - const data = { ...wsAdditionalDetails?.additionalDetails?.appDetails?.additionalDetails }; - setSessionFormData(data); - setFields(data); - if (sessionFormData?.billDetails?.length > 0) { - const values = [ - { title: "WS_APPLICATION_FEE_HEADER", value: sessionFormData?.billDetails?.[0]?.fee }, - { title: "WS_SERVICE_FEE_HEADER", value: sessionFormData?.billDetails?.[0]?.charge }, - { title: "WS_TAX_HEADER", value: sessionFormData?.billDetails?.[0]?.taxAmount }, - ]; - setValues(values); - setBillDetails(sessionFormData?.billDetails?.[0]); - } - }, []); - - let validation = {}; - - const Heading = (props) => { - return

{props.label}

; - }; - - const Close = () => ( - - - - - ); - - const CloseBtn = (props) => { - return ( -
- -
- ); - }; - - const closeToast = () => { - setShowToast(false); - }; - - const addAdhocRebatePenality = (e) => { - const adhocAmount = fields?.adhocPenalty ? Number(fields?.adhocPenalty) : 0; - const rebateAmount = fields?.adhocRebate ? Number(fields?.adhocRebate) : 0; - if (adhocAmount || rebateAmount) { - - const totalAmount = wsAdditionalDetails?.additionalDetails?.data?.totalAmount; - const demandId = wsAdditionalDetails?.additionalDetails?.data?.billDetails?.[0]?.demandId; - - if (rebateAmount > totalAmount) { - setShowToast({ isError: false, isWarning: true, key: "error", message: t("ERR_WS_REBATE_GREATER_THAN_AMOUNT") }); - } else { - const applicationNo = wsAdditionalDetails?.additionalDetails?.appDetails?.applicationNo; - const tenantId = wsAdditionalDetails?.additionalDetails?.appDetails?.tenantId; - const appAdditionalDetails = { ...wsAdditionalDetails?.additionalDetails?.appDetails?.additionalDetails, ...fields } - wsAdditionalDetails.additionalDetails.appDetails.additionalDetails = appAdditionalDetails; - - const data = { - CalculationCriteria: - wsAdditionalDetails?.additionalDetails?.appDetails?.service == "WATER" - ? [ - { - applicationNo: applicationNo, - tenantId: tenantId, - waterConnection: wsAdditionalDetails.additionalDetails.appDetails, - }, - ] - : [ - { - applicationNo: applicationNo, - tenantId: tenantId, - sewerageConnection: wsAdditionalDetails.additionalDetails.appDetails, - }, - ], - isconnectionCalculation: false, - }; - - let businessService = wsAdditionalDetails?.additionalDetails?.appDetails?.service == "WATER" ? "WS" : "SW"; - Digit.WSService.wsCalculationEstimate(data, businessService) - .then((result, err) => { - if (result?.Calculation?.[0]?.taxHeadEstimates?.length > 0) { - result?.Calculation?.[0]?.taxHeadEstimates?.forEach(data => data.amount = data.estimateAmount); - } - - result.Calculation[0].billSlabData = _.groupBy(result?.Calculation?.[0]?.taxHeadEstimates, 'category'); - const values = [ - { title: "WS_APPLICATION_FEE_HEADER", value: result.Calculation?.[0]?.fee }, - { title: "WS_SERVICE_FEE_HEADER", value: result.Calculation?.[0]?.charge }, - { title: "WS_TAX_HEADER", value: result.Calculation?.[0]?.taxAmount }, - ]; - setSessionBillFormData(cloneDeep(result.Calculation[0])); - setBillDetails(result?.Calculation?.[0]); - setValues(values); - fields.billDetails = result?.Calculation; - setSessionFormData(fields); - showPopUp(false); - }) - .catch((e) => { - setShowToast({ isError: true, isWarning: false, key: "error", message: e?.response?.data?.Errors[0]?.message ? t(`${e?.response?.data?.Errors[0]?.code}`) : t("PT_COMMON_ADD_REBATE_PENALITY") }); - }); - } - } else { - setShowToast({ isError: false, isWarning: true, key: "warning", message: t("ERR_WS_ENTER_ATLEAST_ONE_FIELD") }); - } - } - - const selectedValuesData = (value, isDropDownValue = false, e) => { - let values = { ...fields }; - if (isDropDownValue) { - values[`${value}_data`] = e; - values[value] = e.title; - if (e.title == "PT_OTHERS" && value == "adhocPenaltyReason") values[`adhocPenaltyComment`] = ""; - if (e.title == "PT_OTHERS" && value == "adhocRebateReason") values[`adhocRebateComment`] = ""; - } else { - values[value] = e.target.value; - } - setFields(values); - } - - return ( - -
- {values && - -
- {values?.map((value, index) => { - return - })} -
-
-
- - -
-
} - { - wsAdditionalDetails?.additionalDetails?.isAdhocRebate ?
{ - showPopUp(true) - }} - > - {t("WS_PAYMENT_ADD_REBATE_PENALTY")} -
: null - } - {popup && - } - headerBarEnd={ - { - setFields(sessionFormData); - showPopUp(false); - }} />} - actionCancelLabel={t("PT_CANCEL")} - actionCancelOnSubmit={() => { - setFields(sessionFormData); - showPopUp(false); - }} - actionSaveLabel={t("PT_ADD")} - actionSaveOnSubmit={(e) => addAdhocRebatePenality(e)} - hideSubmit={false} - popupStyles={{ overflowY: "auto" }} - > - { -
- - {t("PT_AD_PENALTY")} - - {t("PT_TX_HEADS")} - -
- selectedValuesData("adhocPenaltyReason", true, e)} - selected={fields?.adhocPenaltyReason_data || ""} - isPropertyAssess={true} - name={"adhocPenaltyReason_data"} - t={t} - /> -
- {fields?.adhocPenaltyReason_data?.title === "PT_OTHERS" &&
- {t("PT_REASON")} -
- selectedValuesData("adhocPenaltyComment", false, e)} - {...(validation = { - isRequired: true, - pattern: "^[a-zA-Z-.`' ]*$", - type: "text", - title: t("TL_NAME_ERROR_MESSAGE"), - })} - /> -
-
} - {t("PT_HEAD_AMT")} -
- selectedValuesData("adhocPenalty", false, e)} - {...(validation = { - isRequired: true, - pattern: "^[1-9]+[0-9]*$", - title: t("ERR_DEFAULT_INPUT_FIELD_MSG"), - })} - /> - -
-
- - {t("PT_AD_REBATE")} - {t("PT_TX_HEADS")} -
- selectedValuesData("adhocRebateReason", true, e)} - selected={fields?.adhocRebateReason_data || ""} - name={"adhocRebateReason_data"} - isPropertyAssess={true} - t={t} - /> -
- {fields?.adhocRebateReason_data?.title === "PT_OTHERS" &&
- {t("PT_REASON")} - selectedValuesData("adhocRebateComment", false, e)} - {...(validation = { - isRequired: true, - pattern: "^[a-zA-Z-.`' ]*$", - type: "text", - title: t("TL_NAME_ERROR_MESSAGE"), - })} - /> -
} - {t("PT_HEAD_AMT")} -
- selectedValuesData("adhocRebate", false, e)} - {...(validation = { - isRequired: true, - pattern: "^[1-9]+[0-9]*$", - title: t("ERR_DEFAULT_INPUT_FIELD_MSG"), - })} - /> -
-
-
- }
} - {showToast && - } -
-
- ) -} - -export default WSFeeEstimation; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WeekDateRange.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WeekDateRange.js deleted file mode 100644 index 75069dd741f..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/components/WeekDateRange.js +++ /dev/null @@ -1,30 +0,0 @@ -import React, { useCallback, useState } from "react"; -import { useTranslation } from "react-i18next"; - -const WeekDateRange = (props) => { - const [localSearchParams, setLocalSearchParams] = useState(() => ({})); - const { t } = useTranslation(); - const handleChange = useCallback((data) => { - setLocalSearchParams(() => ({ ...data })); - }, []); - - return ( -
-
-

{props.title}

-
- -
-
-
- ); -}; - -export default WeekDateRange; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AcceptDso.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AcceptDso.js deleted file mode 100644 index e870f2e9a67..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AcceptDso.js +++ /dev/null @@ -1,45 +0,0 @@ -import React from "react"; -import { Dropdown } from "@egovernments/digit-ui-react-components"; - -export const configAcceptDso = ({ t, dsoData, dso, selectVehicleNo, vehicleNoList, vehicleNo, vehicle, action }) => { - return { - label: { - heading: `ES_FSM_ACTION_TITLE_${action}`, - submit: `CS_COMMON_${action}`, - cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - label: t("ES_FSM_ACTION_VEHICLE_REGISTRATION_NO"), - isMandatory: true, - type: "dropdown", - populators: ( - - ), - }, - { - label: t("ES_FSM_ACTION_VEHICLE_CAPACITY_IN_LTRS"), - isMandatory: true, - type: "text", - populators: { - name: "capacity", - validation: { - required: true, - }, - }, - disable: true, - }, - ], - }, - ], - }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AssignDso.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AssignDso.js deleted file mode 100644 index 418caf1e4bc..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/AssignDso.js +++ /dev/null @@ -1,115 +0,0 @@ -import React from "react"; -import { DatePicker, Dropdown, CardLabelError } from "@egovernments/digit-ui-react-components"; - -function todayDate() { - var today = new Date(); - var dd = today.getDate(); - var mm = today.getMonth() + 1; - var yyyy = today.getFullYear(); - - if (dd < 10) { - dd = "0" + dd; - } - - if (mm < 10) { - mm = "0" + mm; - } - - return yyyy + "-" + mm + "-" + dd; -} - -function getFilteredDsoData(dsoData, vehicle) { - return dsoData?.filter((e) => e.vehicles?.find((veh) => veh?.type == vehicle?.code)); -} - -export const configAssignDso = ({ t, dsoData, dso, selectDSO, vehicleMenu, vehicle, selectVehicle, action }) => { - return { - label: { - heading: `ES_FSM_ACTION_TITLE_${action}`, - submit: `CS_COMMON_${action}`, - cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - label: t("ES_FSM_ACTION_VEHICLE_TYPE"), - isMandatory: true, - type: "dropdown", - populators: ( - - ), - }, - { - label: t("ES_FSM_ACTION_DSO_NAME"), - isMandatory: true, - type: "dropdown", - populators: ( - - {getFilteredDsoData(dsoData, vehicle) && !getFilteredDsoData(dsoData, vehicle).length ? ( - {t("ES_COMMON_NO_DSO_AVAILABLE_WITH_SUCH_VEHICLE")} - ) : null} - - - ), - }, - { - label: t("ES_FSM_ACTION_VEHICLE_CAPACITY_IN_LTRS"), - isMandatory: true, - type: "text", - populators: { - name: "capacity", - validation: { - required: true, - }, - }, - disable: true, - }, - // { - // label: t("ES_FSM_ACTION_SERVICE_DATE"), - // isMandatory: true, - // type: "date", - // populators: { - // name: "date", - // validation: { - // required: true, - // }, - // min: Digit.Utils.date.getDate(), - // defaultValue: Digit.Utils.date.getDate(), - // }, - // }, - { - label: t("ES_FSM_ACTION_SERVICE_DATE"), - isMandatory: true, - type: "custom", - populators: { - name: "date", - validation: { - required: true, - }, - customProps: { min: Digit.Utils.date.getDate() }, - defaultValue: Digit.Utils.date.getDate(), - component: (props, customProps) => , - }, - }, - ], - }, - ], - }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAApproverApplication.js deleted file mode 100644 index ca66865bb77..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAApproverApplication.js +++ /dev/null @@ -1,77 +0,0 @@ -import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; -import React from "react"; - -export const configBPAApproverApplication = ({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - assigneeLabel, - businessService, - error -}) => { - let isRejectOrRevocate = false; - if(action?.action == "REVOCATE" || action?.action == "REJECT" || action.action == "SKIP_PAYMENT" || action?.action == "SEND_BACK_TO_CITIZEN" || action?.action == "APPROVE") { - isRejectOrRevocate = true; - } - - let isCommentRequired = false; - if(action?.action == "REVOCATE" || action?.action == "REJECT") { - isCommentRequired = true; - } - - return { - label: { - heading: `WF_${action?.action}_APPLICATION`, - submit: `WF_${businessService}_${action?.action}`, - cancel: "BPA_CITIZEN_CANCEL_BUTTON", - }, - form: [ - { - body: [ - { - label: action.isTerminateState || isRejectOrRevocate ? null : t(assigneeLabel || `WF_ROLE_${action.assigneeRoles?.[0]}`), - type: "dropdown", - populators: action.isTerminateState || isRejectOrRevocate ? null : ( - - ), - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - isMandatory: isCommentRequired, - populators: { - name: "comments", - }, - }, - { - label: `${t("WF_APPROVAL_UPLOAD_HEAD")}`, - populators: ( - { - setUploadedFile(null); - }} - message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} - accept= "image/*, .pdf, .png, .jpeg, .jpg" - iserror={error} - /> - ), - }, - ], - }, - ], - }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAREGApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAREGApproverApplication.js deleted file mode 100644 index 0bdba14bc5b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/BPAREGApproverApplication.js +++ /dev/null @@ -1,71 +0,0 @@ -import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; -import React from "react"; - -export const configBPAREGApproverApplication = ({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - assigneeLabel, - businessService, - error -}) => { - let checkCondtions = true; - if (action?.action == "SENDBACKTOCITIZEN") checkCondtions = false; - if (action.isTerminateState) checkCondtions = false; - - return { - label: { - heading: `WF_${action?.action}_APPLICATION`, - submit: `WF_${businessService?.toUpperCase()}_${action?.action}`, - cancel: "WF_EMPLOYEE_BPAREG_CANCEL", - }, - form: [ - { - body: [ - { - label: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_LABEL"), - placeholder: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - type: "dropdown", - populators: !checkCondtions ? null : ( - - ), - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - { - label: t("BPA_APPROVAL_CHECKLIST_BUTTON_UP_FILE"), - populators: ( - { - setUploadedFile(null); - }} - message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} - accept= "image/*, .pdf, .png, .jpeg, .jpg" - iserror={error} - /> - ) - }, - ], - }, - ], - }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/CompleteApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/CompleteApplication.js deleted file mode 100644 index a4c7c96b2fd..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/CompleteApplication.js +++ /dev/null @@ -1,46 +0,0 @@ -import React from "react"; -import { DatePicker } from "@egovernments/digit-ui-react-components"; - -export const configCompleteApplication = ({ t, vehicle, applicationCreatedTime = 0, action }) => ({ - label: { - heading: `ES_FSM_ACTION_TITLE_${action}`, - submit: `CS_COMMON_${action}`, - cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - label: t("ES_FSM_ACTION_DESLUGED_DATE_LABEL"), - isMandatory: true, - type: "custom", - populators: { - name: "desluged", - validation: { - required: true, - }, - defaultValue: Digit.Utils.date.getDate(), - customProps: { - min: Digit.Utils.date.getDate(applicationCreatedTime), - max: Digit.Utils.date.getDate(), - }, - component: (props, customProps) => , - }, - }, - { - label: t("ES_FSM_ACTION_WASTE_VOLUME_LABEL"), - type: "text", - isMandatory: true, - populators: { - name: "wasteCollected", - validation: { - required: true, - validate: (value) => parseInt(value) <= parseInt(vehicle.capacity), - }, - error: `${t("ES_FSM_ACTION_INVALID_WASTE_VOLUME")} ${vehicle?.capacity} ${t("CS_COMMON_LITRES")}`, - }, - }, - ], - }, - ], -}); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/NOCApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/NOCApproverApplication.js deleted file mode 100644 index 12922b0575e..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/NOCApproverApplication.js +++ /dev/null @@ -1,79 +0,0 @@ -import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; -import React from "react"; - -export const configNOCApproverApplication = ({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - assigneeLabel, - businessService, - error -}) => { - - let isCommentRequired = false; - if(action?.action == "REVOCATE" || action?.action == "REJECT") { - isCommentRequired = true; - } - - let isRejectOrRevocate = false; - if(action?.action == "APPROVE" || action?.action == "REJECT" || action.action == "AUTO_APPROVE" || action.action == "AUTO_REJECT") { - isRejectOrRevocate = true; - } - - return { - label: { - heading: `WF_${action?.action}_APPLICATION`, - submit: `WF_${businessService}_${action?.action}`, - cancel: "CORE_LOGOUTPOPUP_CANCEL", - }, - form: [ - { - body: [ - { - label: action.isTerminateState || isRejectOrRevocate ? null : t(assigneeLabel || `WF_ROLE_${action.assigneeRoles?.[0]}`), - type: "dropdown", - populators: action.isTerminateState || isRejectOrRevocate ? null : ( - - ), - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - isMandatory: isCommentRequired, - populators: { - name: "comments", - }, - }, - { - label: `${t("WF_APPROVAL_UPLOAD_HEAD")}`, - populators: ( - { - setUploadedFile(null); - }} - showHint={true} - message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} - accept= "image/*, .pdf, .png, .jpeg, .jpg" - iserror={error} - /> - ), - }, - ], - }, - ], - }; -}; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTApproverApplication.js deleted file mode 100644 index afcc6a19be2..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTApproverApplication.js +++ /dev/null @@ -1,66 +0,0 @@ -import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; -import React from "react"; - -export const configPTApproverApplication = ({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - assigneeLabel, - businessService, -}) => { - return { - label: { - heading: `WF_${action?.action}_APPLICATION`, - submit: `WF_${businessService}_${action?.action}`, - cancel: "ES_PT_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - label: action.isTerminateState || action?.action === "SENDBACKTOCITIZEN" ? null : t(assigneeLabel || `WF_ROLE_${action.assigneeRoles?.[0]}`), - // isMandatory: !action.isTerminateState, - type: "dropdown", - populators: action.isTerminateState || action?.action === "SENDBACKTOCITIZEN" ? null : ( - - ), - }, - { - label: t("ES_PT_ACTION_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - { - label: `${t("ES_PT_ATTACH_FILE")}${action.docUploadRequired ? " *" : ""}`, - populators: ( - { - setUploadedFile(null); - }} - showHint={true} - hintText={t("PT_ATTACH_RESTRICTIONS_SIZE")} - message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`ES_PT_ACTION_NO_FILEUPLOADED`)} - /> - ), - }, - ], - }, - ], - }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTAssessProperty.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTAssessProperty.js deleted file mode 100644 index dd04037aab6..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/PTAssessProperty.js +++ /dev/null @@ -1,26 +0,0 @@ -import React from "react"; -import { RadioButtons } from "@egovernments/digit-ui-react-components"; - -export const configPTAssessProperty = ({ t, action, financialYears, selectedFinancialYear, setSelectedFinancialYear }) => { - return { - label: { - heading: `WF_${action.action}_APPLICATION`, - submit: `WF_PT.CREATE_${action.action}`, - cancel: "ES_PT_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - label: t("ES_PT_FINANCIAL_YEARS"), - isMandatory: true, - type: "radio", - populators: ( - - ), - }, - ], - }, - ], - }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/ReassignDso.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/ReassignDso.js deleted file mode 100644 index 132a5bc6a7c..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/ReassignDso.js +++ /dev/null @@ -1,101 +0,0 @@ -import React from "react"; -import { Dropdown } from "@egovernments/digit-ui-react-components"; - -function getFilteredDsoData(dsoData, vehicle) { - return dsoData?.filter((e) => e.vehicles?.find((veh) => veh?.type == vehicle?.code)); -} - -export const configReassignDSO = ({ - t, - dsoData, - dso, - selectDSO, - vehicleMenu, - vehicle, - selectVehicle, - reassignReasonMenu, - reassignReason, - selectReassignReason, - action, - showReassignReason, -}) => ({ - label: { - heading: `ES_FSM_ACTION_TITLE_${action}`, - submit: `CS_COMMON_${action}`, - cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - ...(showReassignReason - ? [ - { - label: t("ES_FSM_ACTION_REASSIGN_REASON"), - type: "dropdown", - isMandatory: true, - populators: ( - - ), - }, - ] - : []), - { - label: t("ES_FSM_ACTION_VEHICLE_TYPE"), - isMandatory: vehicle ? false : true, - type: "dropdown", - populators: ( - - ), - }, - { - label: t("ES_FSM_ACTION_DSO_NAME"), - isMandatory: true, - type: "dropdown", - populators: ( - - ), - }, - { - label: t("ES_FSM_ACTION_VEHICLE_CAPACITY_IN_LTRS"), - type: "text", - populators: { - name: "capacity", - validation: { - required: true, - }, - }, - disable: true, - }, - { - label: t("ES_FSM_ACTION_SERVICE_DATE"), - isMandatory: true, - type: "date", - populators: { - name: "date", - validation: { - required: true, - }, - min: Digit.Utils.date.getDate(), - defaultValue: Digit.Utils.date.getDate(), - }, - }, - ], - }, - ], -}); diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/RejectApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/RejectApplication.js deleted file mode 100644 index a18bdaf1110..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/RejectApplication.js +++ /dev/null @@ -1,31 +0,0 @@ -import React from "react"; -import { Dropdown } from "@egovernments/digit-ui-react-components"; - -export const configRejectApplication = ({ t, rejectMenu, setReason, reason, action }) => { - return { - label: { - heading: `ES_FSM_ACTION_TITLE_${action}`, - submit: `CS_COMMON_${action}`, - cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - label: t(`ES_FSM_ACTION_${action.toUpperCase()}_REASON`), - type: "dropdown", - populators: , - isMandatory: true, - }, - { - label: t("ES_FSM_ACTION_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ], - }, - ], - }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/TLApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/TLApproverApplication.js deleted file mode 100644 index 23b20e5be2b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/TLApproverApplication.js +++ /dev/null @@ -1,83 +0,0 @@ -import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; -import React from "react"; - -export const configTLApproverApplication = ({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - assigneeLabel, - businessService, -}) => { - let checkCondtions = true; - if (action?.action == "SENDBACKTOCITIZEN" || action?.action == "APPROVE") checkCondtions = false; - if (action.isTerminateState) checkCondtions = false; - - return { - label: { - heading: `WF_${action?.action}_APPLICATION`, - submit: `WF_${businessService?.toUpperCase()}_${action?.action}`, - cancel: "WF_EMPLOYEE_NEWTL_CANCEL", - }, - form: [ - { - body: [ - { - label: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_LABEL"), - placeholder: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - // isMandatory: false, - type: "dropdown", - populators: !checkCondtions ? null : ( - - ), - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - { - label: t("TL_APPROVAL_CHECKLIST_BUTTON_UP_FILE"), - populators: ( - { - setUploadedFile(null); - }} - message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} - /> - ) - }, - // { - // label: action.docUploadRequired ? t("ES_PT_UPLOAD_FILE") : null, - // populators: action.docUploadRequired ? ( - // { - // setUploadedFile(null); - // }} - // message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`ES_PT_ACTION_NO_FILEUPLOADED`)} - // /> - // ) : null, - // }, - ], - }, - ], - }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSApproverApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSApproverApplication.js deleted file mode 100644 index 2f5f2d45a6a..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSApproverApplication.js +++ /dev/null @@ -1,73 +0,0 @@ -import { Dropdown, UploadFile } from "@egovernments/digit-ui-react-components"; -import React from "react"; - -export const configWSApproverApplication = ({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - assigneeLabel, - businessService, - error -}) => { - let checkCondtions = true; - if (action?.action?.includes("SEND_BACK") || action?.action == "APPROVE_FOR_CONNECTION") checkCondtions = false; - if (action.isTerminateState) checkCondtions = false; - - return { - label: { - heading: `WF_${action?.action}_APPLICATION`, - submit: `WF_${businessService?.toUpperCase()}_${action?.action}`, - cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - label: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_LABEL"), - placeholder: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - // isMandatory: false, - type: "dropdown", - populators: !checkCondtions ? null : ( - - ), - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - { - label: t("WS_APPROVAL_CHECKLIST_BUTTON_UP_FILE"), - populators: ( - { - setUploadedFile(null); - }} - message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} - error={error} - iserror={error} - /> - ) - }, - ], - }, - ], - }; -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSDisconnectApplication.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSDisconnectApplication.js deleted file mode 100644 index 5acdcebe041..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/WSDisconnectApplication.js +++ /dev/null @@ -1,89 +0,0 @@ -import { Dropdown, UploadFile, DatePicker } from "@egovernments/digit-ui-react-components"; -import React from "react"; - -export const configWSDisConnectApplication = ({ - t, - action, - approvers, - selectedApprover, - setSelectedApprover, - selectFile, - uploadedFile, - setUploadedFile, - assigneeLabel, - businessService, - error -}) => { - let checkCondtions = true, isDatePickerDisplay = false; - if (action?.action?.includes("SEND_BACK") || action?.action == "APPROVE_FOR_DISCONNECTION" || action?.action == "RESUBMIT_APPLICATION") checkCondtions = false; - if (action.isTerminateState) checkCondtions = false; - if (action?.action == "EXECUTE_DISCONNECTION" || action?.action == "DISCONNECTION_EXECUTED") isDatePickerDisplay = true; - - - return { - label: { - heading: `WF_${action?.action}_APPLICATION`, - submit: `WF_${businessService?.toUpperCase()}_${action?.action}`, - cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - label: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_LABEL"), - placeholder: !checkCondtions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - // isMandatory: false, - type: "dropdown", - populators: !checkCondtions ? null : ( - - ), - }, - isDatePickerDisplay && { - label: t("ES_FSM_ACTION_SERVICE_DATE"), - isMandatory: isDatePickerDisplay ? true : false, - type: "custom", - populators: isDatePickerDisplay ? { - name: "date", - validation: { - required: true, - }, - // customProps: { max: Digit.Utils.date.getDate() }, - defaultValue: Digit.Utils.date.getDate(), - component: (props, customProps) => , - } : null, - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - { - label: t("WS_APPROVAL_CHECKLIST_BUTTON_UP_FILE"), - populators: ( - { - setUploadedFile(null); - }} - message={uploadedFile ? `1 ${t(`ES_PT_ACTION_FILEUPLOADED`)}` : t(`CS_ACTION_NO_FILEUPLOADED`)} - error={error} - iserror={error} - /> - ) - }, - ], - }, - ], - }; -}; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configApproveModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configApproveModal.js deleted file mode 100644 index 03beb885925..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configApproveModal.js +++ /dev/null @@ -1,53 +0,0 @@ -import { Dropdown } from '@egovernments/digit-ui-react-components'; -import React, { useState } from 'react' - -const configApproveModal = ({ - t, - action -}) => { - if(action?.action === 'ADMINSANCTION'){ - return { - label: { - heading: `WORKS_APPROVE_ESTIMATE`, - submit: `WORKS_APPROVE_ESTIMATE`, - cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ] - } - ] - } - - }else - return { - label: { - heading: `WORKS_APPROVE_LOI`, - submit: `WORKS_APPROVE_LOI`, - cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ] - } - ] - } -} - -export default configApproveModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceApproveModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceApproveModal.js deleted file mode 100644 index 06a29a26339..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceApproveModal.js +++ /dev/null @@ -1,27 +0,0 @@ - -const configAttendanceApproveModal = ({ t, action }) => { - if (action?.applicationStatus === "APPROVED") { - return { - label: { - heading: t("ATM_PROCESSINGMODAL_HEADER"), - submit: t("ATM_FORWARD_FOR_APPROVAL"), - cancel: t("CS_COMMON_CANCEL"), - }, - form: [ - { - body: [ - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ], - }, - ] - }; - } -}; - -export default configAttendanceApproveModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceCheckModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceCheckModal.js deleted file mode 100644 index 374219cc6d4..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceCheckModal.js +++ /dev/null @@ -1,93 +0,0 @@ -const configAttendanceCheckModal = ({ - t, - action, - businessService, - approvers, - selectedApprover, - setSelectedApprover, - designation, - selectedDesignation, - setSelectedDesignation, - department, - selectedDept, - setSelectedDept, - approverLoading = false, -}) => { - let checkConditions = true; - if (action.isTerminateState) checkConditions = false; - - if (designation?.length === 0 || department?.length === 0) return {}; - - if (action?.applicationStatus === "ATTENDANCE_CHECKED") { - return { - label: { - heading: t("ATM_PROCESSINGMODAL_HEADER"), - submit: t("ATM_FORWARD_FOR_CHECK"), - cancel: t("WORKS_CANCEL"), - }, - form: [ - { - body: [ - { - isMandatory: true, - key: "department", - type: "radioordropdown", - label: !checkConditions ? null : t("ATM_APPROVER_DEPT"), - disable: false, - populators: { - name: "department", - optionsKey: "i18nKey", - error: "Department is required", - required: true, - options: department, - }, - }, - { - isMandatory: true, - key: "designation", - type: "radioordropdown", - label: !checkConditions ? null : t("ATM_APPROVER_DESIGNATION"), - disable: false, - populators: { - name: "designation", - optionsKey: "i18nKey", - error: "Designation is required", - required: true, - options: designation, - }, - }, - { - isMandatory: true, - key: "approvers", - type: "radioordropdown", - label: !checkConditions ? null : t("WORKS_APPROVER"), - disable: false, - populators: { - name: "approvers", - optionsKey: "nameOfEmp", - error: "Designation is required", - required: true, - options: approvers, - }, - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ], - }, - ], - defaultValues: { - department: "", - designation: "", - approvers: "", - comments: "", - }, - }; - } -}; - -export default configAttendanceCheckModal; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceRejectModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceRejectModal.js deleted file mode 100644 index c732127aac7..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configAttendanceRejectModal.js +++ /dev/null @@ -1,61 +0,0 @@ -import { LabelFieldPair,CardLabel} from '@egovernments/digit-ui-react-components'; -import React from 'react' - -const configAttendanceRejectModal = ({ - t, - empDepartment, - empDesignation, - empName -}) => { - - const fieldLabelStyle = { - "display" : "grid", - "gridTemplateColumns" : "60% 1fr" - }; - - return { - label: { - heading: t("ATM_PROCESSINGMODAL_HEADER"), - submit: t("ATM_CONFIRM_REJECT"), - cancel: t("CS_COMMON_CANCEL"), - }, - form: [ - { - body: [ - { - withoutLabel:true, - populators: - {t("ATM_DEPARTMENT")} - {empDepartment} - , - }, - { - withoutLabel:true, - populators: - {t("ATM_DESIGNATION")} - {empDesignation} - , - }, - { - withoutLabel:true, - populators: - {t("ATM_REJECTED_BY")} - {empName} - , - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - key: "org_name", - populators: { - name: "comments", - }, - }, - ] - } - ] - } - -} - -export default configAttendanceRejectModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configCheckModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configCheckModal.js deleted file mode 100644 index c267eb9f32f..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configCheckModal.js +++ /dev/null @@ -1,105 +0,0 @@ -import { Dropdown,Loader } from '@egovernments/digit-ui-react-components'; -import React,{useState} from 'react' - -const configCheckModal = ({ - t, - action, - businessService, - approvers, - selectedApprover, - setSelectedApprover, - designation, - selectedDesignation, - setSelectedDesignation, - department, - selectedDept, - setSelectedDept, - approverLoading=false, -}) => { - - let checkConditions = true - if (action.isTerminateState) checkConditions = false; - - if(designation?.length===0 || department?.length===0) return {} - - return { - label: { - heading: `WORKS_CHECK_FORWARD`, - submit: `WORKS_FORWARD_FOR_APPROVAL`, - cancel: "WORKS_CANCEL", - }, - form: [ - { - body:[ - { - label: !checkConditions ? null : t("WORKS_APPROVER_DEPT"), - placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - isMandatory: true, - type: "goToDefaultCase", - populators: !checkConditions ? null : ( - { - setSelectedDept(val) - setSelectedApprover("") - //setValue() - }} - selected={selectedDept} - t={t} - /> - ), - }, - { - label: !checkConditions ? null : t("WORKS_APPROVER_DESIGNATION"), - //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - isMandatory: true, - type: "goToDefaultCase", - populators: !checkConditions ? null : ( - { - setSelectedDesignation(val) - setSelectedApprover("") - //resetting approver dropdown when dept/designation changes - }} - selected={selectedDesignation} - t={t} - /> - ), - }, - { - label: !checkConditions ? null : t("WORKS_APPROVER"), - //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - isMandatory: true, - type: "goToDefaultCase", - populators: !checkConditions ? null : ( - approverLoading ? : - ), - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ] - } - ] - } -} - -export default configCheckModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configRejectModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configRejectModal.js deleted file mode 100644 index ae4be5af3fd..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configRejectModal.js +++ /dev/null @@ -1,127 +0,0 @@ -import { Dropdown,LabelFieldPair,CardLabel} from '@egovernments/digit-ui-react-components'; -import React, { useState } from 'react' - -const configRejectModal = ({ - t, - action, - rejectReasons, - selectedReason, - setSelectedReason, - loiNumber, - department, - estimateNumber -}) => { - - let checkConditions = true - if (action.isTerminateState) checkConditions = false; - - if(rejectReasons?.length === 0) return {} - if(loiNumber){ - return { - label: { - heading: `WORKS_REJECT_LOI`, - submit: `WORKS_REJECT_LOI`, - //cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - withoutLabel:true, - populators: - {t("WORKS_DEPARTMENT")} - {"ENGG"} - , - }, - { - //label: t("WORKS_LOI_ID"), - //type: "text", - withoutLabel: true, - populators: - {t("WORKS_LOI_ID")} - {loiNumber} - - }, - { - label: !checkConditions ? null : t("WORKS_REJECT_REASON"), - //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - // isMandatory: false, - type: "goToDefaultCase", - populators: !checkConditions ? null : ( - - ), - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ] - } - ] - } - }else{ - return { - label: { - heading: `WORKS_REJECT_ESTIMATE`, - submit: `WORKS_REJECT_ESTIMATE`, - //cancel: "CS_COMMON_CANCEL", - }, - form: [ - { - body: [ - { - withoutLabel:true, - populators: - {t("WORKS_DEPARTMENT")} - {"ENGG"} - , - }, - { - //label: t("WORKS_LOI_ID"), - //type: "text", - withoutLabel: true, - populators: - {t("WORKS_ESTIMATE_ID")} - {estimateNumber} - - }, - { - label: !checkConditions ? null : t("WORKS_REJECT_REASON"), - //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - // isMandatory: false, - type: "goToDefaultCase", - populators: !checkConditions ? null : ( - - ), - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ] - } - ] - } - - } -} - -export default configRejectModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillApproveModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillApproveModal.js deleted file mode 100644 index cd01fdc4414..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillApproveModal.js +++ /dev/null @@ -1,57 +0,0 @@ -import React from 'react' -import { LabelFieldPair,CardLabel} from '@egovernments/digit-ui-react-components'; - -const configViewBillApprovalModal = ({ - t, -}) => { - const fieldLabelStyle = { - "display" : "grid", - "gridTemplateColumns" : "60% 1fr" - }; - return { - label: { - heading: t("EXP_PROCESSINGMODAL_HEADER"), - submit: t("EXP_FORWARD_FOR_APPROVAL"), - cancel: t("CS_COMMON_CANCEL"), - }, - form: [ - { - body: [ - { - withoutLabel:true, - populators: - {t("EXP_DEPARTMENT")} - Engineering - , - }, - { - withoutLabel:true, - populators: - {t("EXP_DESIGNATION")} - Junior Engineer - , - }, - { - withoutLabel:true, - populators: - {t("EXP_APPROVER")} - {"RASHMI"} - , - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ], - }, - ], - defaultValues: { - comments: "", - }, - }; -} - -export default configViewBillApprovalModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillCheckModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillCheckModal.js deleted file mode 100644 index 53204b28e75..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillCheckModal.js +++ /dev/null @@ -1,107 +0,0 @@ -import { Dropdown, Loader } from '@egovernments/digit-ui-react-components'; -import React, { useState } from 'react' - -const configViewBillCheckModal = ({ - t, - approvers, - selectedApprover, - setSelectedApprover, - designation, - selectedDesignation, - setSelectedDesignation, - department, - selectedDept, - setSelectedDept, - approverLoading = false, -}) => { - - let checkConditions = true - - - if (designation?.length === 0 || department?.length === 0) return {} - - return { - label: { - heading: t("EXP_FORWARD_BILL_FOR_APPROVAL"), - submit: t("EXP_FORWARD_BILL_FOR_APPROVAL"), - cancel: t("CS_COMMON_CANCEL"), - }, - form: [ - { - body: [ - { - label: !checkConditions ? null : t("WORKS_APPROVER_DEPT"), - placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - isMandatory: true, - type: "goToDefaultCase", - populators: !checkConditions ? null : ( - { - setSelectedDept(val) - setSelectedApprover("") - //setValue() - }} - selected={selectedDept} - t={t} - /> - ), - }, - { - label: !checkConditions ? null : t("WORKS_APPROVER_DESIGNATION"), - //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - isMandatory: true, - type: "goToDefaultCase", - name: "designation", - populators: !checkConditions ? null : ( - { - setSelectedDesignation(val) - setSelectedApprover("") - //resetting approver dropdown when dept/designation changes - }} - selected={selectedDesignation} - t={t} - /> - ), - }, - { - label: !checkConditions ? null : t("WORKS_APPROVER"), - //placeholder: !checkConditions ? null : t("WF_ASSIGNEE_NAME_PLACEHOLDER"), - isMandatory: true, - type: "goToDefaultCase", - populators: !checkConditions ? null : ( - approverLoading ? : - ), - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ] - } - ] - } -} - -export default configViewBillCheckModal; \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillRejectModal.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillRejectModal.js deleted file mode 100644 index 716d6179d10..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/configViewBillRejectModal.js +++ /dev/null @@ -1,59 +0,0 @@ -import React from 'react' -import { LabelFieldPair,CardLabel} from '@egovernments/digit-ui-react-components'; - -const configViewBillRejectModal = ({ - t, -}) => { - - const fieldLabelStyle = { - "display" : "grid", - "gridTemplateColumns" : "60% 1fr" - }; - - return { - label: { - heading: t("EXP_PROCESSINGMODAL_HEADER"), - submit: t("EXP_CONFIRM_REJECT"), - cancel: t("CS_COMMON_CANCEL"), - }, - form: [ - { - body: [ - { - withoutLabel:true, - populators: - {t("EXP_DEPARTMENT")} - Engineering - , - }, - { - withoutLabel:true, - populators: - {t("EXP_DESIGNATION")} - Junior Engineer - , - }, - { - withoutLabel:true, - populators: - {t("EXP_REJECTED_BY")} - {"RASHMI"} - , - }, - { - label: t("WF_COMMON_COMMENTS"), - type: "textarea", - populators: { - name: "comments", - }, - }, - ] - } - ], - defaultValues : { - comments : "", - } - } -} - -export default configViewBillRejectModal \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/index.js deleted file mode 100644 index a736b8ed3eb..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/config/index.js +++ /dev/null @@ -1,47 +0,0 @@ -import { configAssignDso } from "./AssignDso"; -import { configCompleteApplication } from "./CompleteApplication"; -import { configReassignDSO } from "./ReassignDso"; -import { configRejectApplication } from "./RejectApplication"; -import { configAcceptDso } from "./AcceptDso"; -import { configPTApproverApplication } from "./PTApproverApplication"; -import { configPTAssessProperty } from "./PTAssessProperty"; -import { configTLApproverApplication } from "./TLApproverApplication"; -import { configBPAREGApproverApplication } from "./BPAREGApproverApplication"; -import { configBPAApproverApplication } from "./BPAApproverApplication"; -import { configNOCApproverApplication } from "./NOCApproverApplication"; -import { configWSApproverApplication } from "./WSApproverApplication"; -import { configWSDisConnectApplication } from "./WSDisconnectApplication"; -import configCheckModal from "./configCheckModal" -import configApproveModal from "./configApproveModal" -import configRejectModal from "./configRejectModal" -import configAttendanceApproveModal from "./configAttendanceApproveModal"; -import configAttendanceCheckModal from "./configAttendanceCheckModal"; -import configAttendanceRejectModal from "./configAttendanceRejectModal"; -import configViewBillApproveModal from "./configViewBillApproveModal"; -import configViewBillCheckModal from "./configViewBillCheckModal"; -import configViewBillRejectModal from "./configViewBillRejectModal"; - -export { - configAttendanceRejectModal, - configAttendanceCheckModal, - configAttendanceApproveModal, - configCheckModal, - configApproveModal, - configRejectModal, - configAssignDso, - configCompleteApplication, - configReassignDSO, - configRejectApplication, - configAcceptDso, - configPTApproverApplication, - configPTAssessProperty, - configTLApproverApplication, - configBPAREGApproverApplication, - configBPAApproverApplication, - configNOCApproverApplication, - configWSApproverApplication, - configWSDisConnectApplication, - configViewBillRejectModal, - configViewBillCheckModal, - configViewBillApproveModal -}; diff --git a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/index.js b/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/index.js deleted file mode 100644 index feb622ab712..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/packages/modules/templates/ApplicationDetails/index.js +++ /dev/null @@ -1,368 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; -import { useQueryClient } from "react-query"; -import { format } from "date-fns"; - -import { Loader } from "@egovernments/digit-ui-react-components"; - -import ActionModal from "./Modal"; - -import { useHistory, useParams } from "react-router-dom"; -import ApplicationDetailsContent from "./components/ApplicationDetailsContent"; -import ApplicationDetailsToast from "./components/ApplicationDetailsToast"; -import ApplicationDetailsActionBar from "./components/ApplicationDetailsActionBar"; -import ApplicationDetailsWarningPopup from "./components/ApplicationDetailsWarningPopup"; - -const ApplicationDetails = (props) => { - const tenantId = Digit.ULBService.getCurrentTenantId(); - const state = Digit.ULBService.getStateId(); - const { t } = useTranslation(); - const history = useHistory(); - let { id: applicationNumber } = useParams(); - const [displayMenu, setDisplayMenu] = useState(false); - const [selectedAction, setSelectedAction] = useState(null); - const [showModal, setShowModal] = useState(false); - const [isEnableLoader, setIsEnableLoader] = useState(false); - const [isWarningPop, setWarningPopUp] = useState(false); - const [modify, setModify] = useState(false); - const [saveAttendanceState, setSaveAttendanceState] = useState({ displaySave : false, updatePayload: []}) - - const { - applicationDetails, - showToast, - setShowToast, - isLoading, - isDataLoading, - applicationData, - mutate, - nocMutation, - workflowDetails, - businessService, - closeToast, - moduleCode, - timelineStatusPrefix, - forcedActionPrefix, - statusAttribute, - ActionBarStyle, - MenuStyle, - paymentsList, - showTimeLine = true, - oldValue, - isInfoLabel = false, - clearDataDetails, - noBoxShadow, - sectionHeadStyle, - showActionBar = true - } = props; - - useEffect(() => { - if (showToast) { - workflowDetails.revalidate(); - } - }, [showToast]); - - function onActionSelect(action) { - if (action) { - if(action?.isToast){ - setShowToast({ key: "error", error: { message: action?.toastMessage } }); - setTimeout(closeToast, 5000); - } - else if (action?.isWarningPopUp) { - setWarningPopUp(true); - } else if (action?.redirectionUrll) { - //here do the loi edit upon rejection - if (action?.redirectionUrll?.action === "EDIT_LOI_APPLICATION") { - history.push(`${action?.redirectionUrll?.pathname}`, { data: action?.redirectionUrll?.state }); - } - if (action?.redirectionUrll?.action === "EDIT_ESTIMATE_APPLICATION") { - history.push(`${action?.redirectionUrll?.pathname}`,{ data: action?.redirectionUrll?.state }); - } - - } else if (!action?.redirectionUrl) { - if(action?.action === 'EDIT') setModify(true) - else setShowModal(true); - } else { - history.push({ - pathname: action.redirectionUrl?.pathname, - state: { ...action.redirectionUrl?.state }, - }); - } - } - setSelectedAction(action); - setDisplayMenu(false); - } - - const queryClient = useQueryClient(); - - const closeModal = () => { - setSelectedAction(null); - setShowModal(false); - }; - - const closeWarningPopup = () => { - setWarningPopUp(false); - }; - - const getResponseHeader = (action) => { - - if(action?.includes("CHECK")){ - return t("WORKS_LOI_RESPONSE_FORWARD_HEADER") - } else if (action?.includes("APPROVE")){ - return t("WORKS_LOI_RESPONSE_APPROVE_HEADER") - }else if(action?.includes("REJECT")){ - return t("WORKS_LOI_RESPONSE_REJECT_HEADER") - } - } - - const getResponseMessage = (action,updatedLOI) => { - - if (action?.includes("CHECK")) { - return t("WORKS_LOI_RESPONSE_MESSAGE_CHECK", { loiNumber: updatedLOI?.letterOfIndentNumber,name:"Nipun",designation:"SE" }) - } else if (action?.includes("APPROVE")) { - return t("WORKS_LOI_RESPONSE_MESSAGE_APPROVE", { loiNumber: updatedLOI?.letterOfIndentNumber }) - } else if (action?.includes("REJECT")) { - return t("WORKS_LOI_RESPONSE_MESSAGE_REJECT", { loiNumber: updatedLOI?.letterOfIndentNumber }) - } - } - - const getEstimateResponseHeader = (action) => { - - if(action?.includes("CHECK")){ - return t("WORKS_ESTIMATE_RESPONSE_FORWARD_HEADER") - } else if (action?.includes("TECHNICALSANCATION")){ - return t("WORKS_ESTIMATE_RESPONSE_FORWARD_HEADER") - }else if (action?.includes("ADMINSANCTION")){ - return t("WORKS_ESTIMATE_RESPONSE_APPROVE_HEADER") - }else if(action?.includes("REJECT")){ - return t("WORKS_ESTIMATE_RESPONSE_REJECT_HEADER") - } - } - - const getEstimateResponseMessage = (action,updatedEstimate) => { - - if (action?.includes("CHECK")) { - return t("WORKS_ESTIMATE_RESPONSE_MESSAGE_CHECK", { estimateNumber: updatedEstimate?.estimateNumber,Name:"Super",Designation:"SE",Department:"Health" }) - } else if (action?.includes("TECHNICALSANCATION")) { - return t("WORKS_ESTIMATE_RESPONSE_MESSAGE_CHECK", { estimateNumber: updatedEstimate?.estimateNumber,Name:"Super",Designation:"SE",Department:"Health" }) - } else if (action?.includes("ADMINSANCTION")) { - return t("WORKS_ESTIMATE_RESPONSE_MESSAGE_APPROVE", { estimateNumber: updatedEstimate?.estimateNumber }) - } else if (action?.includes("REJECT")) { - return t("WORKS_ESTIMATE_RESPONSE_MESSAGE_REJECT", { estimateNumber: updatedEstimate?.estimateNumber }) - } - } - - const getAttendanceResponseHeaderAndMessage = (action) => { - let response = {} - if (action?.includes("VERIFY")) { - response.header = t("ATM_ATTENDANCE_VERIFIED") - response.message = t("ATM_ATTENDANCE_VERIFIED_SUCCESS") - } else if (action?.includes("REJECT")) { - response.header = t("ATM_ATTENDANCE_REJECTED") - response.message = t("ATM_ATTENDANCE_REJECTED_SUCCESS") - } else if (action?.includes("APPROVE")) { - response.header = t("ATM_ATTENDANCE_APPROVED") - response.message = t("ATM_ATTENDANCE_APPROVED_SUCCESS") - } - return response - } - - const submitAction = async (data, nocData = false, isOBPS = {}) => { - const performedAction = data?.workflow?.action - setIsEnableLoader(true); - if (mutate) { - setIsEnableLoader(true); - mutate(data, { - onError: (error, variables) => { - setIsEnableLoader(false); - setShowToast({ key: "error", error }); - setTimeout(closeToast, 5000); - }, - onSuccess: (data, variables) => { - setIsEnableLoader(false); - //just history.push to the response component from here and show relevant details - if(data?.letterOfIndents?.[0]){ - const updatedLOI = data?.letterOfIndents?.[0] - const state = { - header:getResponseHeader(performedAction,updatedLOI), - id: updatedLOI?.letterOfIndentNumber, - info: t("WORKS_LOI_ID"), - message: getResponseMessage(performedAction,updatedLOI), - links: [ - { - name: t("WORKS_CREATE_NEW_LOI"), - redirectUrl: `/${window.contextPath}/employee/works/create-loi`, - code: "", - svg: "CreateEstimateIcon", - isVisible:false, - type:"add" - }, - { - name: t("WORKS_GOTO_LOI_INBOX"), - redirectUrl: `/${window.contextPath}/employee/works/LOIInbox`, - code: "", - svg: "CreateEstimateIcon", - isVisible:true, - type:"inbox" - }, - ], - responseData:data, - requestData:variables - } - history.push(`/${window.contextPath}/employee/works/response`, state) - } - if(data?.estimates?.[0]){ - const updatedEstimate = data?.estimates?.[0] - const state = { - header:getEstimateResponseHeader(performedAction,updatedEstimate), - id: updatedEstimate?.estimateNumber, - info: t("WORKS_ESTIMATE_ID"), - message: getEstimateResponseMessage(performedAction,updatedEstimate), - links: [ - { - name: t("WORKS_CREATE_ESTIMATE"), - redirectUrl: `/${window.contextPath}/employee/works/create-estimate`, - code: "", - svg: "CreateEstimateIcon", - isVisible:false, - type:"add" - }, - { - name: t("WORKS_GOTO_ESTIMATE_INBOX"), - redirectUrl: `/${window.contextPath}/employee/works/inbox`, - code: "", - svg: "RefreshIcon", - isVisible:true, - type:"inbox" - }, - ], - responseData:data, - requestData:variables - } - history.push(`/${window.contextPath}/employee/works/response`, state) - } - if (isOBPS?.bpa) { - data.selectedAction = selectedAction; - history.replace(`/${window?.contextPath}/employee/obps/response`, { data: data }); - } - if (isOBPS?.isStakeholder) { - data.selectedAction = selectedAction; - history.push(`/${window?.contextPath}/employee/obps/stakeholder-response`, { data: data }); - } - if (isOBPS?.isNoc) { - history.push(`/${window?.contextPath}/employee/noc/response`, { data: data }); - } - if (data?.Amendments?.length > 0 ){ - //RAIN-6981 instead just show a toast here with appropriate message - //show toast here and return - //history.push("/${window?.contextPath}/employee/ws/response-bill-amend", { status: true, state: data?.Amendments?.[0] }) - - if(variables?.AmendmentUpdate?.workflow?.action.includes("SEND_BACK")){ - setShowToast({ key: "success", label: t("ES_MODIFYSWCONNECTION_SEND_BACK_UPDATE_SUCCESS")}) - } else if (variables?.AmendmentUpdate?.workflow?.action.includes("RE-SUBMIT")){ - setShowToast({ key: "success", label: t("ES_MODIFYSWCONNECTION_RE_SUBMIT_UPDATE_SUCCESS") }) - } else if (variables?.AmendmentUpdate?.workflow?.action.includes("APPROVE")){ - setShowToast({ key: "success", label: t("ES_MODIFYSWCONNECTION_APPROVE_UPDATE_SUCCESS") }) - } - else if (variables?.AmendmentUpdate?.workflow?.action.includes("REJECT")){ - setShowToast({ key: "success", label: t("ES_MODIFYWSCONNECTION_REJECT_UPDATE_SUCCESS") }) - } - return - } - if(data?.musterRolls?.[0]) { - const musterRoll = data?.musterRolls?.[0] - const response = getAttendanceResponseHeaderAndMessage(performedAction) - const state = { - header: response?.header, - message: response?.message, - info: t("ATM_REGISTER_ID_WEEK"), - id: `${musterRoll.registerId} | ${format(new Date(musterRoll.startDate), "dd/MM/yyyy")} - ${format(new Date(musterRoll.endDate), "dd/MM/yyyy")}`, - } - history.push(`/${window.contextPath}/employee/attendencemgmt/response`, state) - } - setShowToast({ key: "success", action: selectedAction }); - clearDataDetails && setTimeout(clearDataDetails, 3000); - setTimeout(closeToast, 5000); - queryClient.clear(); - queryClient.refetchQueries("APPLICATION_SEARCH"); - //push false status when reject - - }, - }); - } - - closeModal(); - }; - - if (isLoading || isEnableLoader) { - return ; - } - - return ( - - {!isLoading ? ( - - - {showModal ? ( - - ) : null} - {isWarningPop ? ( - - ) : null} - - {showActionBar && } - - ) : ( - - )} - - ); -}; - -export default ApplicationDetails; diff --git a/frontend/micro-ui/web/micro-ui-internals/publish-develop.sh b/frontend/micro-ui/web/micro-ui-internals/publish-develop.sh deleted file mode 100644 index 4909658c697..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/publish-develop.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -BASEDIR="$(cd "$(dirname "$0")" && pwd)" - -msg() { - echo -e "\n\n\033[32;32m$1\033[0m" -} - - -# msg "Pre-building all packages" -# yarn build -# sleep 5 - -msg "Building and publishing css" -cd "$BASEDIR/packages/css" && rm -rf dist && yarn && npm publish --tag campaign-1.0 - - -# msg "Building and publishing libraries" -# cd "$BASEDIR/packages/modules/workbench-hcm" && rm -rf dist && yarn&& npm publish --tag workbench-1.0 - diff --git a/frontend/micro-ui/web/micro-ui-internals/publish.sh b/frontend/micro-ui/web/micro-ui-internals/publish.sh deleted file mode 100644 index 4909658c697..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/publish.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash - -BASEDIR="$(cd "$(dirname "$0")" && pwd)" - -msg() { - echo -e "\n\n\033[32;32m$1\033[0m" -} - - -# msg "Pre-building all packages" -# yarn build -# sleep 5 - -msg "Building and publishing css" -cd "$BASEDIR/packages/css" && rm -rf dist && yarn && npm publish --tag campaign-1.0 - - -# msg "Building and publishing libraries" -# cd "$BASEDIR/packages/modules/workbench-hcm" && rm -rf dist && yarn&& npm publish --tag workbench-1.0 - diff --git a/frontend/micro-ui/web/micro-ui-internals/scripts/create.sh b/frontend/micro-ui/web/micro-ui-internals/scripts/create.sh deleted file mode 100755 index 9de72331774..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/scripts/create.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -./scripts/run.sh core utilities diff --git a/frontend/micro-ui/web/micro-ui-internals/scripts/deploy.sh b/frontend/micro-ui/web/micro-ui-internals/scripts/deploy.sh deleted file mode 100755 index 5b0c7b831ed..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/scripts/deploy.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash - -curl -v -X POST https://builds.digit.org/job/builds/job/digit-ui/buildWithParameters \ - --user saurabh-egov:114cbf3df675835931688b2d3f0014a1f7 \ - --data-urlencode json='{"parameter": [{"name":"BRANCH", "value":"origin/'$1'"}]}' - -# curl https://builds.digit.org/job/builds/job/digit-ui/lastBuild/api/json | grep --color result\":null - diff --git a/frontend/micro-ui/web/micro-ui-internals/scripts/jenkins.sh b/frontend/micro-ui/web/micro-ui-internals/scripts/jenkins.sh deleted file mode 100755 index a1711fec55b..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/scripts/jenkins.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -./scripts/deploy.sh dev \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/scripts/run.sh b/frontend/micro-ui/web/micro-ui-internals/scripts/run.sh deleted file mode 100755 index f00c59f13b8..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/scripts/run.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -MODULES=( "components" "core" "libraries" "example" ) - -RUNARGS=() -BUILDARGS=() - -for var in "$@" -do - BUILDARGS=( ${BUILDARGS[@]} build:"$var" ) - RUNARGS=( ${RUNARGS[@]} dev:"$var" ) -done - -a=0 -while [ "$a" -lt 3 ] -do - BUILD[$a]=build:${MODULES[$a]} - a=` expr $a + 1 ` -done - -echo "BUILDING MODULES:-" ${BUILD[*]} ${BUILDARGS[*]} -yarn run-p ${BUILD[*]} ${BUILDARGS[*]} - -b=0 -while [ "$b" -lt 4 ] -do - RUN[$b]=dev:${MODULES[$b]} - b=` expr $b + 1 ` -done - -echo "SERVING MODULES:-" ${RUN[*]} ${RUNARGS[*]} -yarn run-p ${RUN[*]} ${RUNARGS[*]} \ No newline at end of file diff --git a/frontend/micro-ui/web/micro-ui-internals/test.js b/frontend/micro-ui/web/micro-ui-internals/test.js deleted file mode 100644 index 60c958d0bac..00000000000 --- a/frontend/micro-ui/web/micro-ui-internals/test.js +++ /dev/null @@ -1,31 +0,0 @@ -const middleWare_1 = (data, _break, _next) => { - data.a = "a"; - _next(data); -}; - - -const middleWare_2 = (data, _break, _next) => { - data.b = "b"; - // _break(); - _next(data); -}; - -const middleWare_3 = (data, _break, _next) => { - data.c = "c"; - _next(data); -}; - -let middleWares = [middleWare_1, middleWare_2, middleWare_3]; - -const callMiddlewares = () => { - let applyBreak = false; - let itr = -1; - let _break = () => (applyBreak = true); - let _next = (data) => { - if (!applyBreak && ++itr < middleWares.length) middleWares[itr](data, _break, _next); - else return; - }; - _next({}); -}; - -callMiddlewares(); diff --git a/frontend/micro-ui/web/microplan/App.js b/frontend/micro-ui/web/microplan/App.js deleted file mode 100644 index afcd26669c6..00000000000 --- a/frontend/micro-ui/web/microplan/App.js +++ /dev/null @@ -1,61 +0,0 @@ -import React from "react"; -import { initLibraries } from "@egovernments/digit-ui-libraries"; - -import { DigitUI } from "@egovernments/digit-ui-module-core"; - -import { UICustomizations } from "./Customisations/UICustomizations"; -import { initMicroplanningComponents } from "@egovernments/digit-ui-module-hcmmicroplanning"; - - -window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); - -const enabledModules = [ - "DSS", - "NDSS", - "Utilities", - "HRMS", - "Engagement", - "Workbench", - "Microplanning" -]; - -const moduleReducers = (initData) => ({ - initData, -}); - -const initDigitUI = () => { - window.Digit.ComponentRegistryService.setupRegistry({ - - }); - - - initMicroplanningComponents() - window.Digit.Customizations = { - PGR: {}, - commonUiConfig: UICustomizations, - }; -}; - -initLibraries().then(() => { - initDigitUI(); -}); - -function App() { - window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); - const stateCode = - window.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || - process.env.REACT_APP_STATE_LEVEL_TENANT_ID; - if (!stateCode) { - return

stateCode is not defined

; - } - return ( - - ); -} - -export default App; diff --git a/frontend/micro-ui/web/microplan/Dockerfile b/frontend/micro-ui/web/microplan/Dockerfile deleted file mode 100644 index 56388b8e2d7..00000000000 --- a/frontend/micro-ui/web/microplan/Dockerfile +++ /dev/null @@ -1,30 +0,0 @@ -FROM egovio/alpine-node-builder-14:yarn AS build -#FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build -RUN apk update && apk upgrade -RUN apk add --no-cache git>2.30.0 -ARG WORK_DIR -WORKDIR /app -ENV NODE_OPTIONS "--max-old-space-size=4792" - -COPY ${WORK_DIR} . -RUN ls -lah - -#RUN node web/envs.js -RUN cd web/ \ - && node -e 'console.log(v8.getHeapStatistics().heap_size_limit/(1024*1024))' \ - && node -e 'console.log("core only")' \ - && cd microplan/ \ - && chmod +x ./install-deps.sh \ - && ./install-deps.sh \ - && cd ../ \ - && yarn install \ - && yarn build:webpack - -FROM nginx:mainline-alpine -#FROM ghcr.io/egovernments/nginx:mainline-alpine -ENV WORK_DIR=/var/web/microplan-ui - -RUN mkdir -p ${WORK_DIR} - -COPY --from=build /app/web/build ${WORK_DIR}/ -COPY --from=build /app/web/microplan/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/micro-ui/web/microplan/install-deps.sh b/frontend/micro-ui/web/microplan/install-deps.sh deleted file mode 100644 index b090c8d6f04..00000000000 --- a/frontend/micro-ui/web/microplan/install-deps.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -BRANCH="$(git branch --show-current)" - -echo "Main Branch: $BRANCH" - -INTERNALS="micro-ui-internals" -cd .. - -cp microplan/App.js src -cp microplan/package.json package.json -cp microplan/webpack.config.js webpack.config.js -cp microplan/inter-package.json $INTERNALS/package.json - -cp $INTERNALS/example/src/UICustomizations.js src/Customisations - -echo "UI :: microplan " && echo "Branch: $(git branch --show-current)" && echo "$(git log -1 --pretty=%B)" && echo "installing packages" - diff --git a/frontend/micro-ui/web/microplan/inter-package.json b/frontend/micro-ui/web/microplan/inter-package.json deleted file mode 100644 index 635c9cc954b..00000000000 --- a/frontend/micro-ui/web/microplan/inter-package.json +++ /dev/null @@ -1,61 +0,0 @@ -{ - "name": "egovernments", - "version": "1.0.0", - "main": "index.js", - "workspaces": [ - "example", - "packages/css", - "packages/modules/*" - ], - "author": "JaganKumar ", - "license": "MIT", - "private": true, - "engines": { - "node": ">=14" - }, - "scripts": { - "start": "SKIP_PREFLIGHT_CHECK=true run-s build start:dev", - "sprint": "SKIP_PREFLIGHT_CHECK=true run-s start:script", - "start:dev": "run-p dev:**", - "start:script": "./scripts/create.sh", - "dev:css": "cd packages/css && yarn start", - "publish:css": "cd packages/css && yarn publish --access public", - "dev:example": "cd example && yarn start", - "dev:hcm-microplanning": "cd packages/modules/hcm-microplanning && yarn start", - "build": "run-p build:**", - "build:hcm-microplanning": "cd packages/modules/hcm-microplanning && yarn build", - "deploy:jenkins": "./scripts/jenkins.sh", - "clean": "rm -rf node_modules" - }, - "resolutions": { - "**/@babel/runtime": "7.20.1", - "**/babel-preset-react-app": "10.0.0", - "**/babel-loader": "8.2.2", - "**/@babel/core": "7.14.0", - "**/@babel/preset-env": "7.14.0", - "**/@babel/plugin-transform-modules-commonjs": "7.14.0", - "**/polished":"4.2.2", - "fast-uri":"2.1.0" - }, - "devDependencies": { - "husky": "7.0.4", - "lint-staged": "12.3.7", - "npm-run-all": "4.1.5", - "prettier": "2.1.2" - }, - "husky": {}, - "lint-staged": { - "*.{js,css,md}": "prettier --write" - }, - "dependencies": { - "lodash": "4.17.21", - "microbundle-crl": "0.13.11", - "@egovernments/digit-ui-react-components": "1.8.1-beta.2", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "react-router-dom": "5.3.0" - } -} diff --git a/frontend/micro-ui/web/microplan/nginx.conf b/frontend/micro-ui/web/microplan/nginx.conf deleted file mode 100644 index 9c84c01c4be..00000000000 --- a/frontend/micro-ui/web/microplan/nginx.conf +++ /dev/null @@ -1,12 +0,0 @@ -server -{ - listen 80; - underscores_in_headers on; - - location /microplan-ui - { - root /var/web; - index index.html index.htm; - try_files $uri $uri/ /microplan-ui/index.html; - } -} \ No newline at end of file diff --git a/frontend/micro-ui/web/microplan/package.json b/frontend/micro-ui/web/microplan/package.json deleted file mode 100644 index dff749d1780..00000000000 --- a/frontend/micro-ui/web/microplan/package.json +++ /dev/null @@ -1,80 +0,0 @@ -{ - "name": "micro-ui", - "version": "1.0.0", - "author": "Jagankumar ", - "license": "MIT", - "private": true, - "engines": { - "node": ">=14" - }, - "workspaces": [ - "micro-ui-internals/packages/modules/*" - ], - "homepage": "/microplan-ui", - "dependencies": { - "@egovernments/digit-ui-libraries": "1.8.2-beta.1", - "@egovernments/digit-ui-module-core": "1.8.2-beta.1", - "@egovernments/digit-ui-module-utilities": "1.0.1-beta.23", - "@egovernments/digit-ui-react-components": "1.8.2-beta.1", - "@egovernments/digit-ui-module-hcmmicroplanning":"0.0.1", - "@egovernments/digit-ui-components": "0.0.2-beta.2", - "babel-loader": "8.1.0", - "clean-webpack-plugin": "4.0.0", - "react": "17.0.2", - "react-dom": "17.0.2", - "jsonpath": "^1.1.1", - "react-router-dom": "5.3.0", - "react-scripts": "4.0.1", - "web-vitals": "1.1.2", - "terser-brunch": "^4.1.0", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "css-loader": "5.2.6", - "style-loader": "2.0.0", - "webpack-cli": "4.10.0" - }, - "devDependencies": { - "@babel/plugin-proposal-private-property-in-object": "7.21.0", - "file-loader": "^6.2.0", - "http-proxy-middleware": "1.3.1", - "lodash": "4.17.21", - "microbundle-crl": "0.13.11", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "react-router-dom": "5.3.0", - "husky": "7.0.4", - "lint-staged": "12.3.7", - "npm-run-all": "4.1.5", - "prettier": "2.1.2" - }, - "scripts": { - "start": "react-scripts start", - "build": "GENERATE_SOURCEMAP=false SKIP_PREFLIGHT_CHECK=true react-scripts build", - "build:prepare": "./build.sh", - "build:libraries": "cd micro-ui-internals && yarn build", - "build:prod": "webpack --mode production", - "build:webpack": "yarn build:libraries &&cd .. && ls && cd ./web && ls && yarn build:prod", - "clean": "rm -rf node_modules" - }, - "eslintConfig": { - "extends": [ - "react-app" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} \ No newline at end of file diff --git a/frontend/micro-ui/web/microplan/webpack.config.js b/frontend/micro-ui/web/microplan/webpack.config.js deleted file mode 100644 index c8036364605..00000000000 --- a/frontend/micro-ui/web/microplan/webpack.config.js +++ /dev/null @@ -1,52 +0,0 @@ -const path = require("path"); -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const { CleanWebpackPlugin } = require("clean-webpack-plugin"); -// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; - -module.exports = { - // mode: 'development', - entry: "./src/index.js", - devtool: "none", - module: { - rules: [ - { - test: /\.(js)$/, - exclude: /node_modules/, - use: ["babel-loader"], - }, - { - test: /\.css$/i, - use: ["style-loader", "css-loader"], - }, - { - test: /\.(png|jpe?g|gif)$/i, - use: [ - { - loader: 'file-loader', - }, - ], - }, - ], - }, - output: { - filename: "[name].bundle.js", - path: path.resolve(__dirname, "build"), - publicPath: "/microplan-ui/", - }, - optimization: { - splitChunks: { - chunks: 'all', - minSize:20000, - maxSize:50000, - enforceSizeThreshold:50000, - minChunks:1, - maxAsyncRequests:30, - maxInitialRequests:30 - }, - }, - plugins: [ - new CleanWebpackPlugin(), - // new BundleAnalyzerPlugin(), - new HtmlWebpackPlugin({ inject: true, template: "public/index.html" }), - ], -}; \ No newline at end of file diff --git a/frontend/micro-ui/web/package.json b/frontend/micro-ui/web/package.json deleted file mode 100644 index e90ab5a52ba..00000000000 --- a/frontend/micro-ui/web/package.json +++ /dev/null @@ -1,85 +0,0 @@ -{ - "name": "micro-ui", - "version": "0.1.0", - "author": "Jagankumar ", - "license": "MIT", - "private": true, - "engines": { - "node": ">=14" - }, - "workspaces": [ - "micro-ui-internals/packages/libraries", - "micro-ui-internals/packages/react-components", - "micro-ui-internals/packages/modules/*" - ], - "homepage": "/digit-ui", - "dependencies": { - "@egovernments/digit-ui-libraries": "1.8.1-beta.4", - "@egovernments/digit-ui-module-workbench": "1.0.1-beta.16", - "@egovernments/digit-ui-module-core": "1.8.2-beta.2", - "@egovernments/digit-ui-module-hrms": "1.8.0-beta.2", - "@egovernments/digit-ui-react-components": "1.8.2-beta.6", - "@egovernments/digit-ui-components": "0.0.2-beta.1", - "@egovernments/digit-ui-module-dss": "1.8.0-beta", - "@egovernments/digit-ui-module-common": "1.8.0-beta", - "@egovernments/digit-ui-module-utilities": "1.0.0-beta", - "@egovernments/digit-ui-module-engagement": "1.5.20", - "babel-loader": "8.1.0", - "clean-webpack-plugin": "4.0.0", - "react": "17.0.2", - "react-dom": "17.0.2", - "jsonpath": "^1.1.1", - "react-router-dom": "5.3.0", - "react-scripts": "4.0.1", - "web-vitals": "1.1.2", - "terser-brunch": "^4.1.0", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "css-loader": "5.2.6", - "style-loader": "2.0.0", - "webpack-cli": "4.10.0" - }, - "devDependencies": { - "@babel/plugin-proposal-private-property-in-object": "7.21.0", - "http-proxy-middleware": "1.3.1", - "lodash": "4.17.21", - "microbundle-crl": "0.13.11", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "react-router-dom": "5.3.0", - "husky": "7.0.4", - "lint-staged": "12.3.7", - "npm-run-all": "4.1.5", - "prettier": "2.1.2" - }, - "scripts": { - "start": "react-scripts start", - "build": "GENERATE_SOURCEMAP=false SKIP_PREFLIGHT_CHECK=true react-scripts build", - "build:prepare": "./build.sh", - "build:libraries": "cd micro-ui-internals && yarn build", - "build:prod": "webpack --mode production", - "build:webpack": "yarn build:libraries &&cd .. && ls && cd ./web && ls && yarn build:prod", - "clean": "rm -rf node_modules" - }, - "eslintConfig": { - "extends": [ - "react-app" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} \ No newline at end of file diff --git a/frontend/micro-ui/web/public/index.html b/frontend/micro-ui/web/public/index.html deleted file mode 100644 index 661b6fa2425..00000000000 --- a/frontend/micro-ui/web/public/index.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - - - - - - - - - - DIGIT - - - - - - -
- - - - \ No newline at end of file diff --git a/frontend/micro-ui/web/public/robots.txt b/frontend/micro-ui/web/public/robots.txt deleted file mode 100644 index e9e57dc4d41..00000000000 --- a/frontend/micro-ui/web/public/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# https://www.robotstxt.org/robotstxt.html -User-agent: * -Disallow: diff --git a/frontend/micro-ui/web/src/App.js b/frontend/micro-ui/web/src/App.js deleted file mode 100644 index d871f8e8f4c..00000000000 --- a/frontend/micro-ui/web/src/App.js +++ /dev/null @@ -1,74 +0,0 @@ -import React from "react"; -import { initLibraries } from "@egovernments/digit-ui-libraries"; -import { - paymentConfigs, - PaymentLinks, - PaymentModule, -} from "@egovernments/digit-ui-module-common"; -import { DigitUI,initCoreComponents } from "@egovernments/digit-ui-module-core"; -import { initDSSComponents } from "@egovernments/digit-ui-module-dss"; -import { initEngagementComponents } from "@egovernments/digit-ui-module-engagement"; -import { initHRMSComponents } from "@egovernments/digit-ui-module-hrms"; -import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities"; -import { UICustomizations } from "./Customisations/UICustomizations"; -import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench"; -// import { initWorkbenchHCMComponents } from "@egovernments/digit-ui-module-hcmworkbench"; - -window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); - -const enabledModules = [ - "DSS", - "NDSS", - "Utilities", - "HRMS", - "Engagement", - "Workbench", - "Microplanning" -]; - -const moduleReducers = (initData) => ({ - initData, -}); - -const initDigitUI = () => { - window.Digit.ComponentRegistryService.setupRegistry({ - PaymentModule, - ...paymentConfigs, - PaymentLinks, - }); - initCoreComponents(); - initDSSComponents(); - initHRMSComponents(); - initEngagementComponents(); - initUtilitiesComponents(); - initWorkbenchComponents(); - - window.Digit.Customizations = { - PGR: {}, - commonUiConfig: UICustomizations, - }; -}; - -initLibraries().then(() => { - initDigitUI(); -}); - -function App() { - window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); - const stateCode = - window.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || - process.env.REACT_APP_STATE_LEVEL_TENANT_ID; - if (!stateCode) { - return

stateCode is not defined

; - } - return ( - - ); -} - -export default App; diff --git a/frontend/micro-ui/web/src/ComponentRegistry.js b/frontend/micro-ui/web/src/ComponentRegistry.js deleted file mode 100644 index 9bafce3dc89..00000000000 --- a/frontend/micro-ui/web/src/ComponentRegistry.js +++ /dev/null @@ -1,11 +0,0 @@ -class Registry { - constructor(registry = {}) { - this._registry = registry; - } - - getComponent(id) { - return this._registry[id]; - } -} - -export default Registry; diff --git a/frontend/micro-ui/web/src/Customisations/UICustomizations.js b/frontend/micro-ui/web/src/Customisations/UICustomizations.js deleted file mode 100644 index 6d17ab0d51b..00000000000 --- a/frontend/micro-ui/web/src/Customisations/UICustomizations.js +++ /dev/null @@ -1,428 +0,0 @@ -import { Link } from "react-router-dom"; -import _ from "lodash"; - -//create functions here based on module name set in mdms(eg->SearchProjectConfig) -//how to call these -> Digit?.Customizations?.[masterName]?.[moduleName] -// these functions will act as middlewares -var Digit = window.Digit || {}; - - - -const businessServiceMap = { - - "muster roll": "MR" -}; - -const inboxModuleNameMap = { - "muster-roll-approval": "muster-roll-service", -}; - -export const UICustomizations = { - businessServiceMap, - updatePayload: (applicationDetails, data, action, businessService) => { - - if (businessService === businessServiceMap.estimate) { - const workflow = { - comment: data.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - estimate: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap.contract) { - const workflow = { - comment: data?.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - contract: applicationDetails, - workflow, - }; - } - if (businessService === businessServiceMap?.["muster roll"]) { - const workflow = { - comment: data?.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - return { - musterRoll: applicationDetails, - workflow, - }; - } - if(businessService === businessServiceMap?.["works.purchase"]){ - const workflow = { - comment: data.comments, - documents: data?.documents?.map((document) => { - return { - documentType: action?.action + " DOC", - fileName: document?.[1]?.file?.name, - fileStoreId: document?.[1]?.fileStoreId?.fileStoreId, - documentUid: document?.[1]?.fileStoreId?.fileStoreId, - tenantId: document?.[1]?.fileStoreId?.tenantId, - }; - }), - assignees: data?.assignees?.uuid ? [data?.assignees?.uuid] : null, - action: action.action, - }; - //filtering out the data - Object.keys(workflow).forEach((key, index) => { - if (!workflow[key] || workflow[key]?.length === 0) delete workflow[key]; - }); - - const additionalFieldsToSet = { - projectId:applicationDetails.additionalDetails.projectId, - invoiceDate:applicationDetails.billDate, - invoiceNumber:applicationDetails.referenceId.split('_')?.[1], - contractNumber:applicationDetails.referenceId.split('_')?.[0], - documents:applicationDetails.additionalDetails.documents - } - return { - bill: {...applicationDetails,...additionalFieldsToSet}, - workflow, - }; - } - }, - enableModalSubmit:(businessService,action,setModalSubmit,data)=>{ - if(businessService === businessServiceMap?.["muster roll"] && action.action==="APPROVE"){ - setModalSubmit(data?.acceptTerms) - } - }, - enableHrmsSearch: (businessService, action) => { - if (businessService === businessServiceMap.estimate) { - return action.action.includes("TECHNICALSANCTION") || action.action.includes("VERIFYANDFORWARD"); - } - if (businessService === businessServiceMap.contract) { - return action.action.includes("VERIFY_AND_FORWARD"); - } - if (businessService === businessServiceMap?.["muster roll"]) { - return action.action.includes("VERIFY"); - } - if(businessService === businessServiceMap?.["works.purchase"]){ - return action.action.includes("VERIFY_AND_FORWARD") - } - return false; - }, - getBusinessService: (moduleCode) => { - if (moduleCode?.includes("estimate")) { - return businessServiceMap?.estimate; - } else if (moduleCode?.includes("contract")) { - return businessServiceMap?.contract; - } else if (moduleCode?.includes("muster roll")) { - return businessServiceMap?.["muster roll"]; - } - else if (moduleCode?.includes("works.purchase")) { - return businessServiceMap?.["works.purchase"]; - } - else if (moduleCode?.includes("works.wages")) { - return businessServiceMap?.["works.wages"]; - } - else if (moduleCode?.includes("works.supervision")) { - return businessServiceMap?.["works.supervision"]; - } - else { - return businessServiceMap; - } - }, - getInboxModuleName: (moduleCode) => { - if (moduleCode?.includes("estimate")) { - return inboxModuleNameMap?.estimate; - } else if (moduleCode?.includes("contract")) { - return inboxModuleNameMap?.contracts; - } else if (moduleCode?.includes("attendence")) { - return inboxModuleNameMap?.attendencemgmt; - } else { - return inboxModuleNameMap; - } - }, - - AttendanceInboxConfig: { - preProcess: (data) => { - - //set tenantId - data.body.inbox.tenantId = Digit.ULBService.getCurrentTenantId(); - data.body.inbox.processSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); - - const musterRollNumber = data?.body?.inbox?.moduleSearchCriteria?.musterRollNumber?.trim(); - if(musterRollNumber) data.body.inbox.moduleSearchCriteria.musterRollNumber = musterRollNumber - - const attendanceRegisterName = data?.body?.inbox?.moduleSearchCriteria?.attendanceRegisterName?.trim(); - if(attendanceRegisterName) data.body.inbox.moduleSearchCriteria.attendanceRegisterName = attendanceRegisterName - - // deleting them for now(assignee-> need clarity from pintu,ward-> static for now,not implemented BE side) - const assignee = _.clone(data.body.inbox.moduleSearchCriteria.assignee); - delete data.body.inbox.moduleSearchCriteria.assignee; - if (assignee?.code === "ASSIGNED_TO_ME") { - data.body.inbox.moduleSearchCriteria.assignee = Digit.UserService.getUser().info.uuid; - } - - //cloning locality and workflow states to format them - // let locality = _.clone(data.body.inbox.moduleSearchCriteria.locality ? data.body.inbox.moduleSearchCriteria.locality : []); - - let selectedOrg = _.clone(data.body.inbox.moduleSearchCriteria.orgId ? data.body.inbox.moduleSearchCriteria.orgId : null); - delete data.body.inbox.moduleSearchCriteria.orgId; - if(selectedOrg) { - data.body.inbox.moduleSearchCriteria.orgId = selectedOrg?.[0]?.applicationNumber; - } - - // let selectedWard = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : null); - // delete data.body.inbox.moduleSearchCriteria.ward; - // if(selectedWard) { - // data.body.inbox.moduleSearchCriteria.ward = selectedWard?.[0]?.code; - // } - - let states = _.clone(data.body.inbox.moduleSearchCriteria.state ? data.body.inbox.moduleSearchCriteria.state : []); - let ward = _.clone(data.body.inbox.moduleSearchCriteria.ward ? data.body.inbox.moduleSearchCriteria.ward : []); - // delete data.body.inbox.moduleSearchCriteria.locality; - delete data.body.inbox.moduleSearchCriteria.state; - delete data.body.inbox.moduleSearchCriteria.ward; - - // locality = locality?.map((row) => row?.code); - states = Object.keys(states)?.filter((key) => states[key]); - ward = ward?.map((row) => row?.code); - - - // //adding formatted data to these keys - // if (locality.length > 0) data.body.inbox.moduleSearchCriteria.locality = locality; - if (states.length > 0) data.body.inbox.moduleSearchCriteria.status = states; - if (ward.length > 0) data.body.inbox.moduleSearchCriteria.ward = ward; - const projectType = _.clone(data.body.inbox.moduleSearchCriteria.projectType ? data.body.inbox.moduleSearchCriteria.projectType : {}); - if (projectType?.code) data.body.inbox.moduleSearchCriteria.projectType = projectType.code; - - //adding tenantId to moduleSearchCriteria - data.body.inbox.moduleSearchCriteria.tenantId = Digit.ULBService.getCurrentTenantId(); - - //setting limit and offset becoz somehow they are not getting set in muster inbox - data.body.inbox .limit = data.state.tableForm.limit - data.body.inbox.offset = data.state.tableForm.offset - delete data.state - return data; - }, - postProcess: (responseArray, uiConfig) => { - const statusOptions = responseArray?.statusMap - ?.filter((item) => item.applicationstatus) - ?.map((item) => ({ code: item.applicationstatus, i18nKey: `COMMON_MASTERS_${item.applicationstatus}` })); - if (uiConfig?.type === "filter") { - let fieldConfig = uiConfig?.fields?.filter((item) => item.type === "dropdown" && item.populators.name === "musterRollStatus"); - if (fieldConfig.length) { - fieldConfig[0].populators.options = statusOptions; - } - } - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - if (key === "ATM_MUSTER_ROLL_ID") { - return ( - - - {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} - - - ); - } - if (key === "ATM_ATTENDANCE_WEEK") { - const week = `${Digit.DateUtils.ConvertTimestampToDate(value?.startDate, "dd/MM/yyyy")}-${Digit.DateUtils.ConvertTimestampToDate( - value?.endDate, - "dd/MM/yyyy" - )}`; - return
{week}
; - } - if (key === "ATM_NO_OF_INDIVIDUALS") { - return
{value?.length}
; - } - if(key === "ATM_AMOUNT_IN_RS"){ - return {value ? Digit.Utils.dss.formatterWithoutRound(value, "number") : t("ES_COMMON_NA")}; - } - if (key === "ATM_SLA") { - return parseInt(value) > 0 ? ( - {t(value) || ""} - ) : ( - {t(value) || ""} - ); - } - if (key === "COMMON_WORKFLOW_STATES") { - return {t(`WF_MUSTOR_${value}`)} - } - //added this in case we change the key and not updated here , it'll throw that nothing was returned from cell error if that case is not handled here. To prevent that error putting this default - return {t(`CASE_NOT_HANDLED`)} - }, - MobileDetailsOnClick: (row, tenantId) => { - let link; - Object.keys(row).map((key) => { - if (key === "ATM_MUSTER_ROLL_ID") - link = `/${window.contextPath}/employee/attendencemgmt/view-attendance?tenantId=${tenantId}&musterRollNumber=${row[key]}`; - }); - return link; - }, - populateReqCriteria: () => { - const tenantId = Digit.ULBService.getCurrentTenantId(); - return { - url: "/org-services/organisation/v1/_search", - params: { limit: 50, offset: 0 }, - body: { - SearchCriteria: { - tenantId: tenantId, - functions : { - type : "CBO" - } - }, - }, - config: { - enabled: true, - select: (data) => { - return data?.organisations; - }, - }, - }; - }, - }, - SearchWageSeekerConfig: { - customValidationCheck: (data) => { - //checking both to and from date are present - const { createdFrom, createdTo } = data; - if ((createdFrom === "" && createdTo !== "") || (createdFrom !== "" && createdTo === "")) - return { warning: true, label: "ES_COMMON_ENTER_DATE_RANGE" }; - - return false; - }, - preProcess: (data) => { - data.params = { ...data.params, tenantId: Digit.ULBService.getCurrentTenantId() }; - - let requestBody = { ...data.body.Individual }; - const pathConfig = { - name: "name.givenName", - }; - const dateConfig = { - createdFrom: "daystart", - createdTo: "dayend", - }; - const selectConfig = { - wardCode: "wardCode[0].code", - socialCategory: "socialCategory.code", - }; - const textConfig = ["name", "individualId"] - let Individual = Object.keys(requestBody) - .map((key) => { - if (selectConfig[key]) { - requestBody[key] = _.get(requestBody, selectConfig[key], null); - } else if (typeof requestBody[key] == "object") { - requestBody[key] = requestBody[key]?.code; - } else if (textConfig?.includes(key)) { - requestBody[key] = requestBody[key]?.trim() - } - return key; - }) - .filter((key) => requestBody[key]) - .reduce((acc, curr) => { - if (pathConfig[curr]) { - _.set(acc, pathConfig[curr], requestBody[curr]); - } else if (dateConfig[curr] && dateConfig[curr]?.includes("day")) { - _.set(acc, curr, Digit.Utils.date.convertDateToEpoch(requestBody[curr], dateConfig[curr])); - } else { - _.set(acc, curr, requestBody[curr]); - } - return acc; - }, {}); - - data.body.Individual = { ...Individual }; - return data; - }, - additionalCustomizations: (row, key, column, value, t, searchResult) => { - //here we can add multiple conditions - //like if a cell is link then we return link - //first we can identify which column it belongs to then we can return relevant result - switch (key) { - case "MASTERS_WAGESEEKER_ID": - return ( - - - {String(value ? (column.translate ? t(column.prefix ? `${column.prefix}${value}` : value) : value) : t("ES_COMMON_NA"))} - - - ); - - case "MASTERS_SOCIAL_CATEGORY": - return value ? {String(t(`MASTERS_${value}`))} : t("ES_COMMON_NA"); - - case "CORE_COMMON_PROFILE_CITY": - return value ? {String(t(Digit.Utils.locale.getCityLocale(value)))} : t("ES_COMMON_NA"); - - case "MASTERS_WARD": - return value ? ( - {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} - ) : ( - t("ES_COMMON_NA") - ); - - case "MASTERS_LOCALITY": - return value ? ( - {String(t(Digit.Utils.locale.getMohallaLocale(value, row?.tenantId)))} - ) : ( - t("ES_COMMON_NA") - ); - default: - return t("ES_COMMON_NA"); - } - }, - MobileDetailsOnClick: (row, tenantId) => { - let link; - Object.keys(row).map((key) => { - if (key === "MASTERS_WAGESEEKER_ID") - link = `/${window.contextPath}/employee/masters/view-wageseeker?tenantId=${tenantId}&wageseekerId=${row[key]}`; - }); - return link; - }, - additionalValidations: (type, data, keys) => { - if (type === "date") { - return data[keys.start] && data[keys.end] ? () => new Date(data[keys.start]).getTime() <= new Date(data[keys.end]).getTime() : true; - } - } - }, -}; diff --git a/frontend/micro-ui/web/src/Customisations/index.js b/frontend/micro-ui/web/src/Customisations/index.js deleted file mode 100644 index 803b1e8763e..00000000000 --- a/frontend/micro-ui/web/src/Customisations/index.js +++ /dev/null @@ -1,19 +0,0 @@ -import { ptComponents } from "./pt"; -import { tlComponents } from "./tl"; - -var Digit = window.Digit || {}; - -const customisedComponent = { - ...ptComponents, - ...tlComponents -} - - - -export const initCustomisationComponents = () => { - Object.entries(customisedComponent).forEach(([key, value]) => { - Digit.ComponentRegistryService.setComponent(key, value); - }); -}; - - diff --git a/frontend/micro-ui/web/src/Customisations/pt/index.js b/frontend/micro-ui/web/src/Customisations/pt/index.js deleted file mode 100644 index 0063fcd4774..00000000000 --- a/frontend/micro-ui/web/src/Customisations/pt/index.js +++ /dev/null @@ -1,13 +0,0 @@ -import PropertyUsageType from "./pageComponents/PropertyUsageType"; -import PTVasikaDetails from "./pageComponents/PTVasikaDetails"; -import PTAllotmentDetails from "./pageComponents/PTAllotmentDetails"; -import PTBusinessDetails from "./pageComponents/PTBusinessDetails"; - - - -export const ptComponents = { - PropertyUsageType: PropertyUsageType, - PTVasikaDetail:PTVasikaDetails, - PTAllotmentDetails:PTAllotmentDetails, - PTBusinessDetails:PTBusinessDetails -}; diff --git a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTAllotmentDetails.js b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTAllotmentDetails.js deleted file mode 100644 index 569aa45e409..00000000000 --- a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTAllotmentDetails.js +++ /dev/null @@ -1,64 +0,0 @@ -import { CardLabel, CitizenInfoLabel, FormStep, LabelFieldPair, TextInput,CardLabelError } from "@egovernments/digit-ui-react-components"; -import React, { useState } from "react"; -var validation ={}; -const PTAllotmentDetails = ({ t, config, onSelect, value, userType, formData }) => { - - const [ - val, setValue - ] = useState(formData?.[config.key]?.alotmentDetails||""); - - const goNext = () => { - onSelect(config.key, {alotmentDetails:val}); - }; - - - if (userType === "employee") { - return ( - - - {t("PT_VASIKA_NO_LABEL") } -
- setValue(e?.target?.value)} - // autoFocus={presentInModifyApplication} - /> -
-
-
- ); - } - return ( - - -
- {`${t("PT_VASIKA_ALLOTMENT_LABEL")}`} - setValue(e?.target?.value)} - - /> -
-
- {} -
- ); -}; - -export default PTAllotmentDetails; diff --git a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTBusinessDetails.js b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTBusinessDetails.js deleted file mode 100644 index 3d28785e7e5..00000000000 --- a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTBusinessDetails.js +++ /dev/null @@ -1,68 +0,0 @@ -import { CardLabel, CitizenInfoLabel, FormStep, LabelFieldPair, TextInput,CardLabelError } from "@egovernments/digit-ui-react-components"; -import React, { useState } from "react"; -var validation ={}; -const PTBusinessDetails = ({ t, config, onSelect, value, userType, formData }) => { - - - const [ - val, setValue - ] = useState(formData?.[config.key]?.businessDetails||""); - - const goNext = () => { - onSelect(config.key, {businessDetails:val}); - }; - - - if (userType === "employee") { - return ( - - - {t("PT_VASIKA_NO_LABEL") } -
- setValue(e?.target?.value)} - // autoFocus={presentInModifyApplication} - /> -
-
- -
- ); - } - return ( - - - -
- {`${t("PT_VASIKA_BUS_DETAILS_LABEL")}`} - setValue(e?.target?.value)} - - /> -
- -
- {} -
- ); -}; - -export default PTBusinessDetails; diff --git a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTVasikaDetails.js b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTVasikaDetails.js deleted file mode 100644 index 0e4b6895745..00000000000 --- a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PTVasikaDetails.js +++ /dev/null @@ -1,79 +0,0 @@ -import { CardLabel, CitizenInfoLabel, FormStep, LabelFieldPair, TextInput,CardLabelError } from "@egovernments/digit-ui-react-components"; -import React, { useState } from "react"; -var validation ={}; -const PTVasikaDetails = ({ t, config, onSelect, value, userType, formData }) => { - - - const [ - val, setValue - ] = useState(formData?.[config.key]?.vasikaNo||""); - const [ - other, setOther - ] = useState(formData?.[config.key]?.vasikaArea||""); - const goNext = () => { - onSelect(config.key, {vasikaNo:val,vasikaArea:other}); - }; - - - if (userType === "employee") { - return ( - - - {t("PT_VASIKA_NO_LABEL") } -
- setValue(e?.target?.value)} - // autoFocus={presentInModifyApplication} - /> -
-
- -
- ); - } - return ( - - - -
- {`${t("PT_VASIKA_NO_LABEL")}`} - setValue(e?.target?.value)} - - /> -
- {`${t("PT_VASIKA_AREA_LABEL")}`} - setOther(e?.target?.value)} - /> -
- {} -
- ); -}; - -export default PTVasikaDetails; diff --git a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PropertyUsageType.js b/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PropertyUsageType.js deleted file mode 100644 index deade4fc2ad..00000000000 --- a/frontend/micro-ui/web/src/Customisations/pt/pageComponents/PropertyUsageType.js +++ /dev/null @@ -1,134 +0,0 @@ -import { - CardLabel, CardLabelError, CitizenInfoLabel, Dropdown, FormStep, LabelFieldPair, RadioButtons -} from "@egovernments/digit-ui-react-components"; -import React, { useEffect, useState } from "react"; -import { useLocation } from "react-router-dom"; - -var Digit = window.Digit || {}; - -const PropertyUsageType = ({ t, config, onSelect, userType, formData, formState, setError, clearErrors, onBlur }) => { - const [usageCategoryMajor, setPropertyPurpose] = useState( - formData?.usageCategoryMajor && formData?.usageCategoryMajor?.code === "NONRESIDENTIAL.OTHERS" - ? { code: `${formData?.usageCategoryMajor?.code}`, i18nKey: `PROPERTYTAX_BILLING_SLAB_OTHERS` } - : formData?.usageCategoryMajor - ); - - const tenantId = Digit.ULBService.getCurrentTenantId(); - const stateId = tenantId.split(".")[0]; - const { data: Menu = { }, isLoading: menuLoading } = Digit.Hooks.pt.usePropertyMDMS(stateId, "PropertyTax", "UsageCategory") || { }; - let usagecat = []; - usagecat = Menu?.PropertyTax?.UsageCategory || []; - let i; - let menu = []; - - const { pathname } = useLocation(); - const presentInModifyApplication = pathname.includes("modify"); - - function usageCategoryMajorMenu(usagecat) { - if (userType === "employee") { - const catMenu = usagecat - ?.filter((e) => e?.code.split(".").length <= 2 && e.code !== "NONRESIDENTIAL") - ?.map((item) => { - const arr = item?.code.split("."); - if (arr.length == 2) return { i18nKey: "PROPERTYTAX_BILLING_SLAB_" + arr[1], code: item?.code }; - else return { i18nKey: "PROPERTYTAX_BILLING_SLAB_" + item?.code, code: item?.code }; - }); - return catMenu; - } else { - for (i = 0; i < 10; i++) { - if ( - Array.isArray(usagecat) && - usagecat.length > 0 && - usagecat[i].code.split(".")[0] == "NONRESIDENTIAL" && - usagecat[i].code.split(".").length == 2 - ) { - menu.push({ i18nKey: "PROPERTYTAX_BILLING_SLAB_" + usagecat[i].code.split(".")[1], code: usagecat[i].code }); - } - } - return menu; - } - } - - useEffect(() => { - if (!menuLoading && presentInModifyApplication && userType === "employee") { - const original = formData?.originalData?.usageCategory; - const selectedOption = usageCategoryMajorMenu(usagecat).filter((e) => e.code === original)[0]; - setPropertyPurpose(selectedOption); - } - }, [menuLoading]); - - const onSkip = () => onSelect(); - - - function selectPropertyPurpose(value) { - setPropertyPurpose(value); - } - - function goNext() { - if (usageCategoryMajor?.i18nKey === "PROPERTYTAX_BILLING_SLAB_OTHERS") { - usageCategoryMajor.i18nKey = "PROPERTYTAX_BILLING_SLAB_NONRESIDENTIAL"; - onSelect(config.key, usageCategoryMajor); - } else { - onSelect(config.key, usageCategoryMajor); - } - } - - useEffect(() => { - if (userType === "employee") { - if (!usageCategoryMajor) { - setError(config.key, { type: "required", message: t(`CORE_COMMON_REQUIRED_ERRMSG`) }); - } else { - clearErrors(config.key); - } - goNext(); - } - }, [usageCategoryMajor]); - - if (userType === "employee") { - return ( - - - {t("PT_ASSESMENT_INFO_USAGE_TYPE") + " *"} - { - selectPropertyPurpose(e); - }} - optionKey="i18nKey" - onBlur={onBlur} - t={t} - /> - - {formState.touched[config.key] ? ( - - {formState.errors?.[config.key]?.message} - - ) : null} - - ); - } - - return ( - - -
- -
-
- {} -
- ); -}; - -export default PropertyUsageType; diff --git a/frontend/micro-ui/web/src/Customisations/tl/TLCustomisation.js b/frontend/micro-ui/web/src/Customisations/tl/TLCustomisation.js deleted file mode 100644 index 642acc52090..00000000000 --- a/frontend/micro-ui/web/src/Customisations/tl/TLCustomisation.js +++ /dev/null @@ -1,5 +0,0 @@ -export const TLCustomisations = { - customiseCreateFormData: (formData, licenceObject) => licenceObject, - customiseRenewalCreateFormData: (formData, licenceObject) => licenceObject, - customiseSendbackFormData: (formData, licenceObject) => licenceObject -} \ No newline at end of file diff --git a/frontend/micro-ui/web/src/Customisations/tl/index.js b/frontend/micro-ui/web/src/Customisations/tl/index.js deleted file mode 100644 index fe2ae4f4e6a..00000000000 --- a/frontend/micro-ui/web/src/Customisations/tl/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import TLUsageType from "./pageComponents/PropertyUsageType"; - - - -export const tlComponents = { - TLPropertyUsageType: TLUsageType, -}; diff --git a/frontend/micro-ui/web/src/Customisations/tl/pageComponents/PropertyUsageType.js b/frontend/micro-ui/web/src/Customisations/tl/pageComponents/PropertyUsageType.js deleted file mode 100644 index 5520a66fc5a..00000000000 --- a/frontend/micro-ui/web/src/Customisations/tl/pageComponents/PropertyUsageType.js +++ /dev/null @@ -1,136 +0,0 @@ -import { - CardLabel, CardLabelError, CitizenInfoLabel, Dropdown, FormStep, LabelFieldPair, RadioButtons -} from "@egovernments/digit-ui-react-components"; -import React, { useEffect, useState } from "react"; -import { useLocation } from "react-router-dom"; - -var Digit = window.Digit || {}; - -const TLUsageType = ({ t, config, onSelect, userType, formData, formState, setError, clearErrors, onBlur }) => { - const [usageCategoryMajor, setPropertyPurpose] = useState( - formData?.usageCategoryMajor && formData?.usageCategoryMajor?.code === "NONRESIDENTIAL.OTHERS" - ? { code: `${formData?.usageCategoryMajor?.code}`, i18nKey: `PROPERTYTAX_BILLING_SLAB_OTHERS` } - : formData?.usageCategoryMajor - ); - - const tenantId = Digit.ULBService.getCurrentTenantId(); - const stateId = tenantId.split(".")[0]; - const { data: Menu = { }, isLoading: menuLoading } = Digit.Hooks.pt.usePropertyMDMS(stateId, "PropertyTax", "UsageCategory") || { }; - let usagecat = []; - usagecat = Menu?.PropertyTax?.UsageCategory || []; - let i; - let menu = []; - - const { pathname } = useLocation(); - const presentInModifyApplication = pathname.includes("modify"); - - function usageCategoryMajorMenu(usagecat) { - if (userType === "employee") { - const catMenu = usagecat - ?.filter((e) => e?.code.split(".").length <= 2 && e.code !== "NONRESIDENTIAL") - ?.map((item) => { - const arr = item?.code.split("."); - if (arr.length == 2) return { i18nKey: "PROPERTYTAX_BILLING_SLAB_" + arr[1], code: item?.code }; - else return { i18nKey: "PROPERTYTAX_BILLING_SLAB_" + item?.code, code: item?.code }; - }); - return catMenu; - } else { - for (i = 0; i < 10; i++) { - if ( - Array.isArray(usagecat) && - usagecat.length > 0 && - usagecat[i].code.split(".")[0] == "NONRESIDENTIAL" && - usagecat[i].code.split(".").length == 2 - ) { - menu.push({ i18nKey: "PROPERTYTAX_BILLING_SLAB_" + usagecat[i].code.split(".")[1], code: usagecat[i].code }); - } - } - return menu; - } - } - - useEffect(() => { - if (!menuLoading && presentInModifyApplication && userType === "employee") { - const original = formData?.originalData?.usageCategory; - const selectedOption = usageCategoryMajorMenu(usagecat).filter((e) => e.code === original)[0]; - setPropertyPurpose(selectedOption); - } - }, [menuLoading]); - - const onSkip = () => onSelect(); - - - function selectPropertyPurpose(value) { - setPropertyPurpose(value); - } - - function goNext() { - if (usageCategoryMajor?.i18nKey === "PROPERTYTAX_BILLING_SLAB_OTHERS") { - usageCategoryMajor.i18nKey = "PROPERTYTAX_BILLING_SLAB_NONRESIDENTIAL"; - onSelect(config.key, usageCategoryMajor); - } else { - onSelect(config.key, usageCategoryMajor); - } - } - - useEffect(() => { - if (userType === "employee") { - if (!usageCategoryMajor) { - setError(config.key, { type: "required", message: t(`CORE_COMMON_REQUIRED_ERRMSG`) }); - } else { - clearErrors(config.key); - } - goNext(); - } - }, [usageCategoryMajor]); - - if (userType === "employee") { - return ( - - - {t("PT_ASSESMENT_INFO_USAGE_TYPE") + " *"} - { - selectPropertyPurpose(e); - }} - optionKey="i18nKey" - onBlur={onBlur} - t={t} - /> - - {formState.touched[config.key] ? ( - - {formState.errors?.[config.key]?.message} - - ) : null} - - ); - } - - return ( - - -
- - - -
-
- {} -
- ); -}; - -export default TLUsageType; diff --git a/frontend/micro-ui/web/src/index.css b/frontend/micro-ui/web/src/index.css deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/frontend/micro-ui/web/src/index.js b/frontend/micro-ui/web/src/index.js deleted file mode 100644 index 9f20bf1b506..00000000000 --- a/frontend/micro-ui/web/src/index.js +++ /dev/null @@ -1,62 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import { initLibraries } from "@egovernments/digit-ui-libraries"; -import "./index.css"; -import App from './App'; -import { TLCustomisations } from './Customisations/tl/TLCustomisation'; - - -initLibraries(); - - -window.Digit.Customizations = { PGR: {} ,TL:TLCustomisations}; - -const user = window.Digit.SessionStorage.get("User"); - -if (!user || !user.access_token || !user.info) { - // login detection - - const parseValue = (value) => { - try { - return JSON.parse(value) - } catch (e) { - return value - } - } - - const getFromStorage = (key) => { - const value = window.localStorage.getItem(key); - return value && value !== "undefined" ? parseValue(value) : null; - } - - const token = getFromStorage("token") - - const citizenToken = getFromStorage("Citizen.token") - const citizenInfo = getFromStorage("Citizen.user-info") - const citizenTenantId = getFromStorage("Citizen.tenant-id") - - const employeeToken = getFromStorage("Employee.token") - const employeeInfo = getFromStorage("Employee.user-info") - const employeeTenantId = getFromStorage("Employee.tenant-id") - const userType = token === citizenToken ? "citizen" : "employee"; - - window.Digit.SessionStorage.set("user_type", userType); - window.Digit.SessionStorage.set("userType", userType); - - const getUserDetails = (access_token, info) => ({ token: access_token, access_token, info }) - - const userDetails = userType === "citizen" ? getUserDetails(citizenToken, citizenInfo) : getUserDetails(employeeToken, employeeInfo) - - window.Digit.SessionStorage.set("User", userDetails); - window.Digit.SessionStorage.set("Citizen.tenantId", citizenTenantId); - window.Digit.SessionStorage.set("Employee.tenantId", employeeTenantId); - // end -} - -ReactDOM.render( - - - , - document.getElementById('root') -); - diff --git a/frontend/micro-ui/web/src/setupProxy.js b/frontend/micro-ui/web/src/setupProxy.js deleted file mode 100644 index 1b8eda94a19..00000000000 --- a/frontend/micro-ui/web/src/setupProxy.js +++ /dev/null @@ -1,30 +0,0 @@ -const { createProxyMiddleware } = require("http-proxy-middleware"); -const createProxy = createProxyMiddleware({ - target: process.env.REACT_APP_PROXY_URL, - changeOrigin: true, -}); -module.exports = function (app) { - [ - "/egov-mdms-service", - "/egov-location", - "/localization", - "/egov-workflow-v2", - "/pgr-services", - "/filestore", - "/egov-hrms", - "/user-otp", - "/user", - "/fsm", - "/billing-service", - "/collection-services", - "/pdf-service", - "/pg-service", - "/vehicle", - "/vendor", - "/property-services", - "/fsm-calculator/v1/billingSlab/_search", - "/muster-roll" - ].forEach((location) => - app.use(location, createProxy) - ); -}; diff --git a/frontend/micro-ui/web/webpack.config.js b/frontend/micro-ui/web/webpack.config.js deleted file mode 100644 index 5f3dc46967a..00000000000 --- a/frontend/micro-ui/web/webpack.config.js +++ /dev/null @@ -1,43 +0,0 @@ -const path = require("path"); -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const { CleanWebpackPlugin } = require("clean-webpack-plugin"); -// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; - -module.exports = { - // mode: 'development', - entry: "./src/index.js", - devtool: "none", - module: { - rules: [ - { - test: /\.(js)$/, - use: ["babel-loader"], - }, - { - test: /\.css$/i, - use: ["style-loader", "css-loader"], - } - ], - }, - output: { - filename: "[name].bundle.js", - path: path.resolve(__dirname, "build"), - publicPath: "/digit-ui/", - }, - optimization: { - splitChunks: { - chunks: 'all', - minSize:20000, - maxSize:50000, - enforceSizeThreshold:50000, - minChunks:1, - maxAsyncRequests:30, - maxInitialRequests:30 - }, - }, - plugins: [ - new CleanWebpackPlugin(), - // new BundleAnalyzerPlugin(), - new HtmlWebpackPlugin({ inject: true, template: "public/index.html" }), - ], -}; \ No newline at end of file diff --git a/frontend/micro-ui/web/workbench/App.js b/frontend/micro-ui/web/workbench/App.js deleted file mode 100644 index 93b15440c5e..00000000000 --- a/frontend/micro-ui/web/workbench/App.js +++ /dev/null @@ -1,72 +0,0 @@ -/** - * The above code initializes various Digit UI modules and components, sets up customizations, and - * renders the DigitUI component based on the enabled modules and state code. - * @returns The `App` component is being returned, which renders the `DigitUI` component with the - * specified props such as `stateCode`, `enabledModules`, `moduleReducers`, and `defaultLanding`. The - * `DigitUI` component is responsible for rendering the UI based on the provided configuration and - * modules. - */ -import React from "react"; -import { initLibraries } from "@egovernments/digit-ui-libraries"; -import { DigitUI } from "@egovernments/digit-ui-module-core"; -// import { initHRMSComponents } from "@egovernments/digit-ui-module-hrms"; -import { UICustomizations } from "./Customisations/UICustomizations"; -import { initWorkbenchComponents } from "@egovernments/digit-ui-module-workbench"; -import { initUtilitiesComponents } from "@egovernments/digit-ui-module-utilities"; -import { initWorkbenchHCMComponents } from "@egovernments/digit-ui-module-hcmworkbench"; -import { initCampaignComponents } from "@egovernments/digit-ui-module-campaign-manager" - -window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); - -const enabledModules = [ - "DSS", - "NDSS", - "Utilities", - // "HRMS", - "Engagement", - "Workbench", - "HCMWORKBENCH", - "Campaign" -]; - -const moduleReducers = (initData) => ({ - initData, -}); - -const initDigitUI = () => { - window.Digit.ComponentRegistryService.setupRegistry({}); - window.Digit.Customizations = { - PGR: {}, - commonUiConfig: UICustomizations, - }; - // initHRMSComponents(); - initUtilitiesComponents(); - initWorkbenchComponents(); - initWorkbenchHCMComponents(); - initCampaignComponents(); - -}; - -initLibraries().then(() => { - initDigitUI(); -}); - -function App() { - window.contextPath = window?.globalConfigs?.getConfig("CONTEXT_PATH"); - const stateCode = - window.globalConfigs?.getConfig("STATE_LEVEL_TENANT_ID") || - process.env.REACT_APP_STATE_LEVEL_TENANT_ID; - if (!stateCode) { - return

stateCode is not defined

; - } - return ( - - ); -} - -export default App; diff --git a/frontend/micro-ui/web/workbench/Dockerfile b/frontend/micro-ui/web/workbench/Dockerfile deleted file mode 100644 index 31b3912759b..00000000000 --- a/frontend/micro-ui/web/workbench/Dockerfile +++ /dev/null @@ -1,29 +0,0 @@ -FROM egovio/alpine-node-builder-14:yarn AS build -#FROM ghcr.io/egovernments/alpine-node-builder-14:yarn AS build -RUN apk update && apk upgrade -RUN apk add --no-cache git>2.30.0 -ARG WORK_DIR -WORKDIR /app -ENV NODE_OPTIONS "--max-old-space-size=4792" - -COPY ${WORK_DIR} . -RUN ls -lah - -#RUN node web/envs.js -RUN cd web/ \ - && node -e 'console.log(v8.getHeapStatistics().heap_size_limit/(1024*1024))' \ - && node -e 'console.log("core only")' \ - && cd workbench/ \ - && ./install-deps.sh \ - && cd ../ \ - && yarn install \ - && yarn build:webpack - -FROM nginx:mainline-alpine -#FROM ghcr.io/egovernments/nginx:mainline-alpine -ENV WORK_DIR=/var/web/workbench-ui - -RUN mkdir -p ${WORK_DIR} - -COPY --from=build /app/web/build ${WORK_DIR}/ -COPY --from=build /app/web/workbench/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/frontend/micro-ui/web/workbench/install-deps.sh b/frontend/micro-ui/web/workbench/install-deps.sh deleted file mode 100755 index 54b8a4c3d7f..00000000000 --- a/frontend/micro-ui/web/workbench/install-deps.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/sh - -BRANCH="$(git branch --show-current)" - -echo "Main Branch: $BRANCH" - -INTERNALS="micro-ui-internals" -cd .. - -cp workbench/App.js src -cp workbench/package.json package.json -cp workbench/webpack.config.js webpack.config.js -cp workbench/inter-package.json $INTERNALS/package.json - -cp $INTERNALS/example/src/UICustomizations.js src/Customisations - -echo "UI :: workbench " && echo "Branch: $(git branch --show-current)" && echo "$(git log -1 --pretty=%B)" && echo "installing packages" - diff --git a/frontend/micro-ui/web/workbench/inter-package.json b/frontend/micro-ui/web/workbench/inter-package.json deleted file mode 100644 index 5216443ec23..00000000000 --- a/frontend/micro-ui/web/workbench/inter-package.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "name": "egovernments", - "version": "1.0.0", - "main": "index.js", - "workspaces": [ - "example", - "packages/css", - "packages/modules/*" - ], - "author": "JaganKumar ", - "license": "MIT", - "private": true, - "engines": { - "node": ">=14" - }, - "scripts": { - "start": "SKIP_PREFLIGHT_CHECK=true run-s build start:dev", - "sprint": "SKIP_PREFLIGHT_CHECK=true run-s start:script", - "start:dev": "run-p dev:**", - "start:script": "./scripts/create.sh", - "dev:css": "cd packages/css && yarn start", - "publish:css": "cd packages/css && yarn publish --access public", - "dev:example": "cd example && yarn start", - "dev:campaign": "cd packages/modules/campaign-manager && yarn start", - "build": "run-p build:**", - "build:campaign": "cd packages/modules/campaign-manager && yarn build", - "deploy:jenkins": "./scripts/jenkins.sh", - "clean": "rm -rf node_modules" - }, - "resolutions": { - "**/@babel/runtime": "7.20.1", - "**/babel-preset-react-app": "10.0.0", - "**/ajv": "8.11.2", - "fast-uri":"2.1.0" - }, - "devDependencies": { - "husky": "7.0.4", - "lint-staged": "12.3.7", - "npm-run-all": "4.1.5", - "prettier": "2.1.2" - }, - "husky": {}, - "lint-staged": { - "*.{js,css,md}": "prettier --write" - }, - "dependencies": { - "lodash": "4.17.21", - "microbundle-crl": "0.13.11", - "@egovernments/digit-ui-react-components": "1.8.2-beta.1", - "@egovernments/digit-ui-components": "0.0.2-beta.1", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "react-router-dom": "5.3.0" - } -} diff --git a/frontend/micro-ui/web/workbench/nginx.conf b/frontend/micro-ui/web/workbench/nginx.conf deleted file mode 100644 index 974ef82f241..00000000000 --- a/frontend/micro-ui/web/workbench/nginx.conf +++ /dev/null @@ -1,12 +0,0 @@ -server -{ - listen 80; - underscores_in_headers on; - - location /workbench-ui - { - root /var/web; - index index.html index.htm; - try_files $uri $uri/ /workbench-ui/index.html; - } -} \ No newline at end of file diff --git a/frontend/micro-ui/web/workbench/package.json b/frontend/micro-ui/web/workbench/package.json deleted file mode 100644 index 7cc60ef7bff..00000000000 --- a/frontend/micro-ui/web/workbench/package.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "name": "micro-ui", - "version": "1.0.0", - "author": "Jagankumar ", - "license": "MIT", - "private": true, - "engines": { - "node": ">=14" - }, - "workspaces": [ - "micro-ui-internals/packages/modules/*" - ], - "homepage": "/workbench-ui", - "dependencies": { - "@egovernments/digit-ui-libraries": "1.8.2-beta.1", - "@egovernments/digit-ui-module-workbench": "1.0.2-beta.3", - "@egovernments/digit-ui-components": "0.0.2-beta.1", - "@egovernments/digit-ui-module-core": "1.8.2-beta.2", - "@egovernments/digit-ui-module-utilities": "1.0.1-beta.30", - "@egovernments/digit-ui-react-components": "1.8.2-beta.6", - "@egovernments/digit-ui-module-hcmworkbench":"0.0.38", - "@egovernments/digit-ui-module-campaign-manager": "0.0.1", - "babel-loader": "8.1.0", - "clean-webpack-plugin": "4.0.0", - "react": "17.0.2", - "react-dom": "17.0.2", - "jsonpath": "^1.1.1", - "react-router-dom": "5.3.0", - "react-scripts": "4.0.1", - "web-vitals": "1.1.2", - "terser-brunch": "^4.1.0", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "css-loader": "5.2.6", - "style-loader": "2.0.0", - "webpack-cli": "4.10.0" - }, - "devDependencies": { - "@babel/plugin-proposal-private-property-in-object": "7.21.0", - "http-proxy-middleware": "1.3.1", - "lodash": "4.17.21", - "microbundle-crl": "0.13.11", - "react": "17.0.2", - "react-dom": "17.0.2", - "react-hook-form": "6.15.8", - "react-i18next": "11.16.2", - "react-query": "3.6.1", - "react-router-dom": "5.3.0", - "husky": "7.0.4", - "lint-staged": "12.3.7", - "npm-run-all": "4.1.5", - "prettier": "2.1.2" - }, - "resolutions": { - "**/babel-loader": "8.2.2", - "**/@babel/core": "7.14.0", - "**/@babel/preset-env": "7.14.0", - "**/@babel/plugin-transform-modules-commonjs": "7.14.0", - "**/polished":"4.2.2", - "fast-uri":"2.1.0" - }, - "scripts": { - "start": "react-scripts start", - "build": "GENERATE_SOURCEMAP=false SKIP_PREFLIGHT_CHECK=true react-scripts build", - "build:prepare": "./build.sh", - "build:libraries": "cd micro-ui-internals && yarn build", - "build:prod": "webpack --mode production", - "build:webpack": "yarn build:libraries &&cd .. && ls && cd ./web && ls && yarn build:prod", - "clean": "rm -rf node_modules" - }, - "eslintConfig": { - "extends": [ - "react-app" - ] - }, - "browserslist": { - "production": [ - ">0.2%", - "not dead", - "not op_mini all" - ], - "development": [ - "last 1 chrome version", - "last 1 firefox version", - "last 1 safari version" - ] - } -} diff --git a/frontend/micro-ui/web/workbench/webpack.config.js b/frontend/micro-ui/web/workbench/webpack.config.js deleted file mode 100644 index c19e631fe01..00000000000 --- a/frontend/micro-ui/web/workbench/webpack.config.js +++ /dev/null @@ -1,44 +0,0 @@ -const path = require("path"); -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const { CleanWebpackPlugin } = require("clean-webpack-plugin"); -// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; - -module.exports = { - // mode: 'development', - entry: "./src/index.js", - devtool: "none", - module: { - rules: [ - { - test: /\.(js)$/, - exclude: /node_modules/, - use: ["babel-loader"], - }, - { - test: /\.css$/i, - use: ["style-loader", "css-loader"], - } - ], - }, - output: { - filename: "[name].bundle.js", - path: path.resolve(__dirname, "build"), - publicPath: "/workbench-ui/", - }, - optimization: { - splitChunks: { - chunks: 'all', - minSize:20000, - maxSize:50000, - enforceSizeThreshold:50000, - minChunks:1, - maxAsyncRequests:30, - maxInitialRequests:30 - }, - }, - plugins: [ - new CleanWebpackPlugin(), - // new BundleAnalyzerPlugin(), - new HtmlWebpackPlugin({ inject: true, template: "public/index.html" }), - ], -}; \ No newline at end of file diff --git a/health-services/project-factory/CHANGELOG.md b/health-services/project-factory/CHANGELOG.md index 55f990d91ba..8781f319963 100644 --- a/health-services/project-factory/CHANGELOG.md +++ b/health-services/project-factory/CHANGELOG.md @@ -8,3 +8,9 @@ All notable changes to this module will be documented in this file. 3. Create Data: Validates and creates resource details of type facility,user and boundary. 4. Generate Data: Generates sheet data of type facility,user and boundary. 5. Boundary and Resource Validation: Validates boundaries and resources during campaign creation and updating. + +## 0.2.0 - 2024-08-7 +#### ProjectFactory service version 0.2 + 1. Timeline integration for workflow of campaign. + 2. Call user, facility and boundary generate when boundaries changed in campaign update flow + 3. Generate target template based on delivery conditions changed to anything from default. diff --git a/health-services/project-factory/README.md b/health-services/project-factory/README.md index 40aee6d33bc..0b545626fe6 100644 --- a/health-services/project-factory/README.md +++ b/health-services/project-factory/README.md @@ -1,84 +1,93 @@ -# ProjectFactory-Service +# ProjectFactory Service -The Project Factory Service is responsible for managing project-type campaigns, including creating, updating, searching, and creating campaigns. +The **ProjectFactory Service** is responsible for managing project-type campaigns, including creating, updating, searching, and generating campaign data. -### DB UML Diagram +## DB UML Diagram -![image](https://github.com/egovernments/DIGIT-Frontend/assets/137176738/8c43998d-742b-4629-ae90-63ab2b18772b) -![image](https://github.com/egovernments/DIGIT-Frontend/assets/137176738/3ff9609d-771a-4c6e-a769-54766e7111f7) +![DB UML Diagram](https://github.com/egovernments/DIGIT-Frontend/assets/137176738/8c43998d-742b-4629-ae90-63ab2b18772b) +![DB UML Diagram](https://github.com/egovernments/DIGIT-Frontend/assets/137176738/3ff9609d-771a-4c6e-a769-54766e7111f7) +## Service Dependencies -### Service Dependencies +### Core Services -#### Core services +- `egov-localization` +- `egov-filestore` +- `egov-persister` +- `egov-mdms` +- `egov-idgen` +- `egov-boundaryservice-v2` -- egov-localization -- egov-filestore -- egov-persister -- egov-mdms -- egov-idgen -- egov-boundaryservice-v2 +### Health Services -#### Health services -- health-project -- health-hrms -- health-facility +- `health-project` +- `health-hrms` +- `health-facility` -### Swagger API Contract -Please refer to the below Swagger API contract, for ProjectFactory service to understand the structure of APIs and to have visualization of all internal APIs [Swagger API contract](https://editor.swagger.io/?url=https://raw.githubusercontent.com/jagankumar-egov/DIGIT-Specs/hcm-workbench/Domain%20Services/Health/project-factory.yaml) +### Caching +- `Redis` is now used to store cache for frequently accessed data to improve performance. + +## Swagger API Contract + +For the structure and visualization of APIs, refer to the [Swagger API contract](https://editor.swagger.io/?url=https://raw.githubusercontent.com/jagankumar-egov/DIGIT-Specs/hcm-workbench/Domain%20Services/Health/project-factory.yaml). ## Service Details -### Funcatinality -1. ProjectFactory Service manages campaigns: creation, updating, searching, and data generation. -2. Project Mapping : In campaign creation full project mapping is done with staff, facility and resources along with proper target values. -3. Create Data: Validates and creates resource details of type facility,user and boundary. -4. Generate Data: Generates sheet data of type facility,user and boundary. -5. Boundary and Resource Validation: Validates boundaries and resources during campaign creation and updating. - -### Feature -1. Functionality to create campaigns easily. -2. Uploading generated datas sheets to filestore and return filestore id for easy access. -3. Supports localisation. -4. Customizable Delivery Rules: Allows defining delivery rules for projects based on specific criteria. -5. Search and Filtering: Enables searching and filtering campaigns based on various parameters like status, date, and creator. -6. Batch Processing: Supports batch processing for creating and updating multiple campaigns simultaneously. +### Functionality + +1. **Campaign Management**: Manages project-type campaigns, including creation, updating, searching, and data generation. +2. **Project Mapping**: Completes full project mapping with staff, facility, and resources along with proper target values during campaign creation. +3. **Data Creation**: Validates and creates resource details of types `facility`, `user`, and `boundary`. +4. **Data Generation**: Generates sheet data of types `facility`, `user`, and `boundary`. +5. **Validation**: Validates boundaries and resources during campaign creation and updating. + +### Features + +1. **Easy Campaign Creation**: Facilitates easy creation of campaigns. +2. **File Storage**: Uploads generated data sheets to `egov-filestore` and returns the file store ID for easy access. +3. **Localization Support**: Supports localization for multi-language adaptability. +4. **Customizable Delivery Rules**: Allows defining delivery rules for projects based on specific criteria. +5. **Search and Filtering**: Enables searching and filtering campaigns based on parameters like status, date, and creator. +6. **Batch Processing**: Supports batch processing for creating and updating multiple campaigns simultaneously. +7. **Caching with Redis**: Improves performance by caching frequently accessed data. ### External Libraries Used -[xlsx](https://github.com/SheetJS/sheetjs):- For reading and writing Excel files. -[ajv](https://github.com/ajv-validator/ajv):- For JSON schema validation. +- **[xlsx](https://github.com/SheetJS/sheetjs)**: For reading and writing Excel files. +- **[ajv](https://github.com/ajv-validator/ajv)**: For JSON schema validation. +- **[lodash](https://github.com/lodash/lodash)**: For utility functions like data manipulation and object iteration. -[lodash](https://github.com/lodash/lodash):- For utility functions like data manipulation and object iteration. +## Configuration +- **Persister Config**: [Link](https://github.com/egovernments/configs/blob/UNIFIED-UAT/health/egov-persister/project-factory-persister.yml) +- **Helm Chart Details**: [Link](https://github.com/egovernments/DIGIT-DevOps/blob/unified-env/deploy-as-code/helm/charts/health-services/project-factory/values.yaml) -### Configuration +## API Endpoints -- Persister config: [here](https://github.com/egovernments/configs/blob/UNIFIED-UAT/health/egov-persister/project-factory-persister.yml) -- Helm chart details: [here](https://github.com/egovernments/DIGIT-DevOps/blob/unified-env/deploy-as-code/helm/charts/health-services/project-factory/values.yaml) - -### API Endpoints +- **`POST /project-factory/v1/project-type/create`**: Creates a new project-type campaign. +- **`PUT /project-factory/v1/project-type/update`**: Updates an existing project-type campaign. +- **`POST /project-factory/v1/project-type/search`**: Searches for project-type campaigns based on specified criteria. +- **`POST /project-factory/v1/data/_create`**: Creates or validates resource data (e.g., facility, user, boundary). +- **`POST /project-factory/v1/data/_search`**: Searches for resource data based on specified criteria. +- **`POST /project-factory/v1/data/_generate`**: Initiates the generation of new data based on provided parameters. +- **`GET /project-factory/v1/data/_download`**: Downloads resource data based on specified criteria. -- `/project-factory/v1/project-type/create`: Creates a new project type campaign. -- `/project-factory/v1/project-type/update`: Updates an existing project type campaign. -- `/project-factory/v1/project-type/search`: Searches for project type campaigns based on specified criteria. -- `/project-factory/v1/data/_create`: Creates or validates resource data (e.g., facility, user, boundary). -- `/project-factory/v1/data/_search`: Searches for resource data based on specified criteria. -- `/project-factory/v1/data/_generate`: Initiates the generation of new data based on provided parameters. -- `/project-factory/v1/data/_download`: Downloads resource data based on specified criteria. +## Kafka Consumers +- **`start-campaign-mapping`**: Initiates the mapping process for campaigns. -### Kafka Consumers +## Kafka Producers -- start-campaign-mapping: This topic is used by the service to initiate the mapping process for campaigns. +- **`save-project-campaign-details`**: Saves project campaign details after creation. +- **`update-project-campaign-details`**: Updates project campaign details. +- **`create-resource-details`**: Creates resource details. +- **`update-resource-details`**: Updates resource details. +- **`create-resource-activity`**: Creates resource activity. +- **`create-generated-resource-details`**: Saves details for generated resources. +- **`update-generated-resource-details`**: Updates details for generated resources. -### Kafka Producers +## Redis Caching -- save-project-campaign-details: This topic is used to save project campaign details after creation. -- update-project-campaign-details: This topic is used to update project campaign details. -- create-resource-details: This topic is used to create resource details. -- update-resource-details: This topic is used to update resource details. -- create-resource-activity: This topic is used to create resource activity creation. -- create-generated-resource-details: This topic is used to save details for generated resources. -- update-generated-resource-details: This topic is used to update details for generated resources. +- **Purpose**: Enhances performance by caching frequently accessed data and reducing the load on the database. +- **Usage**: Commonly used to store temporary data like search results, and other frequently accessed resources. diff --git a/health-services/project-factory/migration/main/V20240624210000__generated_resource_details_alter_column.sql b/health-services/project-factory/migration/main/V20240624210000__generated_resource_details_alter_column.sql new file mode 100644 index 00000000000..dfd13713c78 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240624210000__generated_resource_details_alter_column.sql @@ -0,0 +1,13 @@ +DO $$ +DECLARE + table_name1 TEXT := 'eg_cm_generated_resource_details'; + column_name1 TEXT := 'campaignId'; +BEGIN + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = table_name1 + AND column_name = column_name1 + ) THEN + EXECUTE format('ALTER TABLE %I ADD COLUMN %I character varying(128);', table_name1, column_name1); + END IF; +END $$; \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240625141100__process_details_ddl.sql b/health-services/project-factory/migration/main/V20240625141100__process_details_ddl.sql new file mode 100644 index 00000000000..e7b4037bd8d --- /dev/null +++ b/health-services/project-factory/migration/main/V20240625141100__process_details_ddl.sql @@ -0,0 +1,11 @@ +CREATE TABLE health.eg_cm_campaign_process ( + id VARCHAR(128) PRIMARY KEY, + campaignId VARCHAR(128) NOT NULL, + type VARCHAR(128), + status VARCHAR(128), + details JSONB, + createdtime BIGINT, + lastmodifiedtime BIGINT, + additionaldetails JSONB, + CONSTRAINT fk_campaignId FOREIGN KEY (campaignId) REFERENCES health.eg_cm_campaign_details(id) +); diff --git a/health-services/project-factory/migration/main/V20240708153000__generated_resource_detail_alter_column.sql b/health-services/project-factory/migration/main/V20240708153000__generated_resource_detail_alter_column.sql new file mode 100644 index 00000000000..a67a8061f42 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240708153000__generated_resource_detail_alter_column.sql @@ -0,0 +1,24 @@ +DO $$ +DECLARE + table_name1 TEXT := 'eg_cm_generated_resource_details'; + column_name1 TEXT := 'campaignId'; + column_name2 TEXT := 'campaignid'; +BEGIN + -- Check if "campaignId" column exists and drop it if it does + IF EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = table_name1 + AND column_name = column_name1 + ) THEN + EXECUTE format('ALTER TABLE %I DROP COLUMN %I;', table_name1, column_name1); + END IF; + + -- Check if "campaignid" column exists (case-insensitive) and create it if it doesn't + IF NOT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_name = table_name1 + AND lower(column_name) = lower(column_name2) + ) THEN + EXECUTE format('ALTER TABLE %I ADD COLUMN %I character varying(128);', table_name1, column_name2); + END IF; +END $$; diff --git a/health-services/project-factory/migration/main/V20240725155100__remove_constraint_process_details.sql b/health-services/project-factory/migration/main/V20240725155100__remove_constraint_process_details.sql new file mode 100644 index 00000000000..9142fc152e0 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240725155100__remove_constraint_process_details.sql @@ -0,0 +1,3 @@ +-- Migration script to remove the foreign key constraint +ALTER TABLE eg_cm_campaign_process DROP CONSTRAINT IF EXISTS fk_campaignId; +ALTER TABLE eg_cm_resource_activity DROP CONSTRAINT IF EXISTS eg_cm_resource_activity_resourceDetailsId_fkey; \ No newline at end of file diff --git a/health-services/project-factory/migration/main/V20240731162600__add_uniqiue_constraint_process_track.sql b/health-services/project-factory/migration/main/V20240731162600__add_uniqiue_constraint_process_track.sql new file mode 100644 index 00000000000..d9bfbd0af53 --- /dev/null +++ b/health-services/project-factory/migration/main/V20240731162600__add_uniqiue_constraint_process_track.sql @@ -0,0 +1,10 @@ +-- Step 1: Remove duplicate rows +DELETE FROM eg_cm_campaign_process a +USING health.eg_cm_campaign_process b +WHERE a.id < b.id +AND a.campaignId = b.campaignId +AND a.type = b.type; + +-- Step 2: Add the unique constraint +ALTER TABLE eg_cm_campaign_process +ADD CONSTRAINT uq_campaignId_type UNIQUE (campaignId, type); diff --git a/health-services/project-factory/migration/migrate.sh b/health-services/project-factory/migration/migrate.sh index 5593a173eba..c433c239956 100755 --- a/health-services/project-factory/migration/migrate.sh +++ b/health-services/project-factory/migration/migrate.sh @@ -1,3 +1,4 @@ #!/bin/sh +flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS repair flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS -baselineOnMigrate=true -outOfOrder=true migrate \ No newline at end of file diff --git a/health-services/project-factory/package-lock.json b/health-services/project-factory/package-lock.json index 5d9d7df918a..a7479aa962a 100644 --- a/health-services/project-factory/package-lock.json +++ b/health-services/project-factory/package-lock.json @@ -18,6 +18,7 @@ "hash-sum": "2.0.0", "helmet": "7.1.0", "http-proxy-middleware": "^3.0.0", + "ioredis": "^5.4.1", "jaeger-client": "^3.19.0", "jsonpath": "1.1.1", "kafka-node": "5.0.0", @@ -40,6 +41,7 @@ "@types/http-proxy-middleware": "^1.0.0", "@types/jaeger-client": "^3.18.7", "@types/jest": "29.5.12", + "@types/lodash": "^4.17.5", "@types/morgan": "1.9.9", "@types/node": "20.11.29", "@types/pg": "8.11.3", @@ -53,22 +55,11 @@ "typescript": "5.4.2" } }, - "node_modules/@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@ampproject/remapping": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, - "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" @@ -78,38 +69,43 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/highlight": "^7.10.4" + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, "node_modules/@babel/compat-data": { "version": "7.24.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz", + "integrity": "sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.24.4", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz", + "integrity": "sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==", "dev": true, - "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.24.2", - "@babel/generator": "^7.24.4", + "@babel/generator": "^7.24.5", "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.24.4", - "@babel/parser": "^7.24.4", + "@babel/helper-module-transforms": "^7.24.5", + "@babel/helpers": "^7.24.5", + "@babel/parser": "^7.24.5", "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.1", - "@babel/types": "^7.24.0", + "@babel/traverse": "^7.24.5", + "@babel/types": "^7.24.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -124,26 +120,11 @@ "url": "https://opencollective.com/babel" } }, - "node_modules/@babel/core/node_modules/@babel/code-frame": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", - "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.24.2", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/core/node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -160,25 +141,24 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { - "version": "7.24.4", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz", + "integrity": "sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/types": "^7.24.0", + "@babel/types": "^7.24.5", "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" @@ -192,7 +172,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/compat-data": "^7.23.5", "@babel/helper-validator-option": "^7.23.5", @@ -204,22 +183,35 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" } }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, "node_modules/@babel/helper-environment-visitor": { "version": "7.22.20", "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -229,7 +221,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/template": "^7.22.15", "@babel/types": "^7.23.0" @@ -243,7 +234,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.22.5" }, @@ -256,7 +246,6 @@ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.24.0" }, @@ -265,17 +254,16 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", - "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz", + "integrity": "sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.20" + "@babel/helper-module-imports": "^7.24.3", + "@babel/helper-simple-access": "^7.24.5", + "@babel/helper-split-export-declaration": "^7.24.5", + "@babel/helper-validator-identifier": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -285,36 +273,33 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", - "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz", + "integrity": "sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz", + "integrity": "sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz", + "integrity": "sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" @@ -325,17 +310,15 @@ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.20", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", - "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz", + "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -345,32 +328,31 @@ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.24.4", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz", + "integrity": "sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.1", - "@babel/types": "^7.24.0" + "@babel/traverse": "^7.24.5", + "@babel/types": "^7.24.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", - "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz", + "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-validator-identifier": "^7.24.5", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -384,7 +366,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, - "license": "MIT", "dependencies": { "color-convert": "^1.9.0" }, @@ -397,7 +378,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -412,7 +392,6 @@ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, - "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -421,25 +400,13 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } + "dev": true }, "node_modules/@babel/highlight/node_modules/has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } @@ -449,7 +416,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, - "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -458,9 +424,10 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.4", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz", + "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==", "dev": true, - "license": "MIT", "bin": { "parser": "bin/babel-parser.js" }, @@ -473,7 +440,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -486,7 +452,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -499,7 +464,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.12.13" }, @@ -512,7 +476,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -525,7 +488,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -538,7 +500,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz", "integrity": "sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -554,7 +515,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -567,7 +527,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -580,7 +539,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.10.4" }, @@ -593,7 +551,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -606,7 +563,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -619,7 +575,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -632,7 +587,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -648,7 +602,6 @@ "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz", "integrity": "sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/helper-plugin-utils": "^7.24.0" }, @@ -664,7 +617,6 @@ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/code-frame": "^7.23.5", "@babel/parser": "^7.24.0", @@ -674,35 +626,20 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/template/node_modules/@babel/code-frame": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", - "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.24.2", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/traverse": { - "version": "7.24.1", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", - "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz", + "integrity": "sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.24.1", - "@babel/generator": "^7.24.1", + "@babel/code-frame": "^7.24.2", + "@babel/generator": "^7.24.5", "@babel/helper-environment-visitor": "^7.22.20", "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.24.1", - "@babel/types": "^7.24.0", + "@babel/helper-split-export-declaration": "^7.24.5", + "@babel/parser": "^7.24.5", + "@babel/types": "^7.24.5", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -710,26 +647,11 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/@babel/code-frame": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", - "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.24.2", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/traverse/node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -747,7 +669,6 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } @@ -756,18 +677,16 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@babel/types": { - "version": "7.24.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", - "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "version": "7.24.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz", + "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==", "dev": true, - "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", + "@babel/helper-string-parser": "^7.24.1", + "@babel/helper-validator-identifier": "^7.24.5", "to-fast-properties": "^2.0.0" }, "engines": { @@ -778,14 +697,12 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@colors/colors": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", - "license": "MIT", "engines": { "node": ">=0.1.90" } @@ -795,7 +712,6 @@ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -808,7 +724,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -818,7 +733,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", - "license": "MIT", "dependencies": { "colorspace": "1.1.x", "enabled": "2.0.x", @@ -891,6 +805,18 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/@eslint/eslintrc/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@fast-csv/format": { "version": "4.3.5", "resolved": "https://registry.npmjs.org/@fast-csv/format/-/format-4.3.5.tgz", @@ -928,11 +854,15 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.63.tgz", "integrity": "sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ==" }, + "node_modules/@ioredis/commands": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz", + "integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==" + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -949,7 +879,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "license": "MIT", "engines": { "node": ">=12" }, @@ -957,29 +886,10 @@ "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "license": "MIT" - }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -996,7 +906,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -1007,29 +916,11 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", "dev": true, - "license": "ISC", "dependencies": { "camelcase": "^5.3.1", "find-up": "^4.1.0", @@ -1046,7 +937,6 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -1056,7 +946,6 @@ "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -1066,7 +955,6 @@ "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.7.0.tgz", "integrity": "sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -1084,7 +972,6 @@ "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.7.0.tgz", "integrity": "sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==", "dev": true, - "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", "@jest/reporters": "^29.7.0", @@ -1127,12 +1014,32 @@ } } }, + "node_modules/@jest/core/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/@jest/environment": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.7.0.tgz", "integrity": "sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/fake-timers": "^29.7.0", "@jest/types": "^29.6.3", @@ -1148,7 +1055,6 @@ "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.7.0.tgz", "integrity": "sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==", "dev": true, - "license": "MIT", "dependencies": { "expect": "^29.7.0", "jest-snapshot": "^29.7.0" @@ -1162,7 +1068,6 @@ "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", "dev": true, - "license": "MIT", "dependencies": { "jest-get-type": "^29.6.3" }, @@ -1175,7 +1080,6 @@ "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.7.0.tgz", "integrity": "sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@sinonjs/fake-timers": "^10.0.2", @@ -1193,7 +1097,6 @@ "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.7.0.tgz", "integrity": "sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/expect": "^29.7.0", @@ -1209,7 +1112,6 @@ "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.7.0.tgz", "integrity": "sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==", "dev": true, - "license": "MIT", "dependencies": { "@bcoe/v8-coverage": "^0.2.3", "@jest/console": "^29.7.0", @@ -1248,40 +1150,79 @@ } } }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "node_modules/@jest/reporters/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": ">=8" } }, - "node_modules/@jest/source-map": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", - "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "node_modules/@jest/reporters/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, - "license": "MIT", "dependencies": { - "@jridgewell/trace-mapping": "^0.3.18", - "callsites": "^3.0.0", - "graceful-fs": "^4.2.9" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@jest/test-result": { + "node_modules/@jest/reporters/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.6.3.tgz", + "integrity": "sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.18", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.7.0.tgz", "integrity": "sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==", "dev": true, - "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", "@jest/types": "^29.6.3", @@ -1297,7 +1238,6 @@ "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz", "integrity": "sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/test-result": "^29.7.0", "graceful-fs": "^4.2.9", @@ -1313,7 +1253,6 @@ "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.7.0.tgz", "integrity": "sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@jest/types": "^29.6.3", @@ -1340,7 +1279,6 @@ "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", "@types/istanbul-lib-coverage": "^2.0.0", @@ -1358,7 +1296,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -1373,7 +1310,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -1383,7 +1319,6 @@ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.0.0" } @@ -1392,15 +1327,13 @@ "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, - "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -1410,7 +1343,6 @@ "version": "2.2.2", "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz", "integrity": "sha512-OrcNPXdpSl9UX7qPVRWbmWMCSXrcDa2M9DvrbOTj7ao1S4PlqVFYv9/yLKMkrJKZ/V5A/kDBC690or307i26Og==", - "license": "ISC", "dependencies": { "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", @@ -1422,20 +1354,10 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/@npmcli/agent/node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", - "license": "ISC", - "engines": { - "node": "14 || >=16.14" - } - }, "node_modules/@npmcli/fs": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", - "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", - "license": "ISC", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz", + "integrity": "sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg==", "dependencies": { "semver": "^7.3.5" }, @@ -1443,11 +1365,21 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, + "node_modules/@npmcli/fs/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "license": "MIT", "optional": true, "engines": { "node": ">=14" @@ -1457,15 +1389,13 @@ "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@sinonjs/commons": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "type-detect": "4.0.8" } @@ -1475,7 +1405,6 @@ "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "@sinonjs/commons": "^3.0.0" } @@ -1484,36 +1413,31 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, - "license": "MIT", "dependencies": { "@babel/parser": "^7.20.7", "@babel/types": "^7.20.7", @@ -1527,7 +1451,6 @@ "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.0.0" } @@ -1537,7 +1460,6 @@ "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, - "license": "MIT", "dependencies": { "@babel/parser": "^7.1.0", "@babel/types": "^7.0.0" @@ -1548,7 +1470,6 @@ "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/types": "^7.20.7" } @@ -1558,7 +1479,6 @@ "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", "integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==", "dev": true, - "license": "MIT", "dependencies": { "@types/connect": "*", "@types/node": "*" @@ -1569,7 +1489,6 @@ "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.5.tgz", "integrity": "sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg==", "dev": true, - "license": "MIT", "dependencies": { "@types/express": "*" } @@ -1579,7 +1498,6 @@ "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -1589,7 +1507,6 @@ "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.21.tgz", "integrity": "sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/body-parser": "*", "@types/express-serve-static-core": "^4.17.33", @@ -1598,11 +1515,10 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "4.17.43", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz", - "integrity": "sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg==", + "version": "4.19.0", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz", + "integrity": "sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "@types/qs": "*", @@ -1615,7 +1531,6 @@ "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -1624,15 +1539,13 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/@types/hash-sum/-/hash-sum-1.0.2.tgz", "integrity": "sha512-UP28RddqY8xcU0SCEp9YKutQICXpaAq9N8U2klqF5hegGha7KzTOL8EdhIIV3bOSGBzjEpN9bU/d+nNZBdJYVw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/helmet": { "version": "0.0.47", "resolved": "https://registry.npmjs.org/@types/helmet/-/helmet-0.0.47.tgz", "integrity": "sha512-TcHA/djjdUtrMtq/QAayVLrsgjNNZ1Uhtz0KhfH01mrmjH44E54DA1A0HNbwW0H/NBFqV+tGMo85ACuEhMXcdg==", "dev": true, - "license": "MIT", "dependencies": { "@types/express": "*" } @@ -1641,8 +1554,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/http-proxy": { "version": "1.17.14", @@ -1666,15 +1578,13 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/istanbul-lib-report": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, - "license": "MIT", "dependencies": { "@types/istanbul-lib-coverage": "*" } @@ -1684,7 +1594,6 @@ "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/istanbul-lib-report": "*" } @@ -1705,25 +1614,28 @@ "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.12.tgz", "integrity": "sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==", "dev": true, - "license": "MIT", "dependencies": { "expect": "^29.0.0", "pretty-format": "^29.0.0" } }, + "node_modules/@types/lodash": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw==", + "dev": true + }, "node_modules/@types/mime": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz", "integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/morgan": { "version": "1.9.9", "resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.9.tgz", "integrity": "sha512-iRYSDKVaC6FkGSpEVVIvrRGw0DfJMiQzIn3qr2G5B3C//AWkulhXgaBd7tS9/J79GWSYMTHGs7PfI5b3Y8m+RQ==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -1732,7 +1644,6 @@ "version": "20.11.29", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.29.tgz", "integrity": "sha512-P99thMkD/1YkCvAtOd6/zGedKNA0p2fj4ZpjCzcNiSCBWgm3cNRTBfa/qjFnsKkkojxu4vVLtWpesnZ9+ap+gA==", - "license": "MIT", "dependencies": { "undici-types": "~5.26.4" } @@ -1742,7 +1653,6 @@ "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.11.3.tgz", "integrity": "sha512-xocw4LvpDcj/Ta7bN52tLZm34mso5SZ0Q8fVC0UtD8s85Itip3YHvBeYZhBmC0OThpdOujHsxXtRbEIRxqXPXg==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "pg-protocol": "*", @@ -1750,25 +1660,22 @@ } }, "node_modules/@types/qs": { - "version": "6.9.14", - "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.14.tgz", - "integrity": "sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA==", - "dev": true, - "license": "MIT" + "version": "6.9.15", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", + "integrity": "sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg==", + "dev": true }, "node_modules/@types/range-parser": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", "integrity": "sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==", "dev": true, - "license": "MIT", "dependencies": { "@types/mime": "^1", "@types/node": "*" @@ -1779,7 +1686,6 @@ "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.7.tgz", "integrity": "sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==", "dev": true, - "license": "MIT", "dependencies": { "@types/http-errors": "*", "@types/node": "*", @@ -1790,35 +1696,30 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/strip-json-comments": { "version": "0.0.30", "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/triple-beam": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==", - "license": "MIT" + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" }, "node_modules/@types/uuid": { "version": "9.0.8", "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/@types/xlsx": { "version": "0.0.36", @@ -1835,7 +1736,6 @@ "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, - "license": "MIT", "dependencies": { "@types/yargs-parser": "*" } @@ -1844,14 +1744,12 @@ "version": "21.0.3", "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/abbrev": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -1860,7 +1758,6 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", - "license": "MIT", "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -1895,7 +1792,6 @@ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -1904,7 +1800,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz", "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==", - "license": "Apache-2.0", "engines": { "node": ">=0.8" } @@ -1913,7 +1808,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", - "license": "MIT", "dependencies": { "debug": "^4.3.4" }, @@ -1922,10 +1816,9 @@ } }, "node_modules/agent-base/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "license": "MIT", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dependencies": { "ms": "2.1.2" }, @@ -1941,14 +1834,12 @@ "node_modules/agent-base/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "license": "MIT" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "license": "MIT", "dependencies": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -1993,7 +1884,6 @@ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -2003,7 +1893,6 @@ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, - "license": "MIT", "dependencies": { "type-fest": "^0.21.3" }, @@ -2019,7 +1908,6 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", "dev": true, - "license": "(MIT OR CC0-1.0)", "engines": { "node": ">=10" }, @@ -2028,24 +1916,20 @@ } }, "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "optional": true, "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" @@ -2056,7 +1940,6 @@ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, - "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -2069,7 +1952,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "license": "ISC", "optional": true }, "node_modules/archiver": { @@ -2109,6 +1991,26 @@ "node": ">= 6" } }, + "node_modules/archiver-utils/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/archiver/node_modules/async": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", @@ -2156,7 +2058,7 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", - "license": "ISC", + "deprecated": "This package is no longer supported.", "optional": true, "dependencies": { "delegates": "^1.0.0", @@ -2167,31 +2069,33 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", "dev": true, - "license": "MIT", "dependencies": { "sprintf-js": "~1.0.2" } }, + "node_modules/argparse/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, "node_modules/array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", - "license": "MIT" + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -2200,7 +2104,6 @@ "version": "2.6.4", "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "license": "MIT", "dependencies": { "lodash": "^4.17.14" } @@ -2208,14 +2111,12 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/axios": { "version": "1.6.8", "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", - "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -2227,7 +2128,6 @@ "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.7.0.tgz", "integrity": "sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==", "dev": true, - "license": "MIT", "dependencies": { "@jest/transform": "^29.7.0", "@types/babel__core": "^7.1.14", @@ -2249,7 +2149,6 @@ "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@istanbuljs/load-nyc-config": "^1.0.0", @@ -2266,7 +2165,6 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.12.3", "@babel/parser": "^7.14.7", @@ -2283,7 +2181,6 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "ISC", "bin": { "semver": "bin/semver.js" } @@ -2293,7 +2190,6 @@ "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz", "integrity": "sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", @@ -2309,7 +2205,6 @@ "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", @@ -2333,7 +2228,6 @@ "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz", "integrity": "sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==", "dev": true, - "license": "MIT", "dependencies": { "babel-plugin-jest-hoist": "^29.6.3", "babel-preset-current-node-syntax": "^1.0.0" @@ -2348,8 +2242,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base64-js": { "version": "1.5.1", @@ -2374,7 +2267,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", - "license": "MIT", "dependencies": { "safe-buffer": "5.1.2" }, @@ -2394,10 +2286,12 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", "integrity": "sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==", - "license": "MIT", "dependencies": { "buffers": "~0.1.1", "chainsaw": "~0.1.0" + }, + "engines": { + "node": "*" } }, "node_modules/binary-extensions": { @@ -2405,7 +2299,6 @@ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" }, @@ -2417,7 +2310,6 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "license": "MIT", "optional": true, "dependencies": { "file-uri-to-path": "1.0.0" @@ -2433,7 +2325,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", - "license": "MIT", "dependencies": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" @@ -2471,7 +2362,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2481,7 +2371,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "license": "MIT", "dependencies": { "fill-range": "^7.0.1" }, @@ -2508,7 +2397,6 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { "caniuse-lite": "^1.0.30001587", "electron-to-chromium": "^1.4.668", @@ -2527,7 +2415,6 @@ "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", "dev": true, - "license": "Apache-2.0", "dependencies": { "node-int64": "^0.4.0" } @@ -2559,7 +2446,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", - "license": "MIT", "optional": true, "dependencies": { "buffer-alloc-unsafe": "^1.1.0", @@ -2570,14 +2456,12 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", - "license": "MIT", "optional": true }, "node_modules/buffer-crc32": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "license": "MIT", "engines": { "node": "*" } @@ -2586,15 +2470,13 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", "integrity": "sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==", - "license": "MIT", "optional": true }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/buffer-indexof-polyfill": { "version": "1.0.2", @@ -2608,7 +2490,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/buffermaker/-/buffermaker-1.2.1.tgz", "integrity": "sha512-IdnyU2jDHU65U63JuVQNTHiWjPRH0CS3aYd/WPaEwyX84rFdukhOduAVb1jwUScmb5X0JWPw8NZOrhoLMiyAHQ==", - "license": "MIT", "dependencies": { "long": "1.1.2" } @@ -2639,16 +2520,14 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", "engines": { "node": ">= 0.8" } }, "node_modules/cacache": { - "version": "18.0.2", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz", - "integrity": "sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw==", - "license": "ISC", + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.3.tgz", + "integrity": "sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg==", "dependencies": { "@npmcli/fs": "^3.1.0", "fs-minipass": "^3.0.0", @@ -2667,66 +2546,10 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/cacache/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/cacache/node_modules/glob": { - "version": "10.3.12", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", - "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.10.2" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", - "license": "ISC", - "engines": { - "node": "14 || >=16.14" - } - }, - "node_modules/cacache/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/call-bind": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -2746,7 +2569,6 @@ "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -2756,15 +2578,14 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/caniuse-lite": { - "version": "1.0.30001605", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz", - "integrity": "sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ==", + "version": "1.0.30001620", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001620.tgz", + "integrity": "sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew==", "dev": true, "funding": [ { @@ -2779,14 +2600,12 @@ "type": "github", "url": "https://github.com/sponsors/ai" } - ], - "license": "CC-BY-4.0" + ] }, "node_modules/cfb": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz", "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==", - "license": "Apache-2.0", "dependencies": { "adler-32": "~1.3.0", "crc-32": "~1.2.0" @@ -2799,9 +2618,11 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", "integrity": "sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==", - "license": "MIT/X11", "dependencies": { "traverse": ">=0.3.0 <0.4" + }, + "engines": { + "node": "*" } }, "node_modules/chalk": { @@ -2809,7 +2630,6 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2821,12 +2641,26 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/char-regex": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "node_modules/chalk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" } @@ -2836,7 +2670,6 @@ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -2857,13 +2690,10 @@ } }, "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "license": "ISC", - "engines": { - "node": ">=10" - } + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "optional": true }, "node_modules/ci-info": { "version": "3.9.0", @@ -2876,23 +2706,20 @@ "url": "https://github.com/sponsors/sibiraj-s" } ], - "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/cjs-module-lexer": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", - "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", - "dev": true, - "license": "MIT" + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz", + "integrity": "sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q==", + "dev": true }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "license": "MIT", "engines": { "node": ">=6" } @@ -2902,7 +2729,6 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, - "license": "ISC", "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -2912,12 +2738,41 @@ "node": ">=12" } }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "node_modules/cliui/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -2927,7 +2782,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2937,21 +2791,56 @@ "node": ">=8" } }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/clone": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", - "license": "MIT", "engines": { "node": ">=0.8" } }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", "dev": true, - "license": "MIT", "engines": { "iojs": ">= 1.0.0", "node": ">= 0.12.0" @@ -2961,7 +2850,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", "integrity": "sha512-RpAVKQA5T63xEj6/giIbUEtZwJ4UFIc3ZtvEkiaUERylqe8xb5IvqcgOurZLahv93CLKfxcw5YI+DZcUBRyLXA==", - "license": "MIT", "optional": true, "engines": { "node": ">=0.10.0" @@ -2971,7 +2859,6 @@ "version": "1.15.0", "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz", "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==", - "license": "Apache-2.0", "engines": { "node": ">=0.8" } @@ -2980,14 +2867,12 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz", "integrity": "sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/color": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "license": "MIT", "dependencies": { "color-convert": "^1.9.3", "color-string": "^1.6.0" @@ -2997,7 +2882,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -3008,14 +2892,12 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/color-string": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "license": "MIT", "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" @@ -3025,7 +2907,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "license": "MIT", "dependencies": { "color-name": "1.1.3" } @@ -3033,14 +2914,12 @@ "node_modules/color/node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "license": "MIT" + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, "node_modules/colorspace": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", - "license": "MIT", "dependencies": { "color": "^3.1.3", "text-hex": "1.0.x" @@ -3050,7 +2929,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" }, @@ -3089,7 +2967,6 @@ "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", - "license": "MIT", "dependencies": { "mime-db": ">= 1.43.0 < 2" }, @@ -3101,7 +2978,6 @@ "version": "1.7.4", "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", - "license": "MIT", "dependencies": { "accepts": "~1.3.5", "bytes": "3.0.0", @@ -3119,7 +2995,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3127,21 +3002,18 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "license": "MIT" + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "license": "ISC", "optional": true }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", - "license": "MIT", "dependencies": { "safe-buffer": "5.2.1" }, @@ -3166,14 +3038,12 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/content-type": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -3182,8 +3052,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/cookie": { "version": "0.6.0", @@ -3196,20 +3065,17 @@ "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", - "license": "MIT" + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "license": "MIT" + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, "node_modules/crc-32": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", - "license": "Apache-2.0", "bin": { "crc32": "bin/crc32.njs" }, @@ -3247,7 +3113,6 @@ "resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz", "integrity": "sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "chalk": "^4.0.0", @@ -3268,14 +3133,12 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3285,6 +3148,20 @@ "node": ">= 8" } }, + "node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/dayjs": { "version": "1.11.11", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz", @@ -3294,7 +3171,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -3303,7 +3179,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", - "license": "MIT", "optional": true, "dependencies": { "mimic-response": "^1.0.0" @@ -3313,11 +3188,10 @@ } }, "node_modules/dedent": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", - "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz", + "integrity": "sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==", "dev": true, - "license": "MIT", "peerDependencies": { "babel-plugin-macros": "^3.1.0" }, @@ -3331,7 +3205,6 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "license": "MIT", "optional": true, "engines": { "node": ">=4.0.0" @@ -3340,15 +3213,13 @@ "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "license": "MIT" + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" }, "node_modules/deepmerge": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -3357,7 +3228,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", @@ -3374,7 +3244,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -3383,14 +3252,12 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "license": "MIT", "optional": true }, "node_modules/denque": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz", "integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==", - "license": "Apache-2.0", "engines": { "node": ">=0.10" } @@ -3399,7 +3266,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3408,7 +3274,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -3418,7 +3283,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "license": "Apache-2.0", "optional": true, "bin": { "detect-libc": "bin/detect-libc.js" @@ -3432,7 +3296,6 @@ "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -3442,7 +3305,6 @@ "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -3452,7 +3314,6 @@ "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true, - "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -3462,7 +3323,6 @@ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, - "license": "Apache-2.0", "dependencies": { "esutils": "^2.0.2" }, @@ -3483,7 +3343,6 @@ "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", "dev": true, - "license": "MIT", "dependencies": { "xtend": "^4.0.0" } @@ -3491,26 +3350,24 @@ "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "license": "MIT" + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.726", - "dev": true, - "license": "ISC" + "version": "1.4.772", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.772.tgz", + "integrity": "sha512-jFfEbxR/abTTJA3ci+2ok1NTuOBBtB4jH+UT6PUmRN+DY3WSD4FFRsgoVQ+QNIJ0T7wrXwzsWCI2WKC46b++2A==", + "dev": true }, "node_modules/emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" }, @@ -3519,22 +3376,19 @@ } }, "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "node_modules/enabled": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==", - "license": "MIT" + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" }, "node_modules/encodeurl": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3543,7 +3397,6 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "license": "MIT", "optional": true, "dependencies": { "iconv-lite": "^0.6.2" @@ -3553,7 +3406,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "license": "MIT", "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -3566,7 +3418,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "license": "MIT", "dependencies": { "once": "^1.4.0" } @@ -3576,7 +3427,6 @@ "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" @@ -3585,11 +3435,31 @@ "node": ">=8.6" } }, + "node_modules/enquirer/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/enquirer/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", - "license": "MIT", "engines": { "node": ">=6" } @@ -3597,8 +3467,7 @@ "node_modules/err-code": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "license": "MIT" + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" }, "node_modules/error": { "version": "7.0.2", @@ -3614,16 +3483,20 @@ "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", "dev": true, - "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" } }, + "node_modules/error-ex/node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, "node_modules/es-define-property": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "license": "MIT", "dependencies": { "get-intrinsic": "^1.2.4" }, @@ -3635,7 +3508,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", "engines": { "node": ">= 0.4" } @@ -3645,7 +3517,6 @@ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -3653,14 +3524,21 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } }, "node_modules/escodegen": { "version": "1.14.3", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "license": "BSD-2-Clause", "dependencies": { "esprima": "^4.0.1", "estraverse": "^4.2.0", @@ -3678,54 +3556,16 @@ "source-map": "~0.6.1" } }, - "node_modules/escodegen/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "license": "MIT", - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "license": "MIT", - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/escodegen/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "license": "MIT", - "dependencies": { - "prelude-ls": "~1.1.2" + "node_modules/escodegen/node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" }, "engines": { - "node": ">= 0.8.0" + "node": ">=4" } }, "node_modules/eslint": { @@ -3787,7 +3627,6 @@ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" @@ -3801,7 +3640,6 @@ "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", "dev": true, - "license": "MIT", "dependencies": { "eslint-visitor-keys": "^1.1.0" }, @@ -3817,7 +3655,6 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=4" } @@ -3827,7 +3664,6 @@ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10" } @@ -3848,12 +3684,20 @@ "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/eslint/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "node_modules/eslint/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -3872,12 +3716,98 @@ "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/eslint/node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/eslint/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/eslint/node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eslint/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/eslint/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, - "license": "MIT" + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } }, "node_modules/espree": { "version": "7.3.1", @@ -3903,16 +3833,15 @@ } }, "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "license": "BSD-2-Clause", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz", + "integrity": "sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==", "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" }, "engines": { - "node": ">=4" + "node": ">=0.4.0" } }, "node_modules/esquery": { @@ -3920,7 +3849,6 @@ "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -3933,7 +3861,6 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -3943,7 +3870,6 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -3956,7 +3882,6 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -3965,7 +3890,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -3974,7 +3898,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -3983,7 +3906,6 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4038,7 +3960,6 @@ "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, - "license": "MIT", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", @@ -4070,7 +3991,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "license": "(MIT OR WTFPL)", "optional": true, "engines": { "node": ">=6" @@ -4081,7 +4001,6 @@ "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/expect-utils": "^29.7.0", "jest-get-type": "^29.6.3", @@ -4096,8 +4015,7 @@ "node_modules/exponential-backoff": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", - "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", - "license": "Apache-2.0" + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==" }, "node_modules/express": { "version": "4.19.2", @@ -4157,8 +4075,7 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/fast-csv": { "version": "4.3.6", @@ -4175,28 +4092,24 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "license": "MIT" + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, "node_modules/fb-watchman": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", "dev": true, - "license": "Apache-2.0", "dependencies": { "bser": "2.1.1" } @@ -4204,15 +4117,13 @@ "node_modules/fecha": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", - "license": "MIT" + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, - "license": "MIT", "dependencies": { "flat-cache": "^3.0.4" }, @@ -4224,14 +4135,12 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "license": "MIT", "optional": true }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -4243,7 +4152,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "license": "MIT", "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -4262,7 +4170,6 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, - "license": "MIT", "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -4276,7 +4183,6 @@ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, - "license": "MIT", "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -4290,14 +4196,12 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/fn.name": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==", - "license": "MIT" + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" }, "node_modules/follow-redirects": { "version": "1.15.6", @@ -4309,7 +4213,6 @@ "url": "https://github.com/sponsors/RubenVerborgh" } ], - "license": "MIT", "engines": { "node": ">=4.0" }, @@ -4320,10 +4223,9 @@ } }, "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "license": "ISC", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.0.tgz", + "integrity": "sha512-CrWQNaEl1/6WeZoarcM9LHupTo3RpZO2Pdk1vktwzPiQTsJnAKJmm3TACKeG5UZbWDfaH2AbvYxzP96y0MT7fA==", "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -4339,7 +4241,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", "engines": { "node": ">=14" }, @@ -4351,7 +4252,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -4365,7 +4265,6 @@ "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4374,7 +4273,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz", "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==", - "license": "Apache-2.0", "engines": { "node": ">=0.8" } @@ -4383,7 +4281,6 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4391,14 +4288,12 @@ "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "license": "MIT" + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, "node_modules/fs-minipass": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", - "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -4409,8 +4304,21 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "license": "ISC" + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } }, "node_modules/fstream": { "version": "1.0.12", @@ -4427,6 +4335,26 @@ "node": ">=0.6" } }, + "node_modules/fstream/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/fstream/node_modules/rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", @@ -4443,7 +4371,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -4452,14 +4379,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", "integrity": "sha512-14x4kjc6lkD3ltw589k0NrPD6cCNTD6CWoVUNpB85+DrtONoZn+Rug6xZU5RvSC4+TZPxA5AnBibQYAvZn41Hg==", - "license": "ISC", + "deprecated": "This package is no longer supported.", "optional": true, "dependencies": { "aproba": "^1.0.3", @@ -4472,35 +4398,11 @@ "wide-align": "^1.1.0" } }, - "node_modules/gauge/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gauge/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "license": "MIT", - "optional": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, - "license": "MIT", "engines": { "node": ">=6.9.0" } @@ -4510,7 +4412,6 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true, - "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -4519,7 +4420,6 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2", @@ -4539,7 +4439,6 @@ "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=8.0.0" } @@ -4549,7 +4448,6 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -4561,24 +4459,24 @@ "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "license": "MIT", "optional": true }, "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "license": "ISC", + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz", + "integrity": "sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw==", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -4589,7 +4487,6 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, - "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -4597,6 +4494,28 @@ "node": ">= 6" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/globals": { "version": "12.4.0", "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", @@ -4612,11 +4531,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globals/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "license": "MIT", "dependencies": { "get-intrinsic": "^1.1.3" }, @@ -4627,15 +4554,13 @@ "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -4644,7 +4569,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" }, @@ -4656,7 +4580,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -4668,7 +4591,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -4680,20 +4602,17 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "license": "ISC", "optional": true }, "node_modules/hash-sum": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", - "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==", - "license": "MIT" + "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==" }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, @@ -4705,7 +4624,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/helmet/-/helmet-7.1.0.tgz", "integrity": "sha512-g+HZqgfbpXdCkme/Cd/mZkV0aV3BZZZSugecH03kl38m/Kmdx8jKjBikpDj2cr+Iynv4KpYEviojNdTJActJAg==", - "license": "MIT", "engines": { "node": ">=16.0.0" } @@ -4731,20 +4649,17 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/http-cache-semantics": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==", - "license": "BSD-2-Clause" + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -4773,7 +4688,6 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "license": "MIT", "dependencies": { "agent-base": "^7.1.0", "debug": "^4.3.4" @@ -4783,10 +4697,9 @@ } }, "node_modules/http-proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "license": "MIT", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dependencies": { "ms": "2.1.2" }, @@ -4802,8 +4715,7 @@ "node_modules/http-proxy-agent/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "license": "MIT" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/http-proxy-middleware": { "version": "3.0.0", @@ -4846,7 +4758,6 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", - "license": "MIT", "dependencies": { "agent-base": "^7.0.2", "debug": "4" @@ -4856,10 +4767,9 @@ } }, "node_modules/https-proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "license": "MIT", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dependencies": { "ms": "2.1.2" }, @@ -4875,15 +4785,13 @@ "node_modules/https-proxy-agent/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "license": "MIT" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, - "license": "Apache-2.0", "engines": { "node": ">=10.17.0" } @@ -4892,7 +4800,6 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -4931,8 +4838,7 @@ "node_modules/immediate": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "license": "MIT" + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==" }, "node_modules/import-fresh": { "version": "3.3.0", @@ -4955,7 +4861,6 @@ "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, - "license": "MIT", "dependencies": { "pkg-dir": "^4.2.0", "resolve-cwd": "^3.0.0" @@ -4974,7 +4879,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "license": "MIT", "engines": { "node": ">=0.8.19" } @@ -4983,7 +4887,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "license": "MIT", "engines": { "node": ">=8" } @@ -4992,7 +4895,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "license": "ISC", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -5001,57 +4904,96 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "license": "ISC", "optional": true }, - "node_modules/ip-address": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", - "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", - "license": "MIT", + "node_modules/ioredis": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.4.1.tgz", + "integrity": "sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==", "dependencies": { - "jsbn": "1.1.0", - "sprintf-js": "^1.1.3" + "@ioredis/commands": "^1.1.1", + "cluster-key-slot": "^1.1.0", + "debug": "^4.3.4", + "denque": "^2.1.0", + "lodash.defaults": "^4.2.0", + "lodash.isarguments": "^3.1.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.1.0" }, "engines": { - "node": ">= 12" + "node": ">=12.22.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" } }, - "node_modules/ip-address/node_modules/sprintf-js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "license": "BSD-3-Clause" + "node_modules/ioredis/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/ioredis/node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/ioredis/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", "engines": { "node": ">= 0.10" } }, "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, - "license": "MIT" + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, - "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, @@ -5064,7 +5006,6 @@ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dev": true, - "license": "MIT", "dependencies": { "hasown": "^2.0.0" }, @@ -5076,7 +5017,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -5085,7 +5025,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", "integrity": "sha512-1pqUqRjkhPJ9miNq9SwMfdvi6lBJcd6eFxvfaivQhaH3SgisfiuudvFntdKOmxuee/77l+FPjKrQjWvmPjWrRw==", - "license": "MIT", "optional": true, "dependencies": { "number-is-nan": "^1.0.0" @@ -5099,7 +5038,6 @@ "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -5108,7 +5046,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -5119,14 +5056,12 @@ "node_modules/is-lambda": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "license": "MIT" + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==" }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -5146,7 +5081,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "license": "MIT", "engines": { "node": ">=8" }, @@ -5157,21 +5091,18 @@ "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "license": "MIT" + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">=8" } @@ -5181,7 +5112,6 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.2.tgz", "integrity": "sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", @@ -5193,12 +5123,23 @@ "node": ">=10" } }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/istanbul-lib-report": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "istanbul-lib-coverage": "^3.0.0", "make-dir": "^4.0.0", @@ -5213,7 +5154,6 @@ "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "debug": "^4.1.1", "istanbul-lib-coverage": "^3.0.0", @@ -5228,7 +5168,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, - "license": "MIT", "dependencies": { "ms": "2.1.2" }, @@ -5245,15 +5184,13 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/istanbul-reports": { "version": "3.1.7", "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "html-escaper": "^2.0.0", "istanbul-lib-report": "^3.0.0" @@ -5263,10 +5200,9 @@ } }, "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "license": "BlueOak-1.0.0", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", + "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -5308,7 +5244,6 @@ "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -5335,7 +5270,6 @@ "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.7.0.tgz", "integrity": "sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==", "dev": true, - "license": "MIT", "dependencies": { "execa": "^5.0.0", "jest-util": "^29.7.0", @@ -5345,12 +5279,26 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-changed-files/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/jest-circus": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.7.0.tgz", "integrity": "sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/expect": "^29.7.0", @@ -5377,38 +5325,19 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-cli": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", - "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "node_modules/jest-circus/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, - "license": "MIT", "dependencies": { - "@jest/core": "^29.7.0", - "@jest/test-result": "^29.7.0", - "@jest/types": "^29.6.3", - "chalk": "^4.0.0", - "create-jest": "^29.7.0", - "exit": "^0.1.2", - "import-local": "^3.0.2", - "jest-config": "^29.7.0", - "jest-util": "^29.7.0", - "jest-validate": "^29.7.0", - "yargs": "^17.3.1" - }, - "bin": { - "jest": "bin/jest.js" + "yocto-queue": "^0.1.0" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - }, - "peerDependencies": { - "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + "node": ">=10" }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/jest-config": { @@ -5416,7 +5345,6 @@ "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.7.0.tgz", "integrity": "sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==", "dev": true, - "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@jest/test-sequencer": "^29.7.0", @@ -5457,12 +5385,44 @@ } } }, + "node_modules/jest-config/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/jest-config/node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/jest-diff": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", "dev": true, - "license": "MIT", "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.6.3", @@ -5478,7 +5438,6 @@ "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.7.0.tgz", "integrity": "sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==", "dev": true, - "license": "MIT", "dependencies": { "detect-newline": "^3.0.0" }, @@ -5491,7 +5450,6 @@ "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.7.0.tgz", "integrity": "sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "chalk": "^4.0.0", @@ -5508,7 +5466,6 @@ "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.7.0.tgz", "integrity": "sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", @@ -5526,7 +5483,6 @@ "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", "dev": true, - "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -5536,7 +5492,6 @@ "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.7.0.tgz", "integrity": "sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/graceful-fs": "^4.1.3", @@ -5562,7 +5517,6 @@ "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz", "integrity": "sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==", "dev": true, - "license": "MIT", "dependencies": { "jest-get-type": "^29.6.3", "pretty-format": "^29.7.0" @@ -5576,7 +5530,6 @@ "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", "dev": true, - "license": "MIT", "dependencies": { "chalk": "^4.0.0", "jest-diff": "^29.7.0", @@ -5592,7 +5545,6 @@ "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", "dev": true, - "license": "MIT", "dependencies": { "@babel/code-frame": "^7.12.13", "@jest/types": "^29.6.3", @@ -5608,26 +5560,11 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/jest-message-util/node_modules/@babel/code-frame": { - "version": "7.24.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", - "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/highlight": "^7.24.2", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/jest-mock": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.7.0.tgz", "integrity": "sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -5642,7 +5579,6 @@ "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" }, @@ -5660,7 +5596,6 @@ "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.6.3.tgz", "integrity": "sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==", "dev": true, - "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -5670,7 +5605,6 @@ "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz", "integrity": "sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==", "dev": true, - "license": "MIT", "dependencies": { "chalk": "^4.0.0", "graceful-fs": "^4.2.9", @@ -5691,7 +5625,6 @@ "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz", "integrity": "sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==", "dev": true, - "license": "MIT", "dependencies": { "jest-regex-util": "^29.6.3", "jest-snapshot": "^29.7.0" @@ -5705,7 +5638,6 @@ "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.7.0.tgz", "integrity": "sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/console": "^29.7.0", "@jest/environment": "^29.7.0", @@ -5733,12 +5665,26 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-runner/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/jest-runtime": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.7.0.tgz", "integrity": "sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", @@ -5767,12 +5713,32 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-runtime/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/jest-snapshot": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.7.0.tgz", "integrity": "sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==", "dev": true, - "license": "MIT", "dependencies": { "@babel/core": "^7.11.6", "@babel/generator": "^7.7.2", @@ -5799,12 +5765,23 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/jest-util": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "@types/node": "*", @@ -5822,7 +5799,6 @@ "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", "dev": true, - "license": "MIT", "dependencies": { "@jest/types": "^29.6.3", "camelcase": "^6.2.0", @@ -5840,7 +5816,6 @@ "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -5853,7 +5828,6 @@ "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.7.0.tgz", "integrity": "sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==", "dev": true, - "license": "MIT", "dependencies": { "@jest/test-result": "^29.7.0", "@jest/types": "^29.6.3", @@ -5873,7 +5847,6 @@ "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "dev": true, - "license": "MIT", "dependencies": { "@types/node": "*", "jest-util": "^29.7.0", @@ -5889,7 +5862,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -5900,19 +5872,50 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jest/node_modules/jest-cli": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.7.0.tgz", + "integrity": "sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==", + "dev": true, + "dependencies": { + "@jest/core": "^29.7.0", + "@jest/test-result": "^29.7.0", + "@jest/types": "^29.6.3", + "chalk": "^4.0.0", + "create-jest": "^29.7.0", + "exit": "^0.1.2", + "import-local": "^3.0.2", + "jest-config": "^29.7.0", + "jest-util": "^29.7.0", + "jest-validate": "^29.7.0", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/js-yaml": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, - "license": "MIT", "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -5921,18 +5924,29 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsbn": { + "node_modules/js-yaml/node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/jsbn": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "license": "MIT" + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true, - "license": "MIT", "bin": { "jsesc": "bin/jsesc" }, @@ -5944,15 +5958,13 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/json-schema-traverse": { "version": "1.0.0", @@ -5963,15 +5975,13 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, - "license": "MIT", "bin": { "json5": "lib/cli.js" }, @@ -5983,30 +5993,16 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/jsonpath/-/jsonpath-1.1.1.tgz", "integrity": "sha512-l6Cg7jRpixfbgoWgkrl77dgEj8RPvND0wMH6TwQmi9Qs4TFfS9u5cUFnbeKTwj5ga5Y3BTGGNI28k117LJ009w==", - "license": "MIT", "dependencies": { "esprima": "1.2.2", "static-eval": "2.0.2", "underscore": "1.12.1" } }, - "node_modules/jsonpath/node_modules/esprima": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz", - "integrity": "sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A==", - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/jszip": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", - "license": "(MIT OR GPL-3.0-or-later)", "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", @@ -6018,7 +6014,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/kafka-node/-/kafka-node-5.0.0.tgz", "integrity": "sha512-dD2ga5gLcQhsq1yNoQdy1MU4x4z7YnXM5bcG9SdQuiNr5KKuAmXixH1Mggwdah5o7EfholFbcNDPSVA6BIfaug==", - "license": "MIT", "dependencies": { "async": "^2.6.2", "binary": "~0.3.0", @@ -6045,7 +6040,7 @@ "version": "3.4.0", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "license": "MIT", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", "bin": { "uuid": "bin/uuid" } @@ -6055,7 +6050,6 @@ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, - "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -6065,7 +6059,6 @@ "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -6073,8 +6066,7 @@ "node_modules/kuler": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==", - "license": "MIT" + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" }, "node_modules/lazystream": { "version": "1.0.1", @@ -6092,20 +6084,17 @@ "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" }, "engines": { "node": ">= 0.8.0" @@ -6115,7 +6104,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", - "license": "MIT", "dependencies": { "immediate": "~3.0.5" } @@ -6124,8 +6112,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/listenercount": { "version": "1.0.1", @@ -6137,7 +6124,6 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, - "license": "MIT", "dependencies": { "p-locate": "^4.1.0" }, @@ -6148,8 +6134,7 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, "node_modules/lodash.defaults": { "version": "4.2.0", @@ -6176,6 +6161,11 @@ "resolved": "https://registry.npmjs.org/lodash.groupby/-/lodash.groupby-4.6.0.tgz", "integrity": "sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw==" }, + "node_modules/lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==" + }, "node_modules/lodash.isboolean": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", @@ -6210,8 +6200,7 @@ "version": "4.4.2", "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/lodash.union": { "version": "4.6.0", @@ -6227,7 +6216,6 @@ "version": "2.6.0", "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", - "license": "MIT", "dependencies": { "@colors/colors": "1.6.0", "@types/triple-beam": "^1.3.2", @@ -6243,26 +6231,22 @@ "node_modules/logform/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/long": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/long/-/long-1.1.2.tgz", "integrity": "sha512-pjR3OP1X2VVQhCQlrq3s8UxugQsuoucwMOn9Yj/kN/61HMc+lDFJS5bvpNEHneZ9NVaSm8gNWxZvtGS7lqHb3Q==", - "license": "Apache-2.0", "engines": { "node": ">=0.6" } }, "node_modules/lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "engines": { + "node": "14 || >=16.14" } }, "node_modules/make-dir": { @@ -6270,7 +6254,6 @@ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, - "license": "MIT", "dependencies": { "semver": "^7.5.3" }, @@ -6281,18 +6264,28 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-dir/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "license": "ISC" + "dev": true }, "node_modules/make-fetch-happen": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", - "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", - "license": "ISC", + "version": "13.0.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz", + "integrity": "sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA==", "dependencies": { "@npmcli/agent": "^2.0.0", "cacache": "^18.0.0", @@ -6303,6 +6296,7 @@ "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", "negotiator": "^0.6.3", + "proc-log": "^4.2.0", "promise-retry": "^2.0.1", "ssri": "^10.0.0" }, @@ -6310,12 +6304,19 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/make-fetch-happen/node_modules/proc-log": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz", + "integrity": "sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "tmpl": "1.0.5" } @@ -6324,7 +6325,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6332,21 +6332,18 @@ "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "license": "MIT" + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" }, "node_modules/merge-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6355,7 +6352,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "license": "MIT", "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -6368,7 +6364,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", "bin": { "mime": "cli.js" }, @@ -6380,7 +6375,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6389,7 +6383,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "license": "MIT", "dependencies": { "mime-db": "1.52.0" }, @@ -6402,7 +6395,6 @@ "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -6411,7 +6403,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", - "license": "MIT", "optional": true, "engines": { "node": ">=4" @@ -6421,7 +6412,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -6433,16 +6423,14 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "license": "ISC", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "engines": { "node": ">=16 || 14 >=14.17" } @@ -6451,7 +6439,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", - "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, @@ -6460,10 +6447,9 @@ } }, "node_modules/minipass-fetch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", - "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", - "license": "MIT", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz", + "integrity": "sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg==", "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", @@ -6480,7 +6466,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -6492,7 +6477,6 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -6500,17 +6484,10 @@ "node": ">=8" } }, - "node_modules/minipass-flush/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/minipass-pipeline": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -6522,7 +6499,6 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -6530,17 +6506,10 @@ "node": ">=8" } }, - "node_modules/minipass-pipeline/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/minipass-sized": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -6552,7 +6521,6 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -6560,17 +6528,10 @@ "node": ">=8" } }, - "node_modules/minipass-sized/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "license": "MIT", "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -6583,7 +6544,6 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -6591,17 +6551,10 @@ "node": ">=8" } }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/mkdirp": { "version": "0.5.6", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "license": "MIT", "dependencies": { "minimist": "^1.2.6" }, @@ -6613,7 +6566,6 @@ "version": "1.10.0", "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", - "license": "MIT", "dependencies": { "basic-auth": "~2.0.1", "debug": "2.6.9", @@ -6629,7 +6581,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", - "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -6640,35 +6591,30 @@ "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/nan": { "version": "2.19.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz", "integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==", - "license": "MIT", "optional": true }, "node_modules/napi-build-utils": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "license": "MIT", "optional": true }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/negotiator": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -6676,34 +6622,21 @@ "node_modules/nested-error-stacks": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz", - "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==", - "license": "MIT" + "integrity": "sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==" }, "node_modules/node-abi": { "version": "2.30.1", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz", "integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==", - "license": "MIT", "optional": true, "dependencies": { "semver": "^5.4.1" } }, - "node_modules/node-abi/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "license": "ISC", - "optional": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/node-cache": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/node-cache/-/node-cache-5.1.2.tgz", "integrity": "sha512-t1QzWwnk4sjLWaQAS8CHgOJ+RAfmHpxFWmc36IWTiWHQfs0w5JDMBS1b1ZxQteo0vVVuWJvIUKHDkkeK7vIGCg==", - "license": "MIT", "dependencies": { "clone": "2.x" }, @@ -6734,101 +6667,38 @@ "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/node-gyp/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/node-gyp/node_modules/glob": { - "version": "10.3.12", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", - "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.10.2" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/node-gyp/node_modules/isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", - "license": "ISC", - "engines": { - "node": ">=16" - } - }, - "node_modules/node-gyp/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/node-gyp/node_modules/which": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", - "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" - }, + "node_modules/node-gyp/node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "bin": { - "node-which": "bin/which.js" + "semver": "bin/semver.js" }, "engines": { - "node": "^16.13.0 || >=18.0.0" + "node": ">=10" } }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", - "license": "MIT" + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==" }, "node_modules/node-releases": { "version": "2.0.14", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/noop-logger": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz", "integrity": "sha512-6kM8CLXvuW5crTxsAtva2YLrRrDaiTIkIePWs9moLHqbFWT94WpNFjwS/5dfLfECg5i/lkmw3aoqVidxt23TEQ==", - "license": "MIT", "optional": true }, "node_modules/nopt": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", - "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", - "license": "ISC", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz", + "integrity": "sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==", "dependencies": { "abbrev": "^2.0.0" }, @@ -6843,7 +6713,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -6853,7 +6722,6 @@ "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, - "license": "MIT", "dependencies": { "path-key": "^3.0.0" }, @@ -6865,7 +6733,7 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "license": "ISC", + "deprecated": "This package is no longer supported.", "optional": true, "dependencies": { "are-we-there-yet": "~1.1.2", @@ -6878,7 +6746,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", - "license": "MIT", "optional": true, "engines": { "node": ">=0.10.0" @@ -6888,7 +6755,6 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", "optional": true, "engines": { "node": ">=0.10.0" @@ -6898,7 +6764,6 @@ "version": "1.13.1", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", - "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -6907,14 +6772,12 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -6926,7 +6789,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -6935,7 +6797,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", "dependencies": { "wrappy": "1" } @@ -6944,7 +6805,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", - "license": "MIT", "dependencies": { "fn.name": "1.x.x" } @@ -6954,7 +6814,6 @@ "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, - "license": "MIT", "dependencies": { "mimic-fn": "^2.1.0" }, @@ -6976,22 +6835,19 @@ "node_modules/optional": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/optional/-/optional-0.1.4.tgz", - "integrity": "sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw==", - "license": "MIT" + "integrity": "sha512-gtvrrCfkE08wKcgXaVwQVgwEQ8vel2dc5DDBn9RLQZ3YtmtkBss6A2HY6BnJH4N/4Ku97Ri/SF8sNWE2225WJw==" }, "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, - "license": "MIT", + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" }, "engines": { "node": ">= 0.8.0" @@ -7001,23 +6857,21 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", - "license": "MIT", "optional": true, "engines": { "node": ">=0.10.0" } }, "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, - "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" + "p-try": "^2.0.0" }, "engines": { - "node": ">=10" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -7028,7 +6882,6 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, - "license": "MIT", "dependencies": { "p-limit": "^2.2.0" }, @@ -7036,27 +6889,10 @@ "node": ">=8" } }, - "node_modules/p-locate/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-map": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "license": "MIT", "dependencies": { "aggregate-error": "^3.0.0" }, @@ -7072,7 +6908,6 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -7080,8 +6915,7 @@ "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "license": "(MIT AND Zlib)" + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" }, "node_modules/parent-module": { "version": "1.0.1", @@ -7100,7 +6934,6 @@ "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, - "license": "MIT", "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -7118,7 +6951,6 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -7128,7 +6960,6 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -7137,7 +6968,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7146,7 +6976,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", "engines": { "node": ">=8" } @@ -7155,39 +6984,27 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/path-scurry": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", - "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", - "license": "BlueOak-1.0.0", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=16 || 14 >=14.18" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", - "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", - "license": "ISC", - "engines": { - "node": "14 || >=16.14" - } - }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "license": "MIT" + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, "node_modules/pg": { "version": "8.12.0", @@ -7221,22 +7038,19 @@ "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz", "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", "dev": true, - "license": "MIT", "optional": true }, "node_modules/pg-connection-string": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.4.tgz", "integrity": "sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/pg-int8": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", "dev": true, - "license": "ISC", "engines": { "node": ">=4.0.0" } @@ -7246,7 +7060,6 @@ "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==", "dev": true, - "license": "ISC", "engines": { "node": ">=4" } @@ -7256,7 +7069,6 @@ "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.2.tgz", "integrity": "sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==", "dev": true, - "license": "MIT", "peerDependencies": { "pg": ">=8.0" } @@ -7265,15 +7077,13 @@ "version": "1.6.1", "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.1.tgz", "integrity": "sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/pg-types": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.2.tgz", "integrity": "sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==", "dev": true, - "license": "MIT", "dependencies": { "pg-int8": "1.0.1", "pg-numeric": "1.0.2", @@ -7292,7 +7102,6 @@ "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", "dev": true, - "license": "MIT", "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", @@ -7309,7 +7118,6 @@ "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } @@ -7319,7 +7127,6 @@ "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7329,7 +7136,6 @@ "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7339,7 +7145,6 @@ "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", "dev": true, - "license": "MIT", "dependencies": { "xtend": "^4.0.0" }, @@ -7352,23 +7157,20 @@ "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", "dev": true, - "license": "MIT", "dependencies": { "split2": "^4.1.0" } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true, - "license": "ISC" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true }, "node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "license": "MIT", "engines": { "node": ">=8.6" }, @@ -7381,7 +7183,6 @@ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", "dev": true, - "license": "MIT", "engines": { "node": ">= 6" } @@ -7391,7 +7192,6 @@ "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, - "license": "MIT", "dependencies": { "find-up": "^4.0.0" }, @@ -7404,7 +7204,6 @@ "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.2.tgz", "integrity": "sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" } @@ -7414,7 +7213,6 @@ "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", "dev": true, - "license": "MIT", "dependencies": { "obuf": "~1.1.2" }, @@ -7427,7 +7225,6 @@ "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz", "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" } @@ -7437,7 +7234,6 @@ "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==", "dev": true, - "license": "MIT", "engines": { "node": ">=12" } @@ -7446,14 +7242,12 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.4.tgz", "integrity": "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/prebuild-install": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.0.tgz", "integrity": "sha512-aaLVANlj4HgZweKttFNUVNRxDukytuIuxeK2boIMHjagNJCiVKWFsKF4tCE3ql3GbrD2tExPQ7/pwtEJcHNZeg==", - "license": "MIT", "optional": true, "dependencies": { "detect-libc": "^1.0.3", @@ -7481,11 +7275,9 @@ } }, "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", "engines": { "node": ">= 0.8.0" } @@ -7495,7 +7287,6 @@ "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, - "license": "MIT", "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -7510,7 +7301,6 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -7522,7 +7312,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", - "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } @@ -7538,15 +7327,13 @@ "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "license": "MIT" + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" }, "node_modules/progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -7567,7 +7354,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "license": "MIT", "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -7580,7 +7366,6 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "license": "MIT", "engines": { "node": ">= 4" } @@ -7590,7 +7375,6 @@ "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", "dev": true, - "license": "MIT", "dependencies": { "kleur": "^3.0.3", "sisteransi": "^1.0.5" @@ -7602,14 +7386,12 @@ "node_modules/property-expr": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", - "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==", - "license": "MIT" + "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==" }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" @@ -7621,14 +7403,12 @@ "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "node_modules/pump": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "license": "MIT", "optional": true, "dependencies": { "end-of-stream": "^1.1.0", @@ -7639,7 +7419,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "license": "MIT", "engines": { "node": ">=6" } @@ -7658,14 +7437,12 @@ "type": "opencollective", "url": "https://opencollective.com/fast-check" } - ], - "license": "MIT" + ] }, "node_modules/qs": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.4" }, @@ -7680,7 +7457,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -7689,7 +7465,6 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -7704,7 +7479,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", "optional": true, "dependencies": { "deep-extend": "^0.6.0", @@ -7716,28 +7490,16 @@ "rc": "cli.js" } }, - "node_modules/rc/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", - "dev": true, - "license": "MIT" + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true }, "node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", - "license": "MIT", "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -7780,7 +7542,6 @@ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, - "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, @@ -7788,12 +7549,30 @@ "node": ">=8.10.0" } }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A==", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/regexpp": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" }, @@ -7806,7 +7585,6 @@ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7815,7 +7593,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7830,7 +7607,6 @@ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, - "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", "path-parse": "^1.0.7", @@ -7848,7 +7624,6 @@ "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, - "license": "MIT", "dependencies": { "resolve-from": "^5.0.0" }, @@ -7861,7 +7636,6 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -7880,7 +7654,6 @@ "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" } @@ -7889,7 +7662,6 @@ "version": "0.10.1", "resolved": "https://registry.npmjs.org/retry/-/retry-0.10.1.tgz", "integrity": "sha512-ZXUSQYTHdl3uS7IuCehYfMzKyIDBNoAuUblvy5oGO5UJSUTmStUUVPXbA9Qxd173Bgre53yCQczQuHgRWAdvJQ==", - "license": "MIT", "engines": { "node": "*" } @@ -7898,8 +7670,8 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, - "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -7910,17 +7682,36 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "license": "MIT" + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/safe-stable-stringify": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", - "license": "MIT", "engines": { "node": ">=10" } @@ -7928,14 +7719,12 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, "node_modules/sax": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", - "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", - "license": "ISC" + "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==" }, "node_modules/saxes": { "version": "5.0.1", @@ -7949,43 +7738,18 @@ } }, "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "optional": true, "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" + "semver": "bin/semver" } }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "license": "MIT", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -8008,14 +7772,12 @@ "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/serve-static": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "license": "MIT", "dependencies": { "encodeurl": "~1.0.2", "escape-html": "~1.0.3", @@ -8030,14 +7792,12 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "license": "ISC", "optional": true }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -8053,20 +7813,17 @@ "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "license": "MIT" + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -8078,7 +7835,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", "engines": { "node": ">=8" } @@ -8087,7 +7843,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "license": "MIT", "dependencies": { "call-bind": "^1.0.7", "es-errors": "^1.3.0", @@ -8105,8 +7860,7 @@ "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "devOptional": true, - "license": "ISC" + "devOptional": true }, "node_modules/simple-concat": { "version": "1.0.1", @@ -8126,14 +7880,12 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "optional": true }, "node_modules/simple-get": { "version": "2.8.2", "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-2.8.2.tgz", "integrity": "sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw==", - "license": "MIT", "optional": true, "dependencies": { "decompress-response": "^3.3.0", @@ -8145,30 +7897,21 @@ "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "license": "MIT", "dependencies": { "is-arrayish": "^0.3.1" } }, - "node_modules/simple-swizzle/node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", - "license": "MIT" - }, "node_modules/sisteransi": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -8178,7 +7921,6 @@ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", @@ -8191,12 +7933,26 @@ "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -8205,7 +7961,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "license": "MIT", "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" @@ -8216,7 +7971,6 @@ "resolved": "https://registry.npmjs.org/snappy/-/snappy-6.3.5.tgz", "integrity": "sha512-lonrUtdp1b1uDn1dbwgQbBsb5BbaiLeKq+AGwOk2No+en+VvJThwmtztwulEQsLinRF681pBqib0NUZaizKLIA==", "hasInstallScript": true, - "license": "MIT", "optional": true, "dependencies": { "bindings": "^1.3.1", @@ -8225,10 +7979,9 @@ } }, "node_modules/socks": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz", - "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==", - "license": "MIT", + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", "dependencies": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" @@ -8242,7 +7995,6 @@ "version": "8.0.3", "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.3.tgz", "integrity": "sha512-VNegTZKhuGq5vSD6XNKlbqWhyt/40CgoEw8XxD6dhnm8Jq9IEa3nIa4HwnM8XOqU0CdB0BwWVXusqiFXfHB3+A==", - "license": "MIT", "dependencies": { "agent-base": "^7.1.1", "debug": "^4.3.4", @@ -8253,10 +8005,9 @@ } }, "node_modules/socks-proxy-agent/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "license": "MIT", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", "dependencies": { "ms": "2.1.2" }, @@ -8272,15 +8023,13 @@ "node_modules/socks-proxy-agent/node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "license": "MIT" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "devOptional": true, - "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } @@ -8290,7 +8039,6 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, - "license": "MIT", "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" @@ -8301,23 +8049,19 @@ "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", "dev": true, - "license": "ISC", "engines": { "node": ">= 10.x" } }, "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true, - "license": "BSD-3-Clause" + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" }, "node_modules/ssf": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz", "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==", - "license": "Apache-2.0", "dependencies": { "frac": "~1.1.2" }, @@ -8326,10 +8070,9 @@ } }, "node_modules/ssri": { - "version": "10.0.5", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", - "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", - "license": "ISC", + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz", + "integrity": "sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ==", "dependencies": { "minipass": "^7.0.3" }, @@ -8341,7 +8084,6 @@ "version": "0.0.10", "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "license": "MIT", "engines": { "node": "*" } @@ -8351,7 +8093,6 @@ "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", "dev": true, - "license": "MIT", "dependencies": { "escape-string-regexp": "^2.0.0" }, @@ -8364,16 +8105,19 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/standard-as-callback": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz", + "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A==" + }, "node_modules/static-eval": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/static-eval/-/static-eval-2.0.2.tgz", "integrity": "sha512-N/D219Hcr2bPjLxPiV+TQE++Tsmrady7TqAJugLy7Xk1EumfDWS/f5dtBbkRCGE7wKKXuYockQoj8Rm2/pVKyg==", - "license": "MIT", "dependencies": { "escodegen": "^1.8.1" } @@ -8382,7 +8126,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -8391,7 +8134,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "license": "MIT", "dependencies": { "safe-buffer": "~5.1.0" } @@ -8401,7 +8143,6 @@ "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", "dev": true, - "license": "MIT", "dependencies": { "char-regex": "^1.0.2", "strip-ansi": "^6.0.0" @@ -8410,6 +8151,27 @@ "node": ">=10" } }, + "node_modules/string-length/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/string-template": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", @@ -8419,7 +8181,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", "integrity": "sha512-0XsVpQLnVCXHJfyEs8tC0zpTVIr5PKKsQtkT29IwupnPTjtPmQ3xT/4yCREF9hYkV/3M3kzcUTSAZT6a6h81tw==", - "license": "MIT", "optional": true, "dependencies": { "code-point-at": "^1.0.0", @@ -8435,40 +8196,48 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" - }, + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "engines": { "node": ">=8" } }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, "node_modules/string-width-cjs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "license": "MIT", - "optional": true, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/string-width/node_modules/strip-ansi": { + "node_modules/strip-ansi": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "license": "MIT", "optional": true, "dependencies": { "ansi-regex": "^2.0.0" @@ -8477,27 +8246,19 @@ "node": ">=0.10.0" } }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" - }, + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "engines": { "node": ">=8" } @@ -8507,7 +8268,6 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -8517,22 +8277,17 @@ "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" } }, "node_modules/supports-color": { @@ -8540,7 +8295,6 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, @@ -8553,7 +8307,6 @@ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, - "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -8566,7 +8319,6 @@ "resolved": "https://registry.npmjs.org/table/-/table-6.8.2.tgz", "integrity": "sha512-w2sfv80nrAh2VCbqR5AK27wswXhqcck2AhfnNW76beQXskGZ1V12GwS//yYVa3d3fcvAip2OUnbDAjW2k3v9fA==", "dev": true, - "license": "BSD-3-Clause", "dependencies": { "ajv": "^8.0.1", "lodash.truncate": "^4.4.2", @@ -8578,12 +8330,26 @@ "node": ">=10.0.0" } }, + "node_modules/table/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "node_modules/table/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -8593,7 +8359,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -8603,11 +8368,22 @@ "node": ">=8" } }, + "node_modules/table/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tar": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "license": "ISC", "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -8624,7 +8400,6 @@ "version": "1.16.3", "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz", "integrity": "sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw==", - "license": "MIT", "optional": true, "dependencies": { "chownr": "^1.0.1", @@ -8633,18 +8408,10 @@ "tar-stream": "^1.1.2" } }, - "node_modules/tar-fs/node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "license": "ISC", - "optional": true - }, "node_modules/tar-fs/node_modules/pump": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz", "integrity": "sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw==", - "license": "MIT", "optional": true, "dependencies": { "end-of-stream": "^1.1.0", @@ -8655,7 +8422,6 @@ "version": "1.6.2", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", - "license": "MIT", "optional": true, "dependencies": { "bl": "^1.0.0", @@ -8674,18 +8440,24 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.3.tgz", "integrity": "sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==", - "license": "MIT", "optional": true, "dependencies": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" } }, + "node_modules/tar/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, "node_modules/tar/node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "license": "ISC", "dependencies": { "minipass": "^3.0.0" }, @@ -8697,7 +8469,6 @@ "version": "3.3.6", "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", "dependencies": { "yallist": "^4.0.0" }, @@ -8709,7 +8480,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "license": "ISC", "engines": { "node": ">=8" } @@ -8718,7 +8488,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -8726,12 +8495,6 @@ "node": ">=10" } }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/tdigest": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz", @@ -8746,7 +8509,6 @@ "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", "dev": true, - "license": "ISC", "dependencies": { "@istanbuljs/schema": "^0.1.2", "glob": "^7.1.4", @@ -8756,18 +8518,37 @@ "node": ">=8" } }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", - "license": "MIT" + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/thriftrw": { "version": "3.11.4", @@ -8796,8 +8577,7 @@ "node_modules/tiny-case": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz", - "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==", - "license": "MIT" + "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==" }, "node_modules/tmp": { "version": "0.2.3", @@ -8811,14 +8591,12 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", - "dev": true, - "license": "BSD-3-Clause" + "dev": true }, "node_modules/to-buffer": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", - "license": "MIT", "optional": true }, "node_modules/to-fast-properties": { @@ -8826,7 +8604,6 @@ "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } @@ -8835,7 +8612,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -8847,7 +8623,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", "engines": { "node": ">=0.6" } @@ -8855,21 +8630,21 @@ "node_modules/toposort": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz", - "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==", - "license": "MIT" + "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==" }, "node_modules/traverse": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", "integrity": "sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==", - "license": "MIT/X11" + "engines": { + "node": "*" + } }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true, - "license": "MIT", "bin": { "tree-kill": "cli.js" } @@ -8878,7 +8653,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", - "license": "MIT", "engines": { "node": ">= 14.0.0" } @@ -8888,7 +8662,6 @@ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, - "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -8932,7 +8705,6 @@ "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz", "integrity": "sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==", "dev": true, - "license": "MIT", "dependencies": { "chokidar": "^3.5.1", "dynamic-dedupe": "^0.3.0", @@ -8962,12 +8734,32 @@ } } }, + "node_modules/ts-node-dev/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/ts-node-dev/node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "dev": true, - "license": "MIT", "bin": { "mkdirp": "bin/cmd.js" }, @@ -8979,8 +8771,8 @@ "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, - "license": "ISC", "dependencies": { "glob": "^7.1.3" }, @@ -8993,7 +8785,6 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, - "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -9006,7 +8797,6 @@ "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", "dev": true, - "license": "MIT", "dependencies": { "@types/strip-bom": "^3.0.0", "@types/strip-json-comments": "0.0.30", @@ -9019,26 +8809,14 @@ "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/tsconfig/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "license": "Apache-2.0", "optional": true, "dependencies": { "safe-buffer": "^5.0.1" @@ -9048,13 +8826,11 @@ } }, "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", "dependencies": { - "prelude-ls": "^1.2.1" + "prelude-ls": "~1.1.2" }, "engines": { "node": ">= 0.8.0" @@ -9065,25 +8841,25 @@ "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", "dev": true, - "license": "MIT", "engines": { "node": ">=4" } }, "node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", "engines": { - "node": ">=8" + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -9097,7 +8873,6 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", "dev": true, - "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9109,20 +8884,17 @@ "node_modules/underscore": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", - "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==", - "license": "MIT" + "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "license": "MIT" + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "node_modules/unique-filename": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", - "license": "ISC", "dependencies": { "unique-slug": "^4.0.0" }, @@ -9134,7 +8906,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", - "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" }, @@ -9146,7 +8917,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -9169,9 +8939,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz", + "integrity": "sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ==", "dev": true, "funding": [ { @@ -9187,10 +8957,9 @@ "url": "https://github.com/sponsors/ai" } ], - "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.1.2", + "picocolors": "^1.0.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -9203,7 +8972,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } @@ -9211,14 +8979,12 @@ "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", - "license": "MIT", "engines": { "node": ">= 0.4.0" } @@ -9231,7 +8997,6 @@ "https://github.com/sponsors/broofa", "https://github.com/sponsors/ctavan" ], - "license": "MIT", "bin": { "uuid": "dist/bin/uuid" } @@ -9240,22 +9005,19 @@ "version": "2.4.0", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/v8-to-istanbul": { "version": "9.2.0", "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz", "integrity": "sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==", "dev": true, - "license": "ISC", "dependencies": { "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", @@ -9269,7 +9031,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -9279,41 +9040,45 @@ "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", "dev": true, - "license": "Apache-2.0", "dependencies": { "makeerror": "1.0.12" } }, "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", "dependencies": { - "isexe": "^2.0.0" + "isexe": "^3.1.1" }, "bin": { - "node-which": "bin/node-which" + "node-which": "bin/which.js" }, "engines": { - "node": ">= 8" + "node": "^16.13.0 || >=18.0.0" } }, "node_modules/which-pm-runs": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.1.0.tgz", "integrity": "sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA==", - "license": "MIT", "optional": true, "engines": { "node": ">=4" } }, + "node_modules/which/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "engines": { + "node": ">=16" + } + }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "license": "ISC", "optional": true, "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" @@ -9323,7 +9088,6 @@ "version": "3.12.0", "resolved": "https://registry.npmjs.org/winston/-/winston-3.12.0.tgz", "integrity": "sha512-OwbxKaOlESDi01mC9rkM0dQqQt2I8DAUMRLZ/HpbwvDXm85IryEHgoogy5fziQy38PntgZsLlhAYHz//UPHZ5w==", - "license": "MIT", "dependencies": { "@colors/colors": "^1.6.0", "@dabh/diagnostics": "^2.0.2", @@ -9345,7 +9109,6 @@ "version": "4.7.0", "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz", "integrity": "sha512-ajBj65K5I7denzer2IYW6+2bNIVqLGDHqDw3Ow8Ohh+vdW+rv4MZ6eiDvHoKhfJFZ2auyN8byXieDDJ96ViONg==", - "license": "MIT", "dependencies": { "logform": "^2.3.2", "readable-stream": "^3.6.0", @@ -9359,7 +9122,6 @@ "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -9372,14 +9134,12 @@ "node_modules/winston/node_modules/async": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "license": "MIT" + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" }, "node_modules/winston/node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -9393,7 +9153,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz", "integrity": "sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw==", - "license": "Apache-2.0", "engines": { "node": ">=0.8" } @@ -9402,7 +9161,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/word/-/word-0.3.0.tgz", "integrity": "sha512-OELeY0Q61OXpdUfTp+oweA/vtLVg5VDOXh+3he3PNzLGG/y0oylSOC1xRVj0+l4vQ3tj/bB1HVHv1ocXkQceFA==", - "license": "Apache-2.0", "engines": { "node": ">=0.8" } @@ -9411,24 +9169,21 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" @@ -9439,24 +9194,43 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=8" }, "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, "node_modules/wrap-ansi-cjs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", "engines": { "node": ">=8" } @@ -9465,7 +9239,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -9475,43 +9248,68 @@ "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, "engines": { "node": ">=8" } }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, "node_modules/wrap-ansi/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/write-file-atomic": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "dev": true, - "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" @@ -9544,7 +9342,6 @@ "version": "1.21.0", "resolved": "https://registry.npmjs.org/xlsx-populate/-/xlsx-populate-1.21.0.tgz", "integrity": "sha512-8v2Gm8BehXo6LU7KT802QoXTPkYY1SKk5V8g/UuYZnNB3JzXqud/P99Pxr2yXeKyt+sKlCatmidz6jQNie1hRw==", - "license": "MIT", "dependencies": { "cfb": "^1.1.3", "jszip": "^3.2.2", @@ -9566,7 +9363,6 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", "engines": { "node": ">=0.4" } @@ -9576,24 +9372,20 @@ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, - "license": "ISC", "engines": { "node": ">=10" } }, "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true, - "license": "ISC" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, - "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -9612,17 +9404,30 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, - "license": "ISC", "engines": { "node": ">=12" } }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, "node_modules/yargs/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "license": "MIT", "engines": { "node": ">=8" } @@ -9632,7 +9437,6 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, - "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -9642,12 +9446,23 @@ "node": ">=8" } }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/yn": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=6" } @@ -9657,7 +9472,6 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, - "license": "MIT", "engines": { "node": ">=10" }, @@ -9669,7 +9483,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/yup/-/yup-1.4.0.tgz", "integrity": "sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg==", - "license": "MIT", "dependencies": { "property-expr": "^2.0.5", "tiny-case": "^1.0.3", @@ -9677,18 +9490,6 @@ "type-fest": "^2.19.0" } }, - "node_modules/yup/node_modules/type-fest": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", - "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/zip-stream": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.1.tgz", @@ -9722,6 +9523,26 @@ "node": ">= 10" } }, + "node_modules/zip-stream/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/zip-stream/node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", diff --git a/health-services/project-factory/package.json b/health-services/project-factory/package.json index a91771378fa..31dd40bc152 100644 --- a/health-services/project-factory/package.json +++ b/health-services/project-factory/package.json @@ -1,6 +1,6 @@ { "name": "project-factory", - "version": "0.1.0", + "version": "0.2.0", "main": "src/server/index.ts", "author": "Jagankumar ", "description": "Backend For Frontend service", @@ -54,6 +54,7 @@ "@types/http-proxy-middleware": "^1.0.0", "@types/jaeger-client": "^3.18.7", "@types/jest": "29.5.12", + "@types/lodash": "^4.17.5", "@types/morgan": "1.9.9", "@types/node": "20.11.29", "@types/pg": "8.11.3", diff --git a/health-services/project-factory/postman_collection.json b/health-services/project-factory/postman_collection.json index 5780448766a..d99524df3c1 100644 --- a/health-services/project-factory/postman_collection.json +++ b/health-services/project-factory/postman_collection.json @@ -1,18 +1,13 @@ { "info": { - "_postman_id": "4faeccce-fc50-4dfb-8fef-d973aca136c4", - "name": "Project factory", + "_postman_id": "42be4494-a788-4977-b8f2-e14894cce42b", + "name": "Project-Factory Collection", "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "18845214" + "_exporter_id": "28207698" }, "item": [ { - "name": "facility data generate(template generate)", - "protocolProfileBehavior": { - "disabledSystemHeaders": { - "content-type": true - } - }, + "name": "campain-manage-create Copy", "request": { "method": "POST", "header": [ @@ -30,8 +25,7 @@ }, { "key": "content-type", - "value": "application/json", - "disabled": true + "value": "application/json" }, { "key": "cookie", @@ -72,65 +66,37 @@ { "key": "user-agent", "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" - }, - { - "key": "Content-Type", - "value": "application/json", - "type": "text" } ], "body": { "mode": "raw", - "raw": "{\n \"RequestInfo\":{\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"b902a184-4582-41f8-8144-99930548631d\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1716457221446|en_MZ\",\n \"plainAccessRequest\": {}\n}\n}" + "raw": "{\n // 43cfaf3f-f31f-492f-afeb-cebe4f4301e8\n // d71a1963-27a8-4300-a1c4-2ec99e95331b multiplesheet\n // 6c091ddb-523e-4afd-8a81-afe94196d080 without matching sheetName\n // for unifieddev\n // 1d27af7d-3736-408d-b9bc-796c92fd5f4b multiplesheet\n \"Campaign\": {\n // \"id\": \"string\",\n // \"campaignNo\": \"string\",\n \"hierarchyType\": \"string\",\n \"tenantId\": \"mz\",\n \"campaignName\": \"string\",\n \"boundaryCode\": \"mz\",\n \"startDate\": 1677594987,\n // \"endDate\": 9776881655,\n \"endDate\": 1677594987,\n \"projectType\": \"Household Based Project\",\n \"CampaignDetails\": [\n {\n \"boundaryCode\": \"f5F6xAskA05\",\n \"boundaryType\": \"Provincia\",\n \"startDate\": 1665497225000,\n \"endDate\": 1666497225000,\n \"targets\": [\n {\n \"total\": 300,\n \"target\": 250,\n \"type\": \"household|individual\"\n }\n ],\n \"description\": \"test\",\n \"department\": \"test\",\n \"referenceID\": \" 3fa85f64-5717-4562-b3fc-2c963f66afa6\",\n \"projectSubType\": \"test\",\n \"parentBoundaryCode\": \"mz\",\n // \"projectId\": \"string\",\n \"resources\": [\n {\n \"resourceIds\": [\n \"867ba408-1b82-4746-8274-eb916e625fea\"\n ],\n \"count\": 0,\n \"active\": true,\n \"type\": \"staff\"\n }\n ]\n },\n {\n \"boundaryCode\": \"f5F6xAskA05\",\n \"boundaryType\": \"Provincia\",\n \"startDate\": 1665497225000,\n \"endDate\": 1666497225000,\n \"targets\": [\n {\n \"total\": 700,\n \"target\": 600,\n \"type\": \"household|individual\"\n }\n ],\n \"description\": \"test\",\n \"department\": \"test\",\n \"referenceID\": \" 3fa85f64-5717-4562-b3fc-2c963f66afa6\",\n \"projectSubType\": \"test\",\n \"parentBoundaryCode\": \"mz\",\n // \"projectId\": \"string\",\n \"resources\": [\n {\n \"resourceIds\": [\n \"867ba408-1b82-4746-8274-eb916e625fea\"\n ],\n \"count\": 0,\n \"active\": true,\n \"type\": \"staff\"\n }\n ]\n },\n {\n \"boundaryCode\": \"mz\",\n \"boundaryType\": \"Country\",\n \"startDate\": 1665497225000,\n \"endDate\": 1666497225000,\n \"targets\": [\n {\n \"total\": 1000,\n \"target\": 800,\n \"type\": \"household|individual\"\n }\n ],\n \"description\": \"test\",\n \"department\": \"test\",\n \"referenceID\": \" 3fa85f64-5717-4562-b3fc-2c963f66afa6\",\n \"projectSubType\": \"test\",\n \"parentBoundaryCode\": null,\n // \"projectId\": \"string\",\n \"resources\": [\n {\n \"resourceIds\": [\n \"F-2024-03-21-000882\"\n ],\n \"count\": 0,\n \"active\": true,\n \"type\": \"facility\"\n }\n ]\n },\n {\n \"boundaryCode\": \"mz\",\n \"boundaryType\": \"Country\",\n \"startDate\": 1665497225000,\n \"endDate\": 1666497225000,\n \"targets\": [\n {\n \"total\": 450,\n \"target\": 350,\n \"type\": \"household|individual\"\n }\n ],\n \"description\": \"test\",\n \"department\": \"test\",\n \"referenceID\": \" 3fa85f64-5717-4562-b3fc-2c963f66afa6\",\n \"projectSubType\": \"test\",\n \"parentBoundaryCode\": null,\n // \"projectId\": \"string\",\n \"resources\": [\n {\n \"resourceIds\": [\n // \"e82c3f49-da7c-459c-86a5-a56ac2d4f5b1\"\n \"PVAR-2024-03-21-000052\"\n ],\n \"count\": 0,\n \"active\": true,\n \"type\": \"resource\"\n // \"type\": \"staff|resource|facility\"\n }\n ]\n }\n // Add more entries as needed...\n ],\n \"deliveryRules\": [\n {\n \"startDate\": \"string\",\n \"endDate\": \"string\",\n \"cycle\": \"string\"\n }\n ],\n \"additionalDetails\": {}\n },\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"e45445a1-6891-4a76-a4e6-528e1dd24946\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1710912592752|en_MZ\",\n \"plainAccessRequest\": {}\n}\n}" }, "url": { - "raw": "https://unified-uat.digit.org/project-factory/v1/data/_generate?tenantId=mz&type=boundary&forceUpdate=true&hierarchyType=ADMIN&campaignId=3b331cd6-c0e9-4fd4-9d15-9212ba51706c", - "protocol": "https", + "raw": "http://localhost:8080/project-factory/v1/project-type/createCampaign", + "protocol": "http", "host": [ - "unified-uat", - "digit", - "org" + "localhost" ], + "port": "8080", "path": [ "project-factory", "v1", - "data", - "_generate" - ], - "query": [ - { - "key": "tenantId", - "value": "mz" - }, - { - "key": "type", - "value": "boundary" - }, - { - "key": "forceUpdate", - "value": "true" - }, - { - "key": "hierarchyType", - "value": "ADMIN" - }, - { - "key": "campaignId", - "value": "3b331cd6-c0e9-4fd4-9d15-9212ba51706c" - } + "project-type", + "createCampaign" ] } }, "response": [] }, { - "name": "boundary data generate(template generate)", + "name": "mdms bulk search Copy", "request": { "method": "POST", "header": [ { "key": "authority", - "value": "unified-uat.digit.org" + "value": "unified-dev.digit.org" }, { "key": "accept", @@ -142,19 +108,19 @@ }, { "key": "content-type", - "value": "application/json;charset=UTF-8" + "value": "application/json" }, { "key": "cookie", - "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1ho6v1de2.1ho6v2ouk.ot.21.qu; _ga_H9YC8FEN6F=GS1.1.1709630860.87.1.1709630957.60.0.0; PGADMIN_LANGUAGE=en" + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" }, { "key": "origin", - "value": "https://unified-uat.digit.org" + "value": "https://unified-dev.digit.org" }, { "key": "referer", - "value": "https://unified-uat.digit.org/workbench-ui/employee/campaign/setup-campaign?key=7&preview=false&id=2c948509-4245-4df7-b46b-9cabd5cdb577" + "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" }, { "key": "sec-ch-ua", @@ -187,21 +153,20 @@ ], "body": { "mode": "raw", - "raw": "{\"Filters\":null,\"RequestInfo\":{\"apiId\":\"Rainmaker\",\"authToken\":\"f364ac54-8e9a-49ec-8aff-a3df278bd68d\",\"userInfo\":{\"id\":1052,\"uuid\":\"8b110055-330f-4e7b-b4c0-f618f29b9d47\",\"userName\":\"UATMZ\",\"name\":\"UATMZ\",\"mobileNumber\":\"8998988112\",\"emailId\":null,\"locale\":null,\"type\":\"EMPLOYEE\",\"roles\":[{\"name\":\"System Administrator\",\"code\":\"SYSTEM_ADMINISTRATOR\",\"tenantId\":\"mz\"},{\"name\":\"Campaign Manager\",\"code\":\"CAMPAIGN_MANAGER\",\"tenantId\":\"mz\"},{\"name\":\"Localisation admin\",\"code\":\"LOC_ADMIN\",\"tenantId\":\"mz\"},{\"name\":\"MDMS ADMIN\",\"code\":\"MDMS_ADMIN\",\"tenantId\":\"mz\"}],\"active\":true,\"tenantId\":\"mz\",\"permanentCity\":null},\"msgId\":\"1716892389916|en_IN\",\"plainAccessRequest\":{}}}" + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{Auth}}\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1710912592752|en_MZ\",\n \"plainAccessRequest\": {}\n }\n}" }, "url": { - "raw": "https://unified-uat.digit.org/project-factory/v1/data/_generate?tenantId=mz&type=boundary&forceUpdate=true&hierarchyType=ADMIN&campaignId=2c948509-4245-4df7-b46b-9cabd5cdb577", - "protocol": "https", + "raw": "http://localhost:8080/mdms-bff/v1/mdmsbulk/search?tenantId=mz&schemaName=Dummy.dummy", + "protocol": "http", "host": [ - "unified-uat", - "digit", - "org" + "localhost" ], + "port": "8080", "path": [ - "project-factory", + "mdms-bff", "v1", - "data", - "_generate" + "mdmsbulk", + "search" ], "query": [ { @@ -209,20 +174,8 @@ "value": "mz" }, { - "key": "type", - "value": "boundary" - }, - { - "key": "forceUpdate", - "value": "true" - }, - { - "key": "hierarchyType", - "value": "ADMIN" - }, - { - "key": "campaignId", - "value": "2c948509-4245-4df7-b46b-9cabd5cdb577" + "key": "schemaName", + "value": "Dummy.dummy" } ] } @@ -230,7 +183,12 @@ "response": [] }, { - "name": "User generate data(template generate)", + "name": "campaign-generate Copy", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "content-type": true + } + }, "request": { "method": "POST", "header": [ @@ -260,7 +218,7 @@ }, { "key": "referer", - "value": "https://unified-uat.digit.org/workbench-ui/employee/campaign/setup-campaign?key=7&preview=false&id=2c948509-4245-4df7-b46b-9cabd5cdb577" + "value": "https://unified-uat.digit.org/workbench-ui/employee/campaign/setup-campaign?id=22f77798-3645-44b3-98ee-cc5c0ff2888c&draft=true&fetchBoundary=true&key=8&preview=false&skip=false" }, { "key": "sec-ch-ua", @@ -293,16 +251,15 @@ ], "body": { "mode": "raw", - "raw": "{\"RequestInfo\":{\"apiId\":\"Rainmaker\",\"authToken\":\"f364ac54-8e9a-49ec-8aff-a3df278bd68d\",\"userInfo\":{\"id\":1052,\"uuid\":\"8b110055-330f-4e7b-b4c0-f618f29b9d47\",\"userName\":\"UATMZ\",\"name\":\"UATMZ\",\"mobileNumber\":\"8998988112\",\"emailId\":null,\"locale\":null,\"type\":\"EMPLOYEE\",\"roles\":[{\"name\":\"System Administrator\",\"code\":\"SYSTEM_ADMINISTRATOR\",\"tenantId\":\"mz\"},{\"name\":\"Campaign Manager\",\"code\":\"CAMPAIGN_MANAGER\",\"tenantId\":\"mz\"},{\"name\":\"Localisation admin\",\"code\":\"LOC_ADMIN\",\"tenantId\":\"mz\"},{\"name\":\"MDMS ADMIN\",\"code\":\"MDMS_ADMIN\",\"tenantId\":\"mz\"}],\"active\":true,\"tenantId\":\"mz\",\"permanentCity\":null},\"msgId\":\"1716892389917|en_IN\",\"plainAccessRequest\":{}}}" + "raw": "{\n \"ResourceDetails\": {\n \"type\": \"facility\",\n \"hierarchyType\": \"ADMIN\",\n \"tenantId\": \"mz\",\n \"fileStoreId\": \"fd451260-67e8-4d57-a7bf-81734b0dccc7\",\n \"action\": \"validate\",\n \"campaignId\": \"22f77798-3645-44b3-98ee-cc5c0ff2888c\",\n \"additionalDetails\": {}\n },\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{Auth}}\",\n \"userInfo\": {\n \"id\": 1052,\n \"uuid\": \"8b110055-330f-4e7b-b4c0-f618f29b9d47\",\n \"userName\": \"UATMZ\",\n \"name\": \"UATMZ\",\n \"mobileNumber\": \"8998988112\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS ADMIN\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1716899532287|en_IN\",\n \"plainAccessRequest\": {}\n }\n}" }, "url": { - "raw": "https://unified-uat.digit.org/project-factory/v1/data/_generate?tenantId=mz&type=userWithBoundary&forceUpdate=true&hierarchyType=ADMIN&campaignId=2c948509-4245-4df7-b46b-9cabd5cdb577", - "protocol": "https", + "raw": "http://localhost:8080/project-factory/v1/data/_generate?tenantId=mz&type=userWithBoundary&forceUpdate=true&hierarchyType=ADMIN&campaignId=3b331cd6-c0e9-4fd4-9d15-9212ba51706c", + "protocol": "http", "host": [ - "unified-uat", - "digit", - "org" + "localhost" ], + "port": "8080", "path": [ "project-factory", "v1", @@ -328,7 +285,7 @@ }, { "key": "campaignId", - "value": "2c948509-4245-4df7-b46b-9cabd5cdb577" + "value": "3b331cd6-c0e9-4fd4-9d15-9212ba51706c" } ] } @@ -336,7 +293,7 @@ "response": [] }, { - "name": "data download", + "name": "download-generated Copy", "protocolProfileBehavior": { "disabledSystemHeaders": { "content-type": true @@ -454,13 +411,13 @@ "response": [] }, { - "name": "data create", + "name": "project-factory/v1/data/_create Copy", "request": { "method": "POST", "header": [ { "key": "authority", - "value": "unified-dev.digit.org" + "value": "unified-uat.digit.org" }, { "key": "accept", @@ -472,19 +429,19 @@ }, { "key": "content-type", - "value": "application/json" + "value": "application/json;charset=UTF-8" }, { "key": "cookie", - "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1ho6v1de2.1ho6v2ouk.ot.21.qu; _ga_H9YC8FEN6F=GS1.1.1709630860.87.1.1709630957.60.0.0; PGADMIN_LANGUAGE=en" }, { "key": "origin", - "value": "https://unified-dev.digit.org" + "value": "https://unified-uat.digit.org" }, { "key": "referer", - "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" + "value": "https://unified-uat.digit.org/workbench-ui/employee/campaign/setup-campaign?id=3a567d66-9de5-4812-9441-240ae6ccb674&draft=true&fetchBoundary=true&key=9&preview=false" }, { "key": "sec-ch-ua", @@ -517,7 +474,7 @@ ], "body": { "mode": "raw", - "raw": "{\n \"RequestInfo\":{\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"3dcb7be0-fa76-440f-959c-30c7839ca1d0\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1715753883629|en_MZ\",\n \"plainAccessRequest\": {}\n},\n \"ResourceDetails\": {\n \"type\": \"facility\",\n // \"type\": \"facility|user|boundary\",\n \"tenantId\": \"mz\",\n // empty facility\n // \"fileStoreId\": \"cf37fb7a-f07e-44da-9f11-c06841ffdd44\",\n // worng\n // \"fileStoreId\": \"823110ca-55a1-434b-83d4-138e9e262661\",\n // right\n // \"fileStoreId\":\"252e68d4-44f8-4088-814c-ba0046f7da0f\",\n // right user\n // \"fileStoreId\":\"589fc456-70ab-422f-9c9a-b92ea3304f54\",\n //rightt with 5000 rows\n // \"fileStoreId\": \"0b47f2b3-840a-40b5-af8d-2273b836fd79\",\n //rightt with 200 rows\n // \"fileStoreId\":\"078a35f3-6db9-497b-bed5-d58e0ae3800a\",\n \"fileStoreId\":\"ae72d4a2-1a3a-431c-b30a-699983cf9468\",\n \"action\": \"validate\",\n \"hierarchyType\": \"ADMIN\",\n \"additionalDetails\": {}\n }\n}" + "raw": "{\n \"ResourceDetails\": {\n \"type\": \"boundary\",\n \"hierarchyType\": \"TEST15\",\n \"tenantId\": \"mz\",\n \"fileStoreId\": \"{{fileId}}\",\n \"action\": \"create\",\n // \"campaignId\": \"56cd8661-9d4b-4946-80e9-d50bdcfcce60\",\n \"additionalDetails\": {}\n },\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{Auth}}\",\n \"userInfo\": {\n \"id\": 1052,\n \"uuid\": \"8b110055-330f-4e7b-b4c0-f618f29b9d47\",\n \"userName\": \"UATMZ\",\n \"name\": \"UATMZ\",\n \"mobileNumber\": \"8998988112\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS ADMIN\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1717482930188|en_IN\",\n \"plainAccessRequest\": {}\n}\n}" }, "url": { "raw": "http://localhost:8080/project-factory/v1/data/_create", @@ -537,7 +494,90 @@ "response": [] }, { - "name": "data search", + "name": "project-factory/v1/project-type/search Copy", + "request": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-qa.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json;charset=UTF-8" + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1ho6v1de2.1ho6v2ouk.ot.21.qu; _ga_H9YC8FEN6F=GS1.1.1709630860.87.1.1709630957.60.0.0" + }, + { + "key": "origin", + "value": "https://unified-qa.digit.org" + }, + { + "key": "referer", + "value": "https://unified-qa.digit.org/workbench-ui/employee/campaign/my-campaign" + }, + { + "key": "sec-ch-ua", + "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"Linux\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "same-origin" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{Auth}}\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1716986778045|en_MZ\",\n \"plainAccessRequest\": {}\n },\n \"CampaignDetails\": {\n \"tenantId\": \"mz\",\n \"ids\":[\"{{campaignId}}\"],\n // \"status\": [\n // \"creating\",\n // \"created\"\n // ],\n // \"createdBy\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n // \"campaignsIncludeDates\": true,\n // \"startDate\": 1716986778045,\n // \"endDate\": 1716986778045,\n // \"campaignName\":\"Performance Test Campaign Jun 17 id 00051\",\n \"pagination\": {\n \"sortBy\": \"createdTime\",\n \"sortOrder\": \"desc\",\n \"limit\": 10,\n \"offset\": 0\n }\n }\n}" + }, + "url": { + "raw": "http://localhost:8080/project-fctory/v1/project-type/search", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "project-fctory", + "v1", + "project-type", + "search" + ] + } + }, + "response": [] + }, + { + "name": "project-factory/v1/project-type/search Copy 2", "request": { "method": "POST", "header": [ @@ -624,10 +664,142 @@ ] } }, - "response": [] + "response": [ + { + "name": "project-factory/v1/project-type/search Copy", + "originalRequest": { + "method": "POST", + "header": [ + { + "key": "authority", + "value": "unified-dev.digit.org" + }, + { + "key": "accept", + "value": "application/json, text/plain, */*" + }, + { + "key": "accept-language", + "value": "en-GB,en-US;q=0.9,en;q=0.8" + }, + { + "key": "content-type", + "value": "application/json" + }, + { + "key": "cookie", + "value": "_ga_XBQP06FR8V=GS1.1.1691570094.3.1.1691570094.60.0.0; _ga=GA1.1.2124364284.1689669598; _ga_P1TZCPKF6S=GS1.1.1691648339.2.0.1691648339.60.0.0; __cuid=fe28d9c8c84c4d2487b9cb6c9e4cdec1; amp_fef1e8=f4a3f3ed-50f2-409b-be4f-a1ce1dbb59f2R...1hgs4r9gr.1hgs4robc.nu.1r.pp; _ga_H9YC8FEN6F=GS1.1.1701751656.77.1.1701751677.39.0.0" + }, + { + "key": "origin", + "value": "https://unified-dev.digit.org" + }, + { + "key": "referer", + "value": "https://unified-dev.digit.org/works-ui/employee/measurement/update?tenantId=pg.citya&workOrderNumber=WO/2023-24/000894&mbNumber=MB/2023-24/001252" + }, + { + "key": "sec-ch-ua", + "value": "\"Chromium\";v=\"116\", \"Not)A;Brand\";v=\"24\", \"Google Chrome\";v=\"116\"" + }, + { + "key": "sec-ch-ua-mobile", + "value": "?0" + }, + { + "key": "sec-ch-ua-platform", + "value": "\"Linux\"" + }, + { + "key": "sec-fetch-dest", + "value": "empty" + }, + { + "key": "sec-fetch-mode", + "value": "cors" + }, + { + "key": "sec-fetch-site", + "value": "same-origin" + }, + { + "key": "user-agent", + "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"4d18d41f-bf61-4a50-9382-c7728d57b076\",\n \"userInfo\": {\n \"id\": 947,\n \"uuid\": \"e82c3f49-da7c-459c-86a5-a56ac2d4f5b1\",\n \"userName\": \"EMP44\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"pg\"\n },\n {\n \"name\": \"HCM SYSTEM ADMINISTRATOR\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"pg\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"pg\"\n },\n {\n \"name\": \"SUPER USER\",\n \"code\": \"SUPERUSER\",\n \"tenantId\": \"pg\"\n },\n {\n \"name\": \"HRMS Admin\",\n \"code\": \"HRMS_ADMIN\",\n \"tenantId\": \"pg\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"pg\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1709110250993|en_IN\",\n \"plainAccessRequest\": {}\n },\n \"SearchCriteria\": {\n \"id\": [\n \"fb34e006-0435-4565-acac-988a6992da54\"\n ],\n \"tenantId\": \"mz\",\n \"type\": \"facility\",\n \"status\": \"data-accepted\",\n \"action\": \"create\",\n \"createdBy\": \"e82c3f49-da7c-459c-86a5-a56ac2d4f5b1\"\n }\n}" + }, + "url": { + "raw": "http://localhost:8095/project-factory/v1/data/_search", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8095", + "path": [ + "project-factory", + "v1", + "data", + "_search" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "X-Powered-By", + "value": "Express" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Content-Length", + "value": "563" + }, + { + "key": "ETag", + "value": "W/\"233-jv57E1Q5Yt5KHhUp7M2vxbi5Abg\"" + }, + { + "key": "Date", + "value": "Tue, 02 Apr 2024 05:35:08 GMT" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Keep-Alive", + "value": "timeout=5" + } + ], + "cookie": [], + "body": "{\n \"ResponseInfo\": {\n \"apiId\": \"egov-bff\",\n \"ver\": \"0.0.1\",\n \"ts\": 1712036108718,\n \"status\": \"successful\",\n \"desc\": \"new-response\"\n },\n \"ResourceDetails\": [\n {\n \"id\": \"fb34e006-0435-4565-acac-988a6992da54\",\n \"tenantId\": \"mz\",\n \"status\": \"data-accepted\",\n \"action\": \"create\",\n \"fileStoreId\": \"d5a6f652-37da-49a2-9284-e867b9e4de83\",\n \"processedFilestoreId\": \"5f1fcf05-e6d1-47e0-a96f-019a454cc7d2\",\n \"type\": \"facility\",\n \"createdBy\": \"e82c3f49-da7c-459c-86a5-a56ac2d4f5b1\",\n \"lastModifiedBy\": \"e82c3f49-da7c-459c-86a5-a56ac2d4f5b1\",\n \"createdTime\": 1710921693188,\n \"lastModifiedTime\": 1710921693188,\n \"additionalDetails\": {}\n }\n ]\n}" + } + ] }, { - "name": "campaign create", + "name": "/project-factory/v1/project-type/create Copy", + "event": [ + { + "listen": "test", + "script": { + "exec": [ + "var response=pm.response.json();", + "pm.environment.set(\"campaignId\", response.CampaignDetails.id);", + "pm.environment.set(\"campaignNum\",response.CampaignDetails.campaignNumber)" + ], + "type": "text/javascript", + "packages": {} + } + } + ], "protocolProfileBehavior": { "disabledSystemHeaders": { "content-type": true @@ -699,15 +871,16 @@ ], "body": { "mode": "raw", - "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"0cc530cb-aeb7-4735-a89b-ed5b0607518d\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1713593588138|en_MZ\",\n \"plainAccessRequest\": {}\n},\n \"CampaignDetails\": {\n // \"id\":\"f9f9b96a-d8aa-427b-a755-25bcc22ef60f\",\n \"hierarchyType\": \"ADMIN\",\n \"tenantId\": \"mz\",\n \"campaignName\": \"testName860\",\n \"action\": \"create\",\n // \"action\": \"create\",\n \"startDate\": 1765497222002,\n \"endDate\": 1767497225002,\n // \"projectId\":\"74c57591-13cc-4e21-97d3-2b6c87e7fc98\",\n \"boundaries\": [\n {\n \"code\": \"f5F6xAskA05\",\n \"type\": \"Provincia\",\n \"isRoot\": false\n },\n {\n \"code\": \"mz\",\n \"type\": \"Country\",\n \"isRoot\": true,\n \"includeAllChildren\": true\n }\n ],\n \"resources\": [\n {\n \"filestoreId\": \"252e68d4-44f8-4088-814c-ba0046f7da0f\",\n \"type\": \"facility\",\n \"filename\": \"hkjsss.xlsx\"\n },\n {\n \"filestoreId\":\"49280d90-31f2-4911-8d1e-0482cc6bf70c\",\n \"type\": \"user\",\n \"filename\": \"hkjsss.xlsx\"\n }\n // {\n // \"filestoreId\": \"d96c0248-dcfd-414c-8f8c-635dad0a89f1\",\n // \"type\": \"boundary\",\n // \"filename\": \"s.xlsx\"\n // }\n ],\n \"projectType\": \"LLIN-mz\",\n \"deliveryRules\": [\n {\n \"startDate\": 1666497225000,\n \"endDate\": 1666497225000,\n \"cycleNumber\": 0,\n \"deliveryNumber\": 0,\n \"deliveryRuleNumber\": 0,\n \"products\": [\n \"string\"\n ],\n \"conditions\": [\n {\n \"attribute\": \"string\",\n \"operator\": \"string\",\n \"value\": 0\n }\n ]\n }\n // {\n // \"startDate\": 1667497225001,\n // \"endDate\": 1668897225001,\n // \"cycleNumber\": 0,\n // \"deliveryNumber\": 0,\n // \"deliveryRuleNumber\": 0,\n // \"products\": [\n // \"string\"\n // ],\n // \"conditions\": [\n // {\n // \"attribute\": \"string\",\n // \"operator\": \"string\",\n // \"value\": 0\n // }\n // ]\n // }\n ],\n \"additionalDetails\": {\n \"beneficiaryType\": \"HOUSEHOLD\"\n }\n }\n}" + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{Auth}}\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1713593588138|en_MZ\",\n \"plainAccessRequest\": {}\n },\n \"CampaignDetails\": {\n // \"id\": \"992f8c27-7dde-43f8-9dad-e6ec9d821d39\",\n \"tenantId\": \"mz\",\n // \"status\": \"created\",\n \"action\": \"draft\",\n // \"campaignNumber\": \"CMP-2024-07-30-001374\",\n \"campaignName\": \"jul31_3\",\n \"projectType\": \"LLIN-mz\",\n \"hierarchyType\": \"Health\",\n \"boundaryCode\": \"HEALTH_MO\",\n // \"projectId\": \"baeadf90-ded8-47eb-a02a-c4c9c4527321\",\n \"startDate\": 1722450600000,\n \"endDate\": 1725560999000,\n \"additionalDetails\": {\n \"key\": 10,\n \"beneficiaryType\": \"HOUSEHOLD\"\n },\n \"resources\": [\n {\n \"type\": \"facility\",\n \"filename\": \"Facility Template (56).xlsx\",\n \"resourceId\": \"31a528c6-1345-4587-ad21-7bafcbe3b28f\",\n \"filestoreId\": \"6aebec94-463d-4f81-bb13-5c42ac848c25\",\n \"createResourceId\": \"628b0382-4964-441a-a687-9391b92fa5e5\"\n },\n {\n \"type\": \"boundaryWithTarget\",\n \"filename\": \"Target Template (84).xlsx\",\n \"resourceId\": \"7244300a-dd01-49ca-a39f-27845e84f28c\",\n \"filestoreId\": \"dc3c52ea-96b0-49b4-b38e-6360f09b98e3\"\n },\n {\n \"type\": \"user\",\n \"filename\": \"User Template (30).xlsx\",\n \"resourceId\": \"3fa115c9-a394-48a9-8c53-c9929b0abd0e\",\n \"filestoreId\": \"a0254f2e-1ed0-4255-b471-9a912230eb96\",\n \"createResourceId\": \"ebeaf8e1-e185-4b64-98f1-43b9eb8cc095\"\n }\n ],\n \"boundaries\": [\n {\n \"code\": \"HEALTH_MO\",\n \"type\": \"Country\",\n \"isRoot\": true,\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_NAMPULA\",\n \"type\": \"Province\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO\",\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_02_MOSSURILEE\",\n \"type\": \"District\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_NAMPULA\",\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_02_02_CHITIMA-01\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_02_MOSSURILEE\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_02_01_NSADZO\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_02_MOSSURILEE\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"type\": \"District\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_NAMPULA\",\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_01_04_NIHESSIUE\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_03_CHITEEIMA\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_02_CHIFUNDE-01\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_01_MUALDZI\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n }\n ],\n \"deliveryRules\": [\n {\n \"endDate\": 1723573799000,\n \"products\": [\n {\n \"name\": \"SP 500mg\",\n \"count\": 1,\n \"value\": \"PVAR-2024-03-15-000043\"\n }\n ],\n \"startDate\": 1722537000000,\n \"conditions\": [\n {\n \"value\": 3,\n \"operator\": \"LESS_THAN_EQUAL_TO\",\n \"attribute\": \"CAMPAIGN_BEDNET_INDIVIDUAL_LABEL\"\n },\n {\n \"value\": 1.8,\n \"operator\": \"LESS_THAN_EQUAL_TO\",\n \"attribute\": \"CAMPAIGN_BEDNET_HOUSEHOLD_LABEL\"\n }\n ],\n \"cycleNumber\": 1,\n \"deliveryNumber\": 1,\n \"deliveryRuleNumber\": 1\n }\n ],\n \"auditDetails\": {\n \"createdBy\": \"bfab6822-ec28-40f0-aef1-efd1cda8fcd5\",\n \"lastModifiedBy\": \"bfab6822-ec28-40f0-aef1-efd1cda8fcd5\",\n \"createdTime\": 1722324752043,\n \"lastModifiedTime\": 1722324899659\n }\n }\n}" }, "url": { - "raw": "http://localhost:8080/project-factory/v1/project-type/create", - "protocol": "http", + "raw": "https://unified-dev.digit.org/project-factory/v1/project-type/create", + "protocol": "https", "host": [ - "localhost" + "unified-dev", + "digit", + "org" ], - "port": "8080", "path": [ "project-factory", "v1", @@ -719,7 +892,7 @@ "response": [] }, { - "name": "update campaign", + "name": "/project-factory/v1/project-type/update Copy", "protocolProfileBehavior": { "disabledSystemHeaders": { "content-type": true @@ -792,13 +965,13 @@ ], "body": { "mode": "raw", - "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"44cb5589-8dc2-4182-b5a4-afdb692ce831\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1713364121714|en_MZ\",\n \"plainAccessRequest\": {}\n },\n \"CampaignDetails\": {\n \"id\": \"f9ea7046-75f2-4ac3-837d-caf14fdcdcca\",\n \"tenantId\": \"mz\",\n \"status\": \"drafted\",\n \"action\": \"draft\",\n \"campaignNumber\": \"CMP-2024-05-02-000855\",\n \"campaignName\": \"weartux\",\n \"projectType\": \"MR-DN\",\n \"hierarchyType\": \"ADMIN\",\n \"boundaryCode\": \"\",\n \"projectId\": null,\n \"startDate\": 0,\n \"endDate\": 0,\n \"createdBy\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"lastModifiedBy\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"createdTime\": 1714654527543,\n \"lastModifiedTime\": 1714654527544,\n \"additionalDetails\": {\n \"key\": 2,\n \"beneficiaryType\": \"INDIVIDUAL\"\n },\n \"campaignDetails\": {\n \"resources\": []\n }\n }\n}\n// \"boundaries\": [\n// {\n// \"code\": \"f5F6xAskA05\",\n// \"type\": \"Provincia\",\n// \"isRoot\": false\n// },\n// {\n// \"code\": \"mz\",\n// \"type\": \"Country\",\n// \"isRoot\": true,\n// \"includeAllChildren\": true\n// }\n// ]," + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"44cb5589-8dc2-4182-b5a4-afdb692ce831\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1713364121714|en_MZ\",\n \"plainAccessRequest\": {}\n },\n \"CampaignDetails\": {\n \"id\": \"{{campaignId}}\",\n \"tenantId\": \"mz\",\n \"status\": \"drafted\",\n \"action\": \"create\",\n \"campaignNumber\": \"{{campaignNum}}\",\n \"campaignName\": \"{{campaignName}}\",\n \"projectType\": \"LLIN-mz\",\n \"hierarchyType\": \"Health\",\n \"boundaryCode\": \"HEALTH_MO\",\n // \"projectId\": \"baeadf90-ded8-47eb-a02a-c4c9c4527321\",\n \"startDate\": 1722450600000,\n \"endDate\": 1725560999000,\n \"additionalDetails\": {\n \"key\": 10,\n \"beneficiaryType\": \"HOUSEHOLD\"\n },\n \"resources\": [\n {\n \"type\": \"facility\",\n \"filename\": \"Facility Template (56).xlsx\",\n \"resourceId\": \"31a528c6-1345-4587-ad21-7bafcbe3b28f\",\n \"filestoreId\": \"6aebec94-463d-4f81-bb13-5c42ac848c25\",\n \"createResourceId\": \"628b0382-4964-441a-a687-9391b92fa5e5\"\n },\n {\n \"type\": \"boundaryWithTarget\",\n \"filename\": \"Target Template (84).xlsx\",\n \"resourceId\": \"7244300a-dd01-49ca-a39f-27845e84f28c\",\n \"filestoreId\": \"dc3c52ea-96b0-49b4-b38e-6360f09b98e3\"\n },\n {\n \"type\": \"user\",\n \"filename\": \"User Template (30).xlsx\",\n \"resourceId\": \"3fa115c9-a394-48a9-8c53-c9929b0abd0e\",\n \"filestoreId\": \"a0254f2e-1ed0-4255-b471-9a912230eb96\",\n \"createResourceId\": \"ebeaf8e1-e185-4b64-98f1-43b9eb8cc095\"\n }\n ],\n \"boundaries\": [\n {\n \"code\": \"HEALTH_MO\",\n \"type\": \"Country\",\n \"isRoot\": true,\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_NAMPULA\",\n \"type\": \"Province\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO\",\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_02_MOSSURILEE\",\n \"type\": \"District\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_NAMPULA\",\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_02_02_CHITIMA-01\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_02_MOSSURILEE\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_02_01_NSADZO\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_02_MOSSURILEE\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"type\": \"District\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_NAMPULA\",\n \"includeAllChildren\": false\n },\n {\n \"code\": \"HEALTH_MO_13_01_04_NIHESSIUE\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_03_CHITEEIMA\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_02_CHIFUNDE-01\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n },\n {\n \"code\": \"HEALTH_MO_13_01_01_MUALDZI\",\n \"type\": \"Post Administrative\",\n \"isRoot\": false,\n \"parent\": \"HEALTH_MO_13_01_MURRUPULA\",\n \"includeAllChildren\": true\n }\n ],\n \"deliveryRules\": [\n {\n \"endDate\": 1723573799000,\n \"products\": [\n {\n \"name\": \"SP 500mg\",\n \"count\": 1,\n \"value\": \"PVAR-2024-03-15-000043\"\n }\n ],\n \"startDate\": 1722537000000,\n \"conditions\": [\n {\n \"value\": 3,\n \"operator\": \"LESS_THAN_EQUAL_TO\",\n \"attribute\": \"CAMPAIGN_BEDNET_INDIVIDUAL_LABEL\"\n },\n {\n \"value\": 1.8,\n \"operator\": \"LESS_THAN_EQUAL_TO\",\n \"attribute\": \"CAMPAIGN_BEDNET_HOUSEHOLD_LABEL\"\n }\n ],\n \"cycleNumber\": 1,\n \"deliveryNumber\": 1,\n \"deliveryRuleNumber\": 1\n }\n ],\n \"auditDetails\": {\n \"createdBy\": \"bfab6822-ec28-40f0-aef1-efd1cda8fcd5\",\n \"lastModifiedBy\": \"bfab6822-ec28-40f0-aef1-efd1cda8fcd5\",\n \"createdTime\": 1722324752043,\n \"lastModifiedTime\": 1722324899659\n }\n }\n}" }, "url": { - "raw": "https://unified-qa.digit.org/project-factory/v1/project-type/update", + "raw": "https://unified-dev.digit.org/project-factory/v1/project-type/update", "protocol": "https", "host": [ - "unified-qa", + "unified-dev", "digit", "org" ], @@ -813,7 +986,12 @@ "response": [] }, { - "name": "campaign search", + "name": "getProcessTracks Copy", + "protocolProfileBehavior": { + "disabledSystemHeaders": { + "content-type": true + } + }, "request": { "method": "POST", "header": [ @@ -872,28 +1050,39 @@ { "key": "user-agent", "value": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36" + }, + { + "key": "Content-Type", + "value": "application/json" } ], "body": { "mode": "raw", - "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"b2985fc2-9980-4fba-adcf-3248e3a66490\",\n \"userInfo\": {\n \"id\": 6152,\n \"uuid\": \"63a21269-d40d-4c26-878f-4f4486b1f44b\",\n \"userName\": \"MDMSMZ\",\n \"name\": \"MDMSMZ\",\n \"mobileNumber\": \"8998989222\",\n \"emailId\": null,\n \"locale\": null,\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": null\n },\n \"msgId\": \"1713364121714|en_MZ\",\n \"plainAccessRequest\": {}\n },\n \"CampaignDetails\": {\n \"ids\": [\n \"7cfc93f2-9c4c-4415-9417-e61d2203bdd8\"\n ],\n \"tenantId\": \"mz\",\n // \"startDate\": 1665497224000,\n // \"endDate\": 1665929226005,\n // \"projectType\": \"default1\",\n // \"campaignName\": \"test1Name803\",\n // \"status\": \"started\",\n // \"createdBy\": \"string\",\n // \"campaignNumber\": \"string\",\n \"pagination\": {\n \"sortBy\": \"createdTime\",\n \"sortOrder\": \"desc\",\n \"limit\": 15,\n \"offset\": 0\n }\n // \"createdTime\":1665929226005\n }\n}" + "raw": "{\n \"RequestInfo\": {\n \"apiId\": \"Rainmaker\",\n \"authToken\": \"{{Auth}}\",\n \"userInfo\": {\n \"id\": 1284,\n \"uuid\": \"867ba408-1b82-4746-8274-eb916e625fea\",\n \"userName\": \"EMP57\",\n \"name\": \"Jagan\",\n \"mobileNumber\": \"6667776662\",\n \"emailId\": \"xyz@egovernments.org\",\n \"locale\": \"string\",\n \"type\": \"EMPLOYEE\",\n \"roles\": [\n {\n \"name\": \"System Administrator\",\n \"code\": \"SYSTEM_ADMINISTRATOR\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Localisation admin\",\n \"code\": \"LOC_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"MDMS Admin\",\n \"code\": \"MDMS_ADMIN\",\n \"tenantId\": \"mz\"\n },\n {\n \"name\": \"Campaign Manager\",\n \"code\": \"CAMPAIGN_MANAGER\",\n \"tenantId\": \"mz\"\n }\n ],\n \"active\": true,\n \"tenantId\": \"mz\",\n \"permanentCity\": \"Amritsar\"\n },\n \"msgId\": \"1713593588138|en_MZ\",\n \"plainAccessRequest\": {}\n}\n}" }, "url": { - "raw": "http://localhost:8080/project-factory/v1/project-type/search", - "protocol": "http", + "raw": "https://unified-dev.digit.org/project-factory/v1/project-type/getProcessTrack?campaignId=eeded5f1-e779-454f-9cc7-2b20ba4839e0", + "protocol": "https", "host": [ - "localhost" + "unified-dev", + "digit", + "org" ], - "port": "8080", "path": [ "project-factory", "v1", "project-type", - "search" + "getProcessTrack" + ], + "query": [ + { + "key": "campaignId", + "value": "eeded5f1-e779-454f-9cc7-2b20ba4839e0" + } ] } }, "response": [] } ] -} +} \ No newline at end of file diff --git a/health-services/project-factory/src/server/api/campaignApis.ts b/health-services/project-factory/src/server/api/campaignApis.ts index f0a5a231965..c063f1e653d 100644 --- a/health-services/project-factory/src/server/api/campaignApis.ts +++ b/health-services/project-factory/src/server/api/campaignApis.ts @@ -3,15 +3,17 @@ import { v4 as uuidv4 } from 'uuid'; import { httpRequest } from "../utils/request"; import { getFormattedStringForDebug, logger } from "../utils/logger"; import createAndSearch from '../config/createAndSearch'; -import { getDataFromSheet, generateActivityMessage, throwError, translateSchema, replicateRequest } from "../utils/genericUtils"; +import { getDataFromSheet, generateActivityMessage, throwError, translateSchema, replicateRequest, appendProjectTypeToCapacity } from "../utils/genericUtils"; import { immediateValidationForTargetSheet, validateSheetData, validateTargetSheetData } from '../validators/campaignValidators'; import { callMdmsTypeSchema, getCampaignNumber } from "./genericApis"; -import { boundaryBulkUpload, convertToTypeData, generateHierarchy, generateProcessedFileAndPersist, getLocalizedName, reorderBoundariesOfDataAndValidate } from "../utils/campaignUtils"; +import { boundaryBulkUpload, convertToTypeData, generateHierarchy, generateProcessedFileAndPersist, getBoundaryOnWhichWeSplit, getLocalizedName, reorderBoundariesOfDataAndValidate, checkIfSourceIsMicroplan } from "../utils/campaignUtils"; const _ = require('lodash'); -import { produceModifiedMessages } from "../kafka/Listener"; +import { produceModifiedMessages } from "../kafka/Producer"; import { createDataService } from "../service/dataManageService"; import { searchProjectTypeCampaignService } from "../service/campaignManageService"; import { getExcelWorkbookFromFileURL } from "../utils/excelUtils"; +import { processTrackStatuses, processTrackTypes } from "../config/constants"; +import { persistTrack } from "../utils/processTrackUtils"; @@ -258,8 +260,18 @@ async function getUuidsError(request: any, response: any, mobileNumberRowNumberM errors.push({ status: "INVALID", rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have username` }) count++; } + else if (!user?.userDetails?.password) { + logger.info(`User with mobileNumber ${user?.mobileNumber} doesn't have password`) + errors.push({ status: "INVALID", rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have password` }) + count++; + } + else if (!user?.userUuid) { + logger.info(`User with mobileNumber ${user?.mobileNumber} doesn't have userServiceUuid`) + errors.push({ status: "INVALID", rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], errorDetails: `User with mobileNumber ${user?.mobileNumber} doesn't have userServiceUuid` }) + count++; + } else { - request.body.mobileNumberUuidsMapping[user?.mobileNumber] = { userUuid: user?.id, code: user?.userDetails?.username, rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber] } + request.body.mobileNumberUuidsMapping[user?.mobileNumber] = { userUuid: user?.id, code: user?.userDetails?.username, rowNumber: mobileNumberRowNumberMapping[user?.mobileNumber], password: user?.userDetails?.password, userServiceUuid: user?.userUuid } } } if (count > 0) { @@ -518,11 +530,12 @@ async function processValidate(request: any, localizationMap?: { [key: string]: const createAndSearchConfig = createAndSearch[type] const dataFromSheet = await getDataFromSheet(request, request?.body?.ResourceDetails?.fileStoreId, request?.body?.ResourceDetails?.tenantId, createAndSearchConfig, null, localizationMap) if (type == 'boundaryWithTarget') { + let differentTabsBasedOnLevel = await getBoundaryOnWhichWeSplit(request); + differentTabsBasedOnLevel = getLocalizedName(`${request?.body?.ResourceDetails?.hierarchyType}_${differentTabsBasedOnLevel}`.toUpperCase(), localizationMap); logger.info("target sheet format validation started"); - // added await to ensure validations complete before proceeding, preventing premature errors. - await immediateValidationForTargetSheet(dataFromSheet, localizationMap); + await immediateValidationForTargetSheet(request, dataFromSheet, differentTabsBasedOnLevel, localizationMap); logger.info("target sheet format validation completed and starts with data validation"); - validateTargetSheetData(dataFromSheet, request, createAndSearchConfig?.boundaryValidation, localizationMap); + validateTargetSheetData(dataFromSheet, request, createAndSearchConfig?.boundaryValidation, differentTabsBasedOnLevel, localizationMap); } else { @@ -693,7 +706,8 @@ async function enrichAlreadyExsistingUser(request: any) { employee.uuid = request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber].userUuid; employee.code = request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber].code; employee.user.userName = request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber].code; - employee.user.password = config.user.userDefaultPassword; + employee.user.password = request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber].password; + employee.user.userServiceUuid = request?.body?.mobileNumberUuidsMapping[employee?.user?.mobileNumber].userServiceUuid; } } } @@ -716,7 +730,7 @@ async function performAndSaveResourceActivity(request: any, createAndSearchConfi } _.set(newRequestBody, createAndSearchConfig?.createBulkDetails?.createPath, chunkData); creationTime = Date.now(); - if (type == "facility") { + if (type == "facility" || type == "facilityMicroplan") { await handeFacilityProcess(request, createAndSearchConfig, params, activities, newRequestBody); } else if (type == "user") { @@ -774,16 +788,27 @@ async function handleResouceDetailsError(request: any, error: any) { if (request?.body?.ResourceDetails?.action == "create") { persistMessage.ResourceDetails.additionalDetails = { error: stringifiedError } } - produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC); + await produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC); } - if (request?.body?.Activities && Array.isArray(request?.body?.Activities && request?.body?.Activities.length > 0)) { + if (request?.body?.Activities && Array.isArray(request?.body?.Activities) && request?.body?.Activities.length > 0) { logger.info("Waiting for 2 seconds"); await new Promise(resolve => setTimeout(resolve, 2000)); - produceModifiedMessages(request?.body, config?.kafka?.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC); + const activityObject = request?.body?.Activities; + await produceModifiedMessages(activityObject, config?.kafka?.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC); + } +} + +async function persistCreationProcess(request: any, status: any) { + if (request?.body?.ResourceDetails?.type == "facility") { + await persistTrack(request?.body?.ResourceDetails?.campaignId, processTrackTypes.facilityCreation, status); + } + else if (request?.body?.ResourceDetails?.type == "user") { + await persistTrack(request?.body?.ResourceDetails?.campaignId, processTrackTypes.staffCreation, status); } } async function processAfterValidation(dataFromSheet: any, createAndSearchConfig: any, request: any, localizationMap?: { [key: string]: string }) { + await persistCreationProcess(request, processTrackStatuses.inprogress) try { const typeData = await convertToTypeData(request, dataFromSheet, createAndSearchConfig, request.body, localizationMap) request.body.dataToCreate = typeData.createData; @@ -801,8 +826,10 @@ async function processAfterValidation(dataFromSheet: any, createAndSearchConfig: } } catch (error: any) { console.log(error) + await persistCreationProcess(request, processTrackStatuses.failed) await handleResouceDetailsError(request, error) } + await persistCreationProcess(request, processTrackStatuses.completed) } /** @@ -817,14 +844,39 @@ async function processCreate(request: any, localizationMap?: any) { boundaryBulkUpload(request, localizationMap); } else { - const createAndSearchConfig = createAndSearch[type] + // console.log(`Source is MICROPLAN -->`, source); + let createAndSearchConfig: any; + createAndSearchConfig = createAndSearch[type]; + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignType = responseFromCampaignSearch?.CampaignDetails[0]?.projectType; + if (checkIfSourceIsMicroplan(request?.body?.ResourceDetails)) { + logger.info(`Data create Source is MICROPLAN`); + if (createAndSearchConfig?.parseArrayConfig?.parseLogic) { + createAndSearchConfig.parseArrayConfig.parseLogic = createAndSearchConfig.parseArrayConfig.parseLogic.map( + (item: any) => { + if (item.sheetColumn === "E") { + item.sheetColumnName += `_${campaignType}`; + } + return item; + } + ); + } + } + const dataFromSheet = await getDataFromSheet(request, request?.body?.ResourceDetails?.fileStoreId, request?.body?.ResourceDetails?.tenantId, createAndSearchConfig, undefined, localizationMap) let schema: any; + if (type == "facility") { logger.info("Fetching schema to validate the created data for type: " + type); const mdmsResponse = await callMdmsTypeSchema(request, tenantId, type); schema = mdmsResponse } + else if (type == "facilityMicroplan") { + const mdmsResponse = await callMdmsTypeSchema(request, tenantId, "facility", "microplan"); + schema = mdmsResponse + logger.info("Appending project type to capacity for microplan " + campaignType); + schema = await appendProjectTypeToCapacity(schema, campaignType); + } else if (type == "user") { logger.info("Fetching schema to validate the created data for type: " + type); const mdmsResponse = await callMdmsTypeSchema(request, tenantId, type); @@ -843,33 +895,41 @@ async function processCreate(request: any, localizationMap?: any) { * @param request The HTTP request object. */ async function createProjectCampaignResourcData(request: any) { - // Create resources for a project campaign - if (request?.body?.CampaignDetails?.action == "create" && request?.body?.CampaignDetails?.resources) { - for (const resource of request?.body?.CampaignDetails?.resources) { - if (resource.type != "boundaryWithTarget") { - const resourceDetails = { - type: resource.type, - fileStoreId: resource.filestoreId, - tenantId: request?.body?.CampaignDetails?.tenantId, - action: "create", - hierarchyType: request?.body?.CampaignDetails?.hierarchyType, - additionalDetails: {}, - campaignId: request?.body?.CampaignDetails?.id - }; - logger.info(`Creating the resources for type ${resource.type}`) - logger.debug("resourceDetails " + getFormattedStringForDebug(resourceDetails)) - const createRequestBody = { - RequestInfo: request.body.RequestInfo, - ResourceDetails: resourceDetails - } - const req = replicateRequest(request, createRequestBody) - const res: any = await createDataService(req) - if (res?.id) { - resource.createResourceId = res?.id + await persistTrack(request.body.CampaignDetails.id, processTrackTypes.triggerResourceCreation, processTrackStatuses.inprogress); + try { + // Create resources for a project campaign + if (request?.body?.CampaignDetails?.action == "create" && request?.body?.CampaignDetails?.resources) { + for (const resource of request?.body?.CampaignDetails?.resources) { + if (resource.type != "boundaryWithTarget") { + const resourceDetails = { + type: resource.type, + fileStoreId: resource.filestoreId, + tenantId: request?.body?.CampaignDetails?.tenantId, + action: "create", + hierarchyType: request?.body?.CampaignDetails?.hierarchyType, + additionalDetails: {}, + campaignId: request?.body?.CampaignDetails?.id + }; + logger.info(`Creating the resources for type ${resource.type}`) + logger.debug("resourceDetails " + getFormattedStringForDebug(resourceDetails)) + const createRequestBody = { + RequestInfo: request.body.RequestInfo, + ResourceDetails: resourceDetails + } + const req = replicateRequest(request, createRequestBody) + const res: any = await createDataService(req) + if (res?.id) { + resource.createResourceId = res?.id + } } } } + } catch (error: any) { + console.log(error) + await persistTrack(request?.body?.CampaignDetails?.id, processTrackTypes.triggerResourceCreation, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + throw new Error(error) } + await persistTrack(request.body.CampaignDetails.id, processTrackTypes.triggerResourceCreation, processTrackStatuses.completed); } async function confirmProjectParentCreation(request: any, projectId: any) { diff --git a/health-services/project-factory/src/server/api/genericApis.ts b/health-services/project-factory/src/server/api/genericApis.ts index 3325efc9d73..c7fa9ced8e0 100644 --- a/health-services/project-factory/src/server/api/genericApis.ts +++ b/health-services/project-factory/src/server/api/genericApis.ts @@ -6,10 +6,9 @@ import { getFormattedStringForDebug, logger } from "../utils/logger"; // Import import { correctParentValues, findMapValue, generateActivityMessage, getBoundaryRelationshipData, getDataSheetReady, getLocalizedHeaders, sortCampaignDetails, throwError } from "../utils/genericUtils"; // Import utility functions import { extractCodesFromBoundaryRelationshipResponse, generateFilteredBoundaryData, getConfigurableColumnHeadersBasedOnCampaignType, getFiltersFromCampaignSearchResponse, getLocalizedName } from '../utils/campaignUtils'; // Import utility functions import { getCampaignSearchResponse, getHierarchy } from './campaignApis'; -import { validateMappingId } from '../utils/campaignMappingUtils'; -import { campaignStatuses } from '../config/constants'; const _ = require('lodash'); // Import lodash library import { getExcelWorkbookFromFileURL } from "../utils/excelUtils"; +import { processMapping } from "../utils/campaignMappingUtils"; //Function to get Workbook with different tabs (for type target) @@ -38,9 +37,9 @@ const getTargetWorkbook = async (fileUrl: string, localizationMap?: any) => { function getJsonData(sheetData: any, getRow = false, getSheetName = false, sheetName = "sheet1") { const jsonData: any[] = []; - const headers = sheetData[1]; // Extract the headers from the first row + const headers = sheetData[0]; // Extract the headers from the first row - for (let i = 2; i < sheetData.length; i++) { + for (let i = 1; i < sheetData.length; i++) { const rowData: any = {}; const row = sheetData[i]; if (row) { @@ -52,7 +51,7 @@ function getJsonData(sheetData: any, getRow = false, getSheetName = false, sheet } } if (Object.keys(rowData).length > 0) { - if (getRow) rowData["!row#number!"] = i; + if (getRow) rowData["!row#number!"] = i + 1; if (getSheetName) rowData["!sheet#name!"] = sheetName; jsonData.push(rowData); } @@ -62,11 +61,7 @@ function getJsonData(sheetData: any, getRow = false, getSheetName = false, sheet } function validateFirstRowColumn(createAndSearchConfig: any, worksheet: any, localizationMap: any) { - if ( - createAndSearchConfig && - createAndSearchConfig.parseArrayConfig && - createAndSearchConfig.parseArrayConfig.parseLogic - ) { + if (createAndSearchConfig?.parseArrayConfig?.parseLogic) { const parseLogic = createAndSearchConfig.parseArrayConfig.parseLogic; // Iterate over each column configuration for (const columnConfig of parseLogic) { @@ -91,6 +86,25 @@ function validateFirstRowColumn(createAndSearchConfig: any, worksheet: any, loca } } +function getSheetDataFromWorksheet(worksheet: any) { + var sheetData: any[][] = []; + + worksheet.eachRow({ includeEmpty: true }, (row: any, rowNumber: any) => { + const rowData: any[] = []; + + row.eachCell({ includeEmpty: true }, (cell: any, colNumber: any) => { + const cellValue = getRawCellValue(cell); + rowData[colNumber - 1] = cellValue; // Store cell value (0-based index) + }); + + // Push non-empty row only + if (rowData.some(value => value !== null && value !== undefined)) { + sheetData[rowNumber - 1] = rowData; // Store row data (0-based index) + } + }); + return sheetData; +} + // Function to retrieve data from a specific sheet in an Excel file const getSheetData = async ( fileUrl: string, @@ -99,19 +113,42 @@ const getSheetData = async ( createAndSearchConfig?: any, localizationMap?: { [key: string]: string } ) => { - // Retrieve workbook using the getTargetWorkbook function + // Retrieve workbook using the getExcelWorkbookFromFileURL function const localizedSheetName = getLocalizedName(sheetName, localizationMap); const workbook: any = await getExcelWorkbookFromFileURL(fileUrl, localizedSheetName); const worksheet: any = workbook.getWorksheet(localizedSheetName); - // If parsing array configuration is provided, validate first row of each column validateFirstRowColumn(createAndSearchConfig, worksheet, localizationMap); - const sheetData = worksheet.getSheetValues({ includeEmpty: true }); + // Collect sheet data by iterating through rows and cells + const sheetData = getSheetDataFromWorksheet(worksheet); const jsonData = getJsonData(sheetData, getRow); return jsonData; +}; + +// Helper function to extract raw cell value +function getRawCellValue(cell: any) { + if (cell.value && typeof cell.value === 'object') { + if ('richText' in cell.value) { + // Handle rich text + return cell.value.richText.map((rt: any) => rt.text).join(''); + } else if ('formula' in cell.value) { + // Get the result of the formula + return cell.value.result; + } else if ('error' in cell.value) { + // Get the error value + return cell.value.error; + } else if (cell.value instanceof Date) { + // Handle date values + return cell.value.toISOString(); + } else { + // Return as-is for other object types + return cell.value; + } + } + return cell.value; // Return raw value for plain strings, numbers, etc. } const getTargetSheetData = async ( @@ -131,7 +168,7 @@ const getTargetSheetData = async ( for (const sheetName of localizedSheetNames) { const worksheet = workbook.getWorksheet(sheetName); - const sheetData = worksheet.getSheetValues({ includeEmpty: true }); + const sheetData = getSheetDataFromWorksheet(worksheet); workbookData[sheetName] = getJsonData(sheetData, getRow, getSheetName, sheetName); } return workbookData; @@ -155,10 +192,10 @@ const getTargetSheetDataAfterCode = async ( for (const sheetName of localizedSheetNames) { const worksheet = workbook.getWorksheet(sheetName); - const sheetData = worksheet.getSheetValues({ includeEmpty: true }); + const sheetData = getSheetDataFromWorksheet(worksheet); // Find the target column index where the first row value matches codeColumnName - const firstRow = sheetData[1]; + const firstRow = sheetData[0]; let targetColumnIndex = -1; for (let colIndex = 1; colIndex < firstRow.length; colIndex++) { if (firstRow[colIndex] === codeColumnName) { @@ -545,26 +582,31 @@ async function getAutoGeneratedBoundaryCodes(boundaryList: any, childParentMap: const column = columnsData[i]; for (const element of column) { if (!findMapValue(elementCodesMap, element)) { - const parentCode = findMapValue(childParentMap, element) - if (parentCode !== undefined && parentCode !== null) { - countMap.set(parentCode, (findMapValue(countMap, parentCode) || 0) + 1); - let code; - const grandParentCode = findMapValue(childParentMap, parentCode); - if (grandParentCode != null && grandParentCode != undefined) { - const parentBoundaryCode = findMapValue(elementCodesMap, parentCode) - const lastUnderscoreIndex = parentBoundaryCode.lastIndexOf('_'); - const parentBoundaryCodeTrimmed = lastUnderscoreIndex !== -1 ? parentBoundaryCode.substring(0, lastUnderscoreIndex) : parentBoundaryCode; - code = generateElementCode(countMap.get(parentCode), parentBoundaryCodeTrimmed, element.value); - } else { - code = generateElementCode(countMap.get(parentCode), findMapValue(elementCodesMap, parentCode), element.value); - } + const parentElement = findMapValue(childParentMap, element); + if (parentElement !== undefined && parentElement !== null) { + const parentBoundaryCode = findMapValue(elementCodesMap, parentElement); + const currentCount = (findMapValue(countMap, parentElement) || 0) + 1; + countMap.set(parentElement, currentCount); + + const code = generateElementCode( + currentCount, + parentElement, + parentBoundaryCode, + element.value, + config.excludeBoundaryNameAtLastFromBoundaryCodes, + childParentMap, + elementCodesMap + ); + elementCodesMap.set(element, code); // Store the code of the element in the map } else { // Generate default code if parent code is not found - elementCodesMap.set(element, (request?.body?.ResourceDetails?.hierarchyType + "_").toUpperCase() + element.value.toString().substring(0, 2).toUpperCase()); + const prefix = config?.excludeHierarchyTypeFromBoundaryCodes + ? element.value.toString().substring(0, 2).toUpperCase() + : `${(request?.body?.ResourceDetails?.hierarchyType + "_").toUpperCase()}${element.value.toString().substring(0, 2).toUpperCase()}`; + + elementCodesMap.set(element, prefix); } - } else { - continue; } } } @@ -574,21 +616,33 @@ async function getAutoGeneratedBoundaryCodes(boundaryList: any, childParentMap: /** * Function to generate an element code based on sequence, parent code, and element. * @param sequence Sequence number - * @param parentCode Parent code + * @param parentElement Parent element + * @param parentBoundaryCode Parent boundary code * @param element Element + * @param excludeBoundaryNameAtLastFromBoundaryCodes Whether to exclude boundary name at last + * @param childParentMap Map of child to parent elements + * @param elementCodesMap Map of elements to their codes * @returns Generated element code */ -function generateElementCode(sequence: any, parentCode: any, element: any) { +function generateElementCode(sequence: any, parentElement: any, parentBoundaryCode: any, element: any, excludeBoundaryNameAtLastFromBoundaryCodes?: any, childParentMap?: any, elementCodesMap?: any) { // Pad single-digit numbers with leading zero - let paddedSequence = sequence.toString().padStart(2, "0"); - const code = parentCode.toUpperCase() + - "_" + - paddedSequence + - "_" + - element.toUpperCase(); - return ( - code.trim() - ); + const paddedSequence = sequence.toString().padStart(2, "0"); + let code; + + if (excludeBoundaryNameAtLastFromBoundaryCodes) { + code = `${parentBoundaryCode.toUpperCase()}_${paddedSequence}`; + } else { + const grandParentElement = findMapValue(childParentMap, parentElement); + if (grandParentElement != null && grandParentElement != undefined) { + const lastUnderscoreIndex = parentBoundaryCode ? parentBoundaryCode.lastIndexOf('_') : -1; + const parentBoundaryCodeTrimmed = lastUnderscoreIndex !== -1 ? parentBoundaryCode.substring(0, lastUnderscoreIndex) : parentBoundaryCode; + code = `${parentBoundaryCodeTrimmed.toUpperCase()}_${paddedSequence}_${element.toString().toUpperCase()}`; + } else { + code = `${parentBoundaryCode.toUpperCase()}_${paddedSequence}_${element.toString().toUpperCase()}`; + } + } + + return code.trim(); } /** @@ -637,21 +691,35 @@ async function getBoundarySheetData( headers ); } else { - // logger.info("boundaryData for sheet " + JSON.stringify(boundaryData)) - const responseFromCampaignSearch = - await getCampaignSearchResponse(request); - const FiltersFromCampaignId = getFiltersFromCampaignSearchResponse(responseFromCampaignSearch) - if (FiltersFromCampaignId?.Filters != null) { + let Filters: any = {}; + if (request?.body?.Filters && request?.body?.Filters.boundaries && Array.isArray(request?.body?.Filters.boundaries) && request?.body?.Filters.boundaries.length > 0) { + Filters = { + Filters: { + boundaries: request.body.Filters.boundaries.map((boundary: any) => ({ + ...boundary, + boundaryType: boundary.type // Adding boundaryType field + })) + } + }; + } + else { + // logger.info("boundaryData for sheet " + JSON.stringify(boundaryData)) + const responseFromCampaignSearch = + await getCampaignSearchResponse(request); + Filters = getFiltersFromCampaignSearchResponse(responseFromCampaignSearch) + } + if (Filters?.Filters && Filters.Filters.boundaries && Array.isArray(Filters.Filters.boundaries) && Filters.Filters.boundaries.length > 0) { const filteredBoundaryData = await generateFilteredBoundaryData( request, - FiltersFromCampaignId + Filters ); return await getDataSheetReady( filteredBoundaryData, request, localizationMap ); - } else { + } + else { return await getDataSheetReady(boundaryData, request, localizationMap); } } @@ -671,8 +739,7 @@ async function createStaff(resouceBody: any) { undefined, undefined, undefined, - false, - true + false ); logger.info("Project Staff mapping created"); logger.debug( @@ -700,8 +767,7 @@ async function createProjectResource(resouceBody: any) { undefined, undefined, undefined, - false, - true + false ); logger.debug("Project Resource Created"); logger.debug( @@ -729,8 +795,7 @@ async function createProjectFacility(resouceBody: any) { undefined, undefined, undefined, - false, - true + false ); logger.info("Project Facility Created"); logger.debug( @@ -792,32 +857,31 @@ const createProjectFacilityHelper = (resourceId: any, projectId: any, resouceBod * @param resouceBody The resource body. */ async function createRelatedEntity( - resources: any, - tenantId: any, - projectId: any, - startDate: any, - endDate: any, - resouceBody: any + createRelatedEntityArray: any[], + CampaignDetails: any, + requestBody: any ) { - // Array to hold all promises - const promises = []; - - // Create related entities - for (const resource of resources) { - const type = resource?.type; - for (const resourceId of resource?.resourceIds) { - logger.info(`creating project ${type} mapping for project : ${projectId} and resourceId ${resourceId}`); - if (type === "staff") { - promises.push(createStaffHelper(resourceId, projectId, resouceBody, tenantId, startDate, endDate)); - } else if (type === "resource") { - promises.push(createProjectResourceHelper(resourceId, projectId, resouceBody, tenantId, startDate, endDate)); - } else if (type === "facility") { - promises.push(createProjectFacilityHelper(resourceId, projectId, resouceBody, tenantId)); + const mappingArray = [] + for (const entity of createRelatedEntityArray) { + const { tenantId, projectId, startDate, endDate, resouceBody, campaignId, resources } = entity + for (const resource of resources) { + const type = resource?.type; + const mappingObject: any = { + type, + tenantId, + resource, + projectId, + startDate, + endDate, + resouceBody, + campaignId, + CampaignDetails } + mappingArray.push(mappingObject) } } - // Wait for all promises to complete - await Promise.all(promises); + const mappingObject: any = { mappingArray: mappingArray, CampaignDetails: CampaignDetails, RequestInfo: requestBody?.RequestInfo } + await processMapping(mappingObject) } @@ -827,32 +891,34 @@ async function createRelatedEntity( */ async function createRelatedResouce(requestBody: any) { const id = requestBody?.Campaign?.id; - const campaignDetails = await validateMappingId(requestBody, id); - if (campaignDetails?.status == campaignStatuses.inprogress) { - logger.info("Campaign Already In Progress and Mapped"); - } else { - sortCampaignDetails(requestBody?.Campaign?.CampaignDetails); - correctParentValues(requestBody?.Campaign?.CampaignDetails); - // Create related resources - const { tenantId } = requestBody?.Campaign; - - for (const campaignDetails of requestBody?.Campaign?.CampaignDetails) { - const resouceBody: any = { - RequestInfo: requestBody.RequestInfo, - }; - var { projectId, startDate, endDate, resources } = campaignDetails; - startDate = parseInt(startDate); - endDate = parseInt(endDate); - await createRelatedEntity( - resources, - tenantId, - projectId, - startDate, - endDate, - resouceBody - ); - } + sortCampaignDetails(requestBody?.Campaign?.CampaignDetails); + correctParentValues(requestBody?.Campaign?.CampaignDetails); + // Create related resources + const { tenantId } = requestBody?.Campaign; + const createRelatedEntityArray = []; + for (const campaignDetails of requestBody?.Campaign?.CampaignDetails) { + const resouceBody: any = { + RequestInfo: requestBody.RequestInfo, + }; + var { projectId, startDate, endDate, resources } = campaignDetails; + campaignDetails.id = id; + startDate = parseInt(startDate); + endDate = parseInt(endDate); + createRelatedEntityArray.push({ + resources, + tenantId, + projectId, + startDate, + endDate, + resouceBody, + campaignId: id, + }); } + await createRelatedEntity( + createRelatedEntityArray, + requestBody?.CampaignDetails, + requestBody + ); } /** @@ -1006,7 +1072,7 @@ async function createBoundaryRelationship(request: any, boundaryMap: Map<{ key: logger.info(`Boundary relationship created for boundaryType :: ${boundaryType} & boundaryCode :: ${boundaryCode} `); const newRequestBody = JSON.parse(JSON.stringify(request.body)); - activityMessage.push(await generateActivityMessage(request?.body?.ResourceDetails?.tenantId, request.body, newRequestBody, response, request?.body?.ResourceDetails?.type, url, response?.statusCode)); + activityMessage.push(await generateActivityMessage(request?.body?.ResourceDetails?.tenantId, request.body, newRequestBody, response, request?.body?.ResourceDetails?.type, `${config.host.boundaryHost}${config.paths.boundaryRelationshipCreate}`, response?.statusCode)); } catch (error) { // Log the error and rethrow to be caught by the outer try...catch block logger.error(`Error creating boundary relationship for boundaryType :: ${boundaryType} & boundaryCode :: ${boundaryCode} :: `, error); @@ -1187,5 +1253,8 @@ export { getTargetSheetDataAfterCode, callMdmsData, getMDMSV1Data, - callMdmsTypeSchema -} + callMdmsTypeSchema, + getSheetDataFromWorksheet, + createStaffHelper, + createProjectFacilityHelper, createProjectResourceHelper +}; diff --git a/health-services/project-factory/src/server/config/constants.ts b/health-services/project-factory/src/server/config/constants.ts index fffa89a7c87..5023c9de00b 100644 --- a/health-services/project-factory/src/server/config/constants.ts +++ b/health-services/project-factory/src/server/config/constants.ts @@ -10,7 +10,8 @@ export const CONSTANTS: any = { INVALID_PAGINATION: "Invalid pagination", KAFKA_ERROR: "Some error occured in kafka", SCHEMA_ERROR: " Schema related error", - RESPONSE_NOT_FOUND_ERROR: "Response not found" + RESPONSE_NOT_FOUND_ERROR: "Response not found", + GENERATE_ERROR: "Error while generating user/facility/boundary" }, FILE: { INVALID_FILE: "No download URL returned for the given fileStoreId", @@ -32,7 +33,8 @@ export const CONSTANTS: any = { CAMPAIGN_NOT_FOUND: "Campaign not found", GENERATION_REQUIRE: "First generate then download", RESOURCE_CREATION_ERROR: "Some error occured during resource creation", - CAMPAIGN_NAME_ERROR: "Campaign name already exists" + CAMPAIGN_NAME_ERROR: "Campaign name already exists", + CAMPAIGN_ALREADY_MAPPED: "Campaign is already mapped", }, BOUNDARY: { BOUNDARY_DATA_NOT_FOUND: "No boundary data found in the system.", @@ -108,6 +110,41 @@ export const generatedResourceStatuses: any = { expired: "expired" } +export const processTrackTypes = { + validation: "validation", + triggerResourceCreation: "trigger-resource-creation", + facilityCreation: "facility-creation", + staffCreation: "staff-creation", + targetAndDeliveryRulesCreation: "target-and-delivery-rules-creation", + confirmingResourceCreation: "confirming-resource-creation", + prepareResourceForMapping: "prepare-resource-for-mapping", + validateMappingResource: "validate-mapping-resource", + staffMapping: "staff-mapping", + resourceMapping: "resource-mapping", + facilityMapping: "facility-mapping", + campaignCreation: "campaign-creation", + error: "error" +} + +export const processTrackForUi = [ + processTrackTypes.facilityCreation, + processTrackTypes.staffCreation, + processTrackTypes.targetAndDeliveryRulesCreation, + processTrackTypes.staffMapping, + processTrackTypes.resourceMapping, + processTrackTypes.facilityMapping, + processTrackTypes.campaignCreation, + processTrackTypes.error +]; + + +export const processTrackStatuses = { + inprogress: "inprogress", + completed: "completed", + toBeCompleted: "toBeCompleted", + failed: "failed", +} + // Retrieves the error object containing the error code, message, and notFound flag. export const getErrorCodes = (module: string, key: string): Error => { diff --git a/health-services/project-factory/src/server/config/createAndSearch.ts b/health-services/project-factory/src/server/config/createAndSearch.ts index d89c45b7606..8fb63b1be9f 100644 --- a/health-services/project-factory/src/server/config/createAndSearch.ts +++ b/health-services/project-factory/src/server/config/createAndSearch.ts @@ -132,6 +132,138 @@ const createAndSearch: any = { searchPath: "Facilities" } }, + "facilityMicroplan": { + requiresToSearchFromSheet: [ + { + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CODE", + searchPath: "Facility.id" + } + ], + boundaryValidation: { + column: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE_MANDATORY" + }, + sheetSchema: { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "FacilityTemplateSchema", + "type": "object", + "properties": { + "Facility Name": { + "type": "string", + "maxLength": 2000, + "minLength": 1 + }, + "Facility Type": { + // "type": "string", + "enum": ["Warehouse", "Health Facility", "Storing Resource"] + }, + "Facility Status": { + // "type": "string", + "enum": ["Temporary", "Permanent"] + }, + "Capacity": { + "type": "number", + "minimum": 1, + "maximum": 100000000 + } + }, + "required": [ + "Facility Name", + "Facility Type", + "Facility Status", + "Capacity" + ], + "unique": [ + "Facility Name" + ] + }, + uniqueIdentifier: "id", + uniqueIdentifierColumn: "A", + activeColumn: "F", + activeColumnName: "HCM_ADMIN_CONSOLE_FACILITY_USAGE_MICROPLAN", + uniqueIdentifierColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CODE", + matchEachKey: true, + parseArrayConfig: { + sheetName: "HCM_ADMIN_CONSOLE_FACILITIES", + parseLogic: [ + { + sheetColumn: "A", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CODE", + resultantPath: "id", + type: "string" + }, + { + sheetColumn: "B", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_NAME_MICROPLAN", + resultantPath: "name", + type: "string" + }, + { + sheetColumn: "C", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_TYPE_MICROPLAN", + resultantPath: "usage", + type: "string" + }, + { + sheetColumn: "D", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_STATUS_MICROPLAN", + resultantPath: "isPermanent", + type: "boolean", + conversionCondition: { + "Permanent": "true", + "Temporary": "" + } + }, + { + sheetColumn: "E", + sheetColumnName: "HCM_ADMIN_CONSOLE_FACILITY_CAPACITY_MICROPLAN", + resultantPath: "storageCapacity", + type: "number" + }, + { + sheetColumn: "J", + sheetColumnName: "HCM_ADMIN_CONSOLE_RESIDING_BOUNDARY_CODE_MICROPLAN" + } + ], + tenantId: { + getValueViaPath: "ResourceDetails.tenantId", + resultantPath: "tenantId" + } + }, + createBulkDetails: { + limit: 50, + createPath: "Facilities", + url: config.host.facilityHost + "facility/v1/bulk/_create" + }, + searchDetails: { + searchElements: [ + { + keyPath: "tenantId", + getValueViaPath: "ResourceDetails.tenantId", + isInParams: true, + isInBody: false, + }, + { + keyPath: "Facility", + isInParams: false, + isInBody: true, + } + ], + searchLimit: { + keyPath: "limit", + value: "200", + isInParams: true, + isInBody: false, + }, + searchOffset: { + keyPath: "offset", + value: "0", + isInParams: true, + isInBody: false, + }, + url: config.host.facilityHost + "facility/v1/_search", + searchPath: "Facilities" + } + }, "boundary": { parseArrayConfig: { sheetName: "HCM_ADMIN_CONSOLE_BOUNDARY_CODE", diff --git a/health-services/project-factory/src/server/config/index.ts b/health-services/project-factory/src/server/config/index.ts index 07286afac9e..7260b93c59d 100644 --- a/health-services/project-factory/src/server/config/index.ts +++ b/health-services/project-factory/src/server/config/index.ts @@ -16,7 +16,14 @@ const getDBSchemaName = (dbSchema = "") => { } // Configuration object containing various environment variables const config = { + cacheTime : 300, + enableDynamicTemplateFor: process.env.ENABLE_DYNAMIC_TEMPLATE_FOR || "", + isCallGenerateWhenDeliveryConditionsDiffer: (process.env.IS_CALL_GENERATE_WHEN_DELIVERY_CONDITIONS_DIFFER === "true") || false, + prefixForMicroplanCampaigns: "MP", + excludeHierarchyTypeFromBoundaryCodes: (process.env.EXCLUDE_HIERARCHY_TYPE_FROM_BOUNDARY_CODES === "true") || false, + excludeBoundaryNameAtLastFromBoundaryCodes: (process.env.EXCLUDE_BOUNDARY_NAME_AT_LAST_FROM_BOUNDARY_CODES === "true") || false, masterNameForSchemaOfColumnHeaders: "adminSchema", + masterNameForSplitBoundariesOn: "hierarchyConfig", boundary: { boundaryCode: process.env.BOUNDARY_CODE_HEADER_NAME || "HCM_ADMIN_CONSOLE_BOUNDARY_CODE", boundaryTab: process.env.BOUNDARY_TAB_NAME || "HCM_ADMIN_CONSOLE_BOUNDARY_DATA", @@ -35,6 +42,7 @@ const config = { userSchemaMasterName: process.env.USER_SCHEMA_MASTER || "userSchema", userDefaultPassword: process.env.USER_DEFAULT_PASSWORD || "eGov@123", userPasswordAutoGenerate: process.env.USER_PASSWORD_AUTO_GENERATE || "true", + mapUserViaCommonParent: process.env.MAP_USER_VIA_COMMON_PARENT || false, }, cacheValues: { cacheEnabled: process.env.CACHE_ENABLED, @@ -44,7 +52,7 @@ const config = { kafka: { // Kafka topics KAFKA_SAVE_PROJECT_CAMPAIGN_DETAILS_TOPIC: process.env.KAFKA_SAVE_PROJECT_CAMPAIGN_DETAILS_TOPIC || "save-project-campaign-details", - KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC: process.env.KAFKA_SAVE_PROJECT_CAMPAIGN_DETAILS_TOPIC || "update-project-campaign-details", + KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC: process.env.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC || "update-project-campaign-details", KAFKA_START_CAMPAIGN_MAPPING_TOPIC: process.env.KAFKA_START_CAMPAIGN_MAPPING_TOPIC || "start-campaign-mapping", KAFKA_UPDATE_CAMPAIGN_DETAILS_TOPIC: process.env.KAFKA_UPDATE_CAMPAIGN_DETAILS_TOPIC || "update-campaign-details", KAFKA_CREATE_RESOURCE_DETAILS_TOPIC: process.env.KAFKA_CREATE_RESOURCE_DETAILS_TOPIC || "create-resource-details", @@ -54,6 +62,7 @@ const config = { KAFKA_CREATE_GENERATED_RESOURCE_DETAILS_TOPIC: process.env.KAFKA_CREATE_GENERATED_RESOURCE_DETAILS_TOPIC || "create-generated-resource-details", KAFKA_SAVE_PROCESS_TRACK_TOPIC: process.env.KAFKA_SAVE_PROCESS_TRACK_TOPIC || "save-process-track", KAFKA_UPDATE_PROCESS_TRACK_TOPIC: process.env.KAFKA_UPDATE_PROCESS_TRACK_TOPIC || "update-process-track", + KAFKA_TEST_TOPIC: "test-topic-project-factory", }, // Database configuration diff --git a/health-services/project-factory/src/server/config/models/createRequestSchema.ts b/health-services/project-factory/src/server/config/models/createRequestSchema.ts index ed56e706d16..18a96101fbd 100644 --- a/health-services/project-factory/src/server/config/models/createRequestSchema.ts +++ b/health-services/project-factory/src/server/config/models/createRequestSchema.ts @@ -4,7 +4,7 @@ export const createRequestSchema = { "properties": { "type": { "type": "string", - "enum": ["boundary", "facility", "user", "boundaryWithTarget"] + "enum": ["boundary", "facility", "user", "boundaryWithTarget","facilityMicroplan"] }, "tenantId": { "type": "string", diff --git a/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts b/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts index b47e714dac5..d23b7df2f4f 100644 --- a/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts +++ b/health-services/project-factory/src/server/config/models/downloadRequestSchema.ts @@ -5,7 +5,7 @@ export const downloadRequestSchema = { "tenantId": { "type": "string", "maxLength": 128, - "minLength": 1, + "minLength": 1 }, "type": { "type": "string", @@ -22,14 +22,24 @@ export const downloadRequestSchema = { "hierarchyType": { "type": "string", "maxLength": 128, - "minLength": 1, + "minLength": 1 }, "id": { "type": "string", - "maxlength": 128, - "minLength": 1, + "maxLength": 128, + "minLength": 1 + }, + "status": { + "type": "string", + "maxLength": 500, + "minLength": 1 + }, + "campaignId": { + "type": "string", + "maxLength": 128, + "minLength": 1 } }, "required": ["tenantId", "type", "hierarchyType"], "additionalProperties": false -} \ No newline at end of file +} \ No newline at end of file diff --git a/health-services/project-factory/src/server/config/models/generateRequestSchema.ts b/health-services/project-factory/src/server/config/models/generateRequestSchema.ts index cc1df4b70e6..4ca530f9393 100644 --- a/health-services/project-factory/src/server/config/models/generateRequestSchema.ts +++ b/health-services/project-factory/src/server/config/models/generateRequestSchema.ts @@ -12,8 +12,6 @@ export const generateRequestSchema = { "maxLength": 128, "minLength": 1, "enum": [ - "facility", - "user", "boundary", "facilityWithBoundary", "userWithBoundary" diff --git a/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts b/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts index 384735fb683..dc3232294e2 100644 --- a/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts +++ b/health-services/project-factory/src/server/controllers/campaignManage/campaignManage.controller.ts @@ -1,5 +1,5 @@ import * as express from "express"; -import { createCampaignService, createProjectTypeCampaignService, searchProjectTypeCampaignService, updateProjectTypeCampaignService } from "../../service/campaignManageService"; +import { createCampaignService, createProjectTypeCampaignService, searchProcessTracksService, searchProjectTypeCampaignService, updateProjectTypeCampaignService } from "../../service/campaignManageService"; import { logger } from "../../utils/logger"; import { errorResponder, sendResponse } from "../../utils/genericUtils"; @@ -23,6 +23,7 @@ class campaignManageController { this.router.post(`${this.path}/update`, this.updateProjectTypeCampaign); this.router.post(`${this.path}/search`, this.searchProjectTypeCampaign); this.router.post(`${this.path}/createCampaign`, this.createCampaign); + this.router.post(`${this.path}/getProcessTrack`, this.searchProcessTracks); } /** * Handles the creation of a project type campaign. @@ -111,6 +112,24 @@ class campaignManageController { } }; + searchProcessTracks = async ( + request: express.Request, + response: express.Response + ) => { + try { + logger.info("RECEIVED A PROCESS SEARCH REQUEST"); + const processTrack = await searchProcessTracksService(request); + // Send response with campaign details + return sendResponse(response, { processTrack }, request); + } + catch (e: any) { + console.log(e) + logger.error(String(e)) + // Handle errors and send error response + return errorResponder({ message: String(e), code: e?.code, description: e?.description }, request, response, e?.status || 500); + } + }; + }; export default campaignManageController; diff --git a/health-services/project-factory/src/server/kafka/Listener.ts b/health-services/project-factory/src/server/kafka/Listener.ts index ac91786b621..128f99c08cb 100644 --- a/health-services/project-factory/src/server/kafka/Listener.ts +++ b/health-services/project-factory/src/server/kafka/Listener.ts @@ -1,105 +1,55 @@ -import { Message ,ConsumerGroup, ConsumerGroupOptions} from 'kafka-node'; +import { ConsumerGroup, ConsumerGroupOptions, Message } from 'kafka-node'; import config from '../config'; -import { getFormattedStringForDebug, logger } from '../utils/logger'; // Importing logger utility for logging -import { producer } from './Producer'; // Importing producer from the Producer module -import { processCampaignMapping } from '../utils/campaignMappingUtils'; -import { enrichAndPersistCampaignWithError } from '../utils/campaignUtils'; -import { throwError } from '../utils/genericUtils'; +import { getFormattedStringForDebug, logger } from '../utils/logger'; +import { shutdownGracefully } from '../utils/genericUtils'; +import { handleCampaignMapping } from '../utils/campaignMappingUtils'; - - -// Replace with the correct Kafka broker(s) and topic name -const kafkaConfig:ConsumerGroupOptions = { - kafkaHost: config?.host?.KAFKA_BROKER_HOST, // Use the correct broker address and port +// Kafka Configuration +const kafkaConfig: ConsumerGroupOptions = { + kafkaHost: config?.host?.KAFKA_BROKER_HOST, groupId: 'project-factory', autoCommit: true, autoCommitIntervalMs: 5000, fromOffset: 'latest', - }; -const topicName = config?.kafka?.KAFKA_START_CAMPAIGN_MAPPING_TOPIC; - -// Create a Kafka client -// const kafkaClient = new KafkaClient(kafkaConfig); - -// Create a Kafka consumer -// const consumer = new Consumer(kafkaClient, [{ topic: topicName, partition: 0 }], { autoCommit: true }); - +// Topic Names +const topicNames = [ + config.kafka.KAFKA_START_CAMPAIGN_MAPPING_TOPIC, + config.kafka.KAFKA_TEST_TOPIC +]; -const consumerGroup=new ConsumerGroup(kafkaConfig, topicName) +// Consumer Group Initialization +const consumerGroup = new ConsumerGroup(kafkaConfig, topicNames); -// Exported listener function +// Kafka Listener export function listener() { - // Set up a message event handler consumerGroup.on('message', async (message: Message) => { try { - // Parse the message value as an array of objects - const messageObject: any = JSON.parse(message.value?.toString() || '{}'); - try { - // await processCampaignMapping(messageObject); - logger.info("Received a messageObject for campaign mapping : "); - logger.debug("Message Object of campaign mapping :: " + getFormattedStringForDebug(messageObject)); - await processCampaignMapping(messageObject); - } catch (error: any) { - console.log(error) - logger.error(error) - enrichAndPersistCampaignWithError(messageObject, error) + const messageObject = JSON.parse(message.value?.toString() || '{}'); + + switch (message.topic) { + case config.kafka.KAFKA_START_CAMPAIGN_MAPPING_TOPIC: + await handleCampaignMapping(messageObject); + break; + default: + logger.warn(`Unhandled topic: ${message.topic}`); } - logger.info(`KAFKA :: LISTENER :: Received a message`); - logger.debug(`KAFKA :: LISTENER :: message ${getFormattedStringForDebug(messageObject)}`); + + logger.info(`KAFKA :: LISTENER :: Received a message from topic ${message.topic}`); + logger.debug(`KAFKA :: LISTENER :: Message: ${getFormattedStringForDebug(messageObject)}`); } catch (error) { - logger.info('KAFKA :: LISTENER :: Some Error Occurred '); // Log successful message production - logger.error(`KAFKA :: LISTENER :: Error : ${JSON.stringify(error)}`); // Log producer error - console.log(error) + logger.error(`KAFKA :: LISTENER :: Error processing message: ${error}`); + console.error(error); } }); - // Set up error event handlers consumerGroup.on('error', (err) => { - console.error(`Consumer Error: ${err}`); + logger.error(`Consumer Error: ${err}`); + shutdownGracefully(); }); consumerGroup.on('offsetOutOfRange', (err) => { - console.error(`Offset out of range error: ${err}`); + logger.error(`Offset out of range error: ${err}`); }); } - - -/** - * Produces modified messages to a specified Kafka topic. - * @param modifiedMessages An array of modified messages to be produced. - * @param topic The Kafka topic to which the messages will be produced. - * @returns A promise that resolves when the messages are successfully produced. - */ -async function produceModifiedMessages(modifiedMessages: any[], topic: any) { - try { - logger.info(`KAFKA :: PRODUCER :: a message sent to topic ${topic}`); - logger.debug(`KAFKA :: PRODUCER :: message ${getFormattedStringForDebug(modifiedMessages)}`); - return new Promise((resolve, reject) => { - const payloads = [ - { - topic: topic, - messages: JSON.stringify(modifiedMessages), // Convert modified messages to JSON string - }, - ]; - - // Send payloads to the Kafka producer - producer.send(payloads, (err) => { - if (err) { - logger.info('KAFKA :: PRODUCER :: Some Error Occurred '); - logger.error(`KAFKA :: PRODUCER :: Error : ${JSON.stringify(err)}`); - // reject(err); // Reject promise if there's an error - } else { - logger.info('KAFKA :: PRODUCER :: message sent successfully '); - // resolve(); // Resolve promise if messages are successfully produced - } - }); - }); - } catch (error) { - logger.error(`KAFKA :: PRODUCER :: Exception caught: ${JSON.stringify(error)}`); - throwError("COMMON", 400, "KAKFA_ERROR", "Some error occured in kafka"); // Re-throw the error after logging it - } -} - -export { produceModifiedMessages } // Export the produceModifiedMessages function for external use diff --git a/health-services/project-factory/src/server/kafka/Producer.ts b/health-services/project-factory/src/server/kafka/Producer.ts index b728b48a2ca..dc19acc2fa1 100644 --- a/health-services/project-factory/src/server/kafka/Producer.ts +++ b/health-services/project-factory/src/server/kafka/Producer.ts @@ -1,25 +1,111 @@ -import config from '../config'; // Importing configuration settings -import { Producer, KafkaClient } from 'kafka-node'; // Importing Producer and KafkaClient from 'kafka-node' library +import { Producer, KafkaClient } from 'kafka-node'; import { logger } from "../utils/logger"; +import { shutdownGracefully, throwError } from '../utils/genericUtils'; +import config from '../config'; -// Creating a new Kafka client instance using the configured Kafka broker host -const kafkaClient = new KafkaClient({ - kafkaHost: config?.host?.KAFKA_BROKER_HOST, // Configuring Kafka broker host - connectRetryOptions: { retries: 1 }, // Configuring connection retry options -}); +let kafkaClient: KafkaClient; +let producer: Producer; -// Creating a new Kafka producer instance using the Kafka client -const producer = new Producer(kafkaClient, { partitionerType: 2 }); // Using partitioner type 2 +const createKafkaClientAndProducer = () => { + kafkaClient = new KafkaClient({ + kafkaHost: config?.host?.KAFKA_BROKER_HOST, + connectRetryOptions: { retries: 1 }, + }); -// Event listener for 'ready' event, indicating that the producer is ready to send messages -producer.on('ready', () => { - logger.info('Producer is ready'); // Log message indicating producer is ready -}); + // Event listener for 'error' event, indicating that the client encountered an error + kafkaClient.on('error', (err: any) => { + logger.error('Kafka client is in error state'); // Log message indicating client is in error state + console.error(err.stack || err); // Log the error stack or message + shutdownGracefully(); + }); -// Event listener for 'error' event, indicating that the producer encountered an error -producer.on('error', (err) => { - logger.error('Producer is in error state'); // Log message indicating producer is in error state - console.error(err.stack || err); // Log the error stack or message -}); + producer = new Producer(kafkaClient, { partitionerType: 2 }); -export { producer }; // Exporting the producer instance for external use + producer.on('ready', () => { + logger.info('Producer is ready'); + checkBrokerAvailability(); + }); + + producer.on('error', (err: any) => { + logger.error('Producer is in error state'); + console.error(err); + shutdownGracefully(); + }); +}; + +// Function to check broker availability by listing all brokers +const checkBrokerAvailability = () => { + kafkaClient.loadMetadataForTopics([], (err: any, data: any) => { + if (err) { + logger.error('Error checking broker availability:', err); + shutdownGracefully(); + } else { + const brokers = data[1]?.metadata || {}; + const brokerCount = Object.keys(brokers).length; + logger.info('Broker count:' + String(brokerCount)); + + if (brokerCount <= 0) { + logger.error('No brokers found. Shutting down the service.'); + shutdownGracefully(); + } else { + logger.info('Brokers are available:', brokers); + } + } + }); +}; + + +createKafkaClientAndProducer(); + +const sendWithRetries = (payloads: any[], retries = 3, shutdown: boolean = false): Promise => { + return new Promise((resolve, reject) => { + producer.send(payloads, async (err: any) => { + if (err) { + logger.error('Error sending message:', err); + logger.debug(`Was trying to send: ${JSON.stringify(payloads)}`); + if (retries > 0) { + logger.info(`Retrying to send message. Retries left: ${retries}`); + await new Promise(resolve => setTimeout(resolve, 2000)); // wait before retrying + resolve(sendWithRetries(payloads, retries - 1, shutdown)); + } else { + // Attempt to reconnect and retry + logger.error('Failed to send message after retries. Reconnecting producer...'); + if (shutdown) { + shutdownGracefully(); + } + else { + producer.close(() => { + createKafkaClientAndProducer(); + setTimeout(() => { + sendWithRetries(payloads, 1, true).catch(reject); + }, 2000); // wait before retrying after reconnect + }); + } + } + } else { + logger.info('Message sent successfully'); + resolve(); + } + }); + }); +}; + +async function produceModifiedMessages(modifiedMessages: any[], topic: any) { + try { + logger.info(`KAFKA :: PRODUCER :: A message sent to topic ${topic}`); + logger.debug(`KAFKA :: PRODUCER :: Message ${JSON.stringify(modifiedMessages)}`); + const payloads = [ + { + topic: topic, + messages: JSON.stringify(modifiedMessages), + }, + ]; + + await sendWithRetries(payloads, 3); + } catch (error) { + logger.error(`KAFKA :: PRODUCER :: Exception caught: ${JSON.stringify(error)}`); + throwError("COMMON", 400, "KAFKA_ERROR", "Some error occurred in Kafka"); // Re-throw the error after logging it + } +} + +export { produceModifiedMessages }; diff --git a/health-services/project-factory/src/server/service/campaignManageService.ts b/health-services/project-factory/src/server/service/campaignManageService.ts index 3d3652bb441..4b397e8b28f 100644 --- a/health-services/project-factory/src/server/service/campaignManageService.ts +++ b/health-services/project-factory/src/server/service/campaignManageService.ts @@ -1,10 +1,11 @@ import express from "express"; import { processBasedOnAction, searchProjectCampaignResourcData } from "../utils/campaignUtils"; import { logger } from "../utils/logger"; -import { validateProjectCampaignRequest, validateSearchProjectCampaignRequest } from "../validators/campaignValidators"; +import { validateProjectCampaignRequest, validateSearchProcessTracksRequest, validateSearchProjectCampaignRequest } from "../validators/campaignValidators"; import { validateCampaignRequest } from "../validators/genericValidator"; import { createRelatedResouce } from "../api/genericApis"; import { enrichCampaign } from "../api/campaignApis"; +import { getProcessDetails, modifyProcessDetails } from "../utils/processTrackUtils"; async function createProjectTypeCampaignService(request: express.Request) { // Validate the request for creating a project type campaign @@ -53,10 +54,26 @@ async function createCampaignService( return requestBody?.Campaign }; +async function searchProcessTracksService( + request: express.Request +) { + await validateSearchProcessTracksRequest(request) + logger.info("VALIDATED THE PROCESS SEARCH REQUEST"); + + // Search and return related process tracks + const processDetailsArray = await getProcessDetails(request?.query?.campaignId as string) + + // sort and modify process details so that details with status as toBeCompleted comes in last + const resultArray = modifyProcessDetails(processDetailsArray) + + return resultArray +}; + export { createProjectTypeCampaignService, updateProjectTypeCampaignService, searchProjectTypeCampaignService, - createCampaignService -} \ No newline at end of file + createCampaignService, + searchProcessTracksService +} diff --git a/health-services/project-factory/src/server/service/dataManageService.ts b/health-services/project-factory/src/server/service/dataManageService.ts index ed224dc824f..f6ad7105f65 100644 --- a/health-services/project-factory/src/server/service/dataManageService.ts +++ b/health-services/project-factory/src/server/service/dataManageService.ts @@ -3,12 +3,15 @@ import { processGenericRequest } from "../api/campaignApis"; import { createAndUploadFile, getBoundarySheetData } from "../api/genericApis"; import { getLocalizedName, processDataSearchRequest } from "../utils/campaignUtils"; import { addDataToSheet, enrichResourceDetails, getLocalizedMessagesHandler, searchGeneratedResources, processGenerate, throwError } from "../utils/genericUtils"; -import { logger } from "../utils/logger"; +import { getFormattedStringForDebug, logger } from "../utils/logger"; import { validateCreateRequest, validateDownloadRequest, validateSearchRequest } from "../validators/campaignValidators"; import { validateGenerateRequest } from "../validators/genericValidator"; import { getLocalisationModuleName } from "../utils/localisationUtils"; import { getBoundaryTabName } from "../utils/boundaryUtils"; import { getNewExcelWorkbook } from "../utils/excelUtils"; +import { redis, checkRedisConnection } from "../utils/redisUtils"; // Importing checkRedisConnection function +import config from '../config/index' + const generateDataService = async (request: express.Request) => { @@ -38,24 +41,48 @@ const downloadDataService = async (request: express.Request) => { } const getBoundaryDataService = async ( - request: express.Request) => { + request: express.Request, enableCaching = false) => { try { + const { hierarchyType, campaignId } = request?.query; + const cacheTTL = config?.cacheTime; // TTL in seconds (5 minutes) + const cacheKey = `${campaignId}-${hierarchyType}`; + let isRedisConnected = false; + let cachedData: any = null; + if (cacheKey && enableCaching) { + isRedisConnected = await checkRedisConnection(); + cachedData = await redis.get(cacheKey); // Get cached data + } + if (cachedData) { + logger.info("CACHE HIT :: " + cacheKey); + logger.debug(`CACHED DATA :: ${getFormattedStringForDebug(cachedData)}`); + + // Reset the TTL for the cache key + if (config.cacheValues.resetCache) { + await redis.expire(cacheKey, cacheTTL); + } + + return JSON.parse(cachedData); // Return parsed cached data if available + } else { + logger.info("NO CACHE FOUND :: REQUEST :: " + cacheKey); + } const workbook = getNewExcelWorkbook(); - const { hierarchyType } = request?.query; const localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler(request, request?.query?.tenantId, getLocalisationModuleName(hierarchyType)); const localizationMapModule = await getLocalizedMessagesHandler(request, request?.query?.tenantId); const localizationMap = { ...localizationMapHierarchy, ...localizationMapModule }; // Retrieve boundary sheet data const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); - const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap); const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); addDataToSheet(boundarySheet, boundarySheetData); - const BoundaryFileDetails: any = await createAndUploadFile(workbook, request); + const boundaryFileDetails: any = await createAndUploadFile(workbook, request); // Return boundary file details logger.info("RETURNS THE BOUNDARY RESPONSE"); - return BoundaryFileDetails; + if (cacheKey && isRedisConnected) { + await redis.set(cacheKey, JSON.stringify(boundaryFileDetails), "EX", cacheTTL); // Cache the response data with TTL + } + return boundaryFileDetails; } catch (e: any) { + console.log(e) logger.error(String(e)) // Handle errors and send error response throw (e); diff --git a/health-services/project-factory/src/server/utils/campaignMappingUtils.ts b/health-services/project-factory/src/server/utils/campaignMappingUtils.ts index ac34761d2f8..f4698f4b77d 100644 --- a/health-services/project-factory/src/server/utils/campaignMappingUtils.ts +++ b/health-services/project-factory/src/server/utils/campaignMappingUtils.ts @@ -1,12 +1,15 @@ import createAndSearch from "../config/createAndSearch"; import config from "../config"; -import { getDataFromSheet, throwError } from "./genericUtils"; +import { getDataFromSheet, getLocalizedMessagesHandlerViaRequestInfo, throwError } from "./genericUtils"; import { getFormattedStringForDebug, logger } from "./logger"; -import { httpRequest } from "./request"; -import { produceModifiedMessages } from "../kafka/Listener"; -import { getLocalizedName } from "./campaignUtils"; +import { defaultheader, httpRequest } from "./request"; +import { produceModifiedMessages } from "../kafka/Producer"; +import { enrichAndPersistCampaignWithError, getLocalizedName } from "./campaignUtils"; import { campaignStatuses, resourceDataStatuses } from "../config/constants"; import { createCampaignService } from "../service/campaignManageService"; +import { persistTrack } from "./processTrackUtils"; +import { processTrackTypes, processTrackStatuses } from "../config/constants"; +import { createProjectFacilityHelper, createProjectResourceHelper, createStaffHelper } from "../api/genericApis"; async function createBoundaryWithProjectMapping(projects: any, boundaryWithProject: any) { @@ -36,8 +39,107 @@ function getPvarIds(messageObject: any) { return Array.from(uniquePvarIds); // Convert Set to array before returning } +function trimBoundaryCodes(root: any) { + if (root) { + root.code = root.code.trim(); // Trim the code + + // Recursively trim the codes in the children + for (const child of root.children) { + trimBoundaryCodes(child); + } + } +} + +async function getAllBoundaries(messageObject: any, tenantId: any, rootBoundary: any, hierarchyType: any) { + const BoundarySearchBody = { + RequestInfo: messageObject?.RequestInfo, + } + const params = { + tenantId, + codes: rootBoundary, + hierarchyType, + includeChildren: true + } + const header = { + ...defaultheader, + cachekey: `boundaryRelationShipSearch${params?.hierarchyType}${params?.tenantId}${params.codes || ''}${params?.includeChildren || ''}`, + } + const boundaryResponse = await httpRequest(config.host.boundaryHost + config.paths.boundaryRelationship, BoundarySearchBody, params, undefined, undefined, header); + trimBoundaryCodes(boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0]); + return boundaryResponse?.TenantBoundary?.[0]?.boundary?.[0] +} + +// Function to find the path to a given boundary code +function findPath(root: any, code: string, path: any[] = []) { + if (root.code === code) { + return [...path, root]; + } + for (const child of root.children) { + const result: any = findPath(child, code, [...path, root]); + if (result) return result; + } + return null; +} + +// Function to find the common parent for multiple codes +function findCommonParent(codes: string[], root: any) { + if (codes.length === 0) return null; + + // Find paths for all codes + const paths = codes.map(code => findPath(root, code)).filter(path => path !== null); + + if (paths.length === 0) return null; + + // Compare paths to find the common ancestor + let commonParent: any = null; + + for (let i = 0; i < Math.min(...paths.map(path => path.length)); i++) { + const currentParent = paths[0][i]; + if (paths.every(path => path[i] && path[i].code === currentParent.code)) { + commonParent = currentParent; + } else { + break; + } + } + + return commonParent?.code; +} + +function mapBoundaryCodes(resource: any, code: string, boundaryCode: string, boundaryCodes: any, allBoundaries: any) { + // Split boundary codes if they have comma separated values + const boundaryCodesArray = boundaryCode.split(',').map((bc: string) => bc.trim()); + if (resource?.type == "user" && boundaryCodesArray?.length > 1 && config.user.mapUserViaCommonParent) { + const commonParent = findCommonParent(boundaryCodesArray, allBoundaries); + if (commonParent) { + logger.info(`Boundary Codes Array ${boundaryCodesArray.join(",")} for resource ${resource?.type} has common parent ${commonParent}`) + if (!boundaryCodes[resource?.type]) { + boundaryCodes[resource?.type] = {}; + } + if (!boundaryCodes[resource?.type][commonParent]) { + boundaryCodes[resource?.type][commonParent] = []; + } + boundaryCodes[resource?.type][commonParent].push(code); + logger.info(`Common Parent Boundary code ${commonParent} mapped to resource ${resource?.type} with code ${code}`) + } + } + else { + boundaryCodesArray.forEach((trimmedBC: string) => { + // Trim any leading or trailing spaces + if (!boundaryCodes[resource?.type]) { + boundaryCodes[resource?.type] = {}; + } + if (!boundaryCodes[resource?.type][trimmedBC]) { + boundaryCodes[resource?.type][trimmedBC] = []; + } + boundaryCodes[resource?.type][trimmedBC].push(code); + logger.info(`Boundary code ${trimmedBC} mapped to resource ${resource?.type} with code ${code}`) + }); + } +} + async function enrichBoundaryCodes(resources: any[], messageObject: any, boundaryCodes: any, sheetName: any) { const localizationMap: any = messageObject?.localizationMap + const allBoundaries = await getAllBoundaries(messageObject, messageObject?.Campaign?.tenantId, messageObject?.Campaign?.boundaryCode, messageObject?.Campaign?.hierarchyType); for (const resource of resources) { const processedFilestoreId = resource?.processedFilestoreId; if (processedFilestoreId) { @@ -54,20 +156,7 @@ async function enrichBoundaryCodes(resources: any[], messageObject: any, boundar active = data[activeColumn]; } if (boundaryCode && active == "Active") { - // Split boundary codes if they have comma separated values - const boundaryCodesArray = boundaryCode.split(','); - boundaryCodesArray.forEach((bc: string) => { - // Trim any leading or trailing spaces - const trimmedBC = bc.trim(); - if (!boundaryCodes[resource?.type]) { - boundaryCodes[resource?.type] = {}; - } - if (!boundaryCodes[resource?.type][trimmedBC]) { - boundaryCodes[resource?.type][trimmedBC] = []; - } - boundaryCodes[resource?.type][trimmedBC].push(code); - logger.info(`Boundary code ${trimmedBC} mapped to resource ${resource?.type} with code ${code}`) - }); + mapBoundaryCodes(resource, code, boundaryCode, boundaryCodes, allBoundaries); } } else { @@ -134,34 +223,39 @@ async function getProjectMappingBody(messageObject: any, boundaryWithProject: an } return { RequestInfo: messageObject?.RequestInfo, - Campaign: Campaign + Campaign: Campaign, + CampaignDetails: messageObject?.CampaignDetails } } async function fetchAndMap(resources: any[], messageObject: any) { - const localizationMap = messageObject?.localizationMap; - const sheetName: any = { - "user": getLocalizedName(createAndSearch?.user?.parseArrayConfig?.sheetName, localizationMap), - "facility": getLocalizedName(createAndSearch?.facility?.parseArrayConfig?.sheetName, localizationMap) - } - // Object to store boundary codes - const boundaryCodes: any = {}; + await persistTrack(messageObject?.Campaign?.id, processTrackTypes.prepareResourceForMapping, processTrackStatuses.inprogress) + const localizationMap = await getLocalizedMessagesHandlerViaRequestInfo(messageObject?.RequestInfo, messageObject?.Campaign?.tenantId); + messageObject.localizationMap = localizationMap + try { + const localizationMap = messageObject?.localizationMap; + const sheetName: any = { + "user": getLocalizedName(createAndSearch?.user?.parseArrayConfig?.sheetName, localizationMap), + "facility": getLocalizedName(createAndSearch?.facility?.parseArrayConfig?.sheetName, localizationMap) + } + // Object to store boundary codes + const boundaryCodes: any = {}; - await enrichBoundaryCodes(resources, messageObject, boundaryCodes, sheetName); - logger.info("boundaryCodes : " + JSON.stringify(boundaryCodes)); - var boundaryWithProject: any = {}; - await enrichBoundaryWithProject(messageObject, boundaryWithProject, boundaryCodes); - logger.info("boundaryWithProject : " + JSON.stringify(boundaryWithProject)); - const projectMappingBody = await getProjectMappingBody(messageObject, boundaryWithProject, boundaryCodes); - logger.info("projectMappingBody : " + JSON.stringify(projectMappingBody)); - logger.info("projectMapping started "); - const projectMappingResponse: any = await createCampaignService(projectMappingBody); - logger.info("Project Mapping Response received"); - if (projectMappingResponse) { - logger.info("Campaign Mapping done") - messageObject.CampaignDetails.status = campaignStatuses.inprogress - produceModifiedMessages(messageObject, config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC) + await enrichBoundaryCodes(resources, messageObject, boundaryCodes, sheetName); + logger.info("boundaryCodes : " + JSON.stringify(boundaryCodes)); + var boundaryWithProject: any = {}; + await enrichBoundaryWithProject(messageObject, boundaryWithProject, boundaryCodes); + logger.info("boundaryWithProject : " + JSON.stringify(boundaryWithProject)); + var projectMappingBody = await getProjectMappingBody(messageObject, boundaryWithProject, boundaryCodes); + logger.info("projectMappingBody : " + JSON.stringify(projectMappingBody)); + logger.info("projectMapping started "); + } catch (error: any) { + console.log(error) + await persistTrack(messageObject?.Campaign?.id, processTrackTypes.prepareResourceForMapping, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + throw new Error(error) } + await persistTrack(messageObject?.Campaign?.id, processTrackTypes.prepareResourceForMapping, processTrackStatuses.completed) + await createCampaignService(projectMappingBody); } async function searchResourceDetailsById(resourceDetailId: string, messageObject: any) { @@ -202,45 +296,150 @@ async function processCampaignMapping(messageObject: any) { logger.info("Campaign Already In Progress and Mapped"); } else { - var completedResources: any = [] - var resources = []; - for (const resourceDetailId of resourceDetailsIds) { - var retry = 75; - while (retry--) { - const response = await searchResourceDetailsById(resourceDetailId, messageObject); - logger.info(`response for resourceDetailId: ${resourceDetailId}`); - logger.debug(` response : ${getFormattedStringForDebug(response)}`) - if (response?.status == "invalid") { - logger.error(`resource with id ${resourceDetailId} is invalid`); - throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "resource with id " + resourceDetailId + " is invalid"); - break; - } - else if (response?.status == resourceDataStatuses.failed) { - logger.error(`resource with id ${resourceDetailId} is ${resourceDataStatuses.failed}`); - throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", `resource with id ${resourceDetailId} is ${resourceDataStatuses.failed} : with errorlog ${response?.additionalDetails?.error}`); - break; - } - else if (response?.status == resourceDataStatuses.completed) { - completedResources.push(resourceDetailId); - resources.push(response); - break; - } - else { - logger.info(`Waiting for 20 seconds for resource with id ${resourceDetailId} on retry ${retry}`); - await new Promise(resolve => setTimeout(resolve, 20000)); + await persistTrack(id, processTrackTypes.confirmingResourceCreation, processTrackStatuses.inprogress); + try { + var completedResources: any = [] + var resources = []; + for (const resourceDetailId of resourceDetailsIds) { + var retry = 75; + while (retry--) { + const response = await searchResourceDetailsById(resourceDetailId, messageObject); + logger.info(`response for resourceDetailId: ${resourceDetailId}`); + logger.debug(` response : ${getFormattedStringForDebug(response)}`) + if (response?.status == "invalid") { + logger.error(`resource type ${response?.type} is invalid`); + throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "Data File for resource type " + response?.type + " is invalid"); + break; + } + else if (response?.status == resourceDataStatuses.failed) { + logger.error(`resource type ${response?.type} is ${resourceDataStatuses.failed}`); + throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", `Resource creation of type ${response?.type} failed : with errorlog ${response?.additionalDetails?.error}`); + break; + } + else if (response?.status == resourceDataStatuses.completed) { + completedResources.push(resourceDetailId); + resources.push(response); + break; + } + else { + logger.info(`Waiting for 20 seconds for resource with id ${resourceDetailId} on retry ${retry}`); + await new Promise(resolve => setTimeout(resolve, 20000)); + } } } + var uncompletedResourceIds = resourceDetailsIds?.filter((x: any) => !completedResources.includes(x)); + logger.info("uncompletedResourceIds " + JSON.stringify(uncompletedResourceIds)); + logger.info("completedResources " + JSON.stringify(completedResources)); + if (uncompletedResourceIds?.length > 0) { + throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "resource with id " + JSON.stringify(uncompletedResourceIds) + " is not completed after long wait. Check file"); + } + } catch (error: any) { + console.log(error) + await persistTrack(id, processTrackTypes.confirmingResourceCreation, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + throw new Error(error) } - var uncompletedResourceIds = resourceDetailsIds?.filter((x: any) => !completedResources.includes(x)); - logger.info("uncompletedResourceIds " + JSON.stringify(uncompletedResourceIds)); - logger.info("completedResources " + JSON.stringify(completedResources)); - if (uncompletedResourceIds?.length > 0) { - throwError("COMMON", 400, "INTERNAL_SERVER_ERROR", "resource with id " + JSON.stringify(uncompletedResourceIds) + " is not validated after long wait. Check file"); - } + await persistTrack(id, processTrackTypes.confirmingResourceCreation, processTrackStatuses.completed); await fetchAndMap(resources, messageObject); } } +export async function handleCampaignMapping(messageObject: any) { + try { + logger.info("Received a message for campaign mapping"); + logger.debug("Message Object of campaign mapping: " + getFormattedStringForDebug(messageObject)); + await processCampaignMapping(messageObject); + } catch (error) { + logger.error("Error in campaign mapping: " + error); + await enrichAndPersistCampaignWithError(messageObject, error); + } +} + +export async function handleStaffMapping(mappingArray: any[], campaignId: string, messageObject: any) { + await persistTrack(campaignId, processTrackTypes.staffMapping, processTrackStatuses.inprogress); + try { + const promises = [] + logger.debug("Array of staff mapping: " + getFormattedStringForDebug(mappingArray)); + for (const staffMapping of mappingArray) { + const { resource, projectId, resouceBody, tenantId, startDate, endDate } = staffMapping; + for (const resourceId of resource?.resourceIds) { + promises.push(createStaffHelper(resourceId, projectId, resouceBody, tenantId, startDate, endDate)) + } + } + await Promise.all(promises); + } catch (error: any) { + logger.error("Error in staff mapping: " + error); + await persistTrack(campaignId, processTrackTypes.staffMapping, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + await enrichAndPersistCampaignWithError(messageObject, error); + throw new Error(error) + } + await persistTrack(campaignId, processTrackTypes.staffMapping, processTrackStatuses.completed); +} + +export async function handleResourceMapping(mappingArray: any, campaignId: any, messageObject: any) { + await persistTrack(campaignId, processTrackTypes.resourceMapping, processTrackStatuses.inprogress); + try { + const promises = [] + logger.debug("Arrray of resource mapping: " + getFormattedStringForDebug(mappingArray)); + for (const mapping of mappingArray) { + const { resource, projectId, resouceBody, tenantId, startDate, endDate } = mapping; + for (const resourceId of resource?.resourceIds) { + promises.push(createProjectResourceHelper(resourceId, projectId, resouceBody, tenantId, startDate, endDate)); + } + } + await Promise.all(promises); + } catch (error: any) { + logger.error("Error in resource mapping: " + error); + await persistTrack(campaignId, processTrackTypes.resourceMapping, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + await enrichAndPersistCampaignWithError(messageObject, error); + throw new Error(error) + } + await persistTrack(campaignId, processTrackTypes.resourceMapping, processTrackStatuses.completed); +} + +export async function handleFacilityMapping(mappingArray: any, campaignId: any, messageObject: any) { + await persistTrack(campaignId, processTrackTypes.facilityMapping, processTrackStatuses.inprogress); + try { + const promises = [] + logger.debug("Array of facility mapping: " + getFormattedStringForDebug(mappingArray)); + for (const mapping of mappingArray) { + const { resource, projectId, resouceBody, tenantId } = mapping; + for (const resourceId of resource?.resourceIds) { + promises.push(createProjectFacilityHelper(resourceId, projectId, resouceBody, tenantId)); + } + } + await Promise.all(promises); + } catch (error: any) { + logger.error("Error in facility mapping: " + error); + await persistTrack(campaignId, processTrackTypes.facilityMapping, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + await enrichAndPersistCampaignWithError(messageObject, error); + throw new Error(error) + } + await persistTrack(campaignId, processTrackTypes.facilityMapping, processTrackStatuses.completed); +} + +export async function processMapping(mappingObject: any) { + try { + if (mappingObject?.mappingArray && Array.isArray(mappingObject?.mappingArray) && mappingObject?.mappingArray?.length > 0) { + const resourceMappingArray = mappingObject?.mappingArray?.filter((mappingObject: any) => mappingObject?.type == "resource"); + const facilityMappingArray = mappingObject?.mappingArray?.filter((mappingObject: any) => mappingObject?.type == "facility"); + const staffMappingArray = mappingObject?.mappingArray?.filter((mappingObject: any) => mappingObject?.type == "staff"); + await handleResourceMapping(resourceMappingArray, mappingObject?.CampaignDetails?.id, mappingObject); + await handleFacilityMapping(facilityMappingArray, mappingObject?.CampaignDetails?.id, mappingObject); + await handleStaffMapping(staffMappingArray, mappingObject?.CampaignDetails?.id, mappingObject); + } + logger.info("Mapping completed successfully for campaign: " + mappingObject?.CampaignDetails?.id); + mappingObject.CampaignDetails.status = campaignStatuses.inprogress + const produceMessage: any = { + CampaignDetails: mappingObject?.CampaignDetails + } + await produceModifiedMessages(produceMessage, config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC) + await persistTrack(mappingObject?.CampaignDetails?.id, processTrackTypes.campaignCreation, processTrackStatuses.completed) + } catch (error) { + logger.error("Error in campaign mapping: " + error); + await enrichAndPersistCampaignWithError(mappingObject, error); + } +} + export { processCampaignMapping, diff --git a/health-services/project-factory/src/server/utils/campaignUtils.ts b/health-services/project-factory/src/server/utils/campaignUtils.ts index f2b4e1f37ca..1fbf424ecf9 100644 --- a/health-services/project-factory/src/server/utils/campaignUtils.ts +++ b/health-services/project-factory/src/server/utils/campaignUtils.ts @@ -2,9 +2,9 @@ import { defaultheader, httpRequest } from "./request"; import config from "../config/index"; import { v4 as uuidv4 } from 'uuid'; -import { produceModifiedMessages } from '../kafka/Listener' +import { produceModifiedMessages } from "../kafka/Producer"; import { confirmProjectParentCreation, createProjectCampaignResourcData, getCampaignSearchResponse, getHierarchy, handleResouceDetailsError, projectCreate } from "../api/campaignApis"; -import { getCampaignNumber, createAndUploadFile, getSheetData, createExcelSheet, getAutoGeneratedBoundaryCodesHandler, createBoundaryEntities, createBoundaryRelationship, getMDMSV1Data, getTargetSheetDataAfterCode, callMdmsTypeSchema } from "../api/genericApis"; +import { getCampaignNumber, createAndUploadFile, getSheetData, createExcelSheet, getAutoGeneratedBoundaryCodesHandler, createBoundaryEntities, createBoundaryRelationship, getMDMSV1Data, getTargetSheetDataAfterCode, callMdmsTypeSchema, getSheetDataFromWorksheet } from "../api/genericApis"; import { getFormattedStringForDebug, logger } from "./logger"; import createAndSearch from "../config/createAndSearch"; import { addDataToSheet, createBoundaryDataMainSheet, createReadMeSheet, findMapValue, getBoundaryRelationshipData, getConfigurableColumnHeadersFromSchemaForTargetSheet, getLocalizedHeaders, getLocalizedMessagesHandler, getMdmsDataBasedOnCampaignType, modifyBoundaryData, replicateRequest, throwError } from "./genericUtils"; @@ -12,11 +12,14 @@ import { enrichProjectDetailsFromCampaignDetails } from "./transforms/projectTyp import { executeQuery } from "./db"; import { campaignDetailsTransformer, genericResourceTransformer } from "./transforms/searchResponseConstructor"; import { transformAndCreateLocalisation } from "./transforms/localisationMessageConstructor"; -import { campaignStatuses, headingMapping, resourceDataStatuses } from "../config/constants"; +import { campaignStatuses, headingMapping, processTrackStatuses, processTrackTypes, resourceDataStatuses } from "../config/constants"; import { getBoundaryColumnName, getBoundaryTabName } from "./boundaryUtils"; import { searchProjectTypeCampaignService } from "../service/campaignManageService"; import { validateBoundaryOfResouces } from "../validators/campaignValidators"; import { getExcelWorkbookFromFileURL, getNewExcelWorkbook, lockTargetFields, updateFontNameToRoboto } from "./excelUtils"; +import { areBoundariesSame, callGenerateIfBoundariesDiffer } from "./generateUtils"; +import { createProcessTracks, persistTrack } from "./processTrackUtils"; +import { generateDynamicTargetHeaders, isDynamicTargetTemplateForProjectType, updateTargetColumnsIfDeliveryConditionsDifferForSMC } from "./targetUtils"; const _ = require('lodash'); @@ -220,7 +223,7 @@ function deterMineLastColumnAndEnrichUserDetails(worksheet: any, errorDetailsCol } function adjustRef(worksheet: any, lastColumn: any) { - const range = worksheet.getSheetValues().filter((row: any) => row).length; // Get the number of used rows + const range = getSheetDataFromWorksheet(worksheet).filter((row: any) => row).length; // Get the number of used rows worksheet.views = [ { state: 'frozen', ySplit: 1, topLeftCell: 'A2', activeCell: 'A2' } ]; @@ -475,14 +478,15 @@ async function generateProcessedFileAndPersist(request: any, localizationMap?: { if (request?.body?.ResourceDetails?.action == "create") { persistMessage.ResourceDetails.additionalDetails = {} } - produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC); + await produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_UPDATE_RESOURCE_DETAILS_TOPIC); logger.info(`ResourceDetails to persist : ${request.body.ResourceDetails.type}`); - if (request?.body?.Activities && Array.isArray(request?.body?.Activities && request?.body?.Activities.length > 0)) { + if (request?.body?.Activities && Array.isArray(request?.body?.Activities) && request?.body?.Activities.length > 0) { logger.info("Activities to persist : ") logger.debug(getFormattedStringForDebug(request?.body?.Activities)); logger.info(`Waiting for 2 seconds`); await new Promise(resolve => setTimeout(resolve, 2000)); - produceModifiedMessages(request?.body, config?.kafka?.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC); + const activityObject = request?.body?.Activities; + await produceModifiedMessages(activityObject, config.kafka.KAFKA_CREATE_RESOURCE_ACTIVITY_TOPIC); } } @@ -535,10 +539,15 @@ async function enrichAndPersistCampaignWithError(requestBody: any, error: any) { } requestBody.CampaignDetails.additionalDetails = { ...requestBody?.CampaignDetails?.additionalDetails, - error: String((error?.message + " : " + error?.description) || error) + error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) } const topic = config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC - produceModifiedMessages(requestBody, topic); + // wait for 2 seconds + logger.info(`Waiting for 2 seconds to persist errors`); + await new Promise(resolve => setTimeout(resolve, 2000)); + const produceMessage: any = { CampaignDetails: requestBody.CampaignDetails } + await produceModifiedMessages(produceMessage, topic); + await persistTrack(requestBody?.CampaignDetails?.id, processTrackTypes.error, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); delete requestBody.CampaignDetails.campaignDetails } @@ -569,7 +578,10 @@ async function enrichAndPersistCampaignForCreate(request: any, firstPersist: boo } const topic = firstPersist ? config?.kafka?.KAFKA_SAVE_PROJECT_CAMPAIGN_DETAILS_TOPIC : config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC delete request.body.CampaignDetails.codesTargetMapping - produceModifiedMessages(request?.body, topic); + const produceMessage: any = { + CampaignDetails: request?.body?.CampaignDetails + }; + await produceModifiedMessages(produceMessage, topic); delete request.body.CampaignDetails.campaignDetails } @@ -579,8 +591,16 @@ function enrichInnerCampaignDetails(request: any, updatedInnerCampaignDetails: a updatedInnerCampaignDetails.boundaries = request?.body?.CampaignDetails?.boundaries || [] } + async function enrichAndPersistCampaignForUpdate(request: any, firstPersist: boolean = false) { const action = request?.body?.CampaignDetails?.action; + const existingCampaignDetails = request?.body?.ExistingCampaignDetails; + callGenerateIfBoundariesDiffer(request); + if (existingCampaignDetails) { + if (areBoundariesSame(existingCampaignDetails?.boundaries, request?.body?.CampaignDetails?.boundaries)) { + updateTargetColumnsIfDeliveryConditionsDifferForSMC(request); + } + } const ExistingCampaignDetails = request?.body?.ExistingCampaignDetails; var updatedInnerCampaignDetails = {} enrichInnerCampaignDetails(request, updatedInnerCampaignDetails) @@ -607,7 +627,10 @@ async function enrichAndPersistCampaignForUpdate(request: any, firstPersist: boo request.body.CampaignDetails.projectId = request?.body?.CampaignDetails?.projectId || ExistingCampaignDetails?.projectId || null } delete request.body.CampaignDetails.codesTargetMapping - produceModifiedMessages(request?.body, config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC); + const producerMessage: any = { + CampaignDetails: request?.body?.CampaignDetails + } + await produceModifiedMessages(producerMessage, config?.kafka?.KAFKA_UPDATE_PROJECT_CAMPAIGN_DETAILS_TOPIC); delete request.body.ExistingCampaignDetails delete request.body.CampaignDetails.campaignDetails } @@ -644,10 +667,10 @@ async function persistForCampaignProjectMapping(request: any, createResourceDeta enrichInnerCampaignDetails(request, updatedInnerCampaignDetails) requestBody.CampaignDetails = request?.body?.CampaignDetails requestBody.CampaignDetails.campaignDetails = updatedInnerCampaignDetails - requestBody.localizationMap = localizationMap + // requestBody.localizationMap = localizationMap logger.info("Persisting CampaignProjectMapping..."); logger.debug(`CampaignProjectMapping: ${getFormattedStringForDebug(requestBody)}`); - produceModifiedMessages(requestBody, config?.kafka?.KAFKA_START_CAMPAIGN_MAPPING_TOPIC); + await produceModifiedMessages(requestBody, config?.kafka?.KAFKA_START_CAMPAIGN_MAPPING_TOPIC); } } @@ -665,6 +688,9 @@ async function enrichAndPersistProjectCampaignForFirst(request: any, actionInUrl else if (actionInUrl == "update") { await enrichAndPersistCampaignForUpdate(request, firstPersist) } + if (request?.body?.CampaignDetails?.action == "create") { + await createProcessTracks(request.body.CampaignDetails.id) + } } @@ -1286,38 +1312,46 @@ async function getCodesTarget(request: any, localizationMap?: any) { } async function createProject(request: any, actionUrl: any, localizationMap?: any) { - logger.info("Create Projects started for the given Campaign") - var { tenantId, boundaries, projectType, projectId } = request?.body?.CampaignDetails; - if (boundaries && projectType && !projectId) { - const projectTypeResponse = await getMDMSV1Data({}, 'HCM-PROJECT-TYPES', "projectTypes", tenantId); - var Projects: any = enrichProjectDetailsFromCampaignDetails(request?.body?.CampaignDetails, projectTypeResponse?.filter((types: any) => types?.code == projectType)?.[0]); - const projectCreateBody = { - RequestInfo: request?.body?.RequestInfo, - Projects - } - await reorderBoundaries(request, localizationMap) - boundaries = request?.body?.CampaignDetails?.boundaries; - for (const boundary of boundaries) { - Projects[0].address = { tenantId: tenantId, boundary: boundary?.code, boundaryType: boundary?.type } - if (request?.body?.boundaryProjectMapping?.[boundary?.code]?.parent) { - const parent = request?.body?.boundaryProjectMapping?.[boundary?.code]?.parent - await confirmProjectParentCreation(request, request?.body?.boundaryProjectMapping?.[parent]?.projectId) - Projects[0].parent = request?.body?.boundaryProjectMapping?.[parent]?.projectId - } - else { - Projects[0].parent = null + await persistTrack(request.body.CampaignDetails.id, processTrackTypes.targetAndDeliveryRulesCreation, processTrackStatuses.inprogress); + try { + logger.info("Create Projects started for the given Campaign") + var { tenantId, boundaries, projectType, projectId } = request?.body?.CampaignDetails; + if (boundaries && projectType && !projectId) { + const projectTypeResponse = await getMDMSV1Data({}, 'HCM-PROJECT-TYPES', "projectTypes", tenantId); + var Projects: any = enrichProjectDetailsFromCampaignDetails(request?.body?.CampaignDetails, projectTypeResponse?.filter((types: any) => types?.code == projectType)?.[0]); + const projectCreateBody = { + RequestInfo: request?.body?.RequestInfo, + Projects } - Projects[0].referenceID = request?.body?.CampaignDetails?.id - Projects[0].targets = [ - { - beneficiaryType: request?.body?.CampaignDetails?.additionalDetails?.beneficiaryType, - totalNo: request?.body?.CampaignDetails?.codesTargetMapping[boundary?.code], - targetNo: request?.body?.CampaignDetails?.codesTargetMapping[boundary?.code] + await reorderBoundaries(request, localizationMap) + boundaries = request?.body?.CampaignDetails?.boundaries; + for (const boundary of boundaries) { + Projects[0].address = { tenantId: tenantId, boundary: boundary?.code, boundaryType: boundary?.type } + if (request?.body?.boundaryProjectMapping?.[boundary?.code]?.parent) { + const parent = request?.body?.boundaryProjectMapping?.[boundary?.code]?.parent + await confirmProjectParentCreation(request, request?.body?.boundaryProjectMapping?.[parent]?.projectId) + Projects[0].parent = request?.body?.boundaryProjectMapping?.[parent]?.projectId } - ] - await projectCreate(projectCreateBody, request) + else { + Projects[0].parent = null + } + Projects[0].referenceID = request?.body?.CampaignDetails?.id + Projects[0].targets = [ + { + beneficiaryType: request?.body?.CampaignDetails?.additionalDetails?.beneficiaryType, + totalNo: request?.body?.CampaignDetails?.codesTargetMapping[boundary?.code], + targetNo: request?.body?.CampaignDetails?.codesTargetMapping[boundary?.code] + } + ] + await projectCreate(projectCreateBody, request) + } } + } catch (error: any) { + console.log(error) + await persistTrack(request?.body?.CampaignDetails?.id, processTrackTypes.targetAndDeliveryRulesCreation, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + throw new Error(error) } + await persistTrack(request?.body?.CampaignDetails?.id, processTrackTypes.targetAndDeliveryRulesCreation, processTrackStatuses.completed); } @@ -1325,6 +1359,7 @@ async function processAfterPersist(request: any, actionInUrl: any) { try { const localizationMap = await getLocalizedMessagesHandler(request, request?.body?.CampaignDetails?.tenantId); if (request?.body?.CampaignDetails?.action == "create") { + await persistTrack(request.body.CampaignDetails.id, processTrackTypes.validation, processTrackStatuses.completed); await createProjectCampaignResourcData(request); await createProject(request, actionInUrl, localizationMap) await enrichAndPersistProjectCampaignRequest(request, actionInUrl, false, localizationMap) @@ -1336,7 +1371,7 @@ async function processAfterPersist(request: any, actionInUrl: any) { } catch (error: any) { console.log(error) logger.error(error) - enrichAndPersistCampaignWithError(request?.body, error) + await enrichAndPersistCampaignWithError(request?.body, error) } } @@ -1372,13 +1407,19 @@ async function appendSheetsToWorkbook(request: any, boundaryData: any[], differe const localisedHeading = getLocalizedName(headingInSheet, localizationMap); await createReadMeSheet(request, workbook, localisedHeading, localizationMap); const [mainSheetData, uniqueDistrictsForMainSheet, districtLevelRowBoundaryCodeMap] = createBoundaryDataMainSheet(request, boundaryData, differentTabsBasedOnLevel, hierarchy, localizationMap) - const mainSheet = workbook.addWorksheet(getLocalizedName(getBoundaryTabName(), localizationMap)); - const columnWidths = Array(12).fill(30); - mainSheet.columns = columnWidths.map(width => ({ width })); - // mainSheetData.forEach(row => mainSheet.addRow(row)); - addDataToSheet(mainSheet, mainSheetData, 'F3842D', 30, false, true); + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); + if (!(isSourceMicroplan)) { + const mainSheet = workbook.addWorksheet(getLocalizedName(getBoundaryTabName(), localizationMap)); + const columnWidths = Array(12).fill(30); + mainSheet.columns = columnWidths.map(width => ({ width })); + // mainSheetData.forEach(row => mainSheet.addRow(row)); + addDataToSheet(mainSheet, mainSheetData, 'F3842D', 30, false, true); + mainSheet.state = 'hidden'; + } logger.info("appending different districts tab in the sheet started") - await appendDistricts(request, workbook, uniqueDistrictsForMainSheet, differentTabsBasedOnLevel, boundaryData, localizationMap, districtLevelRowBoundaryCodeMap, hierarchy); + await appendDistricts(request, workbook, uniqueDistrictsForMainSheet, differentTabsBasedOnLevel, boundaryData, localizationMap, districtLevelRowBoundaryCodeMap, hierarchy, campaignObject); logger.info("Sheet with different tabs generated successfully"); return workbook; } catch (error) { @@ -1388,8 +1429,8 @@ async function appendSheetsToWorkbook(request: any, boundaryData: any[], differe } -async function appendDistricts(request: any, workbook: any, uniqueDistrictsForMainSheet: any, differentTabsBasedOnLevel: any, boundaryData: any, localizationMap: any, districtLevelRowBoundaryCodeMap: any, hierarchy: any) { - const configurableColumnHeadersFromSchemaForTargetSheet = await getConfigurableColumnHeadersFromSchemaForTargetSheet(request, hierarchy, boundaryData, differentTabsBasedOnLevel, localizationMap); +async function appendDistricts(request: any, workbook: any, uniqueDistrictsForMainSheet: any, differentTabsBasedOnLevel: any, boundaryData: any, localizationMap: any, districtLevelRowBoundaryCodeMap: any, hierarchy: any, campaignObject: any) { + const configurableColumnHeadersFromSchemaForTargetSheet = await getConfigurableColumnHeadersFromSchemaForTargetSheet(request, hierarchy, boundaryData, differentTabsBasedOnLevel, campaignObject, localizationMap); for (const uniqueData of uniqueDistrictsForMainSheet) { const uniqueDataFromLevelForDifferentTabs = uniqueData.slice(uniqueData.lastIndexOf('#') + 1); logger.info(`generating the boundary data for ${uniqueDataFromLevelForDifferentTabs} - ${differentTabsBasedOnLevel}`) @@ -1404,19 +1445,24 @@ async function appendDistricts(request: any, workbook: any, uniqueDistrictsForMa } newSheetData.push(rowData); } - await createNewSheet(request, workbook, newSheetData, uniqueData, localizationMap, districtLevelRowBoundaryCodeMap, configurableColumnHeadersFromSchemaForTargetSheet); + await createNewSheet(request, workbook, newSheetData, uniqueData, localizationMap, districtLevelRowBoundaryCodeMap, configurableColumnHeadersFromSchemaForTargetSheet, campaignObject); logger.info(`${uniqueDataFromLevelForDifferentTabs} - ${differentTabsBasedOnLevel} boundary data generation completed`) } } } - -async function createNewSheet(request: any, workbook: any, newSheetData: any, uniqueData: any, localizationMap: any, districtLevelRowBoundaryCodeMap: any, localizedHeaders: any) { +async function createNewSheet(request: any, workbook: any, newSheetData: any, uniqueData: any, localizationMap: any, districtLevelRowBoundaryCodeMap: any, localizedHeaders: any, campaignObject: any) { const newSheet = workbook.addWorksheet(getLocalizedName(districtLevelRowBoundaryCodeMap.get(uniqueData), localizationMap)); addDataToSheet(newSheet, newSheetData, 'F3842D', 40); + let columnsNotToBeFreezed: any; const boundaryCodeColumnIndex = localizedHeaders.findIndex((header: any) => header === getLocalizedName(config?.boundary?.boundaryCode, localizationMap)); - const mdmsResponse = await getMdmsDataBasedOnCampaignType(request, localizationMap) - const columnsNotToBeFreezed = mdmsResponse?.columnsNotToBeFreezed; + if (isDynamicTargetTemplateForProjectType(campaignObject?.projectType) && campaignObject.deliveryRules && campaignObject.deliveryRules.length > 0) { + columnsNotToBeFreezed = localizedHeaders.slice(boundaryCodeColumnIndex + 1); + } + else { + const mdmsResponse = await getMdmsDataBasedOnCampaignType(request, localizationMap) + columnsNotToBeFreezed = mdmsResponse?.columnsNotToBeFreezed; + } const localizedColumnsNotToBeFreezed = getLocalizedHeaders(columnsNotToBeFreezed, localizationMap); lockTargetFields(newSheet, localizedColumnsNotToBeFreezed, boundaryCodeColumnIndex); } @@ -1575,10 +1621,12 @@ const autoGenerateBoundaryCodes = async (request: any, localizationMap?: any) => const modifiedBoundaryData = modifyBoundaryDataHeaders(updatedBoundaryData, hierarchy, localizationMap); const [withBoundaryCode, withoutBoundaryCode] = modifyBoundaryData(modifiedBoundaryData, localizationMap); const { mappingMap, countMap } = getCodeMappingsOfExistingBoundaryCodes(withBoundaryCode); - const childParentMap = getChildParentMap(withoutBoundaryCode); + const childParentMap = getChildParentMap([...withBoundaryCode, ...withoutBoundaryCode]); const boundaryMap = await getAutoGeneratedBoundaryCodesHandler(withoutBoundaryCode, childParentMap, mappingMap, countMap, request); logger.info("Boundary Code Auto Generation Completed"); await createBoundaryEntities(request, boundaryMap); + logger.info("waiting for 2 secs to persist the boundary entities before creating boundary relationship") + await new Promise(resolve => setTimeout(resolve, 2000)); const modifiedChildParentMap = modifyChildParentMap(childParentMap, boundaryMap); await createBoundaryRelationship(request, boundaryMap, modifiedChildParentMap); const boundaryDataForSheet = addBoundaryCodeToData(withBoundaryCode, withoutBoundaryCode, boundaryMap); @@ -1738,8 +1786,10 @@ function getFiltersFromCampaignSearchResponse(responseFromCampaignSearch: any) { const getConfigurableColumnHeadersBasedOnCampaignType = async (request: any, localizationMap?: any) => { try { const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const campaignType = responseFromCampaignSearch?.CampaignDetails[0]?.projectType; - + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + let campaignType = campaignObject?.projectType; + const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); + campaignType = (isSourceMicroplan) ? `${config?.prefixForMicroplanCampaigns}-${campaignType}` : campaignType; const mdmsResponse = await callMdmsTypeSchema(request, request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, request?.query?.type || request?.body?.ResourceDetails?.type, campaignType) if (!mdmsResponse || mdmsResponse?.columns.length === 0) { logger.error(`Campaign Type ${campaignType} has not any columns configured in schema`) @@ -1763,22 +1813,24 @@ const getConfigurableColumnHeadersBasedOnCampaignType = async (request: any, loc } -async function getFinalValidHeadersForTargetSheetAsPerCampaignType(request: any, hierarchy: any[], localizationMap?: any) { +async function getFinalValidHeadersForTargetSheetAsPerCampaignType(request: any, hierarchy: any[], differentTabsBasedOnLevel: any, localizationMap?: any) { const modifiedHierarchy = hierarchy.map(ele => `${request?.body?.ResourceDetails?.hierarchyType}_${ele}`.toUpperCase()); const localizedHierarchy = getLocalizedHeaders(modifiedHierarchy, localizationMap); - const index = localizedHierarchy.indexOf(getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap)); + const index = localizedHierarchy.indexOf(getLocalizedName(differentTabsBasedOnLevel, localizationMap)); const expectedHeadersForTargetSheetUptoHierarchy = index !== -1 ? localizedHierarchy.slice(index) : throwError("COMMON", 400, "VALIDATION_ERROR", `${getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap)} level not present in the hierarchy`); - const columnFromSchemaOfTargetTemplate = await getConfigurableColumnHeadersBasedOnCampaignType(request); + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + const columnFromSchemaOfTargetTemplate = await generateDynamicTargetHeaders(request, campaignObject, localizationMap); const localizedcolumnFromSchemaOfTargetTemplate = getLocalizedHeaders(columnFromSchemaOfTargetTemplate, localizationMap) - const expectedHeadersForTargetSheet = [...expectedHeadersForTargetSheetUptoHierarchy, ...localizedcolumnFromSchemaOfTargetTemplate]; + const expectedHeadersForTargetSheet = [...expectedHeadersForTargetSheetUptoHierarchy, getLocalizedName(config?.boundary?.boundaryCode, localizationMap), ...localizedcolumnFromSchemaOfTargetTemplate]; return expectedHeadersForTargetSheet; } async function getDifferentTabGeneratedBasedOnConfig(request: any, boundaryDataGeneratedBeforeDifferentTabSeparation: any, localizationMap?: any) { - // assigning fileStoreId of a single district tab if criteria for multiple tabs are not met var boundaryDataGeneratedAfterDifferentTabSeparation: any = boundaryDataGeneratedBeforeDifferentTabSeparation; const boundaryData = await getBoundaryDataAfterGeneration(boundaryDataGeneratedBeforeDifferentTabSeparation, request, localizationMap); - const differentTabsBasedOnLevel = getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap); + let differentTabsBasedOnLevel = await getBoundaryOnWhichWeSplit(request); + differentTabsBasedOnLevel = getLocalizedName(`${request?.query?.hierarchyType}_${differentTabsBasedOnLevel}`.toUpperCase(), localizationMap); logger.info(`Boundaries are seperated based on hierarchy type ${differentTabsBasedOnLevel}`) const isKeyOfThatTypePresent = boundaryData.some((data: any) => data.hasOwnProperty(differentTabsBasedOnLevel)); const boundaryTypeOnWhichWeSplit = boundaryData.filter((data: any) => data[differentTabsBasedOnLevel]); @@ -1789,6 +1841,19 @@ async function getDifferentTabGeneratedBasedOnConfig(request: any, boundaryDataG return boundaryDataGeneratedAfterDifferentTabSeparation; } +async function getBoundaryOnWhichWeSplit(request: any) { + const mdmsResponse = await getMDMSV1Data(request, config?.values?.moduleName, config?.masterNameForSplitBoundariesOn, request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId); + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const hierarchyTypeFromCampaignResponseObject = responseFromCampaignSearch?.CampaignDetails?.[0].hierarchyType; + return mdmsResponse.filter((item: any) => item.hierarchy == hierarchyTypeFromCampaignResponseObject).map((item: any) => item.splitBoundariesOn); +} + + +function checkIfSourceIsMicroplan(objectWithAdditionalDetails: any): boolean { + return objectWithAdditionalDetails?.additionalDetails?.source === 'microplan'; +} + + @@ -1821,5 +1886,7 @@ export { getFiltersFromCampaignSearchResponse, getConfigurableColumnHeadersBasedOnCampaignType, getFinalValidHeadersForTargetSheetAsPerCampaignType, - getDifferentTabGeneratedBasedOnConfig + getDifferentTabGeneratedBasedOnConfig, + checkIfSourceIsMicroplan, + getBoundaryOnWhichWeSplit } diff --git a/health-services/project-factory/src/server/utils/excelUtils.ts b/health-services/project-factory/src/server/utils/excelUtils.ts index 8624ed7b977..8f7a0acc614 100644 --- a/health-services/project-factory/src/server/utils/excelUtils.ts +++ b/health-services/project-factory/src/server/utils/excelUtils.ts @@ -71,8 +71,8 @@ function updateFontNameToRoboto(worksheet: ExcelJS.Worksheet) { function formatWorksheet(worksheet: any, datas: any, headerSet: any) { // Add empty rows after the main header - worksheet.addRow([]); - worksheet.addRow([]); + // worksheet.addRow([]); + // worksheet.addRow([]); worksheet.addRow([]); // Add the data rows with text wrapping @@ -136,46 +136,70 @@ function performFreezeWholeSheet(sheet: any) { sheet.protect('passwordhere', { selectLockedCells: true }); } -function addDataToSheet(sheet: any, sheetData: any, firstRowColor: any = '93C47D', columnWidth = 40, frozeCells = false, frozeWholeSheet = false) { +// Function to add data to the sheet +function addDataToSheet(sheet: any, sheetData: any, firstRowColor: string = '93C47D', columnWidth: number = 40, frozeCells: boolean = false, frozeWholeSheet: boolean = false) { sheetData?.forEach((row: any, index: number) => { const worksheetRow = sheet.addRow(row); - // Apply fill color to each cell in the first row and make cells bold if (index === 0) { - worksheetRow.eachCell((cell: any, colNumber: number) => { - // Set cell fill color - cell.fill = { - type: 'pattern', - pattern: 'solid', - fgColor: { argb: firstRowColor } // Green color - }; - - // Set font to bold - cell.font = { bold: true }; + formatFirstRow(worksheetRow, sheet, firstRowColor, columnWidth, frozeCells); + } else { + formatOtherRows(worksheetRow, frozeCells); + } + }); + + finalizeSheet(sheet, frozeCells, frozeWholeSheet); +} + +// Function to format the first row +function formatFirstRow(row: any, sheet: any, firstRowColor: string, columnWidth: number, frozeCells: boolean) { + row.eachCell((cell: any, colNumber: number) => { + setFirstRowCellStyles(cell, firstRowColor, frozeCells); + adjustColumnWidth(sheet, colNumber, columnWidth); + adjustRowHeight(row, cell, columnWidth); + }); +} + +// Function to set styles for the first row's cells +function setFirstRowCellStyles(cell: any, firstRowColor: string, frozeCells: boolean) { + cell.fill = { + type: 'pattern', + pattern: 'solid', + fgColor: { argb: firstRowColor } + }; + + cell.font = { bold: true }; - // Enable text wrapping - cell.alignment = { wrapText: true }; + if (frozeCells) { + cell.protection = { locked: true }; + } - // Optionally lock the cell - if (frozeCells) { - cell.protection = { locked: true }; - } + cell.alignment = { vertical: 'top', horizontal: 'left', wrapText: true }; +} - // Update column width based on the length of the cell's text - const currentWidth = sheet.getColumn(colNumber).width || columnWidth; // Default width or current width - const newWidth = Math.max(currentWidth, cell.value.toString().length + 2); // Add padding - sheet.getColumn(colNumber).width = newWidth; - }); +// Function to adjust column width +function adjustColumnWidth(sheet: any, colNumber: number, columnWidth: number) { + sheet.getColumn(colNumber).width = columnWidth; +} +// Function to adjust row height based on content +function adjustRowHeight(row: any, cell: any, columnWidth: number) { + const text = cell.value ? cell.value.toString() : ''; + const lines = Math.ceil(text.length / (columnWidth - 2)); // Approximate number of lines + row.height = Math.max(row.height ?? 0, lines * 15); +} + +// Function to format cells in other rows +function formatOtherRows(row: any, frozeCells: boolean) { + row.eachCell((cell: any) => { + if (frozeCells) { + cell.protection = { locked: true }; } - worksheetRow.eachCell((cell: any) => { - if (frozeCells) { - cell.protection = { locked: true }; - } - }); }); +} - // Protect the entire sheet to enable cell protection settings +// Function to finalize the sheet settings +function finalizeSheet(sheet: any, frozeCells: boolean, frozeWholeSheet: boolean) { if (frozeCells) { performUnfreezeCells(sheet); } @@ -183,9 +207,13 @@ function addDataToSheet(sheet: any, sheetData: any, firstRowColor: any = '93C47D performFreezeWholeSheet(sheet); } updateFontNameToRoboto(sheet); + sheet.views = [{ state: 'frozen', ySplit: 1, zoomScale: 110 }]; } + + + function lockTargetFields(newSheet: any, columnsNotToBeFreezed: any, boundaryCodeColumnIndex: any) { // Make every cell locked by default newSheet.eachRow((row: any) => { diff --git a/health-services/project-factory/src/server/utils/generateUtils.ts b/health-services/project-factory/src/server/utils/generateUtils.ts new file mode 100644 index 00000000000..a8a03e65d7c --- /dev/null +++ b/health-services/project-factory/src/server/utils/generateUtils.ts @@ -0,0 +1,85 @@ +import { getLocalizedMessagesHandler, processGenerate, replicateRequest, throwError } from "./genericUtils"; +import _ from 'lodash'; +import { logger } from "./logger"; +import { getBoundarySheetData } from "../api/genericApis"; +import { getLocalisationModuleName } from "./localisationUtils"; + +// Now you can use Lodash functions with the "_" prefix, e.g., _.isEqual(), _.sortBy(), etc. +function extractProperties(obj: any) { + return { + code: obj.code || null, + includeAllChildren: obj.includeAllChildren || null, + isRoot: obj.isRoot || null + }; +} + +function areBoundariesSame(existingBoundaries: any, currentBoundaries: any) { + if (!existingBoundaries || !currentBoundaries) return false; + if (existingBoundaries.length !== currentBoundaries.length) return false; + const existingSetOfBoundaries = new Set(existingBoundaries.map((exboundary: any) => JSON.stringify(extractProperties(exboundary)))); + const currentSetOfBoundaries = new Set(currentBoundaries.map((currboundary: any) => JSON.stringify(extractProperties(currboundary)))); + return _.isEqual(existingSetOfBoundaries, currentSetOfBoundaries); +} + +async function callGenerateIfBoundariesDiffer(request: any) { + try { + const ExistingCampaignDetails = request?.body?.ExistingCampaignDetails; + if (ExistingCampaignDetails) { + if (!areBoundariesSame(ExistingCampaignDetails?.boundaries, request?.body?.CampaignDetails?.boundaries)) { + logger.info("Boundaries differ, generating new resources"); + + const newRequestBody = { + RequestInfo: request?.body?.RequestInfo, + Filters: { + boundaries: request?.body?.CampaignDetails?.boundaries + } + }; + + const { query } = request; + const params = { + tenantId: request?.body?.CampaignDetails?.tenantId, + forceUpdate: 'true', + hierarchyType: request?.body?.CampaignDetails?.hierarchyType, + campaignId: request?.body?.CampaignDetails?.id + }; + + const newParamsBoundary = { ...query, ...params, type: "boundary" }; + const newRequestBoundary = replicateRequest(request, newRequestBody, newParamsBoundary); + await callGenerate(newRequestBoundary, "boundary"); + + const newParamsFacilityWithBoundary = { ...query, ...params, type: "facilityWithBoundary" }; + const newRequestFacilityWithBoundary = replicateRequest(request, newRequestBody, newParamsFacilityWithBoundary); + await callGenerate(newRequestFacilityWithBoundary, "facilityWithBoundary"); + + const newParamsUserWithBoundary = { ...query, ...params, type: "userWithBoundary" }; + const newRequestUserWithBoundary = replicateRequest(request, newRequestBody, newParamsUserWithBoundary); + await callGenerate(newRequestUserWithBoundary, "userWithBoundary"); + } + } + } catch (error: any) { + logger.error(error); + throwError("COMMON", 400, "GENERATE_ERROR", `Error while generating user/facility/boundary: ${error.message}`); + } +} + +async function callGenerate(request: any, type: any, enableCaching = false) { + logger.info(`calling generate api for type ${type}`); + if (type === "facilityWithBoundary" || type == "userWithBoundary") { + const { hierarchyType } = request.query; + const localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler( + request, + request.query.tenantId, + getLocalisationModuleName(hierarchyType) + ); + const localizationMapModule = await getLocalizedMessagesHandler(request, request.query.tenantId); + const localizationMap = { ...localizationMapHierarchy, ...localizationMapModule }; + const filteredBoundary = await getBoundarySheetData(request, localizationMap); + await processGenerate(request, enableCaching, filteredBoundary); + } else { + await processGenerate(request, enableCaching); + } +} + + + +export { callGenerateIfBoundariesDiffer, callGenerate, areBoundariesSame } diff --git a/health-services/project-factory/src/server/utils/genericUtils.ts b/health-services/project-factory/src/server/utils/genericUtils.ts index fa3c194b8ca..df6f5ec8bfb 100644 --- a/health-services/project-factory/src/server/utils/genericUtils.ts +++ b/health-services/project-factory/src/server/utils/genericUtils.ts @@ -2,20 +2,21 @@ import { NextFunction, Request, Response } from "express"; import { httpRequest, defaultheader } from "./request"; import config, { getErrorCodes } from "../config/index"; import { v4 as uuidv4 } from 'uuid'; -import { produceModifiedMessages } from "../kafka/Listener"; +import { produceModifiedMessages } from "../kafka/Producer"; import { generateHierarchyList, getAllFacilities, getCampaignSearchResponse, getHierarchy } from "../api/campaignApis"; import { getBoundarySheetData, getSheetData, createAndUploadFile, createExcelSheet, getTargetSheetData, callMdmsData, callMdmsTypeSchema } from "../api/genericApis"; import { logger } from "./logger"; -import { getConfigurableColumnHeadersBasedOnCampaignType, getDifferentTabGeneratedBasedOnConfig, getLocalizedName } from "./campaignUtils"; +import { checkIfSourceIsMicroplan, getConfigurableColumnHeadersBasedOnCampaignType, getDifferentTabGeneratedBasedOnConfig, getLocalizedName } from "./campaignUtils"; import Localisation from "../controllers/localisationController/localisation.controller"; import { executeQuery } from "./db"; import { generatedResourceTransformer } from "./transforms/searchResponseConstructor"; import { generatedResourceStatuses, headingMapping, resourceDataStatuses } from "../config/constants"; -import { getLocaleFromRequest, getLocalisationModuleName } from "./localisationUtils"; +import { getLocaleFromRequest, getLocaleFromRequestInfo, getLocalisationModuleName } from "./localisationUtils"; import { getBoundaryColumnName, getBoundaryTabName } from "./boundaryUtils"; import { getBoundaryDataService } from "../service/dataManageService"; import { addDataToSheet, formatWorksheet, getNewExcelWorkbook, updateFontNameToRoboto } from "./excelUtils"; import createAndSearch from "../config/createAndSearch"; +import { generateDynamicTargetHeaders } from "./targetUtils"; const NodeCache = require("node-cache"); const updateGeneratedResourceTopic = config?.kafka?.KAFKA_UPDATE_GENERATED_RESOURCE_DETAILS_TOPIC; @@ -51,6 +52,12 @@ const throwErrorViaRequest = (message: any = "Internal Server Error") => { } }; +function shutdownGracefully() { + logger.info('Shutting down gracefully...'); + // Perform any cleanup tasks here, like closing database connections + process.exit(1); // Exit with a non-zero code to indicate an error +} + function capitalizeFirstLetter(str: string | undefined) { if (!str) return str; return str.charAt(0).toUpperCase() + str.slice(1); @@ -240,27 +247,47 @@ async function generateActivityMessage(tenantId: any, requestBody: any, requestP /* Fetches data from the database */ async function searchGeneratedResources(request: any) { try { - const { type } = request.query; - const { tenantId, hierarchyType } = request.query; - const status = generatedResourceStatuses.completed; - let queryResult: any; - let queryString: string; + const { type, tenantId, hierarchyType, id, status, campaignId } = request.query; + let queryString = `SELECT * FROM ${config?.DB_CONFIG.DB_GENERATED_RESOURCE_DETAILS_TABLE_NAME} WHERE `; + let queryConditions: string[] = []; let queryValues: any[] = []; + if (id) { + queryConditions.push(`id = $${queryValues.length + 1}`); + queryValues.push(id); + } + if (type) { + queryConditions.push(`type = $${queryValues.length + 1}`); + queryValues.push(type); + } - queryString = `SELECT * FROM ${config?.DB_CONFIG.DB_GENERATED_RESOURCE_DETAILS_TABLE_NAME} WHERE `; - // query for download with id - if (request?.query?.id) { - queryString += "id = $1 AND type = $2 AND hierarchytype = $3 AND tenantid = $4 "; - queryValues = [request.query.id, type, hierarchyType, tenantId]; + if (hierarchyType) { + queryConditions.push(`hierarchyType = $${queryValues.length + 1}`); + queryValues.push(hierarchyType); } - else { - queryString += "type = $1 AND hierarchytype = $2 AND tenantid = $3 AND status =$4 "; - queryValues = [type, hierarchyType, tenantId, status]; + if (tenantId) { + queryConditions.push(`tenantId = $${queryValues.length + 1}`); + queryValues.push(tenantId); + } + if (campaignId) { + queryConditions.push(`campaignId = $${queryValues.length + 1}`); + queryValues.push(campaignId); } - queryResult = await executeQuery(queryString, queryValues); + if (status) { + const statusArray = status.split(',').map((s: any) => s.trim()); + const statusConditions = statusArray.map((_: any, index: any) => `status = $${queryValues.length + index + 1}`); + queryConditions.push(`(${statusConditions.join(' OR ')})`); + queryValues.push(...statusArray); + } + + queryString += queryConditions.join(" AND "); + + // Add sorting and limiting + queryString += " ORDER BY createdTime DESC OFFSET 0 LIMIT 1"; + + const queryResult = await executeQuery(queryString, queryValues); return generatedResourceTransformer(queryResult?.rows); - } - catch (error: any) { + } catch (error: any) { + console.log(error) logger.error(`Error fetching data from the database: ${error.message}`); throwError("COMMON", 500, "INTERNAL_SERVER_ERROR", error?.message); return null; // Return null in case of an error @@ -300,7 +327,8 @@ async function generateNewRequestObject(request: any) { lastModifiedBy: request?.body?.RequestInfo?.userInfo.uuid, }, additionalDetails: additionalDetails, - count: null + count: null, + campaignId: request?.query?.campaignId }; return [newEntry]; } @@ -333,20 +361,20 @@ async function getFinalUpdatedResponse(result: any, responseData: any, request: -async function fullProcessFlowForNewEntry(newEntryResponse: any, generatedResource: any, request: any) { +async function fullProcessFlowForNewEntry(newEntryResponse: any, generatedResource: any, request: any, enableCaching = false, filteredBoundary?: any) { try { const { type, hierarchyType } = request?.query; generatedResource = { generatedResource: newEntryResponse } // send message to create toppic logger.info(`processing the generate request for type ${type}`) - produceModifiedMessages(generatedResource, createGeneratedResourceTopic); + await produceModifiedMessages(generatedResource, createGeneratedResourceTopic); const localizationMapHierarchy = hierarchyType && await getLocalizedMessagesHandler(request, request?.query?.tenantId, getLocalisationModuleName(hierarchyType)); const localizationMapModule = await getLocalizedMessagesHandler(request, request?.query?.tenantId); const localizationMap = { ...localizationMapHierarchy, ...localizationMapModule }; if (type === 'boundary') { // get boundary data from boundary relationship search api logger.info("Generating Boundary Data") - const boundaryDataSheetGeneratedBeforeDifferentTabSeparation = await getBoundaryDataService(request); + const boundaryDataSheetGeneratedBeforeDifferentTabSeparation = await getBoundaryDataService(request, enableCaching); logger.info(`Boundary data generated successfully: ${JSON.stringify(boundaryDataSheetGeneratedBeforeDifferentTabSeparation)}`); // get boundary sheet data after being generated logger.info("generating different tabs logic ") @@ -355,18 +383,19 @@ async function fullProcessFlowForNewEntry(newEntryResponse: any, generatedResour const finalResponse = await getFinalUpdatedResponse(boundaryDataSheetGeneratedAfterDifferentTabSeparation, newEntryResponse, request); const generatedResourceNew: any = { generatedResource: finalResponse } // send to update topic - produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); + await produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); request.body.generatedResource = finalResponse; } else if (type == "facilityWithBoundary" || type == 'userWithBoundary') { - await processGenerateRequest(request, localizationMap); + await processGenerateRequest(request, localizationMap, filteredBoundary); const finalResponse = await getFinalUpdatedResponse(request?.body?.fileDetails, newEntryResponse, request); const generatedResourceNew: any = { generatedResource: finalResponse } - produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); + await produceModifiedMessages(generatedResourceNew, updateGeneratedResourceTopic); request.body.generatedResource = finalResponse; } } catch (error: any) { - handleGenerateError(newEntryResponse, generatedResource, error); + console.log(error) + await handleGenerateError(newEntryResponse, generatedResource, error); } } @@ -420,13 +449,40 @@ function correctParentValues(campaignDetails: any) { return campaignDetails; } +function setDropdownFromSchema(request: any, schema: any, localizationMap?: { [key: string]: string }) { + const dropdowns = Object.entries(schema.properties) + .filter(([key, value]: any) => Array.isArray(value.enum) && value.enum.length > 0) + .reduce((result: any, [key, value]: any) => { + // Transform the key using localisedValue function + const newKey: any = getLocalizedName(key, localizationMap); + result[newKey] = value.enum; + return result; + }, {}); + logger.info(`dropdowns to set ${JSON.stringify(dropdowns)}`) + request.body.dropdowns = dropdowns; +} + async function createFacilitySheet(request: any, allFacilities: any[], localizationMap?: { [key: string]: string }) { const tenantId = request?.query?.tenantId; - const schema = await callMdmsTypeSchema(request, tenantId, "facility"); + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const isSourceMicroplan = checkIfSourceIsMicroplan(responseFromCampaignSearch?.CampaignDetails?.[0]); + let schema; + if (isSourceMicroplan) { + schema = await callMdmsTypeSchema(request, tenantId, "facility", "microplan"); + } else { + schema = await callMdmsTypeSchema(request, tenantId, "facility", "all"); + } const keys = schema?.columns; + setDropdownFromSchema(request, schema, localizationMap); const headers = ["HCM_ADMIN_CONSOLE_FACILITY_CODE", ...keys] - const localizedHeaders = getLocalizedHeaders(headers, localizationMap); + let localizedHeaders; + if (isSourceMicroplan) { + localizedHeaders = getLocalizedHeadersForMicroplan(responseFromCampaignSearch, headers, localizationMap); + } + else { + localizedHeaders = getLocalizedHeaders(headers, localizationMap); + } const facilities = allFacilities.map((facility: any) => { return [ facility?.id, @@ -471,13 +527,15 @@ async function createReadMeSheet(request: any, workbook: any, mainHeader: any, l const headerSet = new Set(); - const datas = readMeConfig.texts.flatMap((text: any) => { - const descriptions = text.descriptions.map((description: any) => { - return getLocalizedName(description.text, localizationMap); + const datas = readMeConfig.texts + .filter((text: any) => text?.inSheet) // Filter out texts with inSheet set to false + .flatMap((text: any) => { + const descriptions = text.descriptions.map((description: any) => { + return getLocalizedName(description.text, localizationMap); + }); + headerSet.add(getLocalizedName(text.header, localizationMap)); + return [getLocalizedName(text.header, localizationMap), ...descriptions, ""]; }); - headerSet.add(getLocalizedName(text.header, localizationMap)); - return [getLocalizedName(text.header, localizationMap), ...descriptions, "", "", "", ""]; - }); // Create the worksheet and add the main header const worksheet = workbook.addWorksheet(getLocalizedName("HCM_README_SHEETNAME", localizationMap)); @@ -525,6 +583,21 @@ function getLocalizedHeaders(headers: any, localizationMap?: { [key: string]: st return messages; } +function getLocalizedHeadersForMicroplan(responseFromCampaignSearch: any, headers: any, localizationMap?: { [key: string]: string }) { + + const projectType = responseFromCampaignSearch?.CampaignDetails?.[0]?.projectType; + + headers = headers.map((header: string) => { + if (header === 'HCM_ADMIN_CONSOLE_FACILITY_CAPACITY_MICROPLAN') { + return `${header}_${projectType}`; + } + return header; + }); + + const messages = headers.map((header: any) => (localizationMap ? localizationMap[header] || header : header)); + return messages; +} + function modifyRequestForLocalisation(request: any, tenantId: string) { @@ -594,6 +667,7 @@ async function createFacilityAndBoundaryFile(facilitySheetData: any, boundaryShe addDataToSheet(facilitySheet, facilitySheetData, undefined, undefined, true); hideUniqueIdentifierColumn(facilitySheet, createAndSearch?.["facility"]?.uniqueIdentifierColumn); changeFirstRowColumnColour(facilitySheet, 'E06666'); + await handledropdownthings(facilitySheet, request.body?.dropdowns); // Add boundary sheet to the workbook const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap); @@ -605,8 +679,41 @@ async function createFacilityAndBoundaryFile(facilitySheetData: any, boundaryShe request.body.fileDetails = fileDetails; } - -// Helper function to add data to a sheet +async function handledropdownthings(facilitySheet: any, dropdowns: any) { + let dropdownColumnIndex = -1; + if (dropdowns) { + for (const key of Object.keys(dropdowns)) { + if (dropdowns[key]) { + // Iterate through each row to find the column index of "Boundary Code (Mandatory)" + await facilitySheet.eachRow({ includeEmpty: true }, (row: any) => { + row.eachCell({ includeEmpty: true }, (cell: any, colNumber: any) => { + if (cell.value === key) { + dropdownColumnIndex = colNumber; + } + }); + }); + + // If dropdown column index is found, set multi-select dropdown for subsequent rows + if (dropdownColumnIndex !== -1) { + facilitySheet.getColumn(dropdownColumnIndex).eachCell({ includeEmpty: true }, (cell: any, rowNumber: any) => { + if (rowNumber > 1) { + // Set dropdown list with no typing allowed + cell.dataValidation = { + type: 'list', + formulae: [`"${dropdowns[key].join(',')}"`], + showDropDown: true, // Ensures dropdown is visible + error: 'Please select a value from the dropdown list.', + errorStyle: 'stop', // Prevents any input not in the list + showErrorMessage: true, // Ensures error message is shown + errorTitle: 'Invalid Entry' + }; + } + }); + } + } + } + } +} @@ -623,6 +730,7 @@ async function createUserAndBoundaryFile(userSheetData: any, boundarySheetData: const userSheet = workbook.addWorksheet(localizedUserTab); addDataToSheet(userSheet, userSheetData, undefined, undefined, true); + await handledropdownthings(userSheet, request.body?.dropdowns); // Add boundary sheet to the workbook const localizedBoundaryTab = getLocalizedName(getBoundaryTabName(), localizationMap) const boundarySheet = workbook.addWorksheet(localizedBoundaryTab); @@ -633,7 +741,7 @@ async function createUserAndBoundaryFile(userSheetData: any, boundarySheetData: } -async function generateFacilityAndBoundarySheet(tenantId: string, request: any, localizationMap?: { [key: string]: string }) { +async function generateFacilityAndBoundarySheet(tenantId: string, request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any) { // Get facility and boundary data logger.info("Generating facilities started"); const allFacilities = await getAllFacilities(tenantId, request.body); @@ -641,38 +749,49 @@ async function generateFacilityAndBoundarySheet(tenantId: string, request: any, logger.info(`Facilities generation completed and found ${allFacilities?.length} facilities`); const facilitySheetData: any = await createFacilitySheet(request, allFacilities, localizationMap); // request.body.Filters = { tenantId: tenantId, hierarchyType: request?.query?.hierarchyType, includeChildren: true } - const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); - await createFacilityAndBoundaryFile(facilitySheetData, boundarySheetData, request, localizationMap); + if (filteredBoundary && filteredBoundary.length > 0) { + await createFacilityAndBoundaryFile(facilitySheetData, filteredBoundary, request, localizationMap); + } + else { + const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); + await createFacilityAndBoundaryFile(facilitySheetData, boundarySheetData, request, localizationMap); + } } -async function generateUserAndBoundarySheet(request: any, localizationMap?: { [key: string]: string }) { +async function generateUserAndBoundarySheet(request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any) { const userData: any[] = []; const tenantId = request?.query?.tenantId; const schema = await callMdmsTypeSchema(request, tenantId, "user"); + setDropdownFromSchema(request, schema, localizationMap); const headers = schema?.columns; const localizedHeaders = getLocalizedHeaders(headers, localizationMap); // const localizedUserTab = getLocalizedName(config?.user?.userTab, localizationMap); logger.info("Generated an empty user template"); const userSheetData = await createExcelSheet(userData, localizedHeaders); - const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); - await createUserAndBoundaryFile(userSheetData, boundarySheetData, request, localizationMap); + if (filteredBoundary && filteredBoundary.length > 0) { + await createUserAndBoundaryFile(userSheetData, filteredBoundary, request, localizationMap); + } + else { + const boundarySheetData: any = await getBoundarySheetData(request, localizationMap); + await createUserAndBoundaryFile(userSheetData, boundarySheetData, request, localizationMap); + } } -async function processGenerateRequest(request: any, localizationMap?: { [key: string]: string }) { +async function processGenerateRequest(request: any, localizationMap?: { [key: string]: string }, filteredBoundary?: any) { const { type, tenantId } = request.query if (type == "facilityWithBoundary") { - await generateFacilityAndBoundarySheet(String(tenantId), request, localizationMap); + await generateFacilityAndBoundarySheet(String(tenantId), request, localizationMap, filteredBoundary); } if (type == "userWithBoundary") { - await generateUserAndBoundarySheet(request, localizationMap); + await generateUserAndBoundarySheet(request, localizationMap, filteredBoundary); } } -async function processGenerateForNew(request: any, generatedResource: any, newEntryResponse: any) { +async function processGenerateForNew(request: any, generatedResource: any, newEntryResponse: any, enableCaching = false, filteredBoundary?: any) { request.body.generatedResource = newEntryResponse; - fullProcessFlowForNewEntry(newEntryResponse, generatedResource, request); + await fullProcessFlowForNewEntry(newEntryResponse, generatedResource, request, enableCaching, filteredBoundary); return request.body.generatedResource; } -function handleGenerateError(newEntryResponse: any, generatedResource: any, error: any) { +async function handleGenerateError(newEntryResponse: any, generatedResource: any, error: any) { newEntryResponse.map((item: any) => { item.status = generatedResourceStatuses.failed, item.additionalDetails = { ...item.additionalDetails, error: { @@ -685,21 +804,21 @@ function handleGenerateError(newEntryResponse: any, generatedResource: any, erro }) generatedResource = { generatedResource: newEntryResponse }; logger.error(String(error)); - produceModifiedMessages(generatedResource, updateGeneratedResourceTopic); + await produceModifiedMessages(generatedResource, updateGeneratedResourceTopic); } -async function updateAndPersistGenerateRequest(newEntryResponse: any, oldEntryResponse: any, responseData: any, request: any) { +async function updateAndPersistGenerateRequest(newEntryResponse: any, oldEntryResponse: any, responseData: any, request: any, enableCaching = false, filteredBoundary?: any) { const { forceUpdate } = request.query; const forceUpdateBool: boolean = forceUpdate === 'true'; let generatedResource: any; if (forceUpdateBool && responseData.length > 0) { generatedResource = { generatedResource: oldEntryResponse }; // send message to update topic - produceModifiedMessages(generatedResource, updateGeneratedResourceTopic); + await produceModifiedMessages(generatedResource, updateGeneratedResourceTopic); request.body.generatedResource = oldEntryResponse; } if (responseData.length === 0 || forceUpdateBool) { - processGenerateForNew(request, generatedResource, newEntryResponse) + processGenerateForNew(request, generatedResource, newEntryResponse, enableCaching, filteredBoundary) } else { request.body.generatedResource = responseData @@ -708,7 +827,7 @@ async function updateAndPersistGenerateRequest(newEntryResponse: any, oldEntryRe /* */ -async function processGenerate(request: any) { +async function processGenerate(request: any, enableCaching = false, filteredBoundary?: any) { // fetch the data from db to check any request already exists const responseData = await searchGeneratedResources(request); // modify response from db @@ -718,7 +837,7 @@ async function processGenerate(request: any) { // make old data status as expired const oldEntryResponse = await updateExistingResourceExpired(modifiedResponse, request); // generate data - await updateAndPersistGenerateRequest(newEntryResponse, oldEntryResponse, responseData, request); + await updateAndPersistGenerateRequest(newEntryResponse, oldEntryResponse, responseData, request, enableCaching, filteredBoundary); } /* TODO add comments @nitish-egov @@ -739,8 +858,11 @@ async function enrichResourceDetails(request: any) { lastModifiedBy: request?.body?.RequestInfo?.userInfo?.uuid, lastModifiedTime: Date.now() } + if (request.body.ResourceDetails.type === 'boundary') { + request.body.ResourceDetails.campaignId = null; + } const persistMessage: any = { ResourceDetails: request.body.ResourceDetails }; - produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_CREATE_RESOURCE_DETAILS_TOPIC); + await produceModifiedMessages(persistMessage, config?.kafka?.KAFKA_CREATE_RESOURCE_DETAILS_TOPIC); } function getFacilityIds(data: any) { @@ -931,6 +1053,13 @@ async function getLocalizedMessagesHandler(request: any, tenantId: any, module = return localizationResponse; } +async function getLocalizedMessagesHandlerViaRequestInfo(RequestInfo: any, tenantId: any, module = config.localisation.localizationModule) { + const localisationcontroller = Localisation.getInstance(); + const locale = getLocaleFromRequestInfo(RequestInfo); + const localizationResponse = await localisationcontroller.getLocalisedData(module, locale, tenantId); + return localizationResponse; +} + async function translateSchema(schema: any, localizationMap?: { [key: string]: string }) { @@ -983,25 +1112,78 @@ function getDifferentDistrictTabs(boundaryData: any, differentTabsBasedOnLevel: } -async function getConfigurableColumnHeadersFromSchemaForTargetSheet(request: any, hierarchy: any, boundaryData: any, differentTabsBasedOnLevel: any, localizationMap?: any) { +async function getConfigurableColumnHeadersFromSchemaForTargetSheet(request: any, hierarchy: any, boundaryData: any, differentTabsBasedOnLevel: any, campaignObject: any, localizationMap?: any) { const districtIndex = hierarchy.indexOf(differentTabsBasedOnLevel); - var headers = getLocalizedHeaders(hierarchy.slice(districtIndex), localizationMap); - - const headerColumnsAfterHierarchy = await getConfigurableColumnHeadersBasedOnCampaignType(request); + let headers: any; + const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); + if (isSourceMicroplan) { + logger.info(`Source is Microplan.`); + headers = getLocalizedHeaders(hierarchy, localizationMap); + } + else { + headers = getLocalizedHeaders(hierarchy.slice(districtIndex), localizationMap); + } + const headerColumnsAfterHierarchy = await generateDynamicTargetHeaders(request, campaignObject, localizationMap); const localizedHeadersAfterHierarchy = getLocalizedHeaders(headerColumnsAfterHierarchy, localizationMap); - headers = [...headers, ...localizedHeadersAfterHierarchy] + headers = [...headers, getLocalizedName(config?.boundary?.boundaryCode, localizationMap), ...localizedHeadersAfterHierarchy] return getLocalizedHeaders(headers, localizationMap); } async function getMdmsDataBasedOnCampaignType(request: any, localizationMap?: any) { const responseFromCampaignSearch = await getCampaignSearchResponse(request); - const campaignType = responseFromCampaignSearch?.CampaignDetails[0]?.projectType; + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + let campaignType = campaignObject.projectType; + const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); + campaignType = (isSourceMicroplan) ? `${config?.prefixForMicroplanCampaigns}-${campaignType}` : campaignType; const mdmsResponse = await callMdmsTypeSchema(request, request?.query?.tenantId || request?.body?.ResourceDetails?.tenantId, request?.query?.type || request?.body?.ResourceDetails?.type, campaignType) return mdmsResponse; } +function appendProjectTypeToCapacity(schema: any, projectType: string): any { + const updatedSchema = JSON.parse(JSON.stringify(schema)); // Deep clone the schema + + const capacityKey = 'HCM_ADMIN_CONSOLE_FACILITY_CAPACITY_MICROPLAN'; + const newCapacityKey = `${capacityKey}_${projectType}`; + + // Update properties + if (updatedSchema.properties[capacityKey]) { + updatedSchema.properties[newCapacityKey] = { + ...updatedSchema.properties[capacityKey], + name: `${updatedSchema.properties[capacityKey].name}_${projectType}` + }; + delete updatedSchema.properties[capacityKey]; + } + + // Update required + updatedSchema.required = updatedSchema.required.map((item: string) => + item === capacityKey ? newCapacityKey : item + ); + + // Update columns + updatedSchema.columns = updatedSchema.columns.map((item: string) => + item === capacityKey ? newCapacityKey : item + ); + + // Update unique + updatedSchema.unique = updatedSchema.unique.map((item: string) => + item === capacityKey ? newCapacityKey : item + ); + + // Update errorMessage + if (updatedSchema.errorMessage[capacityKey]) { + updatedSchema.errorMessage[newCapacityKey] = updatedSchema.errorMessage[capacityKey]; + delete updatedSchema.errorMessage[capacityKey]; + } + + // Update columnsNotToBeFreezed + updatedSchema.columnsNotToBeFreezed = updatedSchema.columnsNotToBeFreezed.map((item: string) => + item === capacityKey ? newCapacityKey : item + ); + + return updatedSchema; +} export { @@ -1048,7 +1230,10 @@ export { changeFirstRowColumnColour, getConfigurableColumnHeadersFromSchemaForTargetSheet, createBoundaryDataMainSheet, - getMdmsDataBasedOnCampaignType + getMdmsDataBasedOnCampaignType, + shutdownGracefully, + appendProjectTypeToCapacity, + getLocalizedMessagesHandlerViaRequestInfo }; diff --git a/health-services/project-factory/src/server/utils/localisationUtils.ts b/health-services/project-factory/src/server/utils/localisationUtils.ts index 0b1bd4804be..3d5585947ef 100644 --- a/health-services/project-factory/src/server/utils/localisationUtils.ts +++ b/health-services/project-factory/src/server/utils/localisationUtils.ts @@ -6,7 +6,15 @@ export const getLocaleFromRequest = (request: any) => { const msgId = request?.body?.RequestInfo?.msgId; // Split msgId by '|' delimiter and get the second part (index 1) // If splitting fails or no second part is found, use default locale from config - return msgId.split("|")?.[1] || config?.localisation?.defaultLocale; + return msgId?.split("|")?.[1] || config?.localisation?.defaultLocale; +}; + +export const getLocaleFromRequestInfo = (RequestInfo: any) => { + // Extract msgId from request body + const msgId = RequestInfo?.msgId; + // Split msgId by '|' delimiter and get the second part (index 1) + // If splitting fails or no second part is found, use default locale from config + return msgId?.split("|")?.[1] || config?.localisation?.defaultLocale; }; // Function to generate localisation module name based on hierarchy type @@ -22,17 +30,17 @@ export const getLocalisationModuleName = (hierarchyType: any) => { * @returns The transformed locale string. */ export const getTransformedLocale = (label: string) => { - // Trim leading and trailing whitespace from the label - label = label?.trim(); - // If label is not empty, convert to uppercase and replace special characters with underscores - return label && label.toUpperCase().replace(/[.:-\s\/]/g, "_"); - }; + // Trim leading and trailing whitespace from the label + label = label?.trim(); + // If label is not empty, convert to uppercase and replace special characters with underscores + return label && label.toUpperCase().replace(/[.:-\s\/]/g, "_"); +}; - export const convertLocalisationResponseToMap=(messages:any=[])=>{ - const localizationMap: any = {}; - messages.forEach((message: any) => { - localizationMap[message.code] = message.message; - }); - return localizationMap; - } \ No newline at end of file +export const convertLocalisationResponseToMap = (messages: any = []) => { + const localizationMap: any = {}; + messages.forEach((message: any) => { + localizationMap[message.code] = message.message; + }); + return localizationMap; +} \ No newline at end of file diff --git a/health-services/project-factory/src/server/utils/processTrackUtils.ts b/health-services/project-factory/src/server/utils/processTrackUtils.ts index d822e28fded..6d80346825f 100644 --- a/health-services/project-factory/src/server/utils/processTrackUtils.ts +++ b/health-services/project-factory/src/server/utils/processTrackUtils.ts @@ -1,52 +1,224 @@ import config from './../config'; -import { produceModifiedMessages } from '../kafka/Listener'; +import { produceModifiedMessages } from "../kafka/Producer";; import { v4 as uuidv4 } from 'uuid'; import { executeQuery } from './db'; +import { processTrackForUi, processTrackStatuses, processTrackTypes } from '../config/constants'; +import { logger } from './logger'; + +async function getProcessDetails(id: string, type?: string): Promise { + let query: string; + const values: any[] = [id]; + + logger.info(`Fetching process details for campaignId: ${id}${type ? `, type: ${type}` : ''}`); + + if (type) { + query = ` + SELECT * FROM ${config?.DB_CONFIG.DB_CAMPAIGN_PROCESS_TABLE_NAME} + WHERE campaignid = $1 AND type = $2 + ORDER BY lastmodifiedtime ASC; + `; + values.push(type); + } else { + query = ` + SELECT * FROM ${config?.DB_CONFIG.DB_CAMPAIGN_PROCESS_TABLE_NAME} + WHERE campaignid = $1 + ORDER BY lastmodifiedtime ASC; + `; + } -async function getProcessDetails(id: any): Promise { - const query = `SELECT * FROM ${config?.DB_CONFIG.DB_CAMPAIGN_PROCESS_TABLE_NAME} WHERE id = $1`; - const values = [id]; const queryResponse = await executeQuery(query, values); - return queryResponse.rows[0]; // Assuming only one row is expected + + if (queryResponse.rows.length === 0) { + logger.info('No process details found'); + return []; + } + const uiSet = new Set(processTrackForUi.map((item: any) => item)); + return queryResponse.rows.map((result: any) => ({ + id: result.id, + campaignId: result.campaignid, + type: result.type, + status: result.status, + showInUi: uiSet.has(result.type), + details: result.details, + additionalDetails: result.additionaldetails, + createdTime: parseInt(result.createdtime, 10), + lastModifiedTime: parseInt(result.lastmodifiedtime, 10), + })); } async function persistTrack( - campaignId: any, - type: any, - status: any, - details?: any, - additionalDetails?: any, - id?: any + campaignId: string, + type: string, + status: string, + details?: Record, + additionalDetails?: Record +): Promise { + if (!campaignId) { + logger.info('campaignId is missing, aborting persistTrack'); + return; + } + + logger.info(`Persisting track for campaignId: ${campaignId}, type: ${type}, status: ${status}`); + + if (type == processTrackTypes.error) { + await handleFailedStatus(campaignId, type, status, details, additionalDetails); + } else { + await handleNonFailedStatus(campaignId, type, status, details, additionalDetails); + } +} + +// Handles the case when the status is 'failed' +async function handleFailedStatus( + campaignId: string, + type: string, + status: string, + details?: Record, + additionalDetails?: Record +): Promise { + const processDetailsArray = await getProcessDetails(campaignId); + const inProgressProcessDetails = processDetailsArray.filter((processDetail: any) => processDetail.status === processTrackStatuses.inprogress); + const toBeCompletedProcessDetails = processDetailsArray.filter((processDetail: any) => processDetail.status === processTrackStatuses.toBeCompleted); + const failedStatusArray = processDetailsArray.filter((processDetail: any) => processDetail.status === processTrackStatuses.failed); + if (failedStatusArray.length > 0) { + logger.info('Process already failed, nothing to persist'); + await updateToBeCompletedProcess(toBeCompletedProcessDetails, status, details, additionalDetails, config?.kafka?.KAFKA_UPDATE_PROCESS_TRACK_TOPIC); + return; + } + if (inProgressProcessDetails.length > 0) { + logger.info('Generic fail occured so changing the lastest inprogress status to failed'); + await updateAndProduceMessage(inProgressProcessDetails[inProgressProcessDetails.length - 1], status, details, additionalDetails, config?.kafka?.KAFKA_UPDATE_PROCESS_TRACK_TOPIC); + } else { + logger.info('No inprogress process found, creating a new processDetail to failed'); + await createAndProduceNewProcessDetail(campaignId, type, status, details, additionalDetails, config?.kafka?.KAFKA_SAVE_PROCESS_TRACK_TOPIC); + } + await updateToBeCompletedProcess(toBeCompletedProcessDetails, status, details, additionalDetails, config?.kafka?.KAFKA_UPDATE_PROCESS_TRACK_TOPIC); +} + +async function updateToBeCompletedProcess( + processDetailsArray: any[], + status: string, + details?: Record, + additionalDetails?: Record, + kafkaTopic?: string) { + details = details || {}, + details.error = "HCM_PROCESS_TRACK_PREVIOUS_PROCESS_FAILED" + if (processDetailsArray.length > 0) { + for (let i = 0; i < processDetailsArray.length; i++) { + await updateAndProduceMessage(processDetailsArray[i], status, details, additionalDetails, kafkaTopic); + } + } +} + +// Handles the case when the status is not 'failed' +async function handleNonFailedStatus( + campaignId: string, + type: string, + status: string, + details?: Record, + additionalDetails?: Record ): Promise { - let processDetails: any; + const processDetailsArray = await getProcessDetails(campaignId, type); - if (id) { - processDetails = await getProcessDetails(id); - details = { ...processDetails?.details, ...details }; - additionalDetails = { ...processDetails?.additionalDetails, ...additionalDetails }; + if (processDetailsArray.length === 0) { + logger.info('No process details found, nothing to persist'); + return; } - const processId = id || uuidv4(); - const createdTime = Date.now(); - const lastModifiedTime = Date.now(); + updateAndProduceMessage(processDetailsArray[0], status, details, additionalDetails, config?.kafka?.KAFKA_UPDATE_PROCESS_TRACK_TOPIC); +} + +// Updates an existing process detail and produces the message +async function updateAndProduceMessage( + processDetails: any, + status: string, + details?: Record, + additionalDetails?: Record, + kafkaTopic?: string +) { + updateProcessDetails(processDetails, processDetails.type, status, details, additionalDetails); + const produceMessage: any = { processDetails }; + await produceModifiedMessages(produceMessage, kafkaTopic); +} - processDetails = { - id: processId, +// Creates a new process detail and produces the message +async function createAndProduceNewProcessDetail( + campaignId: string, + type: string, + status: string, + details?: Record, + additionalDetails?: Record, + kafkaTopic?: string +) { + const currentTime = Date.now(); + const processDetail: any = { + id: uuidv4(), campaignId, type, status, - details, - additionalDetails, - createdTime, - lastModifiedTime + createdTime: currentTime, + lastModifiedTime: currentTime, + details: details || {}, + additionalDetails: additionalDetails || {}, }; - const produceObject: any = { - processDetails - }; + updateProcessDetails(processDetail, type, status, details, additionalDetails); + const produceMessage: any = { processDetails: [processDetail] }; + await produceModifiedMessages(produceMessage, kafkaTopic); +} + + +function updateProcessDetails( + processDetails: any, + type: string, + status: string, + details?: any, + additionalDetails?: any +) { + processDetails.lastModifiedTime = Date.now(); + processDetails.details = { ...processDetails.details, ...details }; + processDetails.additionalDetails = { ...processDetails.additionalDetails, ...additionalDetails }; + processDetails.type = type; + processDetails.status = status; +} + +async function createProcessTracks(campaignId: string) { + logger.info(`Creating process tracks for campaignId: ${campaignId}`); + + const processDetailsArray: any[] = []; + + Object.keys(processTrackTypes).forEach(key => { + const type: any = (processTrackTypes as any)[key]; + const currentTime = Date.now(); + if (type != processTrackTypes.error) { + const processDetail: any = { + id: uuidv4(), + campaignId, + type, + status: processTrackStatuses.toBeCompleted, + createdTime: currentTime, + lastModifiedTime: currentTime, + details: {}, + additionalDetails: {} + }; + processDetailsArray.push(processDetail); + } + }); + + logger.info(`Created ${processDetailsArray.length} process tracks`); + const produceMessage: any = { processDetails: processDetailsArray } + await produceModifiedMessages(produceMessage, config?.kafka?.KAFKA_SAVE_PROCESS_TRACK_TOPIC); +} + +function getOrderedDetailsArray(toBeCompletedArray: any[]) { + const order = Object.values(processTrackTypes); + return toBeCompletedArray.sort((a, b) => order.indexOf(a.type) - order.indexOf(b.type)); +} - const topic = id ? config?.kafka?.KAFKA_UPDATE_PROCESS_TRACK_TOPIC : config?.kafka?.KAFKA_SAVE_PROCESS_TRACK_TOPIC; - produceModifiedMessages(produceObject, topic); +export function modifyProcessDetails(processDetailsArray: any[]) { + const toBeCompletedArray = processDetailsArray.filter((item: any) => item.status === processTrackStatuses.toBeCompleted); + const orderedToBeCompletedArray = getOrderedDetailsArray(toBeCompletedArray); + const otherArray = processDetailsArray.filter((item: any) => item.status !== processTrackStatuses.toBeCompleted); + return otherArray.concat(orderedToBeCompletedArray); } -export { persistTrack }; \ No newline at end of file +export { persistTrack, getProcessDetails, createProcessTracks }; diff --git a/health-services/project-factory/src/server/utils/targetUtils.ts b/health-services/project-factory/src/server/utils/targetUtils.ts new file mode 100644 index 00000000000..74a91782dba --- /dev/null +++ b/health-services/project-factory/src/server/utils/targetUtils.ts @@ -0,0 +1,137 @@ +import config from '../config' +import { checkIfSourceIsMicroplan, getConfigurableColumnHeadersBasedOnCampaignType, getLocalizedName } from './campaignUtils'; +import _ from 'lodash'; +import { replicateRequest } from './genericUtils'; +import { callGenerate } from './generateUtils'; + + +async function generateDynamicTargetHeaders(request: any, campaignObject: any, localizationMap?: any) { + const isSourceMicroplan = checkIfSourceIsMicroplan(campaignObject); + let headerColumnsAfterHierarchy: any; + if (isDynamicTargetTemplateForProjectType(campaignObject?.projectType) && campaignObject.deliveryRules && campaignObject.deliveryRules.length > 0 && !isSourceMicroplan) { + const modifiedUniqueDeliveryConditions = modifyDeliveryConditions(campaignObject.deliveryRules); + headerColumnsAfterHierarchy = generateTargetColumnsBasedOnDeliveryConditions(modifiedUniqueDeliveryConditions, localizationMap); + + } + else { + headerColumnsAfterHierarchy = await getConfigurableColumnHeadersBasedOnCampaignType(request); + headerColumnsAfterHierarchy.shift(); + } + return headerColumnsAfterHierarchy; +} + + +function modifyDeliveryConditions(dataa: any[]): any { + let resultSet = new Set(); + dataa.forEach((delivery) => { + const conditions = delivery.conditions; + let newArray: any[] = []; + + conditions.forEach((item: any) => { + const existingIndex = newArray.findIndex( + (element) => element.attribute.code === item.attribute + ); + + if (existingIndex !== -1) { + const existingItem = newArray[existingIndex]; + // Combine conditions if necessary + if (existingItem.operator.code !== item.operator.code) { + newArray[existingIndex] = { + attribute: existingItem.attribute, + operator: { code: "IN_BETWEEN" }, + toValue: + existingItem.value && item.value ? Math.max(existingItem.value, item.value) : null, + fromValue: + existingItem.value && item.value ? Math.min(existingItem.value, item.value) : null + }; + } + } else { + // If attribute does not exist in newArray, add the item + newArray.push({ + attribute: { code: item.attribute }, + operator: { code: item.operator }, + value: item.value + }); + } + }); + newArray.map((element: any) => { + const stringifiedElement = JSON.stringify(element); // Convert object to string + resultSet.add(stringifiedElement); + }) + }); + return resultSet; +} + + +function generateTargetColumnsBasedOnDeliveryConditions(uniqueDeliveryConditions: any, localizationMap?: any) { + const targetColumnsBasedOnDeliveryConditions: string[] = []; + uniqueDeliveryConditions.forEach((str: any, index: number) => { + const uniqueDeliveryConditionsObject = JSON.parse(str); // Parse JSON string into object + const targetColumnString = createTargetString(uniqueDeliveryConditionsObject, localizationMap); + targetColumnsBasedOnDeliveryConditions.push(targetColumnString); + }); + if (targetColumnsBasedOnDeliveryConditions.length > 18) { + targetColumnsBasedOnDeliveryConditions.splice(18); + targetColumnsBasedOnDeliveryConditions.push(getLocalizedName("OTHER_TARGETS", localizationMap)); + } + return targetColumnsBasedOnDeliveryConditions; +} + +function createTargetString(uniqueDeliveryConditionsObject: any, localizationMap?: any) { + let targetString: any; + const prefix = getLocalizedName("HCM_ADMIN_CONSOLE_TARGET_SMC", localizationMap); + const attributeCode = getLocalizedName(uniqueDeliveryConditionsObject.attribute.code.toUpperCase(), localizationMap); + const operatorMessage = getLocalizedName(uniqueDeliveryConditionsObject.operator.code, localizationMap); + const localizedFROM = getLocalizedName("FROM", localizationMap); + const localizedTO = getLocalizedName("TO", localizationMap); + if (uniqueDeliveryConditionsObject.operator.code === 'IN_BETWEEN') { + targetString = `${prefix} ${attributeCode} ${localizedFROM} ${uniqueDeliveryConditionsObject.fromValue} ${localizedTO} ${uniqueDeliveryConditionsObject.toValue}`; + } else { + targetString = `${prefix} ${attributeCode} ${operatorMessage} ${uniqueDeliveryConditionsObject.value}`; + } + return targetString; +} + +async function updateTargetColumnsIfDeliveryConditionsDifferForSMC(request: any) { + const existingCampaignDetails = request?.body?.ExistingCampaignDetails; + if (existingCampaignDetails) { + if (isDynamicTargetTemplateForProjectType(request?.body?.CampaignDetails?.projectType) && config?.isCallGenerateWhenDeliveryConditionsDiffer && !_.isEqual(existingCampaignDetails?.deliveryRules, request?.body?.CampaignDetails?.deliveryRules)) { + const newRequestBody = { + RequestInfo: request?.body?.RequestInfo, + Filters: { + boundaries: request?.body?.CampaignDetails?.boundaries + } + }; + + const { query } = request; + const params = { + tenantId: request?.body?.CampaignDetails?.tenantId, + forceUpdate: 'true', + hierarchyType: request?.body?.CampaignDetails?.hierarchyType, + campaignId: request?.body?.CampaignDetails?.id + }; + + const newParamsBoundary = { ...query, ...params, type: "boundary" }; + const newRequestBoundary = replicateRequest(request, newRequestBody, newParamsBoundary); + await callGenerate(newRequestBoundary, "boundary", true); + } + } +} + +function isDynamicTargetTemplateForProjectType(projectType: string) { + const projectTypesFromConfig = config?.enableDynamicTemplateFor; + const projectTypesArray = projectTypesFromConfig ? projectTypesFromConfig.split(',') : []; + return projectTypesArray.includes(projectType); +} + + + + + +export { + modifyDeliveryConditions, + generateTargetColumnsBasedOnDeliveryConditions, + generateDynamicTargetHeaders, + updateTargetColumnsIfDeliveryConditionsDifferForSMC, + isDynamicTargetTemplateForProjectType +}; diff --git a/health-services/project-factory/src/server/validators/campaignValidators.ts b/health-services/project-factory/src/server/validators/campaignValidators.ts index cddd2c9958a..8c50b9bcd46 100644 --- a/health-services/project-factory/src/server/validators/campaignValidators.ts +++ b/health-services/project-factory/src/server/validators/campaignValidators.ts @@ -2,7 +2,7 @@ import createAndSearch from "../config/createAndSearch"; import config from "../config"; import { getFormattedStringForDebug, logger } from "../utils/logger"; import { defaultheader, httpRequest } from "../utils/request"; -import { getHeadersOfBoundarySheet, getHierarchy, handleResouceDetailsError } from "../api/campaignApis"; +import { getCampaignSearchResponse, getHeadersOfBoundarySheet, getHierarchy, handleResouceDetailsError } from "../api/campaignApis"; import { campaignDetailsSchema } from "../config/models/campaignDetails"; import Ajv from "ajv"; import { getDifferentDistrictTabs, getLocalizedHeaders, getLocalizedMessagesHandler, getMdmsDataBasedOnCampaignType, replicateRequest, throwError } from "../utils/genericUtils"; @@ -20,7 +20,7 @@ import { searchProjectTypeCampaignService } from "../service/campaignManageServi import { campaignStatuses, resourceDataStatuses } from "../config/constants"; import { getBoundaryColumnName, getBoundaryTabName } from "../utils/boundaryUtils"; import addAjvErrors from "ajv-errors"; - +import { generateTargetColumnsBasedOnDeliveryConditions, isDynamicTargetTemplateForProjectType, modifyDeliveryConditions } from "../utils/targetUtils"; @@ -83,75 +83,75 @@ async function fetchBoundariesFromCampaignDetails(request: any) { return responseBoundaries; } -// Compares unique boundaries with response boundaries and throws error for missing codes. -function compareBoundariesWithUnique(uniqueBoundaries: any[], responseBoundaries: any[], request: any) { - // Extracts boundary codes from response boundaries - const responseBoundaryCodes = responseBoundaries.map(boundary => boundary.code.trim()); - - // Finds missing codes from unique boundaries - const missingCodes = uniqueBoundaries.filter(code => !responseBoundaryCodes.includes(code)); - - // Throws error if missing codes exist - if (missingCodes.length > 0) { - throwError( - "COMMON", - 400, - "VALIDATION_ERROR", - `Boundary codes ${missingCodes.join(', ')} do not exist in hierarchyType ${request?.body?.ResourceDetails?.hierarchyType}` - ); - } -} +// // Compares unique boundaries with response boundaries and throws error for missing codes. +// function compareBoundariesWithUnique(uniqueBoundaries: any[], responseBoundaries: any[], request: any) { +// // Extracts boundary codes from response boundaries +// const responseBoundaryCodes = responseBoundaries.map(boundary => boundary.code.trim()); + +// // Finds missing codes from unique boundaries +// const missingCodes = uniqueBoundaries.filter(code => !responseBoundaryCodes.includes(code)); + +// // Throws error if missing codes exist +// if (missingCodes.length > 0) { +// throwError( +// "COMMON", +// 400, +// "VALIDATION_ERROR", +// `Boundary codes ${missingCodes.join(', ')} do not exist in hierarchyType ${request?.body?.ResourceDetails?.hierarchyType}` +// ); +// } +// } // Validates unique boundaries against the response boundaries. -async function validateUniqueBoundaries(uniqueBoundaries: any[], request: any) { - // Fetches response boundaries in chunks - const responseBoundaries = await fetchBoundariesInChunks(request); +// async function validateUniqueBoundaries(uniqueBoundaries: any[], request: any) { +// // Fetches response boundaries in chunks +// const responseBoundaries = await fetchBoundariesInChunks(request); - // Compares unique boundaries with response boundaries - compareBoundariesWithUnique(uniqueBoundaries, responseBoundaries, request); -} +// // Compares unique boundaries with response boundaries +// compareBoundariesWithUnique(uniqueBoundaries, responseBoundaries, request); +// } -async function validateBoundaryData(data: any[], request: any, boundaryColumn: any, localizationMap: any) { - const boundarySet = new Set(); // Create a Set to store unique boundaries - logger.info("validating for the boundary data") - const activeColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName, localizationMap) : null; - const uniqueIdentifierColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName, localizationMap) : null; - if (activeColumnName && uniqueIdentifierColumnName) { - data = data.filter((item: any) => item[activeColumnName] === "Active" || !item[uniqueIdentifierColumnName]); - data.forEach((item: any) => item[activeColumnName] = "Active"); - } - if (data.length == 0) { - if (request?.body?.ResourceDetails?.type == "facility") { - throwError("COMMON", 400, "VALIDATION_ERROR", "All facilities are set to Inactive for this campaign. Please set at least one facility to Active for this campaign or add a new facility for this campaign"); - } - else { - throwError("COMMON", 400, "VALIDATION_ERROR", "Data is empty for this campaign, add atleast one data row"); - } - } - data.forEach((element) => { - const boundaries = element[boundaryColumn]; - if (!boundaries) { - throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary Code is required for element in rowNumber ${element['!row#number!']}`); - } +// async function validateBoundaryData(data: any[], request: any, boundaryColumn: any, localizationMap: any) { +// const boundarySet = new Set(); // Create a Set to store unique boundaries +// logger.info("validating for the boundary data") +// const activeColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.activeColumnName, localizationMap) : null; +// const uniqueIdentifierColumnName = createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName ? getLocalizedName(createAndSearch?.[request?.body?.ResourceDetails?.type]?.uniqueIdentifierColumnName, localizationMap) : null; +// if (activeColumnName && uniqueIdentifierColumnName) { +// data = data.filter((item: any) => item[activeColumnName] === "Active" || !item[uniqueIdentifierColumnName]); +// data.forEach((item: any) => item[activeColumnName] = "Active"); +// } +// if (data.length == 0) { +// if (request?.body?.ResourceDetails?.type == "facility") { +// throwError("COMMON", 400, "VALIDATION_ERROR", "All facilities are set to Inactive for this campaign. Please set at least one facility to Active for this campaign or add a new facility for this campaign"); +// } +// else { +// throwError("COMMON", 400, "VALIDATION_ERROR", "Data is empty for this campaign, add atleast one data row"); +// } +// } +// data.forEach((element) => { +// const boundaries = element[boundaryColumn]; +// if (!boundaries) { +// throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary Code is required for element in rowNumber ${element['!row#number!']}`); +// } - const boundaryList = boundaries.split(",").map((boundary: any) => boundary.trim()); - if (boundaryList.length === 0) { - throwError("COMMON", 400, "VALIDATION_ERROR", `At least 1 boundary is required for element in rowNumber ${element['!row#number!']}`); - } +// const boundaryList = boundaries.split(",").map((boundary: any) => boundary.trim()); +// if (boundaryList.length === 0) { +// throwError("COMMON", 400, "VALIDATION_ERROR", `At least 1 boundary is required for element in rowNumber ${element['!row#number!']}`); +// } - for (const boundary of boundaryList) { - if (!boundary) { - throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary format is invalid in rowNumber ${element['!row#number!']}. Put it with one comma between boundary codes`); - } - boundarySet.add(boundary); // Add boundary to the set - } - }); - const uniqueBoundaries = Array.from(boundarySet); - await validateUniqueBoundaries(uniqueBoundaries, request); -} +// for (const boundary of boundaryList) { +// if (!boundary) { +// throwError("COMMON", 400, "VALIDATION_ERROR", `Boundary format is invalid in rowNumber ${element['!row#number!']}. Put it with one comma between boundary codes`); +// } +// boundarySet.add(boundary); // Add boundary to the set +// } +// }); +// const uniqueBoundaries = Array.from(boundarySet); +// await validateUniqueBoundaries(uniqueBoundaries, request); +// } // async function validateTargetBoundaryData(data: any[], request: any, boundaryColumn: any, errors: any[], localizationMap?: any) { // // const responseBoundaries = await fetchBoundariesInChunks(request); @@ -217,10 +217,21 @@ async function validateBoundaryData(data: any[], request: any, boundaryColumn: a async function validateTargets(request: any, data: any[], errors: any[], localizationMap?: any) { - const mdmsResponse = await getMdmsDataBasedOnCampaignType(request); - const columnsNotToBeFreezed = mdmsResponse?.columnsNotToBeFreezed; - const requiredColumns = mdmsResponse?.required; - const columnsToValidate = columnsNotToBeFreezed.filter((element: any) => requiredColumns.includes(element)); + let columnsToValidate: any; + const responseFromCampaignSearch = await getCampaignSearchResponse(request); + const campaignObject = responseFromCampaignSearch?.CampaignDetails?.[0]; + if (isDynamicTargetTemplateForProjectType(campaignObject?.projectType) && campaignObject.deliveryRules && campaignObject.deliveryRules.length > 0) { + + const modifiedUniqueDeliveryConditions = modifyDeliveryConditions(campaignObject.deliveryRules); + columnsToValidate = generateTargetColumnsBasedOnDeliveryConditions(modifiedUniqueDeliveryConditions, localizationMap); + + } + else { + const mdmsResponse = await getMdmsDataBasedOnCampaignType(request); + const columnsNotToBeFreezed = mdmsResponse?.columnsNotToBeFreezed; + const requiredColumns = mdmsResponse?.required; + columnsToValidate = columnsNotToBeFreezed.filter((element: any) => requiredColumns.includes(element)); + } const localizedTargetColumnNames = getLocalizedHeaders(columnsToValidate, localizationMap); for (const key in data) { if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap)) { @@ -411,16 +422,12 @@ async function validateViaSchema(data: any, schema: any, request: any, localizat async function validateSheetData(data: any, request: any, schema: any, boundaryValidation: any, localizationMap?: { [key: string]: string }) { await validateViaSchema(data, schema, request, localizationMap); - if (boundaryValidation) { - const localisedBoundaryCode = getLocalizedName(boundaryValidation?.column, localizationMap) - await validateBoundaryData(data, request, localisedBoundaryCode, localizationMap); - } } -async function validateTargetSheetData(data: any, request: any, boundaryValidation: any, localizationMap?: any) { +async function validateTargetSheetData(data: any, request: any, boundaryValidation: any, differentTabsBasedOnLevel: any, localizationMap?: any) { try { const errors: any[] = []; - await validateHeadersOfTargetSheet(request, localizationMap); + await validateHeadersOfTargetSheet(request, differentTabsBasedOnLevel, localizationMap); if (boundaryValidation) { // const localizedBoundaryValidationColumn = getLocalizedName(boundaryValidation?.column, localizationMap) // await validateTargetBoundaryData(data, request, localizedBoundaryValidationColumn, errors, localizationMap); @@ -440,11 +447,11 @@ async function validateTargetSheetData(data: any, request: any, boundaryValidati } -async function validateHeadersOfTargetSheet(request: any, localizationMap?: any) { +async function validateHeadersOfTargetSheet(request: any, differentTabsBasedOnLevel: any, localizationMap?: any) { const fileUrl = await validateFile(request); const targetWorkbook: any = await getTargetWorkbook(fileUrl); const hierarchy = await getHierarchy(request, request?.body?.ResourceDetails?.tenantId, request?.body?.ResourceDetails?.hierarchyType); - const finalValidHeadersForTargetSheetAsPerCampaignType = await getFinalValidHeadersForTargetSheetAsPerCampaignType(request, hierarchy, localizationMap); + const finalValidHeadersForTargetSheetAsPerCampaignType = await getFinalValidHeadersForTargetSheetAsPerCampaignType(request, hierarchy, differentTabsBasedOnLevel, localizationMap); logger.info("finalValidHeadersForTargetSheetAsPerCampaignType :" + JSON.stringify(finalValidHeadersForTargetSheetAsPerCampaignType)); logger.info("validating headers of target sheet started") validateHeadersOfTabsWithTargetInTargetSheet(targetWorkbook, finalValidHeadersForTargetSheetAsPerCampaignType); @@ -712,7 +719,7 @@ async function validateBoundariesForTabs(CampaignDetails: any, resource: any, re const resourceBoundaryCodesArray: any[] = []; var activeColumnName: any = null; if (createAndSearch?.[resource.type]?.activeColumn && createAndSearch?.[resource.type]?.activeColumnName) { - activeColumnName = getLocalizedName(createAndSearch?.[resource.type]?.activeColumn, localizationMap); + activeColumnName = getLocalizedName(createAndSearch?.[resource.type]?.activeColumnName, localizationMap); } datas.forEach((data: any) => { const codes = data?.[boundaryColumn]?.split(',').map((code: string) => code.trim()) || []; @@ -730,7 +737,7 @@ async function validateBoundariesForTabs(CampaignDetails: any, resource: any, re var missingBoundaries = rowData.boundaryCodes.filter((code: any) => !boundaryCodesArray.includes(code)); if (missingBoundaries.length > 0) { const errorString = `The following boundary codes are not present in selected boundaries : ${missingBoundaries.join(', ')}` - errors.push({ status: "BOUNDARYMISSING", rowNumber: rowData.rowNumber, errorDetails: errorString }) + errors.push({ status: "BOUNDARYERROR", rowNumber: rowData.rowNumber, errorDetails: errorString }) } } if (errors?.length > 0) { @@ -1159,9 +1166,9 @@ async function validateDownloadRequest(request: any) { await validateHierarchyType(request, hierarchyType, tenantId); } -async function immediateValidationForTargetSheet(dataFromSheet: any, localizationMap: any) { +async function immediateValidationForTargetSheet(request: any, dataFromSheet: any, differentTabsBasedOnLevel: any, localizationMap: any) { logger.info("validating all district tabs present started") - validateAllDistrictTabsPresentOrNot(dataFromSheet, localizationMap); + validateAllDistrictTabsPresentOrNot(request, dataFromSheet, differentTabsBasedOnLevel, localizationMap); logger.info("validation of all district tabs present completed") for (const key in dataFromSheet) { if (key !== getLocalizedName(getBoundaryTabName(), localizationMap) && key !== getLocalizedName(config?.values?.readMeTab, localizationMap)) { @@ -1170,7 +1177,7 @@ async function immediateValidationForTargetSheet(dataFromSheet: any, localizatio if (dataArray.length === 0) { throwError("COMMON", 400, "VALIDATION_ERROR", `The Target Sheet ${key} you have uploaded is empty`) } - const root = getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap); + const root = getLocalizedName(differentTabsBasedOnLevel, localizationMap); for (const boundaryRow of dataArray) { for (const columns in boundaryRow) { if (columns.startsWith('__EMPTY')) { @@ -1187,16 +1194,15 @@ async function immediateValidationForTargetSheet(dataFromSheet: any, localizatio } -function validateAllDistrictTabsPresentOrNot(dataFromSheet: any, localizationMap?: any) { +function validateAllDistrictTabsPresentOrNot(request: any, dataFromSheet: any, differentTabsBasedOnLevel: any, localizationMap?: any) { let tabsIndex = 2; logger.info("target sheet getting validated for different districts"); - const differentTabsBasedOnLevel = getLocalizedName(config?.boundary?.generateDifferentTabsOnBasisOf, localizationMap); const tabsOfDistrict = getDifferentDistrictTabs(dataFromSheet[getLocalizedName(config?.boundary?.boundaryTab, localizationMap)], differentTabsBasedOnLevel); logger.info("found " + tabsOfDistrict?.length + " districts"); logger.debug("actual districts in boundary data sheet : " + getFormattedStringForDebug(tabsOfDistrict)); const tabsFromTargetSheet = Object.keys(dataFromSheet); logger.info("districts present in user filled sheet : " + (tabsFromTargetSheet?.length - tabsIndex)); - logger.debug("districts present in user filled sheet : " + getFormattedStringForDebug(tabsFromTargetSheet)); + logger.debug("districts present in user filled sheet (exclude first two tabs): " + getFormattedStringForDebug(tabsFromTargetSheet)); if (tabsFromTargetSheet.length - tabsIndex !== tabsOfDistrict.length) { throwError("COMMON", 400, "VALIDATION_ERROR", `${differentTabsBasedOnLevel} tabs uplaoded by user is either less or more than the ${differentTabsBasedOnLevel} in the boundary system `) @@ -1207,11 +1213,16 @@ function validateAllDistrictTabsPresentOrNot(dataFromSheet: any, localizationMap throwError("COMMON", 400, "VALIDATION_ERROR", `${differentTabsBasedOnLevel} tab ${tab} not present in the Target Sheet Uploaded`); } } - } } +function validateSearchProcessTracksRequest(request: any) { + if (!request?.query?.campaignId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignId is required in params"); + } +} + export { fetchBoundariesInChunks, @@ -1227,5 +1238,6 @@ export { validateDownloadRequest, validateTargetSheetData, immediateValidationForTargetSheet, - validateBoundaryOfResouces + validateBoundaryOfResouces, + validateSearchProcessTracksRequest } diff --git a/health-services/project-factory/src/server/validators/genericValidator.ts b/health-services/project-factory/src/server/validators/genericValidator.ts index 426f1de67e7..245579d6134 100644 --- a/health-services/project-factory/src/server/validators/genericValidator.ts +++ b/health-services/project-factory/src/server/validators/genericValidator.ts @@ -7,6 +7,9 @@ import { httpRequest } from "../utils/request"; import { getBoundaryRelationshipData, throwError } from "../utils/genericUtils"; import { validateFilters } from "./campaignValidators"; import { generateRequestSchema } from "../config/models/generateRequestSchema"; +import { persistTrack } from "../utils/processTrackUtils"; +import { processTrackTypes, processTrackStatuses, campaignStatuses } from "../config/constants"; +import { validateMappingId } from "../utils/campaignMappingUtils"; // Function to validate data against a JSON schema function validateDataWithSchema(data: any, schema: any): { isValid: boolean; error: any | null | undefined } { @@ -30,6 +33,11 @@ function validateCampaignBodyViaSchema(schema: any, objectData: any) { const dataPath = error.dataPath.replace(/\//g, '.').replace(/^\./, ''); formattedErrorMessage = `${dataPath} ${error.message}`; } + else if (error?.instancePath) { + // Replace slash with dot and remove leading dot if present + const dataPath = error.instancePath.replace(/\//g, '.').replace(/^\./, ''); + formattedErrorMessage = `${dataPath} ${error.message}`; + } else { formattedErrorMessage = `${error.message}` } @@ -61,6 +69,11 @@ function validateBodyViaSchema(schema: any, objectData: any) { const dataPath = error.dataPath.replace(/\//g, '.').replace(/^\./, ''); formattedErrorMessage = `${dataPath} ${error.message}`; } + else if (error?.instancePath) { + // Replace slash with dot and remove leading dot if present + const dataPath = error.instancePath.replace(/\//g, '.').replace(/^\./, ''); + formattedErrorMessage = `${dataPath} ${error.message}`; + } else { formattedErrorMessage = `${error.message}` } @@ -115,15 +128,40 @@ async function validateCampaign(requestBody: any) { // Function to validate the entire campaign request async function validateCampaignRequest(requestBody: any) { - if (requestBody?.Campaign) { - if (!requestBody?.Campaign?.tenantId) { - throwError("COMMON", 400, "VALIDATION_ERROR", "Enter TenantId"); + await persistTrack(requestBody?.Campaign?.id, processTrackTypes.validateMappingResource, processTrackStatuses.inprogress); + try { + if (requestBody?.Campaign) { + if (!requestBody?.Campaign?.tenantId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Enter TenantId"); + } + await validateCampaign(requestBody); + const id = requestBody?.Campaign?.id; + const campaignDetails = await validateMappingId(requestBody, id); + if (campaignDetails?.status == campaignStatuses.inprogress) { + logger.error("Campaign Already In Progress and Mapped"); + throwError("CAMPAIGN", 400, "CAMPAIGN_ALREADY_MAPPED"); + } } - await validateCampaign(requestBody); - } - else { - throwError("COMMON", 400, "VALIDATION_ERROR", "Campaign is required"); + else { + throwError("COMMON", 400, "VALIDATION_ERROR", "Campaign object is missing"); + } + if (requestBody?.CampaignDetails) { + if (!requestBody?.CampaignDetails?.tenantId) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Enter TenantId"); + } + if (!requestBody?.CampaignDetails?.id) { + throwError("COMMON", 400, "VALIDATION_ERROR", "Enter id in CampaignDetails"); + } + } + else { + throwError("COMMON", 400, "VALIDATION_ERROR", "CampaignDetails is missing"); + } + } catch (error: any) { + console.log(error) + await persistTrack(requestBody?.Campaign?.id, processTrackTypes.validateMappingResource, processTrackStatuses.failed, { error: String((error?.message + (error?.description ? ` : ${error?.description}` : '')) || error) }); + throw new Error(error) } + await persistTrack(requestBody?.Campaign?.id, processTrackTypes.validateMappingResource, processTrackStatuses.completed); } // Function to validate and update project response and its ID @@ -220,4 +258,4 @@ export { validateGenerateRequest, validateHierarchyType, validateCampaignBodyViaSchema -}; \ No newline at end of file +}; diff --git a/health-services/project-factory/yarn.lock b/health-services/project-factory/yarn.lock index 0584dc93095..4e9c73bf0f7 100644 --- a/health-services/project-factory/yarn.lock +++ b/health-services/project-factory/yarn.lock @@ -2,11 +2,6 @@ # yarn lockfile v1 -"@aashutoshrathi/word-wrap@^1.2.3": - version "1.2.6" - resolved "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz" - integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== - "@ampproject/remapping@^2.2.0": version "2.3.0" resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz" @@ -15,14 +10,7 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@babel/code-frame@^7.0.0": - version "7.12.11" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz" - integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== - dependencies: - "@babel/highlight" "^7.10.4" - -"@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.2": version "7.24.2" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz" integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== @@ -30,179 +18,148 @@ "@babel/highlight" "^7.24.2" picocolors "^1.0.0" -"@babel/code-frame@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.7.tgz#882fd9e09e8ee324e496bd040401c6f046ef4465" - integrity sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA== - dependencies: - "@babel/highlight" "^7.24.7" - picocolors "^1.0.0" +"@babel/compat-data@^7.23.5": + version "7.24.4" + resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz" + integrity sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ== -"@babel/compat-data@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.7.tgz#d23bbea508c3883ba8251fb4164982c36ea577ed" - integrity sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw== - -"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.7.tgz#b676450141e0b52a3d43bc91da86aa608f950ac4" - integrity sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g== +"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9", "@babel/core@^7.8.0": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz" + integrity sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.24.7" - "@babel/helper-compilation-targets" "^7.24.7" - "@babel/helper-module-transforms" "^7.24.7" - "@babel/helpers" "^7.24.7" - "@babel/parser" "^7.24.7" - "@babel/template" "^7.24.7" - "@babel/traverse" "^7.24.7" - "@babel/types" "^7.24.7" + "@babel/code-frame" "^7.24.2" + "@babel/generator" "^7.24.5" + "@babel/helper-compilation-targets" "^7.23.6" + "@babel/helper-module-transforms" "^7.24.5" + "@babel/helpers" "^7.24.5" + "@babel/parser" "^7.24.5" + "@babel/template" "^7.24.0" + "@babel/traverse" "^7.24.5" + "@babel/types" "^7.24.5" convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.24.7", "@babel/generator@^7.7.2": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.7.tgz#1654d01de20ad66b4b4d99c135471bc654c55e6d" - integrity sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA== +"@babel/generator@^7.24.5", "@babel/generator@^7.7.2": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz" + integrity sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA== dependencies: - "@babel/types" "^7.24.7" + "@babel/types" "^7.24.5" "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" jsesc "^2.5.1" -"@babel/helper-compilation-targets@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz#4eb6c4a80d6ffeac25ab8cd9a21b5dfa48d503a9" - integrity sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg== +"@babel/helper-compilation-targets@^7.23.6": + version "7.23.6" + resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz" + integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== dependencies: - "@babel/compat-data" "^7.24.7" - "@babel/helper-validator-option" "^7.24.7" + "@babel/compat-data" "^7.23.5" + "@babel/helper-validator-option" "^7.23.5" browserslist "^4.22.2" lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-environment-visitor@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz#4b31ba9551d1f90781ba83491dd59cf9b269f7d9" - integrity sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ== - dependencies: - "@babel/types" "^7.24.7" +"@babel/helper-environment-visitor@^7.22.20": + version "7.22.20" + resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== -"@babel/helper-function-name@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz#75f1e1725742f39ac6584ee0b16d94513da38dd2" - integrity sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA== +"@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== dependencies: - "@babel/template" "^7.24.7" - "@babel/types" "^7.24.7" + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" -"@babel/helper-hoist-variables@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz#b4ede1cde2fd89436397f30dc9376ee06b0f25ee" - integrity sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ== +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== dependencies: - "@babel/types" "^7.24.7" + "@babel/types" "^7.22.5" -"@babel/helper-module-imports@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz#f2f980392de5b84c3328fc71d38bd81bbb83042b" - integrity sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA== +"@babel/helper-module-imports@^7.24.3": + version "7.24.3" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz" + integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg== dependencies: - "@babel/traverse" "^7.24.7" - "@babel/types" "^7.24.7" + "@babel/types" "^7.24.0" -"@babel/helper-module-transforms@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz#31b6c9a2930679498db65b685b1698bfd6c7daf8" - integrity sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ== +"@babel/helper-module-transforms@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz" + integrity sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A== dependencies: - "@babel/helper-environment-visitor" "^7.24.7" - "@babel/helper-module-imports" "^7.24.7" - "@babel/helper-simple-access" "^7.24.7" - "@babel/helper-split-export-declaration" "^7.24.7" - "@babel/helper-validator-identifier" "^7.24.7" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-module-imports" "^7.24.3" + "@babel/helper-simple-access" "^7.24.5" + "@babel/helper-split-export-declaration" "^7.24.5" + "@babel/helper-validator-identifier" "^7.24.5" "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.24.0", "@babel/helper-plugin-utils@^7.8.0": - version "7.24.0" - resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz" - integrity sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w== + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.5.tgz" + integrity sha512-xjNLDopRzW2o6ba0gKbkZq5YWEBaK3PCyTOY1K2P/O07LGMhMqlMXPxwN4S5/RhWuCobT8z0jrlKGlYmeR1OhQ== -"@babel/helper-simple-access@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz#bcade8da3aec8ed16b9c4953b74e506b51b5edb3" - integrity sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg== +"@babel/helper-simple-access@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz" + integrity sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ== dependencies: - "@babel/traverse" "^7.24.7" - "@babel/types" "^7.24.7" + "@babel/types" "^7.24.5" -"@babel/helper-split-export-declaration@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz#83949436890e07fa3d6873c61a96e3bbf692d856" - integrity sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA== +"@babel/helper-split-export-declaration@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz" + integrity sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q== dependencies: - "@babel/types" "^7.24.7" + "@babel/types" "^7.24.5" -"@babel/helper-string-parser@^7.23.4": +"@babel/helper-string-parser@^7.24.1": version "7.24.1" resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz" integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== -"@babel/helper-string-parser@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz#4d2d0f14820ede3b9807ea5fc36dfc8cd7da07f2" - integrity sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg== - -"@babel/helper-validator-identifier@^7.22.20": - version "7.22.20" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz" - integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== - -"@babel/helper-validator-identifier@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz#75b889cfaf9e35c2aaf42cf0d72c8e91719251db" - integrity sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w== +"@babel/helper-validator-identifier@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz" + integrity sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA== -"@babel/helper-validator-option@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz#24c3bb77c7a425d1742eec8fb433b5a1b38e62f6" - integrity sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw== +"@babel/helper-validator-option@^7.23.5": + version "7.23.5" + resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz" + integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== -"@babel/helpers@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.7.tgz#aa2ccda29f62185acb5d42fb4a3a1b1082107416" - integrity sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg== +"@babel/helpers@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz" + integrity sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q== dependencies: - "@babel/template" "^7.24.7" - "@babel/types" "^7.24.7" - -"@babel/highlight@^7.10.4", "@babel/highlight@^7.24.2": - version "7.24.2" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz" - integrity sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" - chalk "^2.4.2" - js-tokens "^4.0.0" - picocolors "^1.0.0" + "@babel/template" "^7.24.0" + "@babel/traverse" "^7.24.5" + "@babel/types" "^7.24.5" -"@babel/highlight@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.7.tgz#a05ab1df134b286558aae0ed41e6c5f731bf409d" - integrity sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw== +"@babel/highlight@^7.24.2": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz" + integrity sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw== dependencies: - "@babel/helper-validator-identifier" "^7.24.7" + "@babel/helper-validator-identifier" "^7.24.5" chalk "^2.4.2" js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0", "@babel/parser@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.7.tgz#9a5226f92f0c5c8ead550b750f5608e766c8ce85" - integrity sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.0", "@babel/parser@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz" + integrity sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -302,16 +259,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.24.0" -"@babel/template@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.7.tgz#02efcee317d0609d2c07117cb70ef8fb17ab7315" - integrity sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig== - dependencies: - "@babel/code-frame" "^7.24.7" - "@babel/parser" "^7.24.7" - "@babel/types" "^7.24.7" - -"@babel/template@^7.3.3": +"@babel/template@^7.22.15", "@babel/template@^7.24.0", "@babel/template@^7.3.3": version "7.24.0" resolved "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz" integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA== @@ -320,38 +268,29 @@ "@babel/parser" "^7.24.0" "@babel/types" "^7.24.0" -"@babel/traverse@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.7.tgz#de2b900163fa741721ba382163fe46a936c40cf5" - integrity sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA== - dependencies: - "@babel/code-frame" "^7.24.7" - "@babel/generator" "^7.24.7" - "@babel/helper-environment-visitor" "^7.24.7" - "@babel/helper-function-name" "^7.24.7" - "@babel/helper-hoist-variables" "^7.24.7" - "@babel/helper-split-export-declaration" "^7.24.7" - "@babel/parser" "^7.24.7" - "@babel/types" "^7.24.7" +"@babel/traverse@^7.24.5": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz" + integrity sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA== + dependencies: + "@babel/code-frame" "^7.24.2" + "@babel/generator" "^7.24.5" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.24.5" + "@babel/parser" "^7.24.5" + "@babel/types" "^7.24.5" debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.24.0", "@babel/types@^7.3.3": - version "7.24.0" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz" - integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w== +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0", "@babel/types@^7.24.5", "@babel/types@^7.3.3": + version "7.24.5" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz" + integrity sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ== dependencies: - "@babel/helper-string-parser" "^7.23.4" - "@babel/helper-validator-identifier" "^7.22.20" - to-fast-properties "^2.0.0" - -"@babel/types@^7.24.7": - version "7.24.7" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.7.tgz#6027fe12bc1aa724cd32ab113fb7f1988f1f66f2" - integrity sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q== - dependencies: - "@babel/helper-string-parser" "^7.24.7" - "@babel/helper-validator-identifier" "^7.24.7" + "@babel/helper-string-parser" "^7.24.1" + "@babel/helper-validator-identifier" "^7.24.5" to-fast-properties "^2.0.0" "@bcoe/v8-coverage@^0.2.3": @@ -359,7 +298,7 @@ resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@colors/colors@1.6.0", "@colors/colors@^1.6.0": +"@colors/colors@^1.6.0", "@colors/colors@1.6.0": version "1.6.0" resolved "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz" integrity sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA== @@ -423,7 +362,7 @@ "@ioredis/commands@^1.1.1": version "1.2.0" - resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11" + resolved "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz" integrity sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg== "@isaacs/cliui@^8.0.2": @@ -670,14 +609,6 @@ resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== -"@jridgewell/trace-mapping@0.3.9": - version "0.3.9" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" - integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz" @@ -686,6 +617,14 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@npmcli/agent@^2.0.0": version "2.2.2" resolved "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.2.tgz" @@ -698,9 +637,9 @@ socks-proxy-agent "^8.0.3" "@npmcli/fs@^3.1.0": - version "3.1.0" - resolved "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz" - integrity sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w== + version "3.1.1" + resolved "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.1.tgz" + integrity sha512-q9CRWjpHCMIh5sVyefoD1cA7PkvILqCZsnSOEUUivORLjxCO/Irmue2DprETiNgEqktDBZaM1Bi+jrarx1XdCg== dependencies: semver "^7.3.5" @@ -804,9 +743,9 @@ "@types/node" "*" "@types/express-serve-static-core@^4.17.33": - version "4.17.43" - resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.43.tgz" - integrity sha512-oaYtiBirUOPQGSWNGPWnzyAFJ0BP3cwvN4oWZQY+zUBwpVIGsKUkpBpSztp74drYcjavs7SKFZ4DX1V2QeN8rg== + version "4.19.0" + resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.0.tgz" + integrity sha512-bGyep3JqPCRry1wq+O5n7oiBgGWmeIJXPjXXCo8EK0u8duZGSYar7cGqd3ML2JUsLGeB7fmc06KYo9fLGWqPvQ== dependencies: "@types/node" "*" "@types/qs" "*" @@ -897,6 +836,11 @@ expect "^29.0.0" pretty-format "^29.0.0" +"@types/lodash@^4.17.5": + version "4.17.5" + resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.5.tgz" + integrity sha512-MBIOHVZqVqgfro1euRDWX7OO0fBVUUMrN6Pwm8LQsz8cWhEpihlvR70ENj3f40j58TNxZaWv2ndSkInykNBBJw== + "@types/mime@^1": version "1.3.5" resolved "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz" @@ -931,9 +875,9 @@ pg-types "^4.0.1" "@types/qs@*": - version "6.9.14" - resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.14.tgz" - integrity sha512-5khscbd3SwWMhFqylJBLQ0zIu7c1K6Vz0uBIt915BI3zV0q1nfjRQD3RqSBcPaO6PHEF4ov/t9y89fSiyThlPA== + version "6.9.15" + resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz" + integrity sha512-uXHQKES6DQKKCLh441Xv/dwxOq1TVS3JPUMlEqoEglvlhR6Mxnlew/Xq/LRVHpLyk7iK3zODe1qYHIMltO7XGg== "@types/range-parser@*": version "1.2.7" @@ -1024,7 +968,7 @@ acorn-walk@^8.1.1: resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz" integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== -acorn@^7.4.0: +"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^7.4.0: version "7.4.1" resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== @@ -1059,7 +1003,17 @@ ajv-errors@^3.0.0: resolved "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz" integrity sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ== -ajv@^6.10.0, ajv@^6.12.4: +ajv@^6.10.0: + version "6.12.6" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^6.12.4: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1118,7 +1072,14 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.0.0, ansi-styles@^4.1.0: +ansi-styles@^4.0.0: + version "4.3.0" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== @@ -1230,7 +1191,12 @@ async@^2.6.2: dependencies: lodash "^4.17.14" -async@^3.2.3, async@^3.2.4: +async@^3.2.3: + version "3.2.5" + resolved "https://registry.npmjs.org/async/-/async-3.2.5.tgz" + integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== + +async@^3.2.4: version "3.2.5" resolved "https://registry.npmjs.org/async/-/async-3.2.5.tgz" integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== @@ -1386,7 +1352,7 @@ bluebird@~3.4.1: resolved "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz" integrity sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA== -body-parser@1.20.2, body-parser@^1.20.2: +body-parser@^1.20.2, body-parser@1.20.2: version "1.20.2" resolved "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz" integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== @@ -1426,7 +1392,7 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" -browserslist@^4.22.2: +browserslist@^4.22.2, "browserslist@>= 4.21.0": version "4.23.0" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz" integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== @@ -1517,9 +1483,9 @@ bytes@3.1.2: integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== cacache@^18.0.0: - version "18.0.2" - resolved "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz" - integrity sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw== + version "18.0.3" + resolved "https://registry.npmjs.org/cacache/-/cacache-18.0.3.tgz" + integrity sha512-qXCd4rh6I07cnDqh8V48/94Tc/WSfj+o3Gn6NZ0aZovS255bUx8O13uKxRFd2eWG0xgsco7+YItQNPaa5E85hg== dependencies: "@npmcli/fs" "^3.1.0" fs-minipass "^3.0.0" @@ -1561,9 +1527,9 @@ camelcase@^6.2.0: integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== caniuse-lite@^1.0.30001587: - version "1.0.30001605" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001605.tgz" - integrity sha512-nXwGlFWo34uliI9z3n6Qc0wZaf7zaZWA1CPZ169La5mV3I/gem7bst0vr5XQH5TJXZIMfDeZyOrZnSlVzKxxHQ== + version "1.0.30001620" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001620.tgz" + integrity sha512-WJvYsOjd1/BYUY6SNGUosK9DUidBPDTnOARHp3fSmFO1ekdxaY6nKRttEVrfMmYi80ctS0kz1wiWmm14fVc3ew== cfb@^1.1.3, cfb@~1.2.1: version "1.2.2" @@ -1633,9 +1599,9 @@ ci-info@^3.2.0: integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== cjs-module-lexer@^1.0.0: - version "1.2.3" - resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz" - integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== + version "1.3.1" + resolved "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.3.1.tgz" + integrity sha512-a3KdPAANPbNE4ZUv9h6LckSl9zLsYOP4MBmhIPkRaeyybt+r4UghLvq+xw/YwUcC1gqylCkL4rdVs3Lwupjm4Q== clean-stack@^2.0.0: version "2.2.0" @@ -1658,7 +1624,7 @@ clone@2.x: cluster-key-slot@^1.1.0: version "1.1.2" - resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac" + resolved "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz" integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA== co@^4.6.0: @@ -1681,7 +1647,14 @@ collect-v8-coverage@^1.0.0: resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz" integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== -color-convert@^1.9.0, color-convert@^1.9.3: +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^1.9.3: version "1.9.3" resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== @@ -1695,16 +1668,16 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - color-name@^1.0.0, color-name@~1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + color-string@^1.6.0: version "1.9.1" resolved "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz" @@ -1853,14 +1826,21 @@ dayjs@^1.8.34: resolved "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz" integrity sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg== -debug@2.6.9, debug@^2.1.3: +debug@^2.1.3, debug@2.6.9: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.3.1, debug@^4.3.4: +debug@^4.0.1: + version "4.3.5" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" + integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== + dependencies: + ms "2.1.2" + +debug@^4.1.0: version "4.3.4" resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -1874,6 +1854,27 @@ debug@^4.1.1: dependencies: ms "2.1.2" +debug@^4.3.1: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@^4.3.4: + version "4.3.5" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" + integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== + dependencies: + ms "2.1.2" + +debug@4: + version "4.3.5" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz" + integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== + dependencies: + ms "2.1.2" + decompress-response@^3.3.0: version "3.3.0" resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz" @@ -1882,9 +1883,9 @@ decompress-response@^3.3.0: mimic-response "^1.0.0" dedent@^1.0.0: - version "1.5.1" - resolved "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz" - integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== + version "1.5.3" + resolved "https://registry.npmjs.org/dedent/-/dedent-1.5.3.tgz" + integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== deep-extend@^0.6.0: version "0.6.0" @@ -1927,10 +1928,10 @@ denque@^1.3.0: denque@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/denque/-/denque-2.1.0.tgz#e93e1a6569fb5e66f16a3c2a2964617d349d6ab1" + resolved "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz" integrity sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw== -depd@2.0.0, depd@~2.0.0: +depd@~2.0.0, depd@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== @@ -1992,9 +1993,9 @@ ee-first@1.1.1: integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== electron-to-chromium@^1.4.668: - version "1.4.806" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.806.tgz#2cb046631cbabceb26fc72be68d273fa183e36bc" - integrity sha512-nkoEX2QIB8kwCOtvtgwhXWy2IHVcOLQZu9Qo36uaGB835mdX/h8uLRlosL6QIhLVUnAiicXRW00PwaPZC74Nrg== + version "1.4.772" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.772.tgz" + integrity sha512-jFfEbxR/abTTJA3ci+2ok1NTuOBBtB4jH+UT6PUmRN+DY3WSD4FFRsgoVQ+QNIJ0T7wrXwzsWCI2WKC46b++2A== emittery@^0.13.1: version "0.13.1" @@ -2060,7 +2061,7 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -error@7.0.2, error@^7.0.0: +error@^7.0.0, error@7.0.2: version "7.0.2" resolved "https://registry.npmjs.org/error/-/error-7.0.2.tgz" integrity sha512-UtVv4l5MhijsYUxPJo4390gzfZvAnTHreNnDjnTZaKIiZ/SemXxAhBkYSKtWa5RtBXbLP8tMgn/n0RUa/H7jXw== @@ -2080,7 +2081,7 @@ es-errors@^1.3.0: resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== -escalade@^3.1.1: +escalade@^3.1.1, escalade@^3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz" integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== @@ -2127,7 +2128,12 @@ eslint-utils@^2.1.0: dependencies: eslint-visitor-keys "^1.1.0" -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: +eslint-visitor-keys@^1.1.0: + version "1.3.0" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" + integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== + +eslint-visitor-keys@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== @@ -2189,16 +2195,21 @@ espree@^7.3.0, espree@^7.3.1: acorn-jsx "^5.3.1" eslint-visitor-keys "^1.3.0" -esprima@1.2.2: - version "1.2.2" - resolved "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz" - integrity sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A== +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esprima@^4.0.0, esprima@^4.0.1: +esprima@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== +esprima@1.2.2: + version "1.2.2" + resolved "https://registry.npmjs.org/esprima/-/esprima-1.2.2.tgz" + integrity sha512-+JpPZam9w5DuJ3Q67SqsMGtiHKENSMRVoxvArfJZK01/BfLEObtZ6orJa/MtoGNR/rfMgp5837T41PAmTwAv/A== + esquery@^1.2.0: version "1.5.0" resolved "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz" @@ -2218,7 +2229,12 @@ estraverse@^4.1.1, estraverse@^4.2.0: resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== -estraverse@^5.1.0, estraverse@^5.2.0: +estraverse@^5.1.0: + version "5.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +estraverse@^5.2.0: version "5.3.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== @@ -2431,9 +2447,9 @@ follow-redirects@^1.0.0, follow-redirects@^1.15.6: integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== foreground-child@^3.1.0: - version "3.1.1" - resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz" - integrity sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg== + version "3.2.0" + resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.0.tgz" + integrity sha512-CrWQNaEl1/6WeZoarcM9LHupTo3RpZO2Pdk1vktwzPiQTsJnAKJmm3TACKeG5UZbWDfaH2AbvYxzP96y0MT7fA== dependencies: cross-spawn "^7.0.0" signal-exit "^4.0.1" @@ -2486,11 +2502,6 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.3.2, fsevents@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - fstream@^1.0.12: version "1.0.12" resolved "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz" @@ -2569,17 +2580,41 @@ glob-parent@^5.0.0, glob-parent@~5.1.2: is-glob "^4.0.1" glob@^10.2.2, glob@^10.3.10: - version "10.3.12" - resolved "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz" - integrity sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg== + version "10.4.1" + resolved "https://registry.npmjs.org/glob/-/glob-10.4.1.tgz" + integrity sha512-2jelhlq3E4ho74ZyVLN03oKdAZVUa6UDZzFLVH1H7dnoax+y9qyaq8zBkfDIggjniU19z0wU18y16jMB2eyVIw== dependencies: foreground-child "^3.1.0" - jackspeak "^2.3.6" - minimatch "^9.0.1" - minipass "^7.0.4" - path-scurry "^1.10.2" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + path-scurry "^1.11.1" -glob@^7.1.3, glob@^7.1.4, glob@^7.2.3: +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.1.4: + version "7.2.3" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.2.3: version "7.2.3" resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -2737,13 +2772,6 @@ human-signals@^2.1.0: resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -iconv-lite@0.4.24: - version "0.4.24" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - iconv-lite@^0.6.2: version "0.6.3" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz" @@ -2751,6 +2779,13 @@ iconv-lite@^0.6.2: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" +iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + ieee754@^1.1.13: version "1.2.1" resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" @@ -2800,7 +2835,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.3: +inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.3, inherits@2, inherits@2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -2812,7 +2847,7 @@ ini@~1.3.0: ioredis@^5.4.1: version "5.4.1" - resolved "https://registry.yarnpkg.com/ioredis/-/ioredis-5.4.1.tgz#1c56b70b759f01465913887375ed809134296f40" + resolved "https://registry.npmjs.org/ioredis/-/ioredis-5.4.1.tgz" integrity sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA== dependencies: "@ioredis/commands" "^1.1.1" @@ -2979,10 +3014,10 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jackspeak@^2.3.6: - version "2.3.6" - resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz" - integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ== +jackspeak@^3.1.2: + version "3.4.0" + resolved "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz" + integrity sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw== dependencies: "@isaacs/cliui" "^8.0.2" optionalDependencies: @@ -3203,7 +3238,7 @@ jest-resolve-dependencies@^29.7.0: jest-regex-util "^29.6.3" jest-snapshot "^29.7.0" -jest-resolve@^29.7.0: +jest-resolve@*, jest-resolve@^29.7.0: version "29.7.0" resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.7.0.tgz" integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== @@ -3546,7 +3581,7 @@ lodash.groupby@^4.6.0: lodash.isarguments@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" + resolved "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz" integrity sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg== lodash.isboolean@^3.0.3: @@ -3594,7 +3629,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz" integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ== -lodash@4.17.21, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4: +lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4, lodash@4.17.21: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -3611,20 +3646,20 @@ logform@^2.3.2, logform@^2.4.0: safe-stable-stringify "^2.3.1" triple-beam "^1.3.0" -long@1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/long/-/long-1.1.2.tgz" - integrity sha512-pjR3OP1X2VVQhCQlrq3s8UxugQsuoucwMOn9Yj/kN/61HMc+lDFJS5bvpNEHneZ9NVaSm8gNWxZvtGS7lqHb3Q== - long@^2.4.0: version "2.4.0" resolved "https://registry.npmjs.org/long/-/long-2.4.0.tgz" integrity sha512-ijUtjmO/n2A5PaosNG9ZGDsQ3vxJg7ZW8vsY8Kp0f2yIZWhSJvjmegV7t+9RPQKxKrvj8yKGehhS+po14hPLGQ== +long@1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/long/-/long-1.1.2.tgz" + integrity sha512-pjR3OP1X2VVQhCQlrq3s8UxugQsuoucwMOn9Yj/kN/61HMc+lDFJS5bvpNEHneZ9NVaSm8gNWxZvtGS7lqHb3Q== + lru-cache@^10.0.1, lru-cache@^10.2.0: - version "10.2.0" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz" - integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q== + version "10.2.2" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz" + integrity sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ== lru-cache@^5.1.1: version "5.1.1" @@ -3633,13 +3668,6 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - make-dir@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz" @@ -3653,9 +3681,9 @@ make-error@^1.1.1: integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== make-fetch-happen@^13.0.0: - version "13.0.0" - resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz" - integrity sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A== + version "13.0.1" + resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.1.tgz" + integrity sha512-cKTUFc/rbKUd/9meOvgrpJ2WrNzymt6jfRDdwg5UCnVzv9dTpEj9JS5m3wtziXVCjluIXyL8pcaukYqezIzZQA== dependencies: "@npmcli/agent" "^2.0.0" cacache "^18.0.0" @@ -3666,6 +3694,7 @@ make-fetch-happen@^13.0.0: minipass-flush "^1.0.5" minipass-pipeline "^1.2.4" negotiator "^0.6.3" + proc-log "^4.2.0" promise-retry "^2.0.1" ssri "^10.0.0" @@ -3704,7 +3733,7 @@ micromatch@^4.0.4, micromatch@^4.0.5: braces "^3.0.2" picomatch "^2.3.1" -mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": +"mime-db@>= 1.43.0 < 2", mime-db@1.52.0: version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== @@ -3745,7 +3774,7 @@ minimatch@^5.1.0: dependencies: brace-expansion "^2.0.1" -minimatch@^9.0.1: +minimatch@^9.0.4: version "9.0.4" resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz" integrity sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw== @@ -3765,9 +3794,9 @@ minipass-collect@^2.0.1: minipass "^7.0.3" minipass-fetch@^3.0.0: - version "3.0.4" - resolved "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz" - integrity sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg== + version "3.0.5" + resolved "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.5.tgz" + integrity sha512-2N8elDQAtSnFV0Dk7gt15KHsS0Fyz6CbYZ360h0WTYV1Ty46li3rAXVOQj1THMNLdmrD9Vt5pBPtWtVkpwGBqg== dependencies: minipass "^7.0.3" minipass-sized "^1.0.3" @@ -3803,16 +3832,16 @@ minipass@^3.0.0: dependencies: yallist "^4.0.0" +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3, minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + minipass@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== -"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.2, minipass@^7.0.3, minipass@^7.0.4: - version "7.0.4" - resolved "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz" - integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== - minizlib@^2.1.1, minizlib@^2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz" @@ -3821,14 +3850,19 @@ minizlib@^2.1.1, minizlib@^2.1.2: minipass "^3.0.0" yallist "^4.0.0" -"mkdirp@>=0.5 0", mkdirp@^0.5.1: +mkdirp@^0.5.1, "mkdirp@>=0.5 0": version "0.5.6" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== dependencies: minimist "^1.2.6" -mkdirp@^1.0.3, mkdirp@^1.0.4: +mkdirp@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +mkdirp@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== @@ -3844,6 +3878,11 @@ morgan@1.10.0: on-finished "~2.3.0" on-headers "~1.0.2" +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + ms@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" @@ -3854,7 +3893,7 @@ ms@2.1.2: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.1.1: +ms@2.1.3: version "2.1.3" resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -3874,7 +3913,7 @@ natural-compare@^1.4.0: resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -negotiator@0.6.3, negotiator@^0.6.3: +negotiator@^0.6.3, negotiator@0.6.3: version "0.6.3" resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== @@ -3930,9 +3969,9 @@ noop-logger@^0.1.1: integrity sha512-6kM8CLXvuW5crTxsAtva2YLrRrDaiTIkIePWs9moLHqbFWT94WpNFjwS/5dfLfECg5i/lkmw3aoqVidxt23TEQ== nopt@^7.0.0: - version "7.2.0" - resolved "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz" - integrity sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA== + version "7.2.1" + resolved "https://registry.npmjs.org/nopt/-/nopt-7.2.1.tgz" + integrity sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w== dependencies: abbrev "^2.0.0" @@ -3978,13 +4017,6 @@ obuf@~1.1.2: resolved "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz" integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== -on-finished@2.4.1: - version "2.4.1" - resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - on-finished@~2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz" @@ -3992,6 +4024,13 @@ on-finished@~2.3.0: dependencies: ee-first "1.1.1" +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + on-headers@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz" @@ -4041,16 +4080,16 @@ optionator@^0.8.1: word-wrap "~1.2.3" optionator@^0.9.1: - version "0.9.3" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz" - integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + version "0.9.4" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== dependencies: - "@aashutoshrathi/word-wrap" "^1.2.3" deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" + word-wrap "^1.2.5" os-homedir@^1.0.1: version "1.0.2" @@ -4137,10 +4176,10 @@ path-parse@^1.0.7: resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.10.2: - version "1.10.2" - resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz" - integrity sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== dependencies: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -4204,7 +4243,7 @@ pg-types@^4.0.1: postgres-interval "^3.0.0" postgres-range "^1.1.1" -pg@8.12.0: +pg@>=8.0, pg@8.12.0: version "8.12.0" resolved "https://registry.npmjs.org/pg/-/pg-8.12.0.tgz" integrity sha512-A+LHUSnwnxrnL/tZ+OLfqR1SxLN3c/pgDztZ47Rpbsd4jUytsTtwQo/TLPRzPJMp/1pbhYVhH9cuSZLAajNfjQ== @@ -4224,10 +4263,10 @@ pgpass@1.x: dependencies: split2 "^4.1.0" -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.0.0, picocolors@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz" + integrity sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" @@ -4341,6 +4380,11 @@ proc-log@^3.0.0: resolved "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz" integrity sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A== +proc-log@^4.2.0: + version "4.2.0" + resolved "https://registry.npmjs.org/proc-log/-/proc-log-4.2.0.tgz" + integrity sha512-g8+OnU/L2v+wyiVK+D5fA34J7EH8jZ8DDlvwhRCMxmMj7UCBvxiO1mGeN+36JXIKF4zevU4kRBd8lVgG9vLelA== + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" @@ -4456,9 +4500,9 @@ rc@^1.2.7: strip-json-comments "~2.0.1" react-is@^18.0.0: - version "18.2.0" - resolved "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz" - integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + version "18.3.1" + resolved "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.3.0, readable-stream@^2.3.5, readable-stream@~2.3.6: version "2.3.8" @@ -4498,12 +4542,12 @@ readdirp@~3.6.0: redis-errors@^1.0.0, redis-errors@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + resolved "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz" integrity sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w== redis-parser@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + resolved "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz" integrity sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A== dependencies: redis-errors "^1.0.0" @@ -4569,7 +4613,7 @@ retry@^0.12.0: resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz" integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== -rimraf@2, rimraf@^2.6.1: +rimraf@^2.6.1: version "2.7.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -4583,7 +4627,14 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" -safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +rimraf@2: + version "2.7.1" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1, safe-buffer@5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== @@ -4620,17 +4671,35 @@ semver@^5.4.1: resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^6.3.0, semver@^6.3.1: +semver@^6.3.0: version "6.3.1" resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.2.1, semver@^7.3.5, semver@^7.5.3, semver@^7.5.4: - version "7.6.0" - resolved "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz" - integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== - dependencies: - lru-cache "^6.0.0" +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.2.1: + version "7.6.2" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + +semver@^7.3.5: + version "7.6.2" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + +semver@^7.5.3: + version "7.6.2" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== + +semver@^7.5.4: + version "7.6.2" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz" + integrity sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w== send@0.18.0: version "0.18.0" @@ -4784,14 +4853,14 @@ socks-proxy-agent@^8.0.3: socks "^2.7.1" socks@^2.7.1: - version "2.8.1" - resolved "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz" - integrity sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ== + version "2.8.3" + resolved "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz" + integrity sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw== dependencies: ip-address "^9.0.5" smart-buffer "^4.2.0" -source-map-support@0.5.13, source-map-support@^0.5.12: +source-map-support@^0.5.12, source-map-support@0.5.13: version "0.5.13" resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz" integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== @@ -4827,9 +4896,9 @@ ssf@~0.11.2: frac "~1.1.2" ssri@^10.0.0: - version "10.0.5" - resolved "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz" - integrity sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A== + version "10.0.6" + resolved "https://registry.npmjs.org/ssri/-/ssri-10.0.6.tgz" + integrity sha512-MGrFH9Z4NP9Iyhqn16sDtBpRRNJ0Y2hNa6D65h736fVSaPCHr4DM4sWUNvVaSuC+0OBGhwsrydQwmgfg5LncqQ== dependencies: minipass "^7.0.3" @@ -4847,7 +4916,7 @@ stack-utils@^2.0.3: standard-as-callback@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" + resolved "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz" integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== static-eval@2.0.2: @@ -4862,6 +4931,13 @@ statuses@2.0.1: resolved "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz" integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== +string_decoder@^1.1.1, string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + string-length@^4.0.1: version "4.0.2" resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz" @@ -4893,7 +4969,7 @@ string-width@^1.0.1, "string-width@^1.0.2 || 2 || 3 || 4": is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +string-width@^4.1.0, string-width@^4.2.0: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -4902,7 +4978,16 @@ string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string-width@^5.0.1, string-width@^5.1.2: +string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^5.0.1: version "5.1.2" resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== @@ -4911,12 +4996,14 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string_decoder@^1.1.1, string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== +string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== dependencies: - safe-buffer "~5.1.0" + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" "strip-ansi-cjs@npm:strip-ansi@^6.0.1": version "6.0.1" @@ -4966,7 +5053,12 @@ strip-json-comments@^2.0.0, strip-json-comments@~2.0.1: resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -5162,7 +5254,7 @@ ts-node-dev@2.0.0: ts-node "^10.4.0" tsconfig "^7.0.0" -ts-node@^10.4.0: +ts-node@^10.4.0, ts-node@>=9.0.0: version "10.9.2" resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz" integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== @@ -5240,7 +5332,7 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typescript@5.4.2: +typescript@*, typescript@>=2.7, typescript@5.4.2: version "5.4.2" resolved "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz" integrity sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ== @@ -5269,7 +5361,7 @@ unique-slug@^4.0.0: dependencies: imurmurhash "^0.1.4" -unpipe@1.0.0, unpipe@~1.0.0: +unpipe@~1.0.0, unpipe@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== @@ -5291,12 +5383,12 @@ unzipper@^0.10.11: setimmediate "~1.0.4" update-browserslist-db@^1.0.13: - version "1.0.13" - resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz" - integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== + version "1.0.16" + resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.16.tgz" + integrity sha512-KVbTxlBYlckhF5wgfyZXTWnMn7MMZjMu9XG8bPlliUOP9ThaF4QnhP8qrjrH7DRzHfSk0oQv1wToW+iA5GajEQ== dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" + escalade "^3.1.2" + picocolors "^1.0.1" uri-js@^4.2.2, uri-js@^4.4.1: version "4.4.1" @@ -5315,21 +5407,26 @@ utils-merge@1.0.1: resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -uuid@9.0.1: - version "9.0.1" - resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz" - integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== - uuid@^3.0.0: version "3.4.0" resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== -uuid@^8.3.0, uuid@^8.3.2: +uuid@^8.3.0: + version "8.3.2" + resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +uuid@^8.3.2: version "8.3.2" resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +uuid@9.0.1: + version "9.0.1" + resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + v8-compile-cache-lib@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" @@ -5418,7 +5515,7 @@ wmf@~1.0.1: resolved "https://registry.npmjs.org/wmf/-/wmf-1.0.2.tgz" integrity sha512-/p9K7bEh0Dj6WbXg4JG0xvLQmIadrner1bi45VMJTfnbVHsc7yIajZyoSoK60/dtVBs12Fm6WkUI5/3WAVsNMw== -word-wrap@~1.2.3: +word-wrap@^1.2.5, word-wrap@~1.2.3: version "1.2.5" resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== From 1b1a1d860868193c4796f6b9d602b81336572892 Mon Sep 17 00:00:00 2001 From: nitish-egov <137176807+nitish-egov@users.noreply.github.com> Date: Tue, 13 Aug 2024 09:45:39 +0530 Subject: [PATCH 274/283] mdms config to be taken from devops (#853) --- .../project-factory/src/server/validators/campaignValidators.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/health-services/project-factory/src/server/validators/campaignValidators.ts b/health-services/project-factory/src/server/validators/campaignValidators.ts index 8c50b9bcd46..1af1e291eba 100644 --- a/health-services/project-factory/src/server/validators/campaignValidators.ts +++ b/health-services/project-factory/src/server/validators/campaignValidators.ts @@ -951,7 +951,7 @@ async function validateProjectType(request: any, projectType: any, tenantId: any } } const params = { tenantId: tenantId } - const searchResponse: any = await httpRequest(config.host.mdms + "egov-mdms-service/v1/_search", searchBody, params); + const searchResponse: any = await httpRequest(config.host.mdms + config?.paths?.mdms_search, searchBody, params); if (searchResponse?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes && Array.isArray(searchResponse?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes)) { const projectTypes = searchResponse?.MdmsRes?.["HCM-PROJECT-TYPES"]?.projectTypes; if (!projectTypes.includes(projectType)) { From e3d5238289fcaea3df4ef1a23277fe7c2e59fd9e Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Thu, 29 Aug 2024 16:30:00 +0530 Subject: [PATCH 275/283] HLM service request, updated DataTypeEnum (#872) --- .../egov/servicerequest/web/models/AttributeDefinition.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 cefb96adac8..59c32cf913b 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 @@ -60,7 +60,9 @@ public enum DataTypeEnum { MULTIVALUELIST("MultiValueList"), - FILE("File"); + FILE("File"), + + BOOLEAN("Boolean"); private String value; From a0e714254ca41e0dc1c1a7130eb89c6edb698df1 Mon Sep 17 00:00:00 2001 From: kanishq-egov <138671649+kanishq-egov@users.noreply.github.com> Date: Fri, 30 Aug 2024 13:44:44 +0530 Subject: [PATCH 276/283] Service request changelog 1.5 (#875) * Added changelog and upgraded the versions for household, individual and service request * Update core-services/service-request/CHANGELOG.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update health-services/individual/CHANGELOG.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * HLM fixed merge issues * HLM fixed merge issues * HCMPRE-413: updated the changelog as per code review comments * Update health-services/project/CHANGELOG.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: kavi_elrey@1993 <25226238+kavi-egov@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- core-services/service-request/CHANGELOG.md | 4 ++++ core-services/service-request/pom.xml | 2 +- health-services/household/CHANGELOG.md | 12 +++++++++--- health-services/household/pom.xml | 2 +- health-services/individual/CHANGELOG.md | 8 +++++--- health-services/individual/pom.xml | 2 +- health-services/project/CHANGELOG.md | 1 + health-services/referralmanagement/CHANGELOG.md | 1 + health-services/stock/CHANGELOG.md | 1 + 9 files changed, 24 insertions(+), 9 deletions(-) diff --git a/core-services/service-request/CHANGELOG.md b/core-services/service-request/CHANGELOG.md index a27826b5875..d1d5607bbd3 100644 --- a/core-services/service-request/CHANGELOG.md +++ b/core-services/service-request/CHANGELOG.md @@ -1,5 +1,9 @@ All notable changes to this module will be documented in this file. +## 1.0.1 - 2024-08-29 + +- Added `BOOLEAN` DataType in `AttributeDefinition` + ## 1.0.0 - Base version \ No newline at end of file diff --git a/core-services/service-request/pom.xml b/core-services/service-request/pom.xml index 3c16fbe8189..5b5bfe71423 100644 --- a/core-services/service-request/pom.xml +++ b/core-services/service-request/pom.xml @@ -4,7 +4,7 @@ service-request jar service-request - 1.0.0 + 1.0.1 1.8 ${java.version} diff --git a/health-services/household/CHANGELOG.md b/health-services/household/CHANGELOG.md index 3eed6ddb78c..3b9cbec0526 100644 --- a/health-services/household/CHANGELOG.md +++ b/health-services/household/CHANGELOG.md @@ -1,7 +1,12 @@ All notable changes to this module will be documented in this file. -## 1.1.3 - 2024-05-29 -- Integrated Core 2.9LTS +## 1.1.4 - 2024-08-29 + +- Added `ExistentEntityValidator` fixes + +## 1.1.3 - 2024-05-29 + +- Integrated Core 2.9 LTS - Client reference ID validation added - Upgraded to health models 1.0.20 and health common 1.0.16 - Boundary v2 Integration @@ -11,8 +16,9 @@ All notable changes to this module will be documented in this file. - Upgraded Flyway-Core to 9.22.3 ## 1.1.2 - 2024-05-10 + - Integrated Boundary v2 functionality -- + ## 1.1.1 - 2023-11-15 - Added total count for household diff --git a/health-services/household/pom.xml b/health-services/household/pom.xml index 955934b5e1a..798eba22c92 100644 --- a/health-services/household/pom.xml +++ b/health-services/household/pom.xml @@ -5,7 +5,7 @@ household jar household - 1.1.3 + 1.1.4 17 ${java.version} diff --git a/health-services/individual/CHANGELOG.md b/health-services/individual/CHANGELOG.md index 26df13994d2..2ac982c765d 100644 --- a/health-services/individual/CHANGELOG.md +++ b/health-services/individual/CHANGELOG.md @@ -1,7 +1,11 @@ All notable changes to this module will be documented in this file. +## 1.1.6 - 2024-08-29 + + - Added `ExistentEntityValidator` fixes + +## 1.1.5 - 2024-05-29 -## 1.1.5 - 2024-05-29 - Integrated Core 2.9LTS - Client reference ID validation added - Upgraded to health models 1.0.20 and health common 1.0.16 @@ -24,8 +28,6 @@ All notable changes to this module will be documented in this file. - Added proximity based search support -## 1.1.0 - ## 1.0.0 diff --git a/health-services/individual/pom.xml b/health-services/individual/pom.xml index ab7767c7206..84ca10da8d3 100644 --- a/health-services/individual/pom.xml +++ b/health-services/individual/pom.xml @@ -5,7 +5,7 @@ individual jar individual - 1.1.5 + 1.1.6 17 ${java.version} diff --git a/health-services/project/CHANGELOG.md b/health-services/project/CHANGELOG.md index 7865206457c..95369041416 100644 --- a/health-services/project/CHANGELOG.md +++ b/health-services/project/CHANGELOG.md @@ -13,6 +13,7 @@ All notable changes to this module will be documented in this file. - Upgraded PostgresSQL Driver version to 42.7.1 - Upgraded Flyway base image version to 10.7.1 for DB Migration - Upgraded Flyway-Core to 9.22.3 +- Added `ExistentEntityValidator` fixes ## 1.1.2 - 2024-02-26 - Implemented validation for updating project start date and end date. diff --git a/health-services/referralmanagement/CHANGELOG.md b/health-services/referralmanagement/CHANGELOG.md index 21e78657688..a1f5546b24e 100644 --- a/health-services/referralmanagement/CHANGELOG.md +++ b/health-services/referralmanagement/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this module will be documented in this file. ## 1.0.3 - 2024-08-09 - Upgraded downsync logic. +- Added `ExistentEntityValidator` fixes ## 1.0.2 - 2024-05-29 diff --git a/health-services/stock/CHANGELOG.md b/health-services/stock/CHANGELOG.md index 564823f17b1..de3d5826f7a 100644 --- a/health-services/stock/CHANGELOG.md +++ b/health-services/stock/CHANGELOG.md @@ -8,6 +8,7 @@ All notable changes to this module will be documented in this file. - Upgraded PostgresSQL Driver version to 42.7.1 - Upgraded Flyway base image version to 10.7.1 for DB Migration - Upgraded Flyway-Core to 9.22.3 +- Added `ExistentEntityValidator` fixes ## 1.1.2 - 2024-02-26 - Enhance inventory flow with sender id and receiver id added. From df5b6c9f497d1a7d691d4a59ab2156efedabab19 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 9 Sep 2024 15:00:36 +0530 Subject: [PATCH 277/283] HCMPRE-424: fixed hrms call from pgr-service --- .../src/main/java/org/egov/pgr/util/HRMSUtil.java | 6 ++++-- .../org/egov/pgr/validator/ServiceRequestValidator.java | 4 +++- .../java/org/egov/pgr/web/controllers/MockController.java | 2 +- .../src/main/java/org/egov/pgr/web/models/Workflow.java | 4 ++++ 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/util/HRMSUtil.java b/core-services/pgr-services/src/main/java/org/egov/pgr/util/HRMSUtil.java index 52416b33f23..724c5ee523f 100644 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/util/HRMSUtil.java +++ b/core-services/pgr-services/src/main/java/org/egov/pgr/util/HRMSUtil.java @@ -32,13 +32,15 @@ public HRMSUtil(ServiceRequestRepository serviceRequestRepository, PGRConfigurat /** * Gets the list of department for the given list of uuids of employees + * * @param uuids + * @param employeeUuids * @param requestInfo * @return */ - public List getDepartment(List uuids, RequestInfo requestInfo){ + public List getDepartment(List uuids, List employeeUuids, RequestInfo requestInfo){ - StringBuilder url = getHRMSURI(uuids); + StringBuilder url = getHRMSURI(employeeUuids); RequestInfoWrapper requestInfoWrapper = RequestInfoWrapper.builder().requestInfo(requestInfo).build(); diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/validator/ServiceRequestValidator.java b/core-services/pgr-services/src/main/java/org/egov/pgr/validator/ServiceRequestValidator.java index e6d154759fc..b98a8f90574 100644 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/validator/ServiceRequestValidator.java +++ b/core-services/pgr-services/src/main/java/org/egov/pgr/validator/ServiceRequestValidator.java @@ -159,10 +159,12 @@ private void validateDepartment(ServiceRequest request, Object mdmsData){ String serviceCode = request.getService().getServiceCode(); List assignes = request.getWorkflow().getAssignes(); + List hrmsAssignes = request.getWorkflow().getHrmsAssignes(); + if(CollectionUtils.isEmpty(assignes)) return; - List departments = hrmsUtil.getDepartment(assignes, request.getRequestInfo()); + List departments = hrmsUtil.getDepartment(assignes, hrmsAssignes, request.getRequestInfo()); String jsonPath = MDMS_DEPARTMENT_SEARCH.replace("{SERVICEDEF}",serviceCode); diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/web/controllers/MockController.java b/core-services/pgr-services/src/main/java/org/egov/pgr/web/controllers/MockController.java index 16a32b5a77c..92d32234043 100644 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/web/controllers/MockController.java +++ b/core-services/pgr-services/src/main/java/org/egov/pgr/web/controllers/MockController.java @@ -113,7 +113,7 @@ public ResponseEntity requestsUpdatePost() throws IOException { public ResponseEntity> requestsTest(@RequestBody RequestInfoWrapper requestInfoWrapper, @RequestParam String tenantId, @RequestParam List uuids) { - List department = hrmsUtil.getDepartment(uuids, requestInfoWrapper.getRequestInfo()); + List department = hrmsUtil.getDepartment(uuids, uuids, requestInfoWrapper.getRequestInfo()); return new ResponseEntity<>(department, HttpStatus.OK); } diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/web/models/Workflow.java b/core-services/pgr-services/src/main/java/org/egov/pgr/web/models/Workflow.java index b1260ba4e41..59b606e0b5e 100644 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/web/models/Workflow.java +++ b/core-services/pgr-services/src/main/java/org/egov/pgr/web/models/Workflow.java @@ -35,6 +35,10 @@ public class Workflow { @Valid private List assignes = null; + @JsonProperty("hrmsAssignes") + @Valid + private List hrmsAssignes = null; + @SafeHtml @JsonProperty("comments") private String comments = null; From 1aedebd1590e941d3ae0932a07ef522afca7dfc3 Mon Sep 17 00:00:00 2001 From: kanishq-egov Date: Mon, 9 Sep 2024 15:51:00 +0530 Subject: [PATCH 278/283] HCMPRE-424: updated as per code review comments --- .../src/main/java/org/egov/pgr/util/HRMSUtil.java | 4 ++-- .../java/org/egov/pgr/validator/ServiceRequestValidator.java | 2 +- .../src/main/java/org/egov/pgr/web/models/Workflow.java | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/util/HRMSUtil.java b/core-services/pgr-services/src/main/java/org/egov/pgr/util/HRMSUtil.java index 724c5ee523f..4409e39ed35 100644 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/util/HRMSUtil.java +++ b/core-services/pgr-services/src/main/java/org/egov/pgr/util/HRMSUtil.java @@ -33,8 +33,8 @@ public HRMSUtil(ServiceRequestRepository serviceRequestRepository, PGRConfigurat /** * Gets the list of department for the given list of uuids of employees * - * @param uuids - * @param employeeUuids + * @param uuids user uuids + * @param employeeUuids employee uuids * @param requestInfo * @return */ diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/validator/ServiceRequestValidator.java b/core-services/pgr-services/src/main/java/org/egov/pgr/validator/ServiceRequestValidator.java index b98a8f90574..fe9e1bd148c 100644 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/validator/ServiceRequestValidator.java +++ b/core-services/pgr-services/src/main/java/org/egov/pgr/validator/ServiceRequestValidator.java @@ -159,7 +159,7 @@ private void validateDepartment(ServiceRequest request, Object mdmsData){ String serviceCode = request.getService().getServiceCode(); List assignes = request.getWorkflow().getAssignes(); - List hrmsAssignes = request.getWorkflow().getHrmsAssignes(); + List hrmsAssignes = request.getWorkflow().getHrmsAssignees(); if(CollectionUtils.isEmpty(assignes)) return; diff --git a/core-services/pgr-services/src/main/java/org/egov/pgr/web/models/Workflow.java b/core-services/pgr-services/src/main/java/org/egov/pgr/web/models/Workflow.java index 59b606e0b5e..eb949bfce25 100644 --- a/core-services/pgr-services/src/main/java/org/egov/pgr/web/models/Workflow.java +++ b/core-services/pgr-services/src/main/java/org/egov/pgr/web/models/Workflow.java @@ -37,7 +37,7 @@ public class Workflow { @JsonProperty("hrmsAssignes") @Valid - private List hrmsAssignes = null; + private List hrmsAssignees = null; @SafeHtml @JsonProperty("comments") From 12223699de3660534a990059f4c821f58808c628 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:38:03 +0530 Subject: [PATCH 279/283] Create branch-name-validator (#960) * Create branch-name-validator * Update branch-name-validator * Update .github/workflows/branch-name-validator Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update .github/workflows/branch-name-validator Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .github/workflows/branch-name-validator | 36 +++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/branch-name-validator diff --git a/.github/workflows/branch-name-validator b/.github/workflows/branch-name-validator new file mode 100644 index 00000000000..45dd9c4afa4 --- /dev/null +++ b/.github/workflows/branch-name-validator @@ -0,0 +1,36 @@ +name: Enforce Branch Naming Convention + +on: + push: + branches: + - "*" + pull_request: + branches: + - "*" + +jobs: + branch-name-check: + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Enforce branch naming convention + run: | + # Get the branch name + branch_name=$(echo "${GITHUB_REF#refs/heads/}") + + # Define the branch name pattern + branch_regex="^(master|develop|(HCMPRE|HCMPOST|HCMSUB)-[0-9]{3,}-[a-zA-Z0-9-]+)$" + + # Check if the branch name matches the pattern + if [[ ! "$branch_name" =~ $branch_regex ]]; then + echo "Branch name '$branch_name' does not follow the required naming convention." + echo "Branch names must follow the pattern: (feature|bugfix|hotfix|release)/PROJ-1234-description" + exit 1 + fi + + - name: Success message + run: | + branch_name=$(echo "${GITHUB_REF#refs/heads/}") + echo "Branch name '$branch_name' follows the required naming convention: 'master', 'develop', or (HCMPRE|HCMPOST|HCMSUB)-123-description" From 08df5e75095be203f1e871c8b4307eee37697012 Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:51:05 +0530 Subject: [PATCH 280/283] Update branch-name-validator --- .github/workflows/branch-name-validator | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/branch-name-validator b/.github/workflows/branch-name-validator index 45dd9c4afa4..d613cfe22d6 100644 --- a/.github/workflows/branch-name-validator +++ b/.github/workflows/branch-name-validator @@ -26,7 +26,7 @@ jobs: # Check if the branch name matches the pattern if [[ ! "$branch_name" =~ $branch_regex ]]; then echo "Branch name '$branch_name' does not follow the required naming convention." - echo "Branch names must follow the pattern: (feature|bugfix|hotfix|release)/PROJ-1234-description" + echo "Branch names must follow the pattern: (HCMPRE|HCMPOST|HCMSUB)-123-description" exit 1 fi From 11a58004afaeb411a8e295e613d33f227eef441d Mon Sep 17 00:00:00 2001 From: "kavi_elrey@1993" <25226238+kavi-egov@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:59:43 +0530 Subject: [PATCH 281/283] Rename branch-name-validator to branch-name-validator.yml --- .../{branch-name-validator => branch-name-validator.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{branch-name-validator => branch-name-validator.yml} (100%) diff --git a/.github/workflows/branch-name-validator b/.github/workflows/branch-name-validator.yml similarity index 100% rename from .github/workflows/branch-name-validator rename to .github/workflows/branch-name-validator.yml From 1ad04eed8f19404787c3d77e6f8dd827e8821914 Mon Sep 17 00:00:00 2001 From: tanishi-egov Date: Thu, 17 Oct 2024 11:27:00 +0530 Subject: [PATCH 282/283] Added census-service in build-config (#990) --- build/build-config.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build/build-config.yml b/build/build-config.yml index dec24965782..cafec0ff43c 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -259,6 +259,13 @@ config: build: - work-dir: "analytics/auth-proxy" image-name: "auth-proxy" + - name: "builds/health-campaign-services/health-services/census-service" + build: + - work-dir: "health-services/census-service" + image-name: "census-service" + dockerfile: "build/17/maven/Dockerfile" + - work-dir: "health-services/census-service/src/main/resources/db" + image-name: "census-service-db" # frontend - name: builds/health-campaign-services/frontend/workbench-ui From d4fd0c92a06ef52b41c74f7d4eded1c97ae01b24 Mon Sep 17 00:00:00 2001 From: Palak Garg <86659286+palak-egov@users.noreply.github.com> Date: Thu, 24 Oct 2024 12:01:07 +0530 Subject: [PATCH 283/283] [HCMPRE-658] Refractor resource-estimation-service to resource-generator (#910) Co-authored-by: Priyanka-eGov <74049060+Priyanka-eGov@users.noreply.github.com> --- build/build-config.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/build-config.yml b/build/build-config.yml index cafec0ff43c..2002805a366 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -250,10 +250,10 @@ config: dockerfile: "build/17/maven/Dockerfile" - work-dir: "health-services/plan-service/src/main/resources/db" image-name: "plan-service-db" - - name: "builds/health-campaign-services/health-services/resource-estimation-service" + - name: "builds/health-campaign-services/health-services/resource-generator" build: - - work-dir: "health-services/resource-estimation-service" - image-name: "resource-estimation-service" + - work-dir: "health-services/resource-generator" + image-name: "resource-generator" dockerfile: "build/17/maven/Dockerfile" - name: "builds/health-campaign-services/analytics/auth-proxy" build: